xref: /OK3568_Linux_fs/u-boot/drivers/usb/gadget/core.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2003
3*4882a593Smuzhiyun  * Gerry Hamel, geh@ti.com, Texas Instruments
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Based on
6*4882a593Smuzhiyun  * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright (c) 2000, 2001, 2002 Lineo
9*4882a593Smuzhiyun  * Copyright (c) 2001 Hewlett Packard
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * By:
12*4882a593Smuzhiyun  *	Stuart Lynne <sl@lineo.com>,
13*4882a593Smuzhiyun  *	Tom Rushworth <tbr@lineo.com>,
14*4882a593Smuzhiyun  *	Bruce Balden <balden@lineo.com>
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <malloc.h>
20*4882a593Smuzhiyun #include <usbdevice.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define MAX_INTERFACES 2
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun int maxstrings = 20;
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /* Global variables ************************************************************************** */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun struct usb_string_descriptor **usb_strings;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun int usb_devices;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun extern struct usb_function_driver ep0_driver;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun int registered_functions;
36*4882a593Smuzhiyun int registered_devices;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun char *usbd_device_events[] = {
39*4882a593Smuzhiyun 	"DEVICE_UNKNOWN",
40*4882a593Smuzhiyun 	"DEVICE_INIT",
41*4882a593Smuzhiyun 	"DEVICE_CREATE",
42*4882a593Smuzhiyun 	"DEVICE_HUB_CONFIGURED",
43*4882a593Smuzhiyun 	"DEVICE_RESET",
44*4882a593Smuzhiyun 	"DEVICE_ADDRESS_ASSIGNED",
45*4882a593Smuzhiyun 	"DEVICE_CONFIGURED",
46*4882a593Smuzhiyun 	"DEVICE_SET_INTERFACE",
47*4882a593Smuzhiyun 	"DEVICE_SET_FEATURE",
48*4882a593Smuzhiyun 	"DEVICE_CLEAR_FEATURE",
49*4882a593Smuzhiyun 	"DEVICE_DE_CONFIGURED",
50*4882a593Smuzhiyun 	"DEVICE_BUS_INACTIVE",
51*4882a593Smuzhiyun 	"DEVICE_BUS_ACTIVITY",
52*4882a593Smuzhiyun 	"DEVICE_POWER_INTERRUPTION",
53*4882a593Smuzhiyun 	"DEVICE_HUB_RESET",
54*4882a593Smuzhiyun 	"DEVICE_DESTROY",
55*4882a593Smuzhiyun 	"DEVICE_FUNCTION_PRIVATE",
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun char *usbd_device_states[] = {
59*4882a593Smuzhiyun 	"STATE_INIT",
60*4882a593Smuzhiyun 	"STATE_CREATED",
61*4882a593Smuzhiyun 	"STATE_ATTACHED",
62*4882a593Smuzhiyun 	"STATE_POWERED",
63*4882a593Smuzhiyun 	"STATE_DEFAULT",
64*4882a593Smuzhiyun 	"STATE_ADDRESSED",
65*4882a593Smuzhiyun 	"STATE_CONFIGURED",
66*4882a593Smuzhiyun 	"STATE_UNKNOWN",
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun char *usbd_device_requests[] = {
70*4882a593Smuzhiyun 	"GET STATUS",		/* 0 */
71*4882a593Smuzhiyun 	"CLEAR FEATURE",	/* 1 */
72*4882a593Smuzhiyun 	"RESERVED",		/* 2 */
73*4882a593Smuzhiyun 	"SET FEATURE",		/* 3 */
74*4882a593Smuzhiyun 	"RESERVED",		/* 4 */
75*4882a593Smuzhiyun 	"SET ADDRESS",		/* 5 */
76*4882a593Smuzhiyun 	"GET DESCRIPTOR",	/* 6 */
77*4882a593Smuzhiyun 	"SET DESCRIPTOR",	/* 7 */
78*4882a593Smuzhiyun 	"GET CONFIGURATION",	/* 8 */
79*4882a593Smuzhiyun 	"SET CONFIGURATION",	/* 9 */
80*4882a593Smuzhiyun 	"GET INTERFACE",	/* 10 */
81*4882a593Smuzhiyun 	"SET INTERFACE",	/* 11 */
82*4882a593Smuzhiyun 	"SYNC FRAME",		/* 12 */
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun char *usbd_device_descriptors[] = {
86*4882a593Smuzhiyun 	"UNKNOWN",		/* 0 */
87*4882a593Smuzhiyun 	"DEVICE",		/* 1 */
88*4882a593Smuzhiyun 	"CONFIG",		/* 2 */
89*4882a593Smuzhiyun 	"STRING",		/* 3 */
90*4882a593Smuzhiyun 	"INTERFACE",		/* 4 */
91*4882a593Smuzhiyun 	"ENDPOINT",		/* 5 */
92*4882a593Smuzhiyun 	"DEVICE QUALIFIER",	/* 6 */
93*4882a593Smuzhiyun 	"OTHER SPEED",		/* 7 */
94*4882a593Smuzhiyun 	"INTERFACE POWER",	/* 8 */
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun char *usbd_device_status[] = {
98*4882a593Smuzhiyun 	"USBD_OPENING",
99*4882a593Smuzhiyun 	"USBD_OK",
100*4882a593Smuzhiyun 	"USBD_SUSPENDED",
101*4882a593Smuzhiyun 	"USBD_CLOSING",
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /* Descriptor support functions ************************************************************** */
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /**
109*4882a593Smuzhiyun  * usbd_get_string - find and return a string descriptor
110*4882a593Smuzhiyun  * @index: string index to return
111*4882a593Smuzhiyun  *
112*4882a593Smuzhiyun  * Find an indexed string and return a pointer to a it.
113*4882a593Smuzhiyun  */
usbd_get_string(__u8 index)114*4882a593Smuzhiyun struct usb_string_descriptor *usbd_get_string (__u8 index)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	if (index >= maxstrings) {
117*4882a593Smuzhiyun 		return NULL;
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun 	return usb_strings[index];
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun /* Access to device descriptor functions ***************************************************** */
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun /* *
127*4882a593Smuzhiyun  * usbd_device_configuration_instance - find a configuration instance for this device
128*4882a593Smuzhiyun  * @device:
129*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
130*4882a593Smuzhiyun  *
131*4882a593Smuzhiyun  * Get specifed device configuration. Index should be bConfigurationValue-1.
132*4882a593Smuzhiyun  */
usbd_device_configuration_instance(struct usb_device_instance * device,unsigned int port,unsigned int configuration)133*4882a593Smuzhiyun static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
134*4882a593Smuzhiyun 		unsigned int port, unsigned int configuration)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	if (configuration >= device->configurations)
137*4882a593Smuzhiyun 		return NULL;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	return device->configuration_instance_array + configuration;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun /* *
144*4882a593Smuzhiyun  * usbd_device_interface_instance
145*4882a593Smuzhiyun  * @device:
146*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
147*4882a593Smuzhiyun  * @interface: index to interface
148*4882a593Smuzhiyun  *
149*4882a593Smuzhiyun  * Return the specified interface descriptor for the specified device.
150*4882a593Smuzhiyun  */
usbd_device_interface_instance(struct usb_device_instance * device,int port,int configuration,int interface)151*4882a593Smuzhiyun struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct usb_configuration_instance *configuration_instance;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
156*4882a593Smuzhiyun 		return NULL;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 	if (interface >= configuration_instance->interfaces) {
159*4882a593Smuzhiyun 		return NULL;
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 	return configuration_instance->interface_instance_array + interface;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun /* *
165*4882a593Smuzhiyun  * usbd_device_alternate_descriptor_list
166*4882a593Smuzhiyun  * @device:
167*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
168*4882a593Smuzhiyun  * @interface: index to interface
169*4882a593Smuzhiyun  * @alternate: alternate setting
170*4882a593Smuzhiyun  *
171*4882a593Smuzhiyun  * Return the specified alternate descriptor for the specified device.
172*4882a593Smuzhiyun  */
usbd_device_alternate_instance(struct usb_device_instance * device,int port,int configuration,int interface,int alternate)173*4882a593Smuzhiyun struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	struct usb_interface_instance *interface_instance;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
178*4882a593Smuzhiyun 		return NULL;
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (alternate >= interface_instance->alternates) {
182*4882a593Smuzhiyun 		return NULL;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	return interface_instance->alternates_instance_array + alternate;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun /* *
190*4882a593Smuzhiyun  * usbd_device_device_descriptor
191*4882a593Smuzhiyun  * @device: which device
192*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
193*4882a593Smuzhiyun  * @port: which port
194*4882a593Smuzhiyun  *
195*4882a593Smuzhiyun  * Return the specified configuration descriptor for the specified device.
196*4882a593Smuzhiyun  */
usbd_device_device_descriptor(struct usb_device_instance * device,int port)197*4882a593Smuzhiyun struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	return (device->device_descriptor);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun /**
203*4882a593Smuzhiyun  * usbd_device_configuration_descriptor
204*4882a593Smuzhiyun  * @device: which device
205*4882a593Smuzhiyun  * @port: which port
206*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
207*4882a593Smuzhiyun  *
208*4882a593Smuzhiyun  * Return the specified configuration descriptor for the specified device.
209*4882a593Smuzhiyun  */
usbd_device_configuration_descriptor(struct usb_device_instance * device,int port,int configuration)210*4882a593Smuzhiyun struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
211*4882a593Smuzhiyun 									   usb_device_instance
212*4882a593Smuzhiyun 									   *device, int port, int configuration)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	struct usb_configuration_instance *configuration_instance;
215*4882a593Smuzhiyun 	if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
216*4882a593Smuzhiyun 		return NULL;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 	return (configuration_instance->configuration_descriptor);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun /**
223*4882a593Smuzhiyun  * usbd_device_interface_descriptor
224*4882a593Smuzhiyun  * @device: which device
225*4882a593Smuzhiyun  * @port: which port
226*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
227*4882a593Smuzhiyun  * @interface: index to interface
228*4882a593Smuzhiyun  * @alternate: alternate setting
229*4882a593Smuzhiyun  *
230*4882a593Smuzhiyun  * Return the specified interface descriptor for the specified device.
231*4882a593Smuzhiyun  */
usbd_device_interface_descriptor(struct usb_device_instance * device,int port,int configuration,int interface,int alternate)232*4882a593Smuzhiyun struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
233*4882a593Smuzhiyun 								   *device, int port, int configuration, int interface, int alternate)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	struct usb_interface_instance *interface_instance;
236*4882a593Smuzhiyun 	if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
237*4882a593Smuzhiyun 		return NULL;
238*4882a593Smuzhiyun 	}
239*4882a593Smuzhiyun 	if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
240*4882a593Smuzhiyun 		return NULL;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 	return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun /**
246*4882a593Smuzhiyun  * usbd_device_endpoint_descriptor_index
247*4882a593Smuzhiyun  * @device: which device
248*4882a593Smuzhiyun  * @port: which port
249*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
250*4882a593Smuzhiyun  * @interface: index to interface
251*4882a593Smuzhiyun  * @alternate: index setting
252*4882a593Smuzhiyun  * @index: which index
253*4882a593Smuzhiyun  *
254*4882a593Smuzhiyun  * Return the specified endpoint descriptor for the specified device.
255*4882a593Smuzhiyun  */
usbd_device_endpoint_descriptor_index(struct usb_device_instance * device,int port,int configuration,int interface,int alternate,int index)256*4882a593Smuzhiyun struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
257*4882a593Smuzhiyun 								       *device, int port, int configuration, int interface, int alternate, int index)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct usb_alternate_instance *alternate_instance;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
262*4882a593Smuzhiyun 		return NULL;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 	if (index >= alternate_instance->endpoints) {
265*4882a593Smuzhiyun 		return NULL;
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun 	return *(alternate_instance->endpoints_descriptor_array + index);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun /**
272*4882a593Smuzhiyun  * usbd_device_endpoint_transfersize
273*4882a593Smuzhiyun  * @device: which device
274*4882a593Smuzhiyun  * @port: which port
275*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
276*4882a593Smuzhiyun  * @interface: index to interface
277*4882a593Smuzhiyun  * @index: which index
278*4882a593Smuzhiyun  *
279*4882a593Smuzhiyun  * Return the specified endpoint transfer size;
280*4882a593Smuzhiyun  */
usbd_device_endpoint_transfersize(struct usb_device_instance * device,int port,int configuration,int interface,int alternate,int index)281*4882a593Smuzhiyun int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	struct usb_alternate_instance *alternate_instance;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
286*4882a593Smuzhiyun 		return 0;
287*4882a593Smuzhiyun 	}
288*4882a593Smuzhiyun 	if (index >= alternate_instance->endpoints) {
289*4882a593Smuzhiyun 		return 0;
290*4882a593Smuzhiyun 	}
291*4882a593Smuzhiyun 	return *(alternate_instance->endpoint_transfersize_array + index);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun /**
296*4882a593Smuzhiyun  * usbd_device_endpoint_descriptor
297*4882a593Smuzhiyun  * @device: which device
298*4882a593Smuzhiyun  * @port: which port
299*4882a593Smuzhiyun  * @configuration: index to configuration, 0 - N-1
300*4882a593Smuzhiyun  * @interface: index to interface
301*4882a593Smuzhiyun  * @alternate: alternate setting
302*4882a593Smuzhiyun  * @endpoint: which endpoint
303*4882a593Smuzhiyun  *
304*4882a593Smuzhiyun  * Return the specified endpoint descriptor for the specified device.
305*4882a593Smuzhiyun  */
usbd_device_endpoint_descriptor(struct usb_device_instance * device,int port,int configuration,int interface,int alternate,int endpoint)306*4882a593Smuzhiyun struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun 	struct usb_endpoint_descriptor *endpoint_descriptor;
309*4882a593Smuzhiyun 	int i;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
312*4882a593Smuzhiyun 		if (endpoint_descriptor->bEndpointAddress == endpoint) {
313*4882a593Smuzhiyun 			return endpoint_descriptor;
314*4882a593Smuzhiyun 		}
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 	return NULL;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun /**
320*4882a593Smuzhiyun  * usbd_endpoint_halted
321*4882a593Smuzhiyun  * @device: point to struct usb_device_instance
322*4882a593Smuzhiyun  * @endpoint: endpoint to check
323*4882a593Smuzhiyun  *
324*4882a593Smuzhiyun  * Return non-zero if endpoint is halted.
325*4882a593Smuzhiyun  */
usbd_endpoint_halted(struct usb_device_instance * device,int endpoint)326*4882a593Smuzhiyun int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	return (device->status == USB_STATUS_HALT);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun /**
333*4882a593Smuzhiyun  * usbd_rcv_complete - complete a receive
334*4882a593Smuzhiyun  * @endpoint:
335*4882a593Smuzhiyun  * @len:
336*4882a593Smuzhiyun  * @urb_bad:
337*4882a593Smuzhiyun  *
338*4882a593Smuzhiyun  * Called from rcv interrupt to complete.
339*4882a593Smuzhiyun  */
usbd_rcv_complete(struct usb_endpoint_instance * endpoint,int len,int urb_bad)340*4882a593Smuzhiyun void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	if (endpoint) {
343*4882a593Smuzhiyun 		struct urb *rcv_urb;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 		/*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 		/* if we had an urb then update actual_length, dispatch if neccessary */
348*4882a593Smuzhiyun 		if ((rcv_urb = endpoint->rcv_urb)) {
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 			/*usbdbg("actual: %d buffer: %d\n", */
351*4882a593Smuzhiyun 			/*rcv_urb->actual_length, rcv_urb->buffer_length); */
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 			/* check the urb is ok, are we adding data less than the packetsize */
354*4882a593Smuzhiyun 			if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
355*4882a593Smuzhiyun 			  /*usbdbg("updating actual_length by %d\n",len); */
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 				/* increment the received data size */
358*4882a593Smuzhiyun 				rcv_urb->actual_length += len;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 			} else {
361*4882a593Smuzhiyun 				usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
362*4882a593Smuzhiyun 				       rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 				rcv_urb->actual_length = 0;
365*4882a593Smuzhiyun 				rcv_urb->status = RECV_ERROR;
366*4882a593Smuzhiyun 			}
367*4882a593Smuzhiyun 		} else {
368*4882a593Smuzhiyun 			usberr("no rcv_urb!");
369*4882a593Smuzhiyun 		}
370*4882a593Smuzhiyun 	} else {
371*4882a593Smuzhiyun 		usberr("no endpoint!");
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun /**
377*4882a593Smuzhiyun  * usbd_tx_complete - complete a transmit
378*4882a593Smuzhiyun  * @endpoint:
379*4882a593Smuzhiyun  * @resetart:
380*4882a593Smuzhiyun  *
381*4882a593Smuzhiyun  * Called from tx interrupt to complete.
382*4882a593Smuzhiyun  */
usbd_tx_complete(struct usb_endpoint_instance * endpoint)383*4882a593Smuzhiyun void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun 	if (endpoint) {
386*4882a593Smuzhiyun 		struct urb *tx_urb;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 		/* if we have a tx_urb advance or reset, finish if complete */
389*4882a593Smuzhiyun 		if ((tx_urb = endpoint->tx_urb)) {
390*4882a593Smuzhiyun 			int sent = endpoint->last;
391*4882a593Smuzhiyun 			endpoint->sent += sent;
392*4882a593Smuzhiyun 			endpoint->last -= sent;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 			if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
395*4882a593Smuzhiyun 				tx_urb->actual_length = 0;
396*4882a593Smuzhiyun 				endpoint->sent = 0;
397*4882a593Smuzhiyun 				endpoint->last = 0;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 				/* Remove from active, save for re-use */
400*4882a593Smuzhiyun 				urb_detach(tx_urb);
401*4882a593Smuzhiyun 				urb_append(&endpoint->done, tx_urb);
402*4882a593Smuzhiyun 				/*usbdbg("done->next %p, tx_urb %p, done %p", */
403*4882a593Smuzhiyun 				/*	 endpoint->done.next, tx_urb, &endpoint->done); */
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 				endpoint->tx_urb = first_urb_detached(&endpoint->tx);
406*4882a593Smuzhiyun 				if( endpoint->tx_urb ) {
407*4882a593Smuzhiyun 					endpoint->tx_queue--;
408*4882a593Smuzhiyun 					usbdbg("got urb from tx list");
409*4882a593Smuzhiyun 				}
410*4882a593Smuzhiyun 				if( !endpoint->tx_urb ) {
411*4882a593Smuzhiyun 					/*usbdbg("taking urb from done list"); */
412*4882a593Smuzhiyun 					endpoint->tx_urb = first_urb_detached(&endpoint->done);
413*4882a593Smuzhiyun 				}
414*4882a593Smuzhiyun 				if( !endpoint->tx_urb ) {
415*4882a593Smuzhiyun 					usbdbg("allocating new urb for tx_urb");
416*4882a593Smuzhiyun 					endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
417*4882a593Smuzhiyun 				}
418*4882a593Smuzhiyun 			}
419*4882a593Smuzhiyun 		}
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun /* URB linked list functions ***************************************************** */
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun /*
426*4882a593Smuzhiyun  * Initialize an urb_link to be a single element list.
427*4882a593Smuzhiyun  * If the urb_link is being used as a distinguished list head
428*4882a593Smuzhiyun  * the list is empty when the head is the only link in the list.
429*4882a593Smuzhiyun  */
urb_link_init(urb_link * ul)430*4882a593Smuzhiyun void urb_link_init (urb_link * ul)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun 	if (ul) {
433*4882a593Smuzhiyun 		ul->prev = ul->next = ul;
434*4882a593Smuzhiyun 	}
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun /*
438*4882a593Smuzhiyun  * Detach an urb_link from a list, and set it
439*4882a593Smuzhiyun  * up as a single element list, so no dangling
440*4882a593Smuzhiyun  * pointers can be followed, and so it can be
441*4882a593Smuzhiyun  * joined to another list if so desired.
442*4882a593Smuzhiyun  */
urb_detach(struct urb * urb)443*4882a593Smuzhiyun void urb_detach (struct urb *urb)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun 	if (urb) {
446*4882a593Smuzhiyun 		urb_link *ul = &urb->link;
447*4882a593Smuzhiyun 		ul->next->prev = ul->prev;
448*4882a593Smuzhiyun 		ul->prev->next = ul->next;
449*4882a593Smuzhiyun 		urb_link_init (ul);
450*4882a593Smuzhiyun 	}
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun /*
454*4882a593Smuzhiyun  * Return the first urb_link in a list with a distinguished
455*4882a593Smuzhiyun  * head "hd", or NULL if the list is empty.  This will also
456*4882a593Smuzhiyun  * work as a predicate, returning NULL if empty, and non-NULL
457*4882a593Smuzhiyun  * otherwise.
458*4882a593Smuzhiyun  */
first_urb_link(urb_link * hd)459*4882a593Smuzhiyun urb_link *first_urb_link (urb_link * hd)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	urb_link *nx;
462*4882a593Smuzhiyun 	if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
463*4882a593Smuzhiyun 		/* There is at least one element in the list */
464*4882a593Smuzhiyun 		/* (besides the distinguished head). */
465*4882a593Smuzhiyun 		return (nx);
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 	/* The list is empty */
468*4882a593Smuzhiyun 	return (NULL);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun /*
472*4882a593Smuzhiyun  * Return the first urb in a list with a distinguished
473*4882a593Smuzhiyun  * head "hd", or NULL if the list is empty.
474*4882a593Smuzhiyun  */
first_urb(urb_link * hd)475*4882a593Smuzhiyun struct urb *first_urb (urb_link * hd)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	urb_link *nx;
478*4882a593Smuzhiyun 	if (NULL == (nx = first_urb_link (hd))) {
479*4882a593Smuzhiyun 		/* The list is empty */
480*4882a593Smuzhiyun 		return (NULL);
481*4882a593Smuzhiyun 	}
482*4882a593Smuzhiyun 	return (p2surround (struct urb, link, nx));
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun /*
486*4882a593Smuzhiyun  * Detach and return the first urb in a list with a distinguished
487*4882a593Smuzhiyun  * head "hd", or NULL if the list is empty.
488*4882a593Smuzhiyun  *
489*4882a593Smuzhiyun  */
first_urb_detached(urb_link * hd)490*4882a593Smuzhiyun struct urb *first_urb_detached (urb_link * hd)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun 	struct urb *urb;
493*4882a593Smuzhiyun 	if ((urb = first_urb (hd))) {
494*4882a593Smuzhiyun 		urb_detach (urb);
495*4882a593Smuzhiyun 	}
496*4882a593Smuzhiyun 	return urb;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun /*
501*4882a593Smuzhiyun  * Append an urb_link (or a whole list of
502*4882a593Smuzhiyun  * urb_links) to the tail of another list
503*4882a593Smuzhiyun  * of urb_links.
504*4882a593Smuzhiyun  */
urb_append(urb_link * hd,struct urb * urb)505*4882a593Smuzhiyun void urb_append (urb_link * hd, struct urb *urb)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	if (hd && urb) {
508*4882a593Smuzhiyun 		urb_link *new = &urb->link;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 		/* This allows the new urb to be a list of urbs, */
511*4882a593Smuzhiyun 		/* with new pointing at the first, but the link */
512*4882a593Smuzhiyun 		/* must be initialized. */
513*4882a593Smuzhiyun 		/* Order is important here... */
514*4882a593Smuzhiyun 		urb_link *pul = hd->prev;
515*4882a593Smuzhiyun 		new->prev->next = hd;
516*4882a593Smuzhiyun 		hd->prev = new->prev;
517*4882a593Smuzhiyun 		new->prev = pul;
518*4882a593Smuzhiyun 		pul->next = new;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun /* URB create/destroy functions ***************************************************** */
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun /**
525*4882a593Smuzhiyun  * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
526*4882a593Smuzhiyun  * @device: device instance
527*4882a593Smuzhiyun  * @endpoint: endpoint
528*4882a593Smuzhiyun  *
529*4882a593Smuzhiyun  * Allocate an urb structure. The usb device urb structure is used to
530*4882a593Smuzhiyun  * contain all data associated with a transfer, including a setup packet for
531*4882a593Smuzhiyun  * control transfers.
532*4882a593Smuzhiyun  *
533*4882a593Smuzhiyun  * NOTE: endpoint_address MUST contain a direction flag.
534*4882a593Smuzhiyun  */
usbd_alloc_urb(struct usb_device_instance * device,struct usb_endpoint_instance * endpoint)535*4882a593Smuzhiyun struct urb *usbd_alloc_urb (struct usb_device_instance *device,
536*4882a593Smuzhiyun 			    struct usb_endpoint_instance *endpoint)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun 	struct urb *urb;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) {
541*4882a593Smuzhiyun 		usberr (" F A T A L:  malloc(%zu) FAILED!!!!",
542*4882a593Smuzhiyun 			sizeof (struct urb));
543*4882a593Smuzhiyun 		return NULL;
544*4882a593Smuzhiyun 	}
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	/* Fill in known fields */
547*4882a593Smuzhiyun 	memset (urb, 0, sizeof (struct urb));
548*4882a593Smuzhiyun 	urb->endpoint = endpoint;
549*4882a593Smuzhiyun 	urb->device = device;
550*4882a593Smuzhiyun 	urb->buffer = (u8 *) urb->buffer_data;
551*4882a593Smuzhiyun 	urb->buffer_length = sizeof (urb->buffer_data);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	urb_link_init (&urb->link);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	return urb;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun /**
559*4882a593Smuzhiyun  * usbd_dealloc_urb - deallocate an URB and associated buffer
560*4882a593Smuzhiyun  * @urb: pointer to an urb structure
561*4882a593Smuzhiyun  *
562*4882a593Smuzhiyun  * Deallocate an urb structure and associated data.
563*4882a593Smuzhiyun  */
usbd_dealloc_urb(struct urb * urb)564*4882a593Smuzhiyun void usbd_dealloc_urb (struct urb *urb)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun 	if (urb) {
567*4882a593Smuzhiyun 		free (urb);
568*4882a593Smuzhiyun 	}
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun /* Event signaling functions ***************************************************** */
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun /**
574*4882a593Smuzhiyun  * usbd_device_event - called to respond to various usb events
575*4882a593Smuzhiyun  * @device: pointer to struct device
576*4882a593Smuzhiyun  * @event: event to respond to
577*4882a593Smuzhiyun  *
578*4882a593Smuzhiyun  * Used by a Bus driver to indicate an event.
579*4882a593Smuzhiyun  */
usbd_device_event_irq(struct usb_device_instance * device,usb_device_event_t event,int data)580*4882a593Smuzhiyun void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun 	usb_device_state_t state;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	if (!device || !device->bus) {
585*4882a593Smuzhiyun 		usberr("(%p,%d) NULL device or device->bus", device, event);
586*4882a593Smuzhiyun 		return;
587*4882a593Smuzhiyun 	}
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	state = device->device_state;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	usbinfo("%s", usbd_device_events[event]);
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	switch (event) {
594*4882a593Smuzhiyun 	case DEVICE_UNKNOWN:
595*4882a593Smuzhiyun 		break;
596*4882a593Smuzhiyun 	case DEVICE_INIT:
597*4882a593Smuzhiyun 		device->device_state = STATE_INIT;
598*4882a593Smuzhiyun 		break;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	case DEVICE_CREATE:
601*4882a593Smuzhiyun 		device->device_state = STATE_ATTACHED;
602*4882a593Smuzhiyun 		break;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	case DEVICE_HUB_CONFIGURED:
605*4882a593Smuzhiyun 		device->device_state = STATE_POWERED;
606*4882a593Smuzhiyun 		break;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	case DEVICE_RESET:
609*4882a593Smuzhiyun 		device->device_state = STATE_DEFAULT;
610*4882a593Smuzhiyun 		device->address = 0;
611*4882a593Smuzhiyun 		break;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	case DEVICE_ADDRESS_ASSIGNED:
614*4882a593Smuzhiyun 		device->device_state = STATE_ADDRESSED;
615*4882a593Smuzhiyun 		break;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	case DEVICE_CONFIGURED:
618*4882a593Smuzhiyun 		device->device_state = STATE_CONFIGURED;
619*4882a593Smuzhiyun 		break;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	case DEVICE_DE_CONFIGURED:
622*4882a593Smuzhiyun 		device->device_state = STATE_ADDRESSED;
623*4882a593Smuzhiyun 		break;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	case DEVICE_BUS_INACTIVE:
626*4882a593Smuzhiyun 		if (device->status != USBD_CLOSING) {
627*4882a593Smuzhiyun 			device->status = USBD_SUSPENDED;
628*4882a593Smuzhiyun 		}
629*4882a593Smuzhiyun 		break;
630*4882a593Smuzhiyun 	case DEVICE_BUS_ACTIVITY:
631*4882a593Smuzhiyun 		if (device->status != USBD_CLOSING) {
632*4882a593Smuzhiyun 			device->status = USBD_OK;
633*4882a593Smuzhiyun 		}
634*4882a593Smuzhiyun 		break;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	case DEVICE_SET_INTERFACE:
637*4882a593Smuzhiyun 		break;
638*4882a593Smuzhiyun 	case DEVICE_SET_FEATURE:
639*4882a593Smuzhiyun 		break;
640*4882a593Smuzhiyun 	case DEVICE_CLEAR_FEATURE:
641*4882a593Smuzhiyun 		break;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	case DEVICE_POWER_INTERRUPTION:
644*4882a593Smuzhiyun 		device->device_state = STATE_POWERED;
645*4882a593Smuzhiyun 		break;
646*4882a593Smuzhiyun 	case DEVICE_HUB_RESET:
647*4882a593Smuzhiyun 		device->device_state = STATE_ATTACHED;
648*4882a593Smuzhiyun 		break;
649*4882a593Smuzhiyun 	case DEVICE_DESTROY:
650*4882a593Smuzhiyun 		device->device_state = STATE_UNKNOWN;
651*4882a593Smuzhiyun 		break;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	case DEVICE_FUNCTION_PRIVATE:
654*4882a593Smuzhiyun 		break;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	default:
657*4882a593Smuzhiyun 		usbdbg("event %d - not handled",event);
658*4882a593Smuzhiyun 		break;
659*4882a593Smuzhiyun 	}
660*4882a593Smuzhiyun 	debug("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
661*4882a593Smuzhiyun 		device->name, event, state,
662*4882a593Smuzhiyun 		device->device_state, device->status, device->address);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	/* tell the bus interface driver */
665*4882a593Smuzhiyun 	if( device->event ) {
666*4882a593Smuzhiyun 		/* usbdbg("calling device->event"); */
667*4882a593Smuzhiyun 		device->event(device, event, data);
668*4882a593Smuzhiyun 	}
669*4882a593Smuzhiyun }
670