summaryrefslogtreecommitdiff
path: root/firmware/usbstack/usb_hid.c
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2009-05-16 15:30:09 +0000
committerFrank Gevaerts <frank@gevaerts.be>2009-05-16 15:30:09 +0000
commit69a4117c1d15d91836de91abe5f8f93b868ec808 (patch)
treea3d47f51a0998506ef7b0f5332ddecae3e2106d2 /firmware/usbstack/usb_hid.c
parente435e4d976757f8436484a5b4d158ab7545fcdb6 (diff)
downloadrockbox-69a4117c1d15d91836de91abe5f8f93b868ec808.tar.gz
rockbox-69a4117c1d15d91836de91abe5f8f93b868ec808.zip
Add working USB HID driver, by Tomer Shalev (part of his GSoC work).
This needs support for usb interrupt transfers, so there are some changes in various USB drivers as well (only usb-drv-arc supports it at this point, others won't have working HID yet). HID is disabled for now, as the apps/ part is not included yet. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20962 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/usbstack/usb_hid.c')
-rw-r--r--firmware/usbstack/usb_hid.c346
1 files changed, 227 insertions, 119 deletions
diff --git a/firmware/usbstack/usb_hid.c b/firmware/usbstack/usb_hid.c
index c3cd5d9a04..0c35da2acb 100644
--- a/firmware/usbstack/usb_hid.c
+++ b/firmware/usbstack/usb_hid.c
@@ -25,49 +25,66 @@
25#include "kernel.h" 25#include "kernel.h"
26#include "usb_hid.h" 26#include "usb_hid.h"
27#include "usb_class_driver.h" 27#include "usb_class_driver.h"
28#define LOGF_ENABLE 28//#define LOGF_ENABLE
29#include "logf.h" 29#include "logf.h"
30 30
31#ifdef USB_HID 31#ifdef USB_HID
32 32
33#define CONCAT(low, high) ((high << 8) | low) 33#define CONCAT(low, high) ((high << 8) | low)
34#define SIZE_VALUE 0x01 34#define PACK_VAL1(dest, val) *(dest)++ = (val) & 0xff
35#define PACK_VAL2(dest, val) PACK_VAL1((dest), (val)); \
36 PACK_VAL1((dest), (val >> 8))
37
38/* Documents avaiable here: http://www.usb.org/developers/devclass_docs/ */
39
40#define HID_VER 0x0110 /* 1.1 */
41/* Subclass Codes (HID1_11.pdf, page 18) */
42#define SUBCLASS_BOOT_INTERFACE 1
43/* Protocol Codes (HID1_11.pdf, page 19) */
44#define PROTOCOL_CODE_MOUSE 2
35/* HID main items (HID1_11.pdf, page 38) */ 45/* HID main items (HID1_11.pdf, page 38) */
36#define INPUT (0x80 | SIZE_VALUE) 46#define INPUT 0x80
37#define OUTPUT (0x90 | SIZE_VALUE) 47#define COLLECTION 0xa0
38#define FEATURE (0xb0 | SIZE_VALUE) 48#define COLLECTION_APPLICATION 0x01
39#define COLLECTION (0xa0 | SIZE_VALUE)
40#define COLLECTION_APPLICATION CONCAT(COLLECTION, 0x01)
41#define END_COLLECTION 0xc0 49#define END_COLLECTION 0xc0
50/* Parts (HID1_11.pdf, page 40) */
51#define PREFERERD (1 << 5)
52#define NULL_STATE (1 << 6)
42/* HID global items (HID1_11.pdf, page 45) */ 53/* HID global items (HID1_11.pdf, page 45) */
43#define USAGE_PAGE (0x04 | SIZE_VALUE) 54#define USAGE_PAGE 0x04
44#define LOGICAL_MINIMUM (0x14 | SIZE_VALUE) 55#define LOGICAL_MINIMUM 0x14
45#define LOGICAL_MAXIMUM (0x24 | SIZE_VALUE) 56#define LOGICAL_MAXIMUM 0x24
46#define PHYSICAL_MINIMUM (0x34 | SIZE_VALUE) 57#define REPORT_SIZE 0x74
47#define PHYSICAL_MAXIMUM (0x44 | SIZE_VALUE) 58#define REPORT_ID 0x84
48#define UNIT_EXPONENT (0x54 | SIZE_VALUE) 59#define REPORT_COUNT 0x94
49#define UNIT (0x64 | SIZE_VALUE) 60/* HID local items (HID1_11.pdf, page 50) */
50#define REPORT_SIZE (0x74 | SIZE_VALUE) 61#define USAGE_MINIMUM 0x18
51#define REPORT_ID (0x84 | SIZE_VALUE) 62#define USAGE_MAXIMUM 0x28
52#define REPORT_COUNT (0x94 | SIZE_VALUE) 63/* Types of class descriptors (HID1_11.pdf, page 59) */
53#define PUSH (0xa4 | SIZE_VALUE) 64#define USB_DT_HID 0x21
54#define POP (0xb4 | SIZE_VALUE) 65#define USB_DT_REPORT 0x22
55/* Hut1_12.pdf, Table 1, page 14 */ 66
56#define USAGE_PAGE_CONSUMER CONCAT(USAGE_PAGE, 0x0c) 67/* (Hut1_12.pdf, Table 1, page 14) */
57/* Hut1_12.pdf, Table 17, page 77 */ 68#define USAGE_PAGE_CONSUMER 0x0c
69
58#define CONSUMER_USAGE 0x09 70#define CONSUMER_USAGE 0x09
59#define CONSUMER_USAGE_CONTROL CONCAT(CONSUMER_USAGE, 0x01) 71
60#define CONSUMER_USAGE_MUTE CONCAT(CONSUMER_USAGE, 0xe2) 72/* HID-only class specific requests */
61#define CONSUMER_USAGE_VOLUME_INCREMENT CONCAT(CONSUMER_USAGE, 0xe9) 73#define USB_HID_GET_REPORT 0x01
62#define CONSUMER_USAGE_VOLUME_DECREMENT CONCAT(CONSUMER_USAGE, 0xea) 74#define USB_HID_GET_IDLE 0x02
63/* Hut1_12.pdf, Table 4, page 20 */ 75#define USB_HID_GET_PROTOCOL 0x03
64#define CONSUMER_CONTROL CONCAT(COLLECTION_APPLICATION, 0x01) 76#define USB_HID_SET_REPORT 0x09
65 77#define USB_HID_SET_IDLE 0x0a
66#define USB_DT_HID 0x21 78#define USB_HID_SET_PROTOCOL 0x0b
67#define USB_DT_REPORT 0x22 79
68#define USB_DT_PHYSICAL_DESCRIPTOR 0x23 80#define HID_BUF_SIZE_MSG 16
69 81#define HID_BUF_SIZE_CMD 5
70/* serial interface */ 82#define HID_BUG_SIZE_REPORT 32
83#define HID_NUM_BUFFERS 5
84
85#define HID_BUF_INC(i) do { (i) = ((i) + 1) % HID_NUM_BUFFERS; } while (0)
86
87/* hid interface */
71static struct usb_interface_descriptor __attribute__((aligned(2))) 88static struct usb_interface_descriptor __attribute__((aligned(2)))
72 interface_descriptor = 89 interface_descriptor =
73{ 90{
@@ -77,12 +94,11 @@ static struct usb_interface_descriptor __attribute__((aligned(2)))
77 .bAlternateSetting = 0, 94 .bAlternateSetting = 0,
78 .bNumEndpoints = 1, 95 .bNumEndpoints = 1,
79 .bInterfaceClass = USB_CLASS_HID, 96 .bInterfaceClass = USB_CLASS_HID,
80 .bInterfaceSubClass = 0, 97 .bInterfaceSubClass = SUBCLASS_BOOT_INTERFACE,
81 .bInterfaceProtocol = 0, 98 .bInterfaceProtocol = PROTOCOL_CODE_MOUSE,
82 .iInterface = 0 99 .iInterface = 0
83}; 100};
84 101
85/* USB_DT_HID: Endpoint descriptor */
86struct usb_hid_descriptor { 102struct usb_hid_descriptor {
87 uint8_t bLength; 103 uint8_t bLength;
88 uint8_t bDescriptorType; 104 uint8_t bDescriptorType;
@@ -93,19 +109,19 @@ struct usb_hid_descriptor {
93 uint16_t wDescriptorLength0; 109 uint16_t wDescriptorLength0;
94} __attribute__ ((packed)); 110} __attribute__ ((packed));
95 111
96/* USB_DT_REPORT: Endpoint descriptor */
97static struct usb_hid_descriptor __attribute__((aligned(2))) hid_descriptor = 112static struct usb_hid_descriptor __attribute__((aligned(2))) hid_descriptor =
98{ 113{
99 .bLength = sizeof(struct usb_hid_descriptor), 114 .bLength = sizeof(struct usb_hid_descriptor),
100 .bDescriptorType = USB_DT_HID, 115 .bDescriptorType = USB_DT_HID,
101 .wBcdHID = 0x0100, 116 .wBcdHID = HID_VER,
102 .bCountryCode = 0, 117 .bCountryCode = 0,
103 .bNumDescriptors = 1, 118 .bNumDescriptors = 1,
104 .bDescriptorType0 = 0x22, 119 .bDescriptorType0 = USB_DT_REPORT,
105 .wDescriptorLength0 = 0 120 .wDescriptorLength0 = 0
106}; 121};
107 122
108static struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor = 123static struct usb_endpoint_descriptor __attribute__((aligned(2)))
124 endpoint_descriptor =
109{ 125{
110 .bLength = sizeof(struct usb_endpoint_descriptor), 126 .bLength = sizeof(struct usb_endpoint_descriptor),
111 .bDescriptorType = USB_DT_ENDPOINT, 127 .bDescriptorType = USB_DT_ENDPOINT,
@@ -115,43 +131,46 @@ static struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descr
115 .bInterval = 0 131 .bInterval = 0
116}; 132};
117 133
118/* USB_DT_REPORT: Endpoint descriptor */ 134static unsigned char report_descriptor[HID_BUG_SIZE_REPORT]
119struct usb_report_descriptor { 135 USB_DEVBSS_ATTR __attribute__((aligned(32)));
120 uint16_t wUsagePage;
121 uint16_t wUsage;
122 uint16_t wCollection;
123 uint16_t wCollectionItems[12];
124 uint8_t wEndCollection;
125} __attribute__ ((packed));
126 136
127static struct usb_report_descriptor __attribute__((aligned(2))) report_descriptor = 137static unsigned char send_buffer[HID_NUM_BUFFERS][HID_BUF_SIZE_MSG]
128{ 138 USB_DEVBSS_ATTR __attribute__((aligned(32)));
129 .wUsagePage = USAGE_PAGE_CONSUMER, 139size_t send_buffer_len[HID_NUM_BUFFERS];
130 .wUsage = CONSUMER_USAGE_CONTROL, 140static int cur_buf_prepare;
131 .wCollection = COLLECTION_APPLICATION, 141static int cur_buf_send;
132 .wCollectionItems = {
133 CONCAT(LOGICAL_MINIMUM, 0x0),
134 CONCAT(LOGICAL_MAXIMUM, 0x1),
135 USAGE_PAGE_CONSUMER,
136 CONSUMER_USAGE_MUTE,
137 CONSUMER_USAGE_VOLUME_INCREMENT,
138 CONSUMER_USAGE_VOLUME_DECREMENT,
139 CONCAT(REPORT_COUNT, 0x3),
140 CONCAT(REPORT_SIZE, 0x1),
141 CONCAT(INPUT, 0x42),
142 CONCAT(REPORT_COUNT, 0x5),
143 CONCAT(REPORT_SIZE, 0x1),
144 CONCAT(INPUT, 0x01)
145 },
146 .wEndCollection = END_COLLECTION
147};
148 142
143static uint16_t report_descriptor_len;
144static bool active = false;
149static int ep_in; 145static int ep_in;
150static int usb_interface; 146static int usb_interface;
147static uint32_t report_id;
148
149static void usb_hid_try_send_drv(void);
150
151static void pack_parameter(unsigned char **dest, uint8_t parameter,
152 uint32_t value)
153{
154 uint8_t size_value = 1; /* # of bytes */
155 uint32_t v = value;
156
157 while (v >>= 8)
158 size_value++;
159
160 **dest = parameter | size_value;
161 (*dest)++;
162
163 while (size_value--)
164 {
165 **dest = value & 0xff;
166 (*dest)++;
167 value >>= 8;
168 }
169}
151 170
152int usb_hid_request_endpoints(struct usb_class_driver *drv) 171int usb_hid_request_endpoints(struct usb_class_driver *drv)
153{ 172{
154 ep_in = usb_core_request_endpoint(USB_DIR_IN, drv); 173 ep_in = usb_core_request_endpoint(USB_ENDPOINT_XFER_INT, USB_DIR_IN, drv);
155 if (ep_in < 0) 174 if (ep_in < 0)
156 return -1; 175 return -1;
157 176
@@ -165,25 +184,46 @@ int usb_hid_set_first_interface(int interface)
165 return interface + 1; 184 return interface + 1;
166} 185}
167 186
168
169int usb_hid_get_config_descriptor(unsigned char *dest,int max_packet_size) 187int usb_hid_get_config_descriptor(unsigned char *dest,int max_packet_size)
170{ 188{
171 unsigned char *orig_dest = dest; 189 unsigned char *report, *orig_dest = dest;
172 190
173 logf("hid: config desc."); 191 logf("hid: config desc.");
174 interface_descriptor.bInterfaceNumber = usb_interface;
175 PACK_DESCRIPTOR(dest, interface_descriptor);
176
177 hid_descriptor.wDescriptorLength0 = sizeof(report_descriptor);
178 PACK_DESCRIPTOR(dest, hid_descriptor);
179 192
180 /* Ignore max_packet_size and set to 1 bytes long packet size */ 193 /* Ignore given max_packet_size */
181 (void)max_packet_size; 194 (void)max_packet_size;
182 endpoint_descriptor.wMaxPacketSize = 1; 195
196 /* TODO: Increment report_id for each report, and send command with
197 * appropriate report id */
198 report_id = 2;
199
200 /* Initialize report descriptor */
201 report = report_descriptor;
202 pack_parameter(&report, USAGE_PAGE, USAGE_PAGE_CONSUMER);
203 PACK_VAL2(report, CONCAT(CONSUMER_USAGE, CONSUMER_CONTROL));
204 pack_parameter(&report, COLLECTION, COLLECTION_APPLICATION);
205 pack_parameter(&report, REPORT_ID, report_id);
206 pack_parameter(&report, REPORT_SIZE, 16);
207 pack_parameter(&report, REPORT_COUNT, 2);
208 pack_parameter(&report, LOGICAL_MINIMUM, 1);
209 pack_parameter(&report, LOGICAL_MAXIMUM, 652);
210 pack_parameter(&report, USAGE_MINIMUM, CONSUMER_CONTROL);
211 pack_parameter(&report, USAGE_MAXIMUM, AC_SEND);
212 pack_parameter(&report, INPUT, PREFERERD | NULL_STATE);
213 PACK_VAL1(report, END_COLLECTION);
214 report_descriptor_len = (uint16_t)((uint32_t)report -
215 (uint32_t)report_descriptor);
216
217 interface_descriptor.bInterfaceNumber = usb_interface;
218 PACK_DATA(dest, interface_descriptor);
219 hid_descriptor.wDescriptorLength0 = report_descriptor_len;
220 PACK_DATA(dest, hid_descriptor);
221
222 endpoint_descriptor.wMaxPacketSize = 8;
183 endpoint_descriptor.bInterval = 8; 223 endpoint_descriptor.bInterval = 8;
184 224
185 endpoint_descriptor.bEndpointAddress = ep_in; 225 endpoint_descriptor.bEndpointAddress = ep_in;
186 PACK_DESCRIPTOR(dest, endpoint_descriptor); 226 PACK_DATA(dest, endpoint_descriptor);
187 227
188 return (dest - orig_dest); 228 return (dest - orig_dest);
189} 229}
@@ -191,38 +231,54 @@ int usb_hid_get_config_descriptor(unsigned char *dest,int max_packet_size)
191void usb_hid_init_connection(void) 231void usb_hid_init_connection(void)
192{ 232{
193 logf("hid: init connection"); 233 logf("hid: init connection");
234
235 active = true;
194} 236}
195 237
196/* called by usb_code_init() */ 238/* called by usb_core_init() */
197void usb_hid_init(void) 239void usb_hid_init(void)
198{ 240{
241 int i;
242
199 logf("hid: init"); 243 logf("hid: init");
244
245 for (i = 0; i < HID_NUM_BUFFERS; i++)
246 send_buffer_len[i] = 0;
247
248 cur_buf_prepare = 0;
249 cur_buf_send = 0;
250
251 active = true;
200} 252}
201 253
202void usb_hid_disconnect(void) 254void usb_hid_disconnect(void)
203{ 255{
204 logf("hid: disconnect"); 256 logf("hid: disconnect");
257 active = false;
205} 258}
206 259
207/* called by usb_core_transfer_complete() */ 260/* called by usb_core_transfer_complete() */
208void usb_hid_transfer_complete(int ep,int dir, int status, int length) 261void usb_hid_transfer_complete(int ep, int dir, int status, int length)
209{ 262{
210 (void)ep; 263 (void)ep;
211 (void)dir; 264 (void)dir;
212 (void)status; 265 (void)status;
213 (void)length; 266 (void)length;
214 267
215 logf("hid: transfer complete. ep %d, dir %d, status %d ,length %d", 268 switch (dir) {
216 ep, dir, status, length); 269 case USB_DIR_OUT:
217} 270 break;
271 case USB_DIR_IN: {
272 if (status)
273 break;
218 274
219/* HID-only class specific requests */ 275 send_buffer_len[cur_buf_send] = 0;
220#define USB_HID_GET_REPORT 0x01 276 HID_BUF_INC(cur_buf_send);
221#define USB_HID_GET_IDLE 0x02 277 usb_hid_try_send_drv();
222#define USB_HID_GET_PROTOCOL 0x03 278 break;
223#define USB_HID_SET_REPORT 0x09 279 }
224#define USB_HID_SET_IDLE 0x0a 280 }
225#define USB_HID_SET_PROTOCOL 0x0b 281}
226 282
227/* called by usb_core_control_request() */ 283/* called by usb_core_control_request() */
228bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest) 284bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest)
@@ -231,29 +287,32 @@ bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest)
231 287
232 switch(req->bRequestType & USB_TYPE_MASK) { 288 switch(req->bRequestType & USB_TYPE_MASK) {
233 case USB_TYPE_STANDARD: { 289 case USB_TYPE_STANDARD: {
234 switch(req->wValue>>8) { /* type */ 290 unsigned char *orig_dest = dest;
235 case USB_DT_REPORT: { 291
236 logf("hid: report"); 292 switch(req->wValue>>8) { /* type */
237 if (dest == NULL) { 293 case USB_DT_HID: {
238 logf("dest is NULL!"); 294 logf("hid: type hid");
239 } 295 hid_descriptor.wDescriptorLength0 = report_descriptor_len;
240 if (dest) { 296 PACK_DATA(dest, hid_descriptor);
241 unsigned char *orig_dest = dest; 297 break;
242 PACK_DESCRIPTOR(dest, report_descriptor);
243 if(usb_drv_send(EP_CONTROL, orig_dest, dest - orig_dest))
244 break;
245 usb_core_ack_control(req);
246
247 }
248 handled = true;
249 break;
250 }
251 default:
252 logf("hid: unsup. std. req");
253 break;
254 } 298 }
255 break; 299 case USB_DT_REPORT: {
300 logf("hid: type report");
301 memcpy(dest, &report_descriptor, report_descriptor_len);
302 dest += report_descriptor_len;
303 break;
304 }
305 default:
306 logf("hid: unsup. std. req");
307 break;
256 } 308 }
309 if (dest != orig_dest &&
310 !usb_drv_send(EP_CONTROL, orig_dest, dest - orig_dest)) {
311 usb_core_ack_control(req);
312 handled = true;
313 }
314 break;
315 }
257 316
258 case USB_TYPE_CLASS: { 317 case USB_TYPE_CLASS: {
259 switch (req->bRequest) { 318 switch (req->bRequest) {
@@ -263,7 +322,6 @@ bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest)
263 handled = true; 322 handled = true;
264 break; 323 break;
265 default: 324 default:
266 //logf("hid: unsup. cls. req");
267 logf("%d: unsup. cls. req", req->bRequest); 325 logf("%d: unsup. cls. req", req->bRequest);
268 break; 326 break;
269 } 327 }
@@ -277,12 +335,62 @@ bool usb_hid_control_request(struct usb_ctrlrequest* req, unsigned char* dest)
277 return handled; 335 return handled;
278} 336}
279 337
280void usb_hid_send(unsigned char *data, int length) 338static void usb_hid_try_send_drv(void)
281{ 339{
282 (void)data; 340 int rc;
283 (void)(length); 341 int length = send_buffer_len[cur_buf_send];
342
343 if (!length)
344 return;
345
346 rc = usb_drv_send_nonblocking(ep_in, send_buffer[cur_buf_send], length);
347 if (rc)
348 {
349 send_buffer_len[cur_buf_send] = 0;
350 return;
351 }
352}
353
354static void usb_hid_queue(unsigned char *data, int length)
355{
356 if (!active || length <= 0)
357 return;
358
359 /* Buffer overflow - item still in use */
360 if (send_buffer_len[cur_buf_prepare])
361 return;
362
363 /* Prepare buffer for sending */
364 if (length > HID_BUF_SIZE_MSG)
365 length = HID_BUF_SIZE_MSG;
366 memcpy(send_buffer[cur_buf_prepare], data, length);
367 send_buffer_len[cur_buf_prepare] = length;
368
369 HID_BUF_INC(cur_buf_prepare);
370}
371
372void usb_hid_send_consumer_usage(consumer_usage_page_t id)
373{
374 static unsigned char buf[HID_BUF_SIZE_CMD] USB_DEVBSS_ATTR
375 __attribute__((aligned(32)));
376 unsigned char *dest = buf;
377
378 memset(buf, 0, sizeof(buf));
379
380 logf("HID: Sending 0x%x", id);
381
382 pack_parameter(&dest, 0, id);
383 buf[0] = report_id;
384
385 /* Key pressed */
386 usb_hid_queue(buf, HID_BUF_SIZE_CMD);
387
388 /* Key released */
389 memset(buf, 0, sizeof(buf));
390 buf[0] = report_id;
391 usb_hid_queue(buf, HID_BUF_SIZE_CMD);
284 392
285 logf("hid: send %d bytes: \"%s\"", length, data); 393 usb_hid_try_send_drv();
286} 394}
287 395
288#endif /*USB_HID*/ 396#endif /*USB_HID*/