blob: a68603df769a561fb1d9d709bddb72ad4980f709 [file] [log] [blame]
bellardbb36d472005-11-05 14:22:28 +00001/*
2 * Linux host USB redirector
3 *
4 * Copyright (c) 2005 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
aliguori64838172008-08-21 19:31:10 +00006 * Copyright (c) 2008 Max Krasnyansky
7 * Support for host device auto connect & disconnect
aliguori5d0c5752008-09-14 01:07:41 +00008 * Major rewrite to support fully async operation
aliguori4b096fc2008-08-21 19:28:55 +00009 *
aliguori0f431522008-10-07 20:06:37 +000010 * Copyright 2008 TJ <linux@tjworld.net>
11 * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
12 * to the legacy /proc/bus/usb USB device discovery and handling
13 *
bellardbb36d472005-11-05 14:22:28 +000014 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to deal
16 * in the Software without restriction, including without limitation the rights
17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 * copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 * THE SOFTWARE.
31 */
aliguori446ab122008-09-14 01:06:09 +000032
pbrook87ecb682007-11-17 17:14:51 +000033#include "qemu-common.h"
aliguori1f3870a2008-08-21 19:27:48 +000034#include "qemu-timer.h"
aliguori376253e2009-03-05 23:01:23 +000035#include "monitor.h"
Shahar Havivib373a632010-06-16 15:16:11 +030036#include "sysemu.h"
bellardbb36d472005-11-05 14:22:28 +000037
bellardbb36d472005-11-05 14:22:28 +000038#include <dirent.h>
39#include <sys/ioctl.h>
balrogb9dc0332007-10-04 22:47:34 +000040#include <signal.h>
bellardbb36d472005-11-05 14:22:28 +000041
aliguori446ab122008-09-14 01:06:09 +000042#include <linux/usbdevice_fs.h>
43#include <linux/version.h>
44#include "hw/usb.h"
bellardbb36d472005-11-05 14:22:28 +000045
blueswir1d9cf1572008-09-15 14:57:11 +000046/* We redefine it to avoid version problems */
47struct usb_ctrltransfer {
48 uint8_t bRequestType;
49 uint8_t bRequest;
50 uint16_t wValue;
51 uint16_t wIndex;
52 uint16_t wLength;
53 uint32_t timeout;
54 void *data;
55};
56
57struct usb_ctrlrequest {
58 uint8_t bRequestType;
59 uint8_t bRequest;
60 uint16_t wValue;
61 uint16_t wIndex;
62 uint16_t wLength;
63};
64
Hans de Goede0f5160d2010-11-10 10:06:23 +010065typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
66 int class_id, int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +000067 const char *product_name, int speed);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010068
Markus Armbruster0745eb12009-11-27 13:05:53 +010069//#define DEBUG
aliguori64838172008-08-21 19:31:10 +000070
71#ifdef DEBUG
malcd0f2c4c2010-02-07 02:03:50 +030072#define DPRINTF printf
aliguori64838172008-08-21 19:31:10 +000073#else
malcd0f2c4c2010-02-07 02:03:50 +030074#define DPRINTF(...)
aliguori64838172008-08-21 19:31:10 +000075#endif
bellardbb36d472005-11-05 14:22:28 +000076
blueswir15be8e1f2008-10-25 11:47:20 +000077#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
78
aliguori0f431522008-10-07 20:06:37 +000079#define USBPROCBUS_PATH "/proc/bus/usb"
bellard1f6e24e2006-06-26 21:00:51 +000080#define PRODUCT_NAME_SZ 32
balrogb9dc0332007-10-04 22:47:34 +000081#define MAX_ENDPOINTS 16
aliguori0f431522008-10-07 20:06:37 +000082#define USBDEVBUS_PATH "/dev/bus/usb"
83#define USBSYSBUS_PATH "/sys/bus/usb"
84
85static char *usb_host_device_path;
86
87#define USB_FS_NONE 0
88#define USB_FS_PROC 1
89#define USB_FS_DEV 2
90#define USB_FS_SYS 3
91
92static int usb_fs_type;
bellardbb36d472005-11-05 14:22:28 +000093
balrogb9dc0332007-10-04 22:47:34 +000094/* endpoint association data */
Hans de Goede060dc842010-11-26 11:41:08 +010095#define ISO_FRAME_DESC_PER_URB 32
96#define ISO_URB_COUNT 3
97
98typedef struct AsyncURB AsyncURB;
99
balrogb9dc0332007-10-04 22:47:34 +0000100struct endp_data {
101 uint8_t type;
aliguori64838172008-08-21 19:31:10 +0000102 uint8_t halted;
Hans de Goede060dc842010-11-26 11:41:08 +0100103 AsyncURB *iso_urb;
104 int iso_urb_idx;
105 int max_packet_size;
balrogb9dc0332007-10-04 22:47:34 +0000106};
107
aliguori446ab122008-09-14 01:06:09 +0000108enum {
109 CTRL_STATE_IDLE = 0,
110 CTRL_STATE_SETUP,
111 CTRL_STATE_DATA,
112 CTRL_STATE_ACK
113};
114
115/*
116 * Control transfer state.
David Ahern27911042010-04-24 10:26:22 -0600117 * Note that 'buffer' _must_ follow 'req' field because
Brad Hardsa0102082011-04-13 19:45:33 +1000118 * we need contiguous buffer when we submit control URB.
David Ahern27911042010-04-24 10:26:22 -0600119 */
aliguori446ab122008-09-14 01:06:09 +0000120struct ctrl_struct {
121 uint16_t len;
122 uint16_t offset;
123 uint8_t state;
124 struct usb_ctrlrequest req;
Christian Krausefd7a4462010-01-24 17:34:52 +0100125 uint8_t buffer[8192];
aliguori446ab122008-09-14 01:06:09 +0000126};
127
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100128struct USBAutoFilter {
129 uint32_t bus_num;
130 uint32_t addr;
131 uint32_t vendor_id;
132 uint32_t product_id;
133};
134
bellardbb36d472005-11-05 14:22:28 +0000135typedef struct USBHostDevice {
136 USBDevice dev;
aliguori64838172008-08-21 19:31:10 +0000137 int fd;
138
139 uint8_t descr[1024];
140 int descr_len;
141 int configuration;
aliguori446ab122008-09-14 01:06:09 +0000142 int ninterfaces;
aliguori24772c12008-08-21 19:31:52 +0000143 int closing;
Shahar Havivib373a632010-06-16 15:16:11 +0300144 Notifier exit;
aliguori64838172008-08-21 19:31:10 +0000145
aliguori446ab122008-09-14 01:06:09 +0000146 struct ctrl_struct ctrl;
balrogb9dc0332007-10-04 22:47:34 +0000147 struct endp_data endp_table[MAX_ENDPOINTS];
aliguori4b096fc2008-08-21 19:28:55 +0000148
aliguori4b096fc2008-08-21 19:28:55 +0000149 /* Host side address */
150 int bus_num;
151 int addr;
Hans de Goede0f5160d2010-11-10 10:06:23 +0100152 int devpath;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100153 struct USBAutoFilter match;
aliguori4b096fc2008-08-21 19:28:55 +0000154
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100155 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000156} USBHostDevice;
157
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100158static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
159
160static int usb_host_close(USBHostDevice *dev);
161static int parse_filter(const char *spec, struct USBAutoFilter *f);
162static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100163static int usb_host_read_file(char *line, size_t line_size,
164 const char *device_file, const char *device_name);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100165
aliguori64838172008-08-21 19:31:10 +0000166static int is_isoc(USBHostDevice *s, int ep)
167{
168 return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO;
169}
170
171static int is_halted(USBHostDevice *s, int ep)
172{
173 return s->endp_table[ep - 1].halted;
174}
175
176static void clear_halt(USBHostDevice *s, int ep)
177{
178 s->endp_table[ep - 1].halted = 0;
179}
180
181static void set_halt(USBHostDevice *s, int ep)
182{
183 s->endp_table[ep - 1].halted = 1;
184}
185
Hans de Goede060dc842010-11-26 11:41:08 +0100186static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
187{
188 s->endp_table[ep - 1].iso_urb = iso_urb;
189}
190
191static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
192{
193 return s->endp_table[ep - 1].iso_urb;
194}
195
196static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
197{
198 s->endp_table[ep - 1].iso_urb_idx = i;
199}
200
201static int get_iso_urb_idx(USBHostDevice *s, int ep)
202{
203 return s->endp_table[ep - 1].iso_urb_idx;
204}
205
206static int get_max_packet_size(USBHostDevice *s, int ep)
207{
208 return s->endp_table[ep - 1].max_packet_size;
209}
210
David Ahern27911042010-04-24 10:26:22 -0600211/*
aliguori64838172008-08-21 19:31:10 +0000212 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100213 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600214 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000215 */
Hans de Goede060dc842010-11-26 11:41:08 +0100216struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000217{
aliguori64838172008-08-21 19:31:10 +0000218 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100219 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
aliguori64838172008-08-21 19:31:10 +0000220
Hans de Goede060dc842010-11-26 11:41:08 +0100221 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000222 USBPacket *packet;
223 USBHostDevice *hdev;
Hans de Goede060dc842010-11-26 11:41:08 +0100224
225 /* For buffered iso handling */
226 int iso_frame_idx; /* -1 means in flight */
227};
aliguori64838172008-08-21 19:31:10 +0000228
229static AsyncURB *async_alloc(void)
230{
231 return (AsyncURB *) qemu_mallocz(sizeof(AsyncURB));
balrogb9dc0332007-10-04 22:47:34 +0000232}
233
aliguori64838172008-08-21 19:31:10 +0000234static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000235{
aliguori64838172008-08-21 19:31:10 +0000236 qemu_free(aurb);
237}
balrogb9dc0332007-10-04 22:47:34 +0000238
aliguori446ab122008-09-14 01:06:09 +0000239static void async_complete_ctrl(USBHostDevice *s, USBPacket *p)
240{
241 switch(s->ctrl.state) {
242 case CTRL_STATE_SETUP:
243 if (p->len < s->ctrl.len)
244 s->ctrl.len = p->len;
245 s->ctrl.state = CTRL_STATE_DATA;
246 p->len = 8;
247 break;
248
249 case CTRL_STATE_ACK:
250 s->ctrl.state = CTRL_STATE_IDLE;
251 p->len = 0;
252 break;
253
254 default:
255 break;
256 }
257}
258
aliguori64838172008-08-21 19:31:10 +0000259static void async_complete(void *opaque)
260{
261 USBHostDevice *s = opaque;
262 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000263
aliguori64838172008-08-21 19:31:10 +0000264 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600265 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000266
David Ahern27911042010-04-24 10:26:22 -0600267 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000268 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600269 if (errno == EAGAIN) {
aliguori64838172008-08-21 19:31:10 +0000270 return;
David Ahern27911042010-04-24 10:26:22 -0600271 }
aliguori24772c12008-08-21 19:31:52 +0000272 if (errno == ENODEV && !s->closing) {
David Ahern27911042010-04-24 10:26:22 -0600273 printf("husb: device %d.%d disconnected\n",
274 s->bus_num, s->addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100275 usb_host_close(s);
276 usb_host_auto_check(NULL);
aliguori64838172008-08-21 19:31:10 +0000277 return;
278 }
279
malcd0f2c4c2010-02-07 02:03:50 +0300280 DPRINTF("husb: async. reap urb failed errno %d\n", errno);
aliguori64838172008-08-21 19:31:10 +0000281 return;
balrogb9dc0332007-10-04 22:47:34 +0000282 }
aliguori64838172008-08-21 19:31:10 +0000283
David Ahern27911042010-04-24 10:26:22 -0600284 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000285 aurb, aurb->urb.status, aurb->urb.actual_length);
286
Hans de Goede060dc842010-11-26 11:41:08 +0100287 /* If this is a buffered iso urb mark it as complete and don't do
288 anything else (it is handled further in usb_host_handle_iso_data) */
289 if (aurb->iso_frame_idx == -1) {
290 if (aurb->urb.status == -EPIPE) {
291 set_halt(s, aurb->urb.endpoint & 0xf);
292 }
293 aurb->iso_frame_idx = 0;
294 continue;
295 }
296
297 p = aurb->packet;
298
David Ahern27911042010-04-24 10:26:22 -0600299 if (p) {
aliguori64838172008-08-21 19:31:10 +0000300 switch (aurb->urb.status) {
301 case 0:
302 p->len = aurb->urb.actual_length;
David Ahern27911042010-04-24 10:26:22 -0600303 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
aliguori446ab122008-09-14 01:06:09 +0000304 async_complete_ctrl(s, p);
David Ahern27911042010-04-24 10:26:22 -0600305 }
aliguori64838172008-08-21 19:31:10 +0000306 break;
307
308 case -EPIPE:
309 set_halt(s, p->devep);
David Ahern27911042010-04-24 10:26:22 -0600310 p->len = USB_RET_STALL;
311 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200312
aliguori64838172008-08-21 19:31:10 +0000313 default:
314 p->len = USB_RET_NAK;
315 break;
316 }
317
318 usb_packet_complete(p);
David Ahern27911042010-04-24 10:26:22 -0600319 }
aliguori64838172008-08-21 19:31:10 +0000320
321 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000322 }
balrogb9dc0332007-10-04 22:47:34 +0000323}
324
aliguori64838172008-08-21 19:31:10 +0000325static void async_cancel(USBPacket *unused, void *opaque)
balrogb9dc0332007-10-04 22:47:34 +0000326{
aliguori64838172008-08-21 19:31:10 +0000327 AsyncURB *aurb = opaque;
328 USBHostDevice *s = aurb->hdev;
balrogb9dc0332007-10-04 22:47:34 +0000329
malcd0f2c4c2010-02-07 02:03:50 +0300330 DPRINTF("husb: async cancel. aurb %p\n", aurb);
balrogb9dc0332007-10-04 22:47:34 +0000331
aliguori64838172008-08-21 19:31:10 +0000332 /* Mark it as dead (see async_complete above) */
333 aurb->packet = NULL;
334
335 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
336 if (r < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300337 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
balrogb9dc0332007-10-04 22:47:34 +0000338 }
balrogb9dc0332007-10-04 22:47:34 +0000339}
340
aliguori446ab122008-09-14 01:06:09 +0000341static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000342{
343 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000344 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000345 int ret, i;
346
347 if (configuration == 0) /* address state - ignore */
348 return 1;
349
malcd0f2c4c2010-02-07 02:03:50 +0300350 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000351
balrogb9dc0332007-10-04 22:47:34 +0000352 i = 0;
353 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600354 if (dev_descr_len > dev->descr_len) {
balrogb9dc0332007-10-04 22:47:34 +0000355 goto fail;
David Ahern27911042010-04-24 10:26:22 -0600356 }
balrogb9dc0332007-10-04 22:47:34 +0000357
358 i += dev_descr_len;
359 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600360 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
361 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000362 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000363
balrogb9dc0332007-10-04 22:47:34 +0000364 if (dev->descr[i+1] != USB_DT_CONFIG) {
365 i += dev->descr[i];
366 continue;
367 }
368 config_descr_len = dev->descr[i];
369
David Ahern27911042010-04-24 10:26:22 -0600370 printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000371
aliguori446ab122008-09-14 01:06:09 +0000372 if (configuration < 0 || configuration == dev->descr[i + 5]) {
373 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000374 break;
aliguori446ab122008-09-14 01:06:09 +0000375 }
balrogb9dc0332007-10-04 22:47:34 +0000376
377 i += config_descr_len;
378 }
379
380 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600381 fprintf(stderr,
382 "husb: update iface failed. no matching configuration\n");
balrogb9dc0332007-10-04 22:47:34 +0000383 goto fail;
384 }
385 nb_interfaces = dev->descr[i + 4];
386
387#ifdef USBDEVFS_DISCONNECT
388 /* earlier Linux 2.4 do not support that */
389 {
390 struct usbdevfs_ioctl ctrl;
391 for (interface = 0; interface < nb_interfaces; interface++) {
392 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
393 ctrl.ifno = interface;
Brad Hards021730f2011-04-13 19:45:32 +1000394 ctrl.data = 0;
balrogb9dc0332007-10-04 22:47:34 +0000395 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
396 if (ret < 0 && errno != ENODATA) {
397 perror("USBDEVFS_DISCONNECT");
398 goto fail;
399 }
400 }
401 }
402#endif
403
404 /* XXX: only grab if all interfaces are free */
405 for (interface = 0; interface < nb_interfaces; interface++) {
406 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
407 if (ret < 0) {
408 if (errno == EBUSY) {
aliguori64838172008-08-21 19:31:10 +0000409 printf("husb: update iface. device already grabbed\n");
balrogb9dc0332007-10-04 22:47:34 +0000410 } else {
aliguori64838172008-08-21 19:31:10 +0000411 perror("husb: failed to claim interface");
balrogb9dc0332007-10-04 22:47:34 +0000412 }
413 fail:
414 return 0;
415 }
416 }
417
aliguori64838172008-08-21 19:31:10 +0000418 printf("husb: %d interfaces claimed for configuration %d\n",
balrogb9dc0332007-10-04 22:47:34 +0000419 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000420
aliguori446ab122008-09-14 01:06:09 +0000421 dev->ninterfaces = nb_interfaces;
422 dev->configuration = configuration;
423 return 1;
424}
425
426static int usb_host_release_interfaces(USBHostDevice *s)
427{
428 int ret, i;
429
malcd0f2c4c2010-02-07 02:03:50 +0300430 DPRINTF("husb: releasing interfaces\n");
aliguori446ab122008-09-14 01:06:09 +0000431
432 for (i = 0; i < s->ninterfaces; i++) {
433 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
434 if (ret < 0) {
435 perror("husb: failed to release interface");
436 return 0;
437 }
438 }
439
balrogb9dc0332007-10-04 22:47:34 +0000440 return 1;
441}
442
bellard059809e2006-07-19 18:06:15 +0000443static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000444{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100445 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000446
malcd0f2c4c2010-02-07 02:03:50 +0300447 DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000448
bellardbb36d472005-11-05 14:22:28 +0000449 ioctl(s->fd, USBDEVFS_RESET);
aliguori446ab122008-09-14 01:06:09 +0000450
451 usb_host_claim_interfaces(s, s->configuration);
ths5fafdf22007-09-16 21:08:06 +0000452}
bellardbb36d472005-11-05 14:22:28 +0000453
bellard059809e2006-07-19 18:06:15 +0000454static void usb_host_handle_destroy(USBDevice *dev)
455{
456 USBHostDevice *s = (USBHostDevice *)dev;
457
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100458 usb_host_close(s);
459 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300460 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000461}
462
balrogb9dc0332007-10-04 22:47:34 +0000463static int usb_linux_update_endp_table(USBHostDevice *s);
464
Hans de Goede060dc842010-11-26 11:41:08 +0100465/* iso data is special, we need to keep enough urbs in flight to make sure
466 that the controller never runs out of them, otherwise the device will
467 likely suffer a buffer underrun / overrun. */
468static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
469{
470 AsyncURB *aurb;
471 int i, j, len = get_max_packet_size(s, ep);
472
473 aurb = qemu_mallocz(ISO_URB_COUNT * sizeof(*aurb));
474 for (i = 0; i < ISO_URB_COUNT; i++) {
475 aurb[i].urb.endpoint = ep;
476 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
477 aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length);
478 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
479 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
480 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
481 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
482 aurb[i].urb.iso_frame_desc[j].length = len;
483 if (in) {
484 aurb[i].urb.endpoint |= 0x80;
485 /* Mark as fully consumed (idle) */
486 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
487 }
488 }
489 set_iso_urb(s, ep, aurb);
490
491 return aurb;
492}
493
494static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
495{
496 AsyncURB *aurb;
497 int i, ret, killed = 0, free = 1;
498
499 aurb = get_iso_urb(s, ep);
500 if (!aurb) {
501 return;
502 }
503
504 for (i = 0; i < ISO_URB_COUNT; i++) {
505 /* in flight? */
506 if (aurb[i].iso_frame_idx == -1) {
507 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
508 if (ret < 0) {
509 printf("husb: discard isoc in urb failed errno %d\n", errno);
510 free = 0;
511 continue;
512 }
513 killed++;
514 }
515 }
516
517 /* Make sure any urbs we've killed are reaped before we free them */
518 if (killed) {
519 async_complete(s);
520 }
521
522 for (i = 0; i < ISO_URB_COUNT; i++) {
523 qemu_free(aurb[i].urb.buffer);
524 }
525
526 if (free)
527 qemu_free(aurb);
528 else
529 printf("husb: leaking iso urbs because of discard failure\n");
530 set_iso_urb(s, ep, NULL);
531}
532
533static int urb_status_to_usb_ret(int status)
534{
535 switch (status) {
536 case -EPIPE:
537 return USB_RET_STALL;
538 default:
539 return USB_RET_NAK;
540 }
541}
542
543static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p)
544{
545 AsyncURB *aurb;
546 int i, j, ret, len = 0;
547
548 aurb = get_iso_urb(s, p->devep);
549 if (!aurb) {
550 aurb = usb_host_alloc_iso(s, p->devep, 1);
551 }
552
553 i = get_iso_urb_idx(s, p->devep);
554 j = aurb[i].iso_frame_idx;
555 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
556 /* Check urb status */
557 if (aurb[i].urb.status) {
558 len = urb_status_to_usb_ret(aurb[i].urb.status);
559 /* Move to the next urb */
560 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
561 /* Check frame status */
562 } else if (aurb[i].urb.iso_frame_desc[j].status) {
563 len = urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status);
564 /* Check the frame fits */
565 } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
566 printf("husb: error received isoc data is larger then packet\n");
567 len = USB_RET_NAK;
568 /* All good copy data over */
569 } else {
570 len = aurb[i].urb.iso_frame_desc[j].actual_length;
571 memcpy(p->data,
572 aurb[i].urb.buffer +
573 j * aurb[i].urb.iso_frame_desc[0].length,
574 len);
575 }
576 aurb[i].iso_frame_idx++;
577 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
578 i = (i + 1) % ISO_URB_COUNT;
579 set_iso_urb_idx(s, p->devep, i);
580 }
581 }
582
583 /* (Re)-submit all fully consumed urbs */
584 for (i = 0; i < ISO_URB_COUNT; i++) {
585 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
586 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
587 if (ret < 0) {
588 printf("husb error submitting isoc urb %d: %d\n", i, errno);
589 if (len == 0) {
590 switch(errno) {
591 case ETIMEDOUT:
592 len = USB_RET_NAK;
593 case EPIPE:
594 default:
595 len = USB_RET_STALL;
596 }
597 }
598 break;
599 }
600 aurb[i].iso_frame_idx = -1;
601 }
602 }
603
604 return len;
605}
606
aliguori446ab122008-09-14 01:06:09 +0000607static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000608{
aliguori64838172008-08-21 19:31:10 +0000609 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000610 AsyncURB *aurb;
bellardbb36d472005-11-05 14:22:28 +0000611 int ret;
Hans de Goede060dc842010-11-26 11:41:08 +0100612 uint8_t ep;
613
614 if (p->pid == USB_TOKEN_IN) {
615 ep = p->devep | 0x80;
616 } else {
617 ep = p->devep;
618 }
619
620 if (is_halted(s, p->devep)) {
621 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
622 if (ret < 0) {
623 DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
624 ep, errno);
625 return USB_RET_NAK;
626 }
627 clear_halt(s, p->devep);
628 }
629
630 if (is_isoc(s, p->devep) && p->pid == USB_TOKEN_IN)
631 return usb_host_handle_iso_data(s, p);
bellardbb36d472005-11-05 14:22:28 +0000632
aliguori64838172008-08-21 19:31:10 +0000633 aurb = async_alloc();
aliguori64838172008-08-21 19:31:10 +0000634 aurb->hdev = s;
635 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000636
aliguori64838172008-08-21 19:31:10 +0000637 urb = &aurb->urb;
638
Hans de Goede060dc842010-11-26 11:41:08 +0100639 urb->endpoint = ep;
aliguori64838172008-08-21 19:31:10 +0000640 urb->buffer = p->data;
balrogb9dc0332007-10-04 22:47:34 +0000641 urb->buffer_length = p->len;
aliguori64838172008-08-21 19:31:10 +0000642
643 if (is_isoc(s, p->devep)) {
644 /* Setup ISOC transfer */
645 urb->type = USBDEVFS_URB_TYPE_ISO;
646 urb->flags = USBDEVFS_URB_ISO_ASAP;
647 urb->number_of_packets = 1;
648 urb->iso_frame_desc[0].length = p->len;
balrogb9dc0332007-10-04 22:47:34 +0000649 } else {
aliguori64838172008-08-21 19:31:10 +0000650 /* Setup bulk transfer */
651 urb->type = USBDEVFS_URB_TYPE_BULK;
652 }
653
654 urb->usercontext = s;
655
656 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
657
David Ahern27911042010-04-24 10:26:22 -0600658 DPRINTF("husb: data submit. ep 0x%x len %u aurb %p\n",
659 urb->endpoint, p->len, aurb);
aliguori64838172008-08-21 19:31:10 +0000660
661 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300662 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori64838172008-08-21 19:31:10 +0000663 async_free(aurb);
664
balrogb9dc0332007-10-04 22:47:34 +0000665 switch(errno) {
666 case ETIMEDOUT:
667 return USB_RET_NAK;
668 case EPIPE:
669 default:
670 return USB_RET_STALL;
671 }
672 }
aliguori64838172008-08-21 19:31:10 +0000673
674 usb_defer_packet(p, async_cancel, aurb);
balrogb9dc0332007-10-04 22:47:34 +0000675 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000676}
677
aliguori446ab122008-09-14 01:06:09 +0000678static int ctrl_error(void)
679{
David Ahern27911042010-04-24 10:26:22 -0600680 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000681 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600682 } else {
aliguori446ab122008-09-14 01:06:09 +0000683 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600684 }
aliguori446ab122008-09-14 01:06:09 +0000685}
686
687static int usb_host_set_address(USBHostDevice *s, int addr)
688{
malcd0f2c4c2010-02-07 02:03:50 +0300689 DPRINTF("husb: ctrl set addr %u\n", addr);
aliguori446ab122008-09-14 01:06:09 +0000690 s->dev.addr = addr;
691 return 0;
692}
693
694static int usb_host_set_config(USBHostDevice *s, int config)
695{
696 usb_host_release_interfaces(s);
697
698 int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600699
malcd0f2c4c2010-02-07 02:03:50 +0300700 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600701
702 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000703 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600704 }
aliguori446ab122008-09-14 01:06:09 +0000705 usb_host_claim_interfaces(s, config);
706 return 0;
707}
708
709static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
710{
711 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100712 int i, ret;
713
714 for (i = 1; i < MAX_ENDPOINTS; i++) {
715 if (is_isoc(s, i)) {
716 usb_host_stop_n_free_iso(s, i);
717 }
718 }
aliguori446ab122008-09-14 01:06:09 +0000719
720 si.interface = iface;
721 si.altsetting = alt;
722 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000723
David Ahern27911042010-04-24 10:26:22 -0600724 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
725 iface, alt, ret, errno);
726
727 if (ret < 0) {
728 return ctrl_error();
729 }
aliguori446ab122008-09-14 01:06:09 +0000730 usb_linux_update_endp_table(s);
731 return 0;
732}
733
734static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
735{
736 struct usbdevfs_urb *urb;
737 AsyncURB *aurb;
738 int ret, value, index;
Jim Parisc4c0e232009-08-24 14:56:12 -0400739 int buffer_len;
aliguori446ab122008-09-14 01:06:09 +0000740
David Ahern27911042010-04-24 10:26:22 -0600741 /*
aliguori446ab122008-09-14 01:06:09 +0000742 * Process certain standard device requests.
743 * These are infrequent and are processed synchronously.
744 */
745 value = le16_to_cpu(s->ctrl.req.wValue);
746 index = le16_to_cpu(s->ctrl.req.wIndex);
747
malcd0f2c4c2010-02-07 02:03:50 +0300748 DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
David Ahern27911042010-04-24 10:26:22 -0600749 s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index,
750 s->ctrl.len);
aliguori446ab122008-09-14 01:06:09 +0000751
752 if (s->ctrl.req.bRequestType == 0) {
753 switch (s->ctrl.req.bRequest) {
754 case USB_REQ_SET_ADDRESS:
755 return usb_host_set_address(s, value);
756
757 case USB_REQ_SET_CONFIGURATION:
758 return usb_host_set_config(s, value & 0xff);
759 }
760 }
761
762 if (s->ctrl.req.bRequestType == 1 &&
David Ahern27911042010-04-24 10:26:22 -0600763 s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) {
aliguori446ab122008-09-14 01:06:09 +0000764 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -0600765 }
aliguori446ab122008-09-14 01:06:09 +0000766
767 /* The rest are asynchronous */
768
Jim Parisc4c0e232009-08-24 14:56:12 -0400769 buffer_len = 8 + s->ctrl.len;
770 if (buffer_len > sizeof(s->ctrl.buffer)) {
malcb2e3b6e2009-09-12 03:18:18 +0400771 fprintf(stderr, "husb: ctrl buffer too small (%u > %zu)\n",
772 buffer_len, sizeof(s->ctrl.buffer));
773 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -0400774 }
775
aliguori446ab122008-09-14 01:06:09 +0000776 aurb = async_alloc();
aliguori446ab122008-09-14 01:06:09 +0000777 aurb->hdev = s;
778 aurb->packet = p;
779
David Ahern27911042010-04-24 10:26:22 -0600780 /*
aliguori446ab122008-09-14 01:06:09 +0000781 * Setup ctrl transfer.
782 *
Brad Hardsa0102082011-04-13 19:45:33 +1000783 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +0000784 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -0600785 */
aliguori446ab122008-09-14 01:06:09 +0000786 urb = &aurb->urb;
787
788 urb->type = USBDEVFS_URB_TYPE_CONTROL;
789 urb->endpoint = p->devep;
790
791 urb->buffer = &s->ctrl.req;
Jim Parisc4c0e232009-08-24 14:56:12 -0400792 urb->buffer_length = buffer_len;
aliguori446ab122008-09-14 01:06:09 +0000793
794 urb->usercontext = s;
795
796 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
797
malcd0f2c4c2010-02-07 02:03:50 +0300798 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +0000799
800 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300801 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +0000802 async_free(aurb);
803
804 switch(errno) {
805 case ETIMEDOUT:
806 return USB_RET_NAK;
807 case EPIPE:
808 default:
809 return USB_RET_STALL;
810 }
811 }
812
813 usb_defer_packet(p, async_cancel, aurb);
814 return USB_RET_ASYNC;
815}
816
817static int do_token_setup(USBDevice *dev, USBPacket *p)
818{
819 USBHostDevice *s = (USBHostDevice *) dev;
820 int ret = 0;
821
David Ahern27911042010-04-24 10:26:22 -0600822 if (p->len != 8) {
aliguori446ab122008-09-14 01:06:09 +0000823 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600824 }
825
aliguori446ab122008-09-14 01:06:09 +0000826 memcpy(&s->ctrl.req, p->data, 8);
827 s->ctrl.len = le16_to_cpu(s->ctrl.req.wLength);
828 s->ctrl.offset = 0;
829 s->ctrl.state = CTRL_STATE_SETUP;
830
831 if (s->ctrl.req.bRequestType & USB_DIR_IN) {
832 ret = usb_host_handle_control(s, p);
David Ahern27911042010-04-24 10:26:22 -0600833 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000834 return ret;
David Ahern27911042010-04-24 10:26:22 -0600835 }
aliguori446ab122008-09-14 01:06:09 +0000836
David Ahern27911042010-04-24 10:26:22 -0600837 if (ret < s->ctrl.len) {
aliguori446ab122008-09-14 01:06:09 +0000838 s->ctrl.len = ret;
David Ahern27911042010-04-24 10:26:22 -0600839 }
aliguori446ab122008-09-14 01:06:09 +0000840 s->ctrl.state = CTRL_STATE_DATA;
841 } else {
David Ahern27911042010-04-24 10:26:22 -0600842 if (s->ctrl.len == 0) {
aliguori446ab122008-09-14 01:06:09 +0000843 s->ctrl.state = CTRL_STATE_ACK;
David Ahern27911042010-04-24 10:26:22 -0600844 } else {
aliguori446ab122008-09-14 01:06:09 +0000845 s->ctrl.state = CTRL_STATE_DATA;
David Ahern27911042010-04-24 10:26:22 -0600846 }
aliguori446ab122008-09-14 01:06:09 +0000847 }
848
849 return ret;
850}
851
852static int do_token_in(USBDevice *dev, USBPacket *p)
853{
854 USBHostDevice *s = (USBHostDevice *) dev;
855 int ret = 0;
856
David Ahern27911042010-04-24 10:26:22 -0600857 if (p->devep != 0) {
aliguori446ab122008-09-14 01:06:09 +0000858 return usb_host_handle_data(s, p);
David Ahern27911042010-04-24 10:26:22 -0600859 }
aliguori446ab122008-09-14 01:06:09 +0000860
861 switch(s->ctrl.state) {
862 case CTRL_STATE_ACK:
863 if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
864 ret = usb_host_handle_control(s, p);
David Ahern27911042010-04-24 10:26:22 -0600865 if (ret == USB_RET_ASYNC) {
aliguori446ab122008-09-14 01:06:09 +0000866 return USB_RET_ASYNC;
David Ahern27911042010-04-24 10:26:22 -0600867 }
aliguori446ab122008-09-14 01:06:09 +0000868 s->ctrl.state = CTRL_STATE_IDLE;
869 return ret > 0 ? 0 : ret;
870 }
871
872 return 0;
873
874 case CTRL_STATE_DATA:
875 if (s->ctrl.req.bRequestType & USB_DIR_IN) {
876 int len = s->ctrl.len - s->ctrl.offset;
David Ahern27911042010-04-24 10:26:22 -0600877 if (len > p->len) {
aliguori446ab122008-09-14 01:06:09 +0000878 len = p->len;
David Ahern27911042010-04-24 10:26:22 -0600879 }
aliguori446ab122008-09-14 01:06:09 +0000880 memcpy(p->data, s->ctrl.buffer + s->ctrl.offset, len);
881 s->ctrl.offset += len;
David Ahern27911042010-04-24 10:26:22 -0600882 if (s->ctrl.offset >= s->ctrl.len) {
aliguori446ab122008-09-14 01:06:09 +0000883 s->ctrl.state = CTRL_STATE_ACK;
David Ahern27911042010-04-24 10:26:22 -0600884 }
aliguori446ab122008-09-14 01:06:09 +0000885 return len;
886 }
887
888 s->ctrl.state = CTRL_STATE_IDLE;
889 return USB_RET_STALL;
890
891 default:
892 return USB_RET_STALL;
893 }
894}
895
896static int do_token_out(USBDevice *dev, USBPacket *p)
897{
898 USBHostDevice *s = (USBHostDevice *) dev;
899
David Ahern27911042010-04-24 10:26:22 -0600900 if (p->devep != 0) {
aliguori446ab122008-09-14 01:06:09 +0000901 return usb_host_handle_data(s, p);
David Ahern27911042010-04-24 10:26:22 -0600902 }
aliguori446ab122008-09-14 01:06:09 +0000903
904 switch(s->ctrl.state) {
905 case CTRL_STATE_ACK:
906 if (s->ctrl.req.bRequestType & USB_DIR_IN) {
907 s->ctrl.state = CTRL_STATE_IDLE;
908 /* transfer OK */
909 } else {
910 /* ignore additional output */
911 }
912 return 0;
913
914 case CTRL_STATE_DATA:
915 if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
916 int len = s->ctrl.len - s->ctrl.offset;
David Ahern27911042010-04-24 10:26:22 -0600917 if (len > p->len) {
aliguori446ab122008-09-14 01:06:09 +0000918 len = p->len;
David Ahern27911042010-04-24 10:26:22 -0600919 }
aliguori446ab122008-09-14 01:06:09 +0000920 memcpy(s->ctrl.buffer + s->ctrl.offset, p->data, len);
921 s->ctrl.offset += len;
David Ahern27911042010-04-24 10:26:22 -0600922 if (s->ctrl.offset >= s->ctrl.len) {
aliguori446ab122008-09-14 01:06:09 +0000923 s->ctrl.state = CTRL_STATE_ACK;
David Ahern27911042010-04-24 10:26:22 -0600924 }
aliguori446ab122008-09-14 01:06:09 +0000925 return len;
926 }
927
928 s->ctrl.state = CTRL_STATE_IDLE;
929 return USB_RET_STALL;
930
931 default:
932 return USB_RET_STALL;
933 }
934}
935
936/*
937 * Packet handler.
938 * Called by the HC (host controller).
939 *
940 * Returns length of the transaction or one of the USB_RET_XXX codes.
941 */
blueswir1d9cf1572008-09-15 14:57:11 +0000942static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
aliguori446ab122008-09-14 01:06:09 +0000943{
944 switch(p->pid) {
945 case USB_MSG_ATTACH:
946 s->state = USB_STATE_ATTACHED;
947 return 0;
948
949 case USB_MSG_DETACH:
950 s->state = USB_STATE_NOTATTACHED;
951 return 0;
952
953 case USB_MSG_RESET:
954 s->remote_wakeup = 0;
955 s->addr = 0;
956 s->state = USB_STATE_DEFAULT;
Gerd Hoffmann806b6022009-08-31 14:23:59 +0200957 s->info->handle_reset(s);
aliguori446ab122008-09-14 01:06:09 +0000958 return 0;
959 }
960
961 /* Rest of the PIDs must match our address */
David Ahern27911042010-04-24 10:26:22 -0600962 if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) {
aliguori446ab122008-09-14 01:06:09 +0000963 return USB_RET_NODEV;
David Ahern27911042010-04-24 10:26:22 -0600964 }
aliguori446ab122008-09-14 01:06:09 +0000965
966 switch (p->pid) {
967 case USB_TOKEN_SETUP:
968 return do_token_setup(s, p);
969
970 case USB_TOKEN_IN:
971 return do_token_in(s, p);
972
973 case USB_TOKEN_OUT:
974 return do_token_out(s, p);
David Ahern27911042010-04-24 10:26:22 -0600975
aliguori446ab122008-09-14 01:06:09 +0000976 default:
977 return USB_RET_STALL;
978 }
979}
980
Hans de Goede71d71bb2010-11-10 10:06:24 +0100981static int usb_linux_get_configuration(USBHostDevice *s)
balrogb9dc0332007-10-04 22:47:34 +0000982{
Hans de Goede71d71bb2010-11-10 10:06:24 +0100983 uint8_t configuration;
pbrooke41b3912008-10-28 18:22:59 +0000984 struct usb_ctrltransfer ct;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100985 int ret;
balrogb9dc0332007-10-04 22:47:34 +0000986
Hans de Goede2cc59d82010-11-10 10:06:25 +0100987 if (usb_fs_type == USB_FS_SYS) {
988 char device_name[32], line[1024];
989 int configuration;
990
991 sprintf(device_name, "%d-%d", s->bus_num, s->devpath);
992
993 if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
994 device_name)) {
995 goto usbdevfs;
996 }
997 if (sscanf(line, "%d", &configuration) != 1) {
998 goto usbdevfs;
999 }
1000 return configuration;
1001 }
1002
1003usbdevfs:
balrogb9dc0332007-10-04 22:47:34 +00001004 ct.bRequestType = USB_DIR_IN;
1005 ct.bRequest = USB_REQ_GET_CONFIGURATION;
1006 ct.wValue = 0;
1007 ct.wIndex = 0;
1008 ct.wLength = 1;
1009 ct.data = &configuration;
1010 ct.timeout = 50;
1011
1012 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
1013 if (ret < 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +01001014 perror("usb_linux_get_configuration");
1015 return -1;
balrogb9dc0332007-10-04 22:47:34 +00001016 }
1017
1018 /* in address state */
David Ahern27911042010-04-24 10:26:22 -06001019 if (configuration == 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +01001020 return -1;
David Ahern27911042010-04-24 10:26:22 -06001021 }
balrogb9dc0332007-10-04 22:47:34 +00001022
Hans de Goede71d71bb2010-11-10 10:06:24 +01001023 return configuration;
1024}
1025
Hans de Goedeed3a3282010-11-24 12:50:00 +01001026static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
1027 uint8_t configuration, uint8_t interface)
1028{
1029 uint8_t alt_setting;
1030 struct usb_ctrltransfer ct;
1031 int ret;
1032
Hans de Goedec43831f2010-11-24 12:57:59 +01001033 if (usb_fs_type == USB_FS_SYS) {
1034 char device_name[64], line[1024];
1035 int alt_setting;
1036
1037 sprintf(device_name, "%d-%d:%d.%d", s->bus_num, s->devpath,
1038 (int)configuration, (int)interface);
1039
1040 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
1041 device_name)) {
1042 goto usbdevfs;
1043 }
1044 if (sscanf(line, "%d", &alt_setting) != 1) {
1045 goto usbdevfs;
1046 }
1047 return alt_setting;
1048 }
1049
1050usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +01001051 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
1052 ct.bRequest = USB_REQ_GET_INTERFACE;
1053 ct.wValue = 0;
1054 ct.wIndex = interface;
1055 ct.wLength = 1;
1056 ct.data = &alt_setting;
1057 ct.timeout = 50;
1058 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
1059 if (ret < 0) {
1060 /* Assume alt 0 on error */
1061 return 0;
1062 }
1063
1064 return alt_setting;
1065}
1066
Hans de Goede71d71bb2010-11-10 10:06:24 +01001067/* returns 1 on problem encountered or 0 for success */
1068static int usb_linux_update_endp_table(USBHostDevice *s)
1069{
1070 uint8_t *descriptors;
1071 uint8_t devep, type, configuration, alt_interface;
Hans de Goedeed3a3282010-11-24 12:50:00 +01001072 int interface, length, i;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001073
1074 i = usb_linux_get_configuration(s);
1075 if (i < 0)
1076 return 1;
1077 configuration = i;
1078
balrogb9dc0332007-10-04 22:47:34 +00001079 /* get the desired configuration, interface, and endpoint descriptors
1080 * from device description */
1081 descriptors = &s->descr[18];
1082 length = s->descr_len - 18;
1083 i = 0;
1084
1085 if (descriptors[i + 1] != USB_DT_CONFIG ||
1086 descriptors[i + 5] != configuration) {
malcd0f2c4c2010-02-07 02:03:50 +03001087 DPRINTF("invalid descriptor data - configuration\n");
balrogb9dc0332007-10-04 22:47:34 +00001088 return 1;
1089 }
1090 i += descriptors[i];
1091
1092 while (i < length) {
1093 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1094 (descriptors[i + 1] == USB_DT_INTERFACE &&
1095 descriptors[i + 4] == 0)) {
1096 i += descriptors[i];
1097 continue;
1098 }
1099
1100 interface = descriptors[i + 2];
Hans de Goedeed3a3282010-11-24 12:50:00 +01001101 alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
balrogb9dc0332007-10-04 22:47:34 +00001102
1103 /* the current interface descriptor is the active interface
1104 * and has endpoints */
1105 if (descriptors[i + 3] != alt_interface) {
1106 i += descriptors[i];
1107 continue;
1108 }
1109
1110 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001111 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001112 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001113 }
balrogb9dc0332007-10-04 22:47:34 +00001114
1115 if (i >= length)
1116 break;
1117
1118 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001119 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001120 break;
David Ahern27911042010-04-24 10:26:22 -06001121 }
balrogb9dc0332007-10-04 22:47:34 +00001122
1123 devep = descriptors[i + 2];
1124 switch (descriptors[i + 3] & 0x3) {
1125 case 0x00:
1126 type = USBDEVFS_URB_TYPE_CONTROL;
1127 break;
1128 case 0x01:
1129 type = USBDEVFS_URB_TYPE_ISO;
Hans de Goede060dc842010-11-26 11:41:08 +01001130 s->endp_table[(devep & 0xf) - 1].max_packet_size =
1131 descriptors[i + 4] + (descriptors[i + 5] << 8);
balrogb9dc0332007-10-04 22:47:34 +00001132 break;
1133 case 0x02:
1134 type = USBDEVFS_URB_TYPE_BULK;
1135 break;
1136 case 0x03:
1137 type = USBDEVFS_URB_TYPE_INTERRUPT;
1138 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -05001139 default:
1140 DPRINTF("usb_host: malformed endpoint type\n");
1141 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +00001142 }
1143 s->endp_table[(devep & 0xf) - 1].type = type;
aliguori64838172008-08-21 19:31:10 +00001144 s->endp_table[(devep & 0xf) - 1].halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001145
1146 i += descriptors[i];
1147 }
1148 }
1149 return 0;
1150}
1151
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001152static int usb_host_open(USBHostDevice *dev, int bus_num,
Hans de Goede0f5160d2010-11-10 10:06:23 +01001153 int addr, int devpath, const char *prod_name)
bellardbb36d472005-11-05 14:22:28 +00001154{
balrogb9dc0332007-10-04 22:47:34 +00001155 int fd = -1, ret;
bellardbb36d472005-11-05 14:22:28 +00001156 struct usbdevfs_connectinfo ci;
bellarda594cfb2005-11-06 16:13:29 +00001157 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001158
David Ahern27911042010-04-24 10:26:22 -06001159 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001160 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001161 }
aliguori64838172008-08-21 19:31:10 +00001162 printf("husb: open device %d.%d\n", bus_num, addr);
aliguori1f3870a2008-08-21 19:27:48 +00001163
aliguori0f431522008-10-07 20:06:37 +00001164 if (!usb_host_device_path) {
1165 perror("husb: USB Host Device Path not set");
1166 goto fail;
1167 }
1168 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001169 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001170 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001171 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001172 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001173 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001174 }
malcd0f2c4c2010-02-07 02:03:50 +03001175 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001176
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001177 dev->bus_num = bus_num;
1178 dev->addr = addr;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001179 dev->devpath = devpath;
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001180 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001181
balrogb9dc0332007-10-04 22:47:34 +00001182 /* read the device description */
1183 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1184 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001185 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001186 goto fail;
1187 }
ths3b46e622007-09-17 08:09:54 +00001188
balrogb9dc0332007-10-04 22:47:34 +00001189#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001190 {
balrogb9dc0332007-10-04 22:47:34 +00001191 int x;
1192 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001193 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001194 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001195 }
balrogb9dc0332007-10-04 22:47:34 +00001196 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001197 }
1198#endif
1199
balrogb9dc0332007-10-04 22:47:34 +00001200
David Ahern27911042010-04-24 10:26:22 -06001201 /*
1202 * Initial configuration is -1 which makes us claim first
aliguori446ab122008-09-14 01:06:09 +00001203 * available config. We used to start with 1, which does not
David Ahern27911042010-04-24 10:26:22 -06001204 * always work. I've seen devices where first config starts
aliguori446ab122008-09-14 01:06:09 +00001205 * with 2.
1206 */
David Ahern27911042010-04-24 10:26:22 -06001207 if (!usb_host_claim_interfaces(dev, -1)) {
balrogb9dc0332007-10-04 22:47:34 +00001208 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001209 }
bellardbb36d472005-11-05 14:22:28 +00001210
1211 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1212 if (ret < 0) {
balrog046833e2007-10-31 00:27:50 +00001213 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
bellardbb36d472005-11-05 14:22:28 +00001214 goto fail;
1215 }
1216
aliguori64838172008-08-21 19:31:10 +00001217 printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001218
balrogb9dc0332007-10-04 22:47:34 +00001219 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001220 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001221 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001222 }
balrogb9dc0332007-10-04 22:47:34 +00001223
David Ahern27911042010-04-24 10:26:22 -06001224 if (ci.slow) {
bellardbb36d472005-11-05 14:22:28 +00001225 dev->dev.speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001226 } else {
bellardbb36d472005-11-05 14:22:28 +00001227 dev->dev.speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001228 }
bellardbb36d472005-11-05 14:22:28 +00001229
David Ahern27911042010-04-24 10:26:22 -06001230 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001231 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001232 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001233 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001234 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001235 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001236 }
bellard1f6e24e2006-06-26 21:00:51 +00001237
aliguori64838172008-08-21 19:31:10 +00001238 /* USB devio uses 'write' flag to check for async completions */
1239 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001240
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001241 usb_device_attach(&dev->dev);
1242 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001243
balrogb9dc0332007-10-04 22:47:34 +00001244fail:
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001245 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001246 if (fd != -1) {
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001247 close(fd);
David Ahern27911042010-04-24 10:26:22 -06001248 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001249 return -1;
1250}
1251
1252static int usb_host_close(USBHostDevice *dev)
1253{
Hans de Goede060dc842010-11-26 11:41:08 +01001254 int i;
1255
David Ahern27911042010-04-24 10:26:22 -06001256 if (dev->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001257 return -1;
David Ahern27911042010-04-24 10:26:22 -06001258 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001259
1260 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1261 dev->closing = 1;
Hans de Goede060dc842010-11-26 11:41:08 +01001262 for (i = 1; i < MAX_ENDPOINTS; i++) {
1263 if (is_isoc(dev, i)) {
1264 usb_host_stop_n_free_iso(dev, i);
1265 }
1266 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001267 async_complete(dev);
1268 dev->closing = 0;
1269 usb_device_detach(&dev->dev);
Shahar Havivi00ff2272010-06-16 15:15:37 +03001270 ioctl(dev->fd, USBDEVFS_RESET);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001271 close(dev->fd);
1272 dev->fd = -1;
1273 return 0;
1274}
1275
Shahar Havivib373a632010-06-16 15:16:11 +03001276static void usb_host_exit_notifier(struct Notifier* n)
1277{
1278 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1279
1280 if (s->fd != -1) {
1281 ioctl(s->fd, USBDEVFS_RESET);
1282 }
1283}
1284
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001285static int usb_host_initfn(USBDevice *dev)
1286{
1287 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1288
1289 dev->auto_attach = 0;
1290 s->fd = -1;
1291 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001292 s->exit.notify = usb_host_exit_notifier;
1293 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001294 usb_host_auto_check(NULL);
1295 return 0;
bellardbb36d472005-11-05 14:22:28 +00001296}
1297
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001298static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001299 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001300 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001301 .qdev.size = sizeof(USBHostDevice),
1302 .init = usb_host_initfn,
1303 .handle_packet = usb_host_handle_packet,
1304 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001305 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001306 .usbdevice_name = "host",
1307 .usbdevice_init = usb_host_device_open,
1308 .qdev.props = (Property[]) {
1309 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1310 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
1311 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1312 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
1313 DEFINE_PROP_END_OF_LIST(),
1314 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001315};
1316
1317static void usb_host_register_devices(void)
1318{
1319 usb_qdev_register(&usb_host_dev_info);
1320}
1321device_init(usb_host_register_devices)
1322
aliguori4b096fc2008-08-21 19:28:55 +00001323USBDevice *usb_host_device_open(const char *devname)
1324{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001325 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001326 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001327 char *p;
1328
Markus Armbruster556cd092009-12-09 17:07:53 +01001329 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001330
aliguori5d0c5752008-09-14 01:07:41 +00001331 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001332 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001333 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001334 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001335 } else {
1336 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001337 filter.bus_num = strtoul(devname, NULL, 0);
1338 filter.addr = strtoul(p + 1, NULL, 0);
1339 filter.vendor_id = 0;
1340 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001341 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001342 filter.bus_num = 0;
1343 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001344 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001345 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001346 } else {
1347 goto fail;
1348 }
aliguori5d0c5752008-09-14 01:07:41 +00001349 }
1350
Markus Armbruster0745eb12009-11-27 13:05:53 +01001351 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1352 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001353 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1354 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001355 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001356 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001357
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001358fail:
1359 qdev_free(&dev->qdev);
1360 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001361}
aliguori5d0c5752008-09-14 01:07:41 +00001362
1363int usb_host_device_close(const char *devname)
1364{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001365#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001366 char product_name[PRODUCT_NAME_SZ];
1367 int bus_num, addr;
1368 USBHostDevice *s;
1369
David Ahern27911042010-04-24 10:26:22 -06001370 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001371 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001372 }
1373 if (usb_host_find_device(&bus_num, &addr, product_name,
1374 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001375 return -1;
David Ahern27911042010-04-24 10:26:22 -06001376 }
aliguori5d0c5752008-09-14 01:07:41 +00001377 s = hostdev_find(bus_num, addr);
1378 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001379 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001380 return 0;
1381 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001382#endif
aliguori5d0c5752008-09-14 01:07:41 +00001383
1384 return -1;
1385}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001386
bellarda594cfb2005-11-06 16:13:29 +00001387static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001388 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001389 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001390{
bellarda594cfb2005-11-06 16:13:29 +00001391 const char *p;
1392 char *q;
1393 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001394 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001395 return -1;
David Ahern27911042010-04-24 10:26:22 -06001396 }
bellarda594cfb2005-11-06 16:13:29 +00001397 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001398 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001399 p++;
David Ahern27911042010-04-24 10:26:22 -06001400 }
bellarda594cfb2005-11-06 16:13:29 +00001401 q = buf;
1402 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001403 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001404 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001405 }
bellarda594cfb2005-11-06 16:13:29 +00001406 p++;
1407 }
1408 *q = '\0';
1409 return q - buf;
1410}
bellardbb36d472005-11-05 14:22:28 +00001411
aliguori0f431522008-10-07 20:06:37 +00001412/*
1413 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1414 * host's USB devices. This is legacy support since many distributions
1415 * are moving to /sys/bus/usb
1416 */
1417static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001418{
Blue Swirl660f11b2009-07-31 21:16:51 +00001419 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001420 char line[1024];
1421 char buf[1024];
1422 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
bellarda594cfb2005-11-06 16:13:29 +00001423 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001424 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001425
aliguori0f431522008-10-07 20:06:37 +00001426 if (!usb_host_device_path) {
1427 perror("husb: USB Host Device Path not set");
1428 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001429 }
aliguori0f431522008-10-07 20:06:37 +00001430 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1431 f = fopen(line, "r");
1432 if (!f) {
1433 perror("husb: cannot open devices file");
1434 goto the_end;
1435 }
1436
bellarda594cfb2005-11-06 16:13:29 +00001437 device_count = 0;
1438 bus_num = addr = speed = class_id = product_id = vendor_id = 0;
bellardbb36d472005-11-05 14:22:28 +00001439 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001440 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001441 break;
David Ahern27911042010-04-24 10:26:22 -06001442 }
1443 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001444 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001445 }
bellarda594cfb2005-11-06 16:13:29 +00001446 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001447 if (device_count && (vendor_id || product_id)) {
1448 /* New device. Add the previously discovered device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001449 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001450 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001451 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001452 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001453 }
bellarda594cfb2005-11-06 16:13:29 +00001454 }
David Ahern27911042010-04-24 10:26:22 -06001455 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001456 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001457 }
bellarda594cfb2005-11-06 16:13:29 +00001458 bus_num = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001459 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001460 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001461 }
bellarda594cfb2005-11-06 16:13:29 +00001462 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001463 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001464 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001465 }
1466 if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001467 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001468 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001469 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001470 } else {
bellarda594cfb2005-11-06 16:13:29 +00001471 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001472 }
bellarda594cfb2005-11-06 16:13:29 +00001473 product_name[0] = '\0';
1474 class_id = 0xff;
1475 device_count++;
1476 product_id = 0;
1477 vendor_id = 0;
1478 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001479 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001480 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001481 }
bellarda594cfb2005-11-06 16:13:29 +00001482 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001483 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001484 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001485 }
bellarda594cfb2005-11-06 16:13:29 +00001486 product_id = strtoul(buf, NULL, 16);
1487 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001488 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001489 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001490 }
bellarda594cfb2005-11-06 16:13:29 +00001491 pstrcpy(product_name, sizeof(product_name), buf);
1492 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001493 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001494 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001495 }
bellarda594cfb2005-11-06 16:13:29 +00001496 class_id = strtoul(buf, NULL, 16);
1497 }
1498 fail: ;
1499 }
pbrook38ca0f62006-03-11 18:03:38 +00001500 if (device_count && (vendor_id || product_id)) {
1501 /* Add the last device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001502 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001503 product_id, product_name, speed);
1504 }
1505 the_end:
David Ahern27911042010-04-24 10:26:22 -06001506 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001507 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001508 }
aliguori0f431522008-10-07 20:06:37 +00001509 return ret;
1510}
1511
1512/*
1513 * Read sys file-system device file
1514 *
1515 * @line address of buffer to put file contents in
1516 * @line_size size of line
1517 * @device_file path to device file (printf format string)
1518 * @device_name device being opened (inserted into device_file)
1519 *
1520 * @return 0 failed, 1 succeeded ('line' contains data)
1521 */
David Ahern27911042010-04-24 10:26:22 -06001522static int usb_host_read_file(char *line, size_t line_size,
1523 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001524{
1525 FILE *f;
1526 int ret = 0;
1527 char filename[PATH_MAX];
1528
blueswir1b4e237a2008-12-28 15:45:20 +00001529 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1530 device_file);
aliguori0f431522008-10-07 20:06:37 +00001531 f = fopen(filename, "r");
1532 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001533 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001534 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001535 }
1536
1537 return ret;
1538}
1539
1540/*
1541 * Use /sys/bus/usb/devices/ directory to determine host's USB
1542 * devices.
1543 *
1544 * This code is based on Robert Schiele's original patches posted to
1545 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1546 */
1547static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1548{
Blue Swirl660f11b2009-07-31 21:16:51 +00001549 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001550 char line[1024];
Hans de Goede0f5160d2010-11-10 10:06:23 +01001551 int bus_num, addr, devpath, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001552 int ret = 0;
1553 char product_name[512];
1554 struct dirent *de;
1555
1556 dir = opendir(USBSYSBUS_PATH "/devices");
1557 if (!dir) {
1558 perror("husb: cannot open devices directory");
1559 goto the_end;
1560 }
1561
1562 while ((de = readdir(dir))) {
1563 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
1564 char *tmpstr = de->d_name;
David Ahern27911042010-04-24 10:26:22 -06001565 if (!strncmp(de->d_name, "usb", 3)) {
aliguori0f431522008-10-07 20:06:37 +00001566 tmpstr += 3;
David Ahern27911042010-04-24 10:26:22 -06001567 }
Hans de Goede0f5160d2010-11-10 10:06:23 +01001568 if (sscanf(tmpstr, "%d-%d", &bus_num, &devpath) < 1) {
1569 goto the_end;
1570 }
aliguori0f431522008-10-07 20:06:37 +00001571
David Ahern27911042010-04-24 10:26:22 -06001572 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001573 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001574 }
1575 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001576 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001577 }
blueswir1b4e237a2008-12-28 15:45:20 +00001578 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001579 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001580 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001581 }
1582 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001583 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001584 }
aliguori0f431522008-10-07 20:06:37 +00001585
David Ahern27911042010-04-24 10:26:22 -06001586 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1587 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001588 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001589 }
1590 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001591 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001592 }
blueswir1b4e237a2008-12-28 15:45:20 +00001593 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001594 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001595 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001596 }
1597 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001598 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001599 }
blueswir1b4e237a2008-12-28 15:45:20 +00001600 if (!usb_host_read_file(line, sizeof(line), "product",
1601 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001602 *product_name = 0;
1603 } else {
David Ahern27911042010-04-24 10:26:22 -06001604 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001605 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001606 }
aliguori0f431522008-10-07 20:06:37 +00001607 pstrcpy(product_name, sizeof(product_name), line);
1608 }
1609
David Ahern27911042010-04-24 10:26:22 -06001610 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001611 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001612 }
1613 if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001614 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001615 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001616 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001617 } else {
aliguori0f431522008-10-07 20:06:37 +00001618 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001619 }
aliguori0f431522008-10-07 20:06:37 +00001620
Hans de Goede0f5160d2010-11-10 10:06:23 +01001621 ret = func(opaque, bus_num, addr, devpath, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001622 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001623 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001624 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001625 }
aliguori0f431522008-10-07 20:06:37 +00001626 }
1627 }
1628 the_end:
David Ahern27911042010-04-24 10:26:22 -06001629 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001630 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001631 }
aliguori0f431522008-10-07 20:06:37 +00001632 return ret;
1633}
1634
1635/*
1636 * Determine how to access the host's USB devices and call the
1637 * specific support function.
1638 */
1639static int usb_host_scan(void *opaque, USBScanFunc *func)
1640{
aliguori376253e2009-03-05 23:01:23 +00001641 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001642 FILE *f = NULL;
1643 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001644 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001645 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1646 char devpath[PATH_MAX];
1647
1648 /* only check the host once */
1649 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001650 dir = opendir(USBSYSBUS_PATH "/devices");
1651 if (dir) {
1652 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1653 strcpy(devpath, USBDEVBUS_PATH);
1654 usb_fs_type = USB_FS_SYS;
1655 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001656 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001657 goto found_devices;
1658 }
aliguori0f431522008-10-07 20:06:37 +00001659 f = fopen(USBPROCBUS_PATH "/devices", "r");
1660 if (f) {
1661 /* devices found in /proc/bus/usb/ */
1662 strcpy(devpath, USBPROCBUS_PATH);
1663 usb_fs_type = USB_FS_PROC;
1664 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001665 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001666 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001667 }
1668 /* try additional methods if an access method hasn't been found yet */
1669 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001670 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001671 /* devices found in /dev/bus/usb/ */
1672 strcpy(devpath, USBDEVBUS_PATH);
1673 usb_fs_type = USB_FS_DEV;
1674 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001675 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001676 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001677 }
aliguorif16a0db2008-10-21 16:34:20 +00001678 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001679 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001680 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001681 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001682 }
aliguorif16a0db2008-10-21 16:34:20 +00001683 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001684 }
1685
1686 /* the module setting (used later for opening devices) */
1687 usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001688 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001689 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001690 monitor_printf(mon, "husb: using %s file-system with %s\n",
1691 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001692 }
aliguori0f431522008-10-07 20:06:37 +00001693 }
1694
1695 switch (usb_fs_type) {
1696 case USB_FS_PROC:
1697 case USB_FS_DEV:
1698 ret = usb_host_scan_dev(opaque, func);
1699 break;
1700 case USB_FS_SYS:
1701 ret = usb_host_scan_sys(opaque, func);
1702 break;
aliguorif16a0db2008-10-21 16:34:20 +00001703 default:
1704 ret = -EINVAL;
1705 break;
aliguori0f431522008-10-07 20:06:37 +00001706 }
bellarda594cfb2005-11-06 16:13:29 +00001707 return ret;
1708}
1709
aliguori4b096fc2008-08-21 19:28:55 +00001710static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001711
Hans de Goede0f5160d2010-11-10 10:06:23 +01001712static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001713 int class_id, int vendor_id, int product_id,
1714 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001715{
1716 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001717 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001718
1719 /* Ignore hubs */
1720 if (class_id == 9)
1721 return 0;
1722
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001723 QTAILQ_FOREACH(s, &hostdevs, next) {
1724 f = &s->match;
1725
David Ahern27911042010-04-24 10:26:22 -06001726 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001727 continue;
David Ahern27911042010-04-24 10:26:22 -06001728 }
1729 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001730 continue;
David Ahern27911042010-04-24 10:26:22 -06001731 }
aliguori4b096fc2008-08-21 19:28:55 +00001732
David Ahern27911042010-04-24 10:26:22 -06001733 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001734 continue;
David Ahern27911042010-04-24 10:26:22 -06001735 }
aliguori4b096fc2008-08-21 19:28:55 +00001736
David Ahern27911042010-04-24 10:26:22 -06001737 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001738 continue;
David Ahern27911042010-04-24 10:26:22 -06001739 }
aliguori4b096fc2008-08-21 19:28:55 +00001740 /* We got a match */
1741
Markus Armbruster33e66b82009-10-07 01:15:57 +02001742 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001743 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001744 return 0;
David Ahern27911042010-04-24 10:26:22 -06001745 }
malcd0f2c4c2010-02-07 02:03:50 +03001746 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001747
Hans de Goede0f5160d2010-11-10 10:06:23 +01001748 usb_host_open(s, bus_num, addr, devpath, product_name);
aliguori4b096fc2008-08-21 19:28:55 +00001749 }
1750
1751 return 0;
1752}
1753
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001754static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001755{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001756 struct USBHostDevice *s;
1757 int unconnected = 0;
1758
aliguori4b096fc2008-08-21 19:28:55 +00001759 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001760
1761 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001762 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001763 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001764 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001765 }
1766
1767 if (unconnected == 0) {
1768 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001769 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001770 qemu_del_timer(usb_auto_timer);
David Ahern27911042010-04-24 10:26:22 -06001771 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001772 return;
1773 }
1774
1775 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001776 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001777 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001778 return;
David Ahern27911042010-04-24 10:26:22 -06001779 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001780 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001781 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001782}
1783
1784/*
aliguori5d0c5752008-09-14 01:07:41 +00001785 * Autoconnect filter
1786 * Format:
1787 * auto:bus:dev[:vid:pid]
1788 * auto:bus.dev[:vid:pid]
1789 *
1790 * bus - bus number (dec, * means any)
1791 * dev - device number (dec, * means any)
1792 * vid - vendor id (hex, * means any)
1793 * pid - product id (hex, * means any)
1794 *
1795 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001796 */
aliguori5d0c5752008-09-14 01:07:41 +00001797static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001798{
aliguori5d0c5752008-09-14 01:07:41 +00001799 enum { BUS, DEV, VID, PID, DONE };
1800 const char *p = spec;
1801 int i;
1802
Markus Armbruster0745eb12009-11-27 13:05:53 +01001803 f->bus_num = 0;
1804 f->addr = 0;
1805 f->vendor_id = 0;
1806 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001807
1808 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001809 p = strpbrk(p, ":.");
1810 if (!p) {
1811 break;
1812 }
aliguori5d0c5752008-09-14 01:07:41 +00001813 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001814
David Ahern27911042010-04-24 10:26:22 -06001815 if (*p == '*') {
1816 continue;
1817 }
aliguori5d0c5752008-09-14 01:07:41 +00001818 switch(i) {
1819 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1820 case DEV: f->addr = strtol(p, NULL, 10); break;
1821 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1822 case PID: f->product_id = strtol(p, NULL, 16); break;
1823 }
aliguori4b096fc2008-08-21 19:28:55 +00001824 }
1825
aliguori5d0c5752008-09-14 01:07:41 +00001826 if (i < DEV) {
1827 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1828 return -1;
1829 }
1830
1831 return 0;
1832}
1833
bellarda594cfb2005-11-06 16:13:29 +00001834/**********************/
1835/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001836
bellarda594cfb2005-11-06 16:13:29 +00001837struct usb_class_info {
1838 int class;
1839 const char *class_name;
1840};
1841
1842static const struct usb_class_info usb_class_info[] = {
1843 { USB_CLASS_AUDIO, "Audio"},
1844 { USB_CLASS_COMM, "Communication"},
1845 { USB_CLASS_HID, "HID"},
1846 { USB_CLASS_HUB, "Hub" },
1847 { USB_CLASS_PHYSICAL, "Physical" },
1848 { USB_CLASS_PRINTER, "Printer" },
1849 { USB_CLASS_MASS_STORAGE, "Storage" },
1850 { USB_CLASS_CDC_DATA, "Data" },
1851 { USB_CLASS_APP_SPEC, "Application Specific" },
1852 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1853 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001854 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001855 { USB_CLASS_CONTENT_SEC, "Content Security" },
1856 { -1, NULL }
1857};
1858
1859static const char *usb_class_str(uint8_t class)
1860{
1861 const struct usb_class_info *p;
1862 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001863 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001864 break;
David Ahern27911042010-04-24 10:26:22 -06001865 }
bellardbb36d472005-11-05 14:22:28 +00001866 }
bellarda594cfb2005-11-06 16:13:29 +00001867 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001868}
1869
Blue Swirl179da8a2009-09-07 19:00:18 +00001870static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
pbrook9596ebb2007-11-18 01:44:38 +00001871 int vendor_id, int product_id,
1872 const char *product_name,
1873 int speed)
bellardbb36d472005-11-05 14:22:28 +00001874{
bellarda594cfb2005-11-06 16:13:29 +00001875 const char *class_str, *speed_str;
1876
1877 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001878 case USB_SPEED_LOW:
1879 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001880 break;
ths5fafdf22007-09-16 21:08:06 +00001881 case USB_SPEED_FULL:
1882 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001883 break;
ths5fafdf22007-09-16 21:08:06 +00001884 case USB_SPEED_HIGH:
1885 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001886 break;
1887 default:
ths5fafdf22007-09-16 21:08:06 +00001888 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001889 break;
bellardbb36d472005-11-05 14:22:28 +00001890 }
bellarda594cfb2005-11-06 16:13:29 +00001891
aliguori376253e2009-03-05 23:01:23 +00001892 monitor_printf(mon, " Device %d.%d, speed %s Mb/s\n",
bellarda594cfb2005-11-06 16:13:29 +00001893 bus_num, addr, speed_str);
1894 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001895 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001896 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001897 } else {
aliguori376253e2009-03-05 23:01:23 +00001898 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001899 }
aliguori376253e2009-03-05 23:01:23 +00001900 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001901 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001902 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001903 }
aliguori376253e2009-03-05 23:01:23 +00001904 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001905}
1906
ths5fafdf22007-09-16 21:08:06 +00001907static int usb_host_info_device(void *opaque, int bus_num, int addr,
Hans de Goede0f5160d2010-11-10 10:06:23 +01001908 int devpath, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001909 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001910 const char *product_name,
1911 int speed)
1912{
Blue Swirl179da8a2009-09-07 19:00:18 +00001913 Monitor *mon = opaque;
1914
1915 usb_info_device(mon, bus_num, addr, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001916 product_name, speed);
1917 return 0;
1918}
1919
aliguoriac4ffb52008-09-22 15:04:31 +00001920static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001921{
David Ahern27911042010-04-24 10:26:22 -06001922 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001923 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001924 } else {
1925 snprintf(str, size, "%d", val);
1926 }
aliguori5d0c5752008-09-14 01:07:41 +00001927}
1928
aliguoriac4ffb52008-09-22 15:04:31 +00001929static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001930{
David Ahern27911042010-04-24 10:26:22 -06001931 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001932 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001933 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001934 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06001935 }
aliguori5d0c5752008-09-14 01:07:41 +00001936}
1937
aliguori376253e2009-03-05 23:01:23 +00001938void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00001939{
aliguori5d0c5752008-09-14 01:07:41 +00001940 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001941 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00001942
Blue Swirl179da8a2009-09-07 19:00:18 +00001943 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00001944
David Ahern27911042010-04-24 10:26:22 -06001945 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001946 return;
David Ahern27911042010-04-24 10:26:22 -06001947 }
1948
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001949 monitor_printf(mon, " Auto filters:\n");
1950 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00001951 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001952 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00001953 dec2str(f->bus_num, bus, sizeof(bus));
1954 dec2str(f->addr, addr, sizeof(addr));
1955 hex2str(f->vendor_id, vid, sizeof(vid));
1956 hex2str(f->product_id, pid, sizeof(pid));
aliguori376253e2009-03-05 23:01:23 +00001957 monitor_printf(mon, " Device %s.%s ID %s:%s\n",
1958 bus, addr, vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00001959 }
bellardbb36d472005-11-05 14:22:28 +00001960}