source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/usb-linux.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 15.0 KB
Line 
1/*
2 * Linux host USB redirector
3 *
4 * Copyright (c) 2005 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include "vl.h"
25
26#if defined(__linux__)
27#include <dirent.h>
28#include <sys/ioctl.h>
29/* Some versions of usbdevice_fs.h need __user to be defined for them.   */
30/* This may (harmlessly) conflict with a definition in linux/compiler.h. */
31#define __user
32#include <linux/usbdevice_fs.h>
33#include <linux/version.h>
34
35/* We redefine it to avoid version problems */
36struct usb_ctrltransfer {
37    uint8_t  bRequestType;
38    uint8_t  bRequest;
39    uint16_t wValue;
40    uint16_t wIndex;
41    uint16_t wLength;
42    uint32_t timeout;
43    void *data;
44};
45
46typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
47                        int vendor_id, int product_id, 
48                        const char *product_name, int speed);
49static int usb_host_find_device(int *pbus_num, int *paddr, 
50                                char *product_name, int product_name_size,
51                                const char *devname);
52
53//#define DEBUG
54
55#define USBDEVFS_PATH "/proc/bus/usb"
56#define PRODUCT_NAME_SZ 32
57
58typedef struct USBHostDevice {
59    USBDevice dev;
60    int fd;
61} USBHostDevice;
62
63static void usb_host_handle_reset(USBDevice *dev)
64{
65#if 0
66    USBHostDevice *s = (USBHostDevice *)dev;
67    /* USBDEVFS_RESET, but not the first time as it has already be
68       done by the host OS */
69    ioctl(s->fd, USBDEVFS_RESET);
70#endif
71} 
72
73static void usb_host_handle_destroy(USBDevice *dev)
74{
75    USBHostDevice *s = (USBHostDevice *)dev;
76
77    if (s->fd >= 0)
78        close(s->fd);
79    qemu_free(s);
80}
81
82static int usb_host_handle_control(USBDevice *dev,
83                                   int request,
84                                   int value,
85                                   int index,
86                                   int length,
87                                   uint8_t *data)
88{
89    USBHostDevice *s = (USBHostDevice *)dev;
90    struct usb_ctrltransfer ct;
91    int ret;
92
93    if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
94        /* specific SET_ADDRESS support */
95        dev->addr = value;
96        return 0;
97    } else {
98        ct.bRequestType = request >> 8;
99        ct.bRequest = request;
100        ct.wValue = value;
101        ct.wIndex = index;
102        ct.wLength = length;
103        ct.timeout = 50;
104        ct.data = data;
105        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
106        if (ret < 0) {
107            switch(errno) {
108            case ETIMEDOUT:
109                return USB_RET_NAK;
110            default:
111                return USB_RET_STALL;
112            }
113        } else {
114            return ret;
115        }
116   }
117}
118
119static int usb_host_handle_data(USBDevice *dev, int pid, 
120                                uint8_t devep,
121                                uint8_t *data, int len)
122{
123    USBHostDevice *s = (USBHostDevice *)dev;
124    struct usbdevfs_bulktransfer bt;
125    int ret;
126
127    /* XXX: optimize and handle all data types by looking at the
128       config descriptor */
129    if (pid == USB_TOKEN_IN)
130        devep |= 0x80;
131    bt.ep = devep;
132    bt.len = len;
133    bt.timeout = 50;
134    bt.data = data;
135    ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
136    if (ret < 0) {
137        switch(errno) {
138        case ETIMEDOUT:
139            return USB_RET_NAK;
140        case EPIPE:
141        default:
142#ifdef DEBUG
143            printf("handle_data: errno=%d\n", errno);
144#endif
145            return USB_RET_STALL;
146        }
147    } else {
148        return ret;
149    }
150}
151
152/* XXX: exclude high speed devices or implement EHCI */
153USBDevice *usb_host_device_open(const char *devname)
154{
155    int fd, interface, ret, i;
156    USBHostDevice *dev;
157    struct usbdevfs_connectinfo ci;
158    uint8_t descr[1024];
159    char buf[1024];
160    int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
161    int bus_num, addr;
162    char product_name[PRODUCT_NAME_SZ];
163
164    if (usb_host_find_device(&bus_num, &addr, 
165                             product_name, sizeof(product_name),
166                             devname) < 0) 
167        return NULL;
168   
169    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", 
170             bus_num, addr);
171    fd = open(buf, O_RDWR);
172    if (fd < 0) {
173        perror(buf);
174        return NULL;
175    }
176
177    /* read the config description */
178    descr_len = read(fd, descr, sizeof(descr));
179    if (descr_len <= 0) {
180        perror("read descr");
181        goto fail;
182    }
183   
184    i = 0;
185    dev_descr_len = descr[0];
186    if (dev_descr_len > descr_len)
187        goto fail;
188    i += dev_descr_len;
189    config_descr_len = descr[i];
190    if (i + config_descr_len > descr_len)
191        goto fail;
192    nb_interfaces = descr[i + 4];
193    if (nb_interfaces != 1) {
194        /* NOTE: currently we grab only one interface */
195        fprintf(stderr, "usb_host: only one interface supported\n");
196        goto fail;
197    }
198
199#ifdef USBDEVFS_DISCONNECT
200    /* earlier Linux 2.4 do not support that */
201    {
202        struct usbdevfs_ioctl ctrl;
203        ctrl.ioctl_code = USBDEVFS_DISCONNECT;
204        ctrl.ifno = 0;
205        ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl);
206        if (ret < 0 && errno != ENODATA) {
207            perror("USBDEVFS_DISCONNECT");
208            goto fail;
209        }
210    }
211#endif
212
213    /* XXX: only grab if all interfaces are free */
214    interface = 0;
215    ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
216    if (ret < 0) {
217        if (errno == EBUSY) {
218            fprintf(stderr, "usb_host: device already grabbed\n");
219        } else {
220            perror("USBDEVFS_CLAIMINTERFACE");
221        }
222    fail:
223        close(fd);
224        return NULL;
225    }
226
227    ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
228    if (ret < 0) {
229        perror("USBDEVFS_CONNECTINFO");
230        goto fail;
231    }
232
233#ifdef DEBUG
234    printf("host USB device %d.%d grabbed\n", bus_num, addr);
235#endif   
236
237    dev = qemu_mallocz(sizeof(USBHostDevice));
238    if (!dev)
239        goto fail;
240    dev->fd = fd;
241    if (ci.slow)
242        dev->dev.speed = USB_SPEED_LOW;
243    else
244        dev->dev.speed = USB_SPEED_HIGH;
245    dev->dev.handle_packet = usb_generic_handle_packet;
246
247    dev->dev.handle_reset = usb_host_handle_reset;
248    dev->dev.handle_control = usb_host_handle_control;
249    dev->dev.handle_data = usb_host_handle_data;
250    dev->dev.handle_destroy = usb_host_handle_destroy;
251
252    if (product_name[0] == '\0')
253        snprintf(dev->dev.devname, sizeof(dev->dev.devname),
254                 "host:%s", devname);
255    else
256        pstrcpy(dev->dev.devname, sizeof(dev->dev.devname),
257                product_name);
258
259    return (USBDevice *)dev;
260}
261
262static int get_tag_value(char *buf, int buf_size,
263                         const char *str, const char *tag, 
264                         const char *stopchars)
265{
266    const char *p;
267    char *q;
268    p = strstr(str, tag);
269    if (!p)
270        return -1;
271    p += strlen(tag);
272    while (isspace(*p))
273        p++;
274    q = buf;
275    while (*p != '\0' && !strchr(stopchars, *p)) {
276        if ((q - buf) < (buf_size - 1))
277            *q++ = *p;
278        p++;
279    }
280    *q = '\0';
281    return q - buf;
282}
283
284static int usb_host_scan(void *opaque, USBScanFunc *func)
285{
286    FILE *f;
287    char line[1024];
288    char buf[1024];
289    int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
290    int ret;
291    char product_name[512];
292   
293    f = fopen(USBDEVFS_PATH "/devices", "r");
294    if (!f) {
295        term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
296        return 0;
297    }
298    device_count = 0;
299    bus_num = addr = speed = class_id = product_id = vendor_id = 0;
300    ret = 0;
301    for(;;) {
302        if (fgets(line, sizeof(line), f) == NULL)
303            break;
304        if (strlen(line) > 0)
305            line[strlen(line) - 1] = '\0';
306        if (line[0] == 'T' && line[1] == ':') {
307            if (device_count && (vendor_id || product_id)) {
308                /* New device.  Add the previously discovered device.  */
309                ret = func(opaque, bus_num, addr, class_id, vendor_id, 
310                           product_id, product_name, speed);
311                if (ret)
312                    goto the_end;
313            }
314            if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
315                goto fail;
316            bus_num = atoi(buf);
317            if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
318                goto fail;
319            addr = atoi(buf);
320            if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
321                goto fail;
322            if (!strcmp(buf, "480"))
323                speed = USB_SPEED_HIGH;
324            else if (!strcmp(buf, "1.5"))
325                speed = USB_SPEED_LOW;
326            else
327                speed = USB_SPEED_FULL;
328            product_name[0] = '\0';
329            class_id = 0xff;
330            device_count++;
331            product_id = 0;
332            vendor_id = 0;
333        } else if (line[0] == 'P' && line[1] == ':') {
334            if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
335                goto fail;
336            vendor_id = strtoul(buf, NULL, 16);
337            if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
338                goto fail;
339            product_id = strtoul(buf, NULL, 16);
340        } else if (line[0] == 'S' && line[1] == ':') {
341            if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
342                goto fail;
343            pstrcpy(product_name, sizeof(product_name), buf);
344        } else if (line[0] == 'D' && line[1] == ':') {
345            if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
346                goto fail;
347            class_id = strtoul(buf, NULL, 16);
348        }
349    fail: ;
350    }
351    if (device_count && (vendor_id || product_id)) {
352        /* Add the last device.  */
353        ret = func(opaque, bus_num, addr, class_id, vendor_id, 
354                   product_id, product_name, speed);
355    }
356 the_end:
357    fclose(f);
358    return ret;
359}
360
361typedef struct FindDeviceState {
362    int vendor_id;
363    int product_id;
364    int bus_num;
365    int addr;
366    char product_name[PRODUCT_NAME_SZ];
367} FindDeviceState;
368
369static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, 
370                                     int class_id,
371                                     int vendor_id, int product_id, 
372                                     const char *product_name, int speed)
373{
374    FindDeviceState *s = opaque;
375    if ((vendor_id == s->vendor_id &&
376        product_id == s->product_id) ||
377        (bus_num == s->bus_num &&
378        addr == s->addr)) {
379        pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name);
380        s->bus_num = bus_num;
381        s->addr = addr;
382        return 1;
383    } else {
384        return 0;
385    }
386}
387
388/* the syntax is :
389   'bus.addr' (decimal numbers) or
390   'vendor_id:product_id' (hexa numbers) */
391static int usb_host_find_device(int *pbus_num, int *paddr, 
392                                char *product_name, int product_name_size,
393                                const char *devname)
394{
395    const char *p;
396    int ret;
397    FindDeviceState fs;
398
399    p = strchr(devname, '.');
400    if (p) {
401        *pbus_num = strtoul(devname, NULL, 0);
402        *paddr = strtoul(p + 1, NULL, 0);
403        fs.bus_num = *pbus_num;
404        fs.addr = *paddr;
405        ret = usb_host_scan(&fs, usb_host_find_device_scan);
406        if (ret)
407            pstrcpy(product_name, product_name_size, fs.product_name);
408        return 0;
409    }
410    p = strchr(devname, ':');
411    if (p) {
412        fs.vendor_id = strtoul(devname, NULL, 16);
413        fs.product_id = strtoul(p + 1, NULL, 16);
414        ret = usb_host_scan(&fs, usb_host_find_device_scan);
415        if (ret) {
416            *pbus_num = fs.bus_num;
417            *paddr = fs.addr;
418            pstrcpy(product_name, product_name_size, fs.product_name);
419            return 0;
420        }
421    }
422    return -1;
423}
424
425/**********************/
426/* USB host device info */
427
428struct usb_class_info {
429    int class;
430    const char *class_name;
431};
432
433static const struct usb_class_info usb_class_info[] = {
434    { USB_CLASS_AUDIO, "Audio"},
435    { USB_CLASS_COMM, "Communication"},
436    { USB_CLASS_HID, "HID"},
437    { USB_CLASS_HUB, "Hub" },
438    { USB_CLASS_PHYSICAL, "Physical" },
439    { USB_CLASS_PRINTER, "Printer" },
440    { USB_CLASS_MASS_STORAGE, "Storage" },
441    { USB_CLASS_CDC_DATA, "Data" },
442    { USB_CLASS_APP_SPEC, "Application Specific" },
443    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
444    { USB_CLASS_STILL_IMAGE, "Still Image" },
445    { USB_CLASS_CSCID,  "Smart Card" },
446    { USB_CLASS_CONTENT_SEC, "Content Security" },
447    { -1, NULL }
448};
449
450static const char *usb_class_str(uint8_t class)
451{
452    const struct usb_class_info *p;
453    for(p = usb_class_info; p->class != -1; p++) {
454        if (p->class == class)
455            break;
456    }
457    return p->class_name;
458}
459
460void usb_info_device(int bus_num, int addr, int class_id,
461                     int vendor_id, int product_id, 
462                     const char *product_name,
463                     int speed)
464{
465    const char *class_str, *speed_str;
466
467    switch(speed) {
468    case USB_SPEED_LOW:
469        speed_str = "1.5"; 
470        break;
471    case USB_SPEED_FULL:
472        speed_str = "12"; 
473        break;
474    case USB_SPEED_HIGH:
475        speed_str = "480"; 
476        break;
477    default:
478        speed_str = "?"; 
479        break;
480    }
481
482    term_printf("  Device %d.%d, speed %s Mb/s\n", 
483                bus_num, addr, speed_str);
484    class_str = usb_class_str(class_id);
485    if (class_str) 
486        term_printf("    %s:", class_str);
487    else
488        term_printf("    Class %02x:", class_id);
489    term_printf(" USB device %04x:%04x", vendor_id, product_id);
490    if (product_name[0] != '\0')
491        term_printf(", %s", product_name);
492    term_printf("\n");
493}
494
495static int usb_host_info_device(void *opaque, int bus_num, int addr, 
496                                int class_id,
497                                int vendor_id, int product_id, 
498                                const char *product_name,
499                                int speed)
500{
501    usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
502                    product_name, speed);
503    return 0;
504}
505
506void usb_host_info(void)
507{
508    usb_host_scan(NULL, usb_host_info_device);
509}
510
511#else
512
513void usb_host_info(void)
514{
515    term_printf("USB host devices not supported\n");
516}
517
518/* XXX: modify configure to compile the right host driver */
519USBDevice *usb_host_device_open(const char *devname)
520{
521    return NULL;
522}
523
524#endif
Note: See TracBrowser for help on using the repository browser.