source: trunk/src/ifd/sys-solaris.c @ 1137

Revision 1137, 15.6 KB checked in by alonbl, 3 years ago (diff)

Allow driver to specify events to poll

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Solaris specific functions
3 *
4 * Copyright (C) 2004 William Wanders <william@wanders.org>
5 *
6 */
7
8#include "internal.h"
9#if defined (sun) && !defined (sunray)
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <sys/file.h>
13#include <dirent.h>
14#include <errno.h>
15#include <stdio.h>
16#include <openct/driver.h>
17#include <fcntl.h>
18#include <stddef.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <string.h>
22#include <limits.h>
23
24#include <sys/usb/usba.h>
25#include <sys/usb/clients/ugen/usb_ugen.h>
26
27/*
28 * USB Device Setup Packet
29 * Refer to USB 2.0/ 9.3
30 *
31 * All USB devices respond to requests from the host on the device's
32 * Default Control Pipe. These request are made using control transfers.
33 * The request and the request's parameters are sent to the device in
34 * the Setup packet. Every Setup packet has eight bytes:
35 *
36 * Offset       Field           Size
37 * ----------------------------------
38 *   0          bmRequestType    1
39 *   1          bRequest         1
40 *   2          wValue           2
41 *   4          wIndex           2
42 *   6          wLength          2
43 *
44 * IMPORTANT: Pay attention to (little) endianness.
45 *
46 */
47typedef struct usb_request {
48        uint8_t bmRequestType;  /* Request Type                 */
49        uint8_t bRequest;       /* Setup Request                */
50        uint16_t wValue;        /* Request Info                 */
51        uint16_t wIndex;        /* Index/Offset Info            */
52        uint16_t wLength;       /* Number of bytes in transfer  */
53        uint8_t data[1];        /* Outgoing Data                */
54} usb_request_t;
55
56/*
57 * Globals
58 */
59static int cntrl0_fd = 0;
60static int cntrl0stat_fd = 0;
61static int devstat_fd = 0;
62
63typedef struct ep {
64        int ep_fd[2];
65        int ep_stat_fd[2];
66} ep_t;
67
68typedef ep_t interface_t[128];
69
70static interface_t interfaces[1];
71
72/*
73 * Defines
74 */
75#define USB_DEVICE_ROOT "/dev/usb"
76#define BYTESWAP(in)    (((in & 0xFF) << 8) + ((in & 0xFF00) >> 8))
77#define USB_REQUEST_SIZE        8
78
79/*
80 * Open device status interface
81 */
82static int open_devstat(char *name)
83{
84        /* Open devstat to retrieve control pipe status. */
85        if (!devstat_fd) {
86                char *devstat;
87
88                if ((devstat = calloc(1, strlen(name) + 2)) == NULL) {
89                        ct_error("out of memory");
90                        return IFD_ERROR_NO_MEMORY;
91                }
92                strcpy(devstat, name);
93                strcpy(devstat + strlen(name) - 6, "devstat");
94
95                ifd_debug(6, "open_devstat: open device status: \"%s\"",
96                          devstat);
97
98                if ((devstat_fd =
99                     open(devstat, O_RDONLY | O_EXCL | O_NONBLOCK)) < 0) {
100                        ifd_debug(6, "open_devstat: Error opening \"%s\": %s",
101                                  devstat, strerror(errno));
102                        free(devstat);
103                        return -1;
104                }
105                free(devstat);
106                ifd_debug(6, "open_cntrl0stat: devstat_fd=%d", devstat_fd);
107        }
108        return 0;
109}
110
111/*
112 * Open device control status interface
113 */
114static int open_cntrl0stat(char *name)
115{
116        /* Open cntrl0stat to retrieve control pipe status. */
117        if (!cntrl0stat_fd) {
118                char *cntrl0stat;
119
120                if ((cntrl0stat = calloc(1, strlen(name) + 5)) == NULL) {
121                        ct_error("out of memory");
122                        return -1;
123                }
124                strcpy(cntrl0stat, name);
125                strcat(cntrl0stat, "stat");
126
127                ifd_debug(6,
128                          "open_cntrl0stat: open control pipe status: \"%s\"",
129                          cntrl0stat);
130
131                if ((cntrl0stat_fd = open(cntrl0stat, O_RDONLY | O_EXCL)) < 0) {
132                        ifd_debug(6,
133                                  "open_cntrl0stat: Error opening \"%s\": %s",
134                                  cntrl0stat, strerror(errno));
135                        free(cntrl0stat);
136                        return 0;
137                }
138                free(cntrl0stat);
139                ifd_debug(6, "open_cntrl0stat: cntrl0stat_fd=%d",
140                          cntrl0stat_fd);
141        }
142        return 1;
143}
144
145/*
146 * Open interface endpoint
147 */
148int open_ep(char *name, int interface, int endpoint, int direction, int flags)
149{
150        char filename[256];
151        char intdirep[32];
152
153        if (interfaces[interface][endpoint].ep_fd[direction]) {
154                ifd_debug(6, "open_ep: endpoint already opened");
155                return 0;
156        }
157        sprintf((char *)&intdirep, "if%d%s%d",
158                interface, direction ? "in" : "out", endpoint);
159
160        memset((char *)&filename, 0, strlen(name) + 2);
161        strcpy((char *)&filename, name);
162        filename[strlen(name) - 6] = '\0';
163        strcat((char *)&filename, (char *)&intdirep);
164
165        if ((interfaces[interface][endpoint].ep_fd[direction] =
166             open(filename,
167                  direction ? O_RDONLY | flags : O_WRONLY | flags)) < 0) {
168                ifd_debug(6, "open_ep: error opening \"%s\": %s", filename,
169                          strerror(errno));
170                interfaces[interface][endpoint].ep_fd[direction] = 0;
171                return -1;
172        }
173#if 0
174        strcat((char *)&filename, "stat");
175        if ((interfaces[interface][endpoint].ep_stat_fd[direction] =
176             open(filename, O_RDONLY | O_NONBLOCK)) < 0) {
177                ifd_debug(6, "open_ep: error opening \"%s\": %s", filename,
178                          strerror(errno));
179                close(interfaces[interface][endpoint].ep_fd[direction]);
180                interfaces[interface][endpoint].ep_fd[direction] = 0;
181                interfaces[interface][endpoint].ep_stat_fd[direction] = 0;
182                return -1;
183        }
184#endif
185        return 0;
186}
187
188void close_ep(int interface, int endpoint, int direction)
189{
190        if (interfaces[interface][endpoint].ep_fd[direction]) {
191                close(interfaces[interface][endpoint].ep_fd[direction]);
192                interfaces[interface][endpoint].ep_fd[direction] = 0;
193        }
194        if (interfaces[interface][endpoint].ep_stat_fd[direction]) {
195                close(interfaces[interface][endpoint].ep_stat_fd[direction]);
196                interfaces[interface][endpoint].ep_stat_fd[direction] = 0;
197        }
198}
199
200/*
201 * Prepare a USB control request.  Please see USB 2.0 spec section 9.4.
202 */
203static void
204prepare_usb_control_req(usb_request_t * req, uint8_t bmRequestType,
205                        uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
206                        uint16_t wLength)
207{
208        (*req).bmRequestType = bmRequestType;
209        (*req).bRequest = bRequest;
210
211#ifdef _BIG_ENDIAN
212        /* Sparc is big endian, USB little endian */
213        (*req).wValue = BYTESWAP(wValue);
214        (*req).wIndex = BYTESWAP(wIndex);
215        (*req).wLength = BYTESWAP(wLength);
216#else
217        (*req).wValue = wValue;
218        (*req).wIndex = wIndex;
219        (*req).wLength = wLength;
220#endif                          /* _BIG_ENDIAN */
221}
222
223/*
224 * Poll for presence of USB device
225 */
226int ifd_sysdep_usb_poll_presence(ifd_device_t * dev, struct pollfd *pfd)
227{
228        int devstat = 0;
229
230        pfd->fd = -1;
231        if (open_devstat(dev->name) < 0) {
232                ifd_debug(1,
233                          "ifd_sysdep_usb_poll_presence: cannot open devstat device for %s",
234                          dev->name);
235                return 0;
236        }
237        if (read(devstat_fd, &devstat, sizeof(devstat))) {
238                switch (devstat) {
239                case USB_DEV_STAT_ONLINE:
240                        ifd_debug(1, "devstat: ONLINE (%d)", devstat);
241                        break;
242                case USB_DEV_STAT_DISCONNECTED:
243                        ifd_debug(1, "devstat: DISCONNECTED (%d)", devstat);
244                        return 0;
245                default:
246                        ifd_debug(1, "devstat: %d", devstat);
247                        return 0;
248                }
249        }
250        return 1;
251}
252
253/*
254 * Event fd
255 */
256int ifd_sysdep_usb_get_eventfd(ifd_device_t * dev, short *events)
257{
258        return -1;
259}
260
261/*
262 * USB control command
263 */
264int
265ifd_sysdep_usb_control(ifd_device_t * dev,
266                       unsigned int requesttype,
267                       unsigned int request,
268                       unsigned int value,
269                       unsigned int index, void *data, size_t len, long timeout)
270{
271        int bytes_to_process;
272        int bytes_processed;
273        int failed = 0;
274        usb_request_t *usb_control_req;
275        char *recv_data;
276
277        ifd_debug(6, "ifd_sysdep_usb_control:"
278                  " requestType = 0x%02x"
279                  " request = 0x%02x"
280                  " value = 0x%02x"
281                  " index = 0x%02x", requesttype, request, value, index);
282
283        bytes_to_process = USB_REQUEST_SIZE +
284            ((requesttype & USB_EP_DIR_MASK) == USB_EP_DIR_OUT ? len : 0);
285        if ((usb_control_req = calloc(1, bytes_to_process)) == NULL) {
286                ct_error("out of memory");
287                return -1;
288        }
289        if ((recv_data = calloc(1, len)) == NULL) {
290                ct_error("out of memory");
291                free(usb_control_req);
292                return -1;
293        }
294
295        if (!open_cntrl0stat(dev->name))
296                return -1;
297
298        /* Initialize the USB control request */
299        prepare_usb_control_req(usb_control_req, requesttype, request, value,
300                                index, len);
301
302        /* Add any additional */
303        if (((requesttype & USB_EP_DIR_MASK) == USB_EP_DIR_OUT) && len) {
304                ifd_debug(6, "ifd_sysdep_usb_control: copying output data : %s",
305                          ct_hexdump(data, len));
306                memcpy(usb_control_req->data, data, len);
307        }
308
309        /* Send request down the control pipe to the device. */
310        bytes_processed = write(dev->fd, usb_control_req, bytes_to_process);
311        if (bytes_processed != bytes_to_process) {
312                ifd_debug(6, "ifd_sysdep_usb_control: write failed: %s",
313                          strerror(errno));
314                ct_error("usb_control write failed: %s", strerror(errno));
315                failed = IFD_ERROR_COMM_ERROR;
316                goto cleanup;
317        }
318
319        /* Read the return data from the device. */
320        bytes_processed = read(dev->fd, recv_data, len);
321        if (bytes_processed < 0) {
322                ifd_debug(6, "ifd_sysdep_usb_control: read failed: %s",
323                          strerror(errno));
324                ct_error("usb_control read failed: %s", strerror(errno));
325                failed = IFD_ERROR_COMM_ERROR;
326                goto cleanup;
327        }
328        if (bytes_processed) {
329                ifd_debug(6, "ifd_sysdep_usb_control: input data[%d] : %s",
330                          bytes_processed, ct_hexdump(recv_data,
331                                                      bytes_processed));
332                if ((requesttype & USB_EP_DIR_MASK) == USB_EP_DIR_IN)
333                        memcpy(data, recv_data, bytes_processed);
334        } else
335                ifd_debug(6, "ifd_sysdep_usb_control: input data[%d]",
336                          bytes_processed);
337
338      cleanup:
339        if (recv_data)
340                free(recv_data);
341        if (usb_control_req)
342                free(usb_control_req);
343        if (failed)
344                return failed;
345
346        return bytes_processed;
347}
348
349int ifd_sysdep_usb_set_configuration(ifd_device_t * dev, int config)
350{
351        ct_debug
352            ("ifd_sysdep_usb_set_configuration: config=%d (not yet implemented)",
353             config);
354        return 0;
355}
356
357int ifd_sysdep_usb_set_interface(ifd_device_t * dev, int ifc, int alt)
358{
359        ct_debug
360            ("ifd_sysdep_usb_set_interface: alt=%d ifc=%d (not yet implemented)",
361             alt, ifc);
362        return 0;
363}
364
365int ifd_sysdep_usb_claim_interface(ifd_device_t * dev, int interface)
366{
367        ct_debug
368            ("ifd_sysdep_usb_claim_interface: interface=%d (not yet implented)",
369             interface);
370        return 0;
371}
372
373int ifd_sysdep_usb_release_interface(ifd_device_t * dev, int interface)
374{
375        ct_debug("ifd_sysdep_usb_release_interface: not implented yet");
376        return 0;
377}
378
379int
380ifd_sysdep_usb_bulk(ifd_device_t * dev, int ep, void *buffer, size_t len,
381                    long timeout)
382{
383        int bytes_to_process;
384        int bytes_processed;
385        int direction = (ep & USB_EP_DIR_MASK) == USB_EP_DIR_IN ? 1 : 0;
386        int endpoint = (ep & ~USB_EP_DIR_MASK);
387
388        ct_debug("ifd_sysdep_usb_bulk: endpoint=%d direction=%d", endpoint,
389                 direction);
390        if (open_ep(dev->name, 0, endpoint, direction, 0)) {
391                ct_debug("ifd_sysdep_usb_bulk: opening endpoint failed");
392                return -1;
393        }
394        if (direction) {
395                if ((bytes_to_process =
396                     read(interfaces[0][endpoint].ep_fd[direction], buffer,
397                          len)) < 0) {
398                        ifd_debug(6, "ifd_sysdep_usb_bulk: read failed: %s",
399                                  strerror(errno));
400                        ct_error("usb_bulk read failed: %s", strerror(errno));
401                        return IFD_ERROR_COMM_ERROR;
402                }
403                ct_debug("ifd_sysdep_usb_bulk: read %d bytes",
404                         bytes_to_process);
405                return bytes_to_process;
406        } else {
407                bytes_to_process = len;
408                if ((bytes_processed =
409                     write(interfaces[0][endpoint].ep_fd[direction], buffer,
410                           bytes_to_process)) != bytes_to_process) {
411                        ifd_debug(6, "ifd_sysdep_usb_bulk: write failed: %s",
412                                  strerror(errno));
413                        ct_error("usb_bulk write failed: %s", strerror(errno));
414                        return IFD_ERROR_COMM_ERROR;
415                }
416                ct_debug("ifd_sysdep_usb_bulk: wrote buffer[%d]=%s",
417                         bytes_processed, ct_hexdump(buffer, len));
418                return bytes_processed;
419        }
420}
421
422/*
423 * USB URB capture
424 */
425struct ifd_usb_capture {
426        int type;
427        int endpoint;
428        size_t maxpacket;
429        unsigned int interface;
430};
431
432int
433ifd_sysdep_usb_begin_capture(ifd_device_t * dev,
434                             int type, int ep, size_t maxpacket,
435                             ifd_usb_capture_t ** capret)
436{
437        ifd_usb_capture_t *cap;
438        int direction = (ep & USB_EP_DIR_MASK) == USB_EP_DIR_IN ? 1 : 0;
439        int endpoint = (ep & ~USB_EP_DIR_MASK);
440
441        if (!(cap = (ifd_usb_capture_t *) calloc(1, sizeof(*cap) + maxpacket))) {
442                ct_error("out of memory");
443                return -1;
444        }
445        cap->type = type;
446        cap->endpoint = ep;
447        cap->maxpacket = maxpacket;
448
449        if (!interfaces[0][endpoint].ep_fd[direction]) {
450                if (open_ep(dev->name, 0, endpoint, direction, O_NONBLOCK)) {
451                        ct_debug
452                            ("ifd_sysdep_usb_begin_capture: opening endpoint failed");
453                        return -1;
454                }
455        }
456        *capret = cap;
457        return 0;
458}
459
460int ifd_sysdep_usb_capture_event(ifd_device_t * dev, ifd_usb_capture_t * cap,
461                           void *buffer, size_t len)
462{
463        return IFD_ERROR_NOT_SUPPORTED;
464}
465
466int
467ifd_sysdep_usb_capture(ifd_device_t * dev,
468                       ifd_usb_capture_t * cap,
469                       void *buffer, size_t len, long timeout)
470{
471        struct timeval begin;
472        int bytes_to_process = 0;
473        int direction =
474            (cap->endpoint & USB_EP_DIR_MASK) == USB_EP_DIR_IN ? 1 : 0;
475        int endpoint = (cap->endpoint & ~USB_EP_DIR_MASK);
476
477        gettimeofday(&begin, NULL);
478        do {
479                struct pollfd pfd;
480                long wait;
481
482                if ((wait = (timeout - ifd_time_elapsed(&begin))) <= 0)
483                        return IFD_ERROR_TIMEOUT;
484
485                pfd.fd = interfaces[0][endpoint].ep_fd[direction];
486                pfd.events = POLL_IN;
487                if (poll(&pfd, 1, wait) != 1)
488                        continue;
489
490                if ((bytes_to_process =
491                     read(interfaces[0][endpoint].ep_fd[direction], buffer,
492                          len)) < 0) {
493                        ifd_debug(6, "ifd_sysdep_usb_bulk: read failed: %s",
494                                  strerror(errno));
495                        ct_error("usb_bulk read failed: %s", strerror(errno));
496                        return IFD_ERROR_COMM_ERROR;
497                }
498        } while (!bytes_to_process);
499        ct_debug("ifd_sysdep_usb_capture: read buffer[%d]=%s", bytes_to_process,
500                 ct_hexdump(buffer, bytes_to_process));
501        return bytes_to_process;
502}
503
504int ifd_sysdep_usb_end_capture(ifd_device_t * dev, ifd_usb_capture_t * cap)
505{
506        int direction =
507            (cap->endpoint & USB_EP_DIR_MASK) == USB_EP_DIR_IN ? 1 : 0;
508        int endpoint = (cap->endpoint & ~USB_EP_DIR_MASK);
509        close_ep(0, endpoint, direction);
510        if (cap)
511                free(cap);
512        return 0;
513}
514
515int ifd_sysdep_usb_open(const char *device)
516{
517        return open(device, O_RDWR);
518}
519
520int ifd_sysdep_usb_reset(ifd_device_t * dev)
521{
522        /* not implemented so far */
523        return -1;
524}
525
526/*
527 * Scan the /dev/usb directory to see if there is any control pipe matching:
528 *
529 *            /dev/usb/<vendor>.<product>/<instance>/cntrl0
530 *
531 * If a suitable driver is found for this <vendor> <product> combination
532 * an ifd handler is spawned for every instance.
533 *
534 */
535int ifd_scan_usb(void)
536{
537        DIR *usb_device_root;
538        struct dirent *device_type;
539
540        ifd_debug(1, "ifd_scan_usb:");
541        usb_device_root = opendir(USB_DEVICE_ROOT);
542        do {
543                int vendor = 0, product = 0;
544                char device_type_root_name[256];
545                DIR *device_type_root;
546                struct dirent *device_instance;
547                ifd_devid_t id;
548                const char *driver;
549
550                errno = 0;
551                if ((device_type = readdir(usb_device_root)) == NULL)
552                        continue;
553                if (strncmp(device_type->d_name, ".", 1) == 0)
554                        continue;
555                if (sscanf(device_type->d_name, "%x.%x", &vendor, &product) !=
556                    2)
557                        continue;
558
559                ifd_debug(1, "ifd_scan_usb: found device tree usb:%04x/%04x\n",
560                          vendor, product);
561
562                id.type = IFD_DEVICE_TYPE_USB;
563                id.num = 2;
564                id.val[0] = vendor;
565                id.val[1] = product;
566
567                /* FIXME: if we don't find a driver with vendor/product
568                 * then check for the interface type (ccid) and use
569                 * driver ccid... */
570
571                if (!(driver = ifd_driver_for_id(&id)))
572                        continue;
573
574                ifd_debug(1,
575                          "ifd_scan_usb: found driver type \"%s\" for usb:%04x/%04x\n",
576                          driver, vendor, product);
577
578                sprintf(device_type_root_name, "%s/%s", USB_DEVICE_ROOT,
579                        device_type->d_name);
580                if (!(device_type_root = opendir(device_type_root_name)))
581                        continue;
582
583                do {
584                        int device = -1;
585                        char device_instance_cntrl0_name[256];
586                        char typedev[256];
587                        struct stat dummy;
588
589                        errno = 0;
590                        if ((device_instance =
591                             readdir(device_type_root)) == NULL)
592                                continue;
593
594                        if (strncmp(device_instance->d_name, ".", 1) == 0)
595                                continue;
596                        ifd_debug(1, "ifd_scan_usb: \tfound device %s\n",
597                                  device_instance->d_name);
598                        if (sscanf(device_instance->d_name, "%d", &device) != 1)
599                                continue;
600
601                        sprintf(device_instance_cntrl0_name, "%s/%d/cntrl0",
602                                device_type_root_name, device);
603                        if (stat(device_instance_cntrl0_name, &dummy) == 0) {
604                                ifd_debug(1,
605                                          "ifd_scan_usb: \t\tfound device instance %s\n",
606                                          device_instance_cntrl0_name);
607                                snprintf(typedev, sizeof(typedev),
608                                         "usb:%s", device_instance_cntrl0_name);
609                                ifd_spawn_handler(driver, typedev, -1);
610                        }
611                } while (device_instance != NULL);
612                if (errno != 0)
613                        perror("error reading directory");
614
615                closedir(device_type_root);
616        } while (device_type != NULL);
617
618        if (errno != 0)
619                ifd_debug(1, "ifd_scan_usb: error reading directory");
620
621        closedir(usb_device_root);
622        return 0;
623}
624#endif                          /* sun && !sunray */
Note: See TracBrowser for help on using the repository browser.