Deleted Added
sdiff udiff text old ( 246616 ) new ( 250207 )
full compact
1/* $FreeBSD: head/sys/dev/usb/template/usb_template.c 246616 2013-02-10 10:56:13Z hselasky $ */
2/*-
3 * Copyright (c) 2007 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * This file contains sub-routines to build up USB descriptors from
29 * USB templates.
30 */
31
32#ifdef USB_GLOBAL_INCLUDE_FILE
33#include USB_GLOBAL_INCLUDE_FILE
34#else
35#include <sys/stdint.h>
36#include <sys/stddef.h>
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/types.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/bus.h>
43#include <sys/module.h>
44#include <sys/lock.h>
45#include <sys/mutex.h>
46#include <sys/condvar.h>
47#include <sys/sysctl.h>
48#include <sys/sx.h>
49#include <sys/unistd.h>
50#include <sys/callout.h>
51#include <sys/malloc.h>
52#include <sys/priv.h>
53
54#include <dev/usb/usb.h>
55#include <dev/usb/usb_ioctl.h>
56#include <dev/usb/usbdi.h>
57#include <dev/usb/usbdi_util.h>
58#include "usbdevs.h"
59
60#include <dev/usb/usb_cdc.h>
61#include <dev/usb/usb_core.h>
62#include <dev/usb/usb_dynamic.h>
63#include <dev/usb/usb_busdma.h>
64#include <dev/usb/usb_process.h>
65#include <dev/usb/usb_device.h>
66
67#define USB_DEBUG_VAR usb_debug
68#include <dev/usb/usb_debug.h>
69
70#include <dev/usb/usb_controller.h>
71#include <dev/usb/usb_bus.h>
72#include <dev/usb/template/usb_template.h>
73#endif /* USB_GLOBAL_INCLUDE_FILE */
74
75MODULE_DEPEND(usb_template, usb, 1, 1, 1);
76MODULE_VERSION(usb_template, 1);
77
78/* function prototypes */
79
80static void usb_make_raw_desc(struct usb_temp_setup *, const uint8_t *);
81static void usb_make_endpoint_desc(struct usb_temp_setup *,
82 const struct usb_temp_endpoint_desc *);
83static void usb_make_interface_desc(struct usb_temp_setup *,
84 const struct usb_temp_interface_desc *);
85static void usb_make_config_desc(struct usb_temp_setup *,
86 const struct usb_temp_config_desc *);
87static void usb_make_device_desc(struct usb_temp_setup *,
88 const struct usb_temp_device_desc *);
89static uint8_t usb_hw_ep_match(const struct usb_hw_ep_profile *, uint8_t,
90 uint8_t);
91static uint8_t usb_hw_ep_find_match(struct usb_hw_ep_scratch *,
92 struct usb_hw_ep_scratch_sub *, uint8_t);
93static uint8_t usb_hw_ep_get_needs(struct usb_hw_ep_scratch *, uint8_t,
94 uint8_t);
95static usb_error_t usb_hw_ep_resolve(struct usb_device *,
96 struct usb_descriptor *);
97static const struct usb_temp_device_desc *usb_temp_get_tdd(struct usb_device *);
98static void *usb_temp_get_device_desc(struct usb_device *);
99static void *usb_temp_get_qualifier_desc(struct usb_device *);
100static void *usb_temp_get_config_desc(struct usb_device *, uint16_t *,
101 uint8_t);
102static const void *usb_temp_get_string_desc(struct usb_device *, uint16_t,
103 uint8_t);
104static const void *usb_temp_get_vendor_desc(struct usb_device *,
105 const struct usb_device_request *, uint16_t *plen);
106static const void *usb_temp_get_hub_desc(struct usb_device *);
107static usb_error_t usb_temp_get_desc(struct usb_device *,
108 struct usb_device_request *, const void **, uint16_t *);
109static usb_error_t usb_temp_setup_by_index(struct usb_device *,
110 uint16_t index);
111static void usb_temp_init(void *);
112
113/*------------------------------------------------------------------------*
114 * usb_make_raw_desc
115 *
116 * This function will insert a raw USB descriptor into the generated
117 * USB configuration.
118 *------------------------------------------------------------------------*/
119static void
120usb_make_raw_desc(struct usb_temp_setup *temp,
121 const uint8_t *raw)
122{
123 void *dst;
124 uint8_t len;
125
126 /*
127 * The first byte of any USB descriptor gives the length.
128 */
129 if (raw) {
130 len = raw[0];
131 if (temp->buf) {
132 dst = USB_ADD_BYTES(temp->buf, temp->size);
133 memcpy(dst, raw, len);
134
135 /* check if we have got a CDC union descriptor */
136
137 if ((raw[0] >= sizeof(struct usb_cdc_union_descriptor)) &&
138 (raw[1] == UDESC_CS_INTERFACE) &&
139 (raw[2] == UDESCSUB_CDC_UNION)) {
140 struct usb_cdc_union_descriptor *ud = (void *)dst;
141
142 /* update the interface numbers */
143
144 ud->bMasterInterface +=
145 temp->bInterfaceNumber;
146 ud->bSlaveInterface[0] +=
147 temp->bInterfaceNumber;
148 }
149
150 /* check if we have got an interface association descriptor */
151
152 if ((raw[0] >= sizeof(struct usb_interface_assoc_descriptor)) &&
153 (raw[1] == UDESC_IFACE_ASSOC)) {
154 struct usb_interface_assoc_descriptor *iad = (void *)dst;
155
156 /* update the interface number */
157
158 iad->bFirstInterface +=
159 temp->bInterfaceNumber;
160 }
161
162 /* check if we have got a call management descriptor */
163
164 if ((raw[0] >= sizeof(struct usb_cdc_cm_descriptor)) &&
165 (raw[1] == UDESC_CS_INTERFACE) &&
166 (raw[2] == UDESCSUB_CDC_CM)) {
167 struct usb_cdc_cm_descriptor *ccd = (void *)dst;
168
169 /* update the interface number */
170
171 ccd->bDataInterface +=
172 temp->bInterfaceNumber;
173 }
174 }
175 temp->size += len;
176 }
177}
178
179/*------------------------------------------------------------------------*
180 * usb_make_endpoint_desc
181 *
182 * This function will generate an USB endpoint descriptor from the
183 * given USB template endpoint descriptor, which will be inserted into
184 * the USB configuration.
185 *------------------------------------------------------------------------*/
186static void
187usb_make_endpoint_desc(struct usb_temp_setup *temp,
188 const struct usb_temp_endpoint_desc *ted)
189{
190 struct usb_endpoint_descriptor *ed;
191 const void **rd;
192 uint16_t old_size;
193 uint16_t mps;
194 uint8_t ea; /* Endpoint Address */
195 uint8_t et; /* Endpiont Type */
196
197 /* Reserve memory */
198 old_size = temp->size;
199
200 ea = (ted->bEndpointAddress & (UE_ADDR | UE_DIR_IN | UE_DIR_OUT));
201 et = (ted->bmAttributes & UE_XFERTYPE);
202
203 if (et == UE_ISOCHRONOUS) {
204 /* account for extra byte fields */
205 temp->size += sizeof(*ed) + 2;
206 } else {
207 temp->size += sizeof(*ed);
208 }
209
210 /* Scan all Raw Descriptors first */
211 rd = ted->ppRawDesc;
212 if (rd) {
213 while (*rd) {
214 usb_make_raw_desc(temp, *rd);
215 rd++;
216 }
217 }
218 if (ted->pPacketSize == NULL) {
219 /* not initialized */
220 temp->err = USB_ERR_INVAL;
221 return;
222 }
223 mps = ted->pPacketSize->mps[temp->usb_speed];
224 if (mps == 0) {
225 /* not initialized */
226 temp->err = USB_ERR_INVAL;
227 return;
228 } else if (mps == UE_ZERO_MPS) {
229 /* escape for Zero Max Packet Size */
230 mps = 0;
231 }
232
233 /*
234 * Fill out the real USB endpoint descriptor
235 * in case there is a buffer present:
236 */
237 if (temp->buf) {
238 ed = USB_ADD_BYTES(temp->buf, old_size);
239 if (et == UE_ISOCHRONOUS)
240 ed->bLength = sizeof(*ed) + 2;
241 else
242 ed->bLength = sizeof(*ed);
243 ed->bDescriptorType = UDESC_ENDPOINT;
244 ed->bEndpointAddress = ea;
245 ed->bmAttributes = ted->bmAttributes;
246 USETW(ed->wMaxPacketSize, mps);
247
248 /* setup bInterval parameter */
249
250 if (ted->pIntervals &&
251 ted->pIntervals->bInterval[temp->usb_speed]) {
252 ed->bInterval =
253 ted->pIntervals->bInterval[temp->usb_speed];
254 } else {
255 switch (et) {
256 case UE_BULK:
257 case UE_CONTROL:
258 ed->bInterval = 0; /* not used */
259 break;
260 case UE_INTERRUPT:
261 switch (temp->usb_speed) {
262 case USB_SPEED_LOW:
263 case USB_SPEED_FULL:
264 ed->bInterval = 1; /* 1 ms */
265 break;
266 default:
267 ed->bInterval = 4; /* 1 ms */
268 break;
269 }
270 break;
271 default: /* UE_ISOCHRONOUS */
272 switch (temp->usb_speed) {
273 case USB_SPEED_LOW:
274 case USB_SPEED_FULL:
275 ed->bInterval = 1; /* 1 ms */
276 break;
277 default:
278 ed->bInterval = 1; /* 125 us */
279 break;
280 }
281 break;
282 }
283 }
284 }
285 temp->bNumEndpoints++;
286}
287
288/*------------------------------------------------------------------------*
289 * usb_make_interface_desc
290 *
291 * This function will generate an USB interface descriptor from the
292 * given USB template interface descriptor, which will be inserted
293 * into the USB configuration.
294 *------------------------------------------------------------------------*/
295static void
296usb_make_interface_desc(struct usb_temp_setup *temp,
297 const struct usb_temp_interface_desc *tid)
298{
299 struct usb_interface_descriptor *id;
300 const struct usb_temp_endpoint_desc **ted;
301 const void **rd;
302 uint16_t old_size;
303
304 /* Reserve memory */
305
306 old_size = temp->size;
307 temp->size += sizeof(*id);
308
309 /* Update interface and alternate interface numbers */
310
311 if (tid->isAltInterface == 0) {
312 temp->bAlternateSetting = 0;
313 temp->bInterfaceNumber++;
314 } else {
315 temp->bAlternateSetting++;
316 }
317
318 /* Scan all Raw Descriptors first */
319
320 rd = tid->ppRawDesc;
321
322 if (rd) {
323 while (*rd) {
324 usb_make_raw_desc(temp, *rd);
325 rd++;
326 }
327 }
328 /* Reset some counters */
329
330 temp->bNumEndpoints = 0;
331
332 /* Scan all Endpoint Descriptors second */
333
334 ted = tid->ppEndpoints;
335 if (ted) {
336 while (*ted) {
337 usb_make_endpoint_desc(temp, *ted);
338 ted++;
339 }
340 }
341 /*
342 * Fill out the real USB interface descriptor
343 * in case there is a buffer present:
344 */
345 if (temp->buf) {
346 id = USB_ADD_BYTES(temp->buf, old_size);
347 id->bLength = sizeof(*id);
348 id->bDescriptorType = UDESC_INTERFACE;
349 id->bInterfaceNumber = temp->bInterfaceNumber;
350 id->bAlternateSetting = temp->bAlternateSetting;
351 id->bNumEndpoints = temp->bNumEndpoints;
352 id->bInterfaceClass = tid->bInterfaceClass;
353 id->bInterfaceSubClass = tid->bInterfaceSubClass;
354 id->bInterfaceProtocol = tid->bInterfaceProtocol;
355 id->iInterface = tid->iInterface;
356 }
357}
358
359/*------------------------------------------------------------------------*
360 * usb_make_config_desc
361 *
362 * This function will generate an USB config descriptor from the given
363 * USB template config descriptor, which will be inserted into the USB
364 * configuration.
365 *------------------------------------------------------------------------*/
366static void
367usb_make_config_desc(struct usb_temp_setup *temp,
368 const struct usb_temp_config_desc *tcd)
369{
370 struct usb_config_descriptor *cd;
371 const struct usb_temp_interface_desc **tid;
372 uint16_t old_size;
373
374 /* Reserve memory */
375
376 old_size = temp->size;
377 temp->size += sizeof(*cd);
378
379 /* Reset some counters */
380
381 temp->bInterfaceNumber = 0xFF;
382 temp->bAlternateSetting = 0;
383
384 /* Scan all the USB interfaces */
385
386 tid = tcd->ppIfaceDesc;
387 if (tid) {
388 while (*tid) {
389 usb_make_interface_desc(temp, *tid);
390 tid++;
391 }
392 }
393 /*
394 * Fill out the real USB config descriptor
395 * in case there is a buffer present:
396 */
397 if (temp->buf) {
398 cd = USB_ADD_BYTES(temp->buf, old_size);
399
400 /* compute total size */
401 old_size = temp->size - old_size;
402
403 cd->bLength = sizeof(*cd);
404 cd->bDescriptorType = UDESC_CONFIG;
405 USETW(cd->wTotalLength, old_size);
406 cd->bNumInterface = temp->bInterfaceNumber + 1;
407 cd->bConfigurationValue = temp->bConfigurationValue;
408 cd->iConfiguration = tcd->iConfiguration;
409 cd->bmAttributes = tcd->bmAttributes;
410 cd->bMaxPower = tcd->bMaxPower;
411 cd->bmAttributes |= (UC_REMOTE_WAKEUP | UC_BUS_POWERED);
412
413 if (temp->self_powered) {
414 cd->bmAttributes |= UC_SELF_POWERED;
415 } else {
416 cd->bmAttributes &= ~UC_SELF_POWERED;
417 }
418 }
419}
420
421/*------------------------------------------------------------------------*
422 * usb_make_device_desc
423 *
424 * This function will generate an USB device descriptor from the
425 * given USB template device descriptor.
426 *------------------------------------------------------------------------*/
427static void
428usb_make_device_desc(struct usb_temp_setup *temp,
429 const struct usb_temp_device_desc *tdd)
430{
431 struct usb_temp_data *utd;
432 const struct usb_temp_config_desc **tcd;
433 uint16_t old_size;
434
435 /* Reserve memory */
436
437 old_size = temp->size;
438 temp->size += sizeof(*utd);
439
440 /* Scan all the USB configs */
441
442 temp->bConfigurationValue = 1;
443 tcd = tdd->ppConfigDesc;
444 if (tcd) {
445 while (*tcd) {
446 usb_make_config_desc(temp, *tcd);
447 temp->bConfigurationValue++;
448 tcd++;
449 }
450 }
451 /*
452 * Fill out the real USB device descriptor
453 * in case there is a buffer present:
454 */
455
456 if (temp->buf) {
457 utd = USB_ADD_BYTES(temp->buf, old_size);
458
459 /* Store a pointer to our template device descriptor */
460 utd->tdd = tdd;
461
462 /* Fill out USB device descriptor */
463 utd->udd.bLength = sizeof(utd->udd);
464 utd->udd.bDescriptorType = UDESC_DEVICE;
465 utd->udd.bDeviceClass = tdd->bDeviceClass;
466 utd->udd.bDeviceSubClass = tdd->bDeviceSubClass;
467 utd->udd.bDeviceProtocol = tdd->bDeviceProtocol;
468 USETW(utd->udd.idVendor, tdd->idVendor);
469 USETW(utd->udd.idProduct, tdd->idProduct);
470 USETW(utd->udd.bcdDevice, tdd->bcdDevice);
471 utd->udd.iManufacturer = tdd->iManufacturer;
472 utd->udd.iProduct = tdd->iProduct;
473 utd->udd.iSerialNumber = tdd->iSerialNumber;
474 utd->udd.bNumConfigurations = temp->bConfigurationValue - 1;
475
476 /*
477 * Fill out the USB device qualifier. Pretend that we
478 * don't support any other speeds by setting
479 * "bNumConfigurations" equal to zero. That saves us
480 * generating an extra set of configuration
481 * descriptors.
482 */
483 utd->udq.bLength = sizeof(utd->udq);
484 utd->udq.bDescriptorType = UDESC_DEVICE_QUALIFIER;
485 utd->udq.bDeviceClass = tdd->bDeviceClass;
486 utd->udq.bDeviceSubClass = tdd->bDeviceSubClass;
487 utd->udq.bDeviceProtocol = tdd->bDeviceProtocol;
488 utd->udq.bNumConfigurations = 0;
489 USETW(utd->udq.bcdUSB, 0x0200);
490 utd->udq.bMaxPacketSize0 = 0;
491
492 switch (temp->usb_speed) {
493 case USB_SPEED_LOW:
494 USETW(utd->udd.bcdUSB, 0x0110);
495 utd->udd.bMaxPacketSize = 8;
496 break;
497 case USB_SPEED_FULL:
498 USETW(utd->udd.bcdUSB, 0x0110);
499 utd->udd.bMaxPacketSize = 32;
500 break;
501 case USB_SPEED_HIGH:
502 USETW(utd->udd.bcdUSB, 0x0200);
503 utd->udd.bMaxPacketSize = 64;
504 break;
505 case USB_SPEED_VARIABLE:
506 USETW(utd->udd.bcdUSB, 0x0250);
507 utd->udd.bMaxPacketSize = 255; /* 512 bytes */
508 break;
509 case USB_SPEED_SUPER:
510 USETW(utd->udd.bcdUSB, 0x0300);
511 utd->udd.bMaxPacketSize = 9; /* 2**9 = 512 bytes */
512 break;
513 default:
514 temp->err = USB_ERR_INVAL;
515 break;
516 }
517 }
518}
519
520/*------------------------------------------------------------------------*
521 * usb_hw_ep_match
522 *
523 * Return values:
524 * 0: The endpoint profile does not match the criterias
525 * Else: The endpoint profile matches the criterias
526 *------------------------------------------------------------------------*/
527static uint8_t
528usb_hw_ep_match(const struct usb_hw_ep_profile *pf,
529 uint8_t ep_type, uint8_t ep_dir_in)
530{
531 if (ep_type == UE_CONTROL) {
532 /* special */
533 return (pf->support_control);
534 }
535 if ((pf->support_in && ep_dir_in) ||
536 (pf->support_out && !ep_dir_in)) {
537 if ((pf->support_interrupt && (ep_type == UE_INTERRUPT)) ||
538 (pf->support_isochronous && (ep_type == UE_ISOCHRONOUS)) ||
539 (pf->support_bulk && (ep_type == UE_BULK))) {
540 return (1);
541 }
542 }
543 return (0);
544}
545
546/*------------------------------------------------------------------------*
547 * usb_hw_ep_find_match
548 *
549 * This function is used to find the best matching endpoint profile
550 * for and endpoint belonging to an USB descriptor.
551 *
552 * Return values:
553 * 0: Success. Got a match.
554 * Else: Failure. No match.
555 *------------------------------------------------------------------------*/
556static uint8_t
557usb_hw_ep_find_match(struct usb_hw_ep_scratch *ues,
558 struct usb_hw_ep_scratch_sub *ep, uint8_t is_simplex)
559{
560 const struct usb_hw_ep_profile *pf;
561 uint16_t distance;
562 uint16_t temp;
563 uint16_t max_frame_size;
564 uint8_t n;
565 uint8_t best_n;
566 uint8_t dir_in;
567 uint8_t dir_out;
568
569 distance = 0xFFFF;
570 best_n = 0;
571
572 if ((!ep->needs_in) && (!ep->needs_out)) {
573 return (0); /* we are done */
574 }
575 if (ep->needs_ep_type == UE_CONTROL) {
576 dir_in = 1;
577 dir_out = 1;
578 } else {
579 if (ep->needs_in) {
580 dir_in = 1;
581 dir_out = 0;
582 } else {
583 dir_in = 0;
584 dir_out = 1;
585 }
586 }
587
588 for (n = 1; n != (USB_EP_MAX / 2); n++) {
589
590 /* get HW endpoint profile */
591 (ues->methods->get_hw_ep_profile) (ues->udev, &pf, n);
592 if (pf == NULL) {
593 /* end of profiles */
594 break;
595 }
596 /* check if IN-endpoint is reserved */
597 if (dir_in || pf->is_simplex) {
598 if (ues->bmInAlloc[n / 8] & (1 << (n % 8))) {
599 /* mismatch */
600 continue;
601 }
602 }
603 /* check if OUT-endpoint is reserved */
604 if (dir_out || pf->is_simplex) {
605 if (ues->bmOutAlloc[n / 8] & (1 << (n % 8))) {
606 /* mismatch */
607 continue;
608 }
609 }
610 /* check simplex */
611 if (pf->is_simplex == is_simplex) {
612 /* mismatch */
613 continue;
614 }
615 /* check if HW endpoint matches */
616 if (!usb_hw_ep_match(pf, ep->needs_ep_type, dir_in)) {
617 /* mismatch */
618 continue;
619 }
620 /* get maximum frame size */
621 if (dir_in)
622 max_frame_size = pf->max_in_frame_size;
623 else
624 max_frame_size = pf->max_out_frame_size;
625
626 /* check if we have a matching profile */
627 if (max_frame_size >= ep->max_frame_size) {
628 temp = (max_frame_size - ep->max_frame_size);
629 if (distance > temp) {
630 distance = temp;
631 best_n = n;
632 ep->pf = pf;
633 }
634 }
635 }
636
637 /* see if we got a match */
638 if (best_n != 0) {
639 /* get the correct profile */
640 pf = ep->pf;
641
642 /* reserve IN-endpoint */
643 if (dir_in) {
644 ues->bmInAlloc[best_n / 8] |=
645 (1 << (best_n % 8));
646 ep->hw_endpoint_in = best_n | UE_DIR_IN;
647 ep->needs_in = 0;
648 }
649 /* reserve OUT-endpoint */
650 if (dir_out) {
651 ues->bmOutAlloc[best_n / 8] |=
652 (1 << (best_n % 8));
653 ep->hw_endpoint_out = best_n | UE_DIR_OUT;
654 ep->needs_out = 0;
655 }
656 return (0); /* got a match */
657 }
658 return (1); /* failure */
659}
660
661/*------------------------------------------------------------------------*
662 * usb_hw_ep_get_needs
663 *
664 * This function will figure out the type and number of endpoints
665 * which are needed for an USB configuration.
666 *
667 * Return values:
668 * 0: Success.
669 * Else: Failure.
670 *------------------------------------------------------------------------*/
671static uint8_t
672usb_hw_ep_get_needs(struct usb_hw_ep_scratch *ues,
673 uint8_t ep_type, uint8_t is_complete)
674{
675 const struct usb_hw_ep_profile *pf;
676 struct usb_hw_ep_scratch_sub *ep_iface;
677 struct usb_hw_ep_scratch_sub *ep_curr;
678 struct usb_hw_ep_scratch_sub *ep_max;
679 struct usb_hw_ep_scratch_sub *ep_end;
680 struct usb_descriptor *desc;
681 struct usb_interface_descriptor *id;
682 struct usb_endpoint_descriptor *ed;
683 enum usb_dev_speed speed;
684 uint16_t wMaxPacketSize;
685 uint16_t temp;
686 uint8_t ep_no;
687
688 ep_iface = ues->ep_max;
689 ep_curr = ues->ep_max;
690 ep_end = ues->ep + USB_EP_MAX;
691 ep_max = ues->ep_max;
692 desc = NULL;
693 speed = usbd_get_speed(ues->udev);
694
695repeat:
696
697 while ((desc = usb_desc_foreach(ues->cd, desc))) {
698
699 if ((desc->bDescriptorType == UDESC_INTERFACE) &&
700 (desc->bLength >= sizeof(*id))) {
701
702 id = (void *)desc;
703
704 if (id->bAlternateSetting == 0) {
705 /* going forward */
706 ep_iface = ep_max;
707 } else {
708 /* reset */
709 ep_curr = ep_iface;
710 }
711 }
712 if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
713 (desc->bLength >= sizeof(*ed))) {
714
715 ed = (void *)desc;
716
717 goto handle_endpoint_desc;
718 }
719 }
720 ues->ep_max = ep_max;
721 return (0);
722
723handle_endpoint_desc:
724 temp = (ed->bmAttributes & UE_XFERTYPE);
725
726 if (temp == ep_type) {
727
728 if (ep_curr == ep_end) {
729 /* too many endpoints */
730 return (1); /* failure */
731 }
732 wMaxPacketSize = UGETW(ed->wMaxPacketSize);
733 if ((wMaxPacketSize & 0xF800) &&
734 (speed == USB_SPEED_HIGH)) {
735 /* handle packet multiplier */
736 temp = (wMaxPacketSize >> 11) & 3;
737 wMaxPacketSize &= 0x7FF;
738 if (temp == 1) {
739 wMaxPacketSize *= 2;
740 } else {
741 wMaxPacketSize *= 3;
742 }
743 }
744 /*
745 * Check if we have a fixed endpoint number, else the
746 * endpoint number is allocated dynamically:
747 */
748 ep_no = (ed->bEndpointAddress & UE_ADDR);
749 if (ep_no != 0) {
750
751 /* get HW endpoint profile */
752 (ues->methods->get_hw_ep_profile)
753 (ues->udev, &pf, ep_no);
754 if (pf == NULL) {
755 /* HW profile does not exist - failure */
756 DPRINTFN(0, "Endpoint profile %u "
757 "does not exist\n", ep_no);
758 return (1);
759 }
760 /* reserve fixed endpoint number */
761 if (ep_type == UE_CONTROL) {
762 ues->bmInAlloc[ep_no / 8] |=
763 (1 << (ep_no % 8));
764 ues->bmOutAlloc[ep_no / 8] |=
765 (1 << (ep_no % 8));
766 if ((pf->max_in_frame_size < wMaxPacketSize) ||
767 (pf->max_out_frame_size < wMaxPacketSize)) {
768 DPRINTFN(0, "Endpoint profile %u "
769 "has too small buffer\n", ep_no);
770 return (1);
771 }
772 } else if (ed->bEndpointAddress & UE_DIR_IN) {
773 ues->bmInAlloc[ep_no / 8] |=
774 (1 << (ep_no % 8));
775 if (pf->max_in_frame_size < wMaxPacketSize) {
776 DPRINTFN(0, "Endpoint profile %u "
777 "has too small buffer\n", ep_no);
778 return (1);
779 }
780 } else {
781 ues->bmOutAlloc[ep_no / 8] |=
782 (1 << (ep_no % 8));
783 if (pf->max_out_frame_size < wMaxPacketSize) {
784 DPRINTFN(0, "Endpoint profile %u "
785 "has too small buffer\n", ep_no);
786 return (1);
787 }
788 }
789 } else if (is_complete) {
790
791 /* check if we have enough buffer space */
792 if (wMaxPacketSize >
793 ep_curr->max_frame_size) {
794 return (1); /* failure */
795 }
796 if (ed->bEndpointAddress & UE_DIR_IN) {
797 ed->bEndpointAddress =
798 ep_curr->hw_endpoint_in;
799 } else {
800 ed->bEndpointAddress =
801 ep_curr->hw_endpoint_out;
802 }
803
804 } else {
805
806 /* compute the maximum frame size */
807 if (ep_curr->max_frame_size < wMaxPacketSize) {
808 ep_curr->max_frame_size = wMaxPacketSize;
809 }
810 if (temp == UE_CONTROL) {
811 ep_curr->needs_in = 1;
812 ep_curr->needs_out = 1;
813 } else {
814 if (ed->bEndpointAddress & UE_DIR_IN) {
815 ep_curr->needs_in = 1;
816 } else {
817 ep_curr->needs_out = 1;
818 }
819 }
820 ep_curr->needs_ep_type = ep_type;
821 }
822
823 ep_curr++;
824 if (ep_max < ep_curr) {
825 ep_max = ep_curr;
826 }
827 }
828 goto repeat;
829}
830
831/*------------------------------------------------------------------------*
832 * usb_hw_ep_resolve
833 *
834 * This function will try to resolve endpoint requirements by the
835 * given endpoint profiles that the USB hardware reports.
836 *
837 * Return values:
838 * 0: Success
839 * Else: Failure
840 *------------------------------------------------------------------------*/
841static usb_error_t
842usb_hw_ep_resolve(struct usb_device *udev,
843 struct usb_descriptor *desc)
844{
845 struct usb_hw_ep_scratch *ues;
846 struct usb_hw_ep_scratch_sub *ep;
847 const struct usb_hw_ep_profile *pf;
848 struct usb_bus_methods *methods;
849 struct usb_device_descriptor *dd;
850 uint16_t mps;
851
852 if (desc == NULL)
853 return (USB_ERR_INVAL);
854
855 /* get bus methods */
856 methods = udev->bus->methods;
857
858 if (methods->get_hw_ep_profile == NULL)
859 return (USB_ERR_INVAL);
860
861 if (desc->bDescriptorType == UDESC_DEVICE) {
862
863 if (desc->bLength < sizeof(*dd))
864 return (USB_ERR_INVAL);
865
866 dd = (void *)desc;
867
868 /* get HW control endpoint 0 profile */
869 (methods->get_hw_ep_profile) (udev, &pf, 0);
870 if (pf == NULL) {
871 return (USB_ERR_INVAL);
872 }
873 if (!usb_hw_ep_match(pf, UE_CONTROL, 0)) {
874 DPRINTFN(0, "Endpoint 0 does not "
875 "support control\n");
876 return (USB_ERR_INVAL);
877 }
878 mps = dd->bMaxPacketSize;
879
880 if (udev->speed == USB_SPEED_FULL) {
881 /*
882 * We can optionally choose another packet size !
883 */
884 while (1) {
885 /* check if "mps" is ok */
886 if (pf->max_in_frame_size >= mps) {
887 break;
888 }
889 /* reduce maximum packet size */
890 mps /= 2;
891
892 /* check if "mps" is too small */
893 if (mps < 8) {
894 return (USB_ERR_INVAL);
895 }
896 }
897
898 dd->bMaxPacketSize = mps;
899
900 } else {
901 /* We only have one choice */
902 if (mps == 255) {
903 mps = 512;
904 }
905 /* Check if we support the specified wMaxPacketSize */
906 if (pf->max_in_frame_size < mps) {
907 return (USB_ERR_INVAL);
908 }
909 }
910 return (0); /* success */
911 }
912 if (desc->bDescriptorType != UDESC_CONFIG)
913 return (USB_ERR_INVAL);
914 if (desc->bLength < sizeof(*(ues->cd)))
915 return (USB_ERR_INVAL);
916
917 ues = udev->scratch.hw_ep_scratch;
918
919 memset(ues, 0, sizeof(*ues));
920
921 ues->ep_max = ues->ep;
922 ues->cd = (void *)desc;
923 ues->methods = methods;
924 ues->udev = udev;
925
926 /* Get all the endpoints we need */
927
928 if (usb_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 0) ||
929 usb_hw_ep_get_needs(ues, UE_INTERRUPT, 0) ||
930 usb_hw_ep_get_needs(ues, UE_CONTROL, 0) ||
931 usb_hw_ep_get_needs(ues, UE_BULK, 0)) {
932 DPRINTFN(0, "Could not get needs\n");
933 return (USB_ERR_INVAL);
934 }
935 for (ep = ues->ep; ep != ues->ep_max; ep++) {
936
937 while (ep->needs_in || ep->needs_out) {
938
939 /*
940 * First try to use a simplex endpoint.
941 * Then try to use a duplex endpoint.
942 */
943 if (usb_hw_ep_find_match(ues, ep, 1) &&
944 usb_hw_ep_find_match(ues, ep, 0)) {
945 DPRINTFN(0, "Could not find match\n");
946 return (USB_ERR_INVAL);
947 }
948 }
949 }
950
951 ues->ep_max = ues->ep;
952
953 /* Update all endpoint addresses */
954
955 if (usb_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 1) ||
956 usb_hw_ep_get_needs(ues, UE_INTERRUPT, 1) ||
957 usb_hw_ep_get_needs(ues, UE_CONTROL, 1) ||
958 usb_hw_ep_get_needs(ues, UE_BULK, 1)) {
959 DPRINTFN(0, "Could not update endpoint address\n");
960 return (USB_ERR_INVAL);
961 }
962 return (0); /* success */
963}
964
965/*------------------------------------------------------------------------*
966 * usb_temp_get_tdd
967 *
968 * Returns:
969 * NULL: No USB template device descriptor found.
970 * Else: Pointer to the USB template device descriptor.
971 *------------------------------------------------------------------------*/
972static const struct usb_temp_device_desc *
973usb_temp_get_tdd(struct usb_device *udev)
974{
975 if (udev->usb_template_ptr == NULL) {
976 return (NULL);
977 }
978 return (udev->usb_template_ptr->tdd);
979}
980
981/*------------------------------------------------------------------------*
982 * usb_temp_get_device_desc
983 *
984 * Returns:
985 * NULL: No USB device descriptor found.
986 * Else: Pointer to USB device descriptor.
987 *------------------------------------------------------------------------*/
988static void *
989usb_temp_get_device_desc(struct usb_device *udev)
990{
991 struct usb_device_descriptor *dd;
992
993 if (udev->usb_template_ptr == NULL) {
994 return (NULL);
995 }
996 dd = &udev->usb_template_ptr->udd;
997 if (dd->bDescriptorType != UDESC_DEVICE) {
998 /* sanity check failed */
999 return (NULL);
1000 }
1001 return (dd);
1002}
1003
1004/*------------------------------------------------------------------------*
1005 * usb_temp_get_qualifier_desc
1006 *
1007 * Returns:
1008 * NULL: No USB device_qualifier descriptor found.
1009 * Else: Pointer to USB device_qualifier descriptor.
1010 *------------------------------------------------------------------------*/
1011static void *
1012usb_temp_get_qualifier_desc(struct usb_device *udev)
1013{
1014 struct usb_device_qualifier *dq;
1015
1016 if (udev->usb_template_ptr == NULL) {
1017 return (NULL);
1018 }
1019 dq = &udev->usb_template_ptr->udq;
1020 if (dq->bDescriptorType != UDESC_DEVICE_QUALIFIER) {
1021 /* sanity check failed */
1022 return (NULL);
1023 }
1024 return (dq);
1025}
1026
1027/*------------------------------------------------------------------------*
1028 * usb_temp_get_config_desc
1029 *
1030 * Returns:
1031 * NULL: No USB config descriptor found.
1032 * Else: Pointer to USB config descriptor having index "index".
1033 *------------------------------------------------------------------------*/
1034static void *
1035usb_temp_get_config_desc(struct usb_device *udev,
1036 uint16_t *pLength, uint8_t index)
1037{
1038 struct usb_device_descriptor *dd;
1039 struct usb_config_descriptor *cd;
1040 uint16_t temp;
1041
1042 if (udev->usb_template_ptr == NULL) {
1043 return (NULL);
1044 }
1045 dd = &udev->usb_template_ptr->udd;
1046 cd = (void *)(udev->usb_template_ptr + 1);
1047
1048 if (index >= dd->bNumConfigurations) {
1049 /* out of range */
1050 return (NULL);
1051 }
1052 while (index--) {
1053 if (cd->bDescriptorType != UDESC_CONFIG) {
1054 /* sanity check failed */
1055 return (NULL);
1056 }
1057 temp = UGETW(cd->wTotalLength);
1058 cd = USB_ADD_BYTES(cd, temp);
1059 }
1060
1061 if (pLength) {
1062 *pLength = UGETW(cd->wTotalLength);
1063 }
1064 return (cd);
1065}
1066
1067/*------------------------------------------------------------------------*
1068 * usb_temp_get_vendor_desc
1069 *
1070 * Returns:
1071 * NULL: No vendor descriptor found.
1072 * Else: Pointer to a vendor descriptor.
1073 *------------------------------------------------------------------------*/
1074static const void *
1075usb_temp_get_vendor_desc(struct usb_device *udev,
1076 const struct usb_device_request *req, uint16_t *plen)
1077{
1078 const struct usb_temp_device_desc *tdd;
1079
1080 tdd = usb_temp_get_tdd(udev);
1081 if (tdd == NULL) {
1082 return (NULL);
1083 }
1084 if (tdd->getVendorDesc == NULL) {
1085 return (NULL);
1086 }
1087 return ((tdd->getVendorDesc) (req, plen));
1088}
1089
1090/*------------------------------------------------------------------------*
1091 * usb_temp_get_string_desc
1092 *
1093 * Returns:
1094 * NULL: No string descriptor found.
1095 * Else: Pointer to a string descriptor.
1096 *------------------------------------------------------------------------*/
1097static const void *
1098usb_temp_get_string_desc(struct usb_device *udev,
1099 uint16_t lang_id, uint8_t string_index)
1100{
1101 const struct usb_temp_device_desc *tdd;
1102
1103 tdd = usb_temp_get_tdd(udev);
1104 if (tdd == NULL) {
1105 return (NULL);
1106 }
1107 if (tdd->getStringDesc == NULL) {
1108 return (NULL);
1109 }
1110 return ((tdd->getStringDesc) (lang_id, string_index));
1111}
1112
1113/*------------------------------------------------------------------------*
1114 * usb_temp_get_hub_desc
1115 *
1116 * Returns:
1117 * NULL: No USB HUB descriptor found.
1118 * Else: Pointer to a USB HUB descriptor.
1119 *------------------------------------------------------------------------*/
1120static const void *
1121usb_temp_get_hub_desc(struct usb_device *udev)
1122{
1123 return (NULL); /* needs to be implemented */
1124}
1125
1126/*------------------------------------------------------------------------*
1127 * usb_temp_get_desc
1128 *
1129 * This function is a demultiplexer for local USB device side control
1130 * endpoint requests.
1131 *------------------------------------------------------------------------*/
1132static usb_error_t
1133usb_temp_get_desc(struct usb_device *udev, struct usb_device_request *req,
1134 const void **pPtr, uint16_t *pLength)
1135{
1136 const uint8_t *buf;
1137 uint16_t len;
1138
1139 buf = NULL;
1140 len = 0;
1141
1142 switch (req->bmRequestType) {
1143 case UT_READ_DEVICE:
1144 switch (req->bRequest) {
1145 case UR_GET_DESCRIPTOR:
1146 goto tr_handle_get_descriptor;
1147 default:
1148 goto tr_stalled;
1149 }
1150 case UT_READ_CLASS_DEVICE:
1151 switch (req->bRequest) {
1152 case UR_GET_DESCRIPTOR:
1153 goto tr_handle_get_class_descriptor;
1154 default:
1155 goto tr_stalled;
1156 }
1157 default:
1158 goto tr_stalled;
1159 }
1160
1161tr_handle_get_descriptor:
1162 switch (req->wValue[1]) {
1163 case UDESC_DEVICE:
1164 if (req->wValue[0]) {
1165 goto tr_stalled;
1166 }
1167 buf = usb_temp_get_device_desc(udev);
1168 goto tr_valid;
1169 case UDESC_DEVICE_QUALIFIER:
1170 if (udev->speed != USB_SPEED_HIGH) {
1171 goto tr_stalled;
1172 }
1173 if (req->wValue[0]) {
1174 goto tr_stalled;
1175 }
1176 buf = usb_temp_get_qualifier_desc(udev);
1177 goto tr_valid;
1178 case UDESC_OTHER_SPEED_CONFIGURATION:
1179 if (udev->speed != USB_SPEED_HIGH) {
1180 goto tr_stalled;
1181 }
1182 case UDESC_CONFIG:
1183 buf = usb_temp_get_config_desc(udev,
1184 &len, req->wValue[0]);
1185 goto tr_valid;
1186 case UDESC_STRING:
1187 buf = usb_temp_get_string_desc(udev,
1188 UGETW(req->wIndex), req->wValue[0]);
1189 goto tr_valid;
1190 default:
1191 goto tr_stalled;
1192 }
1193
1194tr_handle_get_class_descriptor:
1195 if (req->wValue[0]) {
1196 goto tr_stalled;
1197 }
1198 buf = usb_temp_get_hub_desc(udev);
1199 goto tr_valid;
1200
1201tr_valid:
1202 if (buf == NULL)
1203 goto tr_stalled;
1204 if (len == 0)
1205 len = buf[0];
1206 *pPtr = buf;
1207 *pLength = len;
1208 return (0); /* success */
1209
1210tr_stalled:
1211 /* try to get a vendor specific descriptor */
1212 len = 0;
1213 buf = usb_temp_get_vendor_desc(udev, req, &len);
1214 if (buf != NULL)
1215 goto tr_valid;
1216 *pPtr = NULL;
1217 *pLength = 0;
1218 return (0); /* we ignore failures */
1219}
1220
1221/*------------------------------------------------------------------------*
1222 * usb_temp_setup
1223 *
1224 * This function generates USB descriptors according to the given USB
1225 * template device descriptor. It will also try to figure out the best
1226 * matching endpoint addresses using the hardware endpoint profiles.
1227 *
1228 * Returns:
1229 * 0: Success
1230 * Else: Failure
1231 *------------------------------------------------------------------------*/
1232usb_error_t
1233usb_temp_setup(struct usb_device *udev,
1234 const struct usb_temp_device_desc *tdd)
1235{
1236 struct usb_temp_setup *uts;
1237 void *buf;
1238 usb_error_t error;
1239 uint8_t n;
1240 uint8_t do_unlock;
1241
1242 /* be NULL safe */
1243 if (tdd == NULL)
1244 return (0);
1245
1246 /* Protect scratch area */
1247 do_unlock = usbd_enum_lock(udev);
1248
1249 uts = udev->scratch.temp_setup;
1250
1251 memset(uts, 0, sizeof(*uts));
1252
1253 uts->usb_speed = udev->speed;
1254 uts->self_powered = udev->flags.self_powered;
1255
1256 /* first pass */
1257
1258 usb_make_device_desc(uts, tdd);
1259
1260 if (uts->err) {
1261 /* some error happened */
1262 goto done;
1263 }
1264 /* sanity check */
1265 if (uts->size == 0) {
1266 uts->err = USB_ERR_INVAL;
1267 goto done;
1268 }
1269 /* allocate zeroed memory */
1270 uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO);
1271 /*
1272 * Allow malloc() to return NULL regardless of M_WAITOK flag.
1273 * This helps when porting the software to non-FreeBSD
1274 * systems.
1275 */
1276 if (uts->buf == NULL) {
1277 /* could not allocate memory */
1278 uts->err = USB_ERR_NOMEM;
1279 goto done;
1280 }
1281 /* second pass */
1282
1283 uts->size = 0;
1284
1285 usb_make_device_desc(uts, tdd);
1286
1287 /*
1288 * Store a pointer to our descriptors:
1289 */
1290 udev->usb_template_ptr = uts->buf;
1291
1292 if (uts->err) {
1293 /* some error happened during second pass */
1294 goto done;
1295 }
1296 /*
1297 * Resolve all endpoint addresses !
1298 */
1299 buf = usb_temp_get_device_desc(udev);
1300 uts->err = usb_hw_ep_resolve(udev, buf);
1301 if (uts->err) {
1302 DPRINTFN(0, "Could not resolve endpoints for "
1303 "Device Descriptor, error = %s\n",
1304 usbd_errstr(uts->err));
1305 goto done;
1306 }
1307 for (n = 0;; n++) {
1308
1309 buf = usb_temp_get_config_desc(udev, NULL, n);
1310 if (buf == NULL) {
1311 break;
1312 }
1313 uts->err = usb_hw_ep_resolve(udev, buf);
1314 if (uts->err) {
1315 DPRINTFN(0, "Could not resolve endpoints for "
1316 "Config Descriptor %u, error = %s\n", n,
1317 usbd_errstr(uts->err));
1318 goto done;
1319 }
1320 }
1321done:
1322 error = uts->err;
1323 if (error)
1324 usb_temp_unsetup(udev);
1325 if (do_unlock)
1326 usbd_enum_unlock(udev);
1327 return (error);
1328}
1329
1330/*------------------------------------------------------------------------*
1331 * usb_temp_unsetup
1332 *
1333 * This function frees any memory associated with the currently
1334 * setup template, if any.
1335 *------------------------------------------------------------------------*/
1336void
1337usb_temp_unsetup(struct usb_device *udev)
1338{
1339 if (udev->usb_template_ptr) {
1340
1341 free(udev->usb_template_ptr, M_USB);
1342
1343 udev->usb_template_ptr = NULL;
1344 }
1345}
1346
1347static usb_error_t
1348usb_temp_setup_by_index(struct usb_device *udev, uint16_t index)
1349{
1350 usb_error_t err;
1351
1352 switch (index) {
1353 case USB_TEMP_MSC:
1354 err = usb_temp_setup(udev, &usb_template_msc);
1355 break;
1356 case USB_TEMP_CDCE:
1357 err = usb_temp_setup(udev, &usb_template_cdce);
1358 break;
1359 case USB_TEMP_MTP:
1360 err = usb_temp_setup(udev, &usb_template_mtp);
1361 break;
1362 case USB_TEMP_MODEM:
1363 err = usb_temp_setup(udev, &usb_template_modem);
1364 break;
1365 case USB_TEMP_AUDIO:
1366 err = usb_temp_setup(udev, &usb_template_audio);
1367 break;
1368 case USB_TEMP_KBD:
1369 err = usb_temp_setup(udev, &usb_template_kbd);
1370 break;
1371 case USB_TEMP_MOUSE:
1372 err = usb_temp_setup(udev, &usb_template_mouse);
1373 break;
1374 default:
1375 return (USB_ERR_INVAL);
1376 }
1377
1378 return (err);
1379}
1380
1381static void
1382usb_temp_init(void *arg)
1383{
1384 /* register our functions */
1385 usb_temp_get_desc_p = &usb_temp_get_desc;
1386 usb_temp_setup_by_index_p = &usb_temp_setup_by_index;
1387 usb_temp_unsetup_p = &usb_temp_unsetup;
1388}
1389
1390SYSINIT(usb_temp_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb_temp_init, NULL);
1391SYSUNINIT(usb_temp_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb_temp_unload, NULL);