From e7905422dbc0e498910842902d7f0edc52dd31d2 Mon Sep 17 00:00:00 2001 From: arighi Date: Wed, 22 Sep 2010 16:57:39 +0000 Subject: [PATCH] USB: add generic usb-keyboard device driver (EXPERIMENTAL) git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4264 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cfg/cfg_usb_keyboard.h | 57 +++++++ bertos/drv/usb_keyboard.c | 302 ++++++++++++++++++++++++++++++++++ bertos/drv/usb_keyboard.h | 48 ++++++ 3 files changed, 407 insertions(+) create mode 100644 bertos/cfg/cfg_usb_keyboard.h create mode 100644 bertos/drv/usb_keyboard.c create mode 100644 bertos/drv/usb_keyboard.h diff --git a/bertos/cfg/cfg_usb_keyboard.h b/bertos/cfg/cfg_usb_keyboard.h new file mode 100644 index 00000000..2937c278 --- /dev/null +++ b/bertos/cfg/cfg_usb_keyboard.h @@ -0,0 +1,57 @@ +/** + * \file + * + * + * \author Andrea Righi + * + * \brief Configuration file for the usb-keyboard driver module + */ + +#ifndef CFG_USB_KEYBOARD_H +#define CFG_USB_KEYBOARD_H + +/** + * Module logging level. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_level" + */ +#define USB_KEYBOARD_LOG_LEVEL LOG_LVL_INFO + +/** + * module logging format. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_format" + */ +#define USB_KEYBOARD_LOG_FORMAT LOG_FMT_TERSE + +#endif /* CFG_USB_KEYBOARD_H */ diff --git a/bertos/drv/usb_keyboard.c b/bertos/drv/usb_keyboard.c new file mode 100644 index 00000000..f38c66a1 --- /dev/null +++ b/bertos/drv/usb_keyboard.c @@ -0,0 +1,302 @@ +/** + * \file + * + * + * \author Andrea Righi + * + * \brief Generic USB keyboard device driver. + * + */ + +#include "cfg/cfg_usb_keyboard.h" + +#define LOG_LEVEL USB_KEYBOARD_LOG_LEVEL +#define LOG_FORMAT USB_KEYBOARD_LOG_FORMAT + +#include +#include +#include +#include +#include + +#include // cpu_relax() + +#include + +#include "drv/usb_hid.h" +#include "drv/usb_keyboard.h" + +/* + * HID device configuration (usb-keyboard) + */ +#define USB_HID_VENDOR_ID 0xffff /* custom */ +#define USB_HID_PRODUCT_ID 0x0000 + +#define USB_HID_INTERFACES 1 +#define USB_HID_ENDPOINTS 1 + +#define USB_STRING_MANUFACTURER 1 +#define USB_STRING_PRODUCT 2 + +#define USB_HID_REPORT_EP (USB_DIR_IN | 1) + +static usb_device_descriptor_t usb_hid_device_descriptor = +{ + .bLength = sizeof(usb_hid_device_descriptor), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x100, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .idVendor = USB_HID_VENDOR_ID, + .idProduct = USB_HID_PRODUCT_ID, + .bcdDevice = 0, + .iManufacturer = USB_STRING_MANUFACTURER, + .iProduct = USB_STRING_PRODUCT, + .iSerialNumber = 0, + .bNumConfigurations = 1, +}; + +static const usb_config_descriptor_t usb_hid_config_descriptor = +{ + .bLength = sizeof(usb_hid_config_descriptor), + .bDescriptorType = USB_DT_CONFIG, + .bNumInterfaces = USB_HID_INTERFACES, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = USB_CONFIG_ATT_ONE, + .bMaxPower = 50, /* 100 mA */ +}; + +static const usb_interface_descriptor_t usb_hid_interface_descriptor = +{ + .bLength = sizeof(usb_hid_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = USB_HID_ENDPOINTS, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_BOOT, + .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_KEYBOARD, + .iInterface = 0, +}; + +/* + * Keyboard report descriptor + * + * Taken from the USB HID spec: + * - E.6 Report Descriptor (Keyboard), HID1_11.pdf, p.69 + */ +static const uint8_t hid_report_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection (Application) + 0x05, 0x07, // Usage Page (Key Codes) + 0x19, 0xE0, // Usage Minimum (224) + 0x29, 0xE7, // Usage Maximum (231) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input (Constant) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x05, 0x08, // Usage Page (Page# for LEDs) + 0x19, 0x01, // Usage Minimum (1) + 0x29, 0x05, // Usage Maximum (5) + 0x91, 0x02, // Output (Data, Variable, Absolute) + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x01, // Output (Constant) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x65, // Logical Maximum(101) + 0x05, 0x07, // Usage Page (Key Codes) + 0x19, 0x00, // Usage Minimum (0) + 0x29, 0x65, // Usage Maximum (101) + 0x81, 0x00, // Input (Data, Array) + 0xC0, // End Collection + 0xC0 // End Collection +}; + +static const usb_hid_descriptor_t usb_hid_descriptor = +{ + .bLength = sizeof(usb_hid_descriptor), + .bDescriptorType = HID_DT_HID, + .bcdHID = usb_cpu_to_le16(0x0110), + .bCountryCode = 0, + .bNumDescriptors = 1, + .bDescriptorHidType = HID_DT_REPORT, + .wDescriptorLength = usb_cpu_to_le16(sizeof(hid_report_descriptor)), +}; + +static const usb_endpoint_descriptor_t usb_hid_ep_descriptor = +{ + .bLength = sizeof(usb_hid_ep_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_HID_REPORT_EP, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = usb_cpu_to_le16(4), + .bInterval = 10, /* resolution in ms */ +}; + +static const usb_descriptor_header_t *usb_hid_config[] = +{ + (const usb_descriptor_header_t *)&usb_hid_config_descriptor, + (const usb_descriptor_header_t *)&usb_hid_interface_descriptor, + (const usb_descriptor_header_t *)&usb_hid_descriptor, + (const usb_descriptor_header_t *)&usb_hid_ep_descriptor, + NULL, +}; + +static DEFINE_USB_STRING(language_str, "\x09\x04"); // Language ID: en_US +static DEFINE_USB_STRING(manufacturer_str, + USB_STRING("B", "e", "R", "T", "O", "S")); +static DEFINE_USB_STRING(product_str, + USB_STRING("U", "S", "B", " ", + "K", "e", "y", "b", "o", "a", "r", "d")); + +static const usb_string_descriptor_t *usb_hid_strings[] = +{ + (usb_string_descriptor_t *)&language_str, + (usb_string_descriptor_t *)&manufacturer_str, + (usb_string_descriptor_t *)&product_str, + NULL, +}; + +static uint8_t report[8]; + +static bool hid_keyboard_configured; + +static void usb_hid_event_cb(usb_ctrlrequest_t *ctrl) +{ + uint16_t value = usb_le16_to_cpu(ctrl->wValue); + uint16_t index = usb_le16_to_cpu(ctrl->wIndex); + uint16_t length = usb_le16_to_cpu(ctrl->wLength); + uint8_t type = ctrl->mRequestType; + uint8_t request = ctrl->bRequest; + + LOG_INFO("%s: s 0x%02x 0x%02x 0x%04x 0x%04x 0x%04x\n", + __func__, type, request, value, index, length); + switch (ctrl->bRequest) + { + case USB_REQ_GET_DESCRIPTOR: + switch (value >> 8) + { + case HID_DT_HID: + LOG_INFO("%s: HID_DT_HID\n", __func__); + usb_ep_write(USB_DIR_IN | 0, + &usb_hid_descriptor, + sizeof(usb_hid_descriptor)); + break; + case HID_DT_REPORT: + LOG_INFO("%s: HID_DT_REPORT\n", __func__); + usb_ep_write(USB_DIR_IN | 0, + &hid_report_descriptor, + sizeof(hid_report_descriptor)); + hid_keyboard_configured = true; + break; + default: + LOG_INFO("%s: unknown HID request\n", __func__); + break; + } + break; + case HID_REQ_GET_REPORT: + LOG_INFO("%s: HID_REQ_GET_REPORT\n", __func__); + break; + case HID_REQ_SET_REPORT: + LOG_INFO("%s: HID_REQ_SET_REPORT\n", __func__); + break; + case HID_REQ_GET_IDLE: + LOG_INFO("%s: HID_REQ_GET_IDLE\n", __func__); + break; + case HID_REQ_SET_IDLE: + LOG_INFO("%s: HID_REQ_SET_IDLE\n", __func__); + usb_ep_write(USB_DIR_IN | 0, NULL, 0); + break; + case HID_REQ_GET_PROTOCOL: + LOG_INFO("%s: HID_REQ_GET_PROTOCOL\n", __func__); + break; + case HID_REQ_SET_PROTOCOL: + LOG_INFO("%s: HID_REQ_SET_PROTOCOL\n", __func__); + break; + default: + LOG_ERR("%s: unknown request: 0x%02x\n", + __func__, ctrl->bRequest); + break; + } +} + +/* Global usb-keyboard descriptor that identifies the usb-keyboard device */ +static struct usb_device usb_keyboard = { + .device = &usb_hid_device_descriptor, + .config = usb_hid_config, + .strings = usb_hid_strings, + .event_cb = usb_hid_event_cb, +}; + +/* Low-level usb-hid device initialization */ +static int usb_keyboard_hw_init(void) +{ + if (usb_device_register(&usb_keyboard) < 0) + return -1; + LOG_INFO("usb-hid: registered new USB keyboard device\n"); + return 0; +} + +/* Send a keyboard event */ +void usb_keyboard_send_event(uint8_t mod, uint8_t code) +{ + report[0] = mod; + report[2] = code; + usb_ep_write(USB_HID_REPORT_EP, &report, sizeof(report)); +} + +/* + * Initialize a USB HID keyboard device. + * + * TODO: support more than one device at the same time. + */ +int usb_keyboard_init(UNUSED_ARG(int, unit)) +{ +#if CONFIG_KERN + MOD_CHECK(proc); +#endif + usb_keyboard_hw_init(); + while (!hid_keyboard_configured) + cpu_relax(); + return 0; +} diff --git a/bertos/drv/usb_keyboard.h b/bertos/drv/usb_keyboard.h new file mode 100644 index 00000000..d3a331c6 --- /dev/null +++ b/bertos/drv/usb_keyboard.h @@ -0,0 +1,48 @@ +/** + * \file + * + * + * \author Andrea Righi + * + * \brief Generic USB keyboard device driver. + * + * $WIZ$ module_name = "usb_keyboard" + * $WIZ$ module_configuration = "bertos/cfg/cfg_usb_keyboard.h" + * $WIZ$ module_depends = "usb" + */ + +#ifndef USB_KEYBOARD_H +#define USB_KEYBOARD_H + +void usb_keyboard_send_event(uint8_t mod, uint8_t code); +int usb_keyboard_init(int unit); + +#endif /* USB_KEYBOARD_H */ -- 2.25.1