blob: 2c6e249bc75b6f79426f4ce351872ddbd3088152 [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
Gerd Hoffmann5557d822011-05-10 11:43:57 +020057typedef int USBScanFunc(void *opaque, int bus_num, int addr, char *port,
Hans de Goede0f5160d2010-11-10 10:06:23 +010058 int class_id, int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +000059 const char *product_name, int speed);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010060
Markus Armbruster0745eb12009-11-27 13:05:53 +010061//#define DEBUG
aliguori64838172008-08-21 19:31:10 +000062
63#ifdef DEBUG
malcd0f2c4c2010-02-07 02:03:50 +030064#define DPRINTF printf
aliguori64838172008-08-21 19:31:10 +000065#else
malcd0f2c4c2010-02-07 02:03:50 +030066#define DPRINTF(...)
aliguori64838172008-08-21 19:31:10 +000067#endif
bellardbb36d472005-11-05 14:22:28 +000068
blueswir15be8e1f2008-10-25 11:47:20 +000069#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
70
aliguori0f431522008-10-07 20:06:37 +000071#define USBPROCBUS_PATH "/proc/bus/usb"
bellard1f6e24e2006-06-26 21:00:51 +000072#define PRODUCT_NAME_SZ 32
Hans de Goede3a4854b2010-11-26 15:02:16 +010073#define MAX_ENDPOINTS 15
Gerd Hoffmann5557d822011-05-10 11:43:57 +020074#define MAX_PORTLEN 16
aliguori0f431522008-10-07 20:06:37 +000075#define USBDEVBUS_PATH "/dev/bus/usb"
76#define USBSYSBUS_PATH "/sys/bus/usb"
77
78static char *usb_host_device_path;
79
80#define USB_FS_NONE 0
81#define USB_FS_PROC 1
82#define USB_FS_DEV 2
83#define USB_FS_SYS 3
84
85static int usb_fs_type;
bellardbb36d472005-11-05 14:22:28 +000086
balrogb9dc0332007-10-04 22:47:34 +000087/* endpoint association data */
Hans de Goede060dc842010-11-26 11:41:08 +010088#define ISO_FRAME_DESC_PER_URB 32
89#define ISO_URB_COUNT 3
Hans de Goedea0b5fec2010-11-26 14:56:17 +010090#define INVALID_EP_TYPE 255
Hans de Goede060dc842010-11-26 11:41:08 +010091
92typedef struct AsyncURB AsyncURB;
93
balrogb9dc0332007-10-04 22:47:34 +000094struct endp_data {
95 uint8_t type;
aliguori64838172008-08-21 19:31:10 +000096 uint8_t halted;
Hans de Goedebb6d5492010-11-26 19:11:03 +010097 uint8_t iso_started;
Hans de Goede060dc842010-11-26 11:41:08 +010098 AsyncURB *iso_urb;
99 int iso_urb_idx;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100100 int iso_buffer_used;
Hans de Goede060dc842010-11-26 11:41:08 +0100101 int max_packet_size;
balrogb9dc0332007-10-04 22:47:34 +0000102};
103
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100104struct USBAutoFilter {
105 uint32_t bus_num;
106 uint32_t addr;
107 uint32_t vendor_id;
108 uint32_t product_id;
109};
110
bellardbb36d472005-11-05 14:22:28 +0000111typedef struct USBHostDevice {
112 USBDevice dev;
aliguori64838172008-08-21 19:31:10 +0000113 int fd;
114
115 uint8_t descr[1024];
116 int descr_len;
117 int configuration;
aliguori446ab122008-09-14 01:06:09 +0000118 int ninterfaces;
aliguori24772c12008-08-21 19:31:52 +0000119 int closing;
Shahar Havivib373a632010-06-16 15:16:11 +0300120 Notifier exit;
aliguori64838172008-08-21 19:31:10 +0000121
balrogb9dc0332007-10-04 22:47:34 +0000122 struct endp_data endp_table[MAX_ENDPOINTS];
aliguori4b096fc2008-08-21 19:28:55 +0000123
aliguori4b096fc2008-08-21 19:28:55 +0000124 /* Host side address */
125 int bus_num;
126 int addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200127 char port[MAX_PORTLEN];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100128 struct USBAutoFilter match;
aliguori4b096fc2008-08-21 19:28:55 +0000129
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100130 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000131} USBHostDevice;
132
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100133static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
134
135static int usb_host_close(USBHostDevice *dev);
136static int parse_filter(const char *spec, struct USBAutoFilter *f);
137static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100138static int usb_host_read_file(char *line, size_t line_size,
139 const char *device_file, const char *device_name);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100140
aliguori64838172008-08-21 19:31:10 +0000141static int is_isoc(USBHostDevice *s, int ep)
142{
143 return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO;
144}
145
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100146static int is_valid(USBHostDevice *s, int ep)
147{
148 return s->endp_table[ep - 1].type != INVALID_EP_TYPE;
149}
150
aliguori64838172008-08-21 19:31:10 +0000151static int is_halted(USBHostDevice *s, int ep)
152{
153 return s->endp_table[ep - 1].halted;
154}
155
156static void clear_halt(USBHostDevice *s, int ep)
157{
158 s->endp_table[ep - 1].halted = 0;
159}
160
161static void set_halt(USBHostDevice *s, int ep)
162{
163 s->endp_table[ep - 1].halted = 1;
164}
165
Hans de Goedebb6d5492010-11-26 19:11:03 +0100166static int is_iso_started(USBHostDevice *s, int ep)
167{
168 return s->endp_table[ep - 1].iso_started;
169}
170
171static void clear_iso_started(USBHostDevice *s, int ep)
172{
173 s->endp_table[ep - 1].iso_started = 0;
174}
175
176static void set_iso_started(USBHostDevice *s, int ep)
177{
178 s->endp_table[ep - 1].iso_started = 1;
179}
180
Hans de Goede060dc842010-11-26 11:41:08 +0100181static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
182{
183 s->endp_table[ep - 1].iso_urb = iso_urb;
184}
185
186static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
187{
188 return s->endp_table[ep - 1].iso_urb;
189}
190
191static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
192{
193 s->endp_table[ep - 1].iso_urb_idx = i;
194}
195
196static int get_iso_urb_idx(USBHostDevice *s, int ep)
197{
198 return s->endp_table[ep - 1].iso_urb_idx;
199}
200
Hans de Goedebb6d5492010-11-26 19:11:03 +0100201static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
202{
203 s->endp_table[ep - 1].iso_buffer_used = i;
204}
205
206static int get_iso_buffer_used(USBHostDevice *s, int ep)
207{
208 return s->endp_table[ep - 1].iso_buffer_used;
209}
210
Hans de Goede060dc842010-11-26 11:41:08 +0100211static int get_max_packet_size(USBHostDevice *s, int ep)
212{
213 return s->endp_table[ep - 1].max_packet_size;
214}
215
David Ahern27911042010-04-24 10:26:22 -0600216/*
aliguori64838172008-08-21 19:31:10 +0000217 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100218 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600219 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000220 */
Hans de Goede060dc842010-11-26 11:41:08 +0100221struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000222{
aliguori64838172008-08-21 19:31:10 +0000223 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100224 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
aliguori64838172008-08-21 19:31:10 +0000225
Hans de Goede060dc842010-11-26 11:41:08 +0100226 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000227 USBPacket *packet;
228 USBHostDevice *hdev;
Hans de Goede060dc842010-11-26 11:41:08 +0100229
230 /* For buffered iso handling */
231 int iso_frame_idx; /* -1 means in flight */
232};
aliguori64838172008-08-21 19:31:10 +0000233
234static AsyncURB *async_alloc(void)
235{
236 return (AsyncURB *) qemu_mallocz(sizeof(AsyncURB));
balrogb9dc0332007-10-04 22:47:34 +0000237}
238
aliguori64838172008-08-21 19:31:10 +0000239static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000240{
aliguori64838172008-08-21 19:31:10 +0000241 qemu_free(aurb);
242}
balrogb9dc0332007-10-04 22:47:34 +0000243
aliguori64838172008-08-21 19:31:10 +0000244static void async_complete(void *opaque)
245{
246 USBHostDevice *s = opaque;
247 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000248
aliguori64838172008-08-21 19:31:10 +0000249 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600250 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000251
David Ahern27911042010-04-24 10:26:22 -0600252 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000253 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600254 if (errno == EAGAIN) {
aliguori64838172008-08-21 19:31:10 +0000255 return;
David Ahern27911042010-04-24 10:26:22 -0600256 }
aliguori24772c12008-08-21 19:31:52 +0000257 if (errno == ENODEV && !s->closing) {
David Ahern27911042010-04-24 10:26:22 -0600258 printf("husb: device %d.%d disconnected\n",
259 s->bus_num, s->addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100260 usb_host_close(s);
261 usb_host_auto_check(NULL);
aliguori64838172008-08-21 19:31:10 +0000262 return;
263 }
264
malcd0f2c4c2010-02-07 02:03:50 +0300265 DPRINTF("husb: async. reap urb failed errno %d\n", errno);
aliguori64838172008-08-21 19:31:10 +0000266 return;
balrogb9dc0332007-10-04 22:47:34 +0000267 }
aliguori64838172008-08-21 19:31:10 +0000268
David Ahern27911042010-04-24 10:26:22 -0600269 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000270 aurb, aurb->urb.status, aurb->urb.actual_length);
271
Hans de Goede060dc842010-11-26 11:41:08 +0100272 /* If this is a buffered iso urb mark it as complete and don't do
273 anything else (it is handled further in usb_host_handle_iso_data) */
274 if (aurb->iso_frame_idx == -1) {
275 if (aurb->urb.status == -EPIPE) {
276 set_halt(s, aurb->urb.endpoint & 0xf);
277 }
278 aurb->iso_frame_idx = 0;
279 continue;
280 }
281
282 p = aurb->packet;
283
David Ahern27911042010-04-24 10:26:22 -0600284 if (p) {
aliguori64838172008-08-21 19:31:10 +0000285 switch (aurb->urb.status) {
286 case 0:
287 p->len = aurb->urb.actual_length;
288 break;
289
290 case -EPIPE:
291 set_halt(s, p->devep);
David Ahern27911042010-04-24 10:26:22 -0600292 p->len = USB_RET_STALL;
293 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200294
aliguori64838172008-08-21 19:31:10 +0000295 default:
296 p->len = USB_RET_NAK;
297 break;
298 }
299
Hans de Goede50b79632011-02-02 17:36:29 +0100300 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
301 usb_generic_async_ctrl_complete(&s->dev, p);
302 } else {
303 usb_packet_complete(&s->dev, p);
304 }
David Ahern27911042010-04-24 10:26:22 -0600305 }
aliguori64838172008-08-21 19:31:10 +0000306
307 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000308 }
balrogb9dc0332007-10-04 22:47:34 +0000309}
310
aliguori64838172008-08-21 19:31:10 +0000311static void async_cancel(USBPacket *unused, void *opaque)
balrogb9dc0332007-10-04 22:47:34 +0000312{
aliguori64838172008-08-21 19:31:10 +0000313 AsyncURB *aurb = opaque;
314 USBHostDevice *s = aurb->hdev;
balrogb9dc0332007-10-04 22:47:34 +0000315
malcd0f2c4c2010-02-07 02:03:50 +0300316 DPRINTF("husb: async cancel. aurb %p\n", aurb);
balrogb9dc0332007-10-04 22:47:34 +0000317
aliguori64838172008-08-21 19:31:10 +0000318 /* Mark it as dead (see async_complete above) */
319 aurb->packet = NULL;
320
321 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
322 if (r < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300323 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
balrogb9dc0332007-10-04 22:47:34 +0000324 }
balrogb9dc0332007-10-04 22:47:34 +0000325}
326
aliguori446ab122008-09-14 01:06:09 +0000327static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000328{
329 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000330 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000331 int ret, i;
332
333 if (configuration == 0) /* address state - ignore */
334 return 1;
335
malcd0f2c4c2010-02-07 02:03:50 +0300336 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000337
balrogb9dc0332007-10-04 22:47:34 +0000338 i = 0;
339 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600340 if (dev_descr_len > dev->descr_len) {
balrogb9dc0332007-10-04 22:47:34 +0000341 goto fail;
David Ahern27911042010-04-24 10:26:22 -0600342 }
balrogb9dc0332007-10-04 22:47:34 +0000343
344 i += dev_descr_len;
345 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600346 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
347 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000348 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000349
balrogb9dc0332007-10-04 22:47:34 +0000350 if (dev->descr[i+1] != USB_DT_CONFIG) {
351 i += dev->descr[i];
352 continue;
353 }
354 config_descr_len = dev->descr[i];
355
David Ahern27911042010-04-24 10:26:22 -0600356 printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000357
aliguori446ab122008-09-14 01:06:09 +0000358 if (configuration < 0 || configuration == dev->descr[i + 5]) {
359 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000360 break;
aliguori446ab122008-09-14 01:06:09 +0000361 }
balrogb9dc0332007-10-04 22:47:34 +0000362
363 i += config_descr_len;
364 }
365
366 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600367 fprintf(stderr,
368 "husb: update iface failed. no matching configuration\n");
balrogb9dc0332007-10-04 22:47:34 +0000369 goto fail;
370 }
371 nb_interfaces = dev->descr[i + 4];
372
373#ifdef USBDEVFS_DISCONNECT
374 /* earlier Linux 2.4 do not support that */
375 {
376 struct usbdevfs_ioctl ctrl;
377 for (interface = 0; interface < nb_interfaces; interface++) {
378 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
379 ctrl.ifno = interface;
Brad Hards021730f2011-04-13 19:45:32 +1000380 ctrl.data = 0;
balrogb9dc0332007-10-04 22:47:34 +0000381 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
382 if (ret < 0 && errno != ENODATA) {
383 perror("USBDEVFS_DISCONNECT");
384 goto fail;
385 }
386 }
387 }
388#endif
389
390 /* XXX: only grab if all interfaces are free */
391 for (interface = 0; interface < nb_interfaces; interface++) {
392 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
393 if (ret < 0) {
394 if (errno == EBUSY) {
aliguori64838172008-08-21 19:31:10 +0000395 printf("husb: update iface. device already grabbed\n");
balrogb9dc0332007-10-04 22:47:34 +0000396 } else {
aliguori64838172008-08-21 19:31:10 +0000397 perror("husb: failed to claim interface");
balrogb9dc0332007-10-04 22:47:34 +0000398 }
399 fail:
400 return 0;
401 }
402 }
403
aliguori64838172008-08-21 19:31:10 +0000404 printf("husb: %d interfaces claimed for configuration %d\n",
balrogb9dc0332007-10-04 22:47:34 +0000405 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000406
aliguori446ab122008-09-14 01:06:09 +0000407 dev->ninterfaces = nb_interfaces;
408 dev->configuration = configuration;
409 return 1;
410}
411
412static int usb_host_release_interfaces(USBHostDevice *s)
413{
414 int ret, i;
415
malcd0f2c4c2010-02-07 02:03:50 +0300416 DPRINTF("husb: releasing interfaces\n");
aliguori446ab122008-09-14 01:06:09 +0000417
418 for (i = 0; i < s->ninterfaces; i++) {
419 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
420 if (ret < 0) {
421 perror("husb: failed to release interface");
422 return 0;
423 }
424 }
425
balrogb9dc0332007-10-04 22:47:34 +0000426 return 1;
427}
428
bellard059809e2006-07-19 18:06:15 +0000429static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000430{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100431 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000432
malcd0f2c4c2010-02-07 02:03:50 +0300433 DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000434
bellardbb36d472005-11-05 14:22:28 +0000435 ioctl(s->fd, USBDEVFS_RESET);
aliguori446ab122008-09-14 01:06:09 +0000436
437 usb_host_claim_interfaces(s, s->configuration);
ths5fafdf22007-09-16 21:08:06 +0000438}
bellardbb36d472005-11-05 14:22:28 +0000439
bellard059809e2006-07-19 18:06:15 +0000440static void usb_host_handle_destroy(USBDevice *dev)
441{
442 USBHostDevice *s = (USBHostDevice *)dev;
443
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100444 usb_host_close(s);
445 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300446 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000447}
448
balrogb9dc0332007-10-04 22:47:34 +0000449static int usb_linux_update_endp_table(USBHostDevice *s);
450
Hans de Goede060dc842010-11-26 11:41:08 +0100451/* iso data is special, we need to keep enough urbs in flight to make sure
452 that the controller never runs out of them, otherwise the device will
453 likely suffer a buffer underrun / overrun. */
454static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
455{
456 AsyncURB *aurb;
457 int i, j, len = get_max_packet_size(s, ep);
458
459 aurb = qemu_mallocz(ISO_URB_COUNT * sizeof(*aurb));
460 for (i = 0; i < ISO_URB_COUNT; i++) {
461 aurb[i].urb.endpoint = ep;
462 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
463 aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length);
464 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
465 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
466 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
467 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
468 aurb[i].urb.iso_frame_desc[j].length = len;
469 if (in) {
470 aurb[i].urb.endpoint |= 0x80;
471 /* Mark as fully consumed (idle) */
472 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
473 }
474 }
475 set_iso_urb(s, ep, aurb);
476
477 return aurb;
478}
479
480static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
481{
482 AsyncURB *aurb;
483 int i, ret, killed = 0, free = 1;
484
485 aurb = get_iso_urb(s, ep);
486 if (!aurb) {
487 return;
488 }
489
490 for (i = 0; i < ISO_URB_COUNT; i++) {
491 /* in flight? */
492 if (aurb[i].iso_frame_idx == -1) {
493 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
494 if (ret < 0) {
495 printf("husb: discard isoc in urb failed errno %d\n", errno);
496 free = 0;
497 continue;
498 }
499 killed++;
500 }
501 }
502
503 /* Make sure any urbs we've killed are reaped before we free them */
504 if (killed) {
505 async_complete(s);
506 }
507
508 for (i = 0; i < ISO_URB_COUNT; i++) {
509 qemu_free(aurb[i].urb.buffer);
510 }
511
512 if (free)
513 qemu_free(aurb);
514 else
515 printf("husb: leaking iso urbs because of discard failure\n");
516 set_iso_urb(s, ep, NULL);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100517 set_iso_urb_idx(s, ep, 0);
518 clear_iso_started(s, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100519}
520
521static int urb_status_to_usb_ret(int status)
522{
523 switch (status) {
524 case -EPIPE:
525 return USB_RET_STALL;
526 default:
527 return USB_RET_NAK;
528 }
529}
530
Hans de Goedebb6d5492010-11-26 19:11:03 +0100531static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100532{
533 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100534 int i, j, ret, max_packet_size, offset, len = 0;
Hans de Goede975f2992010-11-26 14:59:35 +0100535
536 max_packet_size = get_max_packet_size(s, p->devep);
537 if (max_packet_size == 0)
538 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100539
540 aurb = get_iso_urb(s, p->devep);
541 if (!aurb) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100542 aurb = usb_host_alloc_iso(s, p->devep, in);
Hans de Goede060dc842010-11-26 11:41:08 +0100543 }
544
545 i = get_iso_urb_idx(s, p->devep);
546 j = aurb[i].iso_frame_idx;
547 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100548 if (in) {
549 /* Check urb status */
550 if (aurb[i].urb.status) {
551 len = urb_status_to_usb_ret(aurb[i].urb.status);
552 /* Move to the next urb */
553 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
554 /* Check frame status */
555 } else if (aurb[i].urb.iso_frame_desc[j].status) {
556 len = urb_status_to_usb_ret(
557 aurb[i].urb.iso_frame_desc[j].status);
558 /* Check the frame fits */
559 } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
560 printf("husb: received iso data is larger then packet\n");
561 len = USB_RET_NAK;
562 /* All good copy data over */
563 } else {
564 len = aurb[i].urb.iso_frame_desc[j].actual_length;
565 memcpy(p->data,
566 aurb[i].urb.buffer +
567 j * aurb[i].urb.iso_frame_desc[0].length,
568 len);
569 }
Hans de Goede060dc842010-11-26 11:41:08 +0100570 } else {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100571 len = p->len;
572 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
573
574 /* Check the frame fits */
575 if (len > max_packet_size) {
576 printf("husb: send iso data is larger then max packet size\n");
577 return USB_RET_NAK;
578 }
579
580 /* All good copy data over */
581 memcpy(aurb[i].urb.buffer + offset, p->data, len);
582 aurb[i].urb.iso_frame_desc[j].length = len;
583 offset += len;
584 set_iso_buffer_used(s, p->devep, offset);
585
586 /* Start the stream once we have buffered enough data */
587 if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
588 set_iso_started(s, p->devep);
589 }
Hans de Goede060dc842010-11-26 11:41:08 +0100590 }
591 aurb[i].iso_frame_idx++;
592 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
593 i = (i + 1) % ISO_URB_COUNT;
594 set_iso_urb_idx(s, p->devep, i);
595 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100596 } else {
597 if (in) {
598 set_iso_started(s, p->devep);
599 } else {
600 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
601 }
Hans de Goede060dc842010-11-26 11:41:08 +0100602 }
603
Hans de Goedebb6d5492010-11-26 19:11:03 +0100604 if (is_iso_started(s, p->devep)) {
605 /* (Re)-submit all fully consumed / filled urbs */
606 for (i = 0; i < ISO_URB_COUNT; i++) {
607 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
608 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
609 if (ret < 0) {
610 printf("husb error submitting iso urb %d: %d\n", i, errno);
611 if (!in || len == 0) {
612 switch(errno) {
613 case ETIMEDOUT:
614 len = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200615 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100616 case EPIPE:
617 default:
618 len = USB_RET_STALL;
619 }
Hans de Goede060dc842010-11-26 11:41:08 +0100620 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100621 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100622 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100623 aurb[i].iso_frame_idx = -1;
Hans de Goede060dc842010-11-26 11:41:08 +0100624 }
Hans de Goede060dc842010-11-26 11:41:08 +0100625 }
626 }
627
628 return len;
629}
630
Hans de Goede50b79632011-02-02 17:36:29 +0100631static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000632{
Hans de Goede50b79632011-02-02 17:36:29 +0100633 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000634 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000635 AsyncURB *aurb;
bellardbb36d472005-11-05 14:22:28 +0000636 int ret;
Hans de Goede060dc842010-11-26 11:41:08 +0100637 uint8_t ep;
638
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100639 if (!is_valid(s, p->devep)) {
640 return USB_RET_NAK;
641 }
642
Hans de Goede060dc842010-11-26 11:41:08 +0100643 if (p->pid == USB_TOKEN_IN) {
644 ep = p->devep | 0x80;
645 } else {
646 ep = p->devep;
647 }
648
649 if (is_halted(s, p->devep)) {
650 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
651 if (ret < 0) {
652 DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
653 ep, errno);
654 return USB_RET_NAK;
655 }
656 clear_halt(s, p->devep);
657 }
658
Hans de Goedebb6d5492010-11-26 19:11:03 +0100659 if (is_isoc(s, p->devep)) {
660 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
661 }
bellardbb36d472005-11-05 14:22:28 +0000662
aliguori64838172008-08-21 19:31:10 +0000663 aurb = async_alloc();
aliguori64838172008-08-21 19:31:10 +0000664 aurb->hdev = s;
665 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000666
aliguori64838172008-08-21 19:31:10 +0000667 urb = &aurb->urb;
668
Hans de Goede060dc842010-11-26 11:41:08 +0100669 urb->endpoint = ep;
aliguori64838172008-08-21 19:31:10 +0000670 urb->buffer = p->data;
balrogb9dc0332007-10-04 22:47:34 +0000671 urb->buffer_length = p->len;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100672 urb->type = USBDEVFS_URB_TYPE_BULK;
673 urb->usercontext = s;
aliguori64838172008-08-21 19:31:10 +0000674
675 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
676
David Ahern27911042010-04-24 10:26:22 -0600677 DPRINTF("husb: data submit. ep 0x%x len %u aurb %p\n",
678 urb->endpoint, p->len, aurb);
aliguori64838172008-08-21 19:31:10 +0000679
680 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300681 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori64838172008-08-21 19:31:10 +0000682 async_free(aurb);
683
balrogb9dc0332007-10-04 22:47:34 +0000684 switch(errno) {
685 case ETIMEDOUT:
686 return USB_RET_NAK;
687 case EPIPE:
688 default:
689 return USB_RET_STALL;
690 }
691 }
aliguori64838172008-08-21 19:31:10 +0000692
693 usb_defer_packet(p, async_cancel, aurb);
balrogb9dc0332007-10-04 22:47:34 +0000694 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000695}
696
aliguori446ab122008-09-14 01:06:09 +0000697static int ctrl_error(void)
698{
David Ahern27911042010-04-24 10:26:22 -0600699 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000700 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600701 } else {
aliguori446ab122008-09-14 01:06:09 +0000702 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600703 }
aliguori446ab122008-09-14 01:06:09 +0000704}
705
706static int usb_host_set_address(USBHostDevice *s, int addr)
707{
malcd0f2c4c2010-02-07 02:03:50 +0300708 DPRINTF("husb: ctrl set addr %u\n", addr);
aliguori446ab122008-09-14 01:06:09 +0000709 s->dev.addr = addr;
710 return 0;
711}
712
713static int usb_host_set_config(USBHostDevice *s, int config)
714{
715 usb_host_release_interfaces(s);
716
717 int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600718
malcd0f2c4c2010-02-07 02:03:50 +0300719 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600720
721 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000722 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600723 }
aliguori446ab122008-09-14 01:06:09 +0000724 usb_host_claim_interfaces(s, config);
725 return 0;
726}
727
728static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
729{
730 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100731 int i, ret;
732
Hans de Goede3a4854b2010-11-26 15:02:16 +0100733 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100734 if (is_isoc(s, i)) {
735 usb_host_stop_n_free_iso(s, i);
736 }
737 }
aliguori446ab122008-09-14 01:06:09 +0000738
739 si.interface = iface;
740 si.altsetting = alt;
741 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000742
David Ahern27911042010-04-24 10:26:22 -0600743 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
744 iface, alt, ret, errno);
745
746 if (ret < 0) {
747 return ctrl_error();
748 }
aliguori446ab122008-09-14 01:06:09 +0000749 usb_linux_update_endp_table(s);
750 return 0;
751}
752
Hans de Goede50b79632011-02-02 17:36:29 +0100753static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
754 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +0000755{
Hans de Goede50b79632011-02-02 17:36:29 +0100756 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +0000757 struct usbdevfs_urb *urb;
758 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +0100759 int ret;
aliguori446ab122008-09-14 01:06:09 +0000760
David Ahern27911042010-04-24 10:26:22 -0600761 /*
aliguori446ab122008-09-14 01:06:09 +0000762 * Process certain standard device requests.
763 * These are infrequent and are processed synchronously.
764 */
aliguori446ab122008-09-14 01:06:09 +0000765
Hans de Goede50b79632011-02-02 17:36:29 +0100766 /* Note request is (bRequestType << 8) | bRequest */
malcd0f2c4c2010-02-07 02:03:50 +0300767 DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
Hans de Goede50b79632011-02-02 17:36:29 +0100768 request >> 8, request & 0xff, value, index, length);
aliguori446ab122008-09-14 01:06:09 +0000769
Hans de Goede50b79632011-02-02 17:36:29 +0100770 switch (request) {
771 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
772 return usb_host_set_address(s, value);
aliguori446ab122008-09-14 01:06:09 +0000773
Hans de Goede50b79632011-02-02 17:36:29 +0100774 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
775 return usb_host_set_config(s, value & 0xff);
aliguori446ab122008-09-14 01:06:09 +0000776
Hans de Goede50b79632011-02-02 17:36:29 +0100777 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
aliguori446ab122008-09-14 01:06:09 +0000778 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -0600779 }
aliguori446ab122008-09-14 01:06:09 +0000780
781 /* The rest are asynchronous */
782
Hans de Goede50b79632011-02-02 17:36:29 +0100783 if (length > sizeof(dev->data_buf)) {
784 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
785 length, sizeof(dev->data_buf));
malcb2e3b6e2009-09-12 03:18:18 +0400786 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -0400787 }
788
aliguori446ab122008-09-14 01:06:09 +0000789 aurb = async_alloc();
aliguori446ab122008-09-14 01:06:09 +0000790 aurb->hdev = s;
791 aurb->packet = p;
792
David Ahern27911042010-04-24 10:26:22 -0600793 /*
aliguori446ab122008-09-14 01:06:09 +0000794 * Setup ctrl transfer.
795 *
Brad Hardsa0102082011-04-13 19:45:33 +1000796 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +0000797 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -0600798 */
aliguori446ab122008-09-14 01:06:09 +0000799 urb = &aurb->urb;
800
801 urb->type = USBDEVFS_URB_TYPE_CONTROL;
802 urb->endpoint = p->devep;
803
Hans de Goede50b79632011-02-02 17:36:29 +0100804 urb->buffer = &dev->setup_buf;
805 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +0000806
807 urb->usercontext = s;
808
809 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
810
malcd0f2c4c2010-02-07 02:03:50 +0300811 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +0000812
813 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300814 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +0000815 async_free(aurb);
816
817 switch(errno) {
818 case ETIMEDOUT:
819 return USB_RET_NAK;
820 case EPIPE:
821 default:
822 return USB_RET_STALL;
823 }
824 }
825
826 usb_defer_packet(p, async_cancel, aurb);
827 return USB_RET_ASYNC;
828}
829
Hans de Goede71d71bb2010-11-10 10:06:24 +0100830static int usb_linux_get_configuration(USBHostDevice *s)
balrogb9dc0332007-10-04 22:47:34 +0000831{
Hans de Goede71d71bb2010-11-10 10:06:24 +0100832 uint8_t configuration;
pbrooke41b3912008-10-28 18:22:59 +0000833 struct usb_ctrltransfer ct;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100834 int ret;
balrogb9dc0332007-10-04 22:47:34 +0000835
Hans de Goede2cc59d82010-11-10 10:06:25 +0100836 if (usb_fs_type == USB_FS_SYS) {
837 char device_name[32], line[1024];
838 int configuration;
839
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200840 sprintf(device_name, "%d-%s", s->bus_num, s->port);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100841
842 if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
843 device_name)) {
844 goto usbdevfs;
845 }
846 if (sscanf(line, "%d", &configuration) != 1) {
847 goto usbdevfs;
848 }
849 return configuration;
850 }
851
852usbdevfs:
balrogb9dc0332007-10-04 22:47:34 +0000853 ct.bRequestType = USB_DIR_IN;
854 ct.bRequest = USB_REQ_GET_CONFIGURATION;
855 ct.wValue = 0;
856 ct.wIndex = 0;
857 ct.wLength = 1;
858 ct.data = &configuration;
859 ct.timeout = 50;
860
861 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
862 if (ret < 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100863 perror("usb_linux_get_configuration");
864 return -1;
balrogb9dc0332007-10-04 22:47:34 +0000865 }
866
867 /* in address state */
David Ahern27911042010-04-24 10:26:22 -0600868 if (configuration == 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100869 return -1;
David Ahern27911042010-04-24 10:26:22 -0600870 }
balrogb9dc0332007-10-04 22:47:34 +0000871
Hans de Goede71d71bb2010-11-10 10:06:24 +0100872 return configuration;
873}
874
Hans de Goedeed3a3282010-11-24 12:50:00 +0100875static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
876 uint8_t configuration, uint8_t interface)
877{
878 uint8_t alt_setting;
879 struct usb_ctrltransfer ct;
880 int ret;
881
Hans de Goedec43831f2010-11-24 12:57:59 +0100882 if (usb_fs_type == USB_FS_SYS) {
883 char device_name[64], line[1024];
884 int alt_setting;
885
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200886 sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
Hans de Goedec43831f2010-11-24 12:57:59 +0100887 (int)configuration, (int)interface);
888
889 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
890 device_name)) {
891 goto usbdevfs;
892 }
893 if (sscanf(line, "%d", &alt_setting) != 1) {
894 goto usbdevfs;
895 }
896 return alt_setting;
897 }
898
899usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +0100900 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
901 ct.bRequest = USB_REQ_GET_INTERFACE;
902 ct.wValue = 0;
903 ct.wIndex = interface;
904 ct.wLength = 1;
905 ct.data = &alt_setting;
906 ct.timeout = 50;
907 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
908 if (ret < 0) {
909 /* Assume alt 0 on error */
910 return 0;
911 }
912
913 return alt_setting;
914}
915
Hans de Goede71d71bb2010-11-10 10:06:24 +0100916/* returns 1 on problem encountered or 0 for success */
917static int usb_linux_update_endp_table(USBHostDevice *s)
918{
919 uint8_t *descriptors;
920 uint8_t devep, type, configuration, alt_interface;
Hans de Goedeed3a3282010-11-24 12:50:00 +0100921 int interface, length, i;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100922
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100923 for (i = 0; i < MAX_ENDPOINTS; i++)
924 s->endp_table[i].type = INVALID_EP_TYPE;
925
Hans de Goede71d71bb2010-11-10 10:06:24 +0100926 i = usb_linux_get_configuration(s);
927 if (i < 0)
928 return 1;
929 configuration = i;
930
balrogb9dc0332007-10-04 22:47:34 +0000931 /* get the desired configuration, interface, and endpoint descriptors
932 * from device description */
933 descriptors = &s->descr[18];
934 length = s->descr_len - 18;
935 i = 0;
936
937 if (descriptors[i + 1] != USB_DT_CONFIG ||
938 descriptors[i + 5] != configuration) {
malcd0f2c4c2010-02-07 02:03:50 +0300939 DPRINTF("invalid descriptor data - configuration\n");
balrogb9dc0332007-10-04 22:47:34 +0000940 return 1;
941 }
942 i += descriptors[i];
943
944 while (i < length) {
945 if (descriptors[i + 1] != USB_DT_INTERFACE ||
946 (descriptors[i + 1] == USB_DT_INTERFACE &&
947 descriptors[i + 4] == 0)) {
948 i += descriptors[i];
949 continue;
950 }
951
952 interface = descriptors[i + 2];
Hans de Goedeed3a3282010-11-24 12:50:00 +0100953 alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
balrogb9dc0332007-10-04 22:47:34 +0000954
955 /* the current interface descriptor is the active interface
956 * and has endpoints */
957 if (descriptors[i + 3] != alt_interface) {
958 i += descriptors[i];
959 continue;
960 }
961
962 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -0600963 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +0000964 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -0600965 }
balrogb9dc0332007-10-04 22:47:34 +0000966
967 if (i >= length)
968 break;
969
970 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -0600971 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +0000972 break;
David Ahern27911042010-04-24 10:26:22 -0600973 }
balrogb9dc0332007-10-04 22:47:34 +0000974
975 devep = descriptors[i + 2];
976 switch (descriptors[i + 3] & 0x3) {
977 case 0x00:
978 type = USBDEVFS_URB_TYPE_CONTROL;
979 break;
980 case 0x01:
981 type = USBDEVFS_URB_TYPE_ISO;
Hans de Goede060dc842010-11-26 11:41:08 +0100982 s->endp_table[(devep & 0xf) - 1].max_packet_size =
983 descriptors[i + 4] + (descriptors[i + 5] << 8);
balrogb9dc0332007-10-04 22:47:34 +0000984 break;
985 case 0x02:
986 type = USBDEVFS_URB_TYPE_BULK;
987 break;
988 case 0x03:
989 type = USBDEVFS_URB_TYPE_INTERRUPT;
990 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -0500991 default:
992 DPRINTF("usb_host: malformed endpoint type\n");
993 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +0000994 }
995 s->endp_table[(devep & 0xf) - 1].type = type;
aliguori64838172008-08-21 19:31:10 +0000996 s->endp_table[(devep & 0xf) - 1].halted = 0;
balrogb9dc0332007-10-04 22:47:34 +0000997
998 i += descriptors[i];
999 }
1000 }
1001 return 0;
1002}
1003
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001004static int usb_host_open(USBHostDevice *dev, int bus_num,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001005 int addr, char *port, const char *prod_name)
bellardbb36d472005-11-05 14:22:28 +00001006{
balrogb9dc0332007-10-04 22:47:34 +00001007 int fd = -1, ret;
bellardbb36d472005-11-05 14:22:28 +00001008 struct usbdevfs_connectinfo ci;
bellarda594cfb2005-11-06 16:13:29 +00001009 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001010
David Ahern27911042010-04-24 10:26:22 -06001011 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001012 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001013 }
aliguori64838172008-08-21 19:31:10 +00001014 printf("husb: open device %d.%d\n", bus_num, addr);
aliguori1f3870a2008-08-21 19:27:48 +00001015
aliguori0f431522008-10-07 20:06:37 +00001016 if (!usb_host_device_path) {
1017 perror("husb: USB Host Device Path not set");
1018 goto fail;
1019 }
1020 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001021 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001022 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001023 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001024 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001025 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001026 }
malcd0f2c4c2010-02-07 02:03:50 +03001027 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001028
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001029 dev->bus_num = bus_num;
1030 dev->addr = addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001031 strcpy(dev->port, port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001032 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001033
balrogb9dc0332007-10-04 22:47:34 +00001034 /* read the device description */
1035 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1036 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001037 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001038 goto fail;
1039 }
ths3b46e622007-09-17 08:09:54 +00001040
balrogb9dc0332007-10-04 22:47:34 +00001041#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001042 {
balrogb9dc0332007-10-04 22:47:34 +00001043 int x;
1044 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001045 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001046 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001047 }
balrogb9dc0332007-10-04 22:47:34 +00001048 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001049 }
1050#endif
1051
balrogb9dc0332007-10-04 22:47:34 +00001052
David Ahern27911042010-04-24 10:26:22 -06001053 /*
1054 * Initial configuration is -1 which makes us claim first
aliguori446ab122008-09-14 01:06:09 +00001055 * available config. We used to start with 1, which does not
David Ahern27911042010-04-24 10:26:22 -06001056 * always work. I've seen devices where first config starts
aliguori446ab122008-09-14 01:06:09 +00001057 * with 2.
1058 */
David Ahern27911042010-04-24 10:26:22 -06001059 if (!usb_host_claim_interfaces(dev, -1)) {
balrogb9dc0332007-10-04 22:47:34 +00001060 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001061 }
bellardbb36d472005-11-05 14:22:28 +00001062
1063 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1064 if (ret < 0) {
balrog046833e2007-10-31 00:27:50 +00001065 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
bellardbb36d472005-11-05 14:22:28 +00001066 goto fail;
1067 }
1068
aliguori64838172008-08-21 19:31:10 +00001069 printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001070
balrogb9dc0332007-10-04 22:47:34 +00001071 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001072 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001073 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001074 }
balrogb9dc0332007-10-04 22:47:34 +00001075
David Ahern27911042010-04-24 10:26:22 -06001076 if (ci.slow) {
bellardbb36d472005-11-05 14:22:28 +00001077 dev->dev.speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001078 } else {
bellardbb36d472005-11-05 14:22:28 +00001079 dev->dev.speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001080 }
bellardbb36d472005-11-05 14:22:28 +00001081
David Ahern27911042010-04-24 10:26:22 -06001082 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001083 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001084 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001085 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001086 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001087 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001088 }
bellard1f6e24e2006-06-26 21:00:51 +00001089
aliguori64838172008-08-21 19:31:10 +00001090 /* USB devio uses 'write' flag to check for async completions */
1091 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001092
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001093 usb_device_attach(&dev->dev);
1094 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001095
balrogb9dc0332007-10-04 22:47:34 +00001096fail:
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001097 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001098 if (fd != -1) {
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001099 close(fd);
David Ahern27911042010-04-24 10:26:22 -06001100 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001101 return -1;
1102}
1103
1104static int usb_host_close(USBHostDevice *dev)
1105{
Hans de Goede060dc842010-11-26 11:41:08 +01001106 int i;
1107
David Ahern27911042010-04-24 10:26:22 -06001108 if (dev->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001109 return -1;
David Ahern27911042010-04-24 10:26:22 -06001110 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001111
1112 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1113 dev->closing = 1;
Hans de Goede3a4854b2010-11-26 15:02:16 +01001114 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +01001115 if (is_isoc(dev, i)) {
1116 usb_host_stop_n_free_iso(dev, i);
1117 }
1118 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001119 async_complete(dev);
1120 dev->closing = 0;
1121 usb_device_detach(&dev->dev);
Shahar Havivi00ff2272010-06-16 15:15:37 +03001122 ioctl(dev->fd, USBDEVFS_RESET);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001123 close(dev->fd);
1124 dev->fd = -1;
1125 return 0;
1126}
1127
Shahar Havivib373a632010-06-16 15:16:11 +03001128static void usb_host_exit_notifier(struct Notifier* n)
1129{
1130 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1131
1132 if (s->fd != -1) {
1133 ioctl(s->fd, USBDEVFS_RESET);
1134 }
1135}
1136
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001137static int usb_host_initfn(USBDevice *dev)
1138{
1139 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1140
1141 dev->auto_attach = 0;
1142 s->fd = -1;
1143 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001144 s->exit.notify = usb_host_exit_notifier;
1145 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001146 usb_host_auto_check(NULL);
1147 return 0;
bellardbb36d472005-11-05 14:22:28 +00001148}
1149
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001150static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001151 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001152 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001153 .qdev.size = sizeof(USBHostDevice),
1154 .init = usb_host_initfn,
Hans de Goede50b79632011-02-02 17:36:29 +01001155 .handle_packet = usb_generic_handle_packet,
1156 .handle_data = usb_host_handle_data,
1157 .handle_control = usb_host_handle_control,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001158 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001159 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001160 .usbdevice_name = "host",
1161 .usbdevice_init = usb_host_device_open,
1162 .qdev.props = (Property[]) {
1163 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1164 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
1165 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1166 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
1167 DEFINE_PROP_END_OF_LIST(),
1168 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001169};
1170
1171static void usb_host_register_devices(void)
1172{
1173 usb_qdev_register(&usb_host_dev_info);
1174}
1175device_init(usb_host_register_devices)
1176
aliguori4b096fc2008-08-21 19:28:55 +00001177USBDevice *usb_host_device_open(const char *devname)
1178{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001179 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001180 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001181 char *p;
1182
Markus Armbruster556cd092009-12-09 17:07:53 +01001183 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001184
aliguori5d0c5752008-09-14 01:07:41 +00001185 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001186 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001187 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001188 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001189 } else {
1190 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001191 filter.bus_num = strtoul(devname, NULL, 0);
1192 filter.addr = strtoul(p + 1, NULL, 0);
1193 filter.vendor_id = 0;
1194 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001195 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001196 filter.bus_num = 0;
1197 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001198 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001199 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001200 } else {
1201 goto fail;
1202 }
aliguori5d0c5752008-09-14 01:07:41 +00001203 }
1204
Markus Armbruster0745eb12009-11-27 13:05:53 +01001205 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1206 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001207 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1208 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001209 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001210 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001211
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001212fail:
1213 qdev_free(&dev->qdev);
1214 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001215}
aliguori5d0c5752008-09-14 01:07:41 +00001216
1217int usb_host_device_close(const char *devname)
1218{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001219#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001220 char product_name[PRODUCT_NAME_SZ];
1221 int bus_num, addr;
1222 USBHostDevice *s;
1223
David Ahern27911042010-04-24 10:26:22 -06001224 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001225 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001226 }
1227 if (usb_host_find_device(&bus_num, &addr, product_name,
1228 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001229 return -1;
David Ahern27911042010-04-24 10:26:22 -06001230 }
aliguori5d0c5752008-09-14 01:07:41 +00001231 s = hostdev_find(bus_num, addr);
1232 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001233 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001234 return 0;
1235 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001236#endif
aliguori5d0c5752008-09-14 01:07:41 +00001237
1238 return -1;
1239}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001240
bellarda594cfb2005-11-06 16:13:29 +00001241static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001242 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001243 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001244{
bellarda594cfb2005-11-06 16:13:29 +00001245 const char *p;
1246 char *q;
1247 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001248 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001249 return -1;
David Ahern27911042010-04-24 10:26:22 -06001250 }
bellarda594cfb2005-11-06 16:13:29 +00001251 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001252 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001253 p++;
David Ahern27911042010-04-24 10:26:22 -06001254 }
bellarda594cfb2005-11-06 16:13:29 +00001255 q = buf;
1256 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001257 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001258 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001259 }
bellarda594cfb2005-11-06 16:13:29 +00001260 p++;
1261 }
1262 *q = '\0';
1263 return q - buf;
1264}
bellardbb36d472005-11-05 14:22:28 +00001265
aliguori0f431522008-10-07 20:06:37 +00001266/*
1267 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1268 * host's USB devices. This is legacy support since many distributions
1269 * are moving to /sys/bus/usb
1270 */
1271static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001272{
Blue Swirl660f11b2009-07-31 21:16:51 +00001273 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001274 char line[1024];
1275 char buf[1024];
1276 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
bellarda594cfb2005-11-06 16:13:29 +00001277 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001278 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001279
aliguori0f431522008-10-07 20:06:37 +00001280 if (!usb_host_device_path) {
1281 perror("husb: USB Host Device Path not set");
1282 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001283 }
aliguori0f431522008-10-07 20:06:37 +00001284 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1285 f = fopen(line, "r");
1286 if (!f) {
1287 perror("husb: cannot open devices file");
1288 goto the_end;
1289 }
1290
bellarda594cfb2005-11-06 16:13:29 +00001291 device_count = 0;
1292 bus_num = addr = speed = class_id = product_id = vendor_id = 0;
bellardbb36d472005-11-05 14:22:28 +00001293 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001294 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001295 break;
David Ahern27911042010-04-24 10:26:22 -06001296 }
1297 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001298 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001299 }
bellarda594cfb2005-11-06 16:13:29 +00001300 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001301 if (device_count && (vendor_id || product_id)) {
1302 /* New device. Add the previously discovered device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001303 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001304 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001305 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001306 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001307 }
bellarda594cfb2005-11-06 16:13:29 +00001308 }
David Ahern27911042010-04-24 10:26:22 -06001309 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001310 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001311 }
bellarda594cfb2005-11-06 16:13:29 +00001312 bus_num = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001313 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001314 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001315 }
bellarda594cfb2005-11-06 16:13:29 +00001316 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001317 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001318 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001319 }
1320 if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001321 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001322 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001323 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001324 } else {
bellarda594cfb2005-11-06 16:13:29 +00001325 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001326 }
bellarda594cfb2005-11-06 16:13:29 +00001327 product_name[0] = '\0';
1328 class_id = 0xff;
1329 device_count++;
1330 product_id = 0;
1331 vendor_id = 0;
1332 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001333 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001334 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001335 }
bellarda594cfb2005-11-06 16:13:29 +00001336 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001337 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001338 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001339 }
bellarda594cfb2005-11-06 16:13:29 +00001340 product_id = strtoul(buf, NULL, 16);
1341 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001342 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001343 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001344 }
bellarda594cfb2005-11-06 16:13:29 +00001345 pstrcpy(product_name, sizeof(product_name), buf);
1346 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001347 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001348 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001349 }
bellarda594cfb2005-11-06 16:13:29 +00001350 class_id = strtoul(buf, NULL, 16);
1351 }
1352 fail: ;
1353 }
pbrook38ca0f62006-03-11 18:03:38 +00001354 if (device_count && (vendor_id || product_id)) {
1355 /* Add the last device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001356 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001357 product_id, product_name, speed);
1358 }
1359 the_end:
David Ahern27911042010-04-24 10:26:22 -06001360 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001361 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001362 }
aliguori0f431522008-10-07 20:06:37 +00001363 return ret;
1364}
1365
1366/*
1367 * Read sys file-system device file
1368 *
1369 * @line address of buffer to put file contents in
1370 * @line_size size of line
1371 * @device_file path to device file (printf format string)
1372 * @device_name device being opened (inserted into device_file)
1373 *
1374 * @return 0 failed, 1 succeeded ('line' contains data)
1375 */
David Ahern27911042010-04-24 10:26:22 -06001376static int usb_host_read_file(char *line, size_t line_size,
1377 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001378{
1379 FILE *f;
1380 int ret = 0;
1381 char filename[PATH_MAX];
1382
blueswir1b4e237a2008-12-28 15:45:20 +00001383 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1384 device_file);
aliguori0f431522008-10-07 20:06:37 +00001385 f = fopen(filename, "r");
1386 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001387 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001388 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001389 }
1390
1391 return ret;
1392}
1393
1394/*
1395 * Use /sys/bus/usb/devices/ directory to determine host's USB
1396 * devices.
1397 *
1398 * This code is based on Robert Schiele's original patches posted to
1399 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1400 */
1401static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1402{
Blue Swirl660f11b2009-07-31 21:16:51 +00001403 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001404 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001405 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001406 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001407 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001408 char product_name[512];
1409 struct dirent *de;
1410
1411 dir = opendir(USBSYSBUS_PATH "/devices");
1412 if (!dir) {
1413 perror("husb: cannot open devices directory");
1414 goto the_end;
1415 }
1416
1417 while ((de = readdir(dir))) {
1418 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001419 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1420 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001421 }
aliguori0f431522008-10-07 20:06:37 +00001422
David Ahern27911042010-04-24 10:26:22 -06001423 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001424 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001425 }
1426 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001427 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001428 }
blueswir1b4e237a2008-12-28 15:45:20 +00001429 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001430 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001431 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001432 }
1433 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001434 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001435 }
aliguori0f431522008-10-07 20:06:37 +00001436
David Ahern27911042010-04-24 10:26:22 -06001437 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1438 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001439 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001440 }
1441 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001442 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001443 }
blueswir1b4e237a2008-12-28 15:45:20 +00001444 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001445 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001446 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001447 }
1448 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001449 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001450 }
blueswir1b4e237a2008-12-28 15:45:20 +00001451 if (!usb_host_read_file(line, sizeof(line), "product",
1452 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001453 *product_name = 0;
1454 } else {
David Ahern27911042010-04-24 10:26:22 -06001455 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001456 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001457 }
aliguori0f431522008-10-07 20:06:37 +00001458 pstrcpy(product_name, sizeof(product_name), line);
1459 }
1460
David Ahern27911042010-04-24 10:26:22 -06001461 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001462 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001463 }
1464 if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001465 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001466 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001467 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001468 } else {
aliguori0f431522008-10-07 20:06:37 +00001469 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001470 }
aliguori0f431522008-10-07 20:06:37 +00001471
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001472 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001473 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001474 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001475 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001476 }
aliguori0f431522008-10-07 20:06:37 +00001477 }
1478 }
1479 the_end:
David Ahern27911042010-04-24 10:26:22 -06001480 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001481 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001482 }
aliguori0f431522008-10-07 20:06:37 +00001483 return ret;
1484}
1485
1486/*
1487 * Determine how to access the host's USB devices and call the
1488 * specific support function.
1489 */
1490static int usb_host_scan(void *opaque, USBScanFunc *func)
1491{
aliguori376253e2009-03-05 23:01:23 +00001492 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001493 FILE *f = NULL;
1494 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001495 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001496 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1497 char devpath[PATH_MAX];
1498
1499 /* only check the host once */
1500 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001501 dir = opendir(USBSYSBUS_PATH "/devices");
1502 if (dir) {
1503 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1504 strcpy(devpath, USBDEVBUS_PATH);
1505 usb_fs_type = USB_FS_SYS;
1506 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001507 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001508 goto found_devices;
1509 }
aliguori0f431522008-10-07 20:06:37 +00001510 f = fopen(USBPROCBUS_PATH "/devices", "r");
1511 if (f) {
1512 /* devices found in /proc/bus/usb/ */
1513 strcpy(devpath, USBPROCBUS_PATH);
1514 usb_fs_type = USB_FS_PROC;
1515 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001516 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001517 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001518 }
1519 /* try additional methods if an access method hasn't been found yet */
1520 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001521 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001522 /* devices found in /dev/bus/usb/ */
1523 strcpy(devpath, USBDEVBUS_PATH);
1524 usb_fs_type = USB_FS_DEV;
1525 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001526 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001527 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001528 }
aliguorif16a0db2008-10-21 16:34:20 +00001529 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001530 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001531 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001532 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001533 }
aliguorif16a0db2008-10-21 16:34:20 +00001534 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001535 }
1536
1537 /* the module setting (used later for opening devices) */
1538 usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001539 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001540 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001541 monitor_printf(mon, "husb: using %s file-system with %s\n",
1542 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001543 }
aliguori0f431522008-10-07 20:06:37 +00001544 }
1545
1546 switch (usb_fs_type) {
1547 case USB_FS_PROC:
1548 case USB_FS_DEV:
1549 ret = usb_host_scan_dev(opaque, func);
1550 break;
1551 case USB_FS_SYS:
1552 ret = usb_host_scan_sys(opaque, func);
1553 break;
aliguorif16a0db2008-10-21 16:34:20 +00001554 default:
1555 ret = -EINVAL;
1556 break;
aliguori0f431522008-10-07 20:06:37 +00001557 }
bellarda594cfb2005-11-06 16:13:29 +00001558 return ret;
1559}
1560
aliguori4b096fc2008-08-21 19:28:55 +00001561static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001562
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001563static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001564 int class_id, int vendor_id, int product_id,
1565 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001566{
1567 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001568 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001569
1570 /* Ignore hubs */
1571 if (class_id == 9)
1572 return 0;
1573
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001574 QTAILQ_FOREACH(s, &hostdevs, next) {
1575 f = &s->match;
1576
David Ahern27911042010-04-24 10:26:22 -06001577 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001578 continue;
David Ahern27911042010-04-24 10:26:22 -06001579 }
1580 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001581 continue;
David Ahern27911042010-04-24 10:26:22 -06001582 }
aliguori4b096fc2008-08-21 19:28:55 +00001583
David Ahern27911042010-04-24 10:26:22 -06001584 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001585 continue;
David Ahern27911042010-04-24 10:26:22 -06001586 }
aliguori4b096fc2008-08-21 19:28:55 +00001587
David Ahern27911042010-04-24 10:26:22 -06001588 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001589 continue;
David Ahern27911042010-04-24 10:26:22 -06001590 }
aliguori4b096fc2008-08-21 19:28:55 +00001591 /* We got a match */
1592
Markus Armbruster33e66b82009-10-07 01:15:57 +02001593 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001594 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001595 return 0;
David Ahern27911042010-04-24 10:26:22 -06001596 }
malcd0f2c4c2010-02-07 02:03:50 +03001597 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001598
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001599 usb_host_open(s, bus_num, addr, port, product_name);
aliguori4b096fc2008-08-21 19:28:55 +00001600 }
1601
1602 return 0;
1603}
1604
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001605static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001606{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001607 struct USBHostDevice *s;
1608 int unconnected = 0;
1609
aliguori4b096fc2008-08-21 19:28:55 +00001610 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001611
1612 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001613 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001614 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001615 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001616 }
1617
1618 if (unconnected == 0) {
1619 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001620 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001621 qemu_del_timer(usb_auto_timer);
David Ahern27911042010-04-24 10:26:22 -06001622 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001623 return;
1624 }
1625
1626 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001627 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001628 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001629 return;
David Ahern27911042010-04-24 10:26:22 -06001630 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001631 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001632 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001633}
1634
1635/*
aliguori5d0c5752008-09-14 01:07:41 +00001636 * Autoconnect filter
1637 * Format:
1638 * auto:bus:dev[:vid:pid]
1639 * auto:bus.dev[:vid:pid]
1640 *
1641 * bus - bus number (dec, * means any)
1642 * dev - device number (dec, * means any)
1643 * vid - vendor id (hex, * means any)
1644 * pid - product id (hex, * means any)
1645 *
1646 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001647 */
aliguori5d0c5752008-09-14 01:07:41 +00001648static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001649{
aliguori5d0c5752008-09-14 01:07:41 +00001650 enum { BUS, DEV, VID, PID, DONE };
1651 const char *p = spec;
1652 int i;
1653
Markus Armbruster0745eb12009-11-27 13:05:53 +01001654 f->bus_num = 0;
1655 f->addr = 0;
1656 f->vendor_id = 0;
1657 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001658
1659 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001660 p = strpbrk(p, ":.");
1661 if (!p) {
1662 break;
1663 }
aliguori5d0c5752008-09-14 01:07:41 +00001664 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001665
David Ahern27911042010-04-24 10:26:22 -06001666 if (*p == '*') {
1667 continue;
1668 }
aliguori5d0c5752008-09-14 01:07:41 +00001669 switch(i) {
1670 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1671 case DEV: f->addr = strtol(p, NULL, 10); break;
1672 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1673 case PID: f->product_id = strtol(p, NULL, 16); break;
1674 }
aliguori4b096fc2008-08-21 19:28:55 +00001675 }
1676
aliguori5d0c5752008-09-14 01:07:41 +00001677 if (i < DEV) {
1678 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1679 return -1;
1680 }
1681
1682 return 0;
1683}
1684
bellarda594cfb2005-11-06 16:13:29 +00001685/**********************/
1686/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001687
bellarda594cfb2005-11-06 16:13:29 +00001688struct usb_class_info {
1689 int class;
1690 const char *class_name;
1691};
1692
1693static const struct usb_class_info usb_class_info[] = {
1694 { USB_CLASS_AUDIO, "Audio"},
1695 { USB_CLASS_COMM, "Communication"},
1696 { USB_CLASS_HID, "HID"},
1697 { USB_CLASS_HUB, "Hub" },
1698 { USB_CLASS_PHYSICAL, "Physical" },
1699 { USB_CLASS_PRINTER, "Printer" },
1700 { USB_CLASS_MASS_STORAGE, "Storage" },
1701 { USB_CLASS_CDC_DATA, "Data" },
1702 { USB_CLASS_APP_SPEC, "Application Specific" },
1703 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1704 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001705 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001706 { USB_CLASS_CONTENT_SEC, "Content Security" },
1707 { -1, NULL }
1708};
1709
1710static const char *usb_class_str(uint8_t class)
1711{
1712 const struct usb_class_info *p;
1713 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001714 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001715 break;
David Ahern27911042010-04-24 10:26:22 -06001716 }
bellardbb36d472005-11-05 14:22:28 +00001717 }
bellarda594cfb2005-11-06 16:13:29 +00001718 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001719}
1720
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001721static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
1722 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00001723 const char *product_name,
1724 int speed)
bellardbb36d472005-11-05 14:22:28 +00001725{
bellarda594cfb2005-11-06 16:13:29 +00001726 const char *class_str, *speed_str;
1727
1728 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001729 case USB_SPEED_LOW:
1730 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001731 break;
ths5fafdf22007-09-16 21:08:06 +00001732 case USB_SPEED_FULL:
1733 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001734 break;
ths5fafdf22007-09-16 21:08:06 +00001735 case USB_SPEED_HIGH:
1736 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001737 break;
1738 default:
ths5fafdf22007-09-16 21:08:06 +00001739 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001740 break;
bellardbb36d472005-11-05 14:22:28 +00001741 }
bellarda594cfb2005-11-06 16:13:29 +00001742
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001743 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
1744 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00001745 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001746 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001747 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001748 } else {
aliguori376253e2009-03-05 23:01:23 +00001749 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001750 }
aliguori376253e2009-03-05 23:01:23 +00001751 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001752 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001753 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001754 }
aliguori376253e2009-03-05 23:01:23 +00001755 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001756}
1757
ths5fafdf22007-09-16 21:08:06 +00001758static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001759 char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001760 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001761 const char *product_name,
1762 int speed)
1763{
Blue Swirl179da8a2009-09-07 19:00:18 +00001764 Monitor *mon = opaque;
1765
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001766 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001767 product_name, speed);
1768 return 0;
1769}
1770
aliguoriac4ffb52008-09-22 15:04:31 +00001771static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001772{
David Ahern27911042010-04-24 10:26:22 -06001773 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001774 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001775 } else {
1776 snprintf(str, size, "%d", val);
1777 }
aliguori5d0c5752008-09-14 01:07:41 +00001778}
1779
aliguoriac4ffb52008-09-22 15:04:31 +00001780static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001781{
David Ahern27911042010-04-24 10:26:22 -06001782 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001783 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001784 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001785 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06001786 }
aliguori5d0c5752008-09-14 01:07:41 +00001787}
1788
aliguori376253e2009-03-05 23:01:23 +00001789void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00001790{
aliguori5d0c5752008-09-14 01:07:41 +00001791 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001792 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00001793
Blue Swirl179da8a2009-09-07 19:00:18 +00001794 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00001795
David Ahern27911042010-04-24 10:26:22 -06001796 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001797 return;
David Ahern27911042010-04-24 10:26:22 -06001798 }
1799
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001800 monitor_printf(mon, " Auto filters:\n");
1801 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00001802 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001803 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00001804 dec2str(f->bus_num, bus, sizeof(bus));
1805 dec2str(f->addr, addr, sizeof(addr));
1806 hex2str(f->vendor_id, vid, sizeof(vid));
1807 hex2str(f->product_id, pid, sizeof(pid));
aliguori376253e2009-03-05 23:01:23 +00001808 monitor_printf(mon, " Device %s.%s ID %s:%s\n",
1809 bus, addr, vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00001810 }
bellardbb36d472005-11-05 14:22:28 +00001811}