Detect usb keyboard properly, support keyboard hotpluanad multiple keyboards

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-07-17 03:57:59 +02:00
parent b92c6ff67f
commit 3a25376967

View file

@ -54,7 +54,6 @@ static char keyboard_map_shift[128] =
'?' '?'
}; };
static grub_usb_device_t usbdev;
/* Valid values for bmRequestType. See HID definition version 1.11 section /* Valid values for bmRequestType. See HID definition version 1.11 section
7.2. */ 7.2. */
@ -69,36 +68,64 @@ static grub_usb_device_t usbdev;
#define USB_HID_SET_IDLE 0x0A #define USB_HID_SET_IDLE 0x0A
#define USB_HID_SET_PROTOCOL 0x0B #define USB_HID_SET_PROTOCOL 0x0B
static int grub_usb_keyboard_checkkey (struct grub_term_input *term);
static int grub_usb_keyboard_getkey (struct grub_term_input *term);
static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term);
static struct grub_term_input grub_usb_keyboard_term =
{
.checkkey = grub_usb_keyboard_checkkey,
.getkey = grub_usb_keyboard_getkey,
.getkeystatus = grub_usb_keyboard_getkeystatus,
.next = 0
};
static struct grub_term_input grub_usb_keyboards[16];
static void static void
grub_usb_hid (void) grub_usb_keyboard_detach (grub_usb_device_t usbdev,
int config __attribute__ ((unused)),
int interface __attribute__ ((unused)))
{ {
struct grub_usb_desc_device *descdev; unsigned i;
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
if (grub_usb_keyboards[i].data && grub_usb_keyboards[i].data == usbdev)
{
grub_term_unregister_input (&grub_usb_keyboards[i]);
grub_free ((char *) grub_usb_keyboards[i].name);
grub_usb_keyboards[i].name = NULL;
grub_usb_keyboards[i].data = 0;
}
}
auto int usb_iterate (grub_usb_device_t dev); static int
int usb_iterate (grub_usb_device_t dev) grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno)
{ {
descdev = &dev->descdev; unsigned curnum;
grub_dprintf ("usb_keyboard", "%x %x %x\n", grub_dprintf ("usb_keyboard", "%x %x %x %d %d\n",
descdev->class, descdev->subclass, descdev->protocol); usbdev->descdev.class, usbdev->descdev.subclass,
usbdev->descdev.protocol, configno, interfno);
for (curnum = 0; curnum < ARRAY_SIZE (grub_usb_keyboards); curnum++)
if (!grub_usb_keyboards[curnum].data)
break;
if (curnum == ARRAY_SIZE (grub_usb_keyboards))
return 0;
#if 0 #if 0
if (descdev->class != 0x09 if (descdev->class != 0x09
|| descdev->subclass == 0x01 || descdev->subclass == 0x01
|| descdev->protocol != 0x02) || descdev->protocol != 0x02)
return 0; return 0;
#endif #endif
if (descdev->class != 0 || descdev->subclass != 0 || descdev->protocol != 0) if (usbdev->descdev.class != 0
return 0; || usbdev->descdev.subclass != 0 || usbdev->descdev.protocol != 0)
return 0;
grub_printf ("HID found!\n"); grub_printf ("HID found!\n");
usbdev = dev;
return 1;
}
grub_usb_iterate (usb_iterate);
/* Place the device in boot mode. */ /* Place the device in boot mode. */
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_PROTOCOL, grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_PROTOCOL,
@ -107,6 +134,19 @@ grub_usb_hid (void)
/* Reports every time an event occurs and not more often than that. */ /* Reports every time an event occurs and not more often than that. */
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE, grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE,
0<<8, 0, 0, 0); 0<<8, 0, 0, 0);
grub_memcpy (&grub_usb_keyboards[curnum], &grub_usb_keyboard_term,
sizeof (grub_usb_keyboards[curnum]));
grub_usb_keyboards[curnum].data = usbdev;
usbdev->config[configno].interf[interfno].detach_hook
= grub_usb_keyboard_detach;
grub_usb_keyboards[curnum].name = grub_xasprintf ("usb_keyboard%d", curnum);
if (!grub_usb_keyboards[curnum].name)
return 0;
grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]);
return 1;
} }
static grub_err_t static grub_err_t
@ -119,13 +159,14 @@ grub_usb_keyboard_getreport (grub_usb_device_t dev, grub_uint8_t *report)
static int static int
grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused))) grub_usb_keyboard_checkkey (struct grub_term_input *term)
{ {
grub_uint8_t data[8]; grub_uint8_t data[8];
int key; int key;
grub_err_t err; grub_err_t err;
grub_uint64_t currtime; grub_uint64_t currtime;
int timeout = 50; int timeout = 50;
grub_usb_device_t usbdev = term->data;
data[2] = 0; data[2] = 0;
currtime = grub_get_time_ms (); currtime = grub_get_time_ms ();
@ -196,6 +237,7 @@ grub_usb_keyboard_getkey (struct grub_term_input *term)
grub_uint64_t currtime; grub_uint64_t currtime;
int timeout; int timeout;
static grub_usb_keyboard_repeat_t repeat = GRUB_HIDBOOT_REPEAT_NONE; static grub_usb_keyboard_repeat_t repeat = GRUB_HIDBOOT_REPEAT_NONE;
grub_usb_device_t usbdev = term->data;
again: again:
@ -253,13 +295,14 @@ grub_usb_keyboard_getkey (struct grub_term_input *term)
} }
static int static int
grub_usb_keyboard_getkeystatus (struct grub_term_input *term __attribute__ ((unused))) grub_usb_keyboard_getkeystatus (struct grub_term_input *term)
{ {
grub_uint8_t data[8]; grub_uint8_t data[8];
int mods = 0; int mods = 0;
grub_err_t err; grub_err_t err;
grub_uint64_t currtime; grub_uint64_t currtime;
int timeout = 50; int timeout = 50;
grub_usb_device_t usbdev = term->data;
/* Set idle time to the minimum offered by the spec (4 milliseconds) so /* Set idle time to the minimum offered by the spec (4 milliseconds) so
that we can find out the current state. */ that we can find out the current state. */
@ -307,22 +350,27 @@ grub_usb_keyboard_getkeystatus (struct grub_term_input *term __attribute__ ((unu
return mods; return mods;
} }
static struct grub_term_input grub_usb_keyboard_term = struct grub_usb_attach_desc attach_hook =
{ {
.name = "usb_keyboard", .class = GRUB_USB_CLASS_HID,
.checkkey = grub_usb_keyboard_checkkey, .hook = grub_usb_keyboard_attach
.getkey = grub_usb_keyboard_getkey, };
.getkeystatus = grub_usb_keyboard_getkeystatus,
.next = 0
};
GRUB_MOD_INIT(usb_keyboard) GRUB_MOD_INIT(usb_keyboard)
{ {
grub_usb_hid (); grub_usb_register_attach_hook_class (&attach_hook);
grub_term_register_input ("usb_keyboard", &grub_usb_keyboard_term);
} }
GRUB_MOD_FINI(usb_keyboard) GRUB_MOD_FINI(usb_keyboard)
{ {
grub_term_unregister_input (&grub_usb_keyboard_term); unsigned i;
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
if (grub_usb_keyboards[i].data)
{
grub_term_unregister_input (&grub_usb_keyboards[i]);
grub_free ((char *) grub_usb_keyboards[i].name);
grub_usb_keyboards[i].name = NULL;
grub_usb_keyboards[i].data = 0;
}
grub_usb_unregister_attach_hook_class (&attach_hook);
} }