4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
33 * \author Andrea Righi <arighi@develer.com>
35 * \brief Generic USB mouse device driver.
39 #include "cfg/cfg_usb_mouse.h"
41 #define LOG_LEVEL USB_MOUSE_LOG_LEVEL
42 #define LOG_FORMAT USB_MOUSE_LOG_FORMAT
45 #include <cfg/debug.h>
46 #include <cfg/macros.h>
47 #include <cfg/compiler.h>
48 #include <cfg/module.h>
50 #include <cpu/power.h> // cpu_relax()
54 #include "drv/usb_hid.h"
55 #include "drv/usb_mouse.h"
58 * HID device configuration (usb-mouse)
60 #define USB_HID_VENDOR_ID 0xffff /* custom */
61 #define USB_HID_PRODUCT_ID 0x0000
63 #define USB_HID_INTERFACES 1
64 #define USB_HID_ENDPOINTS 1
66 #define USB_STRING_MANUFACTURER 1
67 #define USB_STRING_PRODUCT 2
69 #define USB_HID_REPORT_EP (USB_DIR_IN | 1)
71 static usb_device_descriptor_t usb_hid_device_descriptor =
73 .bLength = sizeof(usb_hid_device_descriptor),
74 .bDescriptorType = USB_DT_DEVICE,
76 .bDeviceClass = USB_CLASS_HID,
79 .idVendor = USB_HID_VENDOR_ID,
80 .idProduct = USB_HID_PRODUCT_ID,
82 .iManufacturer = USB_STRING_MANUFACTURER,
83 .iProduct = USB_STRING_PRODUCT,
85 .bNumConfigurations = 1,
88 static const usb_config_descriptor_t usb_hid_config_descriptor =
90 .bLength = sizeof(usb_hid_config_descriptor),
91 .bDescriptorType = USB_DT_CONFIG,
92 .bNumInterfaces = USB_HID_INTERFACES,
93 .bConfigurationValue = 1,
95 .bmAttributes = USB_CONFIG_ATT_ONE,
96 .bMaxPower = 50, /* 100 mA */
99 static const usb_interface_descriptor_t usb_hid_interface_descriptor =
101 .bLength = sizeof(usb_hid_interface_descriptor),
102 .bDescriptorType = USB_DT_INTERFACE,
103 .bInterfaceNumber = 0,
104 .bAlternateSetting = 0,
105 .bNumEndpoints = USB_HID_ENDPOINTS,
106 .bInterfaceClass = USB_CLASS_HID,
107 .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_BOOT,
108 .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE,
112 static const uint8_t hid_report_descriptor[] =
114 0x05, 0x01, // Usage Page (Generic Desktop)
115 0x09, 0x02, // Usage (Mouse)
116 0xA1, 0x01, // Collection (Application)
117 0x09, 0x01, // Usage (Pointer)
118 0xA1, 0x00, // Collection (Physical)
119 0x05, 0x09, // Usage Page (Buttons)
120 0x19, 0x01, // Usage Minimum (1)
121 0x29, 0x03, // Usage Maximum (3)
122 0x15, 0x00, // Logical Minimum (0)
123 0x25, 0x01, // Logical Maximum (1)
124 0x95, 0x03, // Report Count (3)
125 0x75, 0x01, // Report Size (1)
126 0x81, 0x02, // Input (Data, Variable, Absolute)
127 0x95, 0x01, // Report Count (1)
128 0x75, 0x05, // Report Size (5)
129 0x81, 0x01, // Input (03=Logitech, 01=Hid spec:Constant)
130 0x05, 0x01, // Usage Page (Generic Desktop)
131 0x09, 0x30, // Usage (X)
132 0x09, 0x31, // Usage (Y)
133 0x09, 0x38, // Usage (Logitech:_)
134 0x15, 0x81, // Logical Minimum (-127)
135 0x25, 0x7F, // Logical Maximum (127)
136 0x75, 0x08, // Report Size (8)
137 0x95, 0x02, // Report Count (Logitech=3, Hid spec =2)
138 0x81, 0x06, // Input (Data, Variable, Relative)
139 0xC0, // End Collection
140 0xC0 // End Collection
143 static const usb_hid_descriptor_t usb_hid_descriptor =
145 .bLength = sizeof(usb_hid_descriptor),
146 .bDescriptorType = HID_DT_HID,
147 .bcdHID = usb_cpu_to_le16(0x0110),
149 .bNumDescriptors = 1,
150 .bDescriptorHidType = HID_DT_REPORT,
151 .wDescriptorLength = usb_cpu_to_le16(sizeof(hid_report_descriptor)),
154 static const usb_endpoint_descriptor_t usb_hid_ep_descriptor =
156 .bLength = sizeof(usb_hid_ep_descriptor),
157 .bDescriptorType = USB_DT_ENDPOINT,
158 .bEndpointAddress = USB_HID_REPORT_EP,
159 .bmAttributes = USB_ENDPOINT_XFER_INT,
160 .wMaxPacketSize = usb_cpu_to_le16(4),
161 .bInterval = 10, /* resolution in ms */
164 static const usb_descriptor_header_t *usb_hid_config[] =
166 (const usb_descriptor_header_t *)&usb_hid_config_descriptor,
167 (const usb_descriptor_header_t *)&usb_hid_interface_descriptor,
168 (const usb_descriptor_header_t *)&usb_hid_descriptor,
169 (const usb_descriptor_header_t *)&usb_hid_ep_descriptor,
173 static DEFINE_USB_STRING(language_str, "\x09\x04"); // Language ID: en_US
174 static DEFINE_USB_STRING(manufacturer_str,
175 USB_STRING("B", "e", "R", "T", "O", "S"));
176 static DEFINE_USB_STRING(product_str,
177 USB_STRING("U", "S", "B", " ", "M", "o", "u", "s", "e"));
179 static const usb_string_descriptor_t *usb_hid_strings[] =
181 (usb_string_descriptor_t *)&language_str,
182 (usb_string_descriptor_t *)&manufacturer_str,
183 (usb_string_descriptor_t *)&product_str,
187 typedef struct mouse_report
192 } PACKED mouse_report_t;
194 static mouse_report_t report;
196 static bool hid_mouse_configured;
198 static void usb_hid_event_cb(usb_ctrlrequest_t *ctrl)
200 uint16_t value = usb_le16_to_cpu(ctrl->wValue);
201 uint16_t index = usb_le16_to_cpu(ctrl->wIndex);
202 uint16_t length = usb_le16_to_cpu(ctrl->wLength);
203 uint8_t type = ctrl->mRequestType;
204 uint8_t request = ctrl->bRequest;
206 LOG_INFO("%s: s 0x%02x 0x%02x 0x%04x 0x%04x 0x%04x\n",
207 __func__, type, request, value, index, length);
208 switch (ctrl->bRequest)
210 case USB_REQ_GET_DESCRIPTOR:
214 LOG_INFO("%s: HID_DT_HID\n", __func__);
215 usb_ep_write(USB_DIR_IN | 0,
217 sizeof(usb_hid_descriptor));
220 LOG_INFO("%s: HID_DT_REPORT\n", __func__);
221 usb_ep_write(USB_DIR_IN | 0,
222 &hid_report_descriptor,
223 sizeof(hid_report_descriptor));
224 hid_mouse_configured = true;
228 case HID_REQ_GET_REPORT:
229 LOG_INFO("%s: HID_REQ_GET_REPORT\n", __func__);
231 case HID_REQ_SET_REPORT:
232 LOG_INFO("%s: HID_REQ_SET_REPORT\n", __func__);
234 case HID_REQ_GET_IDLE:
235 LOG_INFO("%s: HID_REQ_GET_IDLE\n", __func__);
237 case HID_REQ_SET_IDLE:
238 LOG_INFO("%s: HID_REQ_SET_IDLE\n", __func__);
239 usb_ep_write(USB_DIR_IN | 0, NULL, 0);
241 case HID_REQ_GET_PROTOCOL:
242 LOG_INFO("%s: HID_REQ_GET_PROTOCOL\n", __func__);
244 case HID_REQ_SET_PROTOCOL:
245 LOG_INFO("%s: HID_REQ_SET_PROTOCOL\n", __func__);
248 LOG_ERR("%s: unknown request: 0x%02x\n",
249 __func__, ctrl->bRequest);
254 /* Global usb-mouse descriptor that identifies the usb-mouse device */
255 static struct usb_device usb_mouse = {
256 .device = &usb_hid_device_descriptor,
257 .config = usb_hid_config,
258 .strings = usb_hid_strings,
259 .event_cb = usb_hid_event_cb,
262 /* Low-level usb-hid device initialization */
263 static int usb_mouse_hw_init(void)
265 if (usb_device_register(&usb_mouse) < 0)
267 LOG_INFO("usb-hid: registered new USB mouse device\n");
271 /* Send a mouse event */
272 void usb_mouse_send_event(int8_t x, int8_t y, int8_t buttons)
276 report.buttons = buttons;
277 usb_ep_write(USB_HID_REPORT_EP, &report, sizeof(report));
281 * Initialize a USB HID device.
283 * TODO: support more than one device at the same time.
285 int usb_mouse_init(UNUSED_ARG(int, unit))
291 while (!hid_mouse_configured)