From 7ea880172d48dd62a799e49e34b8fc1a4ecb82f5 Mon Sep 17 00:00:00 2001 From: arighi Date: Wed, 22 Sep 2010 10:49:14 +0000 Subject: [PATCH] USB: add generic usb-mouse device driver (EXPERIMENTAL) git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4261 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cfg/cfg_usb_mouse.h | 57 +++++++ bertos/drv/usb_hid.h | 79 ++++++++++ bertos/drv/usb_mouse.c | 294 +++++++++++++++++++++++++++++++++++++ bertos/drv/usb_mouse.h | 48 ++++++ 4 files changed, 478 insertions(+) create mode 100644 bertos/cfg/cfg_usb_mouse.h create mode 100644 bertos/drv/usb_hid.h create mode 100644 bertos/drv/usb_mouse.c create mode 100644 bertos/drv/usb_mouse.h diff --git a/bertos/cfg/cfg_usb_mouse.h b/bertos/cfg/cfg_usb_mouse.h new file mode 100644 index 00000000..0244360a --- /dev/null +++ b/bertos/cfg/cfg_usb_mouse.h @@ -0,0 +1,57 @@ +/** + * \file + * + * + * \author Andrea Righi + * + * \brief Configuration file for the usb-mouse driver module + */ + +#ifndef CFG_USB_MOUSE_H +#define CFG_USB_MOUSE_H + +/** + * Module logging level. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_level" + */ +#define USB_MOUSE_LOG_LEVEL LOG_LVL_INFO + +/** + * module logging format. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_format" + */ +#define USB_MOUSE_LOG_FORMAT LOG_FMT_TERSE + +#endif /* CFG_USB_MOUSE_H */ diff --git a/bertos/drv/usb_hid.h b/bertos/drv/usb_hid.h new file mode 100644 index 00000000..0253809d --- /dev/null +++ b/bertos/drv/usb_hid.h @@ -0,0 +1,79 @@ +/** + * \file + * + * + * \author Andrea Righi + * + * \brief Generic USB Human Interface Device (HID) driver. + */ + +#ifndef USB_HID_H +#define USB_HID_H + +/* + * USB HID interface subclass and protocol codes + */ +#define USB_INTERFACE_SUBCLASS_BOOT 1 +#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 +#define USB_INTERFACE_PROTOCOL_MOUSE 2 + +/* + * HID class requests + */ +#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 + +/* + * HID class descriptor types + */ +#define HID_DT_HID (USB_TYPE_CLASS | 0x01) +#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) +#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) + +/* + * USB HID descriptor + */ +typedef struct usb_hid_descriptor +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bDescriptorHidType; + uint16_t wDescriptorLength; +} PACKED usb_hid_descriptor_t; + +#endif /* USB_HID_H */ diff --git a/bertos/drv/usb_mouse.c b/bertos/drv/usb_mouse.c new file mode 100644 index 00000000..35a73f8c --- /dev/null +++ b/bertos/drv/usb_mouse.c @@ -0,0 +1,294 @@ +/** + * \file + * + * + * \author Andrea Righi + * + * \brief Generic USB mouse device driver. + * + */ + +#include "cfg/cfg_usb_mouse.h" + +#define LOG_LEVEL USB_MOUSE_LOG_LEVEL +#define LOG_FORMAT USB_MOUSE_LOG_FORMAT + +#include +#include +#include +#include +#include + +#include // cpu_relax() + +#include + +#include "drv/usb_hid.h" +#include "drv/usb_mouse.h" + +/* + * HID device configuration (usb-mouse) + */ +#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 = USB_CLASS_HID, + .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_MOUSE, + .iInterface = 0, +}; + +static const uint8_t hid_report_descriptor[] = +{ + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Buttons) + 0x19, 0x01, // Usage Minimum (1) + 0x29, 0x03, // Usage Maximum (3) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x03, // Report Count (3) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0x95, 0x01, // Report Count (1) + 0x75, 0x05, // Report Size (5) + 0x81, 0x01, // Input (03=Logitech, 01=Hid spec:Constant) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Logitech:_) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x02, // Report Count (Logitech=3, Hid spec =2) + 0x81, 0x06, // Input (Data, Variable, Relative) + 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", " ", "M", "o", "u", "s", "e")); + +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, +}; + +typedef struct mouse_report +{ + uint8_t buttons; + int8_t x; + int8_t y; +} PACKED mouse_report_t; + +static mouse_report_t report; + +static bool hid_mouse_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_mouse_configured = true; + 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-serial descriptor that identifies the usb-serial device */ +static struct usb_device usb_mouse = { + .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_mouse_hw_init(void) +{ + if (usb_device_register(&usb_mouse) < 0) + return -1; + LOG_INFO("usb-hid: registered new USB mouse device\n"); + return 0; +} + +/* Send a mouse event */ +void usb_mouse_send_event(int8_t x, int8_t y, int8_t buttons) +{ + report.x = x; + report.y = y; + report.buttons = buttons; + usb_ep_write(USB_HID_REPORT_EP, &report, sizeof(report)); +} + +/* + * Initialize a USB HID device. + * + * TODO: support more than one device at the same time. + */ +int usb_mouse_init(UNUSED_ARG(int, unit)) +{ +#if CONFIG_KERN + MOD_CHECK(proc); +#endif + usb_mouse_hw_init(); + while (!hid_mouse_configured) + cpu_relax(); + return 0; +} diff --git a/bertos/drv/usb_mouse.h b/bertos/drv/usb_mouse.h new file mode 100644 index 00000000..4ffbe81f --- /dev/null +++ b/bertos/drv/usb_mouse.h @@ -0,0 +1,48 @@ +/** + * \file + * + * + * \author Andrea Righi + * + * \brief Generic USB mouse device driver. + * + * $WIZ$ module_name = "usb_mouse" + * $WIZ$ module_configuration = "bertos/cfg/cfg_usb_mouse.h" + * $WIZ$ module_depends = "usb" + */ + +#ifndef USB_MOUSE_H +#define USB_MOUSE_H + +void usb_mouse_send_event(int8_t x, int8_t y, int8_t buttons); +int usb_mouse_init(int unit); + +#endif /* USB_MOUSE_H */ -- 2.25.1