Statistics
| Branch: | Revision:

root / usb-linux.c @ c5d6edc3

History | View | Annotate | Download (13.7 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
                                const char *devname);
48

    
49
//#define DEBUG
50

    
51
#define USBDEVFS_PATH "/proc/bus/usb"
52

    
53
typedef struct USBHostDevice {
54
    USBDevice dev;
55
    int fd;
56
} USBHostDevice;
57

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

    
68
static int usb_host_handle_control(USBDevice *dev,
69
                                   int request,
70
                                   int value,
71
                                   int index,
72
                                   int length,
73
                                   uint8_t *data)
74
{
75
    USBHostDevice *s = (USBHostDevice *)dev;
76
    struct usb_ctrltransfer ct;
77
    int ret;
78

    
79
    if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
80
        /* specific SET_ADDRESS support */
81
        dev->addr = value;
82
        return 0;
83
    } else {
84
        ct.bRequestType = request >> 8;
85
        ct.bRequest = request;
86
        ct.wValue = value;
87
        ct.wIndex = index;
88
        ct.wLength = length;
89
        ct.timeout = 50;
90
        ct.data = data;
91
        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
92
        if (ret < 0) {
93
            switch(errno) {
94
            case ETIMEDOUT:
95
                return USB_RET_NAK;
96
            default:
97
                return USB_RET_STALL;
98
            }
99
        } else {
100
            return ret;
101
        }
102
   }
103
}
104

    
105
static int usb_host_handle_data(USBDevice *dev, int pid, 
106
                                uint8_t devep,
107
                                uint8_t *data, int len)
108
{
109
    USBHostDevice *s = (USBHostDevice *)dev;
110
    struct usbdevfs_bulktransfer bt;
111
    int ret;
112

    
113
    /* XXX: optimize and handle all data types by looking at the
114
       config descriptor */
115
    if (pid == USB_TOKEN_IN)
116
        devep |= 0x80;
117
    bt.ep = devep;
118
    bt.len = len;
119
    bt.timeout = 50;
120
    bt.data = data;
121
    ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
122
    if (ret < 0) {
123
        switch(errno) {
124
        case ETIMEDOUT:
125
            return USB_RET_NAK;
126
        case EPIPE:
127
        default:
128
#ifdef DEBUG
129
            printf("handle_data: errno=%d\n", errno);
130
#endif
131
            return USB_RET_STALL;
132
        }
133
    } else {
134
        return ret;
135
    }
136
}
137

    
138
/* XXX: exclude high speed devices or implement EHCI */
139
USBDevice *usb_host_device_open(const char *devname)
140
{
141
    int fd, interface, ret, i;
142
    USBHostDevice *dev;
143
    struct usbdevfs_connectinfo ci;
144
    uint8_t descr[1024];
145
    char buf[1024];
146
    int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
147
    int bus_num, addr;
148

    
149
    if (usb_host_find_device(&bus_num, &addr, devname) < 0) 
150
        return NULL;
151
    
152
    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", 
153
             bus_num, addr);
154
    fd = open(buf, O_RDWR);
155
    if (fd < 0) {
156
        perror(buf);
157
        return NULL;
158
    }
159

    
160
    /* read the config description */
161
    descr_len = read(fd, descr, sizeof(descr));
162
    if (descr_len <= 0) {
163
        perror("read descr");
164
        goto fail;
165
    }
166
    
167
    i = 0;
168
    dev_descr_len = descr[0];
169
    if (dev_descr_len > descr_len)
170
        goto fail;
171
    i += dev_descr_len;
172
    config_descr_len = descr[i];
173
    if (i + config_descr_len > descr_len)
174
        goto fail;
175
    nb_interfaces = descr[i + 4];
176
    if (nb_interfaces != 1) {
177
        /* NOTE: currently we grab only one interface */
178
        fprintf(stderr, "usb_host: only one interface supported\n");
179
        goto fail;
180
    }
181

    
182
#ifdef USBDEVFS_DISCONNECT
183
    /* earlier Linux 2.4 do not support that */
184
    {
185
        struct usbdevfs_ioctl ctrl;
186
        ctrl.ioctl_code = USBDEVFS_DISCONNECT;
187
        ctrl.ifno = 0;
188
        ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl);
189
        if (ret < 0 && errno != ENODATA) {
190
            perror("USBDEVFS_DISCONNECT");
191
            goto fail;
192
        }
193
    }
194
#endif
195

    
196
    /* XXX: only grab if all interfaces are free */
197
    interface = 0;
198
    ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
199
    if (ret < 0) {
200
        if (errno == EBUSY) {
201
            fprintf(stderr, "usb_host: device already grabbed\n");
202
        } else {
203
            perror("USBDEVFS_CLAIMINTERFACE");
204
        }
205
    fail:
206
        close(fd);
207
        return NULL;
208
    }
209

    
210
    ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
211
    if (ret < 0) {
212
        perror("USBDEVFS_CONNECTINFO");
213
        goto fail;
214
    }
215

    
216
#ifdef DEBUG
217
    printf("host USB device %d.%d grabbed\n", bus_num, addr);
218
#endif    
219

    
220
    dev = qemu_mallocz(sizeof(USBHostDevice));
221
    if (!dev)
222
        goto fail;
223
    dev->fd = fd;
224
    if (ci.slow)
225
        dev->dev.speed = USB_SPEED_LOW;
226
    else
227
        dev->dev.speed = USB_SPEED_HIGH;
228
    dev->dev.handle_packet = usb_generic_handle_packet;
229

    
230
    dev->dev.handle_reset = usb_host_handle_reset;
231
    dev->dev.handle_control = usb_host_handle_control;
232
    dev->dev.handle_data = usb_host_handle_data;
233
    return (USBDevice *)dev;
234
}
235

    
236
static int get_tag_value(char *buf, int buf_size,
237
                         const char *str, const char *tag, 
238
                         const char *stopchars)
239
{
240
    const char *p;
241
    char *q;
242
    p = strstr(str, tag);
243
    if (!p)
244
        return -1;
245
    p += strlen(tag);
246
    while (isspace(*p))
247
        p++;
248
    q = buf;
249
    while (*p != '\0' && !strchr(stopchars, *p)) {
250
        if ((q - buf) < (buf_size - 1))
251
            *q++ = *p;
252
        p++;
253
    }
254
    *q = '\0';
255
    return q - buf;
256
}
257

    
258
static int usb_host_scan(void *opaque, USBScanFunc *func)
259
{
260
    FILE *f;
261
    char line[1024];
262
    char buf[1024];
263
    int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
264
    int ret;
265
    char product_name[512];
266
    
267
    f = fopen(USBDEVFS_PATH "/devices", "r");
268
    if (!f) {
269
        term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
270
        return 0;
271
    }
272
    device_count = 0;
273
    bus_num = addr = speed = class_id = product_id = vendor_id = 0;
274
    ret = 0;
275
    for(;;) {
276
        if (fgets(line, sizeof(line), f) == NULL)
277
            break;
278
        if (strlen(line) > 0)
279
            line[strlen(line) - 1] = '\0';
280
        if (line[0] == 'T' && line[1] == ':') {
281
            if (device_count && (vendor_id || product_id)) {
282
                /* New device.  Add the previously discovered device.  */
283
                ret = func(opaque, bus_num, addr, class_id, vendor_id, 
284
                           product_id, product_name, speed);
285
                if (ret)
286
                    goto the_end;
287
            }
288
            if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
289
                goto fail;
290
            bus_num = atoi(buf);
291
            if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
292
                goto fail;
293
            addr = atoi(buf);
294
            if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
295
                goto fail;
296
            if (!strcmp(buf, "480"))
297
                speed = USB_SPEED_HIGH;
298
            else if (!strcmp(buf, "1.5"))
299
                speed = USB_SPEED_LOW;
300
            else
301
                speed = USB_SPEED_FULL;
302
            product_name[0] = '\0';
303
            class_id = 0xff;
304
            device_count++;
305
            product_id = 0;
306
            vendor_id = 0;
307
        } else if (line[0] == 'P' && line[1] == ':') {
308
            if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
309
                goto fail;
310
            vendor_id = strtoul(buf, NULL, 16);
311
            if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
312
                goto fail;
313
            product_id = strtoul(buf, NULL, 16);
314
        } else if (line[0] == 'S' && line[1] == ':') {
315
            if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
316
                goto fail;
317
            pstrcpy(product_name, sizeof(product_name), buf);
318
        } else if (line[0] == 'D' && line[1] == ':') {
319
            if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
320
                goto fail;
321
            class_id = strtoul(buf, NULL, 16);
322
        }
323
    fail: ;
324
    }
325
    if (device_count && (vendor_id || product_id)) {
326
        /* Add the last device.  */
327
        ret = func(opaque, bus_num, addr, class_id, vendor_id, 
328
                   product_id, product_name, speed);
329
    }
330
 the_end:
331
    fclose(f);
332
    return ret;
333
}
334

    
335
typedef struct FindDeviceState {
336
    int vendor_id;
337
    int product_id;
338
    int bus_num;
339
    int addr;
340
} FindDeviceState;
341

    
342
static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, 
343
                                     int class_id,
344
                                     int vendor_id, int product_id, 
345
                                     const char *product_name, int speed)
346
{
347
    FindDeviceState *s = opaque;
348
    if (vendor_id == s->vendor_id &&
349
        product_id == s->product_id) {
350
        s->bus_num = bus_num;
351
        s->addr = addr;
352
        return 1;
353
    } else {
354
        return 0;
355
    }
356
}
357

    
358
/* the syntax is : 
359
   'bus.addr' (decimal numbers) or 
360
   'vendor_id:product_id' (hexa numbers) */
361
static int usb_host_find_device(int *pbus_num, int *paddr, 
362
                                const char *devname)
363
{
364
    const char *p;
365
    int ret;
366
    FindDeviceState fs;
367

    
368
    p = strchr(devname, '.');
369
    if (p) {
370
        *pbus_num = strtoul(devname, NULL, 0);
371
        *paddr = strtoul(p + 1, NULL, 0);
372
        return 0;
373
    }
374
    p = strchr(devname, ':');
375
    if (p) {
376
        fs.vendor_id = strtoul(devname, NULL, 16);
377
        fs.product_id = strtoul(p + 1, NULL, 16);
378
        ret = usb_host_scan(&fs, usb_host_find_device_scan);
379
        if (ret) {
380
            *pbus_num = fs.bus_num;
381
            *paddr = fs.addr;
382
            return 0;
383
        }
384
    }
385
    return -1;
386
}
387

    
388
/**********************/
389
/* USB host device info */
390

    
391
struct usb_class_info {
392
    int class;
393
    const char *class_name;
394
};
395

    
396
static const struct usb_class_info usb_class_info[] = {
397
    { USB_CLASS_AUDIO, "Audio"},
398
    { USB_CLASS_COMM, "Communication"},
399
    { USB_CLASS_HID, "HID"},
400
    { USB_CLASS_HUB, "Hub" },
401
    { USB_CLASS_PHYSICAL, "Physical" },
402
    { USB_CLASS_PRINTER, "Printer" },
403
    { USB_CLASS_MASS_STORAGE, "Storage" },
404
    { USB_CLASS_CDC_DATA, "Data" },
405
    { USB_CLASS_APP_SPEC, "Application Specific" },
406
    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
407
    { USB_CLASS_STILL_IMAGE, "Still Image" },
408
    { USB_CLASS_CSCID,         "Smart Card" },
409
    { USB_CLASS_CONTENT_SEC, "Content Security" },
410
    { -1, NULL }
411
};
412

    
413
static const char *usb_class_str(uint8_t class)
414
{
415
    const struct usb_class_info *p;
416
    for(p = usb_class_info; p->class != -1; p++) {
417
        if (p->class == class)
418
            break;
419
    }
420
    return p->class_name;
421
}
422

    
423
void usb_info_device(int bus_num, int addr, int class_id,
424
                     int vendor_id, int product_id, 
425
                     const char *product_name,
426
                     int speed)
427
{
428
    const char *class_str, *speed_str;
429

    
430
    switch(speed) {
431
    case USB_SPEED_LOW: 
432
        speed_str = "1.5"; 
433
        break;
434
    case USB_SPEED_FULL: 
435
        speed_str = "12"; 
436
        break;
437
    case USB_SPEED_HIGH: 
438
        speed_str = "480"; 
439
        break;
440
    default:
441
        speed_str = "?"; 
442
        break;
443
    }
444

    
445
    term_printf("  Device %d.%d, speed %s Mb/s\n", 
446
                bus_num, addr, speed_str);
447
    class_str = usb_class_str(class_id);
448
    if (class_str) 
449
        term_printf("    %s:", class_str);
450
    else
451
        term_printf("    Class %02x:", class_id);
452
    term_printf(" USB device %04x:%04x", vendor_id, product_id);
453
    if (product_name[0] != '\0')
454
        term_printf(", %s", product_name);
455
    term_printf("\n");
456
}
457

    
458
static int usb_host_info_device(void *opaque, int bus_num, int addr, 
459
                                int class_id,
460
                                int vendor_id, int product_id, 
461
                                const char *product_name,
462
                                int speed)
463
{
464
    usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
465
                    product_name, speed);
466
    return 0;
467
}
468

    
469
void usb_host_info(void)
470
{
471
    usb_host_scan(NULL, usb_host_info_device);
472
}
473

    
474
#else
475

    
476
void usb_host_info(void)
477
{
478
    term_printf("USB host devices not supported\n");
479
}
480

    
481
/* XXX: modify configure to compile the right host driver */
482
USBDevice *usb_host_device_open(const char *devname)
483
{
484
    return NULL;
485
}
486

    
487
#endif