BeRTOS
usbkbd.c
Go to the documentation of this file.
00001 
00039 #include "usb_hid.h"
00040 #include "usbkbd.h"
00041 
00042 #include "cfg/cfg_usbkbd.h"
00043 
00044 #define LOG_LEVEL  USB_KEYBOARD_LOG_LEVEL
00045 #define LOG_FORMAT USB_KEYBOARD_LOG_FORMAT
00046 
00047 #include <cfg/log.h>
00048 #include <cfg/debug.h>
00049 #include <cfg/macros.h>
00050 #include <cfg/compiler.h>
00051 #include <cfg/module.h>
00052 
00053 #include <cpu/power.h> // cpu_relax()
00054 
00055 #include <drv/usb.h>
00056 #include <drv/usb_endpoint.h>
00057 
00058 
00059 /*
00060  * HID device configuration (usb-keyboard)
00061  */
00062 #define USB_HID_VENDOR_ID   USB_KEYBOARD_VENDOR_ID
00063 #define USB_HID_PRODUCT_ID  USB_KEYBOARD_PRODUCT_ID
00064 
00065 #define USB_HID_INTERFACES  1
00066 #define USB_HID_ENDPOINTS   1
00067 
00068 #define USB_STRING_MANUFACTURER 1
00069 #define USB_STRING_PRODUCT  2
00070 
00071 #define USB_HID_REPORT_EP   (USB_DIR_IN | USB_KBD_EP_REPORT)
00072 
00073 static UsbDeviceDesc usb_hid_device_descriptor =
00074 {
00075     .bLength = sizeof(usb_hid_device_descriptor),
00076     .bDescriptorType = USB_DT_DEVICE,
00077     .bcdUSB = 0x100,
00078     .bDeviceClass = 0,
00079     .bDeviceSubClass = 0,
00080     .bDeviceProtocol = 0,
00081     .idVendor = USB_HID_VENDOR_ID,
00082     .idProduct = USB_HID_PRODUCT_ID,
00083     .bcdDevice = 0,
00084     .iManufacturer = USB_STRING_MANUFACTURER,
00085     .iProduct = USB_STRING_PRODUCT,
00086     .iSerialNumber = 0,
00087     .bNumConfigurations = 1,
00088 };
00089 
00090 static const UsbConfigDesc usb_hid_config_descriptor =
00091 {
00092     .bLength = sizeof(usb_hid_config_descriptor),
00093     .bDescriptorType = USB_DT_CONFIG,
00094     .bNumInterfaces = USB_HID_INTERFACES,
00095     .bConfigurationValue = 1,
00096     .iConfiguration = 0,
00097     .bmAttributes = USB_CONFIG_ATT_ONE,
00098     .bMaxPower = 50, /* 100 mA */
00099 };
00100 
00101 static const UsbInterfaceDesc usb_hid_interface_descriptor =
00102 {
00103     .bLength = sizeof(usb_hid_interface_descriptor),
00104     .bDescriptorType = USB_DT_INTERFACE,
00105     .bInterfaceNumber = 0,
00106     .bAlternateSetting = 0,
00107     .bNumEndpoints = USB_HID_ENDPOINTS,
00108     .bInterfaceClass = USB_CLASS_HID,
00109     .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_BOOT,
00110     .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_KEYBOARD,
00111     .iInterface = 0,
00112 };
00113 
00114 /*
00115  * Keyboard report descriptor
00116  *
00117  * Taken from the USB HID spec:
00118  *  - E.6 Report Descriptor (Keyboard), HID1_11.pdf, p.69
00119  */
00120 static const uint8_t hid_report_descriptor[] =
00121 {
00122     0x05, 0x01, // Usage Page (Generic Desktop)
00123     0x09, 0x06, // Usage (Keyboard)
00124     0xA1, 0x01, // Collection (Application)
00125     0x05, 0x07, // Usage Page (Key Codes)
00126     0x19, 0xE0, // Usage Minimum (224)
00127     0x29, 0xE7, // Usage Maximum (231)
00128     0x15, 0x00, // Logical Minimum (0)
00129     0x25, 0x01, // Logical Maximum (1)
00130     0x75, 0x01, // Report Size (1)
00131     0x95, 0x08, // Report Count (8)
00132     0x81, 0x02, // Input (Data, Variable, Absolute)
00133     0x95, 0x01, // Report Count (1)
00134     0x75, 0x08, // Report Size (8)
00135     0x81, 0x01, // Input (Constant)
00136     0x95, 0x05, // Report Count (5)
00137     0x75, 0x01, // Report Size (1)
00138     0x05, 0x08, // Usage Page (Page# for LEDs)
00139     0x19, 0x01, // Usage Minimum (1)
00140     0x29, 0x05, // Usage Maximum (5)
00141     0x91, 0x02, // Output (Data, Variable, Absolute)
00142     0x95, 0x01, // Report Count (1)
00143     0x75, 0x03, // Report Size (3)
00144     0x91, 0x01, // Output (Constant)
00145     0x95, 0x06, // Report Count (6)
00146     0x75, 0x08, // Report Size (8)
00147     0x15, 0x00, // Logical Minimum (0)
00148     0x25, 0x65, // Logical Maximum(101)
00149     0x05, 0x07, // Usage Page (Key Codes)
00150     0x19, 0x00, // Usage Minimum (0)
00151     0x29, 0x65, // Usage Maximum (101)
00152     0x81, 0x00, // Input (Data, Array)
00153     0xC0, // End Collection
00154 };
00155 
00156 static const usb_HidDesc usb_hid_descriptor =
00157 {
00158     .bLength = sizeof(usb_hid_descriptor),
00159     .bDescriptorType = HID_DT_HID,
00160     .bcdHID = usb_cpu_to_le16((uint16_t)0x0110),
00161     .bCountryCode = 0,
00162     .bNumDescriptors = 1,
00163     .bDescriptorHidType = HID_DT_REPORT,
00164     .wDescriptorLength =
00165         usb_cpu_to_le16((uint16_t)sizeof(hid_report_descriptor)),
00166 };
00167 
00168 static const UsbEndpointDesc usb_hid_ep_descriptor =
00169 {
00170     .bLength = sizeof(usb_hid_ep_descriptor),
00171     .bDescriptorType = USB_DT_ENDPOINT,
00172     .bEndpointAddress = USB_HID_REPORT_EP,
00173     .bmAttributes = USB_ENDPOINT_XFER_INT,
00174     .wMaxPacketSize = usb_cpu_to_le16((uint16_t)4),
00175     .bInterval = 10, /* resolution in ms */
00176 };
00177 
00178 static const UsbDescHeader *usb_hid_config[] =
00179 {
00180     (const UsbDescHeader *)&usb_hid_config_descriptor,
00181     (const UsbDescHeader *)&usb_hid_interface_descriptor,
00182     (const UsbDescHeader *)&usb_hid_descriptor,
00183     (const UsbDescHeader *)&usb_hid_ep_descriptor,
00184     NULL,
00185 };
00186 
00187 static const DEFINE_USB_STRING(language_str, "\x09\x04"); // Language ID: en_US
00188 static const DEFINE_USB_STRING(manufacturer_str,
00189         USB_STRING("B", "e", "R", "T", "O", "S"));
00190 static const DEFINE_USB_STRING(product_str,
00191         USB_STRING("U", "S", "B", " ",
00192                 "K", "e", "y", "b", "o", "a", "r", "d"));
00193 
00194 static const UsbStringDesc *usb_hid_strings[] =
00195 {
00196     (const UsbStringDesc *)&language_str,
00197     (const UsbStringDesc *)&manufacturer_str,
00198     (const UsbStringDesc *)&product_str,
00199     NULL,
00200 };
00201 
00202 static uint8_t report[8];
00203 
00204 static bool hid_keyboard_configured;
00205 
00206 static void usb_hid_event_cb(UsbCtrlRequest *ctrl)
00207 {
00208     uint16_t value = usb_le16_to_cpu(ctrl->wValue);
00209     uint16_t index = usb_le16_to_cpu(ctrl->wIndex);
00210     uint16_t length = usb_le16_to_cpu(ctrl->wLength);
00211     uint8_t type = ctrl->mRequestType;
00212     uint8_t request = ctrl->bRequest;
00213 
00214     LOG_INFO("%s: s 0x%02x 0x%02x 0x%04x 0x%04x 0x%04x\n",
00215         __func__, type, request, value, index, length);
00216     switch (ctrl->bRequest)
00217     {
00218     case USB_REQ_GET_DESCRIPTOR:
00219         switch (value >> 8)
00220         {
00221         case HID_DT_HID:
00222             LOG_INFO("%s: HID_DT_HID\n", __func__);
00223             usb_endpointWrite(USB_DIR_IN | 0,
00224                     &usb_hid_descriptor,
00225                     sizeof(usb_hid_descriptor));
00226             break;
00227         case HID_DT_REPORT:
00228             LOG_INFO("%s: HID_DT_REPORT\n", __func__);
00229             usb_endpointWrite(USB_DIR_IN | 0,
00230                     &hid_report_descriptor,
00231                     sizeof(hid_report_descriptor));
00232             hid_keyboard_configured = true;
00233             break;
00234         default:
00235             LOG_INFO("%s: unknown HID request\n", __func__);
00236             break;
00237         }
00238         break;
00239     case HID_REQ_GET_REPORT:
00240         LOG_INFO("%s: HID_REQ_GET_REPORT\n", __func__);
00241         break;
00242     case HID_REQ_SET_REPORT:
00243         LOG_INFO("%s: HID_REQ_SET_REPORT\n", __func__);
00244         usb_endpointWrite(USB_DIR_IN | 0, NULL, 0);
00245         break;
00246     case HID_REQ_GET_IDLE:
00247         LOG_INFO("%s: HID_REQ_GET_IDLE\n", __func__);
00248         break;
00249     case HID_REQ_SET_IDLE:
00250         LOG_INFO("%s: HID_REQ_SET_IDLE\n", __func__);
00251         usb_endpointWrite(USB_DIR_IN | 0, NULL, 0);
00252         break;
00253     case HID_REQ_GET_PROTOCOL:
00254         LOG_INFO("%s: HID_REQ_GET_PROTOCOL\n", __func__);
00255         break;
00256     case HID_REQ_SET_PROTOCOL:
00257         LOG_INFO("%s: HID_REQ_SET_PROTOCOL\n", __func__);
00258         break;
00259     default:
00260         LOG_ERR("%s: unknown request: 0x%02x\n",
00261             __func__, ctrl->bRequest);
00262         break;
00263     }
00264 }
00265 
00266 /* Global usb-keyboard descriptor that identifies the usb-keyboard device */
00267 static UsbDevice usb_keyboard = {
00268     .device = &usb_hid_device_descriptor,
00269     .config = usb_hid_config,
00270     .strings = usb_hid_strings,
00271     .event_cb = usb_hid_event_cb,
00272 };
00273 
00274 /* Low-level usb-hid device initialization */
00275 static int usb_keyboard_hw_init(void)
00276 {
00277     if (usb_deviceRegister(&usb_keyboard) < 0)
00278         return -1;
00279     LOG_INFO("usb-hid: registered new USB keyboard device\n");
00280     return 0;
00281 }
00282 
00283 /* Send a keyboard event */
00284 void usbkbd_sendEvent(uint8_t mod, uint8_t code)
00285 {
00286     report[0] = mod;
00287     report[2] = code;
00288     usb_endpointWrite(USB_HID_REPORT_EP, &report, sizeof(report));
00289 }
00290 
00291 /*
00292  * Initialize a USB HID keyboard device.
00293  *
00294  * TODO: support more than one device at the same time.
00295  */
00296 int usbkbd_init(UNUSED_ARG(int, unit))
00297 {
00298 #if CONFIG_KERN
00299     MOD_CHECK(proc);
00300 #endif
00301     usb_keyboard_hw_init();
00302     while (!hid_keyboard_configured)
00303         cpu_relax();
00304     return 0;
00305 }