From 2a085f4477dc4d988d53c6a02295d05849f309d9 Mon Sep 17 00:00:00 2001 From: Frank Gevaerts Date: Sun, 19 Apr 2009 21:17:18 +0000 Subject: [PATCH] Add preliminary HID driver. It doesn't do anything yet, but that should change soon (FS#10116 by Tomer Shalev) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20750 a1c6a512-1295-4272-9138-f99709370657 --- apps/debug_menu.c | 48 ++++-- firmware/SOURCES | 1 + firmware/export/usb.h | 1 + firmware/export/usb_core.h | 1 + firmware/usbstack/usb_core.c | 27 +++- firmware/usbstack/usb_hid.c | 288 +++++++++++++++++++++++++++++++++++ firmware/usbstack/usb_hid.h | 38 +++++ 7 files changed, 391 insertions(+), 13 deletions(-) create mode 100644 firmware/usbstack/usb_hid.c create mode 100644 firmware/usbstack/usb_hid.h diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 2912129a1a..5fa666796b 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -2583,15 +2583,36 @@ static bool dbg_scrollwheel(void) } #endif -#if defined(HAVE_USBSTACK) && defined(ROCKBOX_HAS_LOGF) && defined(USB_SERIAL) -static bool logf_usb_serial(void) +#if defined (HAVE_USBSTACK) +static bool toggle_usb_core_driver(int driver, char *msg) { - bool serial_enabled = !usb_core_driver_enabled(USB_DRIVER_SERIAL); - usb_core_enable_driver(USB_DRIVER_SERIAL,serial_enabled); - splashf(HZ, "USB logf %s", - serial_enabled?"enabled":"disabled"); + bool enabled = !usb_core_driver_enabled(driver); + + usb_core_enable_driver(driver,enabled); + splashf(HZ, "%s %s", msg, enabled?"enabled":"disabled"); + return false; } +#if 0 && defined(USB_STORAGE) +static bool toggle_usb_mass_storage(void) +{ + return toggle_usb_core_driver(USB_DRIVER_MASS_STORAGE,"USB Mass Storage"); +} +#endif + +#if defined(ROCKBOX_HAS_LOGF) && defined(USB_SERIAL) +static bool toggle_usb_serial(void) +{ + return toggle_usb_core_driver(USB_DRIVER_SERIAL,"USB Serial"); +} +#endif + +#if defined(USB_HID) +static bool toggle_usb_hid(void) +{ + return toggle_usb_core_driver(USB_DRIVER_HID, "USB HID"); +} +#endif #endif #if CONFIG_USBOTG == USBOTG_ISP1583 @@ -2728,17 +2749,22 @@ static const struct the_menu_item menuitems[] = { {"logf", logfdisplay }, {"logfdump", logfdump }, #endif -#if defined(HAVE_USBSTACK) && defined(ROCKBOX_HAS_LOGF) && defined(USB_SERIAL) - {"logf over usb",logf_usb_serial }, +#if defined(HAVE_USBSTACK) +#if 0 && defined(USB_STORAGE) + {"USB Mass-Storage driver", toggle_usb_mass_storage }, #endif -#if 0 && defined(HAVE_USBSTACK) && defined(USB_STORAGE) - {"reconnect usb storage",usb_reconnect}, +#if defined(ROCKBOX_HAS_LOGF) && defined(USB_SERIAL) + {"USB Serial driver (logf)", toggle_usb_serial }, #endif +#if defined(USB_HID) + {"USB HID driver", toggle_usb_hid }, +#endif +#endif /* HAVE_USBSTACK */ #ifdef CPU_BOOST_LOGGING {"cpu_boost log",cpu_boost_log}, #endif #if (defined(HAVE_WHEEL_ACCELERATION) && (CONFIG_KEYPAD==IPOD_4G_PAD) && !defined(SIMULATOR)) - {"Debug scrollwheel", dbg_scrollwheel}, + {"Debug scrollwheel", dbg_scrollwheel }, #endif }; static int menu_action_callback(int btn, struct gui_synclist *lists) diff --git a/firmware/SOURCES b/firmware/SOURCES index adbcb08c95..d96dc8c8a9 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -260,6 +260,7 @@ usbstack/usb_core.c usbstack/usb_storage.c usbstack/usb_serial.c usbstack/usb_charging_only.c +usbstack/usb_hid.c #if CONFIG_USBOTG == USBOTG_ARC target/arm/usb-drv-arc.c #elif CONFIG_USBOTG == USBOTG_ISP1583 diff --git a/firmware/export/usb.h b/firmware/export/usb.h index 2b3452db25..e1bacfffc7 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -93,6 +93,7 @@ enum { USB_DRIVER_MASS_STORAGE, USB_DRIVER_SERIAL, USB_DRIVER_CHARGING_ONLY, + USB_DRIVER_HID, USB_NUM_DRIVERS }; diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h index aac84756f5..abf090ed9d 100644 --- a/firmware/export/usb_core.h +++ b/firmware/export/usb_core.h @@ -26,6 +26,7 @@ //#define USB_SERIAL #define USB_STORAGE #define USB_CHARGING_ONLY +//#define USB_HID #else /* BOOTLOADER */ #define USB_CHARGING_ONLY #endif /* BOOTLOADER */ diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 8c235723ad..838529b484 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -43,6 +43,10 @@ #include "usb_charging_only.h" #endif +#if defined(USB_HID) +#include "usb_hid.h" +#endif + /* TODO: Move target-specific stuff somewhere else (serial number reading) */ #ifdef HAVE_AS3514 @@ -166,8 +170,8 @@ static enum { DEFAULT, ADDRESS, CONFIGURED } usb_state; static int usb_core_num_interfaces; -typedef void (*completion_handler_t)(int ep,int dir, int status, int length); -typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, unsigned char* dest); +typedef void (*completion_handler_t)(int ep,int dir,int status,int length); +typedef bool (*control_handler_t)(struct usb_ctrlrequest* req,unsigned char* dest); static struct { @@ -234,6 +238,25 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] = .notify_hotswap = NULL, #endif }, +#ifdef USB_HID + [USB_DRIVER_HID] = { + .enabled = false, + .needs_exclusive_storage = false, + .first_interface = 0, + .last_interface = 0, + .request_endpoints = usb_hid_request_endpoints, + .set_first_interface = usb_hid_set_first_interface, + .get_config_descriptor = usb_hid_get_config_descriptor, + .init_connection = usb_hid_init_connection, + .init = usb_hid_init, + .disconnect = usb_hid_disconnect, + .transfer_complete = usb_hid_transfer_complete, + .control_request = usb_hid_control_request, +#ifdef HAVE_HOTSWAP + .notify_hotswap = NULL, +#endif + }, +#endif #endif }; diff --git a/firmware/usbstack/usb_hid.c b/firmware/usbstack/usb_hid.c new file mode 100644 index 0000000000..c3cd5d9a04 --- /dev/null +++ b/firmware/usbstack/usb_hid.c @@ -0,0 +1,288 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 by Tomer Shalev + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "string.h" +#include "system.h" +#include "usb_core.h" +#include "usb_drv.h" +#include "kernel.h" +#include "usb_hid.h" +#include "usb_class_driver.h" +#define LOGF_ENABLE +#include "logf.h" + +#ifdef USB_HID + +#define CONCAT(low, high) ((high << 8) | low) +#define SIZE_VALUE 0x01 +/* HID main items (HID1_11.pdf, page 38) */ +#define INPUT (0x80 | SIZE_VALUE) +#define OUTPUT (0x90 | SIZE_VALUE) +#define FEATURE (0xb0 | SIZE_VALUE) +#define COLLECTION (0xa0 | SIZE_VALUE) +#define COLLECTION_APPLICATION CONCAT(COLLECTION, 0x01) +#define END_COLLECTION 0xc0 +/* HID global items (HID1_11.pdf, page 45) */ +#define USAGE_PAGE (0x04 | SIZE_VALUE) +#define LOGICAL_MINIMUM (0x14 | SIZE_VALUE) +#define LOGICAL_MAXIMUM (0x24 | SIZE_VALUE) +#define PHYSICAL_MINIMUM (0x34 | SIZE_VALUE) +#define PHYSICAL_MAXIMUM (0x44 | SIZE_VALUE) +#define UNIT_EXPONENT (0x54 | SIZE_VALUE) +#define UNIT (0x64 | SIZE_VALUE) +#define REPORT_SIZE (0x74 | SIZE_VALUE) +#define REPORT_ID (0x84 | SIZE_VALUE) +#define REPORT_COUNT (0x94 | SIZE_VALUE) +#define PUSH (0xa4 | SIZE_VALUE) +#define POP (0xb4 | SIZE_VALUE) +/* Hut1_12.pdf, Table 1, page 14 */ +#define USAGE_PAGE_CONSUMER CONCAT(USAGE_PAGE, 0x0c) +/* Hut1_12.pdf, Table 17, page 77 */ +#define CONSUMER_USAGE 0x09 +#define CONSUMER_USAGE_CONTROL CONCAT(CONSUMER_USAGE, 0x01) +#define CONSUMER_USAGE_MUTE CONCAT(CONSUMER_USAGE, 0xe2) +#define CONSUMER_USAGE_VOLUME_INCREMENT CONCAT(CONSUMER_USAGE, 0xe9) +#define CONSUMER_USAGE_VOLUME_DECREMENT CONCAT(CONSUMER_USAGE, 0xea) +/* Hut1_12.pdf, Table 4, page 20 */ +#define CONSUMER_CONTROL CONCAT(COLLECTION_APPLICATION, 0x01) + +#define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHYSICAL_DESCRIPTOR 0x23 + +/* serial interface */ +static struct usb_interface_descriptor __attribute__((aligned(2))) + interface_descriptor = +{ + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0 +}; + +/* USB_DT_HID: Endpoint descriptor */ +struct usb_hid_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wBcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bDescriptorType0; + uint16_t wDescriptorLength0; +} __attribute__ ((packed)); + +/* USB_DT_REPORT: Endpoint descriptor */ +static struct usb_hid_descriptor __attribute__((aligned(2))) hid_descriptor = +{ + .bLength = sizeof(struct usb_hid_descriptor), + .bDescriptorType = USB_DT_HID, + .wBcdHID = 0x0100, + .bCountryCode = 0, + .bNumDescriptors = 1, + .bDescriptorType0 = 0x22, + .wDescriptorLength0 = 0 +}; + +static struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor = +{ + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 0, + .bInterval = 0 +}; + +/* USB_DT_REPORT: Endpoint descriptor */ +struct usb_report_descriptor { + uint16_t wUsagePage; + uint16_t wUsage; + uint16_t wCollection; + uint16_t wCollectionItems[12]; + uint8_t wEndCollection; +} __attribute__ ((packed)); + +static struct usb_report_descriptor __attribute__((aligned(2))) report_descriptor = +{ + .wUsagePage = USAGE_PAGE_CONSUMER, + .wUsage = CONSUMER_USAGE_CONTROL, + .wCollection = COLLECTION_APPLICATION, + .wCollectionItems = { + CONCAT(LOGICAL_MINIMUM, 0x0), + CONCAT(LOGICAL_MAXIMUM, 0x1), + USAGE_PAGE_CONSUMER, + CONSUMER_USAGE_MUTE, + CONSUMER_USAGE_VOLUME_INCREMENT, + CONSUMER_USAGE_VOLUME_DECREMENT, + CONCAT(REPORT_COUNT, 0x3), + CONCAT(REPORT_SIZE, 0x1), + CONCAT(INPUT, 0x42), + CONCAT(REPORT_COUNT, 0x5), + CONCAT(REPORT_SIZE, 0x1), + CONCAT(INPUT, 0x01) + }, + .wEndCollection = END_COLLECTION +}; + +static int ep_in; +static int usb_interface; + +int usb_hid_request_endpoints(struct usb_class_driver *drv) +{ + ep_in = usb_core_request_endpoint(USB_DIR_IN, drv); + if (ep_in < 0) + return -1; + + return 0; +} + +int usb_hid_set_first_interface(int interface) +{ + usb_interface = interface; + + return interface + 1; +} + + +int usb_hid_get_config_descriptor(unsigned char *dest,int max_packet_size) +{ + unsigned char *orig_dest = dest; + + logf("hid: config desc."); + interface_descriptor.bInterfaceNumber = usb_interface; + PACK_DESCRIPTOR(dest, interface_descriptor); + + hid_descriptor.wDescriptorLength0 = sizeof(report_descriptor); + PACK_DESCRIPTOR(dest, hid_descriptor); + + /* Ignore max_packet_size and set to 1 bytes long packet size */ + (void)max_packet_size; + endpoint_descriptor.wMaxPacketSize = 1; + endpoint_descriptor.bInterval = 8; + + endpoint_descriptor.bEndpointAddress = ep_in; + PACK_DESCRIPTOR(dest, endpoint_descriptor); + + return (dest - orig_dest); +} + +void usb_hid_init_connection(void) +{ + logf("hid: init connection"); +} + +/* called by usb_code_init() */ +void usb_hid_init(void) +{ + logf("hid: init"); +} + +void usb_hid_disconnect(void) +{ + logf("hid: disconnect"); +} + +/* called by usb_core_transfer_complete() */ +void usb_hid_transfer_complete(int ep,int dir, int status, int length) +{ + (void)ep; + (void)dir; + (void)status; + (void)length; + + logf("hid: transfer complete. ep %d, dir %d, status %d ,length %d", + ep, dir, status, length); +} + +/* HID-only class specific requests */ +#define USB_HID_GET_REPORT 0x01 +#define USB_HID_GET_IDLE 0x02 +#define USB_HID_GET_PROTOCOL 0x03 +#define USB_HID_SET_REPORT 0x09 +#define USB_HID_SET_IDLE 0x0a +#define USB_HID_SET_PROTOCOL 0x0b + +/* called by usb_core_control_request() */ +bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest) +{ + bool handled = false; + + switch(req->bRequestType & USB_TYPE_MASK) { + case USB_TYPE_STANDARD: { + switch(req->wValue>>8) { /* type */ + case USB_DT_REPORT: { + logf("hid: report"); + if (dest == NULL) { + logf("dest is NULL!"); + } + if (dest) { + unsigned char *orig_dest = dest; + PACK_DESCRIPTOR(dest, report_descriptor); + if(usb_drv_send(EP_CONTROL, orig_dest, dest - orig_dest)) + break; + usb_core_ack_control(req); + + } + handled = true; + break; + } + default: + logf("hid: unsup. std. req"); + break; + } + break; + } + + case USB_TYPE_CLASS: { + switch (req->bRequest) { + case USB_HID_SET_IDLE: + logf("hid: set idle"); + usb_core_ack_control(req); + handled = true; + break; + default: + //logf("hid: unsup. cls. req"); + logf("%d: unsup. cls. req", req->bRequest); + break; + } + break; + } + + case USB_TYPE_VENDOR: + logf("hid: unsup. ven. req"); + break; + } + return handled; +} + +void usb_hid_send(unsigned char *data, int length) +{ + (void)data; + (void)(length); + + logf("hid: send %d bytes: \"%s\"", length, data); +} + +#endif /*USB_HID*/ diff --git a/firmware/usbstack/usb_hid.h b/firmware/usbstack/usb_hid.h new file mode 100644 index 0000000000..ff2a33dcbf --- /dev/null +++ b/firmware/usbstack/usb_hid.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 by Tomer Shalev + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef USB_HID_H +#define USB_HID_H + +#include "usb_ch9.h" + +int usb_hid_request_endpoints(struct usb_class_driver *drv); +int usb_hid_set_first_interface(int interface); +int usb_hid_get_config_descriptor(unsigned char *dest, int max_packet_size); +void usb_hid_init_connection(void); +void usb_hid_init(void); +void usb_hid_disconnect(void); +void usb_hid_transfer_complete(int ep, int dir, int status, int length); +bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest); + +void usb_hid_send(unsigned char *data,int length); + +#endif +