usb_keyboard.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /* Support for the HID Boot Protocol. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/term.h>
  20. #include <grub/time.h>
  21. #include <grub/misc.h>
  22. #include <grub/term.h>
  23. #include <grub/usb.h>
  24. #include <grub/dl.h>
  25. #include <grub/time.h>
  26. #include <grub/keyboard_layouts.h>
  27. GRUB_MOD_LICENSE ("GPLv3+");
  28. enum
  29. {
  30. KEY_NO_KEY = 0x00,
  31. KEY_ERR_BUFFER = 0x01,
  32. KEY_ERR_POST = 0x02,
  33. KEY_ERR_UNDEF = 0x03,
  34. KEY_CAPS_LOCK = 0x39,
  35. KEY_NUM_LOCK = 0x53,
  36. };
  37. enum
  38. {
  39. LED_NUM_LOCK = 0x01,
  40. LED_CAPS_LOCK = 0x02
  41. };
  42. /* Valid values for bRequest. See HID definition version 1.11 section 7.2. */
  43. #define USB_HID_GET_REPORT 0x01
  44. #define USB_HID_GET_IDLE 0x02
  45. #define USB_HID_GET_PROTOCOL 0x03
  46. #define USB_HID_SET_REPORT 0x09
  47. #define USB_HID_SET_IDLE 0x0A
  48. #define USB_HID_SET_PROTOCOL 0x0B
  49. #define USB_HID_BOOT_SUBCLASS 0x01
  50. #define USB_HID_KBD_PROTOCOL 0x01
  51. #define GRUB_USB_KEYBOARD_LEFT_CTRL 0x01
  52. #define GRUB_USB_KEYBOARD_LEFT_SHIFT 0x02
  53. #define GRUB_USB_KEYBOARD_LEFT_ALT 0x04
  54. #define GRUB_USB_KEYBOARD_RIGHT_CTRL 0x10
  55. #define GRUB_USB_KEYBOARD_RIGHT_SHIFT 0x20
  56. #define GRUB_USB_KEYBOARD_RIGHT_ALT 0x40
  57. struct grub_usb_keyboard_data
  58. {
  59. grub_usb_device_t usbdev;
  60. grub_uint8_t status;
  61. grub_uint16_t mods;
  62. int interfno;
  63. struct grub_usb_desc_endp *endp;
  64. grub_usb_transfer_t transfer;
  65. grub_uint8_t report[8];
  66. int dead;
  67. int last_key;
  68. grub_uint64_t repeat_time;
  69. grub_uint8_t current_report[8];
  70. grub_uint8_t last_report[8];
  71. int index;
  72. int max_index;
  73. };
  74. static int grub_usb_keyboard_getkey (struct grub_term_input *term);
  75. static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term);
  76. static struct grub_term_input grub_usb_keyboard_term =
  77. {
  78. .getkey = grub_usb_keyboard_getkey,
  79. .getkeystatus = grub_usb_keyboard_getkeystatus,
  80. .next = 0
  81. };
  82. static struct grub_term_input grub_usb_keyboards[16];
  83. static int
  84. interpret_status (grub_uint8_t data0)
  85. {
  86. int mods = 0;
  87. /* Check Shift, Control, and Alt status. */
  88. if (data0 & GRUB_USB_KEYBOARD_LEFT_SHIFT)
  89. mods |= GRUB_TERM_STATUS_LSHIFT;
  90. if (data0 & GRUB_USB_KEYBOARD_RIGHT_SHIFT)
  91. mods |= GRUB_TERM_STATUS_RSHIFT;
  92. if (data0 & GRUB_USB_KEYBOARD_LEFT_CTRL)
  93. mods |= GRUB_TERM_STATUS_LCTRL;
  94. if (data0 & GRUB_USB_KEYBOARD_RIGHT_CTRL)
  95. mods |= GRUB_TERM_STATUS_RCTRL;
  96. if (data0 & GRUB_USB_KEYBOARD_LEFT_ALT)
  97. mods |= GRUB_TERM_STATUS_LALT;
  98. if (data0 & GRUB_USB_KEYBOARD_RIGHT_ALT)
  99. mods |= GRUB_TERM_STATUS_RALT;
  100. return mods;
  101. }
  102. static void
  103. grub_usb_keyboard_detach (grub_usb_device_t usbdev,
  104. int config __attribute__ ((unused)),
  105. int interface __attribute__ ((unused)))
  106. {
  107. unsigned i;
  108. for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
  109. {
  110. struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data;
  111. if (!data)
  112. continue;
  113. if (data->usbdev != usbdev)
  114. continue;
  115. if (data->transfer)
  116. grub_usb_cancel_transfer (data->transfer);
  117. grub_term_unregister_input (&grub_usb_keyboards[i]);
  118. grub_free ((char *) grub_usb_keyboards[i].name);
  119. grub_usb_keyboards[i].name = NULL;
  120. grub_free (grub_usb_keyboards[i].data);
  121. grub_usb_keyboards[i].data = 0;
  122. }
  123. }
  124. static int
  125. grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno)
  126. {
  127. unsigned curnum;
  128. struct grub_usb_keyboard_data *data;
  129. struct grub_usb_desc_endp *endp = NULL;
  130. int j;
  131. grub_dprintf ("usb_keyboard", "%x %x %x %d %d\n",
  132. usbdev->descdev.class, usbdev->descdev.subclass,
  133. usbdev->descdev.protocol, configno, interfno);
  134. for (curnum = 0; curnum < ARRAY_SIZE (grub_usb_keyboards); curnum++)
  135. if (!grub_usb_keyboards[curnum].data)
  136. break;
  137. if (curnum == ARRAY_SIZE (grub_usb_keyboards))
  138. return 0;
  139. if (usbdev->descdev.class != 0
  140. || usbdev->descdev.subclass != 0 || usbdev->descdev.protocol != 0)
  141. return 0;
  142. if (usbdev->config[configno].interf[interfno].descif->subclass
  143. != USB_HID_BOOT_SUBCLASS
  144. || usbdev->config[configno].interf[interfno].descif->protocol
  145. != USB_HID_KBD_PROTOCOL)
  146. return 0;
  147. for (j = 0; j < usbdev->config[configno].interf[interfno].descif->endpointcnt;
  148. j++)
  149. {
  150. endp = &usbdev->config[configno].interf[interfno].descendp[j];
  151. if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp)
  152. == GRUB_USB_EP_INTERRUPT)
  153. break;
  154. }
  155. if (j == usbdev->config[configno].interf[interfno].descif->endpointcnt)
  156. return 0;
  157. grub_dprintf ("usb_keyboard", "HID found!\n");
  158. data = grub_malloc (sizeof (*data));
  159. if (!data)
  160. {
  161. grub_print_error ();
  162. return 0;
  163. }
  164. data->usbdev = usbdev;
  165. data->interfno = interfno;
  166. data->endp = endp;
  167. /* Configure device */
  168. grub_usb_set_configuration (usbdev, configno + 1);
  169. /* Place the device in boot mode. */
  170. grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
  171. USB_HID_SET_PROTOCOL, 0, interfno, 0, 0);
  172. /* Reports every time an event occurs and not more often than that. */
  173. grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
  174. USB_HID_SET_IDLE, 0<<8, interfno, 0, 0);
  175. grub_memcpy (&grub_usb_keyboards[curnum], &grub_usb_keyboard_term,
  176. sizeof (grub_usb_keyboards[curnum]));
  177. grub_usb_keyboards[curnum].data = data;
  178. usbdev->config[configno].interf[interfno].detach_hook
  179. = grub_usb_keyboard_detach;
  180. grub_usb_keyboards[curnum].name = grub_xasprintf ("usb_keyboard%d", curnum);
  181. if (!grub_usb_keyboards[curnum].name)
  182. {
  183. grub_print_error ();
  184. return 0;
  185. }
  186. /* Test showed that getting report may make the keyboard go nuts.
  187. Moreover since we're reattaching keyboard it usually sends
  188. an initial message on interrupt pipe and so we retrieve
  189. the same keystatus.
  190. */
  191. #if 0
  192. {
  193. grub_uint8_t report[8];
  194. grub_usb_err_t err;
  195. grub_memset (report, 0, sizeof (report));
  196. err = grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_IN,
  197. USB_HID_GET_REPORT, 0x0100, interfno,
  198. sizeof (report), (char *) report);
  199. if (err)
  200. data->status = 0;
  201. else
  202. data->status = report[0];
  203. }
  204. #else
  205. data->status = 0;
  206. #endif
  207. data->transfer = grub_usb_bulk_read_background (usbdev,
  208. data->endp,
  209. sizeof (data->report),
  210. (char *) data->report);
  211. if (!data->transfer)
  212. {
  213. grub_print_error ();
  214. return 0;
  215. }
  216. data->last_key = -1;
  217. data->mods = 0;
  218. data->dead = 0;
  219. grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]);
  220. return 1;
  221. }
  222. static void
  223. send_leds (struct grub_usb_keyboard_data *termdata)
  224. {
  225. char report[1];
  226. report[0] = 0;
  227. if (termdata->mods & GRUB_TERM_STATUS_CAPS)
  228. report[0] |= LED_CAPS_LOCK;
  229. if (termdata->mods & GRUB_TERM_STATUS_NUM)
  230. report[0] |= LED_NUM_LOCK;
  231. grub_usb_control_msg (termdata->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
  232. USB_HID_SET_REPORT, 0x0200, termdata->interfno,
  233. sizeof (report), (char *) report);
  234. grub_errno = GRUB_ERR_NONE;
  235. }
  236. static int
  237. parse_keycode (struct grub_usb_keyboard_data *termdata)
  238. {
  239. int index = termdata->index;
  240. int i, keycode;
  241. /* Sanity check */
  242. if (index < 2)
  243. index = 2;
  244. for ( ; index < termdata->max_index; index++)
  245. {
  246. keycode = termdata->current_report[index];
  247. if (keycode == KEY_NO_KEY
  248. || keycode == KEY_ERR_BUFFER
  249. || keycode == KEY_ERR_POST
  250. || keycode == KEY_ERR_UNDEF)
  251. {
  252. /* Don't parse (rest of) this report */
  253. termdata->index = 0;
  254. if (keycode != KEY_NO_KEY)
  255. /* Don't replace last report with current faulty report
  256. * in future ! */
  257. grub_memcpy (termdata->current_report,
  258. termdata->last_report,
  259. sizeof (termdata->report));
  260. return GRUB_TERM_NO_KEY;
  261. }
  262. /* Try to find current keycode in last report. */
  263. for (i = 2; i < 8; i++)
  264. if (keycode == termdata->last_report[i])
  265. break;
  266. if (i < 8)
  267. /* Keycode is in last report, it means it was not released,
  268. * ignore it. */
  269. continue;
  270. if (keycode == KEY_CAPS_LOCK)
  271. {
  272. termdata->mods ^= GRUB_TERM_STATUS_CAPS;
  273. send_leds (termdata);
  274. continue;
  275. }
  276. if (keycode == KEY_NUM_LOCK)
  277. {
  278. termdata->mods ^= GRUB_TERM_STATUS_NUM;
  279. send_leds (termdata);
  280. continue;
  281. }
  282. termdata->last_key = grub_term_map_key (keycode,
  283. interpret_status (termdata->current_report[0])
  284. | termdata->mods);
  285. termdata->repeat_time = grub_get_time_ms () + GRUB_TERM_REPEAT_PRE_INTERVAL;
  286. grub_errno = GRUB_ERR_NONE;
  287. index++;
  288. if (index >= termdata->max_index)
  289. termdata->index = 0;
  290. else
  291. termdata->index = index;
  292. return termdata->last_key;
  293. }
  294. /* All keycodes parsed */
  295. termdata->index = 0;
  296. return GRUB_TERM_NO_KEY;
  297. }
  298. static int
  299. grub_usb_keyboard_getkey (struct grub_term_input *term)
  300. {
  301. grub_usb_err_t err;
  302. struct grub_usb_keyboard_data *termdata = term->data;
  303. grub_size_t actual;
  304. int keycode = GRUB_TERM_NO_KEY;
  305. if (termdata->dead)
  306. return GRUB_TERM_NO_KEY;
  307. if (termdata->index)
  308. keycode = parse_keycode (termdata);
  309. if (keycode != GRUB_TERM_NO_KEY)
  310. return keycode;
  311. /* Poll interrupt pipe. */
  312. err = grub_usb_check_transfer (termdata->transfer, &actual);
  313. if (err == GRUB_USB_ERR_WAIT)
  314. {
  315. if (termdata->last_key != -1
  316. && grub_get_time_ms () > termdata->repeat_time)
  317. {
  318. termdata->repeat_time = grub_get_time_ms ()
  319. + GRUB_TERM_REPEAT_INTERVAL;
  320. return termdata->last_key;
  321. }
  322. return GRUB_TERM_NO_KEY;
  323. }
  324. if (!err && (actual >= 3))
  325. grub_memcpy (termdata->last_report,
  326. termdata->current_report,
  327. sizeof (termdata->report));
  328. grub_memcpy (termdata->current_report,
  329. termdata->report,
  330. sizeof (termdata->report));
  331. termdata->transfer = grub_usb_bulk_read_background (termdata->usbdev,
  332. termdata->endp,
  333. sizeof (termdata->report),
  334. (char *) termdata->report);
  335. if (!termdata->transfer)
  336. {
  337. grub_printf ("%s failed. Stopped\n", term->name);
  338. termdata->dead = 1;
  339. }
  340. termdata->last_key = -1;
  341. grub_dprintf ("usb_keyboard",
  342. "err = %d, actual = %" PRIuGRUB_SIZE
  343. " report: 0x%02x 0x%02x 0x%02x 0x%02x"
  344. " 0x%02x 0x%02x 0x%02x 0x%02x\n",
  345. err, actual,
  346. termdata->current_report[0], termdata->current_report[1],
  347. termdata->current_report[2], termdata->current_report[3],
  348. termdata->current_report[4], termdata->current_report[5],
  349. termdata->current_report[6], termdata->current_report[7]);
  350. if (err || actual < 1)
  351. return GRUB_TERM_NO_KEY;
  352. termdata->status = termdata->current_report[0];
  353. if (actual < 3)
  354. return GRUB_TERM_NO_KEY;
  355. termdata->index = 2; /* New data received. */
  356. termdata->max_index = actual;
  357. return parse_keycode (termdata);
  358. }
  359. static int
  360. grub_usb_keyboard_getkeystatus (struct grub_term_input *term)
  361. {
  362. struct grub_usb_keyboard_data *termdata = term->data;
  363. return interpret_status (termdata->status) | termdata->mods;
  364. }
  365. static struct grub_usb_attach_desc attach_hook =
  366. {
  367. .class = GRUB_USB_CLASS_HID,
  368. .hook = grub_usb_keyboard_attach
  369. };
  370. GRUB_MOD_INIT(usb_keyboard)
  371. {
  372. grub_usb_register_attach_hook_class (&attach_hook);
  373. }
  374. GRUB_MOD_FINI(usb_keyboard)
  375. {
  376. unsigned i;
  377. for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
  378. if (grub_usb_keyboards[i].data)
  379. {
  380. struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data;
  381. if (!data)
  382. continue;
  383. if (data->transfer)
  384. grub_usb_cancel_transfer (data->transfer);
  385. grub_term_unregister_input (&grub_usb_keyboards[i]);
  386. grub_free ((char *) grub_usb_keyboards[i].name);
  387. grub_usb_keyboards[i].name = NULL;
  388. grub_free (grub_usb_keyboards[i].data);
  389. grub_usb_keyboards[i].data = 0;
  390. }
  391. grub_usb_unregister_attach_hook_class (&attach_hook);
  392. }