Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / lib / libusb / usb-hid.c
diff --git a/qemu/roms/SLOF/lib/libusb/usb-hid.c b/qemu/roms/SLOF/lib/libusb/usb-hid.c
new file mode 100644 (file)
index 0000000..f0cab8a
--- /dev/null
@@ -0,0 +1,453 @@
+/*****************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <termctrl.h>
+
+#include "usb-core.h"
+#include "usb-key.h"
+
+/*
+ * HID Spec Version 1.11
+ */
+
+#define HID_REQ_GET_REPORT              0x01
+#define HID_REQ_GET_IDLE                0x02
+#define HID_REQ_GET_PROTOCOL            0x03
+#define HID_REQ_SET_REPORT              0x09
+#define HID_REQ_SET_IDLE                0x0A
+#define HID_REQ_SET_PROTOCOL            0x0B
+
+//#define KEY_DEBUG
+
+/* HID SPEC - 7.2.6 Set_Protocol Request */
+static int usb_hid_set_protocol(struct usb_dev *dev, uint16_t value)
+{
+       struct usb_dev_req req;
+       if (!dev)
+               return false;
+       req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
+       req.bRequest = HID_REQ_SET_PROTOCOL;
+       req.wValue = cpu_to_le16(value);
+       req.wIndex = cpu_to_le16(dev->intf_num);
+       req.wLength = 0;
+       return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+/* HID SPEC - 7.2.4 Set_Idle Request */
+static int usb_hid_set_idle(struct usb_dev *dev, uint16_t ms_delay)
+{
+       struct usb_dev_req req;
+       if (!dev)
+               return false;
+       req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT;
+       req.bRequest = HID_REQ_SET_IDLE;
+       req.wValue = cpu_to_le16((ms_delay/4) << 8);
+       req.wIndex = cpu_to_le16(dev->intf_num);
+       req.wLength = 0;
+       return usb_send_ctrl(dev->control, &req, NULL);
+}
+
+/* HID SPEC - 7.2.1 Get Report Request */
+static int usb_hid_get_report(struct usb_dev *dev, void *data, size_t size)
+{
+       struct usb_dev_req req;
+       if (!dev)
+               return false;
+       req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_IN;
+       req.bRequest = HID_REQ_GET_REPORT;
+       req.wIndex = cpu_to_le16(dev->intf_num);
+
+       req.wLength = cpu_to_le16((uint16_t)size);
+       req.wValue = cpu_to_le16(1 << 8);
+       return usb_send_ctrl(dev->control, &req, data);
+}
+
+/* ring buffer with RD/WR indices for key buffering */
+static uint8_t keybuf[256];    /* size fixed to byte range !   */
+uint8_t r_ptr = 0;             /* RD-index for Keyboard-Buffer */
+uint8_t w_ptr = 0;             /* WR-index for Keyboard-Buffer */
+
+/* variables for LED status */
+uint8_t set_leds;
+const uint8_t *key_std       = NULL;
+const uint8_t *key_std_shift = NULL;
+
+/**
+ * read character from Keyboard-Buffer
+ *
+ * @param   -
+ * @return  > 0  Keycode
+ *          = 0  if no key available
+ */
+static int read_key(void)
+{
+       if (r_ptr != w_ptr)
+               return (int)keybuf[r_ptr++];
+       else
+               return false;
+}
+
+/**
+ * Store character into Keyboard-Buffer
+ *
+ * @param   Key = detected ASCII-Key (> 0)
+ * @return  -
+ */
+static void write_key(uint8_t key)
+{
+       if ((w_ptr + 1) != r_ptr)
+               keybuf[w_ptr++] = key;
+}
+
+/**
+ * Convert keyboard usage-ID to ANSI-Code
+ *
+ * @param   Ctrl=Modifier Byte
+ *          Key =Usage ID from USB Keyboard
+ * @return  -
+ */
+static void get_char(uint8_t ctrl, uint8_t keypos)
+{
+       uint8_t ch;
+
+#ifdef KEY_DEBUG
+       printf("pos %02X\n", keypos);
+#endif
+
+       if (set_leds & LED_CAPS_LOCK)                   /* is CAPS Lock set ? */
+               ctrl |= MODIFIER_SHIFT;                     /* simulate shift */
+
+       if (ctrl == 0) {
+               ch = key_std[keypos];
+               if (ch != 0)
+                       write_key(ch);
+               return;
+       }
+
+       if (ctrl & MODIFIER_SHIFT) {
+               ch = key_std_shift[keypos];
+               if (ch != 0)
+                       write_key(ch);
+               return;
+       }
+
+       if (ctrl & MODIFIER_CTRL) {
+               ch = keycodes_ctrl[keypos];
+               if (ch != 0)
+                       write_key(ch);
+               return;
+       }
+
+       if (ctrl == MODIFIER_ALT_GR) {
+               ch = keycodes_alt_GR[keypos];
+               if (ch != 0)
+                       write_key(ch);
+               return;
+       }
+}
+
+static void check_key_code(uint8_t *buf)
+{
+       static uint8_t key_last[6];                 /* list of processed keys */
+       uint8_t i, j, key_pos;
+
+       /* set translation table to defaults */
+       if ((key_std == NULL) || (key_std_shift == NULL)) {
+               key_std       = keycodes_std_US;
+               key_std_shift = keycodes_shift_US;
+       }
+
+       if (buf[0] & MODIFIER_SHIFT)       /* any shift key pressed ? */
+               set_leds &= ~LED_CAPS_LOCK;       /* CAPS-LOCK-LED always off */
+
+       i = 2;  /* skip modifier byte and reserved byte */
+       while (i < 8) {
+               key_pos = buf[i];
+               if ((key_pos != 0) && (key_pos <= 100)) {    /* support for 101 keys */
+                       j = 0;
+                       /* search if already processed */
+                       while ((j < 6) && (key_pos != key_last[j]))
+                               j++;
+
+                       if (j >= 6) {          /* not found (= not processed) */
+                               switch (key_pos) {
+                               case 0x39:                 /* caps-lock key ? */
+                               case 0x32:                 /* caps-lock key ? */
+                                       set_leds ^= LED_CAPS_LOCK;
+                                       break;
+
+                               case 0x3a:                              /* F1 */
+                                       write_key(0x1b);
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x31);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x3b:                              /* F2 */
+                                       write_key(0x1b);
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x32);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x3c:
+                                       write_key(0x1b);               /* F3 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x33);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x3d:
+                                       write_key(0x1b);                /* F4 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x34);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x3e:
+                                       write_key(0x1b);                /* F5 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x35);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x3f:
+                                       write_key(0x1b);                /* F6 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x37);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x40:
+                                       write_key(0x1b);                /* F7 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x38);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x41:
+                                       write_key(0x1b);                /* F8 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x39);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x42:
+                                       write_key(0x1b);                /* F9 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x30);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x43:
+                                       write_key(0x1b);               /* F10 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x31);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x44:
+                                       write_key(0x1b);               /* F11 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x33);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x45:
+                                       write_key(0x1b);               /* F12 */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x34);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x47:               /* scroll-lock key ? */
+                                       set_leds ^= LED_SCROLL_LOCK;
+                                       break;
+
+                               case 0x49:
+                                       write_key(0x1b);               /* INS */
+                                       write_key(0x5b);
+                                       write_key(0x31);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x4a:
+                                       write_key(0x1b);              /* HOME */
+                                       write_key(0x5b);
+                                       write_key(0x32);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x4b:
+                                       write_key(0x1b);              /* PgUp */
+                                       write_key(0x5b);
+                                       write_key(0x33);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x4c:
+                                       write_key(0x1b);               /* DEL */
+                                       write_key(0x5b);
+                                       write_key(0x34);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x4d:
+                                       write_key(0x1b);               /* END */
+                                       write_key(0x5b);
+                                       write_key(0x35);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x4e:
+                                       write_key(0x1b);              /* PgDn */
+                                       write_key(0x5b);
+                                       write_key(0x36);
+                                       write_key(0x7e);
+                                       break;
+
+                               case 0x4f:
+                                       write_key(0x1b);           /* R-Arrow */
+                                       write_key(0x5b);
+                                       write_key(0x43);
+                                       break;
+
+                               case 0x50:
+                                       write_key(0x1b);           /* L-Arrow */
+                                       write_key(0x5b);
+                                       write_key(0x44);
+                                       break;
+
+                               case 0x51:
+                                       write_key(0x1b);           /* D-Arrow */
+                                       write_key(0x5b);
+                                       write_key(0x42);
+                                       break;
+
+                               case 0x52:
+                                       write_key(0x1b);           /* U-Arrow */
+                                       write_key(0x5b);
+                                       write_key(0x41);
+                                       break;
+
+                               case 0x53:                  /* num-lock key ? */
+                                       set_leds ^= LED_NUM_LOCK;
+                                       break;
+
+                               default:
+                                       /* convert key position to ASCII code */
+                                       get_char(buf[0], key_pos);
+                                       break;
+                               }
+                       }
+               }
+               i++;
+       }
+       /*****************************************/
+       /* all keys are processed, create a copy */
+       /* to flag them as processed             */
+       /*****************************************/
+       for (i = 2, j = 0; j < 6; i++, j++)
+               key_last[j] = buf[i];      /* copy all actual keys to last */
+}
+
+#define USB_HID_SIZE 128
+uint32_t *kbd_buffer;
+
+int usb_hid_kbd_init(struct usb_dev *dev)
+{
+       int i;
+       uint8_t key[8];
+
+       usb_hid_set_protocol(dev, 0);
+       usb_hid_set_idle(dev, 500);
+
+       memset(key, 0, 8);
+       if (usb_hid_get_report(dev, key, 8))
+               check_key_code(key);
+
+       kbd_buffer = SLOF_dma_alloc(USB_HID_SIZE);
+       if (!kbd_buffer) {
+               printf("%s: unable to allocate keyboard buffer\n", __func__);
+               return false;
+       }
+
+#ifdef KEY_DEBUG
+       printf("HID kbd init %d\n", dev->ep_cnt);
+#endif
+       for (i = 0; i < dev->ep_cnt; i++) {
+               if ((dev->ep[i].bmAttributes & USB_EP_TYPE_MASK)
+                       == USB_EP_TYPE_INTR)
+                       usb_dev_populate_pipe(dev, &dev->ep[i], kbd_buffer, USB_HID_SIZE);
+       }
+       return true;
+}
+
+int usb_hid_kbd_exit(struct usb_dev *dev)
+{
+       if (dev->intr) {
+               usb_put_pipe(dev->intr);
+               dev->intr = NULL;
+       }
+       SLOF_dma_free(kbd_buffer, USB_HID_SIZE);
+       return true;
+}
+
+static int usb_poll_key(void *vdev)
+{
+       struct usb_dev *dev = vdev;
+       uint8_t key[8];
+       int rc;
+
+       memset(key, 0, 8);
+       rc = usb_poll_intr(dev->intr, key);
+       if (rc)
+               check_key_code(key);
+       return rc;
+}
+
+unsigned char usb_key_available(void *dev)
+{
+       if (!dev)
+               return false;
+
+       usb_poll_key(dev);
+       if (r_ptr != w_ptr)
+               return true;
+       else
+               return false;
+}
+
+unsigned char usb_read_keyb(void *vdev)
+{
+       if (!vdev)
+               return false;
+
+       while (usb_poll_key(vdev)) {
+               /* loop for all pending keys */
+       }
+       return read_key();
+}