1*53ee8cc1Swenshuai.xi //<MStar Software>
2*53ee8cc1Swenshuai.xi //******************************************************************************
3*53ee8cc1Swenshuai.xi // MStar Software
4*53ee8cc1Swenshuai.xi // Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
5*53ee8cc1Swenshuai.xi // All software, firmware and related documentation herein ("MStar Software") are
6*53ee8cc1Swenshuai.xi // intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
7*53ee8cc1Swenshuai.xi // law, including, but not limited to, copyright law and international treaties.
8*53ee8cc1Swenshuai.xi // Any use, modification, reproduction, retransmission, or republication of all
9*53ee8cc1Swenshuai.xi // or part of MStar Software is expressly prohibited, unless prior written
10*53ee8cc1Swenshuai.xi // permission has been granted by MStar.
11*53ee8cc1Swenshuai.xi //
12*53ee8cc1Swenshuai.xi // By accessing, browsing and/or using MStar Software, you acknowledge that you
13*53ee8cc1Swenshuai.xi // have read, understood, and agree, to be bound by below terms ("Terms") and to
14*53ee8cc1Swenshuai.xi // comply with all applicable laws and regulations:
15*53ee8cc1Swenshuai.xi //
16*53ee8cc1Swenshuai.xi // 1. MStar shall retain any and all right, ownership and interest to MStar
17*53ee8cc1Swenshuai.xi // Software and any modification/derivatives thereof.
18*53ee8cc1Swenshuai.xi // No right, ownership, or interest to MStar Software and any
19*53ee8cc1Swenshuai.xi // modification/derivatives thereof is transferred to you under Terms.
20*53ee8cc1Swenshuai.xi //
21*53ee8cc1Swenshuai.xi // 2. You understand that MStar Software might include, incorporate or be
22*53ee8cc1Swenshuai.xi // supplied together with third party`s software and the use of MStar
23*53ee8cc1Swenshuai.xi // Software may require additional licenses from third parties.
24*53ee8cc1Swenshuai.xi // Therefore, you hereby agree it is your sole responsibility to separately
25*53ee8cc1Swenshuai.xi // obtain any and all third party right and license necessary for your use of
26*53ee8cc1Swenshuai.xi // such third party`s software.
27*53ee8cc1Swenshuai.xi //
28*53ee8cc1Swenshuai.xi // 3. MStar Software and any modification/derivatives thereof shall be deemed as
29*53ee8cc1Swenshuai.xi // MStar`s confidential information and you agree to keep MStar`s
30*53ee8cc1Swenshuai.xi // confidential information in strictest confidence and not disclose to any
31*53ee8cc1Swenshuai.xi // third party.
32*53ee8cc1Swenshuai.xi //
33*53ee8cc1Swenshuai.xi // 4. MStar Software is provided on an "AS IS" basis without warranties of any
34*53ee8cc1Swenshuai.xi // kind. Any warranties are hereby expressly disclaimed by MStar, including
35*53ee8cc1Swenshuai.xi // without limitation, any warranties of merchantability, non-infringement of
36*53ee8cc1Swenshuai.xi // intellectual property rights, fitness for a particular purpose, error free
37*53ee8cc1Swenshuai.xi // and in conformity with any international standard. You agree to waive any
38*53ee8cc1Swenshuai.xi // claim against MStar for any loss, damage, cost or expense that you may
39*53ee8cc1Swenshuai.xi // incur related to your use of MStar Software.
40*53ee8cc1Swenshuai.xi // In no event shall MStar be liable for any direct, indirect, incidental or
41*53ee8cc1Swenshuai.xi // consequential damages, including without limitation, lost of profit or
42*53ee8cc1Swenshuai.xi // revenues, lost or damage of data, and unauthorized system use.
43*53ee8cc1Swenshuai.xi // You agree that this Section 4 shall still apply without being affected
44*53ee8cc1Swenshuai.xi // even if MStar Software has been modified by MStar in accordance with your
45*53ee8cc1Swenshuai.xi // request or instruction for your use, except otherwise agreed by both
46*53ee8cc1Swenshuai.xi // parties in writing.
47*53ee8cc1Swenshuai.xi //
48*53ee8cc1Swenshuai.xi // 5. If requested, MStar may from time to time provide technical supports or
49*53ee8cc1Swenshuai.xi // services in relation with MStar Software to you for your use of
50*53ee8cc1Swenshuai.xi // MStar Software in conjunction with your or your customer`s product
51*53ee8cc1Swenshuai.xi // ("Services").
52*53ee8cc1Swenshuai.xi // You understand and agree that, except otherwise agreed by both parties in
53*53ee8cc1Swenshuai.xi // writing, Services are provided on an "AS IS" basis and the warranty
54*53ee8cc1Swenshuai.xi // disclaimer set forth in Section 4 above shall apply.
55*53ee8cc1Swenshuai.xi //
56*53ee8cc1Swenshuai.xi // 6. Nothing contained herein shall be construed as by implication, estoppels
57*53ee8cc1Swenshuai.xi // or otherwise:
58*53ee8cc1Swenshuai.xi // (a) conferring any license or right to use MStar name, trademark, service
59*53ee8cc1Swenshuai.xi // mark, symbol or any other identification;
60*53ee8cc1Swenshuai.xi // (b) obligating MStar or any of its affiliates to furnish any person,
61*53ee8cc1Swenshuai.xi // including without limitation, you and your customers, any assistance
62*53ee8cc1Swenshuai.xi // of any kind whatsoever, or any information; or
63*53ee8cc1Swenshuai.xi // (c) conferring any license or right under any intellectual property right.
64*53ee8cc1Swenshuai.xi //
65*53ee8cc1Swenshuai.xi // 7. These terms shall be governed by and construed in accordance with the laws
66*53ee8cc1Swenshuai.xi // of Taiwan, R.O.C., excluding its conflict of law rules.
67*53ee8cc1Swenshuai.xi // Any and all dispute arising out hereof or related hereto shall be finally
68*53ee8cc1Swenshuai.xi // settled by arbitration referred to the Chinese Arbitration Association,
69*53ee8cc1Swenshuai.xi // Taipei in accordance with the ROC Arbitration Law and the Arbitration
70*53ee8cc1Swenshuai.xi // Rules of the Association by three (3) arbitrators appointed in accordance
71*53ee8cc1Swenshuai.xi // with the said Rules.
72*53ee8cc1Swenshuai.xi // The place of arbitration shall be in Taipei, Taiwan and the language shall
73*53ee8cc1Swenshuai.xi // be English.
74*53ee8cc1Swenshuai.xi // The arbitration award shall be final and binding to both parties.
75*53ee8cc1Swenshuai.xi //
76*53ee8cc1Swenshuai.xi //******************************************************************************
77*53ee8cc1Swenshuai.xi //<MStar Software>
78*53ee8cc1Swenshuai.xi
79*53ee8cc1Swenshuai.xi #include <MsCommon.h>
80*53ee8cc1Swenshuai.xi
81*53ee8cc1Swenshuai.xi #include "include/drvConfig.h"
82*53ee8cc1Swenshuai.xi #include "include/drvCompiler.h"
83*53ee8cc1Swenshuai.xi #include "include/drvList.h"
84*53ee8cc1Swenshuai.xi #include "include/drvPorts.h"
85*53ee8cc1Swenshuai.xi #include "include/drvPCIMEM.h"
86*53ee8cc1Swenshuai.xi #include "include/drvTimer.h"
87*53ee8cc1Swenshuai.xi #include "include/drvUSB.h"
88*53ee8cc1Swenshuai.xi #include "drvHCD.h"
89*53ee8cc1Swenshuai.xi #define USB_MAXALTSETTING 128
90*53ee8cc1Swenshuai.xi #define USB_MAXENDPOINTS 30
91*53ee8cc1Swenshuai.xi
92*53ee8cc1Swenshuai.xi #define USB_MAXCONFIG 8
93*53ee8cc1Swenshuai.xi #define USB_ALTSETTINGALLOC 4
94*53ee8cc1Swenshuai.xi #define USB_MAXINTERFACES 32
95*53ee8cc1Swenshuai.xi #define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
96*53ee8cc1Swenshuai.xi
usb_parse_endpoint(struct usb_device * dev,struct usb_host_endpoint * endpoint,unsigned char * buffer,int size)97*53ee8cc1Swenshuai.xi static int usb_parse_endpoint(struct usb_device *dev, struct usb_host_endpoint *endpoint, unsigned char *buffer, int size)
98*53ee8cc1Swenshuai.xi {
99*53ee8cc1Swenshuai.xi struct usb_descriptor_header *header;
100*53ee8cc1Swenshuai.xi unsigned char *begin;
101*53ee8cc1Swenshuai.xi int parsed = 0, len, numskipped;
102*53ee8cc1Swenshuai.xi
103*53ee8cc1Swenshuai.xi header = (struct usb_descriptor_header *)buffer;
104*53ee8cc1Swenshuai.xi
105*53ee8cc1Swenshuai.xi if (header->bLength > size) {
106*53ee8cc1Swenshuai.xi usb_err("ran out of descriptors parsing%s","");
107*53ee8cc1Swenshuai.xi return -1;
108*53ee8cc1Swenshuai.xi }
109*53ee8cc1Swenshuai.xi
110*53ee8cc1Swenshuai.xi if (header->bDescriptorType != USB_DT_ENDPOINT) {
111*53ee8cc1Swenshuai.xi usb_warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X",
112*53ee8cc1Swenshuai.xi header->bDescriptorType, USB_DT_ENDPOINT);
113*53ee8cc1Swenshuai.xi return parsed;
114*53ee8cc1Swenshuai.xi }
115*53ee8cc1Swenshuai.xi
116*53ee8cc1Swenshuai.xi if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE)
117*53ee8cc1Swenshuai.xi memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
118*53ee8cc1Swenshuai.xi else
119*53ee8cc1Swenshuai.xi memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE);
120*53ee8cc1Swenshuai.xi
121*53ee8cc1Swenshuai.xi endpoint->desc.wMaxPacketSize = LE16ToCPU(endpoint->desc.wMaxPacketSize);
122*53ee8cc1Swenshuai.xi
123*53ee8cc1Swenshuai.xi #if 0
124*53ee8cc1Swenshuai.xi if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
125*53ee8cc1Swenshuai.xi && usb_endpoint_xfer_bulk(d)) {
126*53ee8cc1Swenshuai.xi unsigned maxp;
127*53ee8cc1Swenshuai.xi
128*53ee8cc1Swenshuai.xi maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
129*53ee8cc1Swenshuai.xi if (maxp != 512)
130*53ee8cc1Swenshuai.xi dev_warn(ddev, "config %d interface %d altsetting %d "
131*53ee8cc1Swenshuai.xi "bulk endpoint 0x%X has invalid maxpacket %d\n",
132*53ee8cc1Swenshuai.xi cfgno, inum, asnum, d->bEndpointAddress,
133*53ee8cc1Swenshuai.xi maxp);
134*53ee8cc1Swenshuai.xi }
135*53ee8cc1Swenshuai.xi #else
136*53ee8cc1Swenshuai.xi if (dev->speed == USB_SPEED_HIGH
137*53ee8cc1Swenshuai.xi && (endpoint->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
138*53ee8cc1Swenshuai.xi unsigned maxp;
139*53ee8cc1Swenshuai.xi
140*53ee8cc1Swenshuai.xi maxp = max_packet(endpoint->desc.wMaxPacketSize);
141*53ee8cc1Swenshuai.xi if (maxp != 512)
142*53ee8cc1Swenshuai.xi diag_printf("bulk endpoint 0x%X has invalid maxpacket %d\n",
143*53ee8cc1Swenshuai.xi endpoint->desc.bEndpointAddress, maxp);
144*53ee8cc1Swenshuai.xi }
145*53ee8cc1Swenshuai.xi #endif
146*53ee8cc1Swenshuai.xi
147*53ee8cc1Swenshuai.xi buffer += header->bLength;
148*53ee8cc1Swenshuai.xi size -= header->bLength;
149*53ee8cc1Swenshuai.xi parsed += header->bLength;
150*53ee8cc1Swenshuai.xi
151*53ee8cc1Swenshuai.xi begin = buffer;
152*53ee8cc1Swenshuai.xi numskipped = 0;
153*53ee8cc1Swenshuai.xi while ((U32)size >= sizeof(struct usb_descriptor_header)) {
154*53ee8cc1Swenshuai.xi header = (struct usb_descriptor_header *)buffer;
155*53ee8cc1Swenshuai.xi
156*53ee8cc1Swenshuai.xi if (header->bLength < 2) {
157*53ee8cc1Swenshuai.xi usb_err("invalid descriptor length of %d", header->bLength);
158*53ee8cc1Swenshuai.xi return -1;
159*53ee8cc1Swenshuai.xi }
160*53ee8cc1Swenshuai.xi
161*53ee8cc1Swenshuai.xi if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
162*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_INTERFACE) ||
163*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_CONFIG) ||
164*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_DEVICE))
165*53ee8cc1Swenshuai.xi break;
166*53ee8cc1Swenshuai.xi #if 0
167*53ee8cc1Swenshuai.xi if ( header->bDescriptorType == USB_DT_OTG )
168*53ee8cc1Swenshuai.xi {
169*53ee8cc1Swenshuai.xi vdbg("OTG descriptor found, bmAttributes=0x%08X\n",buffer[2]);
170*53ee8cc1Swenshuai.xi OTG.otgd->desc.bLength = buffer[0];
171*53ee8cc1Swenshuai.xi OTG.otgd->desc.bDescriptorType = buffer[1];
172*53ee8cc1Swenshuai.xi OTG.otgd->desc.bmAttributes = buffer[2];
173*53ee8cc1Swenshuai.xi }
174*53ee8cc1Swenshuai.xi else
175*53ee8cc1Swenshuai.xi #else
176*53ee8cc1Swenshuai.xi dbg("skipping descriptor 0x%X,len=%d",
177*53ee8cc1Swenshuai.xi header->bDescriptorType,header->bLength);
178*53ee8cc1Swenshuai.xi #endif
179*53ee8cc1Swenshuai.xi numskipped++;
180*53ee8cc1Swenshuai.xi buffer += header->bLength;
181*53ee8cc1Swenshuai.xi size -= header->bLength;
182*53ee8cc1Swenshuai.xi parsed += header->bLength;
183*53ee8cc1Swenshuai.xi }
184*53ee8cc1Swenshuai.xi if (numskipped)
185*53ee8cc1Swenshuai.xi dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
186*53ee8cc1Swenshuai.xi
187*53ee8cc1Swenshuai.xi len = (int)(buffer - begin);
188*53ee8cc1Swenshuai.xi if (!len) {
189*53ee8cc1Swenshuai.xi endpoint->extra = NULL;
190*53ee8cc1Swenshuai.xi endpoint->extralen = 0;
191*53ee8cc1Swenshuai.xi return parsed;
192*53ee8cc1Swenshuai.xi }
193*53ee8cc1Swenshuai.xi
194*53ee8cc1Swenshuai.xi endpoint->extra = (unsigned char *) kmalloc(len, GFP_KERNEL);
195*53ee8cc1Swenshuai.xi
196*53ee8cc1Swenshuai.xi if (!endpoint->extra) {
197*53ee8cc1Swenshuai.xi usb_err("couldn't allocate memory for endpoint extra descriptors%s","");
198*53ee8cc1Swenshuai.xi endpoint->extralen = 0;
199*53ee8cc1Swenshuai.xi return parsed;
200*53ee8cc1Swenshuai.xi }
201*53ee8cc1Swenshuai.xi
202*53ee8cc1Swenshuai.xi memcpy(endpoint->extra, begin, len);
203*53ee8cc1Swenshuai.xi endpoint->extralen = len;
204*53ee8cc1Swenshuai.xi
205*53ee8cc1Swenshuai.xi return parsed;
206*53ee8cc1Swenshuai.xi }
207*53ee8cc1Swenshuai.xi
usb_release_intf(struct device_s * dev)208*53ee8cc1Swenshuai.xi static void usb_release_intf(struct device_s *dev)
209*53ee8cc1Swenshuai.xi {
210*53ee8cc1Swenshuai.xi struct usb_interface *intf;
211*53ee8cc1Swenshuai.xi int j;
212*53ee8cc1Swenshuai.xi int k;
213*53ee8cc1Swenshuai.xi
214*53ee8cc1Swenshuai.xi intf = to_usb_interface(dev);
215*53ee8cc1Swenshuai.xi
216*53ee8cc1Swenshuai.xi if (intf->altsetting) {
217*53ee8cc1Swenshuai.xi for (j = 0; j < intf->num_altsetting; j++) {
218*53ee8cc1Swenshuai.xi struct usb_host_interface *as = &intf->altsetting[j];
219*53ee8cc1Swenshuai.xi if (as->extra)
220*53ee8cc1Swenshuai.xi kfree(as->extra);
221*53ee8cc1Swenshuai.xi
222*53ee8cc1Swenshuai.xi if (as->endpoint) {
223*53ee8cc1Swenshuai.xi for (k = 0; k < as->desc.bNumEndpoints; k++)
224*53ee8cc1Swenshuai.xi if (as->endpoint[k].extra)
225*53ee8cc1Swenshuai.xi kfree(as->endpoint[k].extra);
226*53ee8cc1Swenshuai.xi kfree(as->endpoint);
227*53ee8cc1Swenshuai.xi }
228*53ee8cc1Swenshuai.xi }
229*53ee8cc1Swenshuai.xi kfree(intf->altsetting);
230*53ee8cc1Swenshuai.xi }
231*53ee8cc1Swenshuai.xi kfree(intf);
232*53ee8cc1Swenshuai.xi }
233*53ee8cc1Swenshuai.xi
234*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
usb_parse_interface(struct usb_device * dev,struct usb_interface * interface,unsigned char * buffer,int size)235*53ee8cc1Swenshuai.xi static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size)
236*53ee8cc1Swenshuai.xi {
237*53ee8cc1Swenshuai.xi int i, len, numskipped, retval, parsed = 0;
238*53ee8cc1Swenshuai.xi struct usb_descriptor_header *header;
239*53ee8cc1Swenshuai.xi struct usb_host_interface *ifp;
240*53ee8cc1Swenshuai.xi unsigned char *begin;
241*53ee8cc1Swenshuai.xi
242*53ee8cc1Swenshuai.xi interface->act_altsetting = 0;
243*53ee8cc1Swenshuai.xi interface->num_altsetting = 0;
244*53ee8cc1Swenshuai.xi interface->max_altsetting = USB_ALTSETTINGALLOC;
245*53ee8cc1Swenshuai.xi device_initialize(&interface->dev);
246*53ee8cc1Swenshuai.xi interface->dev.release = usb_release_intf;
247*53ee8cc1Swenshuai.xi
248*53ee8cc1Swenshuai.xi //get_device(&interface->dev);
249*53ee8cc1Swenshuai.xi
250*53ee8cc1Swenshuai.xi interface->altsetting = (struct usb_host_interface *) kmalloc(sizeof(*interface->altsetting) * interface->max_altsetting,
251*53ee8cc1Swenshuai.xi GFP_KERNEL);
252*53ee8cc1Swenshuai.xi
253*53ee8cc1Swenshuai.xi if (!interface->altsetting) {
254*53ee8cc1Swenshuai.xi usb_err("failed to alloc altsetting%s","");
255*53ee8cc1Swenshuai.xi return -1;
256*53ee8cc1Swenshuai.xi }
257*53ee8cc1Swenshuai.xi
258*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
259*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
260*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
261*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
262*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
263*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
264*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
265*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
266*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
267*53ee8cc1Swenshuai.xi while (size > 0) {
268*53ee8cc1Swenshuai.xi struct usb_interface_descriptor *d;
269*53ee8cc1Swenshuai.xi
270*53ee8cc1Swenshuai.xi if (interface->num_altsetting >= interface->max_altsetting) {
271*53ee8cc1Swenshuai.xi struct usb_host_interface *ptr;
272*53ee8cc1Swenshuai.xi int oldmas;
273*53ee8cc1Swenshuai.xi
274*53ee8cc1Swenshuai.xi oldmas = interface->max_altsetting;
275*53ee8cc1Swenshuai.xi interface->max_altsetting += USB_ALTSETTINGALLOC;
276*53ee8cc1Swenshuai.xi if (interface->max_altsetting > USB_MAXALTSETTING) {
277*53ee8cc1Swenshuai.xi usb_warn("too many alt settings (incr %d max %d)\n",
278*53ee8cc1Swenshuai.xi USB_ALTSETTINGALLOC, USB_MAXALTSETTING);
279*53ee8cc1Swenshuai.xi return -1;
280*53ee8cc1Swenshuai.xi }
281*53ee8cc1Swenshuai.xi
282*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
283*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
284*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
285*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
286*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
287*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
288*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
289*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
290*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
291*53ee8cc1Swenshuai.xi ptr = (struct usb_host_interface *) kmalloc(sizeof(*ptr) * interface->max_altsetting, GFP_KERNEL);
292*53ee8cc1Swenshuai.xi if (ptr == NULL) {
293*53ee8cc1Swenshuai.xi usb_err("failed to kmalloc interface->altsetting%s","");
294*53ee8cc1Swenshuai.xi return -1;
295*53ee8cc1Swenshuai.xi }
296*53ee8cc1Swenshuai.xi memcpy(ptr, interface->altsetting, sizeof(*interface->altsetting) * oldmas);
297*53ee8cc1Swenshuai.xi kfree(interface->altsetting);
298*53ee8cc1Swenshuai.xi interface->altsetting = ptr;
299*53ee8cc1Swenshuai.xi }
300*53ee8cc1Swenshuai.xi
301*53ee8cc1Swenshuai.xi ifp = interface->altsetting + interface->num_altsetting;
302*53ee8cc1Swenshuai.xi ifp->endpoint = NULL;
303*53ee8cc1Swenshuai.xi ifp->extra = NULL;
304*53ee8cc1Swenshuai.xi ifp->extralen = 0;
305*53ee8cc1Swenshuai.xi interface->num_altsetting++;
306*53ee8cc1Swenshuai.xi
307*53ee8cc1Swenshuai.xi memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE);
308*53ee8cc1Swenshuai.xi
309*53ee8cc1Swenshuai.xi buffer += ifp->desc.bLength;
310*53ee8cc1Swenshuai.xi parsed += ifp->desc.bLength;
311*53ee8cc1Swenshuai.xi size -= ifp->desc.bLength;
312*53ee8cc1Swenshuai.xi
313*53ee8cc1Swenshuai.xi begin = buffer;
314*53ee8cc1Swenshuai.xi numskipped = 0;
315*53ee8cc1Swenshuai.xi
316*53ee8cc1Swenshuai.xi while ((U32)size >= sizeof(struct usb_descriptor_header)) {
317*53ee8cc1Swenshuai.xi header = (struct usb_descriptor_header *)buffer;
318*53ee8cc1Swenshuai.xi
319*53ee8cc1Swenshuai.xi if (header->bLength < 2) {
320*53ee8cc1Swenshuai.xi usb_err("invalid descriptor len of %d", header->bLength);
321*53ee8cc1Swenshuai.xi return -1;
322*53ee8cc1Swenshuai.xi }
323*53ee8cc1Swenshuai.xi
324*53ee8cc1Swenshuai.xi if ((header->bDescriptorType == USB_DT_INTERFACE) ||
325*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_ENDPOINT) ||
326*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_CONFIG) ||
327*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_DEVICE))
328*53ee8cc1Swenshuai.xi break;
329*53ee8cc1Swenshuai.xi
330*53ee8cc1Swenshuai.xi numskipped++;
331*53ee8cc1Swenshuai.xi
332*53ee8cc1Swenshuai.xi buffer += header->bLength;
333*53ee8cc1Swenshuai.xi parsed += header->bLength;
334*53ee8cc1Swenshuai.xi size -= header->bLength;
335*53ee8cc1Swenshuai.xi }
336*53ee8cc1Swenshuai.xi
337*53ee8cc1Swenshuai.xi if (numskipped)
338*53ee8cc1Swenshuai.xi dbg("skipped %d class/vendor specific interface descriptors", numskipped);
339*53ee8cc1Swenshuai.xi
340*53ee8cc1Swenshuai.xi len = (int)(buffer - begin);
341*53ee8cc1Swenshuai.xi if (len) {
342*53ee8cc1Swenshuai.xi ifp->extra = (unsigned char*) kmalloc(len, GFP_KERNEL);
343*53ee8cc1Swenshuai.xi
344*53ee8cc1Swenshuai.xi if (!ifp->extra) {
345*53ee8cc1Swenshuai.xi usb_err("couldn't allocate memory for interface extra descriptors%s","");
346*53ee8cc1Swenshuai.xi ifp->extralen = 0;
347*53ee8cc1Swenshuai.xi return -1;
348*53ee8cc1Swenshuai.xi }
349*53ee8cc1Swenshuai.xi memcpy(ifp->extra, begin, len);
350*53ee8cc1Swenshuai.xi ifp->extralen = len;
351*53ee8cc1Swenshuai.xi }
352*53ee8cc1Swenshuai.xi
353*53ee8cc1Swenshuai.xi header = (struct usb_descriptor_header *)buffer;
354*53ee8cc1Swenshuai.xi if (((U32)size >= sizeof(struct usb_descriptor_header)) &&
355*53ee8cc1Swenshuai.xi ((header->bDescriptorType == USB_DT_CONFIG) ||
356*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_DEVICE)))
357*53ee8cc1Swenshuai.xi return parsed;
358*53ee8cc1Swenshuai.xi
359*53ee8cc1Swenshuai.xi if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) {
360*53ee8cc1Swenshuai.xi usb_warn("too many endpoints%s","");
361*53ee8cc1Swenshuai.xi return -1;
362*53ee8cc1Swenshuai.xi }
363*53ee8cc1Swenshuai.xi else if ( ifp->desc.bNumEndpoints == 0 )
364*53ee8cc1Swenshuai.xi {
365*53ee8cc1Swenshuai.xi goto skip_ep_pase;
366*53ee8cc1Swenshuai.xi }
367*53ee8cc1Swenshuai.xi
368*53ee8cc1Swenshuai.xi ifp->endpoint = (struct usb_host_endpoint *)
369*53ee8cc1Swenshuai.xi kmalloc(ifp->desc.bNumEndpoints *
370*53ee8cc1Swenshuai.xi sizeof(struct usb_host_endpoint), GFP_KERNEL);
371*53ee8cc1Swenshuai.xi if (!ifp->endpoint) {
372*53ee8cc1Swenshuai.xi usb_err("out of memory%s","");
373*53ee8cc1Swenshuai.xi return -1;
374*53ee8cc1Swenshuai.xi }
375*53ee8cc1Swenshuai.xi
376*53ee8cc1Swenshuai.xi memset(ifp->endpoint, 0, ifp->desc.bNumEndpoints *
377*53ee8cc1Swenshuai.xi sizeof(struct usb_host_endpoint));
378*53ee8cc1Swenshuai.xi
379*53ee8cc1Swenshuai.xi for (i = 0; i < ifp->desc.bNumEndpoints; i++) {
380*53ee8cc1Swenshuai.xi header = (struct usb_descriptor_header *)buffer;
381*53ee8cc1Swenshuai.xi
382*53ee8cc1Swenshuai.xi if (header->bLength > size) {
383*53ee8cc1Swenshuai.xi usb_err("ran out of descriptors parsing%s","");
384*53ee8cc1Swenshuai.xi return -1;
385*53ee8cc1Swenshuai.xi }
386*53ee8cc1Swenshuai.xi
387*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
388*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
389*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
390*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
391*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
392*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
393*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
394*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
395*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
396*53ee8cc1Swenshuai.xi retval = usb_parse_endpoint(dev, ifp->endpoint + i, buffer, size);
397*53ee8cc1Swenshuai.xi if (retval < 0)
398*53ee8cc1Swenshuai.xi return retval;
399*53ee8cc1Swenshuai.xi
400*53ee8cc1Swenshuai.xi buffer += retval;
401*53ee8cc1Swenshuai.xi parsed += retval;
402*53ee8cc1Swenshuai.xi size -= retval;
403*53ee8cc1Swenshuai.xi }
404*53ee8cc1Swenshuai.xi skip_ep_pase:
405*53ee8cc1Swenshuai.xi d = (struct usb_interface_descriptor *)buffer;
406*53ee8cc1Swenshuai.xi if (size < USB_DT_INTERFACE_SIZE
407*53ee8cc1Swenshuai.xi || d->bDescriptorType != USB_DT_INTERFACE
408*53ee8cc1Swenshuai.xi || !d->bAlternateSetting)
409*53ee8cc1Swenshuai.xi return parsed;
410*53ee8cc1Swenshuai.xi }
411*53ee8cc1Swenshuai.xi
412*53ee8cc1Swenshuai.xi return parsed;
413*53ee8cc1Swenshuai.xi }
414*53ee8cc1Swenshuai.xi
usb_parse_configuration(struct usb_device * dev,struct usb_host_config * config,char * buffer)415*53ee8cc1Swenshuai.xi int usb_parse_configuration(struct usb_device *dev, struct usb_host_config *config, char *buffer)
416*53ee8cc1Swenshuai.xi {
417*53ee8cc1Swenshuai.xi int i, size;
418*53ee8cc1Swenshuai.xi int retval = -EINVAL;
419*53ee8cc1Swenshuai.xi struct usb_descriptor_header *header;
420*53ee8cc1Swenshuai.xi
421*53ee8cc1Swenshuai.xi memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
422*53ee8cc1Swenshuai.xi config->desc.wTotalLength = LE16ToCPU(config->desc.wTotalLength);
423*53ee8cc1Swenshuai.xi size = config->desc.wTotalLength;
424*53ee8cc1Swenshuai.xi
425*53ee8cc1Swenshuai.xi //for (i = 0; i < USB_MAXINTERFACES; ++i)
426*53ee8cc1Swenshuai.xi // config->interface[i] = (struct usb_interface)NULL;
427*53ee8cc1Swenshuai.xi
428*53ee8cc1Swenshuai.xi if (config->desc.bNumInterfaces > USB_MAXINTERFACES) {
429*53ee8cc1Swenshuai.xi usb_warn("too many interfaces%s","");
430*53ee8cc1Swenshuai.xi goto error;
431*53ee8cc1Swenshuai.xi }
432*53ee8cc1Swenshuai.xi
433*53ee8cc1Swenshuai.xi for (i = 0; i < config->desc.bNumInterfaces; ++i) {
434*53ee8cc1Swenshuai.xi config->interface[i] = (struct usb_interface *) kmalloc(sizeof(struct usb_interface), GFP_KERNEL);
435*53ee8cc1Swenshuai.xi dbg("kmalloc IF %p, numif %i", config->interface[i], i);
436*53ee8cc1Swenshuai.xi if (!config->interface[i]) {
437*53ee8cc1Swenshuai.xi usb_err("out of memory%s","");
438*53ee8cc1Swenshuai.xi retval = -ENOMEM;
439*53ee8cc1Swenshuai.xi goto error;
440*53ee8cc1Swenshuai.xi }
441*53ee8cc1Swenshuai.xi memset(config->interface[i], 0x00, sizeof(struct usb_interface));
442*53ee8cc1Swenshuai.xi }
443*53ee8cc1Swenshuai.xi
444*53ee8cc1Swenshuai.xi buffer += config->desc.bLength;
445*53ee8cc1Swenshuai.xi size -= config->desc.bLength;
446*53ee8cc1Swenshuai.xi
447*53ee8cc1Swenshuai.xi config->extra = NULL;
448*53ee8cc1Swenshuai.xi config->extralen = 0;
449*53ee8cc1Swenshuai.xi
450*53ee8cc1Swenshuai.xi for (i = 0; i < config->desc.bNumInterfaces; i++) {
451*53ee8cc1Swenshuai.xi int numskipped, len;
452*53ee8cc1Swenshuai.xi char *begin;
453*53ee8cc1Swenshuai.xi
454*53ee8cc1Swenshuai.xi begin = buffer;
455*53ee8cc1Swenshuai.xi numskipped = 0;
456*53ee8cc1Swenshuai.xi while ((U32)size >= sizeof(struct usb_descriptor_header)) {
457*53ee8cc1Swenshuai.xi header = (struct usb_descriptor_header *)buffer;
458*53ee8cc1Swenshuai.xi
459*53ee8cc1Swenshuai.xi if ((header->bLength > size) || (header->bLength < 2)) {
460*53ee8cc1Swenshuai.xi usb_err("invalid descriptor length of %d", header->bLength);
461*53ee8cc1Swenshuai.xi return -1;
462*53ee8cc1Swenshuai.xi }
463*53ee8cc1Swenshuai.xi
464*53ee8cc1Swenshuai.xi if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
465*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_INTERFACE) ||
466*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_CONFIG) ||
467*53ee8cc1Swenshuai.xi (header->bDescriptorType == USB_DT_DEVICE))
468*53ee8cc1Swenshuai.xi break;
469*53ee8cc1Swenshuai.xi
470*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
471*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
472*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
473*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
474*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
475*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
476*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
477*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
478*53ee8cc1Swenshuai.xi /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
479*53ee8cc1Swenshuai.xi dbg("skipping descriptor 0x%X", header->bDescriptorType);
480*53ee8cc1Swenshuai.xi numskipped++;
481*53ee8cc1Swenshuai.xi buffer += header->bLength;
482*53ee8cc1Swenshuai.xi size -= header->bLength;
483*53ee8cc1Swenshuai.xi }
484*53ee8cc1Swenshuai.xi if (numskipped)
485*53ee8cc1Swenshuai.xi dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
486*53ee8cc1Swenshuai.xi
487*53ee8cc1Swenshuai.xi len = (int)(buffer - begin);
488*53ee8cc1Swenshuai.xi if (len) {
489*53ee8cc1Swenshuai.xi if (config->extralen) {
490*53ee8cc1Swenshuai.xi usb_warn("extra config descriptor%s","");
491*53ee8cc1Swenshuai.xi } else {
492*53ee8cc1Swenshuai.xi config->extra = (unsigned char*) kmalloc(len, GFP_KERNEL);
493*53ee8cc1Swenshuai.xi if (!config->extra) {
494*53ee8cc1Swenshuai.xi usb_err("couldn't allocate memory for config extra descriptors%s","");
495*53ee8cc1Swenshuai.xi config->extralen = 0;
496*53ee8cc1Swenshuai.xi return -1;
497*53ee8cc1Swenshuai.xi }
498*53ee8cc1Swenshuai.xi
499*53ee8cc1Swenshuai.xi memcpy(config->extra, begin, len);
500*53ee8cc1Swenshuai.xi config->extralen = len;
501*53ee8cc1Swenshuai.xi }
502*53ee8cc1Swenshuai.xi }
503*53ee8cc1Swenshuai.xi
504*53ee8cc1Swenshuai.xi retval = usb_parse_interface(dev, config->interface[i], (unsigned char*) buffer, size);
505*53ee8cc1Swenshuai.xi if (retval < 0)
506*53ee8cc1Swenshuai.xi return retval;
507*53ee8cc1Swenshuai.xi
508*53ee8cc1Swenshuai.xi buffer += retval;
509*53ee8cc1Swenshuai.xi size -= retval;
510*53ee8cc1Swenshuai.xi }
511*53ee8cc1Swenshuai.xi
512*53ee8cc1Swenshuai.xi return size;
513*53ee8cc1Swenshuai.xi error:
514*53ee8cc1Swenshuai.xi for (i = 0; i < USB_MAXINTERFACES; ++i)
515*53ee8cc1Swenshuai.xi kfree(config->interface[i]);
516*53ee8cc1Swenshuai.xi return retval;
517*53ee8cc1Swenshuai.xi }
518*53ee8cc1Swenshuai.xi
usb_destroy_configuration(struct usb_device * dev)519*53ee8cc1Swenshuai.xi void usb_destroy_configuration(struct usb_device *dev)
520*53ee8cc1Swenshuai.xi {
521*53ee8cc1Swenshuai.xi int c, i;
522*53ee8cc1Swenshuai.xi
523*53ee8cc1Swenshuai.xi if (!dev->config)
524*53ee8cc1Swenshuai.xi return;
525*53ee8cc1Swenshuai.xi
526*53ee8cc1Swenshuai.xi if (dev->rawdescriptors) {
527*53ee8cc1Swenshuai.xi for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
528*53ee8cc1Swenshuai.xi kfree(dev->rawdescriptors[i]);
529*53ee8cc1Swenshuai.xi
530*53ee8cc1Swenshuai.xi kfree(dev->rawdescriptors);
531*53ee8cc1Swenshuai.xi }
532*53ee8cc1Swenshuai.xi
533*53ee8cc1Swenshuai.xi for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
534*53ee8cc1Swenshuai.xi struct usb_host_config *cf = &dev->config[c];
535*53ee8cc1Swenshuai.xi
536*53ee8cc1Swenshuai.xi if (!cf->interface)
537*53ee8cc1Swenshuai.xi break;
538*53ee8cc1Swenshuai.xi
539*53ee8cc1Swenshuai.xi for (i = 0; i < cf->desc.bNumInterfaces; i++) {
540*53ee8cc1Swenshuai.xi //struct usb_interface *ifp = cf->interface[i];
541*53ee8cc1Swenshuai.xi put_device(&ifp->dev);
542*53ee8cc1Swenshuai.xi }
543*53ee8cc1Swenshuai.xi }
544*53ee8cc1Swenshuai.xi kfree(dev->config);
545*53ee8cc1Swenshuai.xi }
546*53ee8cc1Swenshuai.xi
547*53ee8cc1Swenshuai.xi
usb_get_configuration(struct usb_device * dev)548*53ee8cc1Swenshuai.xi int usb_get_configuration(struct usb_device *dev)
549*53ee8cc1Swenshuai.xi {
550*53ee8cc1Swenshuai.xi int result;
551*53ee8cc1Swenshuai.xi U32 cfgno, length;
552*53ee8cc1Swenshuai.xi unsigned char *buffer;
553*53ee8cc1Swenshuai.xi unsigned char *bigbuffer;
554*53ee8cc1Swenshuai.xi struct usb_config_descriptor *desc;
555*53ee8cc1Swenshuai.xi int i=0;
556*53ee8cc1Swenshuai.xi
557*53ee8cc1Swenshuai.xi if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
558*53ee8cc1Swenshuai.xi usb_warn("too many configurations%s","");
559*53ee8cc1Swenshuai.xi return -EINVAL;
560*53ee8cc1Swenshuai.xi }
561*53ee8cc1Swenshuai.xi
562*53ee8cc1Swenshuai.xi if (dev->descriptor.bNumConfigurations < 1) {
563*53ee8cc1Swenshuai.xi usb_warn("not enough configurations%s","");
564*53ee8cc1Swenshuai.xi return -EINVAL;
565*53ee8cc1Swenshuai.xi }
566*53ee8cc1Swenshuai.xi
567*53ee8cc1Swenshuai.xi dev->config = (struct usb_host_config *)
568*53ee8cc1Swenshuai.xi kmalloc(dev->descriptor.bNumConfigurations *
569*53ee8cc1Swenshuai.xi sizeof(struct usb_host_config), GFP_KERNEL);
570*53ee8cc1Swenshuai.xi if (!dev->config) {
571*53ee8cc1Swenshuai.xi usb_err("out of memory%s","");
572*53ee8cc1Swenshuai.xi return -ENOMEM;
573*53ee8cc1Swenshuai.xi }
574*53ee8cc1Swenshuai.xi memset(dev->config, 0, dev->descriptor.bNumConfigurations *
575*53ee8cc1Swenshuai.xi sizeof(struct usb_host_config));
576*53ee8cc1Swenshuai.xi
577*53ee8cc1Swenshuai.xi dev->rawdescriptors = (char **)kmalloc(sizeof(char *) *
578*53ee8cc1Swenshuai.xi dev->descriptor.bNumConfigurations, GFP_KERNEL);
579*53ee8cc1Swenshuai.xi if (!dev->rawdescriptors) {
580*53ee8cc1Swenshuai.xi usb_err("out of memory%s","");
581*53ee8cc1Swenshuai.xi return -ENOMEM;
582*53ee8cc1Swenshuai.xi }
583*53ee8cc1Swenshuai.xi
584*53ee8cc1Swenshuai.xi buffer = (unsigned char*) kmalloc(8, GFP_KERNEL);
585*53ee8cc1Swenshuai.xi if (!buffer) {
586*53ee8cc1Swenshuai.xi usb_err("unable to allocate memory for configuration descriptors%s","");
587*53ee8cc1Swenshuai.xi return -ENOMEM;
588*53ee8cc1Swenshuai.xi }
589*53ee8cc1Swenshuai.xi desc = (struct usb_config_descriptor *)buffer;
590*53ee8cc1Swenshuai.xi
591*53ee8cc1Swenshuai.xi for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
592*53ee8cc1Swenshuai.xi result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
593*53ee8cc1Swenshuai.xi if (result < 8) {
594*53ee8cc1Swenshuai.xi if (result < 0)
595*53ee8cc1Swenshuai.xi {
596*53ee8cc1Swenshuai.xi usb_err("unable to get descriptor%s","");
597*53ee8cc1Swenshuai.xi }
598*53ee8cc1Swenshuai.xi else {
599*53ee8cc1Swenshuai.xi usb_err("config descriptor too short (expected %i, got %i)", 8, result);
600*53ee8cc1Swenshuai.xi result = -EINVAL;
601*53ee8cc1Swenshuai.xi }
602*53ee8cc1Swenshuai.xi goto err;
603*53ee8cc1Swenshuai.xi }
604*53ee8cc1Swenshuai.xi
605*53ee8cc1Swenshuai.xi length = LE16ToCPU(desc->wTotalLength);
606*53ee8cc1Swenshuai.xi bigbuffer = (unsigned char*) kmalloc(length, GFP_KERNEL);
607*53ee8cc1Swenshuai.xi if (!bigbuffer) {
608*53ee8cc1Swenshuai.xi do
609*53ee8cc1Swenshuai.xi {
610*53ee8cc1Swenshuai.xi length = LE16ToCPU(desc->wTotalLength);
611*53ee8cc1Swenshuai.xi i++;
612*53ee8cc1Swenshuai.xi }while(length == 0 );
613*53ee8cc1Swenshuai.xi usb_err("unable to allocate (len=%d) memory for configuration descriptors, i=%d",length,i);
614*53ee8cc1Swenshuai.xi result = -ENOMEM;
615*53ee8cc1Swenshuai.xi goto err;
616*53ee8cc1Swenshuai.xi }
617*53ee8cc1Swenshuai.xi
618*53ee8cc1Swenshuai.xi result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
619*53ee8cc1Swenshuai.xi if (result < 0) {
620*53ee8cc1Swenshuai.xi usb_err("couldn't get all of config descriptors%s","");
621*53ee8cc1Swenshuai.xi kfree(bigbuffer);
622*53ee8cc1Swenshuai.xi goto err;
623*53ee8cc1Swenshuai.xi }
624*53ee8cc1Swenshuai.xi
625*53ee8cc1Swenshuai.xi if ((U32)result < length) {
626*53ee8cc1Swenshuai.xi usb_err("config descriptor too short (expected %i, got %i)", length, result);
627*53ee8cc1Swenshuai.xi result = -EINVAL;
628*53ee8cc1Swenshuai.xi kfree(bigbuffer);
629*53ee8cc1Swenshuai.xi goto err;
630*53ee8cc1Swenshuai.xi }
631*53ee8cc1Swenshuai.xi
632*53ee8cc1Swenshuai.xi dev->rawdescriptors[cfgno] = (char*) bigbuffer;
633*53ee8cc1Swenshuai.xi
634*53ee8cc1Swenshuai.xi result = usb_parse_configuration(dev, &dev->config[cfgno], (char*) bigbuffer);
635*53ee8cc1Swenshuai.xi if (result > 0) {
636*53ee8cc1Swenshuai.xi dbg("descriptor data left%s","");
637*53ee8cc1Swenshuai.xi }
638*53ee8cc1Swenshuai.xi else if (result < 0) {
639*53ee8cc1Swenshuai.xi result = -EINVAL;
640*53ee8cc1Swenshuai.xi goto err;
641*53ee8cc1Swenshuai.xi }
642*53ee8cc1Swenshuai.xi }
643*53ee8cc1Swenshuai.xi
644*53ee8cc1Swenshuai.xi kfree(buffer);
645*53ee8cc1Swenshuai.xi return 0;
646*53ee8cc1Swenshuai.xi err:
647*53ee8cc1Swenshuai.xi kfree(buffer);
648*53ee8cc1Swenshuai.xi dev->descriptor.bNumConfigurations = cfgno;
649*53ee8cc1Swenshuai.xi return result;
650*53ee8cc1Swenshuai.xi }
651*53ee8cc1Swenshuai.xi
652*53ee8cc1Swenshuai.xi
653*53ee8cc1Swenshuai.xi
654*53ee8cc1Swenshuai.xi
655*53ee8cc1Swenshuai.xi
656