xtalk: Caller passes xusb_spec to xusb_find_iface()
[dahdi/tools.git] / xpp / xtalk / xusb.c
1 /*
2  * Written by Oron Peled <oron@actcom.co.il>
3  * Copyright (C) 2008, Xorcom
4  *
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #define _GNU_SOURCE     /* for memrchr() */
24 #include <stdio.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <syslog.h>
30 #include <arpa/inet.h>
31 #include <debug.h>
32 #include <xusb.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <sys/ipc.h>
36 #include <sys/sem.h>
37
38 static const char rcsid[] = "$Id$";
39
40 #define DBG_MASK        0x01
41 #define TIMEOUT 500
42 #define MAX_RETRIES     10
43
44 struct xusb {
45         struct usb_device       *dev;
46         usb_dev_handle          *handle;
47         const struct xusb_spec  *spec;
48         char                    iManufacturer[BUFSIZ];
49         char                    iProduct[BUFSIZ];
50         char                    iSerialNumber[BUFSIZ];
51         char                    iInterface[BUFSIZ];
52         char                    devpath_tail[PATH_MAX + 1];
53         int                     bus_num;
54         int                     device_num;
55         int                     interface_num;
56         int                     ep_out;
57         int                     ep_in;
58         int                     is_usb2;
59         int                     is_claimed;
60         int                     is_open;
61         size_t                  packet_size;
62 };
63
64 static void xusb_init();
65
66 void xusb_init_spec(struct xusb_spec *spec, char *name,
67                 uint16_t vendor_id, uint16_t product_id,
68                 int nifaces, int iface, int nep, int ep_out, int ep_in)
69 {
70         DBG("Initialize %s: interfaces=%d using interface num=%d endpoints=%d (OUT=0x%02X, IN=0x%02X)\n",
71                         name, nifaces, iface, nep, ep_out, ep_in);
72         memset(spec, 0, sizeof(*spec));
73         spec->name = name;
74         spec->num_interfaces = nifaces;
75         spec->my_interface_num = iface;
76         spec->num_endpoints = nep;
77         spec->my_vendor_id = vendor_id;
78         spec->my_product_id = product_id;
79         spec->my_ep_in = ep_in;
80         spec->my_ep_out = ep_out;
81 }
82
83 #define EP_OUT(xusb)    ((xusb)->spec->my_ep_out)
84 #define EP_IN(xusb)     ((xusb)->spec->my_ep_in)
85
86 /*
87  * USB handling
88  */
89
90 static int get_usb_string(struct xusb *xusb, uint8_t item, char *buf, unsigned int len)
91 {
92         char    tmp[BUFSIZ];
93         int     ret;
94
95         assert(xusb->handle);
96         if (!item)
97                 return 0;
98         ret = usb_get_string_simple(xusb->handle, item, tmp, BUFSIZ);
99         if (ret <= 0)
100                 return ret;
101         return snprintf(buf, len, "%s", tmp);
102 }
103
104 static const struct usb_interface_descriptor *get_interface(const struct usb_device *dev, int my_interface_num, int num_interfaces)
105 {
106         const struct usb_interface              *interface;
107         const struct usb_interface_descriptor   *iface_desc;
108         const struct usb_config_descriptor      *config_desc;
109         int                                     num_altsetting;
110
111         config_desc = dev->config;
112         if (!config_desc) {
113                 ERR("No configuration descriptor: strange USB1 controller?\n");
114                 return NULL;
115         }
116         if(num_interfaces && config_desc->bNumInterfaces != num_interfaces) {
117                 DBG("Wrong number of interfaces: have %d need %d\n",
118                         config_desc->bNumInterfaces, num_interfaces);
119                 return NULL;
120         }
121         interface = &config_desc->interface[my_interface_num];
122         assert(interface != NULL);
123         iface_desc = interface->altsetting;
124         num_altsetting = interface->num_altsetting;
125         assert(num_altsetting != 0);
126         assert(iface_desc != NULL);
127         return iface_desc;
128 }
129
130 static int match_interface(const struct usb_device *dev, const struct xusb_spec *spec)
131 {
132         const struct usb_device_descriptor      *dev_desc;
133         const struct usb_interface_descriptor   *iface_desc;
134
135         //debug_mask = 0xFF;
136         //verbose = 1;
137         dev_desc = &dev->descriptor;
138         assert(dev_desc);
139         DBG("Checking: %04X:%04X interfaces=%d interface num=%d endpoints=%d: \"%s\"\n",
140                         spec->my_vendor_id,
141                         spec->my_product_id,
142                         spec->num_interfaces,
143                         spec->my_interface_num,
144                         spec->num_endpoints,
145                         spec->name);
146         if(dev_desc->idVendor != spec->my_vendor_id) {
147                 DBG("Wrong vendor id 0x%X\n", dev_desc->idVendor);
148                 return 0;
149         }
150         if(dev_desc->idProduct != spec->my_product_id) {
151                 DBG("Wrong product id 0x%X\n", dev_desc->idProduct);
152                 return 0;
153         }
154         if((iface_desc = get_interface(dev, spec->my_interface_num, spec->num_interfaces)) == NULL) {
155                 ERR("Could not get interface descriptor of device: %s\n", usb_strerror());
156                 return 0;
157         }
158         if(iface_desc->bInterfaceClass != 0xFF) {
159                 DBG("Wrong interface class 0x%X\n", iface_desc->bInterfaceClass);
160                 return 0;
161         }
162         if(iface_desc->bInterfaceNumber != spec->my_interface_num) {
163                 DBG("Wrong interface number %d (expected %d)\n",
164                         iface_desc->bInterfaceNumber, spec->my_interface_num);
165                 return 0;
166         }
167         if(iface_desc->bNumEndpoints != spec->num_endpoints) {
168                 DBG("Wrong number of endpoints %d\n", iface_desc->bNumEndpoints);
169                 return 0;
170         }
171         return  1;
172 }
173
174 static int xusb_fill_strings(struct xusb *xusb)
175 {
176         const struct usb_device_descriptor      *dev_desc;
177         const struct usb_interface_descriptor   *iface_desc;
178
179
180         dev_desc = &xusb->dev->descriptor;
181         assert(dev_desc);
182         if(get_usb_string(xusb, dev_desc->iManufacturer, xusb->iManufacturer, BUFSIZ) < 0) {
183                 ERR("Failed reading iManufacturer string: %s\n", usb_strerror());
184                 return 0;
185         }
186         if(get_usb_string(xusb, dev_desc->iProduct, xusb->iProduct, BUFSIZ) < 0) {
187                 ERR("Failed reading iProduct string: %s\n", usb_strerror());
188                 return 0;
189         }
190         if(get_usb_string(xusb, dev_desc->iSerialNumber, xusb->iSerialNumber, BUFSIZ) < 0) {
191                 ERR("Failed reading iSerialNumber string: %s\n", usb_strerror());
192                 return 0;
193         }
194         if((iface_desc = get_interface(xusb->dev, xusb->interface_num, 0)) == NULL) {
195                 ERR("Could not get interface descriptor of device: %s\n", usb_strerror());
196                 return 0;
197         }
198         if(get_usb_string(xusb, iface_desc->iInterface, xusb->iInterface, BUFSIZ) < 0) {
199                 ERR("Failed reading iInterface string: %s\n", usb_strerror());
200                 return 0;
201         }
202         return 1;
203 }
204
205 static int xusb_open(struct xusb *xusb)
206 {
207         assert(xusb);
208         if (xusb->is_open)
209                 return 1;
210         if((xusb->handle = usb_open(xusb->dev)) == NULL) {
211                 ERR("Failed to open usb device '%s': %s\n",
212                         xusb->devpath_tail, usb_strerror());
213                 return 0;
214         }
215         xusb->is_open = 1;
216         return 1;
217 }
218
219 int xusb_claim_interface(struct xusb *xusb)
220 {
221         const struct usb_device_descriptor      *dev_desc;
222         int                                     ret;
223
224         assert(xusb);
225         xusb_open(xusb);        /* If it's not open yet... */
226         if(usb_claim_interface(xusb->handle, xusb->interface_num) != 0) {
227                 ERR("usb_claim_interface %d in '%s': %s\n",
228                         xusb->interface_num, xusb->devpath_tail, usb_strerror());
229                 return 0;
230         }
231         xusb->is_claimed = 1;
232         xusb_fill_strings(xusb);
233         dev_desc = &xusb->dev->descriptor;
234         DBG("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n",
235                 dev_desc->idVendor,
236                 dev_desc->idProduct,
237                 xusb->iManufacturer,
238                 xusb->iProduct,
239                 xusb->iSerialNumber,
240                 xusb->iInterface);
241         if(usb_clear_halt(xusb->handle, EP_OUT(xusb)) != 0) {
242                 ERR("Clearing output endpoint: %s\n", usb_strerror());
243                 return 0;
244         }
245         if(usb_clear_halt(xusb->handle, EP_IN(xusb)) != 0) {
246                 ERR("Clearing input endpoint: %s\n", usb_strerror());
247                 return 0;
248         }
249         if((ret = xusb_flushread(xusb)) < 0) {
250                 ERR("xusb_flushread failed: %d\n", ret);
251                 return 0;
252         }
253         return 1;
254 }
255
256 static void xusb_list_dump(struct xlist_node *xusb_list)
257 {
258         struct xlist_node       *curr;
259         struct xusb             *xusb;
260
261         for(curr = xusb_list->next; curr != xusb_list; curr = curr->next) {
262                 struct usb_device               *dev;
263                 struct usb_bus                  *bus;
264                 struct usb_device_descriptor    *dev_desc;
265
266                 xusb = curr->data;
267                 assert(xusb);
268                 dev = xusb->dev;
269                 assert(dev);
270                 bus = dev->bus;
271                 assert(bus);
272                 dev_desc = &dev->descriptor;
273                 assert(dev_desc);
274                 DBG("usb:ID=%04X:%04X [%s / %s / %s], (%s/%s)\n",
275                         dev_desc->idVendor,
276                         dev_desc->idProduct,
277                         xusb->iManufacturer,
278                         xusb->iProduct,
279                         xusb->iSerialNumber,
280                         bus->dirname,
281                         dev->filename
282                         );
283         }
284 }
285
286 void xusb_destroy(struct xusb *xusb)
287 {
288         if(xusb) {
289                 xusb_close(xusb);
290                 memset(xusb, 0, sizeof(*xusb));
291                 free(xusb);
292         }
293 }
294
295 static struct xusb *xusb_new(struct usb_device *dev, const struct xusb_spec *spec)
296 {
297         struct usb_device_descriptor    *dev_desc;
298         struct usb_config_descriptor    *config_desc;
299         struct usb_interface            *interface;
300         struct usb_interface_descriptor *iface_desc;
301         struct usb_endpoint_descriptor  *endpoint;
302         size_t                          max_packet_size;
303         int                             i;
304         struct xusb                     *xusb = NULL;
305
306         /*
307          * Get information from the usb_device
308          */
309         if((dev_desc = &dev->descriptor) == NULL) {
310                 ERR("usb device without a device descriptor\n");
311                 goto fail;
312         }
313         if((config_desc = dev->config) == NULL) {
314                 ERR("usb device without a configuration descriptor\n");
315                 goto fail;
316         }
317         interface = &config_desc->interface[spec->my_interface_num];
318         iface_desc = interface->altsetting;
319         endpoint = iface_desc->endpoint;
320         /* Calculate max packet size */
321         max_packet_size = PACKET_SIZE;
322         for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
323                 DBG("Validating endpoint @ %d (interface %d)\n", i, spec->my_interface_num);
324                 if(endpoint->bEndpointAddress == spec->my_ep_out || endpoint->bEndpointAddress == spec->my_ep_in) {
325                         if(endpoint->wMaxPacketSize > PACKET_SIZE) {
326                                 ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
327                                 goto fail;
328                         }
329                         if(endpoint->wMaxPacketSize < max_packet_size) {
330                                 max_packet_size = endpoint->wMaxPacketSize;
331                         }
332                 }
333         }
334         /* Fill xusb */
335         if((xusb = malloc(sizeof(*xusb))) == NULL) {
336                 ERR("Out of memory");
337                 goto fail;
338         }
339         memset(xusb, 0, sizeof(*xusb));
340         xusb->dev = dev;
341         xusb->spec = spec;
342         sscanf(dev->bus->dirname, "%d", &xusb->bus_num);
343         sscanf(dev->filename, "%d", &xusb->device_num);
344         snprintf(xusb->devpath_tail, PATH_MAX, "%03d/%03d",
345                 xusb->bus_num, xusb->device_num);
346         xusb->interface_num = spec->my_interface_num;
347         xusb->ep_out = spec->my_ep_out;
348         xusb->ep_in = spec->my_ep_in;
349         xusb->packet_size = max_packet_size;
350         xusb->is_usb2 = (max_packet_size == 512);
351         if (! xusb_open(xusb)) {
352                 ERR("Failed opening device: %04X:%04X - %s\n",
353                         dev_desc->idVendor,
354                         dev_desc->idProduct,
355                         xusb->devpath_tail);
356                 goto fail;
357         }
358         DBG("%04X:%04X - %s\n",
359                 dev_desc->idVendor,
360                 dev_desc->idProduct,
361                 xusb->devpath_tail);
362         return xusb;
363 fail:
364         xusb_destroy(xusb);
365         return NULL;
366 }
367
368 struct xusb *xusb_find_iface(const char *devpath,
369         int iface_num,
370         int ep_out,
371         int ep_in,
372         struct xusb_spec *dummy_spec)
373 {
374         struct usb_bus          *bus;
375
376         DBG("\n");
377         xusb_init();
378         for (bus = usb_get_busses(); bus; bus = bus->next) {
379                 int                     bus_num;
380                 char                    tmppath[PATH_MAX + 1];
381                 struct usb_device       *dev;
382
383                 tmppath[0] = '\0';
384                 sscanf(bus->dirname, "%d", &bus_num);
385                 snprintf(tmppath, sizeof(tmppath), "%03d", bus_num);
386                 DBG("Check bus %d: %s ? %s\n", bus_num, tmppath, devpath);
387                 if (strncmp(tmppath, devpath, strlen(tmppath)) != 0)
388                         continue;
389                 DBG("Matched bus %d\n", bus_num);
390                 for (dev = bus->devices; dev; dev = dev->next) {
391                         struct usb_device_descriptor    *dev_desc;
392                         struct usb_config_descriptor    *config_desc;
393                         struct usb_interface            *interface;
394                         struct xusb                     *xusb;
395                         int                             device_num;
396
397                         sscanf(dev->filename, "%d", &device_num);
398                         DBG("Check device %d\n", device_num);
399                         snprintf(tmppath, sizeof(tmppath), "%03d/%03d", bus_num, device_num);
400                         if (strncmp(tmppath, devpath, strlen(tmppath)) != 0)
401                                 continue;
402                         dev_desc = &dev->descriptor;
403                         assert(dev_desc);
404                         config_desc = dev->config;
405                         assert(config_desc);
406                         interface = config_desc->interface;
407                         assert(interface);
408                         DBG("Matched device %s: %X:%X\n", tmppath, dev_desc->idVendor, dev_desc->idProduct);
409                         assert(dummy_spec);
410                         xusb_init_spec(dummy_spec, "<none>",
411                                 dev_desc->idVendor, dev_desc->idProduct,
412                                 config_desc->bNumInterfaces,
413                                 iface_num,
414                                 interface->altsetting->bNumEndpoints,
415                                 ep_out, ep_in);
416                         if((xusb = xusb_new(dev, dummy_spec)) == NULL) {
417                                 ERR("xusb allocation failed\n");
418                         }
419                         return xusb;
420                 }
421         }
422         return NULL;
423 }
424
425 static const char *path_tail(const char *path)
426 {
427         const   char    *p;
428
429         assert(path != NULL);
430         /* Find last '/' */
431         if((p = memrchr(path, '/', strlen(path))) == NULL) {
432                 ERR("Missing a '/' in %s\n", path);
433                 return NULL;
434         }
435         /* Search for a '/' before that */
436         if((p = memrchr(path, '/', p - path)) == NULL) {
437                 p = path;               /* No more '/' */
438         } else {
439                 p++;                    /* skip '/' */
440         }
441         return p;
442 }
443
444 int xusb_filter_bypath(const struct xusb *xusb, void *data)
445 {
446         const char      *p;
447         const char      *path = data;
448
449         DBG("%s\n", path);
450         assert(path != NULL);
451         p = path_tail(path);
452         if(strcmp(xusb->devpath_tail, p) != 0) {
453                 DBG("device path missmatch: '%s' != '%s'\n", xusb->devpath_tail, p);
454                 return 0;
455         }
456         return 1;
457 }
458
459 struct xusb *xusb_find_bypath(const struct xusb_spec *specs, int numspecs, const char *path)
460 {
461         struct xlist_node       *xlist;
462         struct xlist_node       *head;
463         struct xusb             *xusb;
464
465         xlist = xusb_find_byproduct(specs, numspecs, xusb_filter_bypath, (void *)path);
466         head = xlist_shift(xlist);
467         if (!head)
468                 return NULL;
469         if (! xlist_empty(xlist)) {
470                 ERR("Too many matches (extra %zd) to '%s'\n", xlist_length(xlist), path);
471                 return NULL;
472         }
473         xusb = head->data;
474         xlist_destroy(xlist, NULL);
475         return xusb;
476 }
477
478 struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data)
479 {
480         struct xlist_node       *xlist;
481         struct usb_bus          *bus;
482         struct usb_device       *dev;
483
484         DBG("specs(%d)\n", numspecs);
485         if((xlist = xlist_new(NULL)) == NULL) {
486                 ERR("Failed allocation new xlist");
487                 goto fail_xlist;
488         }
489         xusb_init();
490         for (bus = usb_get_busses(); bus; bus = bus->next) {
491                 for (dev = bus->devices; dev; dev = dev->next) {
492                         struct usb_device_descriptor    *dev_desc;
493                         struct xlist_node               *item;
494                         int                             i;
495
496                         dev_desc = &dev->descriptor;
497                         assert(dev_desc);
498                         DBG("usb:%s/%s: ID=%04X:%04X\n",
499                                 dev->bus->dirname,
500                                 dev->filename,
501                                 dev_desc->idVendor,
502                                 dev_desc->idProduct);
503                         for(i = 0; i < numspecs; i++) {
504                                 struct xusb             *xusb;
505                                 const struct xusb_spec  *sp = &specs[i];
506
507                                 if(!match_interface(dev, sp))
508                                         continue;
509                                 if((xusb = xusb_new(dev, sp)) == NULL) {
510                                         ERR("xusb allocation failed\n");
511                                         goto fail_malloc;
512                                 }
513                                 if(filterfunc && !filterfunc(xusb, data)) {
514                                         xusb_destroy(xusb);
515                                         continue;
516                                 }
517                                 item = xlist_new(xusb);
518                                 xlist_append_item(xlist, item);
519                                 break;
520                         }
521                 }
522         }
523         xusb_list_dump(xlist);
524         return xlist;
525 fail_malloc:
526         xlist_destroy(xlist, NULL);
527 fail_xlist:
528         return NULL;
529 }
530
531 struct xusb *xusb_open_one(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data)
532 {
533         struct xlist_node       *xusb_list;
534         struct xlist_node       *curr;
535         int                     num;
536         struct xusb             *xusb = NULL;
537
538         xusb_list = xusb_find_byproduct(specs, numspecs, filterfunc, data);
539         num = xlist_length(xusb_list);
540         DBG("total %d devices\n", num);
541         switch(num) {
542         case 0:
543                 ERR("No matching device.\n");
544                 break;
545         case 1:
546                 curr = xlist_shift(xusb_list);
547                 xusb = curr->data;
548                 xlist_destroy(curr, NULL);
549                 xlist_destroy(xusb_list, NULL);
550                 if(!xusb_claim_interface(xusb)) {
551                         xusb_destroy(xusb);
552                         return NULL;
553                 }
554                 xusb_showinfo(xusb);
555                 break;
556         default:
557                 ERR("Too many devices (%d). Aborting.\n", num);
558                 break;
559         }
560         return xusb;
561 }
562
563 int xusb_interface(struct xusb *xusb)
564 {
565         return xusb->interface_num;
566 }
567
568 size_t xusb_packet_size(const struct xusb *xusb)
569 {
570         return xusb->packet_size;
571 }
572
573 /*
574  * MP device handling
575  */
576 void xusb_showinfo(const struct xusb *xusb)
577 {
578         struct usb_device_descriptor    *dev_desc;
579         struct usb_device               *dev;
580
581         assert(xusb != NULL);
582         dev = xusb->dev;
583         dev_desc = &dev->descriptor;
584         if(verbose <= LOG_INFO) {
585                 INFO("usb:%s/%s: ID=%04X:%04X [%s / %s / %s]\n",
586                         dev->bus->dirname,
587                         dev->filename,
588                         dev_desc->idVendor,
589                         dev_desc->idProduct,
590                         xusb->iManufacturer,
591                         xusb->iProduct,
592                         xusb->iSerialNumber);
593         } else {
594                 printf("USB    Bus/Device:    [%s/%s] (%s,%s)\n",
595                         dev->bus->dirname,
596                         dev->filename,
597                         (xusb->is_open) ? "open" : "closed",
598                         (xusb->is_claimed) ? "claimed" : "unused");
599                 printf("USB    Spec name:     [%s]\n", xusb->spec->name);
600                 printf("USB    iManufacturer: [%s]\n", xusb->iManufacturer);
601                 printf("USB    iProduct:      [%s]\n", xusb->iProduct);
602                 printf("USB    iSerialNumber: [%s]\n", xusb->iSerialNumber);
603         }
604 }
605
606 const char *xusb_serial(const struct xusb *xusb)
607 {
608         return xusb->iSerialNumber;
609 }
610
611 const char *xusb_devpath(const struct xusb *xusb)
612 {
613         return xusb->devpath_tail;
614 }
615
616 const char *xusb_manufacturer(const struct xusb *xusb)
617 {
618         return xusb->iManufacturer;
619 }
620
621 const char *xusb_product(const struct xusb *xusb)
622 {
623         return xusb->iProduct;
624 }
625
626 uint16_t xusb_vendor_id(const struct xusb *xusb)
627 {
628         return  xusb->dev->descriptor.idVendor;
629 }
630
631 uint16_t xusb_product_id(const struct xusb *xusb)
632 {
633         return  xusb->dev->descriptor.idProduct;
634 }
635
636 const struct xusb_spec *xusb_spec(const struct xusb *xusb)
637 {
638         return xusb->spec;
639 }
640
641 int xusb_close(struct xusb *xusb)
642 {
643         if(xusb) {
644                 if(xusb->handle) {
645                         assert(xusb->spec);
646                         assert(xusb->spec->name);
647                         DBG("Closing interface \"%s\"\n", xusb->spec->name);
648                         if(xusb->is_claimed) {
649                                 if(usb_release_interface(xusb->handle, xusb->spec->my_interface_num) != 0) {
650                                         ERR("Releasing interface: usb: %s\n", usb_strerror());
651                                 }
652                                 xusb->is_claimed = 0;
653                         }
654                         if(xusb->is_open) {
655                                 if(usb_close(xusb->handle) != 0) {
656                                         ERR("Closing device: usb: %s\n", usb_strerror());
657                                 }
658                                 xusb->is_open = 0;
659                         }
660                         xusb->handle = NULL;
661                 }
662                 xusb = NULL;
663         }
664         return 0;
665 }
666
667 int xusb_send(struct xusb *xusb, char *buf, int len, int timeout)
668 {
669         int             ret;
670         int             retries = 0;
671
672         dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, buf, len);
673         if(EP_OUT(xusb) & USB_ENDPOINT_IN) {
674                 ERR("%s called with an input endpoint 0x%x\n", __FUNCTION__, EP_OUT(xusb));
675                 return -EINVAL;
676         }
677 retry_write:
678         ret = usb_bulk_write(xusb->handle, EP_OUT(xusb), buf, len, timeout);
679         if(ret < 0) {
680                 /*
681                  * If the device was gone, it may be the
682                  * result of renumeration. Ignore it.
683                  */
684                 if(ret != -ENODEV) {
685                         ERR("bulk_write to endpoint 0x%x failed: (%d) %s\n",
686                                 EP_OUT(xusb), ret, usb_strerror());
687                         dump_packet(LOG_ERR, DBG_MASK, "xusb_send[ERR]", buf, len);
688                         //exit(2);
689                 } else {
690                         DBG("bulk_write to endpoint 0x%x got ENODEV\n", EP_OUT(xusb));
691                         xusb_close(xusb);
692                 }
693                 return ret;
694         }
695         if(!ret) {
696 #if 0
697                 FILE    *fp;
698
699                 fp = fopen("/tmp/xusb.log", "a");
700                 if (!fp) {
701                         ERR("%s: Failed writing to /tmp/xusb.log\n", __func__);
702                         return -EFAULT;
703                 }
704                 fprintf(fp, "[%ld] bulk_write to endpoint 0x%x short write[%d]: (%d)\n",
705                         time(NULL), EP_OUT(xusb), retries, ret);
706                 fclose(fp);
707 #endif
708                 ERR("bulk_write to endpoint 0x%x short write[%d]: (%d)\n",
709                         EP_OUT(xusb), retries, ret);
710                 if (retries++ > MAX_RETRIES) {
711                         return -EFAULT;
712                 }
713                 usleep(100);
714                 goto retry_write;
715         }
716         if(ret != len) {
717                 ERR("bulk_write to endpoint 0x%x short write: (%d) %s\n",
718                         EP_OUT(xusb), ret, usb_strerror());
719                 dump_packet(LOG_ERR, DBG_MASK, "xusb_send[ERR]", buf, len);
720                 return -EFAULT;
721         }
722         return ret;
723 }
724
725 int xusb_recv(struct xusb *xusb, char *buf, size_t len, int timeout)
726 {
727         int     ret;
728         int     retries = 0;
729
730         if(EP_IN(xusb) & USB_ENDPOINT_OUT) {
731                 ERR("%s called with an output endpoint 0x%x\n", __FUNCTION__, EP_IN(xusb));
732                 return -EINVAL;
733         }
734 retry_read:
735         ret = usb_bulk_read(xusb->handle, EP_IN(xusb), buf, len, timeout);
736         if(ret < 0) {
737                 DBG("bulk_read from endpoint 0x%x failed: (%d) %s\n",
738                         EP_IN(xusb), ret, usb_strerror());
739                 memset(buf, 0, len);
740                 return ret;
741         }
742         if(!ret) {
743 #if 0
744                 FILE    *fp;
745
746                 fp = fopen("/tmp/xusb.log", "a");
747                 if (!fp) {
748                         ERR("%s: Failed writing to /tmp/xusb.log\n", __func__);
749                         return -EFAULT;
750                 }
751                 fprintf(fp, "[%ld] bulk_read from endpoint 0x%x short read[%d]: (%d)\n",
752                         time(NULL), EP_IN(xusb), retries, ret);
753                 fclose(fp);
754 #endif
755                 ERR("bulk_read to endpoint 0x%x short read[%d]: (%d)\n",
756                         EP_IN(xusb), retries, ret);
757                 if (retries++ > MAX_RETRIES) {
758                         return -EFAULT;
759                 }
760                 usleep(100);
761                 goto retry_read;
762         }
763         dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, buf, ret);
764         return ret;
765 }
766
767 int xusb_flushread(struct xusb *xusb)
768 {
769         char            tmpbuf[BUFSIZ];
770         int             ret;
771
772         DBG("starting...\n");
773         memset(tmpbuf, 0, BUFSIZ);
774         ret = xusb_recv(xusb, tmpbuf, BUFSIZ, 1);
775         if(ret < 0 && ret != -ETIMEDOUT) {
776                 ERR("ret=%d\n", ret);
777                 return ret;
778         } else if(ret > 0) {
779                 DBG("Got %d bytes:\n", ret);
780                 dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, tmpbuf, ret);
781         }
782         return 0;
783 }
784
785 /*
786  * Serialize calls to usb_find_busses()/usb_find_devices()
787  */
788
789 static const key_t      SEM_KEY = 0x1a2b3c4d;
790 static int semid = -1;  /* Failure */
791
792 static void xusb_lock_usb()
793 {
794         struct sembuf   sembuf;
795
796         while (semid < 0) {
797                 /* Maybe it was already created? */
798                 semid = semget(SEM_KEY, 1, 0);
799                 if (semid < 0) {
800                         /* No, let's create ourselves */
801                         semid = semget(SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0644);
802                         if (semid < 0) {
803                                 /* Someone else won the race to create it */
804                                 if (errno != ENOENT)
805                                         ERR("%s: semget() failed: %s\n",
806                                                 __func__, strerror(errno));
807                                 /* Retry */
808                                 continue;
809                         }
810                         /* Initialize */
811                         if (semctl(semid, 0, SETVAL, 1) < 0)
812                                 ERR("%s: SETVAL() failed: %s\n",
813                                         __func__, strerror(errno));
814                 }
815         }
816         DBG("%d: LOCKING\n", getpid());
817         sembuf.sem_num = 0;
818         sembuf.sem_op = -1;
819         sembuf.sem_flg = SEM_UNDO;
820         if (semop(semid, &sembuf, 1) < 0) {
821                 ERR("%s: semop() failed: %s\n", __func__, strerror(errno));
822         }
823         DBG("%d: LOCKED\n", getpid());
824 }
825
826 static void xusb_unlock_usb()
827 {
828         struct sembuf   sembuf;
829
830         DBG("%d: UNLOCKING\n", getpid());
831         sembuf.sem_num = 0;
832         sembuf.sem_op = 1;
833         sembuf.sem_flg = SEM_UNDO;
834         if (semop(semid, &sembuf, 1) < 0) {
835                 ERR("%s: semop() failed: %s\n", __func__, strerror(errno));
836         }
837         DBG("%d: UNLOCKED\n", getpid());
838 }
839
840 static int              initizalized = 0;
841
842 static void xusb_init()
843 {
844         if (!initizalized) {
845                 if (!getenv("XUSB_NOLOCK"))
846                         xusb_lock_usb();
847                 usb_init();
848                 usb_find_busses();
849                 usb_find_devices();
850                 initizalized = 1;
851                 if (!getenv("XUSB_NOLOCK"))
852                         xusb_unlock_usb();
853         }
854 }