ps2 keyboard:fix can't use ps2 keyboard if typing many times After leaving grub and before finishing linux kernel ps2 driver initialization
diff mbox

Message ID 20150503163241.272593D7131@webmail.sinamail.sina.com.cn
State New
Headers show

Commit Message

penghao122@sina.com May 3, 2015, 4:32 p.m. UTC
Starting  a linux guest with ps2 keyboard ,if you type many times during leaving grub and into linux kernel ,then you can't use keyboard after linux initialization finished.
during grub,the work method of ps2 keyboard is like this:
first ,ps2 keyboard driver send command KBD_CCMD_KBD_ENABLE,
second,if there is a keyboard input,then  ps2 keyboard driver read data.
third ,ps2 keyboard driver send command KBD_CCMD_KBD_ENABLE,
...
this is diffrent method of linux kernel .
After leaving  grub and before finishing linux kernel ps2 driver initialization,if you type many times,the input data keep saving the ps2 queue in qemu .Before linux kernel initialize ps2 keyboard,linux call i8042_init->i8042_controller_check,if i8042_controller_check return fail,then linux kernel ps2 keyboard driver will never initialize. 
(linux kernel 2.6.32 i8042.c)
static int i8042_controller_check(void)
{
 if (i8042_flush() == I8042_BUFFER_SIZE)
  return -ENODEV;
 return 0;
}
static int i8042_flush(void)
{...
while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) {
  udelay(50);
  data = i8042_read_data();
  i++;
  }
return i;
}
 
during calling i8042_flush it is full in qemu queue .
ps_read_data:
                       s->update_irq(s->update_arg, 0);
                       s->update_irq(s->update_arg, q->count != 0);
because q->count!=0, kbd_update_irq can set I8042_STR_OBF.Then i8042_flush()  will return I8042_BUFFER_SIZE.
Signed-off-by: Hao Peng<penghao122@sina.co

Comments

Eric Blake May 4, 2015, 2:31 p.m. UTC | #1
On 05/03/2015 10:32 AM, penghao122@sina.com wrote:

Poor subject line.  Please try to keep subjects under 65 characters in
length (see 'git shortlog -30' for good examples).  Maybe:

keyboard: handle ps2 typing buffer overrun

> Starting  a linux guest with ps2 keyboard ,if you type many times during leaving grub and into linux kernel ,then you can't use keyboard after linux initialization finished.

Also, wrap your commit body messages to fit with 78 columns or so.

Spacing is wrong: s/Starting  a/Staring a/; s/keyboard ,if/keyboard,
if/; s/kernel ,then/kernel, then/

> during grub,the work method of ps2 keyboard is like this:
> first ,ps2 keyboard driver send command KBD_CCMD_KBD_ENABLE,
> second,if there is a keyboard input,then  ps2 keyboard driver read data.
> third ,ps2 keyboard driver send command KBD_CCMD_KBD_ENABLE,

Again, in English, no space before comma, but space afterwards.

> ...
> this is diffrent method of linux kernel .

s/diffrent/different/; s/ ././

> After leaving  grub and before finishing linux kernel ps2 driver initialization,if you type many times,the input data keep saving the ps2 queue in qemu .Before linux kernel initialize ps2 keyboard,linux call i8042_init->i8042_controller_check,if i8042_controller_check return fail,then linux kernel ps2 keyboard driver will never initialize. 

More spacing errors; no trailing space, long line.

> (linux kernel 2.6.32 i8042.c)
> static int i8042_controller_check(void)
> {
>  if (i8042_flush() == I8042_BUFFER_SIZE)
>   return -ENODEV;
>  return 0;
> }
> static int i8042_flush(void)
> {...
> while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) {
>   udelay(50);
>   data = i8042_read_data();
>   i++;
>   }
> return i;
> }

Indentation is weird.

>  
> during calling i8042_flush it is full in qemu queue .
> ps_read_data:
>                        s->update_irq(s->update_arg, 0);
>                        s->update_irq(s->update_arg, q->count != 0);
> because q->count!=0, kbd_update_irq can set I8042_STR_OBF.Then i8042_flush()  will return I8042_BUFFER_SIZE.
> Signed-off-by: Hao Peng<penghao122@sina.co
> --- ps2.c.orig 2015-04-25 09:44:38.865777168 -0400

Missing the usual '---' separator between the commit body and the patch
proper; also missing the diffstat.  Life is easier if you use 'git
format-patch' and/or 'git send-email' to format your patch messages.

More hints at:
http://wiki.qemu.org/Contribute/SubmitAPatch

Patch
diff mbox

--- ps2.c.orig 2015-04-25 09:44:38.865777168 -0400
+++ ps2.c 2015-04-25 09:48:46.385121172 -0400
@@ -150,7 +150,12 @@ 
     q->count++;
     s->update_irq(s->update_arg, 1);
 }
-
+void ps2_clear_queue(void *opaque)
+{
+    PS2State *s = (PS2State *)opaque;
+    PS2Queue *q = &s->queue;
+    q->wptr = q->rptr = q->count = 0;
+}
 /*
    keycode is expressed as follow:
    bit 7    - 0 key pressed, 1 = key released
 
 
--- pckbd.c.orig 2015-04-25 09:36:59.960640241 -0400
+++ pckbd.c 2015-05-03 11:33:47.565002126 -0400
@@ -207,6 +207,8 @@ static uint64_t kbd_read_status(void *opaque, hwaddr addr
     KBDState *s = opaque;
     int val;
     val = s->status;
+    if(s->write-cmd == KBD_CCMD_KBD_ENABLE)
+        val &= ~KBD_STAT_OBF;    
     DPRINTF("kbd: read status=0x%02x\n", val);
     return val;
 }
@@ -251,9 +253,10 @@ static void kbd_write_command(void *opaque, hwaddr addr,
         else
             val = KBD_CCMD_NO_OP;
     }
-
+    s->write_cmd = 0;
     switch(val) {
     case KBD_CCMD_READ_MODE:
+        ps2_clear_queue(s->kbd);
         kbd_queue(s, s->mode, 0);
         break;
     case KBD_CCMD_WRITE_MODE:
@@ -284,6 +287,7 @@ static void kbd_write_command(void *opaque, hwaddr addr,
         kbd_update_irq(s);
         break;
     case KBD_CCMD_KBD_ENABLE:
+        s->write_cmd = KBD_CCMD_KBD_ENABLE;
         s->mode &= ~KBD_MODE_DISABLE_KBD;
         kbd_update_irq(s);
         break;
@@ -365,6 +369,8 @@ static void kbd_write_data(void *opaque, hwaddr addr,
         break;
     }
     s->write_cmd = 0;
+    if(s->write_cmd == KBD_CCMD_WRITE_MODE && s->mode == 0x61)
+        s->write_cmd == KBD_CCMD_KBD_ENABLE;
 }
 
 static void kbd_reset(void *opaque)