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