From: Philip Homburg Date: Mon, 24 Oct 2005 13:57:19 +0000 (+0000) Subject: Raw keyboard and AUX support. Needs cleaning up. X-Git-Tag: v3.1.2a~545 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/doxygen.log?a=commitdiff_plain;h=0b5a135a673349d8f6afd181184e714889965abd;p=minix.git Raw keyboard and AUX support. Needs cleaning up. --- diff --git a/drivers/tty/console.c b/drivers/tty/console.c index 0a752870d..15deeb98d 100644 --- a/drivers/tty/console.c +++ b/drivers/tty/console.c @@ -48,6 +48,9 @@ #define VID_ORG 12 /* 6845's origin register */ #define CURSOR 14 /* 6845's cursor register */ +/* The clock task should provide an interface for this */ +#define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */ + /* Beeper. */ #define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */ #define B_TIME 3 /* length of CTRL-G beep is ticks */ @@ -130,6 +133,7 @@ FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp) ); FORWARD _PROTOTYPE( void cons_org0, (void) ); FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq) ); FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int) ); +PRIVATE _PROTOTYPE( void ser_putc, (char c) ); /*===========================================================================* * cons_write * @@ -761,6 +765,50 @@ PRIVATE void beep() } } + +/*===========================================================================* + * beep_x * + *===========================================================================*/ +PUBLIC void beep_x(freq, dur) +unsigned freq; +clock_t dur; +{ +/* Making a beeping sound on the speaker. + * This routine works by turning on the bits 0 and 1 in port B of the 8255 + * chip that drive the speaker. + */ + static timer_t tmr_stop_beep; + pvb_pair_t char_out[3]; + clock_t now; + int port_b_val, s; + + unsigned long ival= TIMER_FREQ / freq; + if (ival == 0 || ival > 0xffff) + return; /* Frequency out of range */ + + /* Fetch current time in advance to prevent beeping delay. */ + if ((s=getuptime(&now)) != OK) + panic("TTY","Console couldn't get clock's uptime.", s); + if (!beeping) { + /* Set timer channel 2, square wave, with given frequency. */ + pv_set(char_out[0], TIMER_MODE, 0xB6); + pv_set(char_out[1], TIMER2, (ival >> 0) & BYTE); + pv_set(char_out[2], TIMER2, (ival >> 8) & BYTE); + if (sys_voutb(char_out, 3)==OK) { + if (sys_inb(PORT_B, &port_b_val)==OK && + sys_outb(PORT_B, (port_b_val|3))==OK) + beeping = TRUE; + } + } + /* Add a timer to the timers list. Possibly reschedule the alarm. */ + tmrs_settimer(&tty_timers, &tmr_stop_beep, now+dur, stop_beep, NULL); + if (tty_timers->tmr_exp_time != tty_next_timeout) { + tty_next_timeout = tty_timers->tmr_exp_time; + if ((s=sys_setalarm(tty_next_timeout, 1)) != OK) + panic("TTY","Console couldn't set alarm.", s); + } +} + /*===========================================================================* * stop_beep * *===========================================================================*/ @@ -797,9 +845,6 @@ tty_t *tp; cons->c_tty = tp; tp->tty_priv = cons; - /* Initialize the keyboard driver. */ - kb_init(tp); - /* Fill in TTY function hooks. */ tp->tty_devwrite = cons_write; tp->tty_echo = cons_echo; @@ -876,12 +921,16 @@ tty_t *tp; PUBLIC void kputc(c) int c; { -#if 0 - cons_putk(c); -#else /* Accumulate a single character for a kernel message. Send a notification * the to output driver if an END_OF_KMESS is encountered. */ +#if 0 + ser_putc(c); + return; +#endif + + if (panicing) + cons_putk(c); if (c != 0) { kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */ if (kmess.km_size < KMESS_BUF_SIZE) @@ -890,7 +939,6 @@ int c; } else { notify(LOG_PROC_NR); } -#endif } /*===========================================================================* @@ -1137,3 +1185,25 @@ int try; tp->tty_winsize.ws_xpixel= scr_width * 8; tp->tty_winsize.ws_ypixel= scr_lines * font_lines; } + +#define COM1_BASE 0x3F8 +#define COM1_THR (COM1_BASE + 0) +#define LSR_THRE 0x20 +#define COM1_LSR (COM1_BASE + 5) + +PRIVATE void ser_putc(char c) +{ + unsigned long b; + int i; + int lsr, thr; + + lsr= COM1_LSR; + thr= COM1_THR; + for (i= 0; i<100; i++) + { + sys_inb(lsr, &b); + if (b & LSR_THRE) + break; + } + sys_outb(thr, c); +} diff --git a/drivers/tty/keyboard.c b/drivers/tty/keyboard.c index b82094aa8..dae40932c 100644 --- a/drivers/tty/keyboard.c +++ b/drivers/tty/keyboard.c @@ -7,6 +7,8 @@ */ #include "../drivers.h" +#include +#include #include #include #include @@ -23,6 +25,7 @@ #include "../../kernel/proc.h" int irq_hook_id = -1; +int aux_irq_hook_id = -1; /* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */ #define KEYBD 0x60 /* I/O port for keyboard data */ @@ -31,13 +34,23 @@ int irq_hook_id = -1; #define KB_COMMAND 0x64 /* I/O port for commands on AT */ #define KB_STATUS 0x64 /* I/O port for status on AT */ #define KB_ACK 0xFA /* keyboard ack response */ +#define KB_AUX_BYTE 0x20 /* Auxiliary Device Output Buffer Full */ #define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */ #define KB_IN_FULL 0x02 /* status bit set when not ready to receive */ +#define KBC_RD_RAM_CCB 0x20 /* Read controller command byte */ +#define KBC_WR_RAM_CCB 0x60 /* Write controller command byte */ +#define KBC_DI_AUX 0xA7 /* Disable Auxiliary Device */ +#define KBC_EN_AUX 0xA8 /* Enable Auxiliary Device */ +#define KBC_DI_KBD 0xAD /* Disable Keybard Interface */ +#define KBC_EN_KBD 0xAE /* Enable Keybard Interface */ +#define KBC_WRITE_AUX 0xD4 /* Write to Auxiliary Device */ #define LED_CODE 0xED /* command to keyboard to set LEDs */ #define MAX_KB_ACK_RETRIES 0x1000 /* max #times to wait for kb ack */ #define MAX_KB_BUSY_RETRIES 0x1000 /* max #times to loop while kb busy */ #define KBIT 0x80 /* bit used to ack characters to keyboard */ +#define KBC_IN_DELAY 7 /* wait 7 microseconds when polling */ + /* Miscellaneous. */ #define ESC_SCAN 0x01 /* reboot key when panicking */ #define SLASH_SCAN 0x35 /* to recognize numeric slash */ @@ -46,6 +59,13 @@ int irq_hook_id = -1; #define INS_SCAN 0x52 /* INS for use in CTRL-ALT-INS reboot */ #define DEL_SCAN 0x53 /* DEL for use in CTRL-ALT-DEL reboot */ +#define KBD_BUFSZ 64 /* Buffer size for raw scan codes */ +#define KBD_OUT_BUFSZ 16 /* Output buffer to sending data to the + * keyboard. + */ + +#define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1) + #define CONSOLE 0 /* line number for console */ #define KB_IN_BYTES 32 /* size of keyboard input buffer */ PRIVATE char ibuf[KB_IN_BYTES]; /* input buffer */ @@ -81,15 +101,309 @@ typedef struct observer { int proc_nr; int events; } obs_t; PRIVATE obs_t fkey_obs[12]; /* observers for F1-F12 */ PRIVATE obs_t sfkey_obs[12]; /* observers for SHIFT F1-F12 */ +PRIVATE struct kbd +{ + int minor; + int nr_open; + char buf[KBD_BUFSZ]; + int offset; + int avail; + int req_size; + int req_proc; + vir_bytes req_addr; + int incaller; + int select_ops; + int select_proc; +} kbd, kbdaux; + +/* Data that is to be sent to the keyboard. Each byte is ACKed by the + * keyboard. + */ +PRIVATE struct kbd_outack +{ + unsigned char buf[KBD_OUT_BUFSZ]; + int offset; + int avail; + int expect_ack; +} kbdout; + +PRIVATE int kbd_watchdog_set= 0; +PRIVATE int kbd_alive= 1; +PRIVATE timer_t tmr_kbd_wd; + +FORWARD _PROTOTYPE( void handle_req, (struct kbd *kbdp, message *m) ); +FORWARD _PROTOTYPE( int handle_status, (struct kbd *kbdp, message *m) ); +FORWARD _PROTOTYPE( void kbc_cmd0, (int cmd) ); +FORWARD _PROTOTYPE( void kbc_cmd1, (int cmd, int data) ); +FORWARD _PROTOTYPE( int kbc_read, (void) ); +FORWARD _PROTOTYPE( void kbd_send, (void) ); FORWARD _PROTOTYPE( int kb_ack, (void) ); FORWARD _PROTOTYPE( int kb_wait, (void) ); FORWARD _PROTOTYPE( int func_key, (int scode) ); -FORWARD _PROTOTYPE( int scan_keyboard, (void) ); +FORWARD _PROTOTYPE( int scan_keyboard, (unsigned char *bp, int *isauxp) ); FORWARD _PROTOTYPE( unsigned make_break, (int scode) ); FORWARD _PROTOTYPE( void set_leds, (void) ); FORWARD _PROTOTYPE( void show_key_mappings, (void) ); FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try) ); FORWARD _PROTOTYPE( unsigned map_key, (int scode) ); +FORWARD _PROTOTYPE( void micro_delay, (unsigned long usecs) ); +FORWARD _PROTOTYPE( void kbd_watchdog, (timer_t *tmrp) ); + +/*===========================================================================* + * do_kbd * + *===========================================================================*/ +PUBLIC void do_kbd(message *m) +{ + handle_req(&kbd, m); +} + + +/*===========================================================================* + * kbd_status * + *===========================================================================*/ +PUBLIC int kbd_status(message *m) +{ + int r; + + r= handle_status(&kbd, m); + if (r) + return r; + return handle_status(&kbdaux, m); +} + + +/*===========================================================================* + * do_kbdaux * + *===========================================================================*/ +PUBLIC void do_kbdaux(message *m) +{ + handle_req(&kbdaux, m); +} + + +/*===========================================================================* + * handle_req * + *===========================================================================*/ +PRIVATE void handle_req(kbdp, m) +struct kbd *kbdp; +message *m; +{ + int i, n, r, ops, watch; + unsigned char c; + + /* Execute the requested device driver function. */ + r= EINVAL; /* just in case */ + switch (m->m_type) { + case DEV_OPEN: + kbdp->nr_open++; + r= OK; + break; + case DEV_CLOSE: + kbdp->nr_open--; + if (kbdp->nr_open < 0) + { + printf("TTY(kbd): open count is negative\n"); + kbdp->nr_open= 0; + } + if (kbdp->nr_open == 0) + kbdp->avail= 0; + r= OK; + break; + case DEV_READ: + if (kbdp->req_size) + { + /* We handle only request at a time */ + r= EIO; + break; + } + if (kbdp->avail == 0) + { + /* Should record proc */ + kbdp->req_size= m->COUNT; + kbdp->req_proc= m->PROC_NR; + kbdp->req_addr= (vir_bytes)m->ADDRESS; + kbdp->incaller= m->m_source; + r= SUSPEND; + break; + } + + /* Handle read request */ + n= kbdp->avail; + if (n > m->COUNT) + n= m->COUNT; + if (kbdp->offset + n > KBD_BUFSZ) + n= KBD_BUFSZ-kbdp->offset; + if (n <= 0) + panic("TTY", "do_kbd(READ): bad n", n); + r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset], + m->PROC_NR, D, (vir_bytes) m->ADDRESS, n); + if (r == OK) + { + kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ; + kbdp->avail -= n; + r= n; + } + + break; + + case DEV_WRITE: + if (kbdp != &kbdaux) + { + printf("write to keyboard not implemented\n"); + r= EINVAL; + break; + } + + /* Assume that output to AUX only happens during + * initialization and we can afford to lose input. This should + * be fixed at a later time. + */ + for (i= 0; iCOUNT; i++) + { + r= sys_vircopy(m->PROC_NR, D, (vir_bytes) m->ADDRESS+i, + SELF, D, (vir_bytes)&c, 1); + if (r != OK) + break; + kbc_cmd1(KBC_WRITE_AUX, c); + } + r= i; + break; + + case CANCEL: + kbdp->req_size= 0; + r= OK; + break; + case DEV_SELECT: + ops = m->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR); + watch = (m->PROC_NR & SEL_NOTIFY) ? 1 : 0; + + r= 0; + if (kbdp->avail && (ops & SEL_RD)) + { + r |= SEL_RD; + break; + } + + if (ops && watch) + { + kbdp->select_ops |= ops; + kbdp->select_proc= m->m_source; + } + break; + case DEV_IOCTL: + if (kbdp == &kbd && m->TTY_REQUEST == KIOCSLEDS) + { + kio_leds_t leds; + unsigned char b; + + r= sys_vircopy(m->PROC_NR, D, (vir_bytes) m->ADDRESS, + SELF, D, (vir_bytes)&leds, sizeof(leds)); + if (r != OK) + break; + b= 0; + if (leds.kl_bits & KBD_LEDS_NUM) b |= NUM_LOCK; + if (leds.kl_bits & KBD_LEDS_CAPS) b |= CAPS_LOCK; + if (leds.kl_bits & KBD_LEDS_SCROLL) b |= SCROLL_LOCK; + if (kbdout.avail == 0) + kbdout.offset= 0; + if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ) + { + /* Output buffer is full. Ignore this command. + * Reset ACK flag. + */ + kbdout.expect_ack= 0; + } + else + { + kbdout.buf[kbdout.offset+kbdout.avail]= + LED_CODE; + kbdout.buf[kbdout.offset+kbdout.avail+1]= b; + kbdout.avail += 2; + } + if (!kbdout.expect_ack) + kbd_send(); + r= OK; + break; + } + if (kbdp == &kbd && m->TTY_REQUEST == KIOCBELL) + { + kio_bell_t bell; + clock_t ticks; + + r= sys_vircopy(m->PROC_NR, D, (vir_bytes) m->ADDRESS, + SELF, D, (vir_bytes)&bell, sizeof(bell)); + if (r != OK) + break; + + ticks= bell.kb_duration.tv_usec * HZ / 1000000; + ticks += bell.kb_duration.tv_sec * HZ; + if (!ticks) + ticks++; + beep_x(bell.kb_pitch, ticks); + + r= OK; + break; + } + r= ENOTTY; + break; + + default: + printf("Warning, TTY(kbd) got unexpected request %d from %d\n", + m->m_type, m->m_source); + r= EINVAL; + } + tty_reply(TASK_REPLY, m->m_source, m->PROC_NR, r); +} + + +/*===========================================================================* + * handle_status * + *===========================================================================*/ +PRIVATE int handle_status(kbdp, m) +struct kbd *kbdp; +message *m; +{ + int n, r; + + if (kbdp->avail && kbdp->req_size && m->m_source == kbdp->incaller) + { + /* Handle read request */ + n= kbdp->avail; + if (n > kbdp->req_size) + n= kbdp->req_size; + if (kbdp->offset + n > KBD_BUFSZ) + n= KBD_BUFSZ-kbdp->offset; + if (n <= 0) + panic("TTY", "kbd_status: bad n", n); + kbdp->req_size= 0; + r= sys_vircopy(SELF, D, (vir_bytes)&kbdp->buf[kbdp->offset], + kbdp->req_proc, D, kbdp->req_addr, n); + if (r == OK) + { + kbdp->offset= (kbdp->offset+n) % KBD_BUFSZ; + kbdp->avail -= n; + r= n; + } + + m->m_type = DEV_REVIVE; + m->REP_PROC_NR= kbdp->req_proc; + m->REP_STATUS= r; + return 1; + } + if (kbdp->avail && (kbdp->select_ops & SEL_RD) && + m->m_source == kbdp->select_proc) + { + m->m_type = DEV_IO_READY; + m->DEV_MINOR = kbdp->minor; + m->DEV_SEL_OPS = SEL_RD; + + kbdp->select_ops &= ~SEL_RD; + return 1; + } + + return 0; +} + /*===========================================================================* * map_key0 * @@ -137,11 +451,36 @@ PUBLIC void kbd_interrupt(m_ptr) message *m_ptr; { /* A keyboard interrupt has occurred. Process it. */ - int scode; + int o, isaux; + unsigned char scode; + struct kbd *kbdp; static timer_t timer; /* timer must be static! */ /* Fetch the character from the keyboard hardware and acknowledge it. */ - scode = scan_keyboard(); + if (!scan_keyboard(&scode, &isaux)) + return; + + if (isaux) + kbdp= &kbdaux; + else if (kbd.nr_open && !panicing) + kbdp= &kbd; + else + kbdp= NULL; + + if (kbdp) + { + /* raw scan codes or aux data */ + if (kbdp->avail >= KBD_BUFSZ) + return; /* Buffer is full */ + o= (kbdp->offset + kbdp->avail) % KBD_BUFSZ; + kbdp->buf[o]= scode; + kbdp->avail++; + if (kbdp->req_size) + notify(kbdp->incaller); + if (kbdp->select_ops & SEL_RD) + notify(kbdp->select_proc); + return; + } /* Store the scancode in memory so the task can get at it later. */ if (icount < KB_IN_BYTES) { @@ -226,6 +565,62 @@ int try; return 1; } +/*===========================================================================* + * kbd_send * + *===========================================================================*/ +PRIVATE void kbd_send() +{ + unsigned long sb; + int r; + clock_t now; + + if (!kbdout.avail) + return; + if (kbdout.expect_ack) + return; + + sys_inb(KB_STATUS, &sb); + if (sb & (KB_OUT_FULL|KB_IN_FULL)) + { + printf("not sending 1: sb = 0x%x\n", sb); + return; + } + micro_delay(KBC_IN_DELAY); + sys_inb(KB_STATUS, &sb); + if (sb & (KB_OUT_FULL|KB_IN_FULL)) + { + printf("not sending 2: sb = 0x%x\n", sb); + return; + } + + /* Okay, buffer is really empty */ +#if 0 + printf("sending byte 0x%x to keyboard\n", kbdout.buf[kbdout.offset]); +#endif + sys_outb(KEYBD, kbdout.buf[kbdout.offset]); + kbdout.offset++; + kbdout.avail--; + kbdout.expect_ack= 1; + + kbd_alive= 1; + if (kbd_watchdog_set) + { + /* Add a timer to the timers list. Possibly reschedule the + * alarm. + */ + if ((r= getuptime(&now)) != OK) + panic("TTY","Keyboard couldn't get clock's uptime.", r); + tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+HZ, kbd_watchdog, + NULL); + if (tty_timers->tmr_exp_time != tty_next_timeout) { + tty_next_timeout = tty_timers->tmr_exp_time; + if ((r= sys_setalarm(tty_next_timeout, 1)) != OK) + panic("TTY","Keyboard couldn't set alarm.", r); + } + kbd_watchdog_set= 1; + } +} + /*===========================================================================* * make_break * *===========================================================================*/ @@ -312,6 +707,8 @@ PRIVATE void set_leds() int s; if (! machine.pc_at) return; /* PC/XT doesn't have LEDs */ + printf("in set_leds\n"); + kb_wait(); /* wait for buffer empty */ if ((s=sys_outb(KEYBD, LED_CODE)) != OK) printf("Warning, sys_outb couldn't prepare for LED values: %d\n", s); @@ -325,6 +722,77 @@ PRIVATE void set_leds() kb_ack(); /* wait for ack response */ } +/*===========================================================================* + * kbc_cmd0 * + *===========================================================================*/ +PRIVATE void kbc_cmd0(cmd) +int cmd; +{ + kb_wait(); + sys_outb(KB_COMMAND, cmd); +} + +/*===========================================================================* + * kbc_cmd1 * + *===========================================================================*/ +PRIVATE void kbc_cmd1(cmd, data) +int cmd; +int data; +{ + kb_wait(); + sys_outb(KB_COMMAND, cmd); + kb_wait(); + sys_outb(KEYBD, data); +} + + +/*===========================================================================* +* kbc_read * +*===========================================================================*/ +PRIVATE int kbc_read() +{ + int i; + unsigned long byte, st; +#if 0 + struct micro_state ms; +#endif + + printf("in kbc_read\n"); + + /* Wait at most 1 second for a byte from the keyboard or + * the kbd controller, return -1 on a timeout. + */ + for (i= 0; i<1000; i++) + #if 0 + micro_start(&ms); + do +#endif + { + sys_inb(KB_STATUS, &st); + if (st & KB_OUT_FULL) + { + micro_delay(KBC_IN_DELAY); + sys_inb(KEYBD, &byte); + if (st & KB_AUX_BYTE) + { + printf( + "keyboard`kbc_read: ignoring byte (0x%x) from aux device.\n", + byte); + continue; + } + printf("keyboard`kbc_read: returning byte 0x%x\n", + byte); + return byte; + } + } +#if 0 + while (micro_elapsed(&ms) < 1000000); +#endif + panic("TTY", "kbc_read failed to complete", NO_NUM); +} + + + /*===========================================================================* * kb_wait * *===========================================================================*/ @@ -332,14 +800,21 @@ PRIVATE int kb_wait() { /* Wait until the controller is ready; return zero if this times out. */ - int retries, status, temp; - int s; + int retries; + unsigned long status, temp; + int s, isaux; + unsigned char byte; + + printf("in kb_wait\n"); retries = MAX_KB_BUSY_RETRIES + 1; /* wait until not busy */ do { s = sys_inb(KB_STATUS, &status); if (status & KB_OUT_FULL) { - s = sys_inb(KEYBD, &temp); /* discard value */ + if (scan_keyboard(&byte, &isaux)) + { + printf("ignoring %sbyte in kb_wait\n", isaux ? "AUX " : ""); + } } if (! (status & (KB_IN_FULL|KB_OUT_FULL)) ) break; /* wait until ready */ @@ -355,10 +830,13 @@ PRIVATE int kb_ack() /* Wait until kbd acknowledges last command; return zero if this times out. */ int retries, s; - u8_t u8val; + unsigned long u8val; + + printf("in kb_ack\n"); retries = MAX_KB_ACK_RETRIES + 1; do { + printf("ignoring byte in kb_ack\n"); s = sys_inb(KEYBD, &u8val); if (u8val == KB_ACK) break; /* wait for ack */ @@ -384,9 +862,10 @@ tty_t *tp; PUBLIC void kb_init_once(void) { int i; + u8_t ccb; set_leds(); /* turn off numlock led */ - scan_keyboard(); /* discard leftover keystroke */ + scan_keyboard(NULL, NULL); /* discard leftover keystroke */ /* Clear the function key observers array. Also see func_key(). */ for (i=0; i<12; i++) { @@ -396,6 +875,9 @@ PUBLIC void kb_init_once(void) sfkey_obs[i].events = 0; /* Shift F1-F12 observers */ } + kbd.minor= KBD_MINOR; + kbdaux.minor= KBDAUX_MINOR; + /* Set interrupt handler and enable keyboard IRQ. */ irq_hook_id = KEYBOARD_IRQ; /* id to be returned on interrupt */ if ((i=sys_irqsetpolicy(KEYBOARD_IRQ, IRQ_REENABLE, &irq_hook_id)) != OK) @@ -403,6 +885,32 @@ PUBLIC void kb_init_once(void) if ((i=sys_irqenable(&irq_hook_id)) != OK) panic("TTY", "Couldn't enable keyboard IRQs", i); kbd_irq_set |= (1 << KEYBOARD_IRQ); + + /* Set AUX interrupt handler and enable AUX IRQ. */ + aux_irq_hook_id = KBD_AUX_IRQ; /* id to be returned on interrupt */ + if ((i=sys_irqsetpolicy(KBD_AUX_IRQ, IRQ_REENABLE, + &aux_irq_hook_id)) != OK) + panic("TTY", "Couldn't set AUX IRQ policy", i); + if ((i=sys_irqenable(&aux_irq_hook_id)) != OK) + panic("TTY", "Couldn't enable AUX IRQs", i); + kbd_irq_set |= (1 << KBD_AUX_IRQ); + + /* Disable the keyboard and aux */ + kbc_cmd0(KBC_DI_KBD); + kbc_cmd0(KBC_DI_AUX); + + /* Get the current configuration byte */ + kbc_cmd0(KBC_RD_RAM_CCB); + ccb= kbc_read(); + + /* Enable both interrupts. */ + kbc_cmd1(KBC_WR_RAM_CCB, ccb | 3); + + /* Re-enable the keyboard device. */ + kbc_cmd0(KBC_EN_KBD); + + /* Enable the aux device. */ + kbc_cmd0(KBC_EN_AUX); } /*===========================================================================* @@ -610,8 +1118,11 @@ PRIVATE void show_key_mappings() /*===========================================================================* * scan_keyboard * *===========================================================================*/ -PRIVATE int scan_keyboard() +PRIVATE int scan_keyboard(bp, isauxp) +unsigned char *bp; +int *isauxp; { +#if 0 /* Is this old XT code? It doesn't match the PS/2 hardware */ /* Fetch the character from the keyboard hardware and acknowledge it. */ pvb_pair_t byte_in[2], byte_out[2]; @@ -624,6 +1135,41 @@ PRIVATE int scan_keyboard() sys_voutb(byte_out, 2); /* request actual output */ return(byte_in[0].value); /* return scan code */ +#else + unsigned long b, sb; + + sys_inb(KB_STATUS, &sb); + if (!(sb & KB_OUT_FULL)) + { + if (kbdout.avail && !kbdout.expect_ack) + kbd_send(); + return 0; + } + sys_inb(KEYBD, &b); +#if 0 + printf("got byte 0x%x from %s\n", b, (sb & KB_AUX_BYTE) ? "AUX" : "keyboard"); +#endif + if (!(sb & KB_AUX_BYTE) && b == KB_ACK && kbdout.expect_ack) + { +#if 1 + printf("got ACK from keyboard\n"); +#endif + kbdout.expect_ack= 0; + micro_delay(KBC_IN_DELAY); + kbd_send(); + return 0; + } + if (bp) + *bp= b; + if (isauxp) + *isauxp= !!(sb & KB_AUX_BYTE); + if (kbdout.avail && !kbdout.expect_ack) + { + micro_delay(KBC_IN_DELAY); + kbd_send(); + } + return 1; +#endif } /*===========================================================================* @@ -633,13 +1179,13 @@ PUBLIC void do_panic_dumps(m) message *m; /* request message to TTY */ { /* Wait for keystrokes for printing debugging info and reboot. */ - int quiet, code; + unsigned char code; + int isaux; /* A panic! Allow debug dumps until user wants to shutdown. */ printf("\nHit ESC to reboot, DEL to shutdown, F-keys for debug dumps\n"); - (void) scan_keyboard(); /* ack any old input */ - quiet = scan_keyboard();/* quiescent value (0 on PC, last code on AT)*/ + (void) scan_keyboard(NULL, NULL); /* ack any old input */ for (;;) { tickdelay(10); /* See if there are pending request for output, but don't block. @@ -654,16 +1200,51 @@ message *m; /* request message to TTY */ } tickdelay(1); /* allow more */ } - code = scan_keyboard(); - if (code != quiet) { - /* A key has been pressed. */ - switch (code) { /* possibly abort MINIX */ - case ESC_SCAN: sys_abort(RBT_REBOOT); return; - case DEL_SCAN: sys_abort(RBT_HALT); return; - } - (void) func_key(code); /* check for function key */ - quiet = scan_keyboard(); + if (!scan_keyboard(&code, &isaux)) + continue; + if (isaux) + continue; + + /* A key has been pressed. */ + switch (code) { /* possibly abort MINIX */ + case ESC_SCAN: sys_abort(RBT_REBOOT); return; + case DEL_SCAN: sys_abort(RBT_HALT); return; } + (void) func_key(code); /* check for function key */ } } +static void micro_delay(unsigned long usecs) +{ + tickdelay(MICROS_TO_TICKS(usecs)); +} + +/*===========================================================================* + * kbd_watchdog * + *===========================================================================*/ +PRIVATE void kbd_watchdog(tmrp) +timer_t *tmrp; +{ + int r; + clock_t now; + + kbd_watchdog_set= 0; + if (!kbdout.avail) + return; /* Watchdog is no longer needed */ + if (!kbd_alive) + { + printf("kbd_watchdog: should reset keyboard\n"); + } + kbd_alive= 0; + + if ((r= getuptime(&now)) != OK) + panic("TTY","Keyboard couldn't get clock's uptime.", r); + tmrs_settimer(&tty_timers, &tmr_kbd_wd, now+HZ, kbd_watchdog, + NULL); + if (tty_timers->tmr_exp_time != tty_next_timeout) { + tty_next_timeout = tty_timers->tmr_exp_time; + if ((r= sys_setalarm(tty_next_timeout, 1)) != OK) + panic("TTY","Keyboard couldn't set alarm.", r); + } + kbd_watchdog_set= 1; +} diff --git a/drivers/tty/rs232.c b/drivers/tty/rs232.c index 3e28c5b36..620ad8b88 100644 --- a/drivers/tty/rs232.c +++ b/drivers/tty/rs232.c @@ -886,7 +886,11 @@ register rs232_t *rs; /* line with input interrupt */ } } - if (rs->icount == buflen(rs->ibuf)) return; /* input buffer full, discard */ + if (rs->icount == buflen(rs->ibuf)) + { + printf("in_int: discarding byte\n"); + return; /* input buffer full, discard */ + } if (++rs->icount == RS_IHIGHWATER && rs->idevready) istop(rs); *rs->ihead = c; @@ -895,6 +899,8 @@ register rs232_t *rs; /* line with input interrupt */ rs->tty->tty_events = 1; force_timeout(); } + else + printf("in_int: icount = %d\n", rs->icount); } /*===========================================================================* diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c index c1448ead7..bcf8e2ebe 100644 --- a/drivers/tty/tty.c +++ b/drivers/tty/tty.c @@ -166,6 +166,15 @@ PUBLIC void main(void) register struct proc *rp; register tty_t *tp; + kputc('H'); + kputc('e'); + kputc('l'); + kputc('l'); + kputc('o'); + kputc(','); + kputc(' '); + printf("TTY\n"); + /* Initialize the TTY driver. */ tty_init(); @@ -257,7 +266,13 @@ PUBLIC void main(void) continue; } line = tty_mess.TTY_LINE; - if ((line - CONS_MINOR) < NR_CONS) { + if (line == KBD_MINOR) { + do_kbd(&tty_mess); + continue; + } else if (line == KBDAUX_MINOR) { + do_kbdaux(&tty_mess); + continue; + } else if ((line - CONS_MINOR) < NR_CONS) { tp = tty_addr(line - CONS_MINOR); } else if (line == LOG_MINOR) { tp = tty_addr(0); @@ -364,6 +379,8 @@ message *m_ptr; if (!event_found) event_found = pty_status(m_ptr); #endif + if (!event_found) + event_found= kbd_status(m_ptr); if (! event_found) { /* No events of interest were found. Return an empty message. */ @@ -386,18 +403,22 @@ register message *m_ptr; /* pointer to message sent to the task */ /* A process wants to read from a terminal. */ int r, status; phys_bytes phys_addr; + int more_verbose= (tp == tty_addr(NR_CONS)); /* Check if there is already a process hanging in a read, check if the * parameters are correct, do I/O. */ if (tp->tty_inleft > 0) { + if (more_verbose) printf("do_read: EIO\n"); r = EIO; } else if (m_ptr->COUNT <= 0) { + if (more_verbose) printf("do_read: EINVAL\n"); r = EINVAL; } else if (sys_umap(m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT, &phys_addr) != OK) { + if (more_verbose) printf("do_read: EFAULT\n"); r = EFAULT; } else { /* Copy information from the message to the tty struct. */ @@ -447,6 +468,7 @@ register message *m_ptr; /* pointer to message sent to the task */ tp->tty_inrepcode = REVIVE; } } + if (more_verbose) printf("do_read: replying %d\n", r); tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r); if (tp->tty_select_ops) select_retry(tp); @@ -830,13 +852,12 @@ PUBLIC int select_try(struct tty *tp, int ops) if (tp->tty_outleft > 0) ready_ops |= SEL_WR; else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR; } - return ready_ops; } PUBLIC int select_retry(struct tty *tp) { - if (select_try(tp, tp->tty_select_ops)) + if (tp->tty_select_ops && select_try(tp, tp->tty_select_ops)) notify(tp->tty_select_proc); return OK; } @@ -892,7 +913,9 @@ tty_t *tp; /* TTY to check for events. */ } } if (tp->tty_select_ops) + { select_retry(tp); + } #if NR_PTYS > 0 if (ispty(tp)) select_retry_pty(tp); @@ -1521,6 +1544,10 @@ PRIVATE void tty_init() tty_devnop; if (tp < tty_addr(NR_CONS)) { scr_init(tp); + + /* Initialize the keyboard driver. */ + kb_init(tp); + tp->tty_minor = CONS_MINOR + s; } else if (tp < tty_addr(NR_CONS+NR_RS_LINES)) { @@ -1541,6 +1568,7 @@ PRIVATE void tty_init() if (sigaction(SIGKMESS,&sa,NULL)<0) panic("TTY","sigaction failed", errno); if (sigaction(SIGKSTOP,&sa,NULL)<0) panic("TTY","sigaction failed", errno); #endif + printf("end of tty_init\n"); } /*===========================================================================* diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index 298ffbc2f..433d4ed88 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -9,6 +9,8 @@ /* First minor numbers for the various classes of TTY devices. */ #define CONS_MINOR 0 +#define KBD_MINOR 13 +#define KBDAUX_MINOR 14 #define LOG_MINOR 15 #define RS232_MINOR 16 #define TTYPX_MINOR 128 @@ -101,6 +103,8 @@ extern int irq_hook_id; /* hook id for keyboard irq */ extern unsigned long kbd_irq_set; extern unsigned long rs_irq_set; +extern int panicing; /* From panic.c in sysutil */ + /* Values for the fields. */ #define NOT_ESCAPED 0 /* previous character is not LNEXT (^V) */ #define ESCAPED 1 /* previous character was LNEXT (^V) */ @@ -162,6 +166,7 @@ _PROTOTYPE( void scr_init, (struct tty *tp) ); _PROTOTYPE( void toggle_scroll, (void) ); _PROTOTYPE( int con_loadfont, (message *m) ); _PROTOTYPE( void select_console, (int cons_line) ); +_PROTOTYPE( void beep_x, ( unsigned freq, clock_t dur) ); /* keyboard.c */ _PROTOTYPE( void kb_init, (struct tty *tp) ); @@ -170,6 +175,9 @@ _PROTOTYPE( int kbd_loadmap, (message *m) ); _PROTOTYPE( void do_panic_dumps, (message *m) ); _PROTOTYPE( void do_fkey_ctl, (message *m) ); _PROTOTYPE( void kbd_interrupt, (message *m) ); +_PROTOTYPE( void do_kbd, (message *m) ); +_PROTOTYPE( void do_kbdaux, (message *m) ); +_PROTOTYPE( int kbd_status, (message *m_ptr) ); /* pty.c */ _PROTOTYPE( void do_pty, (struct tty *tp, message *m_ptr) );