Statistics
| Branch: | Revision:

root / usb-linux.c @ 5fafdf24

History | View | Annotate | Download (14.8 kB)

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
#include <linux/usbdevice_fs.h>
30
#include <linux/version.h>
31

    
32
/* We redefine it to avoid version problems */
33
struct usb_ctrltransfer {
34
    uint8_t  bRequestType;
35
    uint8_t  bRequest;
36
    uint16_t wValue;
37
    uint16_t wIndex;
38
    uint16_t wLength;
39
    uint32_t timeout;
40
    void *data;
41
};
42

    
43
typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
44
                        int vendor_id, int product_id,
45
                        const char *product_name, int speed);
46
static int usb_host_find_device(int *pbus_num, int *paddr,
47
                                char *product_name, int product_name_size,
48
                                const char *devname);
49

    
50
//#define DEBUG
51

    
52
#define USBDEVFS_PATH "/proc/bus/usb"
53
#define PRODUCT_NAME_SZ 32
54

    
55
typedef struct USBHostDevice {
56
    USBDevice dev;
57
    int fd;
58
} USBHostDevice;
59

    
60
static void usb_host_handle_reset(USBDevice *dev)
61
{
62
#if 0
63
    USBHostDevice *s = (USBHostDevice *)dev;
64
    /* USBDEVFS_RESET, but not the first time as it has already be
65
       done by the host OS */
66
    ioctl(s->fd, USBDEVFS_RESET);
67
#endif
68
}
69

    
70
static void usb_host_handle_destroy(USBDevice *dev)
71
{
72
    USBHostDevice *s = (USBHostDevice *)dev;
73

    
74
    if (s->fd >= 0)
75
        close(s->fd);
76
    qemu_free(s);
77
}
78

    
79
static int usb_host_handle_control(USBDevice *dev,
80
                                   int request,
81
                                   int value,
82
                                   int index,
83
                                   int length,
84
                                   uint8_t *data)
85
{
86
    USBHostDevice *s = (USBHostDevice *)dev;
87
    struct usb_ctrltransfer ct;
88
    int ret;
89

    
90
    if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
91
        /* specific SET_ADDRESS support */
92
        dev->addr = value;
93
        return 0;
94
    } else {
95
        ct.bRequestType = request >> 8;
96
        ct.bRequest = request;
97
        ct.wValue = value;
98
        ct.wIndex = index;
99
        ct.wLength = length;
100
        ct.timeout = 50;
101
        ct.data = data;
102
        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
103
        if (ret < 0) {
104
            switch(errno) {
105
            case ETIMEDOUT:
106
                return USB_RET_NAK;
107
            default:
108
                return USB_RET_STALL;
109
            }
110
        } else {
111
            return ret;
112
        }
113
   }
114
}
115

    
116
static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
117
{
118
    USBHostDevice *s = (USBHostDevice *)dev;
119
    struct usbdevfs_bulktransfer bt;
120
    int ret;
121
    uint8_t devep = p->devep;
122

    
123
    /* XXX: optimize and handle all data types by looking at the
124
       config descriptor */
125
    if (p->pid == USB_TOKEN_IN)
126
        devep |= 0x80;
127
    bt.ep = devep;
128
    bt.len = p->len;
129
    bt.timeout = 50;
130
    bt.data = p->data;
131
    ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
132
    if (ret < 0) {
133
        switch(errno) {
134
        case ETIMEDOUT:
135
            return USB_RET_NAK;
136
        case EPIPE:
137
        default:
138
#ifdef DEBUG
139
            printf("handle_data: errno=%d\n", errno);
140
#endif
141
            return USB_RET_STALL;
142
        }
143
    } else {
144
        return ret;
145
    }
146
}
147

    
148
/* XXX: exclude high speed devices or implement EHCI */
149
USBDevice *usb_host_device_open(const char *devname)
150
{
151
    int fd, interface, ret, i;
152
    USBHostDevice *dev;
153
    struct usbdevfs_connectinfo ci;
154
    uint8_t descr[1024];
155
    char buf[1024];
156
    int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
157
    int bus_num, addr;
158
    char product_name[PRODUCT_NAME_SZ];
159

    
160
    if (usb_host_find_device(&bus_num, &addr,
161
                             product_name, sizeof(product_name),
162
                             devname) < 0)
163
        return NULL;
164
   
165
    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
166
             bus_num, addr);
167
    fd = open(buf, O_RDWR);
168
    if (fd < 0) {
169
        perror(buf);
170
        return NULL;
171
    }
172

    
173
    /* read the config description */
174
    descr_len = read(fd, descr, sizeof(descr));
175
    if (descr_len <= 0) {
176
        perror("read descr");
177
        goto fail;
178
    }
179
   
180
    i = 0;
181
    dev_descr_len = descr[0];
182
    if (dev_descr_len > descr_len)
183
        goto fail;
184
    i += dev_descr_len;
185
    config_descr_len = descr[i];
186
    if (i + config_descr_len > descr_len)
187
        goto fail;
188
    nb_interfaces = descr[i + 4];
189
    if (nb_interfaces != 1) {
190
        /* NOTE: currently we grab only one interface */
191
        fprintf(stderr, "usb_host: only one interface supported\n");
192
        goto fail;
193
    }
194

    
195
#ifdef USBDEVFS_DISCONNECT
196
    /* earlier Linux 2.4 do not support that */
197
    {
198
        struct usbdevfs_ioctl ctrl;
199
        ctrl.ioctl_code = USBDEVFS_DISCONNECT;
200
        ctrl.ifno = 0;
201
        ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl);
202
        if (ret < 0 && errno != ENODATA) {
203
            perror("USBDEVFS_DISCONNECT");
204
            goto fail;
205
        }
206
    }
207
#endif
208

    
209
    /* XXX: only grab if all interfaces are free */
210
    interface = 0;
211
    ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
212
    if (ret < 0) {
213
        if (errno == EBUSY) {
214
            fprintf(stderr, "usb_host: device already grabbed\n");
215
        } else {
216
            perror("USBDEVFS_CLAIMINTERFACE");
217
        }
218
    fail:
219
        close(fd);
220
        return NULL;
221
    }
222

    
223
    ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
224
    if (ret < 0) {
225
        perror("USBDEVFS_CONNECTINFO");
226
        goto fail;
227
    }
228

    
229
#ifdef DEBUG
230
    printf("host USB device %d.%d grabbed\n", bus_num, addr);
231
#endif   
232

    
233
    dev = qemu_mallocz(sizeof(USBHostDevice));
234
    if (!dev)
235
        goto fail;
236
    dev->fd = fd;
237
    if (ci.slow)
238
        dev->dev.speed = USB_SPEED_LOW;
239
    else
240
        dev->dev.speed = USB_SPEED_HIGH;
241
    dev->dev.handle_packet = usb_generic_handle_packet;
242

    
243
    dev->dev.handle_reset = usb_host_handle_reset;
244
    dev->dev.handle_control = usb_host_handle_control;
245
    dev->dev.handle_data = usb_host_handle_data;
246
    dev->dev.handle_destroy = usb_host_handle_destroy;
247

    
248
    if (product_name[0] == '\0')
249
        snprintf(dev->dev.devname, sizeof(dev->dev.devname),
250
                 "host:%s", devname);
251
    else
252
        pstrcpy(dev->dev.devname, sizeof(dev->dev.devname),
253
                product_name);
254

    
255
    return (USBDevice *)dev;
256
}
257

    
258
static int get_tag_value(char *buf, int buf_size,
259
                         const char *str, const char *tag,
260
                         const char *stopchars)
261
{
262
    const char *p;
263
    char *q;
264
    p = strstr(str, tag);
265
    if (!p)
266
        return -1;
267
    p += strlen(tag);
268
    while (isspace(*p))
269
        p++;
270
    q = buf;
271
    while (*p != '\0' && !strchr(stopchars, *p)) {
272
        if ((q - buf) < (buf_size - 1))
273
            *q++ = *p;
274
        p++;
275
    }
276
    *q = '\0';
277
    return q - buf;
278
}
279

    
280
static int usb_host_scan(void *opaque, USBScanFunc *func)
281
{
282
    FILE *f;
283
    char line[1024];
284
    char buf[1024];
285
    int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
286
    int ret;
287
    char product_name[512];
288
   
289
    f = fopen(USBDEVFS_PATH "/devices", "r");
290
    if (!f) {
291
        term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
292
        return 0;
293
    }
294
    device_count = 0;
295
    bus_num = addr = speed = class_id = product_id = vendor_id = 0;
296
    ret = 0;
297
    for(;;) {
298
        if (fgets(line, sizeof(line), f) == NULL)
299
            break;
300
        if (strlen(line) > 0)
301
            line[strlen(line) - 1] = '\0';
302
        if (line[0] == 'T' && line[1] == ':') {
303
            if (device_count && (vendor_id || product_id)) {
304
                /* New device.  Add the previously discovered device.  */
305
                ret = func(opaque, bus_num, addr, class_id, vendor_id,
306
                           product_id, product_name, speed);
307
                if (ret)
308
                    goto the_end;
309
            }
310
            if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
311
                goto fail;
312
            bus_num = atoi(buf);
313
            if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
314
                goto fail;
315
            addr = atoi(buf);
316
            if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
317
                goto fail;
318
            if (!strcmp(buf, "480"))
319
                speed = USB_SPEED_HIGH;
320
            else if (!strcmp(buf, "1.5"))
321
                speed = USB_SPEED_LOW;
322
            else
323
                speed = USB_SPEED_FULL;
324
            product_name[0] = '\0';
325
            class_id = 0xff;
326
            device_count++;
327
            product_id = 0;
328
            vendor_id = 0;
329
        } else if (line[0] == 'P' && line[1] == ':') {
330
            if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
331
                goto fail;
332
            vendor_id = strtoul(buf, NULL, 16);
333
            if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
334
                goto fail;
335
            product_id = strtoul(buf, NULL, 16);
336
        } else if (line[0] == 'S' && line[1] == ':') {
337
            if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
338
                goto fail;
339
            pstrcpy(product_name, sizeof(product_name), buf);
340
        } else if (line[0] == 'D' && line[1] == ':') {
341
            if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
342
                goto fail;
343
            class_id = strtoul(buf, NULL, 16);
344
        }
345
    fail: ;
346
    }
347
    if (device_count && (vendor_id || product_id)) {
348
        /* Add the last device.  */
349
        ret = func(opaque, bus_num, addr, class_id, vendor_id,
350
                   product_id, product_name, speed);
351
    }
352
 the_end:
353
    fclose(f);
354
    return ret;
355
}
356

    
357
typedef struct FindDeviceState {
358
    int vendor_id;
359
    int product_id;
360
    int bus_num;
361
    int addr;
362
    char product_name[PRODUCT_NAME_SZ];
363
} FindDeviceState;
364

    
365
static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
366
                                     int class_id,
367
                                     int vendor_id, int product_id,
368
                                     const char *product_name, int speed)
369
{
370
    FindDeviceState *s = opaque;
371
    if ((vendor_id == s->vendor_id &&
372
        product_id == s->product_id) ||
373
        (bus_num == s->bus_num &&
374
        addr == s->addr)) {
375
        pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name);
376
        s->bus_num = bus_num;
377
        s->addr = addr;
378
        return 1;
379
    } else {
380
        return 0;
381
    }
382
}
383

    
384
/* the syntax is :
385
   'bus.addr' (decimal numbers) or
386
   'vendor_id:product_id' (hexa numbers) */
387
static int usb_host_find_device(int *pbus_num, int *paddr,
388
                                char *product_name, int product_name_size,
389
                                const char *devname)
390
{
391
    const char *p;
392
    int ret;
393
    FindDeviceState fs;
394

    
395
    p = strchr(devname, '.');
396
    if (p) {
397
        *pbus_num = strtoul(devname, NULL, 0);
398
        *paddr = strtoul(p + 1, NULL, 0);
399
        fs.bus_num = *pbus_num;
400
        fs.addr = *paddr;
401
        ret = usb_host_scan(&fs, usb_host_find_device_scan);
402
        if (ret)
403
            pstrcpy(product_name, product_name_size, fs.product_name);
404
        return 0;
405
    }
406
    p = strchr(devname, ':');
407
    if (p) {
408
        fs.vendor_id = strtoul(devname, NULL, 16);
409
        fs.product_id = strtoul(p + 1, NULL, 16);
410
        ret = usb_host_scan(&fs, usb_host_find_device_scan);
411
        if (ret) {
412
            *pbus_num = fs.bus_num;
413
            *paddr = fs.addr;
414
            pstrcpy(product_name, product_name_size, fs.product_name);
415
            return 0;
416
        }
417
    }
418
    return -1;
419
}
420

    
421
/**********************/
422
/* USB host device info */
423

    
424
struct usb_class_info {
425
    int class;
426
    const char *class_name;
427
};
428

    
429
static const struct usb_class_info usb_class_info[] = {
430
    { USB_CLASS_AUDIO, "Audio"},
431
    { USB_CLASS_COMM, "Communication"},
432
    { USB_CLASS_HID, "HID"},
433
    { USB_CLASS_HUB, "Hub" },
434
    { USB_CLASS_PHYSICAL, "Physical" },
435
    { USB_CLASS_PRINTER, "Printer" },
436
    { USB_CLASS_MASS_STORAGE, "Storage" },
437
    { USB_CLASS_CDC_DATA, "Data" },
438
    { USB_CLASS_APP_SPEC, "Application Specific" },
439
    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
440
    { USB_CLASS_STILL_IMAGE, "Still Image" },
441
    { USB_CLASS_CSCID,         "Smart Card" },
442
    { USB_CLASS_CONTENT_SEC, "Content Security" },
443
    { -1, NULL }
444
};
445

    
446
static const char *usb_class_str(uint8_t class)
447
{
448
    const struct usb_class_info *p;
449
    for(p = usb_class_info; p->class != -1; p++) {
450
        if (p->class == class)
451
            break;
452
    }
453
    return p->class_name;
454
}
455

    
456
void usb_info_device(int bus_num, int addr, int class_id,
457
                     int vendor_id, int product_id,
458
                     const char *product_name,
459
                     int speed)
460
{
461
    const char *class_str, *speed_str;
462

    
463
    switch(speed) {
464
    case USB_SPEED_LOW:
465
        speed_str = "1.5";
466
        break;
467
    case USB_SPEED_FULL:
468
        speed_str = "12";
469
        break;
470
    case USB_SPEED_HIGH:
471
        speed_str = "480";
472
        break;
473
    default:
474
        speed_str = "?";
475
        break;
476
    }
477

    
478
    term_printf("  Device %d.%d, speed %s Mb/s\n",
479
                bus_num, addr, speed_str);
480
    class_str = usb_class_str(class_id);
481
    if (class_str)
482
        term_printf("    %s:", class_str);
483
    else
484
        term_printf("    Class %02x:", class_id);
485
    term_printf(" USB device %04x:%04x", vendor_id, product_id);
486
    if (product_name[0] != '\0')
487
        term_printf(", %s", product_name);
488
    term_printf("\n");
489
}
490

    
491
static int usb_host_info_device(void *opaque, int bus_num, int addr,
492
                                int class_id,
493
                                int vendor_id, int product_id,
494
                                const char *product_name,
495
                                int speed)
496
{
497
    usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
498
                    product_name, speed);
499
    return 0;
500
}
501

    
502
void usb_host_info(void)
503
{
504
    usb_host_scan(NULL, usb_host_info_device);
505
}
506

    
507
#else
508

    
509
void usb_host_info(void)
510
{
511
    term_printf("USB host devices not supported\n");
512
}
513

    
514
/* XXX: modify configure to compile the right host driver */
515
USBDevice *usb_host_device_open(const char *devname)
516
{
517
    return NULL;
518
}
519

    
520
#endif