Move unpack lwip ip address macro to macros module.
[bertos.git] / bertos / drv / usbmouse.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
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.
10  *
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.
15  *
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
19  *
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.
28  *
29  * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \author Andrea Righi <arighi@develer.com>
34  *
35  * \brief Generic USB mouse device driver.
36  *
37  * notest: avr
38  * notest: arm
39  */
40
41 #include "usb_hid.h"
42 #include "usbmouse.h"
43
44 #include "cfg/cfg_usbmouse.h"
45
46 #define LOG_LEVEL  USB_MOUSE_LOG_LEVEL
47 #define LOG_FORMAT USB_MOUSE_LOG_FORMAT
48
49 #include <cfg/log.h>
50 #include <cfg/debug.h>
51 #include <cfg/macros.h>
52 #include <cfg/compiler.h>
53 #include <cfg/module.h>
54
55 #include <cpu/power.h> // cpu_relax()
56
57 #include <drv/usb.h>
58 #include <drv/usb_endpoint.h>
59
60
61 /*
62  * HID device configuration (usb-mouse)
63  */
64 #define USB_HID_VENDOR_ID       USB_MOUSE_VENDOR_ID
65 #define USB_HID_PRODUCT_ID      USB_MOUSE_PRODUCT_ID
66
67 #define USB_HID_INTERFACES      1
68 #define USB_HID_ENDPOINTS       1
69
70 #define USB_STRING_MANUFACTURER 1
71 #define USB_STRING_PRODUCT      2
72
73 #define USB_HID_REPORT_EP       (USB_DIR_IN | USB_MOUSE_EP_REPORT)
74
75 static UsbDeviceDesc usb_hid_device_descriptor =
76 {
77         .bLength = sizeof(usb_hid_device_descriptor),
78         .bDescriptorType = USB_DT_DEVICE,
79         .bcdUSB = 0x100,
80         .bDeviceClass = 0,
81         .bDeviceSubClass = 0,
82         .bDeviceProtocol = 0,
83         .idVendor = USB_HID_VENDOR_ID,
84         .idProduct = USB_HID_PRODUCT_ID,
85         .bcdDevice = 0,
86         .iManufacturer = USB_STRING_MANUFACTURER,
87         .iProduct = USB_STRING_PRODUCT,
88         .iSerialNumber = 0,
89         .bNumConfigurations = 1,
90 };
91
92 static const UsbConfigDesc usb_hid_config_descriptor =
93 {
94         .bLength = sizeof(usb_hid_config_descriptor),
95         .bDescriptorType = USB_DT_CONFIG,
96         .bNumInterfaces = USB_HID_INTERFACES,
97         .bConfigurationValue = 1,
98         .iConfiguration = 0,
99         .bmAttributes = USB_CONFIG_ATT_ONE,
100         .bMaxPower = 50, /* 100 mA */
101 };
102
103 static const UsbInterfaceDesc usb_hid_interface_descriptor =
104 {
105         .bLength = sizeof(usb_hid_interface_descriptor),
106         .bDescriptorType = USB_DT_INTERFACE,
107         .bInterfaceNumber = 0,
108         .bAlternateSetting = 0,
109         .bNumEndpoints = USB_HID_ENDPOINTS,
110         .bInterfaceClass = USB_CLASS_HID,
111         .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_BOOT,
112         .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE,
113         .iInterface = 0,
114 };
115
116 static const uint8_t hid_report_descriptor[] =
117 {
118         0x05, 0x01, // Usage Page (Generic Desktop)
119         0x09, 0x02, // Usage (Mouse)
120         0xA1, 0x01, // Collection (Application)
121         0x09, 0x01, // Usage (Pointer)
122         0xA1, 0x00, // Collection (Physical)
123         0x05, 0x09, // Usage Page (Buttons)
124         0x19, 0x01, // Usage Minimum (1)
125         0x29, 0x03, // Usage Maximum (3)
126         0x15, 0x00, // Logical Minimum (0)
127         0x25, 0x01, // Logical Maximum (1)
128         0x95, 0x03, // Report Count (3)
129         0x75, 0x01, // Report Size (1)
130         0x81, 0x02, // Input (Data, Variable, Absolute)
131         0x95, 0x01, // Report Count (1)
132         0x75, 0x05, // Report Size (5)
133         0x81, 0x01, // Input (03=Logitech, 01=Hid spec:Constant)
134         0x05, 0x01, // Usage Page (Generic Desktop)
135         0x09, 0x30, // Usage (X)
136         0x09, 0x31, // Usage (Y)
137         0x09, 0x38, // Usage (Logitech:_)
138         0x15, 0x81, // Logical Minimum (-127)
139         0x25, 0x7F, // Logical Maximum (127)
140         0x75, 0x08, // Report Size (8)
141         0x95, 0x02, // Report Count (Logitech=3, Hid spec =2)
142         0x81, 0x06, // Input (Data, Variable, Relative)
143         0xC0,   // End Collection
144         0xC0    // End Collection
145 };
146
147 static const usb_HidDesc usb_hid_descriptor =
148 {
149         .bLength = sizeof(usb_hid_descriptor),
150         .bDescriptorType = HID_DT_HID,
151         .bcdHID = usb_cpu_to_le16((uint16_t)0x0110),
152         .bCountryCode = 0,
153         .bNumDescriptors = 1,
154         .bDescriptorHidType = HID_DT_REPORT,
155         .wDescriptorLength =
156                 usb_cpu_to_le16((uint16_t)sizeof(hid_report_descriptor)),
157 };
158
159 static const UsbEndpointDesc usb_hid_ep_descriptor =
160 {
161         .bLength = sizeof(usb_hid_ep_descriptor),
162         .bDescriptorType = USB_DT_ENDPOINT,
163         .bEndpointAddress = USB_HID_REPORT_EP,
164         .bmAttributes = USB_ENDPOINT_XFER_INT,
165         .wMaxPacketSize = usb_cpu_to_le16((uint16_t)4),
166         .bInterval = 10, /* resolution in ms */
167 };
168
169 static const UsbDescHeader *usb_hid_config[] =
170 {
171         (const UsbDescHeader *)&usb_hid_config_descriptor,
172         (const UsbDescHeader *)&usb_hid_interface_descriptor,
173         (const UsbDescHeader *)&usb_hid_descriptor,
174         (const UsbDescHeader *)&usb_hid_ep_descriptor,
175         NULL,
176 };
177
178 static const DEFINE_USB_STRING(language_str, "\x09\x04"); // Language ID: en_US
179 static const DEFINE_USB_STRING(manufacturer_str,
180                 USB_STRING("B", "e", "R", "T", "O", "S"));
181 static const DEFINE_USB_STRING(product_str,
182                 USB_STRING("U", "S", "B", " ", "M", "o", "u", "s", "e"));
183
184 static const UsbStringDesc *usb_hid_strings[] =
185 {
186         (const UsbStringDesc *)&language_str,
187         (const UsbStringDesc *)&manufacturer_str,
188         (const UsbStringDesc *)&product_str,
189         NULL,
190 };
191
192 typedef struct mouse_report
193 {
194         uint8_t buttons;
195         int8_t x;
196         int8_t y;
197 } PACKED mouse_report_t;
198
199 static mouse_report_t report;
200
201 static bool hid_mouse_configured;
202
203 static void usb_hid_event_cb(UsbCtrlRequest *ctrl)
204 {
205         uint16_t value = usb_le16_to_cpu(ctrl->wValue);
206         uint16_t index = usb_le16_to_cpu(ctrl->wIndex);
207         uint16_t length = usb_le16_to_cpu(ctrl->wLength);
208         uint8_t type = ctrl->mRequestType;
209         uint8_t request = ctrl->bRequest;
210
211         LOG_INFO("%s: s 0x%02x 0x%02x 0x%04x 0x%04x 0x%04x\n",
212                 __func__, type, request, value, index, length);
213         switch (ctrl->bRequest)
214         {
215         case USB_REQ_GET_DESCRIPTOR:
216                 switch (value >> 8)
217                 {
218                 case HID_DT_HID:
219                         LOG_INFO("%s: HID_DT_HID\n", __func__);
220                         usb_endpointWrite(USB_DIR_IN | 0,
221                                         &usb_hid_descriptor,
222                                         sizeof(usb_hid_descriptor));
223                         break;
224                 case HID_DT_REPORT:
225                         LOG_INFO("%s: HID_DT_REPORT\n", __func__);
226                         usb_endpointWrite(USB_DIR_IN | 0,
227                                         &hid_report_descriptor,
228                                         sizeof(hid_report_descriptor));
229                         hid_mouse_configured = true;
230                         break;
231                 }
232                 break;
233         case HID_REQ_GET_REPORT:
234                 LOG_INFO("%s: HID_REQ_GET_REPORT\n", __func__);
235                 break;
236         case HID_REQ_SET_REPORT:
237                 LOG_INFO("%s: HID_REQ_SET_REPORT\n", __func__);
238                 break;
239         case HID_REQ_GET_IDLE:
240                 LOG_INFO("%s: HID_REQ_GET_IDLE\n", __func__);
241                 break;
242         case HID_REQ_SET_IDLE:
243                 LOG_INFO("%s: HID_REQ_SET_IDLE\n", __func__);
244                 usb_endpointWrite(USB_DIR_IN | 0, NULL, 0);
245                 break;
246         case HID_REQ_GET_PROTOCOL:
247                 LOG_INFO("%s: HID_REQ_GET_PROTOCOL\n", __func__);
248                 break;
249         case HID_REQ_SET_PROTOCOL:
250                 LOG_INFO("%s: HID_REQ_SET_PROTOCOL\n", __func__);
251                 break;
252         default:
253                 LOG_ERR("%s: unknown request: 0x%02x\n",
254                         __func__, ctrl->bRequest);
255                 break;
256         }
257 }
258
259 /* Global usb-mouse descriptor that identifies the usb-mouse device */
260 static UsbDevice usb_mouse = {
261         .device = &usb_hid_device_descriptor,
262         .config = usb_hid_config,
263         .strings = usb_hid_strings,
264         .event_cb = usb_hid_event_cb,
265 };
266
267 /* Low-level usb-hid device initialization */
268 static int usb_mouse_hw_init(void)
269 {
270         if (usb_deviceRegister(&usb_mouse) < 0)
271                 return -1;
272         LOG_INFO("usb-hid: registered new USB mouse device\n");
273         return 0;
274 }
275
276 /* Send a mouse event */
277 void usbmouse_sendEvent(int8_t x, int8_t y, int8_t buttons)
278 {
279         report.x = x;
280         report.y = y;
281         report.buttons = buttons;
282         usb_endpointWrite(USB_HID_REPORT_EP, &report, sizeof(report));
283 }
284
285 /*
286  * Initialize a USB HID device.
287  *
288  * TODO: support more than one device at the same time.
289  */
290 int usbmouse_init(UNUSED_ARG(int, unit))
291 {
292 #if CONFIG_KERN
293         MOD_CHECK(proc);
294 #endif
295         usb_mouse_hw_init();
296         while (!hid_mouse_configured)
297                 cpu_relax();
298         return 0;
299 }