]> Zhao Yanbai Git Server - minix.git/commitdiff
Raw keyboard and AUX support. Needs cleaning up.
authorPhilip Homburg <philip@cs.vu.nl>
Mon, 24 Oct 2005 13:57:19 +0000 (13:57 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Mon, 24 Oct 2005 13:57:19 +0000 (13:57 +0000)
drivers/tty/console.c
drivers/tty/keyboard.c
drivers/tty/rs232.c
drivers/tty/tty.c
drivers/tty/tty.h

index 0a752870d9cd7088eceafad4508b736144660159..15deeb98de0b4f742924f4f2edd6ebbd7d594db3 100644 (file)
@@ -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);
+}
index b82094aa887fb8c94eab1c17d8cdab5c4806ceff..dae40932c8a9f98fe079bead6df4034ea1652193 100644 (file)
@@ -7,6 +7,8 @@
  */
 
 #include "../drivers.h"
+#include <sys/ioctl.h>
+#include <sys/kbdio.h>
 #include <sys/time.h>
 #include <sys/select.h>
 #include <termios.h>
@@ -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; i<m->COUNT; 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;
+}
index 3e28c5b36f5ef43ab598d9dca667c95c954fb4d5..620ad8b88c4b072ad8467923911dc3496d738a2b 100644 (file)
@@ -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);
 }
 
 /*===========================================================================*
index c1448ead768a694fda072051905de4def84899c3..bcf8e2ebeef3d00d5c2133d592c28f2777616259 100644 (file)
@@ -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");
 }
 
 /*===========================================================================*
index 298ffbc2ff8db363b5ce75b33c1fd62aa5ff258d..433d4ed88ec62a391237b5d8804f1db546d01b55 100644 (file)
@@ -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)              );