libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
usb_standard.c
Go to the documentation of this file.
1/** @defgroup usb_standard_file Generic USB Standard Request Interface
2
3@ingroup USB
4
5@brief <b>Generic USB Standard Request Interface</b>
6
7@version 1.0.0
8
9@author @htmlonly &copy; @endhtmlonly 2010
10Gareth McMullin <gareth@blacksphere.co.nz>
11
12@date 10 March 2013
13
14LGPL License Terms @ref lgpl_license
15*/
16
17/*
18 * This file is part of the libopencm3 project.
19 *
20 * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
21 *
22 * This library is free software: you can redistribute it and/or modify
23 * it under the terms of the GNU Lesser General Public License as published by
24 * the Free Software Foundation, either version 3 of the License, or
25 * (at your option) any later version.
26 *
27 * This library is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU Lesser General Public License for more details.
31 *
32 * You should have received a copy of the GNU Lesser General Public License
33 * along with this library. If not, see <http://www.gnu.org/licenses/>.
34 */
35
36/**@{*/
37
38#include <string.h>
39#include <libopencm3/usb/usbd.h>
40#include "usb_private.h"
41
44{
45 int i;
46
47 for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) {
48 if (usbd_dev->user_callback_set_config[i]) {
49 if (usbd_dev->user_callback_set_config[i] == callback) {
50 return 0;
51 }
52 continue;
53 }
54
55 usbd_dev->user_callback_set_config[i] = callback;
56 return 0;
57 }
58
59 return -1;
60}
61
64{
65 usbd_dev->user_callback_set_altsetting = callback;
66}
67
68static uint16_t build_config_descriptor(usbd_device *usbd_dev,
69 uint8_t index, uint8_t *buf, uint16_t len)
70{
71 uint8_t *tmpbuf = buf;
72 const struct usb_config_descriptor *cfg = &usbd_dev->config[index];
73 uint16_t count, total = 0, totallen = 0;
74 uint16_t i, j, k;
75
76 memcpy(buf, cfg, count = MIN(len, cfg->bLength));
77 buf += count;
78 len -= count;
79 total += count;
80 totallen += cfg->bLength;
81
82 /* For each interface... */
83 for (i = 0; i < cfg->bNumInterfaces; i++) {
84 /* Interface Association Descriptor, if any */
85 if (cfg->interface[i].iface_assoc) {
86 const struct usb_iface_assoc_descriptor *assoc =
87 cfg->interface[i].iface_assoc;
88 memcpy(buf, assoc, count = MIN(len, assoc->bLength));
89 buf += count;
90 len -= count;
91 total += count;
92 totallen += assoc->bLength;
93 }
94 /* For each alternate setting... */
95 for (j = 0; j < cfg->interface[i].num_altsetting; j++) {
96 const struct usb_interface_descriptor *iface =
97 &cfg->interface[i].altsetting[j];
98 /* Copy interface descriptor. */
99 memcpy(buf, iface, count = MIN(len, iface->bLength));
100 buf += count;
101 len -= count;
102 total += count;
103 totallen += iface->bLength;
104 /* Copy extra bytes (function descriptors). */
105 if (iface->extra) {
106 memcpy(buf, iface->extra,
107 count = MIN(len, iface->extralen));
108 buf += count;
109 len -= count;
110 total += count;
111 totallen += iface->extralen;
112 }
113 /* For each endpoint... */
114 for (k = 0; k < iface->bNumEndpoints; k++) {
115 const struct usb_endpoint_descriptor *ep =
116 &iface->endpoint[k];
117 memcpy(buf, ep, count = MIN(len, ep->bLength));
118 buf += count;
119 len -= count;
120 total += count;
121 totallen += ep->bLength;
122 /* Copy extra bytes (class specific). */
123 if (ep->extra) {
124 memcpy(buf, ep->extra,
125 count = MIN(len, ep->extralen));
126 buf += count;
127 len -= count;
128 total += count;
129 totallen += ep->extralen;
130 }
131 }
132 }
133 }
134
135 /* Fill in wTotalLength.
136 * Note that tmpbuf is sometimes not halfword-aligned */
137 memcpy((tmpbuf + 2), &totallen, sizeof(uint16_t));
138
139 return total;
140}
141
142static int usb_descriptor_type(uint16_t wValue)
143{
144 return wValue >> 8;
145}
146
147static int usb_descriptor_index(uint16_t wValue)
148{
149 return wValue & 0xFF;
150}
151
154 struct usb_setup_data *req,
155 uint8_t **buf, uint16_t *len)
156{
157 int i, array_idx, descr_idx;
158 struct usb_string_descriptor *sd;
159
160 descr_idx = usb_descriptor_index(req->wValue);
161
162 switch (usb_descriptor_type(req->wValue)) {
163 case USB_DT_DEVICE:
164 *buf = (uint8_t *) usbd_dev->desc;
165 *len = MIN(*len, usbd_dev->desc->bLength);
166 return USBD_REQ_HANDLED;
168 *buf = usbd_dev->ctrl_buf;
169 *len = build_config_descriptor(usbd_dev, descr_idx, *buf, *len);
170 return USBD_REQ_HANDLED;
171 case USB_DT_STRING:
172 sd = (struct usb_string_descriptor *)usbd_dev->ctrl_buf;
173
174 if (descr_idx == 0) {
175 /* Send sane Language ID descriptor... */
177 sd->bLength = sizeof(sd->bLength) +
178 sizeof(sd->bDescriptorType) +
179 sizeof(sd->wData[0]);
180
181 *len = MIN(*len, sd->bLength);
182 } else if (descr_idx == usbd_dev->extra_string_idx) {
183 /* This string is returned as UTF16, hence the
184 * multiplication
185 */
186 sd->bLength = strlen(usbd_dev->extra_string) * 2 +
187 sizeof(sd->bLength) +
188 sizeof(sd->bDescriptorType);
189
190 *len = MIN(*len, sd->bLength);
191
192 for (i = 0; i < (*len / 2) - 1; i++) {
193 sd->wData[i] =
194 usbd_dev->extra_string[i];
195 }
196 } else {
197 array_idx = descr_idx - 1;
198
199 if (!usbd_dev->strings) {
200 /* Device doesn't support strings. */
201 return USBD_REQ_NOTSUPP;
202 }
203
204 /* Check that string index is in range. */
205 if (array_idx >= usbd_dev->num_strings) {
206 return USBD_REQ_NOTSUPP;
207 }
208
209 /* Strings with Language ID differnet from
210 * USB_LANGID_ENGLISH_US are not supported */
211 if (req->wIndex != USB_LANGID_ENGLISH_US) {
212 return USBD_REQ_NOTSUPP;
213 }
214
215 /* This string is returned as UTF16, hence the
216 * multiplication
217 */
218 sd->bLength = strlen(usbd_dev->strings[array_idx]) * 2 +
219 sizeof(sd->bLength) +
220 sizeof(sd->bDescriptorType);
221
222 *len = MIN(*len, sd->bLength);
223
224 for (i = 0; i < (*len / 2) - 1; i++) {
225 sd->wData[i] =
226 usbd_dev->strings[array_idx][i];
227 }
228 }
229
231 *buf = (uint8_t *)sd;
232
233 return USBD_REQ_HANDLED;
234 }
235 return USBD_REQ_NOTSUPP;
236}
237
240 struct usb_setup_data *req, uint8_t **buf,
241 uint16_t *len)
242{
243 (void)req;
244 (void)buf;
245 (void)len;
246
247 /* The actual address is only latched at the STATUS IN stage. */
248 if ((req->bmRequestType != 0) || (req->wValue >= 128)) {
249 return USBD_REQ_NOTSUPP;
250 }
251
252 usbd_dev->current_address = req->wValue;
253
254 /*
255 * Special workaround for STM32F10[57] that require the address
256 * to be set here. This is undocumented!
257 */
258 if (usbd_dev->driver->set_address_before_status) {
259 usbd_dev->driver->set_address(usbd_dev, req->wValue);
260 }
261
262 return USBD_REQ_HANDLED;
263}
264
267 struct usb_setup_data *req,
268 uint8_t **buf, uint16_t *len)
269{
270 unsigned i;
271 int found_index = -1;
272 const struct usb_config_descriptor *cfg;
273
274 (void)req;
275 (void)buf;
276 (void)len;
277
278 if (req->wValue > 0) {
279 for (i = 0; i < usbd_dev->desc->bNumConfigurations; i++) {
280 if (req->wValue
281 == usbd_dev->config[i].bConfigurationValue) {
282 found_index = i;
283 break;
284 }
285 }
286 if (found_index < 0) {
287 return USBD_REQ_NOTSUPP;
288 }
289 }
290
291 usbd_dev->current_config = found_index + 1;
292
293 if (usbd_dev->current_config > 0) {
294 cfg = &usbd_dev->config[usbd_dev->current_config - 1];
295
296 /* reset all alternate settings configuration */
297 for (i = 0; i < cfg->bNumInterfaces; i++) {
298 if (cfg->interface[i].cur_altsetting) {
299 *cfg->interface[i].cur_altsetting = 0;
300 }
301 }
302 }
303
304 /* Reset all endpoints. */
305 usbd_dev->driver->ep_reset(usbd_dev);
306
307 if (usbd_dev->user_callback_set_config[0]) {
308 /*
309 * Flush control callbacks. These will be reregistered
310 * by the user handler.
311 */
312 for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
313 usbd_dev->user_control_callback[i].cb = NULL;
314 }
315
316 for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) {
317 if (usbd_dev->user_callback_set_config[i]) {
318 usbd_dev->user_callback_set_config[i](usbd_dev,
319 req->wValue);
320 }
321 }
322 }
323
324 return USBD_REQ_HANDLED;
325}
326
329 struct usb_setup_data *req,
330 uint8_t **buf, uint16_t *len)
331{
332 (void)req;
333
334 if (*len > 1) {
335 *len = 1;
336 }
337 if (usbd_dev->current_config > 0) {
338 const struct usb_config_descriptor *cfg =
339 &usbd_dev->config[usbd_dev->current_config - 1];
340 (*buf)[0] = cfg->bConfigurationValue;
341 } else {
342 (*buf)[0] = 0;
343 }
344
345 return USBD_REQ_HANDLED;
346}
347
350 struct usb_setup_data *req,
351 uint8_t **buf, uint16_t *len)
352{
353 const struct usb_config_descriptor *cfx =
354 &usbd_dev->config[usbd_dev->current_config - 1];
355 const struct usb_interface *iface;
356
357 (void)buf;
358
359 if (req->wIndex >= cfx->bNumInterfaces) {
360 return USBD_REQ_NOTSUPP;
361 }
362
363 iface = &cfx->interface[req->wIndex];
364
365 if (req->wValue >= iface->num_altsetting) {
366 return USBD_REQ_NOTSUPP;
367 }
368
369 if (iface->cur_altsetting) {
370 *iface->cur_altsetting = req->wValue;
371 } else if (req->wValue > 0) {
372 return USBD_REQ_NOTSUPP;
373 }
374
375 if (usbd_dev->user_callback_set_altsetting) {
376 usbd_dev->user_callback_set_altsetting(usbd_dev,
377 req->wIndex,
378 req->wValue);
379 }
380
381 *len = 0;
382
383 return USBD_REQ_HANDLED;
384}
385
388 struct usb_setup_data *req,
389 uint8_t **buf, uint16_t *len)
390{
391 uint8_t *cur_altsetting;
392 const struct usb_config_descriptor *cfx =
393 &usbd_dev->config[usbd_dev->current_config - 1];
394
395 if (req->wIndex >= cfx->bNumInterfaces) {
396 return USBD_REQ_NOTSUPP;
397 }
398
399 *len = 1;
400 cur_altsetting = cfx->interface[req->wIndex].cur_altsetting;
401 (*buf)[0] = (cur_altsetting) ? *cur_altsetting : 0;
402
403 return USBD_REQ_HANDLED;
404}
405
408 struct usb_setup_data *req,
409 uint8_t **buf, uint16_t *len)
410{
411 (void)usbd_dev;
412 (void)req;
413
414 /* bit 0: self powered */
415 /* bit 1: remote wakeup */
416 if (*len > 2) {
417 *len = 2;
418 }
419 (*buf)[0] = 0;
420 (*buf)[1] = 0;
421
422 return USBD_REQ_HANDLED;
423}
424
427 struct usb_setup_data *req,
428 uint8_t **buf, uint16_t *len)
429{
430 (void)usbd_dev;
431 (void)req;
432 /* not defined */
433
434 if (*len > 2) {
435 *len = 2;
436 }
437 (*buf)[0] = 0;
438 (*buf)[1] = 0;
439
440 return USBD_REQ_HANDLED;
441}
442
445 struct usb_setup_data *req,
446 uint8_t **buf, uint16_t *len)
447{
448 (void)req;
449
450 if (*len > 2) {
451 *len = 2;
452 }
453 (*buf)[0] = usbd_ep_stall_get(usbd_dev, req->wIndex) ? 1 : 0;
454 (*buf)[1] = 0;
455
456 return USBD_REQ_HANDLED;
457}
458
461 struct usb_setup_data *req,
462 uint8_t **buf, uint16_t *len)
463{
464 (void)buf;
465 (void)len;
466
467 usbd_ep_stall_set(usbd_dev, req->wIndex, 1);
468
469 return USBD_REQ_HANDLED;
470}
471
474 struct usb_setup_data *req,
475 uint8_t **buf, uint16_t *len)
476{
477 (void)buf;
478 (void)len;
479
480 usbd_ep_stall_set(usbd_dev, req->wIndex, 0);
481
482 return USBD_REQ_HANDLED;
483}
484
485/* Do not appear to belong to the API, so are omitted from docs */
486/**@}*/
487
490 struct usb_setup_data *req, uint8_t **buf,
491 uint16_t *len)
492{
493 enum usbd_request_return_codes (*command)(usbd_device *usbd_dev,
494 struct usb_setup_data *req,
495 uint8_t **buf, uint16_t *len) = NULL;
496
497 switch (req->bRequest) {
501 /* Device wakeup code goes here. */
502 }
503
504 if (req->wValue == USB_FEAT_TEST_MODE) {
505 /* Test mode code goes here. */
506 }
507
508 break;
510 /*
511 * SET ADDRESS is an exception.
512 * It is only processed at STATUS stage.
513 */
514 command = usb_standard_set_address;
515 break;
518 break;
521 break;
524 break;
526 /*
527 * GET_STATUS always responds with zero reply.
528 * The application may override this behaviour.
529 */
531 break;
533 /* SET_DESCRIPTOR is optional and not implemented. */
534 break;
535 }
536
537 if (!command) {
538 return USBD_REQ_NOTSUPP;
539 }
540
541 return command(usbd_dev, req, buf, len);
542}
543
546 struct usb_setup_data *req, uint8_t **buf,
547 uint16_t *len)
548{
549 enum usbd_request_return_codes (*command)(usbd_device *usbd_dev,
550 struct usb_setup_data *req,
551 uint8_t **buf, uint16_t *len) = NULL;
552
553 switch (req->bRequest) {
556 /* not defined */
557 break;
560 break;
563 break;
566 break;
567 }
568
569 if (!command) {
570 return USBD_REQ_NOTSUPP;
571 }
572
573 return command(usbd_dev, req, buf, len);
574}
575
578 struct usb_setup_data *req, uint8_t **buf,
579 uint16_t *len)
580{
581 enum usbd_request_return_codes (*command) (usbd_device *usbd_dev,
582 struct usb_setup_data *req,
583 uint8_t **buf, uint16_t *len) = NULL;
584
585 switch (req->bRequest) {
587 if (req->wValue == USB_FEAT_ENDPOINT_HALT) {
589 }
590 break;
592 if (req->wValue == USB_FEAT_ENDPOINT_HALT) {
594 }
595 break;
598 break;
600 /* FIXME: SYNCH_FRAME is not implemented. */
601 /*
602 * SYNCH_FRAME is used for synchronization of isochronous
603 * endpoints which are not yet implemented.
604 */
605 break;
606 }
607
608 if (!command) {
609 return USBD_REQ_NOTSUPP;
610 }
611
612 return command(usbd_dev, req, buf, len);
613}
614
617 uint8_t **buf, uint16_t *len)
618{
619 /* FIXME: Have class/vendor requests as well. */
621 return USBD_REQ_NOTSUPP;
622 }
623
624 switch (req->bmRequestType & USB_REQ_TYPE_RECIPIENT) {
626 return _usbd_standard_request_device(usbd_dev, req, buf, len);
628 return _usbd_standard_request_interface(usbd_dev, req,
629 buf, len);
631 return _usbd_standard_request_endpoint(usbd_dev, req, buf, len);
632 default:
633 return USBD_REQ_NOTSUPP;
634 }
635}
636
uint8_t usbd_ep_stall_get(usbd_device *usbd_dev, uint8_t addr)
Get STALL status of an endpoint.
Definition: usb.c:163
struct _usbd_device usbd_device
Definition: usbd.h:53
void usbd_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall)
Set/clear STALL condition on an endpoint.
Definition: usb.c:158
usbd_request_return_codes
Definition: usbd.h:46
void(* usbd_set_config_callback)(usbd_device *usbd_dev, uint16_t wValue)
Definition: usbd.h:125
void(* usbd_set_altsetting_callback)(usbd_device *usbd_dev, uint16_t wIndex, uint16_t wValue)
Definition: usbd.h:128
@ USBD_REQ_HANDLED
Definition: usbd.h:48
@ USBD_REQ_NOTSUPP
Definition: usbd.h:47
static enum usbd_request_return_codes usb_standard_interface_get_status(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:426
static enum usbd_request_return_codes usb_standard_get_configuration(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:328
static enum usbd_request_return_codes usb_standard_get_descriptor(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:153
static int usb_descriptor_type(uint16_t wValue)
Definition: usb_standard.c:142
static enum usbd_request_return_codes usb_standard_get_interface(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:387
static enum usbd_request_return_codes usb_standard_endpoint_get_status(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:444
static enum usbd_request_return_codes usb_standard_set_configuration(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:266
static enum usbd_request_return_codes usb_standard_device_get_status(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:407
static enum usbd_request_return_codes usb_standard_set_interface(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:349
static enum usbd_request_return_codes usb_standard_set_address(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:239
static enum usbd_request_return_codes usb_standard_endpoint_unstall(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:473
int usbd_register_set_config_callback(usbd_device *usbd_dev, usbd_set_config_callback callback)
Registers a "Set Config" callback.
Definition: usb_standard.c:42
void usbd_register_set_altsetting_callback(usbd_device *usbd_dev, usbd_set_altsetting_callback callback)
Registers a "Set Interface" (alternate setting) callback.
Definition: usb_standard.c:62
static enum usbd_request_return_codes usb_standard_endpoint_stall(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:460
static int usb_descriptor_index(uint16_t wValue)
Definition: usb_standard.c:147
static uint16_t build_config_descriptor(usbd_device *usbd_dev, uint8_t index, uint8_t *buf, uint16_t len)
Definition: usb_standard.c:68
#define USB_FEAT_TEST_MODE
Definition: usbstd.h:116
#define USB_REQ_GET_INTERFACE
Definition: usbstd.h:95
#define USB_DT_CONFIGURATION
Definition: usbstd.h:101
#define USB_REQ_SET_INTERFACE
Definition: usbstd.h:96
#define USB_REQ_SET_FEATURE
Definition: usbstd.h:88
#define USB_REQ_TYPE_STANDARD
Definition: usbstd.h:74
#define USB_REQ_TYPE_DEVICE
Definition: usbstd.h:79
#define USB_REQ_CLEAR_FEATURE
Definition: usbstd.h:86
#define USB_REQ_SET_SYNCH_FRAME
Definition: usbstd.h:97
#define USB_REQ_TYPE_RECIPIENT
Definition: usbstd.h:78
#define USB_REQ_SET_CONFIGURATION
Definition: usbstd.h:94
#define USB_DT_STRING
Definition: usbstd.h:102
#define USB_REQ_TYPE_TYPE
Definition: usbstd.h:73
#define USB_REQ_TYPE_INTERFACE
Definition: usbstd.h:80
#define USB_DT_DEVICE
Definition: usbstd.h:100
#define USB_REQ_GET_STATUS
Definition: usbstd.h:85
#define USB_FEAT_ENDPOINT_HALT
Definition: usbstd.h:114
#define USB_REQ_TYPE_ENDPOINT
Definition: usbstd.h:81
#define USB_FEAT_DEVICE_REMOTE_WAKEUP
Definition: usbstd.h:115
#define USB_REQ_SET_ADDRESS
Definition: usbstd.h:90
#define USB_REQ_GET_DESCRIPTOR
Definition: usbstd.h:91
#define USB_REQ_GET_CONFIGURATION
Definition: usbstd.h:93
#define USB_REQ_SET_DESCRIPTOR
Definition: usbstd.h:92
@ USB_LANGID_ENGLISH_US
Definition: usbstd.h:273
uint8_t bNumInterfaces
Definition: usbstd.h:172
const struct usb_interface * interface
Definition: usbstd.h:179
uint8_t bConfigurationValue
Definition: usbstd.h:173
const void * extra
Definition: usbstd.h:221
const struct usb_endpoint_descriptor * endpoint
Definition: usbstd.h:205
const void * extra
Definition: usbstd.h:206
const struct usb_iface_assoc_descriptor * iface_assoc
Definition: usbstd.h:163
const struct usb_interface_descriptor * altsetting
Definition: usbstd.h:164
uint8_t num_altsetting
Definition: usbstd.h:162
uint8_t * cur_altsetting
Definition: usbstd.h:161
uint16_t wIndex
Definition: usbstd.h:60
uint8_t bRequest
Definition: usbstd.h:58
uint8_t bmRequestType
Definition: usbstd.h:57
uint16_t wValue
Definition: usbstd.h:59
uint8_t bDescriptorType
Definition: usbstd.h:254
uint16_t wData[]
Definition: usbstd.h:255
enum usbd_request_return_codes _usbd_standard_request_interface(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:545
enum usbd_request_return_codes _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:616
enum usbd_request_return_codes _usbd_standard_request_device(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:489
enum usbd_request_return_codes _usbd_standard_request_endpoint(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:577