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