/[pcsclite]/trunk/Drivers/ccid/src/ccid_usb.c
ViewVC logotype

Contents of /trunk/Drivers/ccid/src/ccid_usb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1281 - (hide annotations) (download)
Thu Oct 7 20:28:49 2004 UTC (8 years, 7 months ago) by rousseau
File MIME type: text/plain
File size: 17701 byte(s)
the first argument of get_desc() is lun instead of channel and the
function uses LunToReaderIndex() to get the reader index
1 rousseau 269 /*
2     ccid_usb.c: USB access routines using the libusb library
3 rousseau 649 Copyright (C) 2003-2004 Ludovic Rousseau
4 rousseau 269
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18     */
19    
20     /*
21     * $Id$
22     */
23    
24     #define __CCID_USB__
25    
26     #include <stdio.h>
27     #include <string.h>
28     #include <errno.h>
29 rousseau 1052 # ifdef S_SPLINT_S
30     # include <sys/types.h>
31     # endif
32 rousseau 269 #include <usb.h>
33    
34 rousseau 878 #include "ccid.h"
35 rousseau 269 #include "config.h"
36     #include "debug.h"
37 rousseau 878 #include "defs.h"
38 rousseau 269 #include "utils.h"
39     #include "parser.h"
40 rousseau 878 #include "ccid_ifdhandler.h"
41 rousseau 269
42    
43 rousseau 570 /* read timeout
44     * we must wait enough so that the card can finish its calculation
45     * the card, and then the reader should send TIME REQUEST bytes
46     * so this timeout should never occur */
47     #define USB_READ_TIMEOUT (60 * 1000) /* 1 minute timeout */
48 rousseau 269
49 rousseau 570 /* write timeout
50     * we don't have to wait a long time since the card was doing nothing */
51     #define USB_WRITE_TIMEOUT (5 * 1000) /* 5 seconds timeout */
52    
53 rousseau 762 /*
54     * Proprietary USB Class (0xFF) are (or are not) accepted
55     * A proprietary class is used for devices released before the final CCID
56     * specifications were ready.
57     * We should not have problems with non CCID devices becasue the
58     * Manufacturer and Product ID are also used to identify the device */
59     #define ALLOW_PROPRIETARY_CLASS
60 rousseau 570
61 rousseau 1256 /*
62     * The O2Micro OZ776S reader has a wrong USB descriptor
63     * The extra[] field is associated with the last endpoint instead of the
64     * main USB descriptor
65     */
66     #define O2MICRO_OZ776_PATCH
67    
68 rousseau 269 #define BUS_DEVICE_STRSIZE 32
69    
70     typedef struct
71     {
72     usb_dev_handle *handle;
73     struct usb_device *dev;
74    
75     /*
76     * Endpoints
77     */
78     int bulk_in;
79     int bulk_out;
80 rousseau 406
81     /*
82     * CCID infos common to USB and serial
83     */
84     _ccid_descriptor ccid;
85    
86 rousseau 269 } _usbDevice;
87    
88 rousseau 406 /* The _usbDevice structure must be defined before including ccid_usb.h */
89 rousseau 269 #include "ccid_usb.h"
90    
91 rousseau 878 static int get_end_points(struct usb_device *dev, _usbDevice *usb_device);
92    
93 rousseau 892 /* ne need to initialize to 0 since it is static */
94 rousseau 1077 static _usbDevice usbDevice[CCID_DRIVER_MAX_READERS];
95 rousseau 269
96     #define PCSCLITE_MANUKEY_NAME "ifdVendorID"
97     #define PCSCLITE_PRODKEY_NAME "ifdProductID"
98     #define PCSCLITE_NAMEKEY_NAME "ifdFriendlyName"
99    
100 rousseau 649
101 rousseau 269 /*****************************************************************************
102     *
103     * OpenUSB
104     *
105     ****************************************************************************/
106 rousseau 1106 status_t OpenUSB(unsigned int reader_index, /*@unused@*/ int Channel)
107 rousseau 269 {
108 rousseau 1106 return OpenUSBByName(reader_index, NULL);
109 rousseau 649 } /* OpenUSB */
110    
111    
112     /*****************************************************************************
113     *
114     * OpenUSBByName
115     *
116     ****************************************************************************/
117 rousseau 1106 status_t OpenUSBByName(unsigned int reader_index, /*@null@*/ char *device)
118 rousseau 649 {
119 rousseau 269 static struct usb_bus *busses = NULL;
120     int alias = 0;
121     struct usb_bus *bus;
122     struct usb_dev_handle *dev_handle;
123     char keyValue[TOKEN_MAX_VALUE_SIZE];
124     int vendorID, productID;
125 rousseau 301 char infofile[FILENAME_MAX];
126 rousseau 892 unsigned int device_vendor, device_product;
127 rousseau 781 char *dirname = NULL, *filename = NULL;
128 rousseau 1151 static int previous_reader_index = -1;
129 rousseau 269
130 rousseau 1106 DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, device);
131 rousseau 269
132 rousseau 662 /* device name specified */
133     if (device)
134     {
135 rousseau 781 /* format: usb:%04x/%04x, vendor, product */
136 rousseau 662 if (strncmp("usb:", device, 4) != 0)
137     {
138     DEBUG_CRITICAL2("device name does not start with \"usb:\": %s",
139     device);
140     return STATUS_UNSUCCESSFUL;
141     }
142    
143     if (sscanf(device, "usb:%x/%x", &device_vendor, &device_product) != 2)
144     {
145     DEBUG_CRITICAL2("device name can't be parsed: %s", device);
146     return STATUS_UNSUCCESSFUL;
147     }
148 rousseau 781
149     /* format usb:%04x/%04x:libusb:%s
150     * with %s set to %s:%s, dirname, filename */
151     if ((dirname = strstr(device, "libusb:")) != NULL)
152     {
153     /* dirname points to the first char after libusb: */
154     dirname += strlen("libusb:");
155    
156     /* search the : (separation) char */
157     filename = strchr(dirname, ':');
158    
159     if (filename)
160     {
161     /* end the dirname string */
162     *filename = '\0';
163    
164     /* filename points to the first char after : */
165     filename++;
166     }
167     else
168     {
169     /* parse failed */
170     dirname = NULL;
171    
172     DEBUG_CRITICAL2("can't parse using libusb scheme: %s", device);
173     }
174     }
175 rousseau 662 }
176    
177 rousseau 269 if (busses == NULL)
178     usb_init();
179    
180     usb_find_busses();
181     usb_find_devices();
182    
183     busses = usb_get_busses();
184    
185     if (busses == NULL)
186     {
187     DEBUG_CRITICAL("No USB busses found");
188     return STATUS_UNSUCCESSFUL;
189     }
190    
191 rousseau 1106 /* is the reader_index already used? */
192     if (usbDevice[reader_index].handle != NULL)
193 rousseau 269 {
194 rousseau 1106 DEBUG_CRITICAL2("USB driver with index %X already in use",
195     reader_index);
196 rousseau 269 return STATUS_UNSUCCESSFUL;
197     }
198    
199 rousseau 301 /* Info.plist full patch filename */
200 rousseau 406 snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist",
201     PCSCLITE_HP_DROPDIR, BUNDLE);
202 rousseau 301
203 rousseau 269 /* general driver info */
204 rousseau 301 if (!LTPBundleFindValueWithKey(infofile, "ifdManufacturerString", keyValue, 0))
205 rousseau 774 {
206 rousseau 269 DEBUG_CRITICAL2("Manufacturer: %s", keyValue);
207 rousseau 774 }
208 rousseau 269 else
209     {
210     DEBUG_CRITICAL2("LTPBundleFindValueWithKey error. Can't find %s?",
211 rousseau 301 infofile);
212 rousseau 269 return STATUS_UNSUCCESSFUL;
213     }
214 rousseau 301 if (!LTPBundleFindValueWithKey(infofile, "ifdProductString", keyValue, 0))
215 rousseau 774 {
216 rousseau 269 DEBUG_CRITICAL2("ProductString: %s", keyValue);
217 rousseau 774 }
218 rousseau 269 else
219     return STATUS_UNSUCCESSFUL;
220 rousseau 301 if (!LTPBundleFindValueWithKey(infofile, "Copyright", keyValue, 0))
221 rousseau 774 {
222 rousseau 269 DEBUG_CRITICAL2("Copyright: %s", keyValue);
223 rousseau 774 }
224 rousseau 269 else
225     return STATUS_UNSUCCESSFUL;
226     vendorID = strlen(keyValue);
227     alias = 0x1D;
228     for (; vendorID--;)
229     alias ^= keyValue[vendorID];
230    
231     /* for any supported reader */
232 rousseau 301 while (LTPBundleFindValueWithKey(infofile, PCSCLITE_MANUKEY_NAME, keyValue, alias) == 0)
233 rousseau 269 {
234 rousseau 1079 vendorID = strtoul(keyValue, NULL, 0);
235 rousseau 269
236 rousseau 301 if (LTPBundleFindValueWithKey(infofile, PCSCLITE_PRODKEY_NAME, keyValue, alias))
237 rousseau 269 goto end;
238 rousseau 1079 productID = strtoul(keyValue, NULL, 0);
239 rousseau 269
240 rousseau 301 if (LTPBundleFindValueWithKey(infofile, PCSCLITE_NAMEKEY_NAME, keyValue, alias))
241 rousseau 269 goto end;
242    
243 rousseau 662 /* go to next supported reader for next round */
244     alias++;
245    
246     /* the device was specified but is not the one we are trying to find */
247     if (device
248     && (vendorID != device_vendor || productID != device_product))
249     continue;
250    
251 rousseau 269 /* on any USB buses */
252     for (bus = busses; bus; bus = bus->next)
253     {
254     struct usb_device *dev;
255    
256     /* any device on this bus */
257     for (dev = bus->devices; dev; dev = dev->next)
258     {
259 rousseau 781 /* device defined by name? */
260     if (dirname && (strcmp(dirname, bus->dirname)
261     || strcmp(filename, dev->filename)))
262     continue;
263    
264 rousseau 269 if (dev->descriptor.idVendor == vendorID
265     && dev->descriptor.idProduct == productID)
266     {
267     int r, already_used;
268 rousseau 662 struct usb_interface *usb_interface = NULL;
269     int interface;
270 rousseau 269
271     /* is it already opened? */
272     already_used = FALSE;
273 rousseau 649
274 rousseau 1077 for (r=0; r<CCID_DRIVER_MAX_READERS; r++)
275 rousseau 269 {
276 rousseau 662 if (usbDevice[r].dev)
277 rousseau 269 {
278 rousseau 662 DEBUG_COMM3("Checking device: %s/%s",
279     bus->dirname, dev->filename);
280     /* same busname, same filename */
281     if (strcmp(usbDevice[r].dev->bus->dirname, bus->dirname) == 0 && strcmp(usbDevice[r].dev->filename, dev->filename) == 0)
282     already_used = TRUE;
283 rousseau 269 }
284     }
285    
286 rousseau 662 /* this reader is already managed by us */
287     if (already_used)
288 rousseau 269 {
289 rousseau 1151 if ((previous_reader_index != -1)
290     && (strcmp(usbDevice[previous_reader_index].dev->bus->dirname, bus->dirname) == 0)
291     && (strcmp(usbDevice[previous_reader_index].dev->filename, dev->filename) == 0)
292     && usbDevice[previous_reader_index].ccid.bCurrentSlotIndex < usbDevice[previous_reader_index].ccid.bMaxSlotIndex)
293     {
294     /* we reuse the same device
295     * and the reader is multi-slot */
296     usbDevice[reader_index] = usbDevice[previous_reader_index];
297     usbDevice[reader_index].ccid.pbSeq = usbDevice[previous_reader_index].ccid.pbSeq;
298     usbDevice[reader_index].ccid.bCurrentSlotIndex++;
299     DEBUG_INFO2("Opening slot: %d",
300     usbDevice[reader_index].ccid.bCurrentSlotIndex);
301     goto end;
302     }
303     else
304     {
305     DEBUG_INFO3("USB device %s/%s already in use."
306     " Checking next one.",
307     bus->dirname, dev->filename);
308     }
309 rousseau 301
310 rousseau 662 continue;
311     }
312 rousseau 269
313 rousseau 662 DEBUG_COMM3("Trying to open USB bus/device: %s/%s",
314     bus->dirname, dev->filename);
315 rousseau 269
316 rousseau 662 dev_handle = usb_open(dev);
317     if (dev_handle == NULL)
318     {
319     DEBUG_CRITICAL4("Can't usb_open(%s/%s): %s",
320     bus->dirname, dev->filename, strerror(errno));
321 rousseau 650
322 rousseau 662 continue;
323     }
324 rousseau 579
325 rousseau 662 /* now we found a free reader and we try to use it */
326     if (dev->config == NULL)
327     {
328     DEBUG_CRITICAL3("No dev->config found for %s/%s",
329     bus->dirname, dev->filename);
330     return STATUS_UNSUCCESSFUL;
331     }
332 rousseau 269
333 rousseau 662 usb_interface = get_ccid_usb_interface(dev);
334     if (usb_interface == NULL)
335     {
336     DEBUG_CRITICAL3("Can't find a CCID interface on %s/%s",
337     bus->dirname, dev->filename);
338     return STATUS_UNSUCCESSFUL;
339     }
340 rousseau 269
341 rousseau 662 if (usb_interface->altsetting->extralen != 54)
342     {
343     DEBUG_CRITICAL4("Extra field for %s/%s has a wrong length: %d", bus->dirname, dev->filename, usb_interface->altsetting->extralen);
344     return STATUS_UNSUCCESSFUL;
345 rousseau 269 }
346 rousseau 662
347     interface = usb_interface->altsetting->bInterfaceNumber;
348     if (usb_claim_interface(dev_handle, interface) < 0)
349 rousseau 269 {
350 rousseau 662 DEBUG_CRITICAL4("Can't claim interface %s/%s: %s",
351     bus->dirname, dev->filename, strerror(errno));
352     return STATUS_UNSUCCESSFUL;
353 rousseau 269 }
354 rousseau 662
355     DEBUG_INFO4("Found Vendor/Product: %04X/%04X (%s)",
356     dev->descriptor.idVendor,
357     dev->descriptor.idProduct, keyValue);
358     DEBUG_INFO3("Using USB bus/device: %s/%s",
359     bus->dirname, dev->filename);
360    
361     /* Get Endpoints values*/
362 rousseau 1106 get_end_points(dev, &usbDevice[reader_index]);
363 rousseau 662
364     /* store device information */
365 rousseau 1106 usbDevice[reader_index].handle = dev_handle;
366     usbDevice[reader_index].dev = dev;
367 rousseau 662
368     /* CCID common informations */
369 rousseau 1149 usbDevice[reader_index].ccid.real_bSeq = 0;
370     usbDevice[reader_index].ccid.pbSeq = &usbDevice[reader_index].ccid.real_bSeq;
371 rousseau 1106 usbDevice[reader_index].ccid.readerID =
372 rousseau 662 (dev->descriptor.idVendor << 16) +
373     dev->descriptor.idProduct;
374 rousseau 1106 usbDevice[reader_index].ccid.dwFeatures = dw2i(usb_interface->altsetting->extra, 40);
375     usbDevice[reader_index].ccid.bPINSupport = usb_interface->altsetting->extra[52];
376     usbDevice[reader_index].ccid.dwMaxCCIDMessageLength = dw2i(usb_interface->altsetting->extra, 44);
377     usbDevice[reader_index].ccid.dwMaxIFSD = dw2i(usb_interface->altsetting->extra, 28);
378     usbDevice[reader_index].ccid.dwDefaultClock = dw2i(usb_interface->altsetting->extra, 10);
379     usbDevice[reader_index].ccid.dwMaxDataRate = dw2i(usb_interface->altsetting->extra, 23);
380     usbDevice[reader_index].ccid.bMaxSlotIndex = usb_interface->altsetting->extra[4];
381     usbDevice[reader_index].ccid.bCurrentSlotIndex = 0;
382 rousseau 662 goto end;
383 rousseau 269 }
384     }
385     }
386     }
387     end:
388 rousseau 1106 if (usbDevice[reader_index].handle == NULL)
389 rousseau 269 return STATUS_UNSUCCESSFUL;
390    
391 rousseau 1151 /* memorise the current reader_index so we can detect
392     * a new OpenUSBByName on a multi slot reader */
393     previous_reader_index = reader_index;
394    
395 rousseau 269 return STATUS_SUCCESS;
396 rousseau 649 } /* OpenUSBByName */
397 rousseau 269
398    
399     /*****************************************************************************
400     *
401     * WriteUSB
402     *
403     ****************************************************************************/
404 rousseau 1106 status_t WriteUSB(unsigned int reader_index, unsigned int length,
405     unsigned char *buffer)
406 rousseau 269 {
407     int rv;
408     #ifdef DEBUG_LEVEL_COMM
409     char debug_header[] = "-> 121234 ";
410    
411 rousseau 1106 sprintf(debug_header, "-> %06X ", (int)reader_index);
412 rousseau 269 #endif
413    
414     #ifdef DEBUG_LEVEL_COMM
415     DEBUG_XXD(debug_header, buffer, length);
416     #endif
417    
418 rousseau 1106 rv = usb_bulk_write(usbDevice[reader_index].handle,
419     usbDevice[reader_index].bulk_out, (char *)buffer, length,
420     USB_WRITE_TIMEOUT);
421 rousseau 269
422     if (rv < 0)
423     {
424 rousseau 662 DEBUG_CRITICAL4("usb_bulk_write(%s/%s): %s",
425 rousseau 1106 usbDevice[reader_index].dev->bus->dirname,
426     usbDevice[reader_index].dev->filename, strerror(errno));
427 rousseau 269 return STATUS_UNSUCCESSFUL;
428     }
429    
430     return STATUS_SUCCESS;
431     } /* WriteUSB */
432    
433    
434     /*****************************************************************************
435     *
436     * ReadUSB
437     *
438     ****************************************************************************/
439 rousseau 1106 status_t ReadUSB(unsigned int reader_index, unsigned int * length,
440     unsigned char *buffer)
441 rousseau 269 {
442     int rv;
443     #ifdef DEBUG_LEVEL_COMM
444     char debug_header[] = "<- 121234 ";
445    
446 rousseau 1106 sprintf(debug_header, "<- %06X ", (int)reader_index);
447 rousseau 269 #endif
448    
449 rousseau 1106 rv = usb_bulk_read(usbDevice[reader_index].handle,
450     usbDevice[reader_index].bulk_in, (char *)buffer, *length,
451     USB_READ_TIMEOUT);
452 rousseau 269
453     if (rv < 0)
454     {
455 rousseau 895 *length = 0;
456 rousseau 662 DEBUG_CRITICAL4("usb_bulk_read(%s/%s): %s",
457 rousseau 1106 usbDevice[reader_index].dev->bus->dirname,
458     usbDevice[reader_index].dev->filename, strerror(errno));
459 rousseau 269 return STATUS_UNSUCCESSFUL;
460     }
461    
462 rousseau 895 *length = rv;
463    
464 rousseau 269 #ifdef DEBUG_LEVEL_COMM
465     DEBUG_XXD(debug_header, buffer, *length);
466     #endif
467    
468     return STATUS_SUCCESS;
469     } /* ReadUSB */
470    
471    
472     /*****************************************************************************
473     *
474     * CloseUSB
475     *
476     ****************************************************************************/
477 rousseau 1106 status_t CloseUSB(unsigned int reader_index)
478 rousseau 269 {
479 rousseau 650 struct usb_interface *usb_interface;
480     int interface;
481 rousseau 269
482     /* device not opened */
483 rousseau 1106 if (usbDevice[reader_index].dev == NULL)
484 rousseau 269 return STATUS_UNSUCCESSFUL;
485    
486 rousseau 662 DEBUG_COMM3("Closing USB device: %s/%s",
487 rousseau 1106 usbDevice[reader_index].dev->bus->dirname,
488     usbDevice[reader_index].dev->filename);
489 rousseau 269
490 rousseau 1106 usb_interface = get_ccid_usb_interface(usbDevice[reader_index].dev);
491 rousseau 650 interface = usb_interface ?
492     usb_interface->altsetting->bInterfaceNumber :
493 rousseau 1106 usbDevice[reader_index].dev->config->interface->altsetting->bInterfaceNumber;
494 rousseau 650
495 rousseau 892 /* reset so that bSeq starts at 0 again */
496 rousseau 1106 usb_reset(usbDevice[reader_index].handle);
497 rousseau 892
498 rousseau 1106 usb_release_interface(usbDevice[reader_index].handle, interface);
499     usb_close(usbDevice[reader_index].handle);
500 rousseau 269
501     /* mark the resource unused */
502 rousseau 1106 usbDevice[reader_index].handle = NULL;
503     usbDevice[reader_index].dev = NULL;
504 rousseau 269
505     return STATUS_SUCCESS;
506     } /* CloseUSB */
507    
508    
509 rousseau 301 /*****************************************************************************
510     *
511 rousseau 406 * get_ccid_descriptor
512 rousseau 301 *
513     ****************************************************************************/
514 rousseau 1106 _ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
515 rousseau 269 {
516 rousseau 1106 return &usbDevice[reader_index].ccid;
517 rousseau 406 } /* get_ccid_descriptor */
518 rousseau 269
519    
520 rousseau 301 /*****************************************************************************
521     *
522     * get_desc
523     *
524     ****************************************************************************/
525 rousseau 1281 int get_desc(int lun, usb_dev_handle **handle, struct
526 rousseau 269 usb_device **dev)
527     {
528 rousseau 1281 int reader_index;
529 rousseau 269
530 rousseau 1281 if (-1 == (reader_index = LunToReaderIndex(lun)))
531     return FALSE;
532 rousseau 269
533 rousseau 1281 *handle = usbDevice[reader_index].handle;
534     *dev = usbDevice[reader_index].dev;
535    
536     return TRUE;
537 rousseau 269 } /* get_desc */
538    
539 rousseau 649
540 rousseau 301 /*****************************************************************************
541     *
542     * get_end_points
543     *
544     ****************************************************************************/
545 rousseau 878 static int get_end_points(struct usb_device *dev, _usbDevice *usb_device)
546 rousseau 269 {
547     int i;
548     int bEndpointAddress;
549 rousseau 650 struct usb_interface *usb_interface = get_ccid_usb_interface(dev);
550    
551 rousseau 269 /*
552     * 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
553     */
554     for (i=0; i<3; i++)
555     {
556 rousseau 650 if (usb_interface->altsetting->endpoint[i].bmAttributes != USB_ENDPOINT_TYPE_BULK)
557 rousseau 269 continue;
558    
559 rousseau 650 bEndpointAddress = usb_interface->altsetting->endpoint[i].bEndpointAddress;
560 rousseau 269
561     if ((bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN)
562     usb_device->bulk_in = bEndpointAddress;
563    
564     if ((bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
565     usb_device->bulk_out = bEndpointAddress;
566     }
567    
568     return 0;
569     } /* get_end_points */
570    
571 rousseau 650
572     /*****************************************************************************
573     *
574     * get_ccid_usb_interface
575     *
576     ****************************************************************************/
577 rousseau 1054 /*@null@*/ struct usb_interface * get_ccid_usb_interface(struct usb_device *dev)
578 rousseau 650 {
579     struct usb_interface *usb_interface = NULL;
580    
581     /* if multiple interfaces use the first one with CCID class type */
582     if (dev->config->bNumInterfaces > 1)
583     {
584     int ii;
585     for (ii=0; ii<dev->config->bNumInterfaces; ii++)
586     {
587 rousseau 738 /* CCID Class? */
588     if (dev->config->interface[ii].altsetting->bInterfaceClass == 0xb
589     #ifdef ALLOW_PROPRIETARY_CLASS
590     || dev->config->interface[ii].altsetting->bInterfaceClass == 0xff
591     #endif
592     )
593 rousseau 650 {
594     usb_interface = &dev->config->interface[ii];
595     break;
596     }
597     }
598     }
599     else
600 rousseau 1256 /* only one interface found */
601 rousseau 650 usb_interface = dev->config->interface;
602    
603 rousseau 1256 #ifdef O2MICRO_OZ776_PATCH
604     if (usb_interface != NULL
605     && (OZ776 == (dev->descriptor.idVendor << 16)
606     + dev->descriptor.idProduct)
607     && (0 == usb_interface->altsetting->extralen)) /* this is the bug */
608     {
609     int i;
610    
611     for (i=0; i<usb_interface->altsetting->bNumEndpoints; i++)
612     {
613     /* find the extra[] array */
614     if (54 == usb_interface->altsetting->endpoint[i].extralen)
615     {
616     /* get the extra[] from the endpoint */
617     usb_interface->altsetting->extralen = 54;
618     usb_interface->altsetting->extra =
619     usb_interface->altsetting->endpoint[i].extra;
620     break;
621     }
622     }
623     }
624     #endif
625    
626 rousseau 650 return usb_interface;
627     } /* get_ccid_usb_interface */
628    

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5