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