1433d6423SLionel Sambuc /* Keyboard driver for PCs and ATs. */
2433d6423SLionel Sambuc #include <minix/drivers.h>
3433d6423SLionel Sambuc #include <minix/input.h>
4433d6423SLionel Sambuc #include <minix/inputdriver.h>
5433d6423SLionel Sambuc
6433d6423SLionel Sambuc #include "pckbd.h"
7433d6423SLionel Sambuc
8433d6423SLionel Sambuc /*
9433d6423SLionel Sambuc * Data that is to be sent to the keyboard. Each byte is ACKed by the keyboard.
10433d6423SLionel Sambuc * This is currently somewhat overpowered for its only purpose: setting LEDs.
11433d6423SLionel Sambuc */
12433d6423SLionel Sambuc static struct kbdout {
13433d6423SLionel Sambuc unsigned char buf[KBD_OUT_BUFSZ];
14433d6423SLionel Sambuc int offset;
15433d6423SLionel Sambuc int avail;
16433d6423SLionel Sambuc int expect_ack;
17433d6423SLionel Sambuc } kbdout;
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc static int kbd_watchdog_set = 0;
20433d6423SLionel Sambuc static int kbd_alive = 1;
21433d6423SLionel Sambuc static minix_timer_t tmr_kbd_wd;
22433d6423SLionel Sambuc
23433d6423SLionel Sambuc static int irq_hook_id = -1;
24433d6423SLionel Sambuc static int aux_irq_hook_id = -1;
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc static int kbd_state = 0;
27433d6423SLionel Sambuc
28433d6423SLionel Sambuc static unsigned char aux_bytes[3];
29433d6423SLionel Sambuc static unsigned char aux_state = 0;
30433d6423SLionel Sambuc static int aux_counter = 0;
313d310546SLionel Sambuc static int aux_available = 0;
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc static void pckbd_leds(unsigned int);
34433d6423SLionel Sambuc static void pckbd_intr(unsigned int);
35433d6423SLionel Sambuc static void pckbd_alarm(clock_t);
36433d6423SLionel Sambuc
37433d6423SLionel Sambuc static struct inputdriver pckbd_tab = {
38433d6423SLionel Sambuc .idr_leds = pckbd_leds,
39433d6423SLionel Sambuc .idr_intr = pckbd_intr,
40433d6423SLionel Sambuc .idr_alarm = pckbd_alarm
41433d6423SLionel Sambuc };
42433d6423SLionel Sambuc
43433d6423SLionel Sambuc /*
44433d6423SLionel Sambuc * The watchdog timer function, implementing all but the actual reset.
45433d6423SLionel Sambuc */
46433d6423SLionel Sambuc static void
kbd_watchdog(int arg __unused)47*cfd712b4SDavid van Moolenbroek kbd_watchdog(int arg __unused)
48433d6423SLionel Sambuc {
49433d6423SLionel Sambuc kbd_watchdog_set = 0;
50433d6423SLionel Sambuc if (!kbdout.avail)
51433d6423SLionel Sambuc return; /* Watchdog is no longer needed */
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc if (!kbd_alive)
54433d6423SLionel Sambuc printf("PCKBD: watchdog should reset keyboard\n");
55433d6423SLionel Sambuc kbd_alive = 0;
56433d6423SLionel Sambuc
57433d6423SLionel Sambuc set_timer(&tmr_kbd_wd, sys_hz(), kbd_watchdog, 0);
58433d6423SLionel Sambuc
59433d6423SLionel Sambuc kbd_watchdog_set = 1;
60433d6423SLionel Sambuc }
61433d6423SLionel Sambuc
62433d6423SLionel Sambuc /*
63433d6423SLionel Sambuc * Send queued data to the keyboard.
64433d6423SLionel Sambuc */
65433d6423SLionel Sambuc static void
kbd_send(void)66433d6423SLionel Sambuc kbd_send(void)
67433d6423SLionel Sambuc {
68433d6423SLionel Sambuc u32_t sb;
69433d6423SLionel Sambuc int r;
70433d6423SLionel Sambuc
71433d6423SLionel Sambuc if (!kbdout.avail)
72433d6423SLionel Sambuc return;
73433d6423SLionel Sambuc if (kbdout.expect_ack)
74433d6423SLionel Sambuc return;
75433d6423SLionel Sambuc
76433d6423SLionel Sambuc if ((r = sys_inb(KB_STATUS, &sb)) != OK)
77433d6423SLionel Sambuc printf("PCKBD: send sys_inb() failed (1): %d\n", r);
78433d6423SLionel Sambuc
79433d6423SLionel Sambuc if (sb & (KB_OUT_FULL | KB_IN_FULL)) {
80433d6423SLionel Sambuc printf("PCKBD: not sending (1): sb = 0x%x\n", sb);
81433d6423SLionel Sambuc return;
82433d6423SLionel Sambuc }
83433d6423SLionel Sambuc micro_delay(KBC_IN_DELAY);
84433d6423SLionel Sambuc if ((r = sys_inb(KB_STATUS, &sb)) != OK)
85433d6423SLionel Sambuc printf("PCKBD: send sys_inb() failed (2): %d\n", r);
86433d6423SLionel Sambuc if (sb & (KB_OUT_FULL | KB_IN_FULL)) {
87433d6423SLionel Sambuc printf("PCKBD: not sending (2): sb = 0x%x\n", sb);
88433d6423SLionel Sambuc return;
89433d6423SLionel Sambuc }
90433d6423SLionel Sambuc
91433d6423SLionel Sambuc /* Okay, buffer is really empty */
92433d6423SLionel Sambuc if ((r = sys_outb(KEYBD, kbdout.buf[kbdout.offset])) != OK)
93433d6423SLionel Sambuc printf("PCKBD: send sys_outb() failed: %d\n", r);
94433d6423SLionel Sambuc kbdout.offset++;
95433d6423SLionel Sambuc kbdout.avail--;
96433d6423SLionel Sambuc kbdout.expect_ack = 1;
97433d6423SLionel Sambuc
98433d6423SLionel Sambuc kbd_alive = 1;
99433d6423SLionel Sambuc if (kbd_watchdog_set) {
100433d6423SLionel Sambuc /* Set a watchdog timer for one second. */
101433d6423SLionel Sambuc set_timer(&tmr_kbd_wd, sys_hz(), kbd_watchdog, 0);
102433d6423SLionel Sambuc
103433d6423SLionel Sambuc kbd_watchdog_set = 1;
104433d6423SLionel Sambuc }
105433d6423SLionel Sambuc }
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc /*
108433d6423SLionel Sambuc * Try to obtain input from the keyboard.
109433d6423SLionel Sambuc */
110433d6423SLionel Sambuc static int
scan_keyboard(unsigned char * bp,int * isauxp)111433d6423SLionel Sambuc scan_keyboard(unsigned char *bp, int *isauxp)
112433d6423SLionel Sambuc {
113433d6423SLionel Sambuc u32_t b, sb;
114433d6423SLionel Sambuc int r;
115433d6423SLionel Sambuc
116433d6423SLionel Sambuc if ((r = sys_inb(KB_STATUS, &sb)) != OK) {
117433d6423SLionel Sambuc printf("PCKBD: scan sys_inb() failed (1): %d\n", r);
118433d6423SLionel Sambuc return FALSE;
119433d6423SLionel Sambuc }
120433d6423SLionel Sambuc if (!(sb & KB_OUT_FULL)) {
121433d6423SLionel Sambuc if (kbdout.avail && !kbdout.expect_ack)
122433d6423SLionel Sambuc kbd_send();
123433d6423SLionel Sambuc return FALSE;
124433d6423SLionel Sambuc }
125433d6423SLionel Sambuc if ((r = sys_inb(KEYBD, &b)) != OK) {
126433d6423SLionel Sambuc printf("PCKBD: scan sys_inb() failed (2): %d\n", r);
127433d6423SLionel Sambuc return FALSE;
128433d6423SLionel Sambuc }
1293d310546SLionel Sambuc if (!(sb & 0x40) && b == KB_ACK && kbdout.expect_ack) {
130433d6423SLionel Sambuc kbdout.expect_ack = 0;
131433d6423SLionel Sambuc micro_delay(KBC_IN_DELAY);
132433d6423SLionel Sambuc kbd_send();
133433d6423SLionel Sambuc return FALSE;
134433d6423SLionel Sambuc }
135433d6423SLionel Sambuc if (bp)
136433d6423SLionel Sambuc *bp = b;
137433d6423SLionel Sambuc if (isauxp)
138433d6423SLionel Sambuc *isauxp = !!(sb & KB_AUX_BYTE);
139433d6423SLionel Sambuc if (kbdout.avail && !kbdout.expect_ack) {
140433d6423SLionel Sambuc micro_delay(KBC_IN_DELAY);
141433d6423SLionel Sambuc kbd_send();
142433d6423SLionel Sambuc }
143433d6423SLionel Sambuc return TRUE;
144433d6423SLionel Sambuc }
145433d6423SLionel Sambuc
146433d6423SLionel Sambuc /*
147433d6423SLionel Sambuc * Wait until the controller is ready. Return TRUE on success, FALSE on
148433d6423SLionel Sambuc * timeout. Since this may discard input, only use during initialization.
149433d6423SLionel Sambuc */
150433d6423SLionel Sambuc static int
kb_wait(void)151433d6423SLionel Sambuc kb_wait(void)
152433d6423SLionel Sambuc {
153433d6423SLionel Sambuc spin_t spin;
154433d6423SLionel Sambuc u32_t status;
155433d6423SLionel Sambuc int r, isaux;
156433d6423SLionel Sambuc unsigned char byte;
157433d6423SLionel Sambuc
158433d6423SLionel Sambuc SPIN_FOR(&spin, KBC_WAIT_TIME) {
159433d6423SLionel Sambuc if ((r = sys_inb(KB_STATUS, &status)) != OK)
160433d6423SLionel Sambuc printf("PCKBD: wait sys_inb() failed: %d\n", r);
161433d6423SLionel Sambuc if (status & KB_OUT_FULL)
162433d6423SLionel Sambuc (void) scan_keyboard(&byte, &isaux);
163433d6423SLionel Sambuc if (!(status & (KB_IN_FULL | KB_OUT_FULL)))
164433d6423SLionel Sambuc return TRUE; /* wait until ready */
165433d6423SLionel Sambuc }
166433d6423SLionel Sambuc
167433d6423SLionel Sambuc printf("PCKBD: wait timeout\n");
168433d6423SLionel Sambuc return FALSE;
169433d6423SLionel Sambuc }
170433d6423SLionel Sambuc
171433d6423SLionel Sambuc /*
172433d6423SLionel Sambuc * Set the LEDs on the caps, num, and scroll lock keys.
173433d6423SLionel Sambuc */
174433d6423SLionel Sambuc static void
set_leds(unsigned char ledmask)175433d6423SLionel Sambuc set_leds(unsigned char ledmask)
176433d6423SLionel Sambuc {
177433d6423SLionel Sambuc if (kbdout.avail == 0)
178433d6423SLionel Sambuc kbdout.offset = 0;
179433d6423SLionel Sambuc if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ) {
180433d6423SLionel Sambuc /*
181433d6423SLionel Sambuc * The output buffer is full. Ignore this command. Reset the
182433d6423SLionel Sambuc * ACK flag.
183433d6423SLionel Sambuc */
184433d6423SLionel Sambuc kbdout.expect_ack = 0;
185433d6423SLionel Sambuc } else {
186433d6423SLionel Sambuc kbdout.buf[kbdout.offset+kbdout.avail] = LED_CODE;
187433d6423SLionel Sambuc kbdout.buf[kbdout.offset+kbdout.avail+1] = ledmask;
188433d6423SLionel Sambuc kbdout.avail += 2;
189433d6423SLionel Sambuc }
190433d6423SLionel Sambuc if (!kbdout.expect_ack)
191433d6423SLionel Sambuc kbd_send();
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc
194433d6423SLionel Sambuc /*
195433d6423SLionel Sambuc * Send a command to the keyboard.
196433d6423SLionel Sambuc */
197433d6423SLionel Sambuc static void
kbc_cmd0(int cmd)198433d6423SLionel Sambuc kbc_cmd0(int cmd)
199433d6423SLionel Sambuc {
200433d6423SLionel Sambuc int r;
201433d6423SLionel Sambuc
202433d6423SLionel Sambuc kb_wait();
203433d6423SLionel Sambuc if ((r = sys_outb(KB_COMMAND, cmd)) != OK)
204433d6423SLionel Sambuc printf("PCKBD: cmd0 sys_outb() failed: %d\n", r);
205433d6423SLionel Sambuc }
206433d6423SLionel Sambuc
207433d6423SLionel Sambuc /*
208433d6423SLionel Sambuc * Send a command to the keyboard, including data.
209433d6423SLionel Sambuc */
210433d6423SLionel Sambuc static void
kbc_cmd1(int cmd,int data)211433d6423SLionel Sambuc kbc_cmd1(int cmd, int data)
212433d6423SLionel Sambuc {
213433d6423SLionel Sambuc int r;
214433d6423SLionel Sambuc
215433d6423SLionel Sambuc kb_wait();
216433d6423SLionel Sambuc if ((r = sys_outb(KB_COMMAND, cmd)) != OK)
217433d6423SLionel Sambuc printf("PCKBD: cmd1 sys_outb() failed (1): %d\n", r);
218433d6423SLionel Sambuc kb_wait();
219433d6423SLionel Sambuc if ((r = sys_outb(KEYBD, data)) != OK)
220433d6423SLionel Sambuc printf("PCKBD: cmd1 sys_outb() failed (2): %d\n", r);
221433d6423SLionel Sambuc }
222433d6423SLionel Sambuc
223433d6423SLionel Sambuc /*
224433d6423SLionel Sambuc * Wait at most one second for a byte from the keyboard or the controller.
225433d6423SLionel Sambuc */
226433d6423SLionel Sambuc static int
kbc_read(void)227433d6423SLionel Sambuc kbc_read(void)
228433d6423SLionel Sambuc {
229433d6423SLionel Sambuc u32_t byte, status;
230433d6423SLionel Sambuc spin_t spin;
231433d6423SLionel Sambuc int r;
232433d6423SLionel Sambuc
233433d6423SLionel Sambuc SPIN_FOR(&spin, KBC_READ_TIME) {
234433d6423SLionel Sambuc if ((r = sys_inb(KB_STATUS, &status)) != OK)
235433d6423SLionel Sambuc printf("PCKBD: read sys_inb() failed (1): %d\n", r);
236433d6423SLionel Sambuc if (status & KB_OUT_FULL) {
237433d6423SLionel Sambuc micro_delay(KBC_IN_DELAY);
238433d6423SLionel Sambuc if ((r = sys_inb(KEYBD, &byte)) != OK)
239433d6423SLionel Sambuc printf("PCKBD: read sys_inb() failed (2): "
240433d6423SLionel Sambuc "%d\n", r);
241433d6423SLionel Sambuc if (status & KB_AUX_BYTE)
242433d6423SLionel Sambuc printf("PCKBD: read got aux 0x%x\n", byte);
243433d6423SLionel Sambuc return byte;
244433d6423SLionel Sambuc }
245433d6423SLionel Sambuc }
246433d6423SLionel Sambuc
247433d6423SLionel Sambuc panic("kbc_read failed to complete");
248433d6423SLionel Sambuc }
249433d6423SLionel Sambuc
250433d6423SLionel Sambuc /*
251433d6423SLionel Sambuc * Initialize the keyboard hardware.
252433d6423SLionel Sambuc */
253e1e2bc96Srlfnb static int
kb_init(void)254433d6423SLionel Sambuc kb_init(void)
255433d6423SLionel Sambuc {
256433d6423SLionel Sambuc int r, ccb;
257433d6423SLionel Sambuc
2583d310546SLionel Sambuc /* Disable the keyboard and AUX. */
2593d310546SLionel Sambuc kbc_cmd0(KBC_DI_KBD);
2603d310546SLionel Sambuc kbc_cmd0(KBC_DI_AUX);
2613d310546SLionel Sambuc
262433d6423SLionel Sambuc /* Discard leftover keystroke. */
263433d6423SLionel Sambuc scan_keyboard(NULL, NULL);
264433d6423SLionel Sambuc
2653d310546SLionel Sambuc /* Get the current configuration byte. */
2663d310546SLionel Sambuc kbc_cmd0(KBC_RD_RAM_CCB);
2673d310546SLionel Sambuc ccb = kbc_read();
2683d310546SLionel Sambuc
2693d310546SLionel Sambuc /* If bit 5 is clear, it is a single channel controler for sure.. */
2703d310546SLionel Sambuc aux_available = (ccb & 0x10);
2713d310546SLionel Sambuc
2723d310546SLionel Sambuc /* Execute Controller Self Test. */
2733d310546SLionel Sambuc kbc_cmd0(0xAA);
2743d310546SLionel Sambuc r = kbc_read();
275e1e2bc96Srlfnb if (r != 0x55){
276e1e2bc96Srlfnb printf("PCKBD: Controller self-test failed.\n");
277e1e2bc96Srlfnb return EGENERIC;
278e1e2bc96Srlfnb }
2793d310546SLionel Sambuc
280433d6423SLionel Sambuc /* Set interrupt handler and enable keyboard IRQ. */
281433d6423SLionel Sambuc irq_hook_id = KEYBOARD_IRQ; /* id to be returned on interrupt */
282433d6423SLionel Sambuc r = sys_irqsetpolicy(KEYBOARD_IRQ, IRQ_REENABLE, &irq_hook_id);
283433d6423SLionel Sambuc if (r != OK)
284433d6423SLionel Sambuc panic("Couldn't set keyboard IRQ policy: %d", r);
285433d6423SLionel Sambuc if ((r = sys_irqenable(&irq_hook_id)) != OK)
286433d6423SLionel Sambuc panic("Couldn't enable keyboard IRQs: %d", r);
287433d6423SLionel Sambuc
2883d310546SLionel Sambuc /* Activate IRQ bit for the keyboard. */
2893d310546SLionel Sambuc ccb |= 0x1;
2903d310546SLionel Sambuc
2913d310546SLionel Sambuc if (aux_available != 0) {
292433d6423SLionel Sambuc /* Set AUX interrupt handler and enable AUX IRQ. */
293433d6423SLionel Sambuc aux_irq_hook_id = KBD_AUX_IRQ; /* id to be returned on interrupt */
294433d6423SLionel Sambuc r = sys_irqsetpolicy(KBD_AUX_IRQ, IRQ_REENABLE, &aux_irq_hook_id);
295433d6423SLionel Sambuc if (r != OK)
296433d6423SLionel Sambuc panic("Couldn't set AUX IRQ policy: %d", r);
297433d6423SLionel Sambuc if ((r = sys_irqenable(&aux_irq_hook_id)) != OK)
298433d6423SLionel Sambuc panic("Couldn't enable AUX IRQs: %d", r);
299433d6423SLionel Sambuc
3003d310546SLionel Sambuc /* Activate IRQ for AUX. */
3013d310546SLionel Sambuc ccb |= 0x2;
3023d310546SLionel Sambuc }
303433d6423SLionel Sambuc
3043d310546SLionel Sambuc /* Enable interrupt(s). */
3053d310546SLionel Sambuc kbc_cmd1(KBC_WR_RAM_CCB, ccb);
306433d6423SLionel Sambuc
307433d6423SLionel Sambuc /* Re-enable the keyboard device. */
308433d6423SLionel Sambuc kbc_cmd0(KBC_EN_KBD);
309433d6423SLionel Sambuc
3103d310546SLionel Sambuc if (aux_available != 0) {
311433d6423SLionel Sambuc /* Enable the AUX device. */
312433d6423SLionel Sambuc kbc_cmd0(KBC_EN_AUX);
3133d310546SLionel Sambuc kbc_cmd1(0xD4, 0xF6);
3143d310546SLionel Sambuc kbc_cmd1(0xD4, 0xF4);
3153d310546SLionel Sambuc }
316433d6423SLionel Sambuc
317433d6423SLionel Sambuc /* Set the initial LED state. */
318433d6423SLionel Sambuc kb_wait();
319433d6423SLionel Sambuc
320433d6423SLionel Sambuc set_leds(0);
321e1e2bc96Srlfnb return OK;
322433d6423SLionel Sambuc }
323433d6423SLionel Sambuc
324433d6423SLionel Sambuc /*
325433d6423SLionel Sambuc * Process a keyboard scancode.
326433d6423SLionel Sambuc */
327433d6423SLionel Sambuc static void
kbd_process(unsigned char scode)328433d6423SLionel Sambuc kbd_process(unsigned char scode)
329433d6423SLionel Sambuc {
330433d6423SLionel Sambuc int press, index, page, code;
331433d6423SLionel Sambuc
332433d6423SLionel Sambuc press = !(scode & SCAN_RELEASE) ? INPUT_PRESS : INPUT_RELEASE;
333433d6423SLionel Sambuc index = scode & ~SCAN_RELEASE;
334433d6423SLionel Sambuc
335433d6423SLionel Sambuc switch (kbd_state) {
336433d6423SLionel Sambuc case 1:
337433d6423SLionel Sambuc page = scanmap_escaped[index].page;
338433d6423SLionel Sambuc code = scanmap_escaped[index].code;
339433d6423SLionel Sambuc break;
340433d6423SLionel Sambuc case 2:
341433d6423SLionel Sambuc kbd_state = (index == SCAN_CTRL) ? 3 : 0;
342433d6423SLionel Sambuc return;
343433d6423SLionel Sambuc case 3:
344433d6423SLionel Sambuc if (index == SCAN_NUMLOCK) {
345433d6423SLionel Sambuc page = INPUT_PAGE_KEY;
346433d6423SLionel Sambuc code = INPUT_KEY_PAUSE;
347433d6423SLionel Sambuc break;
348433d6423SLionel Sambuc }
349433d6423SLionel Sambuc /* FALLTHROUGH */
350433d6423SLionel Sambuc default:
351433d6423SLionel Sambuc switch (scode) {
352433d6423SLionel Sambuc case SCAN_EXT0:
353433d6423SLionel Sambuc kbd_state = 1;
354433d6423SLionel Sambuc return;
355433d6423SLionel Sambuc case SCAN_EXT1:
356433d6423SLionel Sambuc kbd_state = 2;
357433d6423SLionel Sambuc return;
358433d6423SLionel Sambuc }
359433d6423SLionel Sambuc page = scanmap_normal[index].page;
360433d6423SLionel Sambuc code = scanmap_normal[index].code;
361433d6423SLionel Sambuc break;
362433d6423SLionel Sambuc }
363433d6423SLionel Sambuc
364433d6423SLionel Sambuc if (page)
365433d6423SLionel Sambuc inputdriver_send_event(FALSE /*mouse*/, page, code, press, 0);
366433d6423SLionel Sambuc
367433d6423SLionel Sambuc kbd_state = 0;
368433d6423SLionel Sambuc }
369433d6423SLionel Sambuc
370433d6423SLionel Sambuc /*
371433d6423SLionel Sambuc * Process an auxiliary (mouse) scancode.
372433d6423SLionel Sambuc */
373433d6423SLionel Sambuc static void
kbdaux_process(unsigned char scode)374433d6423SLionel Sambuc kbdaux_process(unsigned char scode)
375433d6423SLionel Sambuc {
376433d6423SLionel Sambuc u32_t delta;
377433d6423SLionel Sambuc int i;
378433d6423SLionel Sambuc
379433d6423SLionel Sambuc if (aux_counter == 0 && !(scode & 0x08))
380433d6423SLionel Sambuc return; /* resync */
381433d6423SLionel Sambuc
382433d6423SLionel Sambuc aux_bytes[aux_counter++] = scode;
383433d6423SLionel Sambuc
384433d6423SLionel Sambuc if (aux_counter < 3)
385433d6423SLionel Sambuc return; /* need more first */
386433d6423SLionel Sambuc
387433d6423SLionel Sambuc aux_counter = 0;
388433d6423SLionel Sambuc
389433d6423SLionel Sambuc /* Send an event for each button state change. */
390433d6423SLionel Sambuc for (i = 0; i < 3; i++) {
391433d6423SLionel Sambuc if ((aux_state ^ aux_bytes[0]) & (1 << i)) {
392433d6423SLionel Sambuc aux_state ^= (1 << i);
393433d6423SLionel Sambuc
394433d6423SLionel Sambuc inputdriver_send_event(TRUE /*mouse*/,
395433d6423SLionel Sambuc INPUT_PAGE_BUTTON, INPUT_BUTTON_1 + i,
3963d310546SLionel Sambuc !!(aux_state & (1 << i)), 0);
397433d6423SLionel Sambuc }
398433d6423SLionel Sambuc }
399433d6423SLionel Sambuc
400433d6423SLionel Sambuc /* Send an event for each relative mouse movement, X and/or Y. */
401433d6423SLionel Sambuc for (i = 0; i < 2; i++) {
402433d6423SLionel Sambuc delta = aux_bytes[1 + i];
403433d6423SLionel Sambuc if (delta != 0) {
404433d6423SLionel Sambuc if (aux_bytes[0] & (0x10 << i))
405433d6423SLionel Sambuc delta |= 0xFFFFFF00; /* make signed */
406433d6423SLionel Sambuc
407433d6423SLionel Sambuc inputdriver_send_event(TRUE /*mouse*/, INPUT_PAGE_GD,
408433d6423SLionel Sambuc !i ? INPUT_GD_X : INPUT_GD_Y, delta,
409433d6423SLionel Sambuc INPUT_FLAG_REL);
410433d6423SLionel Sambuc }
411433d6423SLionel Sambuc }
412433d6423SLionel Sambuc }
413433d6423SLionel Sambuc
414433d6423SLionel Sambuc /*
415433d6423SLionel Sambuc * Set keyboard LEDs.
416433d6423SLionel Sambuc */
417433d6423SLionel Sambuc static void
pckbd_leds(unsigned int leds)418433d6423SLionel Sambuc pckbd_leds(unsigned int leds)
419433d6423SLionel Sambuc {
420433d6423SLionel Sambuc unsigned char b;
421433d6423SLionel Sambuc
422433d6423SLionel Sambuc b = 0;
423433d6423SLionel Sambuc if (leds & (1 << INPUT_LED_NUMLOCK)) b |= LED_NUM_LOCK;
424433d6423SLionel Sambuc if (leds & (1 << INPUT_LED_CAPSLOCK)) b |= LED_CAPS_LOCK;
425433d6423SLionel Sambuc if (leds & (1 << INPUT_LED_SCROLLLOCK)) b |= LED_SCROLL_LOCK;
426433d6423SLionel Sambuc
427433d6423SLionel Sambuc set_leds(b);
428433d6423SLionel Sambuc }
429433d6423SLionel Sambuc
430433d6423SLionel Sambuc /*
431433d6423SLionel Sambuc * Process a keyboard interrupt.
432433d6423SLionel Sambuc */
433433d6423SLionel Sambuc static void
pckbd_intr(unsigned int UNUSED (mask))434433d6423SLionel Sambuc pckbd_intr(unsigned int UNUSED(mask))
435433d6423SLionel Sambuc {
436433d6423SLionel Sambuc unsigned char scode;
437433d6423SLionel Sambuc int isaux;
438433d6423SLionel Sambuc
439433d6423SLionel Sambuc /* Fetch a character from the keyboard hardware and acknowledge it. */
440433d6423SLionel Sambuc if (!scan_keyboard(&scode, &isaux))
441433d6423SLionel Sambuc return;
442433d6423SLionel Sambuc
443433d6423SLionel Sambuc if (!isaux) {
444433d6423SLionel Sambuc /* A keyboard key press or release. */
445433d6423SLionel Sambuc kbd_process(scode);
446433d6423SLionel Sambuc } else {
447433d6423SLionel Sambuc /* A mouse event. */
448433d6423SLionel Sambuc kbdaux_process(scode);
449433d6423SLionel Sambuc }
450433d6423SLionel Sambuc }
451433d6423SLionel Sambuc
452433d6423SLionel Sambuc /*
453433d6423SLionel Sambuc * Process a timer signal.
454433d6423SLionel Sambuc */
455433d6423SLionel Sambuc static void
pckbd_alarm(clock_t stamp)456433d6423SLionel Sambuc pckbd_alarm(clock_t stamp)
457433d6423SLionel Sambuc {
458433d6423SLionel Sambuc expire_timers(stamp);
459433d6423SLionel Sambuc }
460433d6423SLionel Sambuc
461433d6423SLionel Sambuc /*
462433d6423SLionel Sambuc * Initialize the driver.
463433d6423SLionel Sambuc */
464433d6423SLionel Sambuc static int
pckbd_init(int UNUSED (type),sef_init_info_t * UNUSED (info))465433d6423SLionel Sambuc pckbd_init(int UNUSED(type), sef_init_info_t *UNUSED(info))
466433d6423SLionel Sambuc {
4673d310546SLionel Sambuc int flags = INPUT_DEV_KBD;
468433d6423SLionel Sambuc /* Initialize the watchdog timer. */
469433d6423SLionel Sambuc init_timer(&tmr_kbd_wd);
470433d6423SLionel Sambuc
471433d6423SLionel Sambuc /* Initialize the keyboard. */
472e1e2bc96Srlfnb int r;
473e1e2bc96Srlfnb if((r = kb_init())!=OK){
474e1e2bc96Srlfnb return r;
475e1e2bc96Srlfnb }
476433d6423SLionel Sambuc
477433d6423SLionel Sambuc /* Announce the driver's presence. */
4783d310546SLionel Sambuc if (aux_available != 0)
4793d310546SLionel Sambuc flags |= INPUT_DEV_MOUSE;
4803d310546SLionel Sambuc inputdriver_announce(flags);
481433d6423SLionel Sambuc
482433d6423SLionel Sambuc return OK;
483433d6423SLionel Sambuc }
484433d6423SLionel Sambuc
485433d6423SLionel Sambuc /*
486433d6423SLionel Sambuc * Set callback routines and let SEF initialize.
487433d6423SLionel Sambuc */
488433d6423SLionel Sambuc static void
pckbd_startup(void)489433d6423SLionel Sambuc pckbd_startup(void)
490433d6423SLionel Sambuc {
491433d6423SLionel Sambuc sef_setcb_init_fresh(pckbd_init);
492433d6423SLionel Sambuc
493433d6423SLionel Sambuc sef_startup();
494433d6423SLionel Sambuc }
495433d6423SLionel Sambuc
496433d6423SLionel Sambuc /*
497433d6423SLionel Sambuc * PC keyboard/mouse driver task.
498433d6423SLionel Sambuc */
499433d6423SLionel Sambuc int
main(void)500433d6423SLionel Sambuc main(void)
501433d6423SLionel Sambuc {
502433d6423SLionel Sambuc pckbd_startup();
503433d6423SLionel Sambuc
504433d6423SLionel Sambuc inputdriver_task(&pckbd_tab);
505433d6423SLionel Sambuc
506433d6423SLionel Sambuc return 0;
507433d6423SLionel Sambuc }
508