2009-02-21 14:55:06 +00:00
|
|
|
|
/* Support for the HID Boot Protocol. */
|
|
|
|
|
/*
|
|
|
|
|
* GRUB -- GRand Unified Bootloader
|
|
|
|
|
* Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
|
|
|
|
*
|
|
|
|
|
* GRUB is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* GRUB is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <grub/term.h>
|
|
|
|
|
#include <grub/time.h>
|
|
|
|
|
#include <grub/cpu/io.h>
|
|
|
|
|
#include <grub/misc.h>
|
|
|
|
|
#include <grub/term.h>
|
|
|
|
|
#include <grub/usb.h>
|
|
|
|
|
#include <grub/dl.h>
|
|
|
|
|
#include <grub/time.h>
|
2010-08-19 13:32:43 +00:00
|
|
|
|
#include <grub/keyboard_layouts.h>
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-21 22:01:21 +00:00
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
KEY_NO_KEY = 0x00,
|
|
|
|
|
KEY_ERR_BUFFER = 0x01,
|
|
|
|
|
KEY_ERR_POST = 0x02,
|
|
|
|
|
KEY_ERR_UNDEF = 0x03,
|
|
|
|
|
KEY_CAPS_LOCK = 0x39,
|
|
|
|
|
KEY_NUM_LOCK = 0x53,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
LED_NUM_LOCK = 0x01,
|
|
|
|
|
LED_CAPS_LOCK = 0x02
|
|
|
|
|
};
|
2009-08-28 13:20:34 +00:00
|
|
|
|
|
|
|
|
|
/* Valid values for bRequest. See HID definition version 1.11 section 7.2. */
|
|
|
|
|
#define USB_HID_GET_REPORT 0x01
|
|
|
|
|
#define USB_HID_GET_IDLE 0x02
|
|
|
|
|
#define USB_HID_GET_PROTOCOL 0x03
|
|
|
|
|
#define USB_HID_SET_REPORT 0x09
|
|
|
|
|
#define USB_HID_SET_IDLE 0x0A
|
|
|
|
|
#define USB_HID_SET_PROTOCOL 0x0B
|
|
|
|
|
|
2010-08-01 21:08:33 +00:00
|
|
|
|
#define USB_HID_BOOT_SUBCLASS 0x01
|
|
|
|
|
#define USB_HID_KBD_PROTOCOL 0x01
|
|
|
|
|
|
2010-08-19 13:32:43 +00:00
|
|
|
|
#define GRUB_USB_KEYBOARD_LEFT_CTRL 0x01
|
|
|
|
|
#define GRUB_USB_KEYBOARD_LEFT_SHIFT 0x02
|
|
|
|
|
#define GRUB_USB_KEYBOARD_LEFT_ALT 0x04
|
|
|
|
|
#define GRUB_USB_KEYBOARD_RIGHT_CTRL 0x10
|
|
|
|
|
#define GRUB_USB_KEYBOARD_RIGHT_SHIFT 0x20
|
|
|
|
|
#define GRUB_USB_KEYBOARD_RIGHT_ALT 0x40
|
|
|
|
|
|
2010-08-20 20:13:19 +00:00
|
|
|
|
struct grub_usb_keyboard_data
|
|
|
|
|
{
|
|
|
|
|
grub_usb_device_t usbdev;
|
|
|
|
|
grub_uint8_t status;
|
2010-08-20 22:29:57 +00:00
|
|
|
|
grub_uint16_t mods;
|
|
|
|
|
int interfno;
|
2010-08-20 20:13:19 +00:00
|
|
|
|
struct grub_usb_desc_endp *endp;
|
2010-08-21 21:17:44 +00:00
|
|
|
|
grub_usb_transfer_t transfer;
|
|
|
|
|
grub_uint8_t report[8];
|
|
|
|
|
int dead;
|
2010-08-21 22:29:34 +00:00
|
|
|
|
int last_key;
|
|
|
|
|
grub_uint64_t repeat_time;
|
2010-09-18 22:34:25 +00:00
|
|
|
|
grub_uint8_t current_report[8];
|
|
|
|
|
grub_uint8_t last_report[8];
|
|
|
|
|
int index;
|
|
|
|
|
int max_index;
|
2010-08-20 20:13:19 +00:00
|
|
|
|
};
|
|
|
|
|
|
2010-07-17 01:57:59 +00:00
|
|
|
|
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 =
|
|
|
|
|
{
|
|
|
|
|
.getkey = grub_usb_keyboard_getkey,
|
|
|
|
|
.getkeystatus = grub_usb_keyboard_getkeystatus,
|
|
|
|
|
.next = 0
|
|
|
|
|
};
|
|
|
|
|
|
2010-08-21 21:17:44 +00:00
|
|
|
|
static struct grub_term_input grub_usb_keyboards[16];
|
|
|
|
|
|
2010-08-19 13:32:43 +00:00
|
|
|
|
static int
|
|
|
|
|
interpret_status (grub_uint8_t data0)
|
|
|
|
|
{
|
|
|
|
|
int mods = 0;
|
|
|
|
|
|
|
|
|
|
/* Check Shift, Control, and Alt status. */
|
|
|
|
|
if (data0 & GRUB_USB_KEYBOARD_LEFT_SHIFT)
|
|
|
|
|
mods |= GRUB_TERM_STATUS_LSHIFT;
|
|
|
|
|
if (data0 & GRUB_USB_KEYBOARD_RIGHT_SHIFT)
|
|
|
|
|
mods |= GRUB_TERM_STATUS_RSHIFT;
|
|
|
|
|
if (data0 & GRUB_USB_KEYBOARD_LEFT_CTRL)
|
|
|
|
|
mods |= GRUB_TERM_STATUS_LCTRL;
|
|
|
|
|
if (data0 & GRUB_USB_KEYBOARD_RIGHT_CTRL)
|
|
|
|
|
mods |= GRUB_TERM_STATUS_RCTRL;
|
|
|
|
|
if (data0 & GRUB_USB_KEYBOARD_LEFT_ALT)
|
|
|
|
|
mods |= GRUB_TERM_STATUS_LALT;
|
|
|
|
|
if (data0 & GRUB_USB_KEYBOARD_RIGHT_ALT)
|
|
|
|
|
mods |= GRUB_TERM_STATUS_RALT;
|
|
|
|
|
|
|
|
|
|
return mods;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-21 14:55:06 +00:00
|
|
|
|
static void
|
2010-07-17 01:57:59 +00:00
|
|
|
|
grub_usb_keyboard_detach (grub_usb_device_t usbdev,
|
|
|
|
|
int config __attribute__ ((unused)),
|
|
|
|
|
int interface __attribute__ ((unused)))
|
2009-02-21 14:55:06 +00:00
|
|
|
|
{
|
2010-07-17 01:57:59 +00:00
|
|
|
|
unsigned i;
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
|
2009-02-21 14:55:06 +00:00
|
|
|
|
{
|
2010-08-20 17:34:29 +00:00
|
|
|
|
struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data;
|
|
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (data->usbdev != usbdev)
|
|
|
|
|
continue;
|
|
|
|
|
|
2010-08-21 21:09:37 +00:00
|
|
|
|
if (data->transfer)
|
|
|
|
|
grub_usb_cancel_transfer (data->transfer);
|
|
|
|
|
|
2010-08-20 17:34:29 +00:00
|
|
|
|
grub_term_unregister_input (&grub_usb_keyboards[i]);
|
|
|
|
|
grub_free ((char *) grub_usb_keyboards[i].name);
|
|
|
|
|
grub_usb_keyboards[i].name = NULL;
|
|
|
|
|
grub_free (grub_usb_keyboards[i].data);
|
|
|
|
|
grub_usb_keyboards[i].data = 0;
|
|
|
|
|
}
|
2010-07-17 01:57:59 +00:00
|
|
|
|
}
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-07-17 01:57:59 +00:00
|
|
|
|
static int
|
|
|
|
|
grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno)
|
|
|
|
|
{
|
|
|
|
|
unsigned curnum;
|
2010-08-20 12:36:29 +00:00
|
|
|
|
struct grub_usb_keyboard_data *data;
|
2010-08-20 14:34:34 +00:00
|
|
|
|
struct grub_usb_desc_endp *endp = NULL;
|
|
|
|
|
int j;
|
2010-07-17 01:57:59 +00:00
|
|
|
|
|
|
|
|
|
grub_dprintf ("usb_keyboard", "%x %x %x %d %d\n",
|
|
|
|
|
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;
|
2009-06-10 21:04:23 +00:00
|
|
|
|
|
2010-07-17 01:57:59 +00:00
|
|
|
|
if (curnum == ARRAY_SIZE (grub_usb_keyboards))
|
|
|
|
|
return 0;
|
2009-06-10 21:04:23 +00:00
|
|
|
|
|
2010-07-17 01:57:59 +00:00
|
|
|
|
if (usbdev->descdev.class != 0
|
|
|
|
|
|| usbdev->descdev.subclass != 0 || usbdev->descdev.protocol != 0)
|
|
|
|
|
return 0;
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-08-01 21:08:33 +00:00
|
|
|
|
if (usbdev->config[configno].interf[interfno].descif->subclass
|
|
|
|
|
!= USB_HID_BOOT_SUBCLASS
|
|
|
|
|
|| usbdev->config[configno].interf[interfno].descif->protocol
|
|
|
|
|
!= USB_HID_KBD_PROTOCOL)
|
|
|
|
|
return 0;
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-08-20 14:34:34 +00:00
|
|
|
|
for (j = 0; j < usbdev->config[configno].interf[interfno].descif->endpointcnt;
|
|
|
|
|
j++)
|
|
|
|
|
{
|
|
|
|
|
endp = &usbdev->config[configno].interf[interfno].descendp[j];
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-08-20 14:34:34 +00:00
|
|
|
|
if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp)
|
|
|
|
|
== GRUB_USB_EP_INTERRUPT)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (j == usbdev->config[configno].interf[interfno].descif->endpointcnt)
|
|
|
|
|
return 0;
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-08-20 18:26:57 +00:00
|
|
|
|
grub_dprintf ("usb_keyboard", "HID found!\n");
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-08-20 12:36:29 +00:00
|
|
|
|
data = grub_malloc (sizeof (*data));
|
|
|
|
|
if (!data)
|
|
|
|
|
{
|
|
|
|
|
grub_print_error ();
|
|
|
|
|
return 0;
|
2009-02-21 14:55:06 +00:00
|
|
|
|
}
|
2010-08-20 12:36:29 +00:00
|
|
|
|
|
|
|
|
|
data->usbdev = usbdev;
|
2010-08-20 22:29:57 +00:00
|
|
|
|
data->interfno = interfno;
|
2010-08-20 14:34:34 +00:00
|
|
|
|
data->endp = endp;
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-09-18 22:34:25 +00:00
|
|
|
|
/* Configure device */
|
|
|
|
|
grub_usb_set_configuration (usbdev, configno + 1);
|
|
|
|
|
|
2009-02-21 14:55:06 +00:00
|
|
|
|
/* Place the device in boot mode. */
|
2010-07-18 22:13:06 +00:00
|
|
|
|
grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
2010-08-21 11:56:55 +00:00
|
|
|
|
USB_HID_SET_PROTOCOL, 0, interfno, 0, 0);
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2009-05-04 20:06:05 +00:00
|
|
|
|
/* Reports every time an event occurs and not more often than that. */
|
2010-07-18 22:13:06 +00:00
|
|
|
|
grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
2010-08-21 11:56:55 +00:00
|
|
|
|
USB_HID_SET_IDLE, 0<<8, interfno, 0, 0);
|
2010-07-17 01:57:59 +00:00
|
|
|
|
|
|
|
|
|
grub_memcpy (&grub_usb_keyboards[curnum], &grub_usb_keyboard_term,
|
|
|
|
|
sizeof (grub_usb_keyboards[curnum]));
|
2010-08-20 12:36:29 +00:00
|
|
|
|
grub_usb_keyboards[curnum].data = data;
|
2010-07-17 01:57:59 +00:00
|
|
|
|
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)
|
2010-08-20 12:36:29 +00:00
|
|
|
|
{
|
|
|
|
|
grub_print_error ();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-08-21 11:56:55 +00:00
|
|
|
|
/* Test showed that getting report may make the keyboard go nuts.
|
|
|
|
|
Moreover since we're reattaching keyboard it usually sends
|
|
|
|
|
an initial message on interrupt pipe and so we retrieve
|
|
|
|
|
the same keystatus.
|
|
|
|
|
*/
|
|
|
|
|
#if 0
|
2010-08-20 12:36:29 +00:00
|
|
|
|
{
|
|
|
|
|
grub_uint8_t report[8];
|
|
|
|
|
grub_usb_err_t err;
|
|
|
|
|
grub_memset (report, 0, sizeof (report));
|
|
|
|
|
err = grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_IN,
|
2010-08-21 11:56:55 +00:00
|
|
|
|
USB_HID_GET_REPORT, 0x0100, interfno,
|
2010-08-20 12:36:29 +00:00
|
|
|
|
sizeof (report), (char *) report);
|
|
|
|
|
if (err)
|
2010-08-23 10:07:49 +00:00
|
|
|
|
data->status = 0;
|
2010-08-20 12:36:29 +00:00
|
|
|
|
else
|
2010-08-23 10:07:49 +00:00
|
|
|
|
data->status = report[0];
|
2010-08-20 12:36:29 +00:00
|
|
|
|
}
|
2010-08-21 11:56:55 +00:00
|
|
|
|
#else
|
|
|
|
|
data->status = 0;
|
|
|
|
|
#endif
|
2010-07-17 01:57:59 +00:00
|
|
|
|
|
2010-08-21 15:12:51 +00:00
|
|
|
|
data->transfer = grub_usb_bulk_read_background (usbdev,
|
|
|
|
|
data->endp->endp_addr,
|
|
|
|
|
sizeof (data->report),
|
|
|
|
|
(char *) data->report);
|
|
|
|
|
if (!data->transfer)
|
|
|
|
|
{
|
|
|
|
|
grub_print_error ();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-07-17 01:57:59 +00:00
|
|
|
|
|
2010-08-21 22:31:43 +00:00
|
|
|
|
data->last_key = -1;
|
2010-08-20 22:29:57 +00:00
|
|
|
|
data->mods = 0;
|
2010-08-21 22:31:43 +00:00
|
|
|
|
data->dead = 0;
|
2010-08-20 22:29:57 +00:00
|
|
|
|
|
2010-08-20 12:36:29 +00:00
|
|
|
|
grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]);
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-08-20 12:36:29 +00:00
|
|
|
|
return 1;
|
2009-02-21 14:55:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-20 22:29:57 +00:00
|
|
|
|
static void
|
|
|
|
|
send_leds (struct grub_usb_keyboard_data *termdata)
|
|
|
|
|
{
|
|
|
|
|
char report[1];
|
|
|
|
|
report[0] = 0;
|
|
|
|
|
if (termdata->mods & GRUB_TERM_STATUS_CAPS)
|
2010-08-21 22:01:21 +00:00
|
|
|
|
report[0] |= LED_CAPS_LOCK;
|
|
|
|
|
if (termdata->mods & GRUB_TERM_STATUS_NUM)
|
|
|
|
|
report[0] |= LED_NUM_LOCK;
|
2010-08-20 22:29:57 +00:00
|
|
|
|
grub_usb_control_msg (termdata->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
|
|
|
|
|
USB_HID_SET_REPORT, 0x0200, termdata->interfno,
|
|
|
|
|
sizeof (report), (char *) report);
|
|
|
|
|
grub_errno = GRUB_ERR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-18 22:34:25 +00:00
|
|
|
|
static int
|
|
|
|
|
parse_keycode (struct grub_usb_keyboard_data *termdata)
|
|
|
|
|
{
|
|
|
|
|
int index = termdata->index;
|
|
|
|
|
int i, keycode;
|
|
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
|
if (index < 2)
|
|
|
|
|
index = 2;
|
|
|
|
|
|
|
|
|
|
for ( ; index < termdata->max_index; index++)
|
|
|
|
|
{
|
|
|
|
|
keycode = termdata->current_report[index];
|
|
|
|
|
|
|
|
|
|
if (keycode == KEY_NO_KEY
|
|
|
|
|
|| keycode == KEY_ERR_BUFFER
|
|
|
|
|
|| keycode == KEY_ERR_POST
|
|
|
|
|
|| keycode == KEY_ERR_UNDEF)
|
|
|
|
|
{
|
|
|
|
|
/* Don't parse (rest of) this report */
|
|
|
|
|
termdata->index = 0;
|
|
|
|
|
if (keycode != KEY_NO_KEY)
|
|
|
|
|
/* Don't replace last report with current faulty report
|
|
|
|
|
* in future ! */
|
|
|
|
|
grub_memcpy (termdata->current_report,
|
|
|
|
|
termdata->last_report,
|
|
|
|
|
sizeof (termdata->report));
|
|
|
|
|
return GRUB_TERM_NO_KEY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to find current keycode in last report. */
|
|
|
|
|
for (i = 2; i < 8; i++)
|
|
|
|
|
if (keycode == termdata->last_report[i])
|
|
|
|
|
break;
|
|
|
|
|
if (i < 8)
|
|
|
|
|
/* Keycode is in last report, it means it was not released,
|
|
|
|
|
* ignore it. */
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (keycode == KEY_CAPS_LOCK)
|
|
|
|
|
{
|
|
|
|
|
termdata->mods ^= GRUB_TERM_STATUS_CAPS;
|
|
|
|
|
send_leds (termdata);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (keycode == KEY_NUM_LOCK)
|
|
|
|
|
{
|
|
|
|
|
termdata->mods ^= GRUB_TERM_STATUS_NUM;
|
|
|
|
|
send_leds (termdata);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
termdata->last_key = grub_term_map_key (keycode,
|
|
|
|
|
interpret_status (termdata->current_report[0])
|
|
|
|
|
| termdata->mods);
|
|
|
|
|
termdata->repeat_time = grub_get_time_ms () + GRUB_TERM_REPEAT_PRE_INTERVAL;
|
|
|
|
|
|
|
|
|
|
grub_errno = GRUB_ERR_NONE;
|
|
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
if (index >= termdata->max_index)
|
|
|
|
|
termdata->index = 0;
|
|
|
|
|
else
|
|
|
|
|
termdata->index = index;
|
|
|
|
|
|
|
|
|
|
return termdata->last_key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* All keycodes parsed */
|
|
|
|
|
termdata->index = 0;
|
|
|
|
|
return GRUB_TERM_NO_KEY;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-21 14:55:06 +00:00
|
|
|
|
static int
|
2010-08-23 10:07:49 +00:00
|
|
|
|
grub_usb_keyboard_getkey (struct grub_term_input *term)
|
2009-02-21 14:55:06 +00:00
|
|
|
|
{
|
2010-08-20 12:36:29 +00:00
|
|
|
|
grub_usb_err_t err;
|
|
|
|
|
struct grub_usb_keyboard_data *termdata = term->data;
|
|
|
|
|
grub_size_t actual;
|
2010-09-18 22:34:25 +00:00
|
|
|
|
int keycode = GRUB_TERM_NO_KEY;
|
2010-08-20 12:36:29 +00:00
|
|
|
|
|
2010-08-21 15:12:51 +00:00
|
|
|
|
if (termdata->dead)
|
2010-08-23 10:53:42 +00:00
|
|
|
|
return GRUB_TERM_NO_KEY;
|
2010-08-21 15:12:51 +00:00
|
|
|
|
|
2010-09-18 22:34:25 +00:00
|
|
|
|
if (termdata->index)
|
|
|
|
|
keycode = parse_keycode (termdata);
|
|
|
|
|
if (keycode != GRUB_TERM_NO_KEY)
|
|
|
|
|
return keycode;
|
|
|
|
|
|
2010-08-20 12:36:29 +00:00
|
|
|
|
/* Poll interrupt pipe. */
|
2010-08-21 15:12:51 +00:00
|
|
|
|
err = grub_usb_check_transfer (termdata->transfer, &actual);
|
|
|
|
|
|
|
|
|
|
if (err == GRUB_USB_ERR_WAIT)
|
2010-08-21 22:29:34 +00:00
|
|
|
|
{
|
|
|
|
|
if (termdata->last_key != -1
|
|
|
|
|
&& grub_get_time_ms () > termdata->repeat_time)
|
|
|
|
|
{
|
|
|
|
|
termdata->repeat_time = grub_get_time_ms ()
|
|
|
|
|
+ GRUB_TERM_REPEAT_INTERVAL;
|
2010-08-23 10:07:49 +00:00
|
|
|
|
return termdata->last_key;
|
2010-08-21 22:29:34 +00:00
|
|
|
|
}
|
2010-08-23 10:53:42 +00:00
|
|
|
|
return GRUB_TERM_NO_KEY;
|
2010-08-21 22:29:34 +00:00
|
|
|
|
}
|
2010-08-21 15:12:51 +00:00
|
|
|
|
|
2010-09-18 22:34:25 +00:00
|
|
|
|
if (!err && (actual >= 3))
|
|
|
|
|
grub_memcpy (termdata->last_report,
|
|
|
|
|
termdata->current_report,
|
|
|
|
|
sizeof (termdata->report));
|
|
|
|
|
|
|
|
|
|
grub_memcpy (termdata->current_report,
|
|
|
|
|
termdata->report,
|
|
|
|
|
sizeof (termdata->report));
|
2010-08-21 15:12:51 +00:00
|
|
|
|
|
|
|
|
|
termdata->transfer = grub_usb_bulk_read_background (termdata->usbdev,
|
|
|
|
|
termdata->endp->endp_addr,
|
|
|
|
|
sizeof (termdata->report),
|
|
|
|
|
(char *) termdata->report);
|
|
|
|
|
if (!termdata->transfer)
|
|
|
|
|
{
|
|
|
|
|
grub_printf ("%s failed. Stopped\n", term->name);
|
|
|
|
|
termdata->dead = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-21 22:29:34 +00:00
|
|
|
|
termdata->last_key = -1;
|
2010-08-21 21:17:44 +00:00
|
|
|
|
|
|
|
|
|
grub_dprintf ("usb_keyboard",
|
2010-09-19 20:05:48 +00:00
|
|
|
|
"err = %d, actual = %" PRIuGRUB_SIZE
|
|
|
|
|
" report: 0x%02x 0x%02x 0x%02x 0x%02x"
|
2010-08-21 21:17:44 +00:00
|
|
|
|
" 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
|
|
|
|
err, actual,
|
2010-09-18 22:34:25 +00:00
|
|
|
|
termdata->current_report[0], termdata->current_report[1],
|
|
|
|
|
termdata->current_report[2], termdata->current_report[3],
|
|
|
|
|
termdata->current_report[4], termdata->current_report[5],
|
|
|
|
|
termdata->current_report[6], termdata->current_report[7]);
|
2010-08-21 21:17:44 +00:00
|
|
|
|
|
2010-08-20 14:49:24 +00:00
|
|
|
|
if (err || actual < 1)
|
2010-08-23 10:53:42 +00:00
|
|
|
|
return GRUB_TERM_NO_KEY;
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-09-18 22:34:25 +00:00
|
|
|
|
termdata->status = termdata->current_report[0];
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
2010-08-21 22:01:21 +00:00
|
|
|
|
if (actual < 3)
|
2010-08-23 10:53:42 +00:00
|
|
|
|
return GRUB_TERM_NO_KEY;
|
2010-08-21 22:01:21 +00:00
|
|
|
|
|
2010-09-18 22:34:25 +00:00
|
|
|
|
termdata->index = 2; /* New data received. */
|
|
|
|
|
termdata->max_index = actual;
|
|
|
|
|
|
|
|
|
|
return parse_keycode (termdata);
|
2009-02-21 14:55:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-08-28 13:20:34 +00:00
|
|
|
|
static int
|
2010-07-17 01:57:59 +00:00
|
|
|
|
grub_usb_keyboard_getkeystatus (struct grub_term_input *term)
|
2009-08-28 13:20:34 +00:00
|
|
|
|
{
|
2010-08-20 12:36:29 +00:00
|
|
|
|
struct grub_usb_keyboard_data *termdata = term->data;
|
2009-08-28 13:20:34 +00:00
|
|
|
|
|
2010-08-20 22:29:57 +00:00
|
|
|
|
return interpret_status (termdata->status) | termdata->mods;
|
2009-08-28 13:20:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-23 11:05:13 +00:00
|
|
|
|
static struct grub_usb_attach_desc attach_hook =
|
2010-07-17 01:57:59 +00:00
|
|
|
|
{
|
|
|
|
|
.class = GRUB_USB_CLASS_HID,
|
|
|
|
|
.hook = grub_usb_keyboard_attach
|
|
|
|
|
};
|
2009-02-21 14:55:06 +00:00
|
|
|
|
|
|
|
|
|
GRUB_MOD_INIT(usb_keyboard)
|
|
|
|
|
{
|
2010-07-17 01:57:59 +00:00
|
|
|
|
grub_usb_register_attach_hook_class (&attach_hook);
|
2009-02-21 14:55:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GRUB_MOD_FINI(usb_keyboard)
|
|
|
|
|
{
|
2010-07-17 01:57:59 +00:00
|
|
|
|
unsigned i;
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
|
|
|
|
|
if (grub_usb_keyboards[i].data)
|
|
|
|
|
{
|
2010-08-21 21:09:37 +00:00
|
|
|
|
struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data;
|
|
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (data->transfer)
|
|
|
|
|
grub_usb_cancel_transfer (data->transfer);
|
|
|
|
|
|
2010-07-17 01:57:59 +00:00
|
|
|
|
grub_term_unregister_input (&grub_usb_keyboards[i]);
|
|
|
|
|
grub_free ((char *) grub_usb_keyboards[i].name);
|
|
|
|
|
grub_usb_keyboards[i].name = NULL;
|
2010-08-21 21:09:37 +00:00
|
|
|
|
grub_free (grub_usb_keyboards[i].data);
|
2010-07-17 01:57:59 +00:00
|
|
|
|
grub_usb_keyboards[i].data = 0;
|
|
|
|
|
}
|
|
|
|
|
grub_usb_unregister_attach_hook_class (&attach_hook);
|
2009-02-21 14:55:06 +00:00
|
|
|
|
}
|