xref: /utopia/UTPA2-700.0.x/modules/usb/drv/usb_ecos/usbhost/drvMsg.c (revision 53ee8cc121a030b8d368113ac3e966b4705770ef)
1 //<MStar Software>
2 //******************************************************************************
3 // MStar Software
4 // Copyright (c) 2010 - 2012 MStar Semiconductor, Inc. All rights reserved.
5 // All software, firmware and related documentation herein ("MStar Software") are
6 // intellectual property of MStar Semiconductor, Inc. ("MStar") and protected by
7 // law, including, but not limited to, copyright law and international treaties.
8 // Any use, modification, reproduction, retransmission, or republication of all
9 // or part of MStar Software is expressly prohibited, unless prior written
10 // permission has been granted by MStar.
11 //
12 // By accessing, browsing and/or using MStar Software, you acknowledge that you
13 // have read, understood, and agree, to be bound by below terms ("Terms") and to
14 // comply with all applicable laws and regulations:
15 //
16 // 1. MStar shall retain any and all right, ownership and interest to MStar
17 //    Software and any modification/derivatives thereof.
18 //    No right, ownership, or interest to MStar Software and any
19 //    modification/derivatives thereof is transferred to you under Terms.
20 //
21 // 2. You understand that MStar Software might include, incorporate or be
22 //    supplied together with third party`s software and the use of MStar
23 //    Software may require additional licenses from third parties.
24 //    Therefore, you hereby agree it is your sole responsibility to separately
25 //    obtain any and all third party right and license necessary for your use of
26 //    such third party`s software.
27 //
28 // 3. MStar Software and any modification/derivatives thereof shall be deemed as
29 //    MStar`s confidential information and you agree to keep MStar`s
30 //    confidential information in strictest confidence and not disclose to any
31 //    third party.
32 //
33 // 4. MStar Software is provided on an "AS IS" basis without warranties of any
34 //    kind. Any warranties are hereby expressly disclaimed by MStar, including
35 //    without limitation, any warranties of merchantability, non-infringement of
36 //    intellectual property rights, fitness for a particular purpose, error free
37 //    and in conformity with any international standard.  You agree to waive any
38 //    claim against MStar for any loss, damage, cost or expense that you may
39 //    incur related to your use of MStar Software.
40 //    In no event shall MStar be liable for any direct, indirect, incidental or
41 //    consequential damages, including without limitation, lost of profit or
42 //    revenues, lost or damage of data, and unauthorized system use.
43 //    You agree that this Section 4 shall still apply without being affected
44 //    even if MStar Software has been modified by MStar in accordance with your
45 //    request or instruction for your use, except otherwise agreed by both
46 //    parties in writing.
47 //
48 // 5. If requested, MStar may from time to time provide technical supports or
49 //    services in relation with MStar Software to you for your use of
50 //    MStar Software in conjunction with your or your customer`s product
51 //    ("Services").
52 //    You understand and agree that, except otherwise agreed by both parties in
53 //    writing, Services are provided on an "AS IS" basis and the warranty
54 //    disclaimer set forth in Section 4 above shall apply.
55 //
56 // 6. Nothing contained herein shall be construed as by implication, estoppels
57 //    or otherwise:
58 //    (a) conferring any license or right to use MStar name, trademark, service
59 //        mark, symbol or any other identification;
60 //    (b) obligating MStar or any of its affiliates to furnish any person,
61 //        including without limitation, you and your customers, any assistance
62 //        of any kind whatsoever, or any information; or
63 //    (c) conferring any license or right under any intellectual property right.
64 //
65 // 7. These terms shall be governed by and construed in accordance with the laws
66 //    of Taiwan, R.O.C., excluding its conflict of law rules.
67 //    Any and all dispute arising out hereof or related hereto shall be finally
68 //    settled by arbitration referred to the Chinese Arbitration Association,
69 //    Taipei in accordance with the ROC Arbitration Law and the Arbitration
70 //    Rules of the Association by three (3) arbitrators appointed in accordance
71 //    with the said Rules.
72 //    The place of arbitration shall be in Taipei, Taiwan and the language shall
73 //    be English.
74 //    The arbitration award shall be final and binding to both parties.
75 //
76 //******************************************************************************
77 //<MStar Software>
78 
79 #include <MsCommon.h>
80 #include <cyg/hal/hal_if.h>
81 
82 #include  "include/drvConfig.h"
83 
84 #ifdef CONFIG_DEBUG
85 #define DEBUG
86 #else
87 #undef DEBUG
88 #endif
89 
90 #include  "include/drvCompiler.h"
91 #include  "include/drvErrno.h"
92 #include  "include/drvPorts.h"
93 #include  "include/drvPCIMEM.h"
94 #include  "include/drvTimer.h"
95 #include  "include/drvList.h"
96 
97 #include "include/drvUSB.h"
98 #include "drvHCD.h"
99 #include "include/drvCPE_AMBA.h"
100 #include "drvEHCI.h"
101 
102 #if 1
103 
104 char usb_string_buf[64];
105 
106 struct usb_api_data {
107   //wait_queue_head_t wqh;
108   int done;
109 };
110 
usb_api_blocking_completion(struct urb * urb,struct pt_regs * regs)111 static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
112 {
113 	struct usb_api_data *awd = (struct usb_api_data *)urb->context;
114 
115 
116 	if (urb->SetDMABuf != NULL)
117 	{
118 		//MsOS_FreeMemory(urb->SetDMABuf, gs32NonCachedPoolID_MIU0 );
119 		Usb_FreeNonCachedMemory(urb->SetDMABuf);
120 
121 		urb->SetDMABuf = NULL;
122 	}
123 
124 	if (urb->TxDMABuf != NULL)
125 	{
126 		if (usb_pipein(urb->pipe))
127         {
128             #ifdef DEBUG_PERFORMANCE
129             if (urb->transfer_buffer_length >= 512)
130                 diag_printf("usb_api_blocking_completion: copy length: 0x%lx \n", urb->transfer_buffer_length);
131             #endif
132 			memcpy(urb->transfer_buffer, urb->TxDMABuf, urb->transfer_buffer_length);
133         }
134 		//MsOS_FreeMemory(urb->TxDMABuf,gs32NonCachedPoolID_MIU0 );
135 		Usb_FreeNonCachedMemory(urb->TxDMABuf);
136 
137 		urb->TxDMABuf = NULL;
138 	}
139 
140 	awd->done = 1;
141 	wmb();
142 
143 	wake_up(&awd->wqh);
144 }
145 
usb_start_wait_urb(struct urb * urb,int timeout,int * actual_length)146 static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
147 {
148   struct usb_api_data awd;
149   int status;
150   U32 d_cnt=0;
151 
152   DECLARE_WAITQUEUE(wait, current);
153   init_waitqueue_head(&awd.wqh);
154 
155   awd.done = 0;
156 
157   set_current_state(TASK_UNINTERRUPTIBLE);
158   add_wait_queue(&awd.wqh, &wait);
159 
160   urb->context = &awd;
161   status = usb_submit_urb(urb, GFP_ATOMIC);
162   if (status) {
163 
164     usb_free_urb(urb);
165 
166     set_current_state(TASK_RUNNING);
167     remove_wait_queue(&awd.wqh, &wait);
168     return status;
169   }
170 
171   while ( timeout && (awd.done == 0) )
172   {
173     if ( d_cnt > (U32) timeout)
174     {
175       timeout =0;
176       break;
177     }
178     else
179     {
180       //mdelay(1);//tick base is 1 ms
181       HAL_DELAY_US(1000);
182       d_cnt+=1;
183     }
184     set_current_state(TASK_UNINTERRUPTIBLE);
185     rmb();
186   }
187   //dbg("Done(%d) or time-out,tick is %ld\n",awd.done,jiffies);
188 
189   set_current_state(TASK_RUNNING);
190   remove_wait_queue(&awd.wqh, &wait);
191 
192   if (!timeout && !awd.done) {
193     if (urb->status != -EINPROGRESS) {  /* No callback?!! */
194       printk(KERN_ERR "usb: raced timeout, "
195           "pipe 0x%x status %d time left %d\n",
196           urb->pipe, urb->status, timeout);
197       status = urb->status;
198     } else {
199         struct usb_hcd * hcd =  urb->dev->bus->hcpriv;
200         diag_printf("usb_control/bulk_msg: timeout... %d \n", urb->status);
201 
202         diag_printf("<usb_start_wait_urb> set Bad Device...............................................\n");
203         hcd->isBadDevice = TRUE;
204         hcd->badDeviceCnt++;
205 
206       if (usb_unlink_urb(urb) == -ETIMEDOUT)
207       {
208         diag_printf("timeout retry\n");
209         usb_unlink_urb(urb);
210       }
211       diag_printf("unllnk urb ok\n");
212       status = -ETIMEDOUT;
213     }
214   } else
215   status = urb->status;
216 
217   if (actual_length)
218     *actual_length = urb->actual_length;
219 
220   usb_free_urb(urb);
221   return status;
222 }
223 
usb_internal_control_msg(struct usb_device * usb_dev,unsigned int pipe,struct usb_ctrlrequest * cmd,void * data,int len,int timeout)224 int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
225           struct usb_ctrlrequest *cmd,  void *data, int len, int timeout)
226 {
227   struct urb *urb;
228   int retv;
229   int length;
230 
231   urb = usb_alloc_urb(0, GFP_NOIO);
232   if (!urb)
233     return -ENOMEM;
234 
235   usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,
236        usb_api_blocking_completion, 0);
237   retv = usb_start_wait_urb(urb, timeout, &length);
238   if (retv < 0)
239      {
240      	diag_printf("usb_start_wait_urb retv:%d \n",-retv);
241        	return retv;
242      }
243   else
244     return length;
245 }
246 
usb_control_msg(struct usb_device * dev,unsigned int pipe,unsigned char request,unsigned char requesttype,unsigned short value,unsigned short index,void * data,unsigned short size,int timeout)247 int usb_control_msg(struct usb_device *dev, unsigned int pipe, unsigned char request, unsigned char requesttype,
248        unsigned short value, unsigned short index, void *data, unsigned short size, int timeout)
249 {
250   struct usb_ctrlrequest *dr = (struct usb_ctrlrequest*) kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
251   int ret;
252   U32 addr_t;
253 
254   if (!dr)
255     return -ENOMEM;
256 
257   addr_t = (U32)dr;
258   dr->bRequestType= requesttype;
259   dr->bRequest = request;
260   dr->wValue = CPUToLE16(value);
261   dr->wIndex = CPUToLE16(index);
262   dr->wLength = CPUToLE16(size);
263 
264   ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
265 
266   kfree((void *)addr_t);
267 
268   return ret;
269 }
270 
271 
usb_bulk_msg(struct usb_device * usb_dev,unsigned int pipe,void * data,int len,int * actual_length,int timeout)272 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
273       void *data, int len, int *actual_length, int timeout)
274 {
275   struct urb *urb;
276 
277   if (len < 0)
278     return -EINVAL;
279 
280   urb=usb_alloc_urb(0, GFP_KERNEL);
281   if (!urb)
282     return -ENOMEM;
283 
284   usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
285         usb_api_blocking_completion, 0);
286 
287   return usb_start_wait_urb(urb,timeout,actual_length);
288 }
289 
usb_get_descriptor(struct usb_device * dev,unsigned char type,unsigned char index,void * buf,int size)290 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
291 {
292   int ii = 5;
293   int relt;
294 
295 /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
296   memset(buf,0,size);
297 
298 /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
299   while (ii--) {
300     if ((relt = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
301             USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
302             (type << 8) + index, 0, buf, size,
303             HZ * USB_CTRL_GET_TIMEOUT)) > 0
304         || relt == -EPIPE)
305       break;
306   }
307   return relt;
308 }
309 
usb_get_string(struct usb_device * dev,unsigned short langid,unsigned char index,void * buf,int size)310 int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
311 {
312 /*USB HOST USB HOST USB HOST USB HOST USB HOST USB HOST*/
313   return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
314     USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
315     (USB_DT_STRING << 8) + index, langid, buf, size,
316     HZ * USB_CTRL_GET_TIMEOUT);
317 }
318 
usb_get_device_descriptor(struct usb_device * dev)319 int usb_get_device_descriptor(struct usb_device *dev)
320 {
321   int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,
322              sizeof(dev->descriptor));
323   if (ret >= 0) {
324     dev->descriptor.bcdUSB = LE16ToCPU(dev->descriptor.bcdUSB);
325     dev->descriptor.idVendor = LE16ToCPU(dev->descriptor.idVendor);
326     dev->descriptor.idProduct = LE16ToCPU(dev->descriptor.idProduct);
327     dev->descriptor.bcdDevice = LE16ToCPU(dev->descriptor.bcdDevice);
328   }
329   return ret;
330 }
331 
usb_get_status(struct usb_device * dev,int type,int target,void * data)332 int usb_get_status(struct usb_device *dev, int type, int target, void *data)
333 {
334   return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
335     USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2,
336     HZ * USB_CTRL_GET_TIMEOUT);
337 }
338 
usb_clear_halt(struct usb_device * dev,int pipe)339 int usb_clear_halt(struct usb_device *dev, int pipe)
340 {
341   int result;
342   int endp = usb_pipeendpoint(pipe);
343 
344   if (usb_pipein (pipe))
345     endp |= USB_DIR_IN;
346 
347   result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
348     USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0,
349     HZ * USB_CTRL_SET_TIMEOUT);
350 
351   if (result < 0)
352     return result;
353 
354   usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
355   usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
356 
357   return 0;
358 }
359 
usb_disable_endpoint(struct usb_device * dev,U32 epaddr)360 void usb_disable_endpoint(struct usb_device *dev, U32 epaddr)
361 {
362   if (dev && dev->bus && dev->bus->op && dev->bus->op->disable)
363     dev->bus->op->disable(dev, epaddr);
364   else {
365     U32 epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
366 
367     if (usb_endpoint_out(epaddr)) {
368       usb_endpoint_halt(dev, epnum, 1);
369       dev->epmaxpacketout[epnum] = 0;
370     } else {
371       usb_endpoint_halt(dev, epnum, 0);
372       dev->epmaxpacketin[epnum] = 0;
373     }
374   }
375 }
376 
usb_disable_interface(struct usb_device * dev,struct usb_interface * intf)377 void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
378 {
379   struct usb_host_interface *hintf =
380       &intf->altsetting[intf->act_altsetting];
381   int i;
382 
383   for (i = 0; i < hintf->desc.bNumEndpoints; ++i) {
384     usb_disable_endpoint(dev,
385         hintf->endpoint[i].desc.bEndpointAddress);
386   }
387 }
388 
usb_disable_device(struct usb_device * dev,int skip_ep0)389 void usb_disable_device(struct usb_device *dev, int skip_ep0)
390 {
391   int i;
392 
393   dbg("nuking URBs for device %s", dev->dev.bus_id);
394   for (i = skip_ep0; i < 16; ++i) {
395     usb_disable_endpoint(dev, i);
396     usb_disable_endpoint(dev, i + USB_DIR_IN);
397   }
398 }
399 
400 
usb_enable_endpoint(struct usb_device * dev,struct usb_endpoint_descriptor * epd)401 void usb_enable_endpoint(struct usb_device *dev,
402     struct usb_endpoint_descriptor *epd)
403 {
404   int maxsize = epd->wMaxPacketSize;
405   unsigned int eptaddr = epd->bEndpointAddress;
406   unsigned int eptnum = eptaddr & USB_ENDPOINT_NUMBER_MASK;
407   int is_control = ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
408         USB_ENDPOINT_XFER_CONTROL);
409 
410   if (usb_endpoint_out(eptaddr) || is_control) {
411     usb_endpoint_running(dev, eptnum, 1);
412     usb_settoggle(dev, eptnum, 1, 0);
413     dev->epmaxpacketout[eptnum] = maxsize;
414   }
415   if (!usb_endpoint_out(eptaddr) || is_control) {
416     usb_endpoint_running(dev, eptnum, 0);
417     usb_settoggle(dev, eptnum, 0, 0);
418     dev->epmaxpacketin[eptnum] = maxsize;
419   }
420 }
421 
usb_enable_interface(struct usb_device * dev,struct usb_interface * intf)422 void usb_enable_interface(struct usb_device *dev,
423     struct usb_interface *intf)
424 {
425   struct usb_host_interface *hintf =
426       &intf->altsetting[intf->act_altsetting];
427   int i;
428 
429   for (i = 0; i < hintf->desc.bNumEndpoints; ++i)
430     usb_enable_endpoint(dev, &hintf->endpoint[i].desc);
431 }
432 
usb_set_interface(struct usb_device * dev,int interface,int alternate)433 int usb_set_interface(struct usb_device *dev, int interface, int alternate)
434 {
435   struct usb_interface *iface;
436   int ret;
437   int manual = 0;
438 
439   iface = usb_ifnum_to_if(dev, interface);
440   if (!iface) {
441     usb_warn("Invalid interface %d", interface);
442     return -EINVAL;
443   }
444 
445   if (alternate < 0 || alternate >= iface->num_altsetting)
446     return -EINVAL;
447 
448   ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
449            USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
450            iface->altsetting[alternate]
451              .desc.bAlternateSetting,
452            interface, NULL, 0, HZ * 5);
453 
454   if (ret == -EPIPE && iface->num_altsetting == 1) {
455     dbg("manual set interface for iface %d, alt %d",
456       interface, alternate);
457     manual = 1;
458   } else if (ret < 0)
459     return ret;
460 
461   usb_disable_interface(dev, iface);
462 
463   iface->act_altsetting = alternate;
464 
465   if (manual) {
466     struct usb_host_interface *iface_as =
467         &iface->altsetting[alternate];
468     int ii;
469 
470     for (ii = 0; ii < iface_as->desc.bNumEndpoints; ii++) {
471       unsigned int epaddr =
472         iface_as->endpoint[ii].desc.bEndpointAddress;
473       unsigned int pipe =
474   __create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr)
475   | (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN);
476 
477       usb_clear_halt(dev, pipe);
478     }
479   }
480 
481   usb_enable_interface(dev, iface);
482 
483   return 0;
484 }
485 
usb_set_configuration(struct usb_device * dev,int configuration)486 int usb_set_configuration(struct usb_device *dev, int configuration)
487 {
488   int i, ret;
489   struct usb_host_config *cp = NULL;
490 
491   for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
492     if (dev->config[i].desc.bConfigurationValue == configuration) {
493       cp = &dev->config[i];
494       break;
495     }
496   }
497   if ((!cp && configuration != 0) || (cp && configuration == 0)) {
498     usb_warn("selecting invalid configuration %d", configuration);
499     return -EINVAL;
500   }
501 
502   if (dev->state != USB_STATE_ADDRESS)
503     usb_disable_device (dev, 1);  // Skip ep0
504   dev->toggle[0] = dev->toggle[1] = 0;
505   dev->halted[0] = dev->halted[1] = 0;
506   dev->state = USB_STATE_ADDRESS;
507 
508   if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
509       USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
510       NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
511     return ret;
512   if (configuration)
513     dev->state = USB_STATE_CONFIGURED;
514   dev->actconfig = cp;
515 
516   for (i = 0; i < cp->desc.bNumInterfaces; ++i) {
517     struct usb_interface *intf = cp->interface[i];
518 
519     intf->act_altsetting = 0;
520     usb_enable_interface(dev, intf);
521   }
522 
523     // Add string
524     if (dev->descriptor.iProduct)
525     {
526         usb_string(dev, dev->descriptor.iProduct, usb_string_buf, 64);
527         dev->product = usb_string_buf;
528     }
529     else
530         dev->product = NULL;
531     diag_printf("USB device product string (index 2) = %s\n", dev->product);
532 
533   return 0;
534 }
535 
536 
usb_string(struct usb_device * dev,int index,char * buf,size_t size)537 int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
538 {
539 #if 1
540 
541   unsigned char *tbuf;
542   int err, len;
543   U32 u, idx;
544   if ( (int)size <= 0 || !buf || !index)
545     return -EINVAL;
546   buf[0] = 0;
547   tbuf = (unsigned char*) kmalloc(256, GFP_KERNEL);
548   if (!tbuf)
549     return -ENOMEM;
550 
551   /* get langid for strings if it's not yet known */
552   if (!dev->have_langid) {
553     err = usb_get_string(dev, 0, 0, tbuf, 4);
554     if (err < 0) {
555       dbg("error getting string descriptor 0 (error=%d)", err);
556       goto errout;
557     } else if (err < 4 || tbuf[0] < 4) {
558       dbg("string descriptor 0 too short%s","");
559       err = -EINVAL;
560       goto errout;
561     } else {
562       dev->have_langid = -1;
563       dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
564         /* always use the first langid listed */
565       dbg("USB device number %d default language ID 0x%x",
566         dev->devnum, dev->string_langid);
567     }
568   }
569 
570   err = usb_get_string(dev, dev->string_langid, index, tbuf, 2);
571   if(err<2)
572     goto errout;
573   len=tbuf[0];
574 
575   err = usb_get_string(dev, dev->string_langid, index, tbuf, len);
576   if (err < 0)
577     goto errout;
578 
579   size--;
580   for (idx = 0, u = 2; u < (U32) err; u += 2) {
581     if (idx >= size)
582       break;
583     if (tbuf[u+1])
584       buf[idx++] = '?';
585     else
586       buf[idx++] = tbuf[u];
587   }
588   buf[idx] = 0;
589   err = idx;
590 
591  errout:
592   kfree(tbuf);
593   return err;
594   #else
595   return 0;
596   #endif
597 }
598 
599 
usb_reset_configuration(struct usb_device * dev)600 int usb_reset_configuration(struct usb_device *dev)
601 {
602    int      i, retval;
603    struct usb_host_config  *config;
604 
605    for (i = 1; i < 16; ++i) {
606      usb_disable_endpoint(dev, i);
607      usb_disable_endpoint(dev, i + USB_DIR_IN);
608   }
609 
610   config = dev->actconfig;
611   retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
612       USB_REQ_SET_CONFIGURATION, 0,
613       config->desc.bConfigurationValue, 0,
614       NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
615   if (retval < 0)
616     return retval;
617 
618   dev->toggle[0] = dev->toggle[1] = 0;
619   dev->halted[0] = dev->halted[1] = 0;
620 
621   for (i = 0; i < config->desc.bNumInterfaces; i++) {
622     struct usb_interface *intf = config->interface[i];
623     intf->act_altsetting = 0;
624     usb_enable_interface(dev, intf);
625   }
626   return 0;
627 }
628 #endif	//#ifdef
629 
630