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