root/trunk/src/ifd/sys-bsd.c

Revision 1166, 15.4 KB (checked in by aj, 6 months ago)

abort if retries reach 0 or something other than EIO was returned.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * *BSD specific functions
3 *
4 * Copyright (C) 2003 Olaf Kirch <okir@suse.de>
5 * Copyright (C) 2003 Andreas Jellinghaus <aj@dungeon.inka.de>
6 * Copyright (C) 2003 Markus Friedl <markus@openbsd.org>
7 * Copyright (C) 2004-2005 William Wanders <william@wanders.org>
8 *
9 * These functions need to be re-implemented for every
10 * new platform.
11 */
12
13#include "internal.h"
14#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
15#include <sys/types.h>
16#ifndef ENABLE_LIBUSB
17#if defined(__DragonFly__)
18#include <bus/usb/usb.h>
19#else
20#include <dev/usb/usb.h>
21#endif
22#endif /* !ENABLE_LIBUSB */
23#include <sys/stat.h>
24#include <sys/ioctl.h>
25#include <sys/poll.h>
26#include <sys/file.h>
27#include <string.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <signal.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <errno.h>
34#include <openct/driver.h>
35#ifdef ENABLE_LIBUSB
36#include <usb.h>
37#endif
38
39#include "usb-descriptors.h"
40
41#ifdef ENABLE_LIBUSB
42struct usb_dev_handle *devices[128];
43#endif
44
45/*
46 * Poll for presence of USB device
47 */
48int ifd_sysdep_usb_poll_presence(ifd_device_t * dev, struct pollfd *pfd)
49{
50        if (pfd->revents & POLLHUP)
51                return 0;
52        pfd->fd = dev->fd;
53        pfd->events = POLLHUP;
54        return 1;
55}
56
57#ifndef ENABLE_LIBUSB
58typedef struct ep {
59        int ep_fd;
60} ep_t;
61
62typedef ep_t interface_t[128];
63
64static interface_t interfaces[1];
65
66#define USB_REQUEST_SIZE        8
67
68/*
69 * Open interface endpoint
70 */
71int open_ep(char *name, int interface, int endpoint, int flags)
72{
73        char filename[256];
74
75        if (interfaces[interface][endpoint].ep_fd) {
76                ifd_debug(6, "open_ep: endpoint already opened");
77                return 0;
78        }
79
80#ifdef __OpenBSD__
81        snprintf(filename, sizeof(filename), "%s.%02d", name, endpoint);
82#else
83        snprintf(filename, sizeof(filename), "%s.%d", name, endpoint);
84#endif /* __OpenBSD__ */
85
86        if ((interfaces[interface][endpoint].ep_fd = open(filename, flags)) < 0) {
87                ifd_debug(6, "open_ep: error opening \"%s\": %s", filename,
88                          strerror(errno));
89                interfaces[interface][endpoint].ep_fd = 0;
90                return -1;
91        }
92        return 0;
93}
94
95static void
96close_ep(int interface, int endpoint)
97{
98        if (interfaces[interface][endpoint].ep_fd) {
99                close(interfaces[interface][endpoint].ep_fd);
100                interfaces[interface][endpoint].ep_fd = 0;
101        }
102}
103#endif /* !ENABLE_LIBUSB */
104
105int ifd_sysdep_usb_bulk(ifd_device_t * dev, int ep, void *buffer, size_t len,
106                        long timeout)
107{
108        int bytes_to_process;
109        int bytes_processed;
110        int direction =
111            (ep & IFD_USB_ENDPOINT_DIR_MASK) == IFD_USB_ENDPOINT_IN ? 1 : 0;
112        int endpoint = (ep & ~IFD_USB_ENDPOINT_DIR_MASK);
113
114        ct_debug("ifd_sysdep_usb_bulk: endpoint=%d direction=%d", endpoint,
115                 direction);
116        if (direction) {
117#ifdef ENABLE_LIBUSB
118                if ((bytes_to_process =
119                     usb_bulk_read(devices[dev->fd], ep, buffer, len,
120                                   timeout)) < 0) {
121                        ifd_debug(6, "ifd_sysdep_usb_bulk: read failed: %s",
122                                  strerror(errno));
123                        ct_error("usb_bulk read failed: %s", strerror(errno));
124                        return IFD_ERROR_COMM_ERROR;
125                }
126#else
127                int one = 1;
128
129                if (open_ep(dev->name, 0, endpoint, O_RDONLY | O_NONBLOCK)) {
130                        ct_debug("ifd_sysdep_usb_bulk: opening endpoint failed");
131                        return -1;
132                }
133
134                if (ioctl(interfaces[0][endpoint].ep_fd, USB_SET_SHORT_XFER,
135                    &one) < 0) {
136                        ifd_debug(6, "ifd_sysdep_usb_bulk: USB_SET_SHORT_XFER"
137                                  " failed: %s", strerror(errno));
138                        ct_error("usb_bulk read failed: %s", strerror(errno));
139                }
140                if ((bytes_to_process =
141                     read(interfaces[0][endpoint].ep_fd, buffer, len)) < 0) {
142                        ifd_debug(6, "ifd_sysdep_usb_bulk: read failed: %s",
143                                  strerror(errno));
144                        ct_error("usb_bulk read failed: %s", strerror(errno));
145                        return IFD_ERROR_COMM_ERROR;
146                }
147#endif /* ENABLE_LIBUSB */
148                ct_debug("ifd_sysdep_usb_bulk: read %d bytes",
149                         bytes_to_process);
150                return bytes_to_process;
151        } else {
152#ifndef ENABLE_LIBUSB
153                if (open_ep(dev->name, 0, endpoint, O_WRONLY | O_NONBLOCK)) {
154                        ct_debug("ifd_sysdep_usb_bulk: opening endpoint failed");
155                        return -1;
156                }
157#endif /* !ENABLE_LIBUSB */
158
159                bytes_to_process = len;
160                if ((bytes_processed =
161#ifdef ENABLE_LIBUSB
162                     usb_bulk_write(devices[dev->fd], ep, buffer,
163                                    bytes_to_process, timeout)
164#else
165                     write(interfaces[0][endpoint].ep_fd, buffer,
166                           bytes_to_process)
167#endif /* ENABLE_LIBUSB */
168                            ) != bytes_to_process) {
169                        ifd_debug(6, "ifd_sysdep_usb_bulk: write failed: %s",
170                                  strerror(errno));
171                        ct_error("usb_bulk write failed: %s", strerror(errno));
172                        return IFD_ERROR_COMM_ERROR;
173                }
174                ct_debug("ifd_sysdep_usb_bulk: wrote buffer[%d]=%s",
175                         bytes_processed, ct_hexdump(buffer, len));
176                return bytes_processed;
177        }
178}
179
180int ifd_sysdep_usb_get_eventfd(ifd_device_t * dev, short *events)
181{
182        return -1;
183}
184
185/*
186 * USB URB capture
187 */
188struct ifd_usb_capture {
189        int type;
190        int endpoint;
191        size_t maxpacket;
192        unsigned int interface;
193};
194
195int ifd_sysdep_usb_begin_capture(ifd_device_t * dev, int type, int ep,
196                                 size_t maxpacket, ifd_usb_capture_t ** capret)
197{
198        ifd_usb_capture_t *cap;
199#ifndef ENABLE_LIBUSB
200        int direction =
201            (ep & IFD_USB_ENDPOINT_DIR_MASK) == IFD_USB_ENDPOINT_IN ? 1 : 0;
202        int endpoint = (ep & ~IFD_USB_ENDPOINT_DIR_MASK);
203#endif /* !ENABLE_LIBUSB */
204
205        if (!(cap = (ifd_usb_capture_t *) calloc(1, sizeof(*cap) + maxpacket))) {
206                ct_error("out of memory");
207                return IFD_ERROR_NO_MEMORY;
208        }
209        cap->type = type;
210        cap->endpoint = ep;
211        cap->maxpacket = maxpacket;
212
213#ifndef ENABLE_LIBUSB
214        if (!interfaces[0][endpoint].ep_fd) {
215                if (open_ep(dev->name, 0, endpoint, O_RDONLY | O_NONBLOCK)) {
216                        ct_debug
217                            ("ifd_sysdep_usb_begin_capture: opening endpoint failed");
218                        return -1;
219                }
220        }
221#endif /* !ENABLE_LIBUSB */
222        *capret = cap;
223        return 0;
224}
225
226int ifd_sysdep_usb_capture_event(ifd_device_t * dev, ifd_usb_capture_t * cap,
227                           void *buffer, size_t len)
228{
229        return IFD_ERROR_NOT_SUPPORTED;
230}
231
232int ifd_sysdep_usb_capture(ifd_device_t * dev, ifd_usb_capture_t * cap,
233                           void *buffer, size_t len, long timeout)
234{
235        int bytes_to_process = 0;
236#ifdef ENABLE_LIBUSB
237        if ((bytes_to_process =
238             usb_interrupt_read(devices[dev->fd], cap->endpoint, buffer, len,
239                                timeout)) < 0) {
240                ifd_debug(6,
241                          "ifd_sysdep_usb_capture: usb_interrupt_read failed: %s",
242                          strerror(errno));
243                ct_error("usb_bulk read failed: %s", strerror(errno));
244                return IFD_ERROR_COMM_ERROR;
245        }
246#else
247        struct timeval begin;
248        int direction =
249            (cap->endpoint & IFD_USB_ENDPOINT_DIR_MASK) ==
250            IFD_USB_ENDPOINT_IN ? 1 : 0;
251        int endpoint = (cap->endpoint & ~IFD_USB_ENDPOINT_DIR_MASK);
252
253        gettimeofday(&begin, NULL);
254        do {
255                struct pollfd pfd;
256                long wait;
257
258                if ((wait = (timeout - ifd_time_elapsed(&begin))) <= 0)
259                        return IFD_ERROR_TIMEOUT;
260
261                pfd.fd = interfaces[0][endpoint].ep_fd;
262                pfd.events = POLLIN;
263                if (poll(&pfd, 1, wait) != 1)
264                        continue;
265
266                if ((bytes_to_process =
267                     read(interfaces[0][endpoint].ep_fd, buffer, len)) < 0) {
268                        ifd_debug(6, "ifd_sysdep_usb_bulk: read failed: %s",
269                                  strerror(errno));
270                        ct_error("usb_bulk read failed: %s", strerror(errno));
271                        return IFD_ERROR_COMM_ERROR;
272                }
273        } while (!bytes_to_process);
274#endif /* ENABLE_LIBUSB */
275        ct_debug("ifd_sysdep_usb_capture: read buffer[%d]=%s", bytes_to_process,
276                 ct_hexdump(buffer, bytes_to_process));
277        return bytes_to_process;
278}
279
280int ifd_sysdep_usb_end_capture(ifd_device_t * dev, ifd_usb_capture_t * cap)
281{
282#ifndef ENABLE_LIBUSB
283        int direction =
284            (cap->endpoint & IFD_USB_ENDPOINT_DIR_MASK) ==
285            IFD_USB_ENDPOINT_IN ? 1 : 0;
286        int endpoint = (cap->endpoint & ~IFD_USB_ENDPOINT_DIR_MASK);
287        close_ep(0, endpoint);
288#endif /* !ENABLE_LIBUSB */
289        if (cap)
290                free(cap);
291        return 0;
292}
293
294/*
295 * USB control command
296 */
297int ifd_sysdep_usb_control(ifd_device_t * dev, unsigned int requesttype,
298                           unsigned int request, unsigned int value,
299                           unsigned int index, void *data, size_t len,
300                           long timeout)
301{
302        int rc, val;
303
304#ifdef ENABLE_LIBUSB
305        ct_debug("ifd_sysdep_usb_control: dev->fd=%d handle=0x%x", dev->fd,
306                 devices[dev->fd]);
307        if ((rc =
308             usb_control_msg(devices[dev->fd], requesttype, request, value,
309                             index, data, len, timeout)) < 0) {
310                ifd_debug(1, "usb_control_msg failed: %d", rc);
311                ct_error("usb_control_msg failed: %s(%d)",
312                         strerror(errno), errno);
313                return IFD_ERROR_COMM_ERROR;
314        }
315
316        ct_debug("ifd_sysdep_usb_control: return rc=%d", rc);
317        return rc;
318#else
319        struct usb_ctl_request ctrl;
320        int retries;
321
322        ifd_debug(1, "BSD: ifd_sysdep_usb_control(0x%x)", request);
323        memset(&ctrl, 0, sizeof(ctrl));
324
325        ctrl.ucr_request.bmRequestType = requesttype;
326        ctrl.ucr_request.bRequest = request;
327        USETW(ctrl.ucr_request.wValue, value);
328        USETW(ctrl.ucr_request.wIndex, index);
329        USETW(ctrl.ucr_request.wLength, len);
330
331        ctrl.ucr_data = data;
332        ctrl.ucr_flags = USBD_SHORT_XFER_OK;
333
334        ifd_debug(1, "BSD: CTRL bmRequestType 0x%x bRequest 0x%x "
335                  "wValue 0x%x wIndex 0x%x wLength 0x%x",
336                  requesttype, request, value, index, len);
337        if (len)
338                ifd_debug(5, "BSD: CTRL SEND data %s", ct_hexdump(data, len));
339
340        val = timeout;
341        if ((rc = ioctl(dev->fd, USB_SET_TIMEOUT, &val)) < 0) {
342                ifd_debug(1, "USB_SET_TIMEOUT failed: %d", rc);
343                ct_error("usb_set_timeout failed: %s(%d)",
344                         strerror(errno), errno);
345                return IFD_ERROR_COMM_ERROR;
346        }
347
348        retries = 5;
349        while ((rc = ioctl(dev->fd, USB_DO_REQUEST, &ctrl)) < 0 && retries > 0) {
350                ifd_debug(1, "USB_DO_REQUEST failed: %d", rc);
351                ct_error("usb_do_request failed: %s (%d)",
352                         strerror(errno), errno);
353                retries--;
354                if ((retries == 0) || (errno != EIO))
355                        return IFD_ERROR_COMM_ERROR;
356        }
357
358        if (ctrl.ucr_data == NULL)
359                ifd_debug(1, "BSD: ctrl.ucr_data == NULL ");
360        if (ctrl.ucr_data && ctrl.ucr_actlen)
361                ifd_debug(1, "BSD: CTRL RECV data %s",
362                          ct_hexdump(ctrl.ucr_data, ctrl.ucr_actlen));
363        return ctrl.ucr_actlen;
364#endif /* ENABLE_LIBUSB */
365}
366
367int ifd_sysdep_usb_set_configuration(ifd_device_t * dev, int config)
368{
369        int rc;
370#ifdef ENABLE_LIBUSB
371        if ((rc = usb_set_configuration(devices[dev->fd], config)) < 0) {
372                ifd_debug(1, "usb_set_configuration failed: %d", rc);
373#else
374        int value;
375        value = config;
376        if ((rc = ioctl(dev->fd, USB_SET_CONFIG, &value)) < 0) {
377                ifd_debug(1, "USB_SET_CONFIG failed: %d", rc);
378#endif /* ENABLE_LIBUSB */
379                ct_error("usb_set_configuration failed: %s(%d)",
380                         strerror(errno), errno);
381                return IFD_ERROR_COMM_ERROR;
382        }
383        return 0;
384}
385
386int ifd_sysdep_usb_set_interface(ifd_device_t * dev, int ifc, int alt)
387{
388        int rc;
389#ifdef ENABLE_LIBUSB
390        if ((rc = usb_set_altinterface(devices[dev->fd], alt)) < 0) {
391                ifd_debug(1, "usb_set_altinterface failed: %d", rc);
392#else
393        struct usb_alt_interface {
394                int uai_config_index;
395                int uai_interface_index;
396                int uai_alt_no;
397        } value;
398
399        value.uai_config_index = ifc;
400        value.uai_interface_index = 0;
401        value.uai_alt_no = alt;
402        if ((rc = ioctl(dev->fd, USB_SET_ALTINTERFACE, &value)) < 0) {
403                ifd_debug(1, "USB_SET_ALTINTERFACE failed: %d", rc);
404#endif /* ENABLE_LIBUSB */
405                ct_error("usb_set_interface failed: %s(%d)",
406                         strerror(errno), errno);
407                return IFD_ERROR_COMM_ERROR;
408        }
409        return 0;
410}
411
412int ifd_sysdep_usb_claim_interface(ifd_device_t * dev, int interface)
413{
414#ifdef ENABLE_LIBUSB
415        int rc;
416
417        ct_debug("ifd_sysdep_usb_claim_interface: interface=%d", interface);
418        if ((rc = usb_claim_interface(devices[dev->fd], interface)) < 0) {
419                ifd_debug(1, "usb_clain_interface failed: %d", rc);
420                ct_error("usb_release_interface failed: %s(%d)",
421                         strerror(errno), errno);
422                return IFD_ERROR_COMM_ERROR;
423        }
424#else
425        ct_debug
426            ("ifd_sysdep_usb_claim_interface: interface=%d (not yet implemented)",
427             interface);
428#endif /* ENABLE_LIBUSB */
429        return 0;
430}
431
432int ifd_sysdep_usb_release_interface(ifd_device_t * dev, int interface)
433{
434#ifdef ENABLE_LIBUSB
435        int rc;
436
437        ct_debug("ifd_sysdep_usb_release_interface: interface=%d", interface);
438        if ((rc = usb_release_interface(devices[dev->fd], interface)) < 0) {
439                ifd_debug(1, "usb_release_interface failed: %d", rc);
440                ct_error("usb_release_interface failed: %s(%d)",
441                         strerror(errno), errno);
442                return IFD_ERROR_COMM_ERROR;
443        }
444#else
445        ct_debug
446            ("ifd_sysdep_usb_release_interface: interface=%d (not yet implemented)",
447             interface);
448#endif /* ENABLE_LIBUSB */
449        return 0;
450}
451
452int ifd_sysdep_usb_open(const char *device)
453{
454#ifdef ENABLE_LIBUSB
455        struct usb_bus *bus;
456        struct usb_device *dev;
457
458        ct_debug("ifd_sysdep_usb_open: name=%s", device);
459        ct_debug("ifd_sysdep_usb_open: usb_init()");
460        usb_init();
461        ct_debug("ifd_sysdep_usb_open: usb_find_busses()");
462        usb_find_busses();
463        ct_debug("ifd_sysdep_usb_open: usb_find_devices()");
464        usb_find_devices();
465
466        ct_debug("ifd_sysdep_usb_open: walk devices");
467        for (bus = usb_busses; bus; bus = bus->next) {
468                for (dev = bus->devices; dev; dev = dev->next) {
469                        int i;
470
471                        if (strcmp(dev->filename, device) != 0)
472                                continue;
473
474                        ct_debug
475                            ("ifd_sysdep_usb_open: found match name=%s device=%s",
476                             device, dev->filename);
477                        for (i = 0; i < 128; i++) {
478                                if (devices[i] == NULL) {
479                                        devices[i] = usb_open(dev);
480                                        ct_debug
481                                            ("ifd_sysdep_usb_open: usb_open index=%d handle=0x%x",
482                                             i, devices[i]);
483                                        return i;
484                                }
485                        }
486                }
487        }
488        return -1;
489#else
490#ifdef __OpenBSD__
491        char path[256];
492
493        if (snprintf(&path, sizeof(path), "%s.00", device) < 0)
494                return -1;
495        return open(path, O_RDWR);
496#else
497        return open(device, O_RDWR);
498#endif /* __OpenBSD__ */
499#endif /* ENABLE_LIBUSB */
500}
501
502int ifd_sysdep_usb_reset(ifd_device_t * dev)
503{
504        /* not implemented so far */
505        return -1;
506}
507
508/*
509 * Scan all usb devices to see if there is one we support
510 */
511int ifd_scan_usb(void)
512{
513#ifdef ENABLE_LIBUSB
514        struct usb_bus *bus;
515        struct usb_device *dev;
516        ifd_devid_t id;
517
518        usb_init();
519        usb_find_busses();
520        usb_find_devices();
521
522        id.type = IFD_DEVICE_TYPE_USB;
523        id.num = 2;
524        for (bus = usb_busses; bus; bus = bus->next) {
525                for (dev = bus->devices; dev; dev = dev->next) {
526                        const char *driver;
527                        char typedev[PATH_MAX];
528
529                        id.val[0] = dev->descriptor.idVendor;
530                        id.val[1] = dev->descriptor.idProduct;
531
532                        /* FIXME: if we don't find a driver with vendor/product
533                         * then check for the interface type (ccid) and use
534                         * driver ccid... */
535
536                        if (!(driver = ifd_driver_for_id(&id)))
537                                continue;
538
539                        snprintf(typedev, sizeof(typedev),
540                                 "usb:%s", dev->filename);
541
542                        ifd_spawn_handler(driver, typedev, -1);
543                }
544        }
545#else
546        int i, controller_fd;
547        char controller_devname[10];
548
549        ifd_debug(1, "BSD: ifd_scan_usb");
550        for (i = 0; i < 10; i++) {
551                int address;
552
553                snprintf(controller_devname, 10, "/dev/usb%d.00", i);
554                if ((controller_fd = open(controller_devname, O_RDONLY)) < 0)
555                        continue;
556
557                if (controller_fd < 0) {
558                        if (errno == ENOENT || errno == ENXIO)
559                                continue;
560                        /* a more suitable error recovery should be done here */
561                        continue;
562                }
563                for (address = 1; address < USB_MAX_DEVICES; address++) {
564                        struct usb_device_info device_info;
565                        ifd_devid_t id;
566                        const char *driver;
567                        char typedev[256];
568
569                        device_info.udi_addr = address;
570
571                        if (ioctl(controller_fd, USB_DEVICEINFO, &device_info)) {
572                                if (errno != ENXIO)
573                                        fprintf(stderr,
574                                                "addr %d: I/O error\n",
575                                                address);
576                                continue;
577                        }
578
579                        if (strncmp
580                            (device_info.udi_devnames[0], "ugen", 4) != 0)
581                                continue;
582
583                        id.type = IFD_DEVICE_TYPE_USB;
584                        id.num = 2;
585
586                        id.val[0] = device_info.udi_vendorNo;
587                        id.val[1] = device_info.udi_productNo;
588
589                        ifd_debug(1, "BSD: ifd_scan_usb: "
590                                  "ifd_driver_for(%s[0x%04x].%s[0x%04x)",
591                                  device_info.udi_vendor,
592                                  device_info.udi_vendorNo,
593                                  device_info.udi_product,
594                                  device_info.udi_productNo);
595
596                        /* FIXME: if we don't find a driver with vendor/product
597                         * then check for the interface type (ccid) and use
598                         * driver ccid... */
599
600                        if (!(driver = ifd_driver_for_id(&id)))
601                                continue;
602                        snprintf(typedev, sizeof(typedev),
603                                 "usb:/dev/%s", device_info.udi_devnames[0]);
604
605                        ifd_spawn_handler(driver, typedev, -1);
606                }
607                close(controller_fd);
608        }
609#endif /* ENABLE_LIBUSB */
610        return 0;
611}
612#endif                          /* __Net/Free/OpenBSD__ */
Note: See TracBrowser for help on using the browser.