removed clang-format and clang_complete files from the repo
[dosdemo] / src / dos / sball.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <dos.h>
5 #include <conio.h>
6
7 #ifdef __WATCOMC__
8 #include <i86.h>
9 #endif
10
11 #ifdef __DJGPP__
12 #include <dpmi.h>
13 #include <go32.h>
14 #include <pc.h>
15 #endif
16
17 #include "sball.h"
18 #include "inttypes.h"
19 #include "dosutil.h"
20
21 struct motion {
22         int x, y, z;
23         int rx, ry, rz;
24 };
25
26 #define UART1_BASE      0x3f8
27 #define UART2_BASE      0x2f8
28 #define UART1_IRQ       4
29 #define UART2_IRQ       3
30
31 #define UART_DATA       0
32 #define UART_INTR       1
33 #define UART_DIVLO      0
34 #define UART_DIVHI      1
35 #define UART_FIFO       2
36 #define UART_IID        2
37 #define UART_LCTL       3
38 #define UART_MCTL       4
39 #define UART_LSTAT      5
40 #define UART_MSTAT      6
41
42 /* interrupt enable register bits */
43 #define INTR_RECV       1
44 #define INTR_SEND       2
45 #define INTR_LSTAT      4
46 #define INTR_DELTA      8
47
48 /* fifo control register bits */
49 #define FIFO_ENABLE             0x01
50 #define FIFO_RECV_CLEAR 0x02
51 #define FIFO_SEND_CLEAR 0x04
52 #define FIFO_DMA                0x08
53 #define FIFO_TRIG_4             0x40
54 #define FIFO_TRIG_8             0x80
55 #define FIFO_TRIG_14    0xc0
56
57 /* interrupt id register bits */
58 #define IID_PENDING             0x01
59 #define IID_ID0                 0x02
60 #define IID_ID1                 0x04
61 #define IID_ID2                 0x08
62 #define IID_FIFO_EN             0xc0
63
64 #define IID_SOURCE              0xe
65
66 #define IID_DELTA               0
67 #define IID_SEND                0x2
68 #define IID_RECV                0x4
69 #define IID_FIFO                0xc
70 #define IID_STATUS              0x6
71
72 /* line control register bits */
73 #define LCTL_BITS_8     0x03
74 #define LCTL_STOP_2     0x04
75 #define LCTL_DLAB       0x80
76 #define LCTL_8N1        LCTL_BITS_8
77 #define LCTL_8N2        (LCTL_BITS_8 | LCTL_STOP_2)
78
79 /* modem control register bits */
80 #define MCTL_DTR        0x01
81 #define MCTL_RTS        0x02
82 #define MCTL_OUT1       0x04
83 #define MCTL_OUT2       0x08
84 #define MCTL_LOOP       0x10
85
86 /* line status register bits */
87 #define LST_DRDY                0x01
88 #define LST_ERR_OVER    0x02
89 #define LST_ERR_PARITY  0x04
90 #define LST_ERR_FRAME   0x08
91 #define LST_ERR_BRK             0x10
92 #define LST_TREG_EMPTY  0x20
93 #define LST_TIDLE               0x40
94 #define LST_ERROR               0x80
95
96 /* modem status register bits */
97 #define MST_DELTA_CTS   0x01
98 #define MST_DELTA_DSR   0x02
99 #define MST_TERI                0x04
100 #define MST_DELTA_DCD   0x08
101 #define MST_CTS                 0x10
102 #define MST_DSR                 0x20
103 #define MST_RING                0x40
104 #define MST_DCD                 0x80
105
106 /* interrupt controller stuff */
107 #define PIC1_CMD_PORT   0x20
108 #define PIC1_DATA_PORT  0x21
109 #define PIC2_CMD_PORT   0xa0
110 #define PIC2_DATA_PORT  0xa1
111 #define OCW2_EOI                0x20
112
113 struct packet {
114         int id;
115         char data[80];
116 };
117
118 static int init_smouse(void);
119 static void read_motion(int *m, const char *s);
120 static void read_keystate(unsigned int *stptr, const char *s);
121 static void procpkt(struct packet *p);
122 static void enqueue_event(sball_event *ev);
123
124 #define COM_FMT_8N1             LCTL_8N1
125 #define COM_FMT_8N2             LCTL_8N2
126 static void com_setup(int port, int baud, unsigned int fmt);
127 static void com_close(void);
128
129 static void com_putc(char c);
130 static void com_puts(const char *s);
131 static int com_getc(void);
132 static char *com_gets(char *buf, int sz);
133
134 static int com_have_recv(void);
135 static int com_can_send(void);
136
137 #ifdef __WATCOMC__
138 #define INTERRUPT       __interrupt __far
139 static void (INTERRUPT *prev_recv_intr)(void);
140 #endif
141
142 #ifdef __DJGPP__
143 #define INTERRUPT
144
145 static _go32_dpmi_seginfo intr, prev_intr;
146 #endif
147
148 static void INTERRUPT recv_intr(void);
149
150 static int uart_base, uart_intr_num;
151
152 static struct packet pktbuf[16];
153 static int pktbuf_ridx, pktbuf_widx;
154 #define BNEXT(x)        (((x) + 1) & 0xf)
155 #define BEMPTY(b)       (b##_ridx == b##_widx)
156
157 static sball_event evbuf[16];
158 static int evbuf_ridx, evbuf_widx;
159
160
161 int sball_init(void)
162 {
163         com_setup(0, 9600, COM_FMT_8N2);
164         init_smouse();
165         return 0;
166 }
167
168 void sball_shutdown(void)
169 {
170         com_close();
171 }
172
173 int sball_getdev(void)
174 {
175         return 0;
176 }
177
178 int sball_pending(void)
179 {
180         _disable();
181         while(!BEMPTY(pktbuf)) {
182                 procpkt(pktbuf + pktbuf_ridx);
183                 pktbuf_ridx = BNEXT(pktbuf_ridx);
184         }
185         _enable();
186         return !BEMPTY(evbuf);
187 }
188
189 int sball_getevent(sball_event *ev)
190 {
191         _disable();
192         while(!BEMPTY(pktbuf)) {
193                 procpkt(pktbuf + pktbuf_ridx);
194                 pktbuf_ridx = BNEXT(pktbuf_ridx);
195         }
196         _enable();
197
198         if(BEMPTY(evbuf)) {
199                 return 0;
200         }
201         *ev = evbuf[evbuf_ridx];
202         evbuf_ridx = BNEXT(evbuf_ridx);
203         return 1;
204 }
205
206 static int init_smouse(void)
207 {
208         /* try repeatedly zeroing the device until we get a response */
209         do {
210                 delay(500);
211                 com_puts("z\r");
212         } while(BEMPTY(pktbuf));
213
214         /* then ask for id string and request motion updates */
215         com_puts("vQ\r");
216         com_puts("m3\r");
217         return 0;
218 }
219
220 static void procpkt(struct packet *p)
221 {
222         static unsigned int bnstate;
223         int i;
224         unsigned int st, delta, prev;
225         sball_event *ev;
226
227         switch(p->id) {
228         case 'd':
229                 ev = evbuf + evbuf_widx;
230                 read_motion(ev->motion.motion, p->data);
231                 ev->type = SBALL_EV_MOTION;
232                 enqueue_event(ev);
233                 break;
234
235         case 'k':
236                 read_keystate(&st, p->data);
237
238                 delta = st ^ bnstate;
239                 prev = bnstate;
240                 bnstate = st;
241
242                 for(i=0; i<32; i++) {
243                         if(delta & 1) {
244                                 ev = evbuf + evbuf_widx;
245                                 ev->type = SBALL_EV_BUTTON;
246                                 ev->button.id = i;
247                                 ev->button.pressed = st & 1;
248                                 ev->button.state = prev ^ (1 << i);
249                                 enqueue_event(ev);
250                         }
251                         st >>= 1;
252                         delta >>= 1;
253                 }
254                 break;
255
256         case 'v':
257                 printf("Device: %s\n", p->data);
258                 break;
259         /*
260         default:
261                 printf("DBG %c -> %s\n", (char)p->id, p->data);
262         */
263         }
264 }
265
266 static void enqueue_event(sball_event *ev)
267 {
268         if(ev != evbuf + evbuf_widx) {
269                 evbuf[evbuf_widx] = *ev;
270         }
271
272         evbuf_widx = BNEXT(evbuf_widx);
273         if(evbuf_widx == evbuf_ridx) {
274                 fprintf(stderr, "enqueue_event: overflow, dropping oldest\n");
275                 evbuf_ridx = BNEXT(evbuf_ridx);
276         }
277 }
278
279 static void com_setup(int port, int baud, unsigned int fmt)
280 {
281         unsigned char ctl;
282         unsigned short div = 115200 / baud;
283         static int base[] = {UART1_BASE, UART2_BASE};
284         static int irq[] = {UART1_IRQ, UART2_IRQ};
285
286         uart_base = base[port];
287         uart_intr_num = irq[port] | 8;
288
289         _disable();
290 #ifdef __WATCOMC__
291         prev_recv_intr = _dos_getvect(uart_intr_num);
292         _dos_setvect(uart_intr_num, recv_intr);
293 #endif
294 #ifdef __DJGPP__
295         _go32_dpmi_get_protected_mode_interrupt_vector(uart_intr_num, &prev_intr);
296         intr.pm_offset = (intptr_t)recv_intr;
297         intr.pm_selector = _go32_my_cs();
298         _go32_dpmi_allocate_iret_wrapper(&intr);
299         _go32_dpmi_set_protected_mode_interrupt_vector(uart_intr_num, &intr);
300 #endif
301         /* unmask the appropriate interrupt */
302         outp(PIC1_DATA_PORT, inp(PIC1_DATA_PORT) & ~(1 << irq[port]));
303
304         outp(uart_base + UART_LCTL, LCTL_DLAB);
305         outp(uart_base + UART_DIVLO, div & 0xff);
306         outp(uart_base + UART_DIVHI, (div >> 8) & 0xff);
307         outp(uart_base + UART_LCTL, fmt);       /* fmt should be LCTL_8N1, LCTL_8N2 etc */
308         outp(uart_base + UART_FIFO, FIFO_ENABLE | FIFO_SEND_CLEAR | FIFO_RECV_CLEAR);
309         outp(uart_base + UART_MCTL, MCTL_DTR | MCTL_RTS | MCTL_OUT2);
310         outp(uart_base + UART_INTR, INTR_RECV);
311
312         _enable();
313 }
314
315 static void com_close(void)
316 {
317         _disable();
318         outp(uart_base + UART_INTR, 0);
319         outp(uart_base + UART_MCTL, 0);
320 #ifdef __WATCOMC__
321         _dos_setvect(uart_intr_num, prev_recv_intr);
322 #endif
323 #ifdef __DJGPP__
324         _go32_dpmi_set_protected_mode_interrupt_vector(uart_intr_num, &prev_intr);
325         _go32_dpmi_free_iret_wrapper(&intr);
326 #endif
327         _enable();
328 }
329
330 static void com_putc(char c)
331 {
332         while(!com_can_send());
333         while((inp(uart_base + UART_MSTAT) & MST_CTS) == 0);
334         outp(uart_base + UART_DATA, c);
335 }
336
337 static void com_puts(const char *s)
338 {
339         while(*s) {
340                 com_putc(*s++);
341         }
342 }
343
344 static int com_getc(void)
345 {
346         int have;
347         while(!(have = com_have_recv()));
348         return inp(uart_base + UART_DATA);
349 }
350
351 static char *com_gets(char *buf, int sz)
352 {
353         int c;
354         char *ptr = buf;
355
356         while(sz-- > 1 && (c = com_getc()) != -1) {
357                 if(c == '\r') {
358                         *ptr++ = '\n';
359                         break;
360                 }
361                 *ptr++ = c;
362         }
363         if(c == -1) {
364                 return 0;
365         }
366         *ptr = 0;
367         return buf;
368 }
369
370 static int com_have_recv(void)
371 {
372         unsigned short stat = inp(uart_base + UART_LSTAT);
373         if(stat & LST_ERROR) {
374                 fprintf(stderr, "receive error\n");
375                 abort();
376         }
377         return stat & LST_DRDY;
378 }
379
380 static int com_can_send(void)
381 {
382         return inp(uart_base + UART_LSTAT) & LST_TREG_EMPTY;
383 }
384
385 static void INTERRUPT recv_intr()
386 {
387         static char buf[128];
388         static char *bptr = buf;
389         struct packet *pkt;
390         int idreg, c, datasz;
391
392         while(((idreg = inp(uart_base + UART_IID)) & IID_PENDING) == 0) {
393                 while(com_have_recv()) {
394                         if((c = inp(uart_base + UART_DATA)) == '\r') {
395                                 *bptr = 0;
396                                 datasz = bptr - buf;
397                                 bptr = buf;
398
399                                 pkt = pktbuf + pktbuf_widx;
400                                 pktbuf_widx = BNEXT(pktbuf_widx);
401
402                                 if(pktbuf_widx == pktbuf_ridx) {
403                                         /* we overflowed, drop the oldest packet */
404                                         pktbuf_ridx = BNEXT(pktbuf_ridx);
405                                 }
406
407                                 if(datasz > sizeof pkt->data) {
408                                         datasz = sizeof pkt->data;      /* truncate */
409                                 }
410                                 pkt->id = buf[0];
411                                 memcpy(pkt->data, buf + 1, datasz);
412
413                         } else if(bptr - buf < sizeof buf - 1) {
414                                 *bptr++ = c;
415                         }
416                 }
417         }
418
419         outp(PIC1_CMD_PORT, OCW2_EOI);
420 }
421
422 static void read_motion(int *m, const char *s)
423 {
424         int i;
425
426         for(i=0; i<6; i++) {
427                 long val = ((((long)s[0] & 0xf) << 12) |
428                         (((long)s[1] & 0xf) << 8) |
429                         (((long)s[2] & 0xf) << 4) |
430                         ((long)s[3] & 0xf)) - 32768;
431                 s += 4;
432                 *m++ = (int)val;
433         }
434 }
435
436 static void read_keystate(unsigned int *stptr, const char *s)
437 {
438         int i, bit = 0;
439         unsigned int st = 0;
440
441         for(i=0; i<3; i++) {
442                 st |= ((unsigned int)*s++ & 0xf) << bit;
443                 bit += 4;
444         }
445         *stptr = st;
446 }