usb_template.c revision 188942
1184610Salfred/* $FreeBSD: head/sys/dev/usb/template/usb_template.c 188942 2009-02-23 18:31:00Z thompsa $ */
2184610Salfred/*-
3184610Salfred * Copyright (c) 2007 Hans Petter Selasky. All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred *
14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24184610Salfred * SUCH DAMAGE.
25184610Salfred */
26184610Salfred
27184610Salfred/*
28184610Salfred * This file contains sub-routines to build up USB descriptors from
29184610Salfred * USB templates.
30184610Salfred */
31184610Salfred
32188942Sthompsa#include <dev/usb/usb.h>
33188942Sthompsa#include <dev/usb/usb_cdc.h>
34188942Sthompsa#include <dev/usb/usb_mfunc.h>
35188942Sthompsa#include <dev/usb/usb_defs.h>
36188942Sthompsa#include <dev/usb/usb_error.h>
37184610Salfred
38184610Salfred#define	USB_DEBUG_VAR usb2_debug
39184610Salfred
40188942Sthompsa#include <dev/usb/usb_core.h>
41188942Sthompsa#include <dev/usb/usb_busdma.h>
42188942Sthompsa#include <dev/usb/usb_process.h>
43188942Sthompsa#include <dev/usb/usb_debug.h>
44188942Sthompsa#include <dev/usb/usb_parse.h>
45188942Sthompsa#include <dev/usb/usb_device.h>
46188942Sthompsa#include <dev/usb/usb_dynamic.h>
47184610Salfred
48188942Sthompsa#include <dev/usb/usb_controller.h>
49188942Sthompsa#include <dev/usb/usb_bus.h>
50184610Salfred
51188942Sthompsa#include <dev/usb/template/usb_template.h>
52184610Salfred
53188942SthompsaMODULE_DEPEND(usb_template, usb, 1, 1, 1);
54188942SthompsaMODULE_VERSION(usb_template, 1);
55184610Salfred
56184610Salfred/* function prototypes */
57184610Salfred
58185948Sthompsastatic void	usb2_make_raw_desc(struct usb2_temp_setup *, const uint8_t *);
59185948Sthompsastatic void	usb2_make_endpoint_desc(struct usb2_temp_setup *,
60185948Sthompsa		    const struct usb2_temp_endpoint_desc *);
61185948Sthompsastatic void	usb2_make_interface_desc(struct usb2_temp_setup *,
62185948Sthompsa		    const struct usb2_temp_interface_desc *);
63185948Sthompsastatic void	usb2_make_config_desc(struct usb2_temp_setup *,
64185948Sthompsa		    const struct usb2_temp_config_desc *);
65185948Sthompsastatic void	usb2_make_device_desc(struct usb2_temp_setup *,
66185948Sthompsa		    const struct usb2_temp_device_desc *);
67185948Sthompsastatic uint8_t	usb2_hw_ep_match(const struct usb2_hw_ep_profile *, uint8_t,
68185948Sthompsa		    uint8_t);
69185948Sthompsastatic uint8_t	usb2_hw_ep_find_match(struct usb2_hw_ep_scratch *,
70185948Sthompsa		    struct usb2_hw_ep_scratch_sub *, uint8_t);
71185948Sthompsastatic uint8_t	usb2_hw_ep_get_needs(struct usb2_hw_ep_scratch *, uint8_t,
72185948Sthompsa		    uint8_t);
73185948Sthompsastatic usb2_error_t usb2_hw_ep_resolve(struct usb2_device *,
74185948Sthompsa		    struct usb2_descriptor *);
75185948Sthompsastatic const struct usb2_temp_device_desc *usb2_temp_get_tdd(struct usb2_device *);
76185948Sthompsastatic void	*usb2_temp_get_device_desc(struct usb2_device *);
77185948Sthompsastatic void	*usb2_temp_get_qualifier_desc(struct usb2_device *);
78185948Sthompsastatic void	*usb2_temp_get_config_desc(struct usb2_device *, uint16_t *,
79185948Sthompsa		    uint8_t);
80185948Sthompsastatic const void *usb2_temp_get_string_desc(struct usb2_device *, uint16_t,
81185948Sthompsa		    uint8_t);
82185948Sthompsastatic const void *usb2_temp_get_vendor_desc(struct usb2_device *,
83185948Sthompsa		    const struct usb2_device_request *);
84185948Sthompsastatic const void *usb2_temp_get_hub_desc(struct usb2_device *);
85185948Sthompsastatic void	usb2_temp_get_desc(struct usb2_device *,
86185948Sthompsa		    struct usb2_device_request *, const void **, uint16_t *);
87185948Sthompsastatic usb2_error_t usb2_temp_setup(struct usb2_device *,
88185948Sthompsa		    const struct usb2_temp_device_desc *);
89185948Sthompsastatic void	usb2_temp_unsetup(struct usb2_device *);
90185948Sthompsastatic usb2_error_t usb2_temp_setup_by_index(struct usb2_device *,
91185948Sthompsa		    uint16_t index);
92185948Sthompsastatic void	usb2_temp_init(void *);
93184610Salfred
94184610Salfred/*------------------------------------------------------------------------*
95184610Salfred *	usb2_make_raw_desc
96184610Salfred *
97184610Salfred * This function will insert a raw USB descriptor into the generated
98184610Salfred * USB configuration.
99184610Salfred *------------------------------------------------------------------------*/
100184610Salfredstatic void
101184610Salfredusb2_make_raw_desc(struct usb2_temp_setup *temp,
102184610Salfred    const uint8_t *raw)
103184610Salfred{
104184610Salfred	void *dst;
105184610Salfred	uint8_t len;
106184610Salfred
107184610Salfred	/*
108184610Salfred         * The first byte of any USB descriptor gives the length.
109184610Salfred         */
110184610Salfred	if (raw) {
111184610Salfred		len = raw[0];
112184610Salfred		if (temp->buf) {
113184610Salfred			dst = USB_ADD_BYTES(temp->buf, temp->size);
114184610Salfred			bcopy(raw, dst, len);
115184610Salfred
116184610Salfred			/* check if we have got a CDC union descriptor */
117184610Salfred
118184610Salfred			if ((raw[0] >= sizeof(struct usb2_cdc_union_descriptor)) &&
119184610Salfred			    (raw[1] == UDESC_CS_INTERFACE) &&
120184610Salfred			    (raw[2] == UDESCSUB_CDC_UNION)) {
121184610Salfred				struct usb2_cdc_union_descriptor *ud = (void *)dst;
122184610Salfred
123184610Salfred				/* update the interface numbers */
124184610Salfred
125184610Salfred				ud->bMasterInterface +=
126184610Salfred				    temp->bInterfaceNumber;
127184610Salfred				ud->bSlaveInterface[0] +=
128184610Salfred				    temp->bInterfaceNumber;
129184610Salfred			}
130184610Salfred		}
131184610Salfred		temp->size += len;
132184610Salfred	}
133184610Salfred}
134184610Salfred
135184610Salfred/*------------------------------------------------------------------------*
136184610Salfred *	usb2_make_endpoint_desc
137184610Salfred *
138184610Salfred * This function will generate an USB endpoint descriptor from the
139184610Salfred * given USB template endpoint descriptor, which will be inserted into
140184610Salfred * the USB configuration.
141184610Salfred *------------------------------------------------------------------------*/
142184610Salfredstatic void
143184610Salfredusb2_make_endpoint_desc(struct usb2_temp_setup *temp,
144184610Salfred    const struct usb2_temp_endpoint_desc *ted)
145184610Salfred{
146184610Salfred	struct usb2_endpoint_descriptor *ed;
147184610Salfred	const void **rd;
148184610Salfred	uint16_t old_size;
149184610Salfred	uint16_t mps;
150184610Salfred	uint8_t ea = 0;			/* Endpoint Address */
151184610Salfred	uint8_t et = 0;			/* Endpiont Type */
152184610Salfred
153184610Salfred	/* Reserve memory */
154184610Salfred	old_size = temp->size;
155184610Salfred	temp->size += sizeof(*ed);
156184610Salfred
157184610Salfred	/* Scan all Raw Descriptors first */
158184610Salfred
159184610Salfred	rd = ted->ppRawDesc;
160184610Salfred	if (rd) {
161184610Salfred		while (*rd) {
162184610Salfred			usb2_make_raw_desc(temp, *rd);
163184610Salfred			rd++;
164184610Salfred		}
165184610Salfred	}
166184610Salfred	if (ted->pPacketSize == NULL) {
167184610Salfred		/* not initialized */
168184610Salfred		temp->err = USB_ERR_INVAL;
169184610Salfred		return;
170184610Salfred	}
171184610Salfred	mps = ted->pPacketSize->mps[temp->usb2_speed];
172184610Salfred	if (mps == 0) {
173184610Salfred		/* not initialized */
174184610Salfred		temp->err = USB_ERR_INVAL;
175184610Salfred		return;
176184610Salfred	} else if (mps == UE_ZERO_MPS) {
177184610Salfred		/* escape for Zero Max Packet Size */
178184610Salfred		mps = 0;
179184610Salfred	}
180184610Salfred	ea = (ted->bEndpointAddress & (UE_ADDR | UE_DIR_IN | UE_DIR_OUT));
181184610Salfred	et = (ted->bmAttributes & UE_XFERTYPE);
182184610Salfred
183184610Salfred	/*
184184610Salfred	 * Fill out the real USB endpoint descriptor
185184610Salfred	 * in case there is a buffer present:
186184610Salfred	 */
187184610Salfred	if (temp->buf) {
188184610Salfred		ed = USB_ADD_BYTES(temp->buf, old_size);
189184610Salfred		ed->bLength = sizeof(*ed);
190184610Salfred		ed->bDescriptorType = UDESC_ENDPOINT;
191184610Salfred		ed->bEndpointAddress = ea;
192184610Salfred		ed->bmAttributes = ted->bmAttributes;
193184610Salfred		USETW(ed->wMaxPacketSize, mps);
194184610Salfred
195184610Salfred		/* setup bInterval parameter */
196184610Salfred
197184610Salfred		if (ted->pIntervals &&
198184610Salfred		    ted->pIntervals->bInterval[temp->usb2_speed]) {
199184610Salfred			ed->bInterval =
200184610Salfred			    ted->pIntervals->bInterval[temp->usb2_speed];
201184610Salfred		} else {
202184610Salfred			switch (et) {
203184610Salfred			case UE_BULK:
204184610Salfred			case UE_CONTROL:
205184610Salfred				ed->bInterval = 0;	/* not used */
206184610Salfred				break;
207184610Salfred			case UE_INTERRUPT:
208184610Salfred				switch (temp->usb2_speed) {
209184610Salfred				case USB_SPEED_LOW:
210184610Salfred				case USB_SPEED_FULL:
211184610Salfred					ed->bInterval = 1;	/* 1 ms */
212184610Salfred					break;
213184610Salfred				default:
214184610Salfred					ed->bInterval = 8;	/* 8*125 us */
215184610Salfred					break;
216184610Salfred				}
217184610Salfred				break;
218184610Salfred			default:	/* UE_ISOCHRONOUS */
219184610Salfred				switch (temp->usb2_speed) {
220184610Salfred				case USB_SPEED_LOW:
221184610Salfred				case USB_SPEED_FULL:
222184610Salfred					ed->bInterval = 1;	/* 1 ms */
223184610Salfred					break;
224184610Salfred				default:
225184610Salfred					ed->bInterval = 1;	/* 125 us */
226184610Salfred					break;
227184610Salfred				}
228184610Salfred				break;
229184610Salfred			}
230184610Salfred		}
231184610Salfred	}
232184610Salfred	temp->bNumEndpoints++;
233184610Salfred}
234184610Salfred
235184610Salfred/*------------------------------------------------------------------------*
236184610Salfred *	usb2_make_interface_desc
237184610Salfred *
238184610Salfred * This function will generate an USB interface descriptor from the
239184610Salfred * given USB template interface descriptor, which will be inserted
240184610Salfred * into the USB configuration.
241184610Salfred *------------------------------------------------------------------------*/
242184610Salfredstatic void
243184610Salfredusb2_make_interface_desc(struct usb2_temp_setup *temp,
244184610Salfred    const struct usb2_temp_interface_desc *tid)
245184610Salfred{
246184610Salfred	struct usb2_interface_descriptor *id;
247184610Salfred	const struct usb2_temp_endpoint_desc **ted;
248184610Salfred	const void **rd;
249184610Salfred	uint16_t old_size;
250184610Salfred
251184610Salfred	/* Reserve memory */
252184610Salfred
253184610Salfred	old_size = temp->size;
254184610Salfred	temp->size += sizeof(*id);
255184610Salfred
256184610Salfred	/* Update interface and alternate interface numbers */
257184610Salfred
258184610Salfred	if (tid->isAltInterface == 0) {
259184610Salfred		temp->bAlternateSetting = 0;
260184610Salfred		temp->bInterfaceNumber++;
261184610Salfred	} else {
262184610Salfred		temp->bAlternateSetting++;
263184610Salfred	}
264184610Salfred
265184610Salfred	/* Scan all Raw Descriptors first */
266184610Salfred
267184610Salfred	rd = tid->ppRawDesc;
268184610Salfred
269184610Salfred	if (rd) {
270184610Salfred		while (*rd) {
271184610Salfred			usb2_make_raw_desc(temp, *rd);
272184610Salfred			rd++;
273184610Salfred		}
274184610Salfred	}
275184610Salfred	/* Reset some counters */
276184610Salfred
277184610Salfred	temp->bNumEndpoints = 0;
278184610Salfred
279184610Salfred	/* Scan all Endpoint Descriptors second */
280184610Salfred
281184610Salfred	ted = tid->ppEndpoints;
282184610Salfred	if (ted) {
283184610Salfred		while (*ted) {
284184610Salfred			usb2_make_endpoint_desc(temp, *ted);
285184610Salfred			ted++;
286184610Salfred		}
287184610Salfred	}
288184610Salfred	/*
289184610Salfred	 * Fill out the real USB interface descriptor
290184610Salfred	 * in case there is a buffer present:
291184610Salfred	 */
292184610Salfred	if (temp->buf) {
293184610Salfred		id = USB_ADD_BYTES(temp->buf, old_size);
294184610Salfred		id->bLength = sizeof(*id);
295184610Salfred		id->bDescriptorType = UDESC_INTERFACE;
296184610Salfred		id->bInterfaceNumber = temp->bInterfaceNumber;
297184610Salfred		id->bAlternateSetting = temp->bAlternateSetting;
298184610Salfred		id->bNumEndpoints = temp->bNumEndpoints;
299184610Salfred		id->bInterfaceClass = tid->bInterfaceClass;
300184610Salfred		id->bInterfaceSubClass = tid->bInterfaceSubClass;
301184610Salfred		id->bInterfaceProtocol = tid->bInterfaceProtocol;
302184610Salfred		id->iInterface = tid->iInterface;
303184610Salfred	}
304184610Salfred}
305184610Salfred
306184610Salfred/*------------------------------------------------------------------------*
307184610Salfred *	usb2_make_config_desc
308184610Salfred *
309184610Salfred * This function will generate an USB config descriptor from the given
310184610Salfred * USB template config descriptor, which will be inserted into the USB
311184610Salfred * configuration.
312184610Salfred *------------------------------------------------------------------------*/
313184610Salfredstatic void
314184610Salfredusb2_make_config_desc(struct usb2_temp_setup *temp,
315184610Salfred    const struct usb2_temp_config_desc *tcd)
316184610Salfred{
317184610Salfred	struct usb2_config_descriptor *cd;
318184610Salfred	const struct usb2_temp_interface_desc **tid;
319184610Salfred	uint16_t old_size;
320184610Salfred
321184610Salfred	/* Reserve memory */
322184610Salfred
323184610Salfred	old_size = temp->size;
324184610Salfred	temp->size += sizeof(*cd);
325184610Salfred
326184610Salfred	/* Reset some counters */
327184610Salfred
328184610Salfred	temp->bInterfaceNumber = 0 - 1;
329184610Salfred	temp->bAlternateSetting = 0;
330184610Salfred
331184610Salfred	/* Scan all the USB interfaces */
332184610Salfred
333184610Salfred	tid = tcd->ppIfaceDesc;
334184610Salfred	if (tid) {
335184610Salfred		while (*tid) {
336184610Salfred			usb2_make_interface_desc(temp, *tid);
337184610Salfred			tid++;
338184610Salfred		}
339184610Salfred	}
340184610Salfred	/*
341184610Salfred	 * Fill out the real USB config descriptor
342184610Salfred	 * in case there is a buffer present:
343184610Salfred	 */
344184610Salfred	if (temp->buf) {
345184610Salfred		cd = USB_ADD_BYTES(temp->buf, old_size);
346184610Salfred
347184610Salfred		/* compute total size */
348184610Salfred		old_size = temp->size - old_size;
349184610Salfred
350184610Salfred		cd->bLength = sizeof(*cd);
351184610Salfred		cd->bDescriptorType = UDESC_CONFIG;
352184610Salfred		USETW(cd->wTotalLength, old_size);
353184610Salfred		cd->bNumInterface = temp->bInterfaceNumber + 1;
354184610Salfred		cd->bConfigurationValue = temp->bConfigurationValue;
355184610Salfred		cd->iConfiguration = tcd->iConfiguration;
356184610Salfred		cd->bmAttributes = tcd->bmAttributes;
357184610Salfred		cd->bMaxPower = tcd->bMaxPower;
358184610Salfred		cd->bmAttributes |= (UC_REMOTE_WAKEUP | UC_BUS_POWERED);
359184610Salfred
360184610Salfred		if (temp->self_powered) {
361184610Salfred			cd->bmAttributes |= UC_SELF_POWERED;
362184610Salfred		} else {
363184610Salfred			cd->bmAttributes &= ~UC_SELF_POWERED;
364184610Salfred		}
365184610Salfred	}
366184610Salfred}
367184610Salfred
368184610Salfred/*------------------------------------------------------------------------*
369184610Salfred *	usb2_make_device_desc
370184610Salfred *
371184610Salfred * This function will generate an USB device descriptor from the
372184610Salfred * given USB template device descriptor.
373184610Salfred *------------------------------------------------------------------------*/
374184610Salfredstatic void
375184610Salfredusb2_make_device_desc(struct usb2_temp_setup *temp,
376184610Salfred    const struct usb2_temp_device_desc *tdd)
377184610Salfred{
378184610Salfred	struct usb2_temp_data *utd;
379184610Salfred	const struct usb2_temp_config_desc **tcd;
380184610Salfred	uint16_t old_size;
381184610Salfred
382184610Salfred	/* Reserve memory */
383184610Salfred
384184610Salfred	old_size = temp->size;
385184610Salfred	temp->size += sizeof(*utd);
386184610Salfred
387184610Salfred	/* Scan all the USB configs */
388184610Salfred
389184610Salfred	temp->bConfigurationValue = 1;
390184610Salfred	tcd = tdd->ppConfigDesc;
391184610Salfred	if (tcd) {
392184610Salfred		while (*tcd) {
393184610Salfred			usb2_make_config_desc(temp, *tcd);
394184610Salfred			temp->bConfigurationValue++;
395184610Salfred			tcd++;
396184610Salfred		}
397184610Salfred	}
398184610Salfred	/*
399184610Salfred	 * Fill out the real USB device descriptor
400184610Salfred	 * in case there is a buffer present:
401184610Salfred	 */
402184610Salfred
403184610Salfred	if (temp->buf) {
404184610Salfred		utd = USB_ADD_BYTES(temp->buf, old_size);
405184610Salfred
406184610Salfred		/* Store a pointer to our template device descriptor */
407184610Salfred		utd->tdd = tdd;
408184610Salfred
409184610Salfred		/* Fill out USB device descriptor */
410184610Salfred		utd->udd.bLength = sizeof(utd->udd);
411184610Salfred		utd->udd.bDescriptorType = UDESC_DEVICE;
412184610Salfred		utd->udd.bDeviceClass = tdd->bDeviceClass;
413184610Salfred		utd->udd.bDeviceSubClass = tdd->bDeviceSubClass;
414184610Salfred		utd->udd.bDeviceProtocol = tdd->bDeviceProtocol;
415184610Salfred		USETW(utd->udd.idVendor, tdd->idVendor);
416184610Salfred		USETW(utd->udd.idProduct, tdd->idProduct);
417184610Salfred		USETW(utd->udd.bcdDevice, tdd->bcdDevice);
418184610Salfred		utd->udd.iManufacturer = tdd->iManufacturer;
419184610Salfred		utd->udd.iProduct = tdd->iProduct;
420184610Salfred		utd->udd.iSerialNumber = tdd->iSerialNumber;
421184610Salfred		utd->udd.bNumConfigurations = temp->bConfigurationValue - 1;
422184610Salfred
423184610Salfred		/*
424184610Salfred		 * Fill out the USB device qualifier. Pretend that we
425184610Salfred		 * don't support any other speeds by setting
426184610Salfred		 * "bNumConfigurations" equal to zero. That saves us
427184610Salfred		 * generating an extra set of configuration
428184610Salfred		 * descriptors.
429184610Salfred		 */
430184610Salfred		utd->udq.bLength = sizeof(utd->udq);
431184610Salfred		utd->udq.bDescriptorType = UDESC_DEVICE_QUALIFIER;
432184610Salfred		utd->udq.bDeviceClass = tdd->bDeviceClass;
433184610Salfred		utd->udq.bDeviceSubClass = tdd->bDeviceSubClass;
434184610Salfred		utd->udq.bDeviceProtocol = tdd->bDeviceProtocol;
435184610Salfred		utd->udq.bNumConfigurations = 0;
436184610Salfred		USETW(utd->udq.bcdUSB, 0x0200);
437184610Salfred		utd->udq.bMaxPacketSize0 = 0;
438184610Salfred
439184610Salfred		switch (temp->usb2_speed) {
440184610Salfred		case USB_SPEED_LOW:
441184610Salfred			USETW(utd->udd.bcdUSB, 0x0110);
442184610Salfred			utd->udd.bMaxPacketSize = 8;
443184610Salfred			break;
444184610Salfred		case USB_SPEED_FULL:
445184610Salfred			USETW(utd->udd.bcdUSB, 0x0110);
446184610Salfred			utd->udd.bMaxPacketSize = 32;
447184610Salfred			break;
448184610Salfred		case USB_SPEED_HIGH:
449184610Salfred			USETW(utd->udd.bcdUSB, 0x0200);
450184610Salfred			utd->udd.bMaxPacketSize = 64;
451184610Salfred			break;
452184610Salfred		case USB_SPEED_VARIABLE:
453184610Salfred			USETW(utd->udd.bcdUSB, 0x0250);
454184610Salfred			utd->udd.bMaxPacketSize = 255;	/* 512 bytes */
455184610Salfred			break;
456184610Salfred		default:
457184610Salfred			temp->err = USB_ERR_INVAL;
458184610Salfred			break;
459184610Salfred		}
460184610Salfred	}
461184610Salfred}
462184610Salfred
463184610Salfred/*------------------------------------------------------------------------*
464184610Salfred *	usb2_hw_ep_match
465184610Salfred *
466184610Salfred * Return values:
467184610Salfred *    0: The endpoint profile does not match the criterias
468184610Salfred * Else: The endpoint profile matches the criterias
469184610Salfred *------------------------------------------------------------------------*/
470184610Salfredstatic uint8_t
471184610Salfredusb2_hw_ep_match(const struct usb2_hw_ep_profile *pf,
472184610Salfred    uint8_t ep_type, uint8_t ep_dir_in)
473184610Salfred{
474184610Salfred	if (ep_type == UE_CONTROL) {
475184610Salfred		/* special */
476184610Salfred		return (pf->support_control);
477184610Salfred	}
478184610Salfred	if ((pf->support_in && ep_dir_in) ||
479184610Salfred	    (pf->support_out && !ep_dir_in)) {
480184610Salfred		if ((pf->support_interrupt && (ep_type == UE_INTERRUPT)) ||
481184610Salfred		    (pf->support_isochronous && (ep_type == UE_ISOCHRONOUS)) ||
482184610Salfred		    (pf->support_bulk && (ep_type == UE_BULK))) {
483184610Salfred			return (1);
484184610Salfred		}
485184610Salfred	}
486184610Salfred	return (0);
487184610Salfred}
488184610Salfred
489184610Salfred/*------------------------------------------------------------------------*
490184610Salfred *	usb2_hw_ep_find_match
491184610Salfred *
492184610Salfred * This function is used to find the best matching endpoint profile
493184610Salfred * for and endpoint belonging to an USB descriptor.
494184610Salfred *
495184610Salfred * Return values:
496184610Salfred *    0: Success. Got a match.
497184610Salfred * Else: Failure. No match.
498184610Salfred *------------------------------------------------------------------------*/
499184610Salfredstatic uint8_t
500184610Salfredusb2_hw_ep_find_match(struct usb2_hw_ep_scratch *ues,
501184610Salfred    struct usb2_hw_ep_scratch_sub *ep, uint8_t is_simplex)
502184610Salfred{
503184610Salfred	const struct usb2_hw_ep_profile *pf;
504184610Salfred	uint16_t distance;
505184610Salfred	uint16_t temp;
506184610Salfred	uint16_t max_frame_size;
507184610Salfred	uint8_t n;
508184610Salfred	uint8_t best_n;
509184610Salfred	uint8_t dir_in;
510184610Salfred	uint8_t dir_out;
511184610Salfred
512184610Salfred	distance = 0xFFFF;
513184610Salfred	best_n = 0;
514184610Salfred
515184610Salfred	if ((!ep->needs_in) && (!ep->needs_out)) {
516184610Salfred		return (0);		/* we are done */
517184610Salfred	}
518184610Salfred	if (ep->needs_ep_type == UE_CONTROL) {
519184610Salfred		dir_in = 1;
520184610Salfred		dir_out = 1;
521184610Salfred	} else {
522184610Salfred		if (ep->needs_in) {
523184610Salfred			dir_in = 1;
524184610Salfred			dir_out = 0;
525184610Salfred		} else {
526184610Salfred			dir_in = 0;
527184610Salfred			dir_out = 1;
528184610Salfred		}
529184610Salfred	}
530184610Salfred
531184610Salfred	for (n = 1; n != (USB_EP_MAX / 2); n++) {
532184610Salfred
533184610Salfred		/* get HW endpoint profile */
534184610Salfred		(ues->methods->get_hw_ep_profile) (ues->udev, &pf, n);
535184610Salfred		if (pf == NULL) {
536184610Salfred			/* end of profiles */
537184610Salfred			break;
538184610Salfred		}
539184610Salfred		/* check if IN-endpoint is reserved */
540184610Salfred		if (dir_in || pf->is_simplex) {
541184610Salfred			if (ues->bmInAlloc[n / 8] & (1 << (n % 8))) {
542184610Salfred				/* mismatch */
543184610Salfred				continue;
544184610Salfred			}
545184610Salfred		}
546184610Salfred		/* check if OUT-endpoint is reserved */
547184610Salfred		if (dir_out || pf->is_simplex) {
548184610Salfred			if (ues->bmOutAlloc[n / 8] & (1 << (n % 8))) {
549184610Salfred				/* mismatch */
550184610Salfred				continue;
551184610Salfred			}
552184610Salfred		}
553184610Salfred		/* check simplex */
554184610Salfred		if (pf->is_simplex == is_simplex) {
555184610Salfred			/* mismatch */
556184610Salfred			continue;
557184610Salfred		}
558184610Salfred		/* check if HW endpoint matches */
559184610Salfred		if (!usb2_hw_ep_match(pf, ep->needs_ep_type, dir_in)) {
560184610Salfred			/* mismatch */
561184610Salfred			continue;
562184610Salfred		}
563184610Salfred		/* get maximum frame size */
564184610Salfred		if (dir_in)
565184610Salfred			max_frame_size = pf->max_in_frame_size;
566184610Salfred		else
567184610Salfred			max_frame_size = pf->max_out_frame_size;
568184610Salfred
569184610Salfred		/* check if we have a matching profile */
570184610Salfred		if (max_frame_size >= ep->max_frame_size) {
571184610Salfred			temp = (max_frame_size - ep->max_frame_size);
572184610Salfred			if (distance > temp) {
573184610Salfred				distance = temp;
574184610Salfred				best_n = n;
575184610Salfred				ep->pf = pf;
576184610Salfred			}
577184610Salfred		}
578184610Salfred	}
579184610Salfred
580184610Salfred	/* see if we got a match */
581184610Salfred	if (best_n != 0) {
582184610Salfred		/* get the correct profile */
583184610Salfred		pf = ep->pf;
584184610Salfred
585184610Salfred		/* reserve IN-endpoint */
586184610Salfred		if (dir_in) {
587184610Salfred			ues->bmInAlloc[best_n / 8] |=
588184610Salfred			    (1 << (best_n % 8));
589184610Salfred			ep->hw_endpoint_in = best_n | UE_DIR_IN;
590184610Salfred			ep->needs_in = 0;
591184610Salfred		}
592184610Salfred		/* reserve OUT-endpoint */
593184610Salfred		if (dir_out) {
594184610Salfred			ues->bmOutAlloc[best_n / 8] |=
595184610Salfred			    (1 << (best_n % 8));
596184610Salfred			ep->hw_endpoint_out = best_n | UE_DIR_OUT;
597184610Salfred			ep->needs_out = 0;
598184610Salfred		}
599184610Salfred		return (0);		/* got a match */
600184610Salfred	}
601184610Salfred	return (1);			/* failure */
602184610Salfred}
603184610Salfred
604184610Salfred/*------------------------------------------------------------------------*
605184610Salfred *	usb2_hw_ep_get_needs
606184610Salfred *
607184610Salfred * This function will figure out the type and number of endpoints
608184610Salfred * which are needed for an USB configuration.
609184610Salfred *
610184610Salfred * Return values:
611184610Salfred *    0: Success.
612184610Salfred * Else: Failure.
613184610Salfred *------------------------------------------------------------------------*/
614184610Salfredstatic uint8_t
615184610Salfredusb2_hw_ep_get_needs(struct usb2_hw_ep_scratch *ues,
616184610Salfred    uint8_t ep_type, uint8_t is_complete)
617184610Salfred{
618184610Salfred	const struct usb2_hw_ep_profile *pf;
619184610Salfred	struct usb2_hw_ep_scratch_sub *ep_iface;
620184610Salfred	struct usb2_hw_ep_scratch_sub *ep_curr;
621184610Salfred	struct usb2_hw_ep_scratch_sub *ep_max;
622184610Salfred	struct usb2_hw_ep_scratch_sub *ep_end;
623184610Salfred	struct usb2_descriptor *desc;
624184610Salfred	struct usb2_interface_descriptor *id;
625184610Salfred	struct usb2_endpoint_descriptor *ed;
626184610Salfred	uint16_t wMaxPacketSize;
627184610Salfred	uint16_t temp;
628184610Salfred	uint8_t speed;
629184610Salfred	uint8_t ep_no;
630184610Salfred
631184610Salfred	ep_iface = ues->ep_max;
632184610Salfred	ep_curr = ues->ep_max;
633184610Salfred	ep_end = ues->ep + USB_EP_MAX;
634184610Salfred	ep_max = ues->ep_max;
635184610Salfred	desc = NULL;
636184610Salfred	speed = usb2_get_speed(ues->udev);
637184610Salfred
638184610Salfredrepeat:
639184610Salfred
640184610Salfred	while ((desc = usb2_desc_foreach(ues->cd, desc))) {
641184610Salfred
642184610Salfred		if ((desc->bDescriptorType == UDESC_INTERFACE) &&
643184610Salfred		    (desc->bLength >= sizeof(*id))) {
644184610Salfred
645184610Salfred			id = (void *)desc;
646184610Salfred
647184610Salfred			if (id->bAlternateSetting == 0) {
648184610Salfred				/* going forward */
649184610Salfred				ep_iface = ep_max;
650184610Salfred			} else {
651184610Salfred				/* reset */
652184610Salfred				ep_curr = ep_iface;
653184610Salfred			}
654184610Salfred		}
655184610Salfred		if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
656184610Salfred		    (desc->bLength >= sizeof(*ed))) {
657184610Salfred
658184610Salfred			ed = (void *)desc;
659184610Salfred
660184610Salfred			goto handle_endpoint_desc;
661184610Salfred		}
662184610Salfred	}
663184610Salfred	ues->ep_max = ep_max;
664184610Salfred	return (0);
665184610Salfred
666184610Salfredhandle_endpoint_desc:
667184610Salfred	temp = (ed->bmAttributes & UE_XFERTYPE);
668184610Salfred
669184610Salfred	if (temp == ep_type) {
670184610Salfred
671184610Salfred		if (ep_curr == ep_end) {
672184610Salfred			/* too many endpoints */
673184610Salfred			return (1);	/* failure */
674184610Salfred		}
675184610Salfred		wMaxPacketSize = UGETW(ed->wMaxPacketSize);
676184610Salfred		if ((wMaxPacketSize & 0xF800) &&
677184610Salfred		    (speed == USB_SPEED_HIGH)) {
678184610Salfred			/* handle packet multiplier */
679184610Salfred			temp = (wMaxPacketSize >> 11) & 3;
680184610Salfred			wMaxPacketSize &= 0x7FF;
681184610Salfred			if (temp == 1) {
682184610Salfred				wMaxPacketSize *= 2;
683184610Salfred			} else {
684184610Salfred				wMaxPacketSize *= 3;
685184610Salfred			}
686184610Salfred		}
687184610Salfred		/*
688184610Salfred		 * Check if we have a fixed endpoint number, else the
689184610Salfred		 * endpoint number is allocated dynamically:
690184610Salfred		 */
691184610Salfred		ep_no = (ed->bEndpointAddress & UE_ADDR);
692184610Salfred		if (ep_no != 0) {
693184610Salfred
694184610Salfred			/* get HW endpoint profile */
695184610Salfred			(ues->methods->get_hw_ep_profile)
696184610Salfred			    (ues->udev, &pf, ep_no);
697184610Salfred			if (pf == NULL) {
698184610Salfred				/* HW profile does not exist - failure */
699184610Salfred				DPRINTFN(0, "Endpoint profile %u "
700184610Salfred				    "does not exist\n", ep_no);
701184610Salfred				return (1);
702184610Salfred			}
703184610Salfred			/* reserve fixed endpoint number */
704184610Salfred			if (ep_type == UE_CONTROL) {
705184610Salfred				ues->bmInAlloc[ep_no / 8] |=
706184610Salfred				    (1 << (ep_no % 8));
707184610Salfred				ues->bmOutAlloc[ep_no / 8] |=
708184610Salfred				    (1 << (ep_no % 8));
709184610Salfred				if ((pf->max_in_frame_size < wMaxPacketSize) ||
710184610Salfred				    (pf->max_out_frame_size < wMaxPacketSize)) {
711184610Salfred					DPRINTFN(0, "Endpoint profile %u "
712184610Salfred					    "has too small buffer!\n", ep_no);
713184610Salfred					return (1);
714184610Salfred				}
715184610Salfred			} else if (ed->bEndpointAddress & UE_DIR_IN) {
716184610Salfred				ues->bmInAlloc[ep_no / 8] |=
717184610Salfred				    (1 << (ep_no % 8));
718184610Salfred				if (pf->max_in_frame_size < wMaxPacketSize) {
719184610Salfred					DPRINTFN(0, "Endpoint profile %u "
720184610Salfred					    "has too small buffer!\n", ep_no);
721184610Salfred					return (1);
722184610Salfred				}
723184610Salfred			} else {
724184610Salfred				ues->bmOutAlloc[ep_no / 8] |=
725184610Salfred				    (1 << (ep_no % 8));
726184610Salfred				if (pf->max_out_frame_size < wMaxPacketSize) {
727184610Salfred					DPRINTFN(0, "Endpoint profile %u "
728184610Salfred					    "has too small buffer!\n", ep_no);
729184610Salfred					return (1);
730184610Salfred				}
731184610Salfred			}
732184610Salfred		} else if (is_complete) {
733184610Salfred
734184610Salfred			/* check if we have enough buffer space */
735184610Salfred			if (wMaxPacketSize >
736184610Salfred			    ep_curr->max_frame_size) {
737184610Salfred				return (1);	/* failure */
738184610Salfred			}
739184610Salfred			if (ed->bEndpointAddress & UE_DIR_IN) {
740184610Salfred				ed->bEndpointAddress =
741184610Salfred				    ep_curr->hw_endpoint_in;
742184610Salfred			} else {
743184610Salfred				ed->bEndpointAddress =
744184610Salfred				    ep_curr->hw_endpoint_out;
745184610Salfred			}
746184610Salfred
747184610Salfred		} else {
748184610Salfred
749184610Salfred			/* compute the maximum frame size */
750184610Salfred			if (ep_curr->max_frame_size < wMaxPacketSize) {
751184610Salfred				ep_curr->max_frame_size = wMaxPacketSize;
752184610Salfred			}
753184610Salfred			if (temp == UE_CONTROL) {
754184610Salfred				ep_curr->needs_in = 1;
755184610Salfred				ep_curr->needs_out = 1;
756184610Salfred			} else {
757184610Salfred				if (ed->bEndpointAddress & UE_DIR_IN) {
758184610Salfred					ep_curr->needs_in = 1;
759184610Salfred				} else {
760184610Salfred					ep_curr->needs_out = 1;
761184610Salfred				}
762184610Salfred			}
763184610Salfred			ep_curr->needs_ep_type = ep_type;
764184610Salfred		}
765184610Salfred
766184610Salfred		ep_curr++;
767184610Salfred		if (ep_max < ep_curr) {
768184610Salfred			ep_max = ep_curr;
769184610Salfred		}
770184610Salfred	}
771184610Salfred	goto repeat;
772184610Salfred}
773184610Salfred
774184610Salfred/*------------------------------------------------------------------------*
775184610Salfred *	usb2_hw_ep_resolve
776184610Salfred *
777184610Salfred * This function will try to resolve endpoint requirements by the
778184610Salfred * given endpoint profiles that the USB hardware reports.
779184610Salfred *
780184610Salfred * Return values:
781184610Salfred *    0: Success
782184610Salfred * Else: Failure
783184610Salfred *------------------------------------------------------------------------*/
784184610Salfredstatic usb2_error_t
785184610Salfredusb2_hw_ep_resolve(struct usb2_device *udev,
786184610Salfred    struct usb2_descriptor *desc)
787184610Salfred{
788184610Salfred	struct usb2_hw_ep_scratch *ues;
789184610Salfred	struct usb2_hw_ep_scratch_sub *ep;
790184610Salfred	const struct usb2_hw_ep_profile *pf;
791184610Salfred	struct usb2_bus_methods *methods;
792184610Salfred	struct usb2_device_descriptor *dd;
793184610Salfred	uint16_t mps;
794184610Salfred
795184610Salfred	if (desc == NULL) {
796184610Salfred		return (USB_ERR_INVAL);
797184610Salfred	}
798184610Salfred	/* get bus methods */
799184610Salfred	methods = udev->bus->methods;
800184610Salfred
801184610Salfred	if (methods->get_hw_ep_profile == NULL) {
802184610Salfred		return (USB_ERR_INVAL);
803184610Salfred	}
804184610Salfred	if (desc->bDescriptorType == UDESC_DEVICE) {
805184610Salfred
806184610Salfred		if (desc->bLength < sizeof(*dd)) {
807184610Salfred			return (USB_ERR_INVAL);
808184610Salfred		}
809184610Salfred		dd = (void *)desc;
810184610Salfred
811184610Salfred		/* get HW control endpoint 0 profile */
812184610Salfred		(methods->get_hw_ep_profile) (udev, &pf, 0);
813184610Salfred		if (pf == NULL) {
814184610Salfred			return (USB_ERR_INVAL);
815184610Salfred		}
816184610Salfred		if (!usb2_hw_ep_match(pf, UE_CONTROL, 0)) {
817184610Salfred			DPRINTFN(0, "Endpoint 0 does not "
818184610Salfred			    "support control\n");
819184610Salfred			return (USB_ERR_INVAL);
820184610Salfred		}
821184610Salfred		mps = dd->bMaxPacketSize;
822184610Salfred
823184610Salfred		if (udev->speed == USB_SPEED_FULL) {
824184610Salfred			/*
825184610Salfred			 * We can optionally choose another packet size !
826184610Salfred			 */
827184610Salfred			while (1) {
828184610Salfred				/* check if "mps" is ok */
829184610Salfred				if (pf->max_in_frame_size >= mps) {
830184610Salfred					break;
831184610Salfred				}
832184610Salfred				/* reduce maximum packet size */
833184610Salfred				mps /= 2;
834184610Salfred
835184610Salfred				/* check if "mps" is too small */
836184610Salfred				if (mps < 8) {
837184610Salfred					return (USB_ERR_INVAL);
838184610Salfred				}
839184610Salfred			}
840184610Salfred
841184610Salfred			dd->bMaxPacketSize = mps;
842184610Salfred
843184610Salfred		} else {
844184610Salfred			/* We only have one choice */
845184610Salfred			if (mps == 255) {
846184610Salfred				mps = 512;
847184610Salfred			}
848184610Salfred			/* Check if we support the specified wMaxPacketSize */
849184610Salfred			if (pf->max_in_frame_size < mps) {
850184610Salfred				return (USB_ERR_INVAL);
851184610Salfred			}
852184610Salfred		}
853184610Salfred		return (0);		/* success */
854184610Salfred	}
855184610Salfred	if (desc->bDescriptorType != UDESC_CONFIG) {
856184610Salfred		return (USB_ERR_INVAL);
857184610Salfred	}
858184610Salfred	if (desc->bLength < sizeof(*(ues->cd))) {
859184610Salfred		return (USB_ERR_INVAL);
860184610Salfred	}
861184610Salfred	ues = udev->bus->scratch[0].hw_ep_scratch;
862184610Salfred
863184610Salfred	bzero(ues, sizeof(*ues));
864184610Salfred
865184610Salfred	ues->ep_max = ues->ep;
866184610Salfred	ues->cd = (void *)desc;
867184610Salfred	ues->methods = methods;
868184610Salfred	ues->udev = udev;
869184610Salfred
870184610Salfred	/* Get all the endpoints we need */
871184610Salfred
872184610Salfred	if (usb2_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 0) ||
873184610Salfred	    usb2_hw_ep_get_needs(ues, UE_INTERRUPT, 0) ||
874184610Salfred	    usb2_hw_ep_get_needs(ues, UE_CONTROL, 0) ||
875184610Salfred	    usb2_hw_ep_get_needs(ues, UE_BULK, 0)) {
876184610Salfred		DPRINTFN(0, "Could not get needs\n");
877184610Salfred		return (USB_ERR_INVAL);
878184610Salfred	}
879184610Salfred	for (ep = ues->ep; ep != ues->ep_max; ep++) {
880184610Salfred
881184610Salfred		while (ep->needs_in || ep->needs_out) {
882184610Salfred
883184610Salfred			/*
884184610Salfred		         * First try to use a simplex endpoint.
885184610Salfred		         * Then try to use a duplex endpoint.
886184610Salfred		         */
887184610Salfred			if (usb2_hw_ep_find_match(ues, ep, 1) &&
888184610Salfred			    usb2_hw_ep_find_match(ues, ep, 0)) {
889184610Salfred				DPRINTFN(0, "Could not find match\n");
890184610Salfred				return (USB_ERR_INVAL);
891184610Salfred			}
892184610Salfred		}
893184610Salfred	}
894184610Salfred
895184610Salfred	ues->ep_max = ues->ep;
896184610Salfred
897184610Salfred	/* Update all endpoint addresses */
898184610Salfred
899184610Salfred	if (usb2_hw_ep_get_needs(ues, UE_ISOCHRONOUS, 1) ||
900184610Salfred	    usb2_hw_ep_get_needs(ues, UE_INTERRUPT, 1) ||
901184610Salfred	    usb2_hw_ep_get_needs(ues, UE_CONTROL, 1) ||
902184610Salfred	    usb2_hw_ep_get_needs(ues, UE_BULK, 1)) {
903184610Salfred		DPRINTFN(0, "Could not update endpoint address\n");
904184610Salfred		return (USB_ERR_INVAL);
905184610Salfred	}
906184610Salfred	return (0);			/* success */
907184610Salfred}
908184610Salfred
909184610Salfred/*------------------------------------------------------------------------*
910184610Salfred *	usb2_temp_get_tdd
911184610Salfred *
912184610Salfred * Returns:
913184610Salfred *  NULL: No USB template device descriptor found.
914184610Salfred *  Else: Pointer to the USB template device descriptor.
915184610Salfred *------------------------------------------------------------------------*/
916184610Salfredstatic const struct usb2_temp_device_desc *
917184610Salfredusb2_temp_get_tdd(struct usb2_device *udev)
918184610Salfred{
919184610Salfred	if (udev->usb2_template_ptr == NULL) {
920184610Salfred		return (NULL);
921184610Salfred	}
922184610Salfred	return (udev->usb2_template_ptr->tdd);
923184610Salfred}
924184610Salfred
925184610Salfred/*------------------------------------------------------------------------*
926184610Salfred *	usb2_temp_get_device_desc
927184610Salfred *
928184610Salfred * Returns:
929184610Salfred *  NULL: No USB device descriptor found.
930184610Salfred *  Else: Pointer to USB device descriptor.
931184610Salfred *------------------------------------------------------------------------*/
932184610Salfredstatic void *
933184610Salfredusb2_temp_get_device_desc(struct usb2_device *udev)
934184610Salfred{
935184610Salfred	struct usb2_device_descriptor *dd;
936184610Salfred
937184610Salfred	if (udev->usb2_template_ptr == NULL) {
938184610Salfred		return (NULL);
939184610Salfred	}
940184610Salfred	dd = &udev->usb2_template_ptr->udd;
941184610Salfred	if (dd->bDescriptorType != UDESC_DEVICE) {
942184610Salfred		/* sanity check failed */
943184610Salfred		return (NULL);
944184610Salfred	}
945184610Salfred	return (dd);
946184610Salfred}
947184610Salfred
948184610Salfred/*------------------------------------------------------------------------*
949184610Salfred *	usb2_temp_get_qualifier_desc
950184610Salfred *
951184610Salfred * Returns:
952184610Salfred *  NULL: No USB device_qualifier descriptor found.
953184610Salfred *  Else: Pointer to USB device_qualifier descriptor.
954184610Salfred *------------------------------------------------------------------------*/
955184610Salfredstatic void *
956184610Salfredusb2_temp_get_qualifier_desc(struct usb2_device *udev)
957184610Salfred{
958184610Salfred	struct usb2_device_qualifier *dq;
959184610Salfred
960184610Salfred	if (udev->usb2_template_ptr == NULL) {
961184610Salfred		return (NULL);
962184610Salfred	}
963184610Salfred	dq = &udev->usb2_template_ptr->udq;
964184610Salfred	if (dq->bDescriptorType != UDESC_DEVICE_QUALIFIER) {
965184610Salfred		/* sanity check failed */
966184610Salfred		return (NULL);
967184610Salfred	}
968184610Salfred	return (dq);
969184610Salfred}
970184610Salfred
971184610Salfred/*------------------------------------------------------------------------*
972184610Salfred *	usb2_temp_get_config_desc
973184610Salfred *
974184610Salfred * Returns:
975184610Salfred *  NULL: No USB config descriptor found.
976184610Salfred *  Else: Pointer to USB config descriptor having index "index".
977184610Salfred *------------------------------------------------------------------------*/
978184610Salfredstatic void *
979184610Salfredusb2_temp_get_config_desc(struct usb2_device *udev,
980184610Salfred    uint16_t *pLength, uint8_t index)
981184610Salfred{
982184610Salfred	struct usb2_device_descriptor *dd;
983184610Salfred	struct usb2_config_descriptor *cd;
984184610Salfred	uint16_t temp;
985184610Salfred
986184610Salfred	if (udev->usb2_template_ptr == NULL) {
987184610Salfred		return (NULL);
988184610Salfred	}
989184610Salfred	dd = &udev->usb2_template_ptr->udd;
990184610Salfred	cd = (void *)(udev->usb2_template_ptr + 1);
991184610Salfred
992184610Salfred	if (index >= dd->bNumConfigurations) {
993184610Salfred		/* out of range */
994184610Salfred		return (NULL);
995184610Salfred	}
996184610Salfred	while (index--) {
997184610Salfred		if (cd->bDescriptorType != UDESC_CONFIG) {
998184610Salfred			/* sanity check failed */
999184610Salfred			return (NULL);
1000184610Salfred		}
1001184610Salfred		temp = UGETW(cd->wTotalLength);
1002184610Salfred		cd = USB_ADD_BYTES(cd, temp);
1003184610Salfred	}
1004184610Salfred
1005184610Salfred	if (pLength) {
1006184610Salfred		*pLength = UGETW(cd->wTotalLength);
1007184610Salfred	}
1008184610Salfred	return (cd);
1009184610Salfred}
1010184610Salfred
1011184610Salfred/*------------------------------------------------------------------------*
1012184610Salfred *	usb2_temp_get_vendor_desc
1013184610Salfred *
1014184610Salfred * Returns:
1015184610Salfred *  NULL: No vendor descriptor found.
1016184610Salfred *  Else: Pointer to a vendor descriptor.
1017184610Salfred *------------------------------------------------------------------------*/
1018184610Salfredstatic const void *
1019184610Salfredusb2_temp_get_vendor_desc(struct usb2_device *udev,
1020184610Salfred    const struct usb2_device_request *req)
1021184610Salfred{
1022184610Salfred	const struct usb2_temp_device_desc *tdd;
1023184610Salfred
1024184610Salfred	tdd = usb2_temp_get_tdd(udev);
1025184610Salfred	if (tdd == NULL) {
1026184610Salfred		return (NULL);
1027184610Salfred	}
1028184610Salfred	if (tdd->getVendorDesc == NULL) {
1029184610Salfred		return (NULL);
1030184610Salfred	}
1031184610Salfred	return ((tdd->getVendorDesc) (req));
1032184610Salfred}
1033184610Salfred
1034184610Salfred/*------------------------------------------------------------------------*
1035184610Salfred *	usb2_temp_get_string_desc
1036184610Salfred *
1037184610Salfred * Returns:
1038184610Salfred *  NULL: No string descriptor found.
1039184610Salfred *  Else: Pointer to a string descriptor.
1040184610Salfred *------------------------------------------------------------------------*/
1041184610Salfredstatic const void *
1042184610Salfredusb2_temp_get_string_desc(struct usb2_device *udev,
1043184610Salfred    uint16_t lang_id, uint8_t string_index)
1044184610Salfred{
1045184610Salfred	const struct usb2_temp_device_desc *tdd;
1046184610Salfred
1047184610Salfred	tdd = usb2_temp_get_tdd(udev);
1048184610Salfred	if (tdd == NULL) {
1049184610Salfred		return (NULL);
1050184610Salfred	}
1051184610Salfred	if (tdd->getStringDesc == NULL) {
1052184610Salfred		return (NULL);
1053184610Salfred	}
1054184610Salfred	return ((tdd->getStringDesc) (lang_id, string_index));
1055184610Salfred}
1056184610Salfred
1057184610Salfred/*------------------------------------------------------------------------*
1058184610Salfred *	usb2_temp_get_hub_desc
1059184610Salfred *
1060184610Salfred * Returns:
1061184610Salfred *  NULL: No USB HUB descriptor found.
1062184610Salfred *  Else: Pointer to a USB HUB descriptor.
1063184610Salfred *------------------------------------------------------------------------*/
1064184610Salfredstatic const void *
1065184610Salfredusb2_temp_get_hub_desc(struct usb2_device *udev)
1066184610Salfred{
1067184610Salfred	return (NULL);			/* needs to be implemented */
1068184610Salfred}
1069184610Salfred
1070184610Salfred/*------------------------------------------------------------------------*
1071184610Salfred *	usb2_temp_get_desc
1072184610Salfred *
1073184610Salfred * This function is a demultiplexer for local USB device side control
1074184610Salfred * endpoint requests.
1075184610Salfred *------------------------------------------------------------------------*/
1076184610Salfredstatic void
1077184610Salfredusb2_temp_get_desc(struct usb2_device *udev, struct usb2_device_request *req,
1078184610Salfred    const void **pPtr, uint16_t *pLength)
1079184610Salfred{
1080184610Salfred	const uint8_t *buf;
1081184610Salfred	uint16_t len;
1082184610Salfred
1083184610Salfred	buf = NULL;
1084184610Salfred	len = 0;
1085184610Salfred
1086184610Salfred	switch (req->bmRequestType) {
1087184610Salfred	case UT_READ_DEVICE:
1088184610Salfred		switch (req->bRequest) {
1089184610Salfred		case UR_GET_DESCRIPTOR:
1090184610Salfred			goto tr_handle_get_descriptor;
1091184610Salfred		default:
1092184610Salfred			goto tr_stalled;
1093184610Salfred		}
1094184610Salfred		break;
1095184610Salfred	case UT_READ_CLASS_DEVICE:
1096184610Salfred		switch (req->bRequest) {
1097184610Salfred		case UR_GET_DESCRIPTOR:
1098184610Salfred			goto tr_handle_get_class_descriptor;
1099184610Salfred		default:
1100184610Salfred			goto tr_stalled;
1101184610Salfred		}
1102184610Salfred		break;
1103184610Salfred	case UT_READ_VENDOR_DEVICE:
1104184610Salfred	case UT_READ_VENDOR_OTHER:
1105184610Salfred		buf = usb2_temp_get_vendor_desc(udev, req);
1106184610Salfred		goto tr_valid;
1107184610Salfred	default:
1108184610Salfred		goto tr_stalled;
1109184610Salfred	}
1110184610Salfred
1111184610Salfredtr_handle_get_descriptor:
1112184610Salfred	switch (req->wValue[1]) {
1113184610Salfred	case UDESC_DEVICE:
1114184610Salfred		if (req->wValue[0]) {
1115184610Salfred			goto tr_stalled;
1116184610Salfred		}
1117184610Salfred		buf = usb2_temp_get_device_desc(udev);
1118184610Salfred		goto tr_valid;
1119184610Salfred	case UDESC_DEVICE_QUALIFIER:
1120184610Salfred		if (udev->speed != USB_SPEED_HIGH) {
1121184610Salfred			goto tr_stalled;
1122184610Salfred		}
1123184610Salfred		if (req->wValue[0]) {
1124184610Salfred			goto tr_stalled;
1125184610Salfred		}
1126184610Salfred		buf = usb2_temp_get_qualifier_desc(udev);
1127184610Salfred		goto tr_valid;
1128184610Salfred	case UDESC_OTHER_SPEED_CONFIGURATION:
1129184610Salfred		if (udev->speed != USB_SPEED_HIGH) {
1130184610Salfred			goto tr_stalled;
1131184610Salfred		}
1132184610Salfred	case UDESC_CONFIG:
1133184610Salfred		buf = usb2_temp_get_config_desc(udev,
1134184610Salfred		    &len, req->wValue[0]);
1135184610Salfred		goto tr_valid;
1136184610Salfred	case UDESC_STRING:
1137184610Salfred		buf = usb2_temp_get_string_desc(udev,
1138184610Salfred		    UGETW(req->wIndex), req->wValue[0]);
1139184610Salfred		goto tr_valid;
1140184610Salfred	default:
1141184610Salfred		goto tr_stalled;
1142184610Salfred	}
1143184610Salfred	goto tr_stalled;
1144184610Salfred
1145184610Salfredtr_handle_get_class_descriptor:
1146184610Salfred	if (req->wValue[0]) {
1147184610Salfred		goto tr_stalled;
1148184610Salfred	}
1149184610Salfred	buf = usb2_temp_get_hub_desc(udev);
1150184610Salfred	goto tr_valid;
1151184610Salfred
1152184610Salfredtr_valid:
1153184610Salfred	if (buf == NULL) {
1154184610Salfred		goto tr_stalled;
1155184610Salfred	}
1156184610Salfred	if (len == 0) {
1157184610Salfred		len = buf[0];
1158184610Salfred	}
1159184610Salfred	*pPtr = buf;
1160184610Salfred	*pLength = len;
1161184610Salfred	return;
1162184610Salfred
1163184610Salfredtr_stalled:
1164184610Salfred	*pPtr = NULL;
1165184610Salfred	*pLength = 0;
1166184610Salfred}
1167184610Salfred
1168184610Salfred/*------------------------------------------------------------------------*
1169184610Salfred *	usb2_temp_setup
1170184610Salfred *
1171184610Salfred * This function generates USB descriptors according to the given USB
1172184610Salfred * template device descriptor. It will also try to figure out the best
1173184610Salfred * matching endpoint addresses using the hardware endpoint profiles.
1174184610Salfred *
1175184610Salfred * Returns:
1176184610Salfred *    0: Success
1177184610Salfred * Else: Failure
1178184610Salfred *------------------------------------------------------------------------*/
1179184610Salfredstatic usb2_error_t
1180184610Salfredusb2_temp_setup(struct usb2_device *udev,
1181184610Salfred    const struct usb2_temp_device_desc *tdd)
1182184610Salfred{
1183184610Salfred	struct usb2_temp_setup *uts;
1184184610Salfred	void *buf;
1185184610Salfred	uint8_t n;
1186184610Salfred
1187184610Salfred	if (tdd == NULL) {
1188184610Salfred		/* be NULL safe */
1189184610Salfred		return (0);
1190184610Salfred	}
1191184610Salfred	uts = udev->bus->scratch[0].temp_setup;
1192184610Salfred
1193184610Salfred	bzero(uts, sizeof(*uts));
1194184610Salfred
1195184610Salfred	uts->usb2_speed = udev->speed;
1196184610Salfred	uts->self_powered = udev->flags.self_powered;
1197184610Salfred
1198184610Salfred	/* first pass */
1199184610Salfred
1200184610Salfred	usb2_make_device_desc(uts, tdd);
1201184610Salfred
1202184610Salfred	if (uts->err) {
1203184610Salfred		/* some error happened */
1204184610Salfred		return (uts->err);
1205184610Salfred	}
1206184610Salfred	/* sanity check */
1207184610Salfred	if (uts->size == 0) {
1208184610Salfred		return (USB_ERR_INVAL);
1209184610Salfred	}
1210184610Salfred	/* allocate zeroed memory */
1211184610Salfred	uts->buf = malloc(uts->size, M_USB, M_WAITOK | M_ZERO);
1212184610Salfred	if (uts->buf == NULL) {
1213184610Salfred		/* could not allocate memory */
1214184610Salfred		return (USB_ERR_NOMEM);
1215184610Salfred	}
1216184610Salfred	/* second pass */
1217184610Salfred
1218184610Salfred	uts->size = 0;
1219184610Salfred
1220184610Salfred	usb2_make_device_desc(uts, tdd);
1221184610Salfred
1222184610Salfred	/*
1223184610Salfred	 * Store a pointer to our descriptors:
1224184610Salfred	 */
1225184610Salfred	udev->usb2_template_ptr = uts->buf;
1226184610Salfred
1227184610Salfred	if (uts->err) {
1228184610Salfred		/* some error happened during second pass */
1229184610Salfred		goto error;
1230184610Salfred	}
1231184610Salfred	/*
1232184610Salfred	 * Resolve all endpoint addresses !
1233184610Salfred	 */
1234184610Salfred	buf = usb2_temp_get_device_desc(udev);
1235184610Salfred	uts->err = usb2_hw_ep_resolve(udev, buf);
1236184610Salfred	if (uts->err) {
1237184610Salfred		DPRINTFN(0, "Could not resolve endpoints for "
1238184610Salfred		    "Device Descriptor, error = %s\n",
1239184610Salfred		    usb2_errstr(uts->err));
1240184610Salfred		goto error;
1241184610Salfred	}
1242184610Salfred	for (n = 0;; n++) {
1243184610Salfred
1244184610Salfred		buf = usb2_temp_get_config_desc(udev, NULL, n);
1245184610Salfred		if (buf == NULL) {
1246184610Salfred			break;
1247184610Salfred		}
1248184610Salfred		uts->err = usb2_hw_ep_resolve(udev, buf);
1249184610Salfred		if (uts->err) {
1250184610Salfred			DPRINTFN(0, "Could not resolve endpoints for "
1251184610Salfred			    "Config Descriptor %u, error = %s\n", n,
1252184610Salfred			    usb2_errstr(uts->err));
1253184610Salfred			goto error;
1254184610Salfred		}
1255184610Salfred	}
1256184610Salfred	return (uts->err);
1257184610Salfred
1258184610Salfrederror:
1259184610Salfred	usb2_temp_unsetup(udev);
1260184610Salfred	return (uts->err);
1261184610Salfred}
1262184610Salfred
1263184610Salfred/*------------------------------------------------------------------------*
1264184610Salfred *	usb2_temp_unsetup
1265184610Salfred *
1266184610Salfred * This function frees any memory associated with the currently
1267184610Salfred * setup template, if any.
1268184610Salfred *------------------------------------------------------------------------*/
1269184610Salfredstatic void
1270184610Salfredusb2_temp_unsetup(struct usb2_device *udev)
1271184610Salfred{
1272184610Salfred	if (udev->usb2_template_ptr) {
1273184610Salfred
1274184610Salfred		free(udev->usb2_template_ptr, M_USB);
1275184610Salfred
1276184610Salfred		udev->usb2_template_ptr = NULL;
1277184610Salfred	}
1278184610Salfred}
1279184610Salfred
1280184610Salfredstatic usb2_error_t
1281184610Salfredusb2_temp_setup_by_index(struct usb2_device *udev, uint16_t index)
1282184610Salfred{
1283184610Salfred	usb2_error_t err;
1284184610Salfred
1285184610Salfred	switch (index) {
1286184610Salfred	case 0:
1287184610Salfred		err = usb2_temp_setup(udev, &usb2_template_msc);
1288184610Salfred		break;
1289184610Salfred	case 1:
1290184610Salfred		err = usb2_temp_setup(udev, &usb2_template_cdce);
1291184610Salfred		break;
1292184610Salfred	case 2:
1293184610Salfred		err = usb2_temp_setup(udev, &usb2_template_mtp);
1294184610Salfred		break;
1295184610Salfred	default:
1296184610Salfred		return (USB_ERR_INVAL);
1297184610Salfred	}
1298184610Salfred
1299184610Salfred	return (err);
1300184610Salfred}
1301184610Salfred
1302184610Salfredstatic void
1303184610Salfredusb2_temp_init(void *arg)
1304184610Salfred{
1305184610Salfred	/* register our functions */
1306184610Salfred	usb2_temp_get_desc_p = &usb2_temp_get_desc;
1307184610Salfred	usb2_temp_setup_by_index_p = &usb2_temp_setup_by_index;
1308184610Salfred	usb2_temp_unsetup_p = &usb2_temp_unsetup;
1309184610Salfred}
1310184610Salfred
1311184610SalfredSYSINIT(usb2_temp_init, SI_SUB_LOCK, SI_ORDER_FIRST, usb2_temp_init, NULL);
1312184610SalfredSYSUNINIT(usb2_temp_unload, SI_SUB_LOCK, SI_ORDER_ANY, usb2_temp_unload, NULL);
1313