Statistics
| Branch: | Revision:

root / usb-linux.c @ 4d611c9a

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

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

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

    
51
//#define DEBUG
52

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
256
    return (USBDevice *)dev;
257
}
258

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
508
#else
509

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

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

    
521
#endif