/[qemu]/qemu/hw/pckbd.c
ViewVC logotype

Diff of /qemu/hw/pckbd.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.12 by bellard, Mon Nov 21 23:29:55 2005 UTC revision 1.13 by bellard, Sat Nov 26 10:14:03 2005 UTC
# Line 110  Line 110 
110    
111  #define KBD_QUEUE_SIZE 256  #define KBD_QUEUE_SIZE 256
112    
113  typedef struct {  #define KBD_PENDING_KBD         1
114      uint8_t aux[KBD_QUEUE_SIZE];  #define KBD_PENDING_AUX         2
     uint8_t data[KBD_QUEUE_SIZE];  
     int rptr, wptr, count;  
 } KBDQueue;  
115    
116  typedef struct KBDState {  typedef struct KBDState {
     KBDQueue queue;  
117      uint8_t write_cmd; /* if non zero, write data to port 60 is expected */      uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
118      uint8_t status;      uint8_t status;
119      uint8_t mode;      uint8_t mode;
120      /* keyboard state */      /* Bitmask of devices with data available.  */
121      int kbd_write_cmd;      int pending;
122      int scan_enabled;      void *kbd;
123      /* mouse state */      void *mouse;
     int mouse_write_cmd;  
     uint8_t mouse_status;  
     uint8_t mouse_resolution;  
     uint8_t mouse_sample_rate;  
     uint8_t mouse_wrap;  
     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */  
     uint8_t mouse_detect_state;  
     int mouse_dx; /* current values, needed for 'poll' mode */  
     int mouse_dy;  
     int mouse_dz;  
     uint8_t mouse_buttons;  
124  } KBDState;  } KBDState;
125    
126  KBDState kbd_state;  KBDState kbd_state;
# Line 145  KBDState kbd_state; Line 130  KBDState kbd_state;
130     incorrect, but it avoids having to simulate exact delays */     incorrect, but it avoids having to simulate exact delays */
131  static void kbd_update_irq(KBDState *s)  static void kbd_update_irq(KBDState *s)
132  {  {
     KBDQueue *q = &s->queue;  
133      int irq12_level, irq1_level;      int irq12_level, irq1_level;
134    
135      irq1_level = 0;          irq1_level = 0;    
136      irq12_level = 0;          irq12_level = 0;    
137      s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);      s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
138      if (q->count != 0) {      if (s->pending) {
139          s->status |= KBD_STAT_OBF;          s->status |= KBD_STAT_OBF;
140          if (q->aux[q->rptr]) {          /* kdb data takes priority over aux data.  */
141            if (s->pending == KBD_PENDING_AUX) {
142              s->status |= KBD_STAT_MOUSE_OBF;              s->status |= KBD_STAT_MOUSE_OBF;
143              if (s->mode & KBD_MODE_MOUSE_INT)              if (s->mode & KBD_MODE_MOUSE_INT)
144                  irq12_level = 1;                  irq12_level = 1;
# Line 167  static void kbd_update_irq(KBDState *s) Line 152  static void kbd_update_irq(KBDState *s)
152      pic_set_irq(12, irq12_level);      pic_set_irq(12, irq12_level);
153  }  }
154    
155  static void kbd_queue(KBDState *s, int b, int aux)  static void kbd_update_kbd_irq(void *opaque, int level)
156  {  {
157      KBDQueue *q = &s->queue;      KBDState *s = (KBDState *)opaque;
158    
159  #if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)      if (level)
160      if (aux)          s->pending |= KBD_PENDING_KBD;
         printf("mouse event: 0x%02x\n", b);  
 #ifdef DEBUG_KBD  
161      else      else
162          printf("kbd event: 0x%02x\n", b);          s->pending &= ~KBD_PENDING_KBD;
 #endif  
 #endif  
     if (q->count >= KBD_QUEUE_SIZE)  
         return;  
     q->aux[q->wptr] = aux;  
     q->data[q->wptr] = b;  
     if (++q->wptr == KBD_QUEUE_SIZE)  
         q->wptr = 0;  
     q->count++;  
163      kbd_update_irq(s);      kbd_update_irq(s);
164  }  }
165    
166  static void pc_kbd_put_keycode(void *opaque, int keycode)  static void kbd_update_aux_irq(void *opaque, int level)
167  {  {
168      KBDState *s = opaque;      KBDState *s = (KBDState *)opaque;
169      kbd_queue(s, keycode, 0);  
170        if (level)
171            s->pending |= KBD_PENDING_AUX;
172        else
173            s->pending &= ~KBD_PENDING_AUX;
174        kbd_update_irq(s);
175  }  }
176    
177  static uint32_t kbd_read_status(void *opaque, uint32_t addr)  static uint32_t kbd_read_status(void *opaque, uint32_t addr)
# Line 206  static uint32_t kbd_read_status(void *op Line 185  static uint32_t kbd_read_status(void *op
185      return val;      return val;
186  }  }
187    
188    static void kbd_queue(KBDState *s, int b, int aux)
189    {
190        if (aux)
191            ps2_queue(s->mouse, b);
192        else
193            ps2_queue(s->kbd, b);
194    }
195    
196  static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)  static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
197  {  {
198      KBDState *s = opaque;      KBDState *s = opaque;
# Line 287  static void kbd_write_command(void *opaq Line 274  static void kbd_write_command(void *opaq
274  static uint32_t kbd_read_data(void *opaque, uint32_t addr)  static uint32_t kbd_read_data(void *opaque, uint32_t addr)
275  {  {
276      KBDState *s = opaque;      KBDState *s = opaque;
     KBDQueue *q;  
     int val, index, aux;  
       
     q = &s->queue;  
     if (q->count == 0) {  
         /* NOTE: if no data left, we return the last keyboard one  
            (needed for EMM386) */  
         /* XXX: need a timer to do things correctly */  
         index = q->rptr - 1;  
         if (index < 0)  
             index = KBD_QUEUE_SIZE - 1;  
         val = q->data[index];  
     } else {  
         aux = q->aux[q->rptr];  
         val = q->data[q->rptr];  
         if (++q->rptr == KBD_QUEUE_SIZE)  
             q->rptr = 0;  
         q->count--;  
         /* reading deasserts IRQ */  
         if (aux)  
             pic_set_irq(12, 0);  
         else  
             pic_set_irq(1, 0);  
     }  
     /* reassert IRQs if data left */  
     kbd_update_irq(s);  
 #ifdef DEBUG_KBD  
     printf("kbd: read data=0x%02x\n", val);  
 #endif  
     return val;  
 }  
277    
278  static void kbd_reset_keyboard(KBDState *s)      if (s->pending == KBD_PENDING_AUX)
279  {          return ps2_read_data(s->mouse);
     s->scan_enabled = 1;  
 }  
280    
281  static void kbd_write_keyboard(KBDState *s, int val)      return ps2_read_data(s->kbd);
 {  
     switch(s->kbd_write_cmd) {  
     default:  
     case -1:  
         switch(val) {  
         case 0x00:  
             kbd_queue(s, KBD_REPLY_ACK, 0);  
             break;  
         case 0x05:  
             kbd_queue(s, KBD_REPLY_RESEND, 0);  
             break;  
         case KBD_CMD_GET_ID:  
             kbd_queue(s, KBD_REPLY_ACK, 0);  
             kbd_queue(s, 0xab, 0);  
             kbd_queue(s, 0x83, 0);  
             break;  
         case KBD_CMD_ECHO:  
             kbd_queue(s, KBD_CMD_ECHO, 0);  
             break;  
         case KBD_CMD_ENABLE:  
             s->scan_enabled = 1;  
             kbd_queue(s, KBD_REPLY_ACK, 0);  
             break;  
         case KBD_CMD_SET_LEDS:  
         case KBD_CMD_SET_RATE:  
             s->kbd_write_cmd = val;  
             kbd_queue(s, KBD_REPLY_ACK, 0);  
             break;  
         case KBD_CMD_RESET_DISABLE:  
             kbd_reset_keyboard(s);  
             s->scan_enabled = 0;  
             kbd_queue(s, KBD_REPLY_ACK, 0);  
             break;  
         case KBD_CMD_RESET_ENABLE:  
             kbd_reset_keyboard(s);  
             s->scan_enabled = 1;  
             kbd_queue(s, KBD_REPLY_ACK, 0);  
             break;  
         case KBD_CMD_RESET:  
             kbd_reset_keyboard(s);  
             kbd_queue(s, KBD_REPLY_ACK, 0);  
             kbd_queue(s, KBD_REPLY_POR, 0);  
             break;  
         default:  
             kbd_queue(s, KBD_REPLY_ACK, 0);  
             break;  
         }  
         break;  
     case KBD_CMD_SET_LEDS:  
         kbd_queue(s, KBD_REPLY_ACK, 0);  
         s->kbd_write_cmd = -1;  
         break;  
     case KBD_CMD_SET_RATE:  
         kbd_queue(s, KBD_REPLY_ACK, 0);  
         s->kbd_write_cmd = -1;  
         break;  
     }  
 }  
   
 static void kbd_mouse_send_packet(KBDState *s)  
 {  
     unsigned int b;  
     int dx1, dy1, dz1;  
   
     dx1 = s->mouse_dx;  
     dy1 = s->mouse_dy;  
     dz1 = s->mouse_dz;  
     /* XXX: increase range to 8 bits ? */  
     if (dx1 > 127)  
         dx1 = 127;  
     else if (dx1 < -127)  
         dx1 = -127;  
     if (dy1 > 127)  
         dy1 = 127;  
     else if (dy1 < -127)  
         dy1 = -127;  
     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);  
     kbd_queue(s, b, 1);  
     kbd_queue(s, dx1 & 0xff, 1);  
     kbd_queue(s, dy1 & 0xff, 1);  
     /* extra byte for IMPS/2 or IMEX */  
     switch(s->mouse_type) {  
     default:  
         break;  
     case 3:  
         if (dz1 > 127)  
             dz1 = 127;  
         else if (dz1 < -127)  
                 dz1 = -127;  
         kbd_queue(s, dz1 & 0xff, 1);  
         break;  
     case 4:  
         if (dz1 > 7)  
             dz1 = 7;  
         else if (dz1 < -7)  
             dz1 = -7;  
         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);  
         kbd_queue(s, b, 1);  
         break;  
     }  
   
     /* update deltas */  
     s->mouse_dx -= dx1;  
     s->mouse_dy -= dy1;  
     s->mouse_dz -= dz1;  
 }  
   
 static void pc_kbd_mouse_event(void *opaque,  
                                int dx, int dy, int dz, int buttons_state)  
 {  
     KBDState *s = opaque;  
   
     /* check if deltas are recorded when disabled */  
     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))  
         return;  
   
     s->mouse_dx += dx;  
     s->mouse_dy -= dy;  
     s->mouse_dz += dz;  
     /* XXX: SDL sometimes generates nul events: we delete them */  
     if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&  
         s->mouse_buttons == buttons_state)  
         return;  
     s->mouse_buttons = buttons_state;  
       
     if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&  
         (s->queue.count < (KBD_QUEUE_SIZE - 16))) {  
         for(;;) {  
             /* if not remote, send event. Multiple events are sent if  
                too big deltas */  
             kbd_mouse_send_packet(s);  
             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)  
                 break;  
         }  
     }  
 }  
   
 static void kbd_write_mouse(KBDState *s, int val)  
 {  
 #ifdef DEBUG_MOUSE  
     printf("kbd: write mouse 0x%02x\n", val);  
 #endif  
     switch(s->mouse_write_cmd) {  
     default:  
     case -1:  
         /* mouse command */  
         if (s->mouse_wrap) {  
             if (val == AUX_RESET_WRAP) {  
                 s->mouse_wrap = 0;  
                 kbd_queue(s, AUX_ACK, 1);  
                 return;  
             } else if (val != AUX_RESET) {  
                 kbd_queue(s, val, 1);  
                 return;  
             }  
         }  
         switch(val) {  
         case AUX_SET_SCALE11:  
             s->mouse_status &= ~MOUSE_STATUS_SCALE21;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_SET_SCALE21:  
             s->mouse_status |= MOUSE_STATUS_SCALE21;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_SET_STREAM:  
             s->mouse_status &= ~MOUSE_STATUS_REMOTE;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_SET_WRAP:  
             s->mouse_wrap = 1;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_SET_REMOTE:  
             s->mouse_status |= MOUSE_STATUS_REMOTE;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_GET_TYPE:  
             kbd_queue(s, AUX_ACK, 1);  
             kbd_queue(s, s->mouse_type, 1);  
             break;  
         case AUX_SET_RES:  
         case AUX_SET_SAMPLE:  
             s->mouse_write_cmd = val;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_GET_SCALE:  
             kbd_queue(s, AUX_ACK, 1);  
             kbd_queue(s, s->mouse_status, 1);  
             kbd_queue(s, s->mouse_resolution, 1);  
             kbd_queue(s, s->mouse_sample_rate, 1);  
             break;  
         case AUX_POLL:  
             kbd_queue(s, AUX_ACK, 1);  
             kbd_mouse_send_packet(s);  
             break;  
         case AUX_ENABLE_DEV:  
             s->mouse_status |= MOUSE_STATUS_ENABLED;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_DISABLE_DEV:  
             s->mouse_status &= ~MOUSE_STATUS_ENABLED;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_SET_DEFAULT:  
             s->mouse_sample_rate = 100;  
             s->mouse_resolution = 2;  
             s->mouse_status = 0;  
             kbd_queue(s, AUX_ACK, 1);  
             break;  
         case AUX_RESET:  
             s->mouse_sample_rate = 100;  
             s->mouse_resolution = 2;  
             s->mouse_status = 0;  
             s->mouse_type = 0;  
             kbd_queue(s, AUX_ACK, 1);  
             kbd_queue(s, 0xaa, 1);  
             kbd_queue(s, s->mouse_type, 1);  
             break;  
         default:  
             break;  
         }  
         break;  
     case AUX_SET_SAMPLE:  
         s->mouse_sample_rate = val;  
         /* detect IMPS/2 or IMEX */  
         switch(s->mouse_detect_state) {  
         default:  
         case 0:  
             if (val == 200)  
                 s->mouse_detect_state = 1;  
             break;  
         case 1:  
             if (val == 100)  
                 s->mouse_detect_state = 2;  
             else if (val == 200)  
                 s->mouse_detect_state = 3;  
             else  
                 s->mouse_detect_state = 0;  
             break;  
         case 2:  
             if (val == 80)  
                 s->mouse_type = 3; /* IMPS/2 */  
             s->mouse_detect_state = 0;  
             break;  
         case 3:  
             if (val == 80)  
                 s->mouse_type = 4; /* IMEX */  
             s->mouse_detect_state = 0;  
             break;  
         }  
         kbd_queue(s, AUX_ACK, 1);  
         s->mouse_write_cmd = -1;  
         break;  
     case AUX_SET_RES:  
         s->mouse_resolution = val;  
         kbd_queue(s, AUX_ACK, 1);  
         s->mouse_write_cmd = -1;  
         break;  
     }  
282  }  }
283    
284  void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)  void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
# Line 597  void kbd_write_data(void *opaque, uint32 Line 291  void kbd_write_data(void *opaque, uint32
291    
292      switch(s->write_cmd) {      switch(s->write_cmd) {
293      case 0:      case 0:
294          kbd_write_keyboard(s, val);          ps2_write_keyboard(s->kbd, val);
295          break;          break;
296      case KBD_CCMD_WRITE_MODE:      case KBD_CCMD_WRITE_MODE:
297          s->mode = val;          s->mode = val;
298            /* ??? */
299          kbd_update_irq(s);          kbd_update_irq(s);
300          break;          break;
301      case KBD_CCMD_WRITE_OBUF:      case KBD_CCMD_WRITE_OBUF:
# Line 618  void kbd_write_data(void *opaque, uint32 Line 313  void kbd_write_data(void *opaque, uint32
313          }          }
314          break;          break;
315      case KBD_CCMD_WRITE_MOUSE:      case KBD_CCMD_WRITE_MOUSE:
316          kbd_write_mouse(s, val);          ps2_write_mouse(s->mouse, val);
317          break;          break;
318      default:      default:
319          break;          break;
# Line 629  void kbd_write_data(void *opaque, uint32 Line 324  void kbd_write_data(void *opaque, uint32
324  static void kbd_reset(void *opaque)  static void kbd_reset(void *opaque)
325  {  {
326      KBDState *s = opaque;      KBDState *s = opaque;
     KBDQueue *q;  
327    
     s->kbd_write_cmd = -1;  
     s->mouse_write_cmd = -1;  
328      s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;      s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
329      s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;      s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
     q = &s->queue;  
     q->rptr = 0;  
     q->wptr = 0;  
     q->count = 0;  
330  }  }
331    
332  static void kbd_save(QEMUFile* f, void* opaque)  static void kbd_save(QEMUFile* f, void* opaque)
# Line 648  static void kbd_save(QEMUFile* f, void* Line 336  static void kbd_save(QEMUFile* f, void*
336      qemu_put_8s(f, &s->write_cmd);      qemu_put_8s(f, &s->write_cmd);
337      qemu_put_8s(f, &s->status);      qemu_put_8s(f, &s->status);
338      qemu_put_8s(f, &s->mode);      qemu_put_8s(f, &s->mode);
     qemu_put_be32s(f, &s->kbd_write_cmd);  
     qemu_put_be32s(f, &s->scan_enabled);  
     qemu_put_be32s(f, &s->mouse_write_cmd);  
     qemu_put_8s(f, &s->mouse_status);  
     qemu_put_8s(f, &s->mouse_resolution);  
     qemu_put_8s(f, &s->mouse_sample_rate);  
     qemu_put_8s(f, &s->mouse_wrap);  
     qemu_put_8s(f, &s->mouse_type);  
     qemu_put_8s(f, &s->mouse_detect_state);  
     qemu_put_be32s(f, &s->mouse_dx);  
     qemu_put_be32s(f, &s->mouse_dy);  
     qemu_put_be32s(f, &s->mouse_dz);  
     qemu_put_8s(f, &s->mouse_buttons);  
339  }  }
340    
341  static int kbd_load(QEMUFile* f, void* opaque, int version_id)  static int kbd_load(QEMUFile* f, void* opaque, int version_id)
342  {  {
343      KBDState *s = (KBDState*)opaque;      KBDState *s = (KBDState*)opaque;
344            
345      if (version_id != 1)      if (version_id != 2)
346          return -EINVAL;          return -EINVAL;
347      qemu_get_8s(f, &s->write_cmd);      qemu_get_8s(f, &s->write_cmd);
348      qemu_get_8s(f, &s->status);      qemu_get_8s(f, &s->status);
349      qemu_get_8s(f, &s->mode);      qemu_get_8s(f, &s->mode);
     qemu_get_be32s(f, &s->kbd_write_cmd);  
     qemu_get_be32s(f, &s->scan_enabled);  
     qemu_get_be32s(f, &s->mouse_write_cmd);  
     qemu_get_8s(f, &s->mouse_status);  
     qemu_get_8s(f, &s->mouse_resolution);  
     qemu_get_8s(f, &s->mouse_sample_rate);  
     qemu_get_8s(f, &s->mouse_wrap);  
     qemu_get_8s(f, &s->mouse_type);  
     qemu_get_8s(f, &s->mouse_detect_state);  
     qemu_get_be32s(f, &s->mouse_dx);  
     qemu_get_be32s(f, &s->mouse_dy);  
     qemu_get_be32s(f, &s->mouse_dz);  
     qemu_get_8s(f, &s->mouse_buttons);  
350      return 0;      return 0;
351  }  }
352    
# Line 693  void kbd_init(void) Line 355  void kbd_init(void)
355      KBDState *s = &kbd_state;      KBDState *s = &kbd_state;
356            
357      kbd_reset(s);      kbd_reset(s);
358      register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);      register_savevm("pckbd", 0, 2, kbd_save, kbd_load, s);
359      register_ioport_read(0x60, 1, 1, kbd_read_data, s);      register_ioport_read(0x60, 1, 1, kbd_read_data, s);
360      register_ioport_write(0x60, 1, 1, kbd_write_data, s);      register_ioport_write(0x60, 1, 1, kbd_write_data, s);
361      register_ioport_read(0x64, 1, 1, kbd_read_status, s);      register_ioport_read(0x64, 1, 1, kbd_read_status, s);
362      register_ioport_write(0x64, 1, 1, kbd_write_command, s);      register_ioport_write(0x64, 1, 1, kbd_write_command, s);
363    
364      qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);      s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
365      qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);      s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
366      qemu_register_reset(kbd_reset, s);      qemu_register_reset(kbd_reset, s);
367  }  }

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.13

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26