source: trunk/src/ifd/sys-linux.c @ 1160

Revision 1160, 14.3 KB checked in by aj, 3 years ago (diff)

Aktiv Co./Aleksey Samsonov:
corrected comment in src/ifd/sys-linux.c

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Linux specific functions
3 *
4 * Copyright (C) 2003 Olaf Kirch <okir@suse.de>
5 *
6 * These functions need to be re-implemented for every
7 * new platform.
8 */
9
10#include "internal.h"
11#if defined (__linux__) && !defined (sunray)
12#include <sys/types.h>
13#include <sys/sysmacros.h>
14#include <sys/stat.h>
15#include <sys/ioctl.h>
16#include <sys/poll.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/file.h>
20#include <dirent.h>
21#include <string.h>
22#include <stdio.h>
23#include <stdarg.h>
24#include <signal.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <limits.h>
30#ifdef ENABLE_LIBUSB
31#include <usb.h>
32#endif
33#include <openct/driver.h>
34
35/* imported from linux kernel header include/linux/usbdevice_fs.h */
36
37#define USBDEVICE_SUPER_MAGIC 0x9fa2
38
39/* usbdevfs ioctl codes */
40
41struct usbdevfs_ctrltransfer {
42        uint8_t bRequestType;
43        uint8_t bRequest;
44        uint16_t wValue;
45        uint16_t wIndex;
46        uint16_t wLength;
47        uint32_t timeout;  /* in milliseconds */
48        void *data;
49};
50
51struct usbdevfs_bulktransfer {
52        unsigned int ep;
53        unsigned int len;
54        unsigned int timeout; /* in milliseconds */
55        void *data;
56};
57
58struct usbdevfs_setinterface {
59        unsigned int interface;
60        unsigned int altsetting;
61};
62
63struct usbdevfs_disconnectsignal {
64        unsigned int signr;
65        void *context;
66};
67
68#define USBDEVFS_MAXDRIVERNAME 255
69
70struct usbdevfs_getdriver {
71        unsigned int interface;
72        char driver[USBDEVFS_MAXDRIVERNAME + 1];
73};
74
75struct usbdevfs_connectinfo {
76        unsigned int devnum;
77        unsigned char slow;
78};
79
80#define USBDEVFS_URB_SHORT_NOT_OK          1
81#define USBDEVFS_URB_ISO_ASAP              2
82
83#define USBDEVFS_URB_TYPE_ISO              0
84#define USBDEVFS_URB_TYPE_INTERRUPT        1
85#define USBDEVFS_URB_TYPE_CONTROL          2
86#define USBDEVFS_URB_TYPE_BULK             3
87
88struct usbdevfs_iso_packet_desc {
89        unsigned int length;
90        unsigned int actual_length;
91        unsigned int status;
92};
93
94struct usbdevfs_urb {
95        unsigned char type;
96        unsigned char endpoint;
97        int status;
98        unsigned int flags;
99        void *buffer;
100        int buffer_length;
101        int actual_length;
102        int start_frame;
103        int number_of_packets;
104        int error_count;
105        unsigned int signr;  /* signal to be sent on error, -1 if none should be sent */
106        void *usercontext;
107        struct usbdevfs_iso_packet_desc iso_frame_desc[0];
108};
109
110/* ioctls for talking directly to drivers */
111struct usbdevfs_ioctl {
112        int     ifno;           /* interface 0..N ; negative numbers reserved */
113        int     ioctl_code;     /* MUST encode size + direction of data so the
114                                 * macros in <asm/ioctl.h> give correct values */
115        void *data;     /* param buffer (in, or out) */
116};
117
118/* You can do most things with hubs just through control messages,
119 * except find out what device connects to what port. */
120struct usbdevfs_hub_portinfo {
121        char nports;            /* number of downstream ports in this hub */
122        char port [127];        /* e.g. port 3 connects to device 27 */
123};
124
125#define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
126#define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
127#define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
128#define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
129#define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
130#define USBDEVFS_GETDRIVER         _IOW('U', 8, struct usbdevfs_getdriver)
131#define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
132#define USBDEVFS_DISCARDURB        _IO('U', 11)
133#define USBDEVFS_REAPURB           _IOW('U', 12, void *)
134#define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
135#define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
136#define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
137#define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
138#define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)
139#define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
140#define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
141#define USBDEVFS_RESET             _IO('U', 20)
142#define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
143#define USBDEVFS_DISCONNECT        _IO('U', 22)
144#define USBDEVFS_CONNECT           _IO('U', 23)
145
146/* end of import from usbdevice_fs.h */
147
148#define USB_DISCONNECT_SIGNAL (SIGRTMIN)
149
150/*
151 * Poll for presence of USB device
152 */
153int ifd_sysdep_usb_poll_presence(ifd_device_t * dev, struct pollfd *pfd)
154{
155        if (pfd->revents & POLLHUP)
156                return 0;
157        pfd->fd = dev->fd;
158        pfd->events = POLLHUP;
159        return 1;
160}
161
162/*
163 * Event fd to use.
164 */
165int ifd_sysdep_usb_get_eventfd(ifd_device_t * dev, short *events)
166{
167        *events = POLLOUT;
168        return dev->fd;
169}
170
171/*
172 * USB control command
173 */
174int ifd_sysdep_usb_control(ifd_device_t * dev, unsigned int requesttype,
175                           unsigned int request, unsigned int value,
176                           unsigned int idx, void *data, size_t len,
177                           long timeout)
178{
179        struct usbdevfs_ctrltransfer ctrl;
180        int rc;
181
182        ctrl.bRequestType = requesttype;
183        ctrl.bRequest = request;
184        ctrl.wValue = value;
185        ctrl.wIndex = idx;
186        ctrl.wLength = len;
187        ctrl.data = data;
188        ctrl.timeout = timeout;
189
190        if ((rc = ioctl(dev->fd, USBDEVFS_CONTROL, &ctrl)) < 0) {
191                ct_error("usb_control failed: %m");
192                return IFD_ERROR_COMM_ERROR;
193        }
194
195        return rc;
196}
197
198int ifd_sysdep_usb_set_configuration(ifd_device_t * dev, int config)
199{
200        if (ioctl(dev->fd, USBDEVFS_SETCONFIGURATION, &config) < 0) {
201                ct_error("usb_setconfig failed: %m");
202                return IFD_ERROR_COMM_ERROR;
203        }
204        return 0;
205}
206
207int ifd_sysdep_usb_set_interface(ifd_device_t * dev, int ifc, int alt)
208{
209        struct usbdevfs_setinterface set;
210
211        set.interface = ifc;
212        set.altsetting = alt;
213        if (ioctl(dev->fd, USBDEVFS_SETINTERFACE, &set) < 0) {
214                ct_error("usb_setinterface failed: %m");
215                return IFD_ERROR_COMM_ERROR;
216        }
217        return 0;
218}
219
220int ifd_sysdep_usb_claim_interface(ifd_device_t * dev, int interface)
221{
222        if (ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface) < 0) {
223                ct_error("usb_claiminterface failed: %m");
224                return IFD_ERROR_COMM_ERROR;
225        }
226        return 0;
227}
228
229int ifd_sysdep_usb_release_interface(ifd_device_t * dev, int interface)
230{
231        if (ioctl(dev->fd, USBDEVFS_RELEASEINTERFACE, &interface) < 0) {
232                ct_error("usb_releaseinterface failed: %m");
233                return IFD_ERROR_COMM_ERROR;
234        }
235        return 0;
236}
237
238int ifd_sysdep_usb_reset(ifd_device_t * dev)
239{
240        if (ioctl(dev->fd, USBDEVFS_RESET, NULL) < 0) {
241                ct_error("usb_reset failed: %m");
242                return IFD_ERROR_COMM_ERROR;
243        }
244        return 0;
245}
246
247/*
248 * USB bulk transfer
249 */
250int ifd_sysdep_usb_bulk(ifd_device_t * dev, int ep, void *buffer, size_t len,
251                        long timeout)
252{
253        struct usbdevfs_bulktransfer bulk;
254        int rc;
255
256        bulk.ep = ep;
257        bulk.data = buffer;
258        bulk.len = len;
259        bulk.timeout = timeout;
260        if ((rc = ioctl(dev->fd, USBDEVFS_BULK, &bulk)) < 0) {
261                ct_error("usb_bulk failed: %m");
262                return IFD_ERROR_COMM_ERROR;
263        }
264
265        return rc;
266}
267
268/*
269 * USB URB capture
270 */
271struct ifd_usb_capture {
272        struct usbdevfs_urb urb;
273        int type;
274        int endpoint;
275        size_t maxpacket;
276};
277
278static int usb_submit_urb(int fd, struct ifd_usb_capture *cap)
279{
280        /* Fill in the URB details */
281        ifd_debug(6, "submit urb %p", &cap->urb);
282        memset(&cap->urb, 0, sizeof(cap->urb));
283        cap->urb.type = cap->type;
284        cap->urb.endpoint = cap->endpoint;
285        cap->urb.buffer = (caddr_t) (cap + 1);
286        cap->urb.buffer_length = cap->maxpacket;
287        return ioctl(fd, USBDEVFS_SUBMITURB, &cap->urb);
288}
289
290int ifd_sysdep_usb_begin_capture(ifd_device_t * dev, int type, int endpoint,
291                                 size_t maxpacket, ifd_usb_capture_t ** capret)
292{
293        ifd_usb_capture_t *cap;
294
295        cap = (ifd_usb_capture_t *) calloc(1, sizeof(*cap) + maxpacket);
296        if (!cap) {
297                ct_error("out of memory");
298                return IFD_ERROR_NO_MEMORY;
299        }
300
301        cap->type = type;
302        cap->endpoint = endpoint;
303        cap->maxpacket = maxpacket;
304
305        if (usb_submit_urb(dev->fd, cap) < 0) {
306                ct_error("usb_submiturb failed: %m");
307                ifd_sysdep_usb_end_capture(dev, cap);
308                return IFD_ERROR_COMM_ERROR;
309        }
310
311        *capret = cap;
312        return 0;
313}
314
315int ifd_sysdep_usb_capture_event(ifd_device_t * dev, ifd_usb_capture_t * cap,
316                           void *buffer, size_t len)
317{
318        struct usbdevfs_urb *purb;
319        size_t copied = 0;
320        int rc = 0;
321
322        purb = NULL;
323        rc = ioctl(dev->fd, USBDEVFS_REAPURBNDELAY, &purb);
324        if (rc < 0) {
325                if (errno == EAGAIN)
326                        return 0;
327                ct_error("usb_reapurb failed: %m");
328                return IFD_ERROR_COMM_ERROR;
329        }
330
331        if (purb != &cap->urb) {
332                ifd_debug(2, "reaped usb urb %p", purb);
333                return 0;
334        }
335
336        if (purb->status == -1) {
337                return IFD_ERROR_COMM_ERROR;
338        }
339
340        if (purb->actual_length) {
341                ifd_debug(6, "usb reapurb: len=%u",
342                          purb->actual_length);
343                if ((copied = purb->actual_length) > len)
344                        copied = len;
345                if (copied && buffer)
346                        memcpy(buffer, purb->buffer, copied);
347        }
348        else {
349                usleep(10000);
350        }
351
352        /* Re-submit URB */
353        usb_submit_urb(dev->fd, cap);
354
355        return copied;
356}
357
358int ifd_sysdep_usb_capture(ifd_device_t * dev, ifd_usb_capture_t * cap,
359                           void *buffer, size_t len, long timeout)
360{
361        struct timeval begin;
362        size_t copied;
363        int rc = 0;
364
365        /* Loop until we've reaped the response to the
366         * URB we sent */
367        copied = 0;
368        gettimeofday(&begin, NULL);
369        do {
370                struct pollfd pfd;
371                long wait;
372
373                if ((wait = timeout - ifd_time_elapsed(&begin)) <= 0)
374                        return IFD_ERROR_TIMEOUT;
375
376                pfd.fd = dev->fd;
377                pfd.events = POLLOUT;
378                if (poll(&pfd, 1, wait) != 1)
379                        continue;
380
381                rc = ifd_sysdep_usb_capture_event(dev, cap, buffer, len);
382                if (rc < 0) {
383                        return rc;
384                }
385                copied = (size_t)rc;
386        } while (!copied);
387
388        return copied;
389}
390
391int ifd_sysdep_usb_end_capture(ifd_device_t * dev, ifd_usb_capture_t * cap)
392{
393        int rc = 0;
394
395        if (ioctl(dev->fd, USBDEVFS_DISCARDURB, &cap->urb) < 0
396            && errno != EINVAL) {
397                ct_error("usb_discardurb failed: %m");
398                rc = IFD_ERROR_COMM_ERROR;
399        }
400        /* Discarding an URB will place it in the queue of completed
401         * request, with urb->status == -1. So if we don't reap this
402         * URB now, the next call to REAPURB will return this one,
403         * clobbering random memory.
404         */
405        (void)ioctl(dev->fd, USBDEVFS_REAPURBNDELAY, &cap->urb);
406        free(cap);
407        return rc;
408}
409
410int ifd_sysdep_usb_open(const char *device)
411{
412        struct usbdevfs_disconnectsignal ds;
413        struct sigaction act;
414        int fd = -1;
415        int ret = -1;
416
417        fd = open(device, O_RDWR);
418        if (fd == -1) {
419                goto cleanup;
420        }
421
422        /*
423         * The following will send signal
424         * to the process when device is disconnected
425         * even if the signal is ignored the blocking
426         * call will exit.
427         * <linux.2.6.28 - This code will have no affect.
428         * =linux-2.6.28 - CONFIG_USB_DEVICEFS must be on.
429         * >=linux-2.6.29 - works.
430         */
431        memset(&act, 0, sizeof(act));
432        act.sa_handler = SIG_IGN;
433        if (sigaction(USB_DISCONNECT_SIGNAL, &act, NULL) == -1) {
434                goto cleanup;
435        }
436
437        memset(&ds, 0, sizeof(ds));
438        ds.signr = USB_DISCONNECT_SIGNAL;
439        if (ioctl(fd, USBDEVFS_DISCSIGNAL, &ds) == -1) {
440                goto cleanup;
441        }
442
443        ret = fd;
444        fd = -1;
445
446cleanup:
447        if (fd != -1) {
448                close(fd);
449        }
450
451        return ret;
452}
453
454#ifndef ENABLE_LIBUSB
455static int read_number (const char *read_format, const char *format, ...) {
456        va_list args;
457        char full[PATH_MAX];
458        FILE *fp = NULL;
459        int n = -1;
460
461        va_start(args, format);
462        vsnprintf (full, sizeof(full), format, args);
463        va_end(args);
464
465        if ((fp = fopen (full, "r")) == NULL) {
466                goto out;
467        }
468
469        fscanf (fp, read_format, &n);
470
471out:
472        if (fp != NULL) {
473                fclose (fp);
474        }
475
476        return n;
477}
478#endif
479
480/*
481 * Scan all usb devices to see if there is one we support
482 */
483int ifd_scan_usb(void)
484{
485#ifdef ENABLE_LIBUSB
486        ifd_devid_t id;
487        struct usb_bus *bus;
488        struct usb_device *dev;
489
490        usb_init();
491        usb_find_busses();
492        usb_find_devices();
493
494        id.type = IFD_DEVICE_TYPE_USB;
495        id.num = 2;
496        for (bus = usb_busses; bus; bus = bus->next) {
497                for (dev = bus->devices; dev; dev = dev->next) {
498                        const char *driver = NULL;
499                        char typedev[PATH_MAX];
500                        struct stat buf;
501
502                        id.val[0] = dev->descriptor.idVendor;
503                        id.val[1] = dev->descriptor.idProduct;
504
505                        /* if we don't find a driver with vendor/product
506                         * then check for the interface type (ccid) and use
507                         * driver ccid... */
508
509                        if (!(driver = ifd_driver_for_id(&id))) {
510                                /* no driver found, check for interface class */
511                                int conf;
512                                for (conf = 0; conf < dev->descriptor.bNumConfigurations;
513                                        conf++) {
514                                        int interf;
515                                        for (interf = 0; interf < dev->config[conf].bNumInterfaces;
516                                                interf++) {
517                                                int alt;
518                                                for (alt = 0; alt < dev->config[conf].interface[interf].num_altsetting; alt++) {
519                                                        if (dev->config[conf].interface[interf].altsetting[alt].bInterfaceClass == 0x0b) {
520                                                                driver = "ccid";
521                                                        }
522                                                }
523                                        }       
524                                }
525                        }
526
527                        if (driver != NULL) {
528                                snprintf(typedev, sizeof(typedev),
529                                         "/dev/bus/usb/%s/%s",
530                                         bus->dirname, dev->filename);
531                                if (stat(typedev, &buf) == 0) {
532                                        snprintf(typedev, sizeof(typedev),
533                                                "usb:/dev/bus/usb/%s/%s",
534                                                bus->dirname, dev->filename);
535                                        ifd_spawn_handler(driver, typedev, -1);
536                                } else {
537                                        snprintf(typedev, sizeof(typedev),
538                                                "usb:/proc/bus/usb/%s/%s",
539                                                bus->dirname, dev->filename);
540                                        ifd_spawn_handler(driver, typedev, -1);
541                                }
542                        }
543                }
544        }
545#else
546        const char *base = "/sys/bus/usb/devices";
547        DIR *dir = NULL;
548        struct dirent *ent;
549
550        if ((dir = opendir (base)) == NULL) {
551                goto out;
552        }
553
554        while ((ent = readdir (dir)) != NULL) {
555                if (ent->d_name[0] != '.') {
556                        int idProduct = -1;
557                        int idVendor = -1;
558                        int busnum = -1;
559                        int devnum = -1;
560
561                        idProduct = read_number ("%x", "%s/%s/%s", base, ent->d_name, "idProduct");
562                        idVendor = read_number ("%x", "%s/%s/%s", base, ent->d_name, "idVendor");
563                        busnum = read_number ("%d", "%s/%s/%s", base, ent->d_name, "busnum");
564                        devnum = read_number ("%d", "%s/%s/%s", base, ent->d_name, "devnum");
565
566                        ifd_debug (6, "coldplug: %s usb: %04x:%04x bus: %03d:%03d\n", ent->d_name, idProduct, idVendor, busnum, devnum);
567
568                        if (idProduct != -1 && idVendor != -1 && busnum != -1 && devnum != -1) {
569                                const char *driver = NULL;
570                                ifd_devid_t id;
571
572                                id.type = IFD_DEVICE_TYPE_USB;
573                                id.num = 2;
574                                id.val[0] = idVendor;
575                                id.val[1] = idProduct;
576
577                                if ((driver = ifd_driver_for_id(&id)) == NULL) {
578                                        DIR *dir1 = NULL;
579                                        struct dirent *ent1;
580
581                                        if ((dir1 = opendir (base)) != NULL) {
582                                                while ((ent1 = readdir (dir1)) != NULL && driver == NULL) {
583                                                        /* skip all none bus elements */
584                                                        if (strncmp (ent->d_name, ent1->d_name, strlen (ent->d_name))) {
585                                                                continue;
586                                                        }
587
588                                                        if (
589                                                                read_number (
590                                                                        "%x",
591                                                                        "%s/%s/%s/%s",
592                                                                        base,
593                                                                        ent->d_name,
594                                                                        ent1->d_name,
595                                                                        "bInterfaceClass"
596                                                                ) == 0x0b
597                                                        ) {
598                                                                driver = "ccid";
599                                                        }
600                                                }
601                                                closedir (dir1);
602                                        }
603                                }
604
605                                if (driver != NULL) {
606                                        char typedev[1024];
607
608                                        snprintf(typedev, sizeof(typedev),
609                                                "usb:/dev/bus/usb/%03d/%03d",
610                                                busnum, devnum);
611                                        ifd_spawn_handler(driver, typedev, -1);
612                                }
613                        }
614                }
615        }
616
617out:
618        if (dir != NULL) {
619                closedir (dir);
620        }
621#endif
622        return 0;
623}
624
625#endif                          /* __linux__ */
Note: See TracBrowser for help on using the repository browser.