1 /*****************************************************************************
2 * Copyright (c) 2013 IBM Corporation
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
21 * HID Spec Version 1.11
24 #define HID_REQ_GET_REPORT 0x01
25 #define HID_REQ_GET_IDLE 0x02
26 #define HID_REQ_GET_PROTOCOL 0x03
27 #define HID_REQ_SET_REPORT 0x09
28 #define HID_REQ_SET_IDLE 0x0A
29 #define HID_REQ_SET_PROTOCOL 0x0B
31 //key position for latin letters
32 #define KEYP_LATIN_A 4
33 #define KEYP_LATIN_Z 29
37 /* HID SPEC - 7.2.6 Set_Protocol Request */
38 static int usb_hid_set_protocol(struct usb_dev *dev, uint16_t value)
40 struct usb_dev_req req;
43 req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
44 req.bRequest = HID_REQ_SET_PROTOCOL;
45 req.wValue = cpu_to_le16(value);
46 req.wIndex = cpu_to_le16(dev->intf_num);
48 return usb_send_ctrl(dev->control, &req, NULL);
51 /* HID SPEC - 7.2.4 Set_Idle Request */
52 static int usb_hid_set_idle(struct usb_dev *dev, uint16_t ms_delay)
54 struct usb_dev_req req;
57 req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
58 req.bRequest = HID_REQ_SET_IDLE;
59 req.wValue = cpu_to_le16((ms_delay/4) << 8);
60 req.wIndex = cpu_to_le16(dev->intf_num);
62 return usb_send_ctrl(dev->control, &req, NULL);
65 /* HID SPEC - 7.2.1 Get Report Request */
66 static int usb_hid_get_report(struct usb_dev *dev, void *data, size_t size)
68 struct usb_dev_req req;
71 req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_IN;
72 req.bRequest = HID_REQ_GET_REPORT;
73 req.wIndex = cpu_to_le16(dev->intf_num);
75 req.wLength = cpu_to_le16((uint16_t)size);
76 req.wValue = cpu_to_le16(1 << 8);
77 return usb_send_ctrl(dev->control, &req, data);
80 /* ring buffer with RD/WR indices for key buffering */
81 static uint8_t keybuf[256]; /* size fixed to byte range ! */
82 uint8_t r_ptr = 0; /* RD-index for Keyboard-Buffer */
83 uint8_t w_ptr = 0; /* WR-index for Keyboard-Buffer */
85 /* variables for LED status */
87 const uint8_t *key_std = NULL;
88 const uint8_t *key_std_shift = NULL;
90 uint8_t ctrl; /* modifiers */
93 * read character from Keyboard-Buffer
97 * = 0 if no key available
99 static int read_key(void)
102 return (int)keybuf[r_ptr++];
108 * Store character into Keyboard-Buffer
110 * @param Key = detected ASCII-Key (> 0)
113 static void write_key(uint8_t key)
115 if ((w_ptr + 1) != r_ptr)
116 keybuf[w_ptr++] = key;
120 * Checks if keypos is a latin key
124 static bool is_latin(uint8_t keypos)
126 return keypos >= KEYP_LATIN_A && keypos <= KEYP_LATIN_Z;
130 * Convert keyboard usage-ID to ANSI-Code
132 * @param Ctrl=Modifier Byte
133 * Key =Usage ID from USB Keyboard
136 static void get_char(uint8_t ctrl, uint8_t keypos)
142 printf("pos %02X\n", keypos);
145 if (set_leds & LED_CAPS_LOCK) /* is CAPS Lock set ? */
148 /* caps is a shift only for latin chars */
149 if ((!caps && ctrl == 0) || (caps && !is_latin(keypos))) {
150 ch = key_std[keypos];
156 if ((ctrl & MODIFIER_SHIFT) || caps) {
157 ch = key_std_shift[keypos];
163 if (ctrl & MODIFIER_CTRL) {
164 ch = keycodes_ctrl[keypos];
170 if (ctrl == MODIFIER_ALT_GR) {
171 ch = keycodes_alt_GR[keypos];
178 static void check_key_code(uint8_t *buf)
180 static uint8_t key_last[6]; /* list of processed keys */
181 uint8_t i, j, key_pos;
183 /* set translation table to defaults */
184 if ((key_std == NULL) || (key_std_shift == NULL)) {
185 key_std = keycodes_std_US;
186 key_std_shift = keycodes_shift_US;
189 if (buf[0] & MODIFIER_SHIFT) /* any shift key pressed ? */
190 set_leds &= ~LED_CAPS_LOCK; /* CAPS-LOCK-LED always off */
192 i = 2; /* skip modifier byte and reserved byte */
195 if ((key_pos != 0) && (key_pos <= 100)) { /* support for 101 keys */
197 /* search if already processed */
198 while ((j < 6) && (key_pos != key_last[j]))
201 if (j >= 6) { /* not found (= not processed) */
203 case 0x39: /* caps-lock key ? */
204 case 0x32: /* caps-lock key ? */
205 set_leds ^= LED_CAPS_LOCK;
208 case 0x36: /*Shift pressed*/
209 ctrl |= MODIFIER_SHIFT;
211 case 0xb6: /*Shift unpressed*/
212 ctrl &= ~MODIFIER_SHIFT;
229 write_key(0x1b); /* F3 */
236 write_key(0x1b); /* F4 */
243 write_key(0x1b); /* F5 */
251 write_key(0x1b); /* F6 */
259 write_key(0x1b); /* F7 */
267 write_key(0x1b); /* F8 */
275 write_key(0x1b); /* F9 */
283 write_key(0x1b); /* F10 */
291 write_key(0x1b); /* F11 */
299 write_key(0x1b); /* F12 */
306 case 0x47: /* scroll-lock key ? */
307 set_leds ^= LED_SCROLL_LOCK;
311 write_key(0x1b); /* INS */
318 write_key(0x1b); /* HOME */
324 write_key(0x1b); /* PgUp */
331 write_key(0x1b); /* DEL */
338 write_key(0x1b); /* END */
344 write_key(0x1b); /* PgDn */
351 write_key(0x1b); /* R-Arrow */
357 write_key(0x1b); /* L-Arrow */
363 write_key(0x1b); /* D-Arrow */
369 write_key(0x1b); /* U-Arrow */
374 case 0x53: /* num-lock key ? */
375 set_leds ^= LED_NUM_LOCK;
379 /* convert key position to ASCII code */
380 get_char(buf[0], key_pos);
387 /*****************************************/
388 /* all keys are processed, create a copy */
389 /* to flag them as processed */
390 /*****************************************/
391 for (i = 2, j = 0; j < 6; i++, j++)
392 key_last[j] = buf[i]; /* copy all actual keys to last */
395 #define USB_HID_SIZE 128
396 uint32_t *kbd_buffer;
398 int usb_hid_kbd_init(struct usb_dev *dev)
403 usb_hid_set_protocol(dev, 0);
404 usb_hid_set_idle(dev, 500);
407 if (usb_hid_get_report(dev, key, 8))
410 kbd_buffer = SLOF_dma_alloc(USB_HID_SIZE);
412 printf("%s: unable to allocate keyboard buffer\n", __func__);
417 printf("HID kbd init %d\n", dev->ep_cnt);
419 for (i = 0; i < dev->ep_cnt; i++) {
420 if ((dev->ep[i].bmAttributes & USB_EP_TYPE_MASK)
422 usb_dev_populate_pipe(dev, &dev->ep[i], kbd_buffer, USB_HID_SIZE);
427 int usb_hid_kbd_exit(struct usb_dev *dev)
430 usb_put_pipe(dev->intr);
433 SLOF_dma_free(kbd_buffer, USB_HID_SIZE);
437 static int usb_poll_key(void *vdev)
439 struct usb_dev *dev = vdev;
444 rc = usb_poll_intr(dev->intr, key);
450 unsigned char usb_key_available(void *dev)
462 unsigned char usb_read_keyb(void *vdev)
464 if (usb_key_available(vdev))