blob: feb4d36d0bef320c12a5e3824b82b8b09dd6e2f0 [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>
bellardbb36d472005-11-05 14:22:28 +000040
aliguori446ab122008-09-14 01:06:09 +000041#include <linux/usbdevice_fs.h>
42#include <linux/version.h>
43#include "hw/usb.h"
bellardbb36d472005-11-05 14:22:28 +000044
blueswir1d9cf1572008-09-15 14:57:11 +000045/* We redefine it to avoid version problems */
46struct usb_ctrltransfer {
47 uint8_t bRequestType;
48 uint8_t bRequest;
49 uint16_t wValue;
50 uint16_t wIndex;
51 uint16_t wLength;
52 uint32_t timeout;
53 void *data;
54};
55
Gerd Hoffmann5557d822011-05-10 11:43:57 +020056typedef int USBScanFunc(void *opaque, int bus_num, int addr, char *port,
Hans de Goede0f5160d2010-11-10 10:06:23 +010057 int class_id, int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +000058 const char *product_name, int speed);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010059
Markus Armbruster0745eb12009-11-27 13:05:53 +010060//#define DEBUG
aliguori64838172008-08-21 19:31:10 +000061
62#ifdef DEBUG
malcd0f2c4c2010-02-07 02:03:50 +030063#define DPRINTF printf
aliguori64838172008-08-21 19:31:10 +000064#else
malcd0f2c4c2010-02-07 02:03:50 +030065#define DPRINTF(...)
aliguori64838172008-08-21 19:31:10 +000066#endif
bellardbb36d472005-11-05 14:22:28 +000067
blueswir15be8e1f2008-10-25 11:47:20 +000068#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
69
aliguori0f431522008-10-07 20:06:37 +000070#define USBPROCBUS_PATH "/proc/bus/usb"
bellard1f6e24e2006-06-26 21:00:51 +000071#define PRODUCT_NAME_SZ 32
Hans de Goede3a4854b2010-11-26 15:02:16 +010072#define MAX_ENDPOINTS 15
Gerd Hoffmann5557d822011-05-10 11:43:57 +020073#define MAX_PORTLEN 16
aliguori0f431522008-10-07 20:06:37 +000074#define USBDEVBUS_PATH "/dev/bus/usb"
75#define USBSYSBUS_PATH "/sys/bus/usb"
76
77static char *usb_host_device_path;
78
79#define USB_FS_NONE 0
80#define USB_FS_PROC 1
81#define USB_FS_DEV 2
82#define USB_FS_SYS 3
83
84static int usb_fs_type;
bellardbb36d472005-11-05 14:22:28 +000085
balrogb9dc0332007-10-04 22:47:34 +000086/* endpoint association data */
Hans de Goede060dc842010-11-26 11:41:08 +010087#define ISO_FRAME_DESC_PER_URB 32
88#define ISO_URB_COUNT 3
Hans de Goedea0b5fec2010-11-26 14:56:17 +010089#define INVALID_EP_TYPE 255
Hans de Goede060dc842010-11-26 11:41:08 +010090
Gerd Hoffmann71138532011-05-16 10:21:51 +020091/* devio.c limits single requests to 16k */
92#define MAX_USBFS_BUFFER_SIZE 16384
93
Hans de Goede060dc842010-11-26 11:41:08 +010094typedef struct AsyncURB AsyncURB;
95
balrogb9dc0332007-10-04 22:47:34 +000096struct endp_data {
97 uint8_t type;
aliguori64838172008-08-21 19:31:10 +000098 uint8_t halted;
Hans de Goedebb6d5492010-11-26 19:11:03 +010099 uint8_t iso_started;
Hans de Goede060dc842010-11-26 11:41:08 +0100100 AsyncURB *iso_urb;
101 int iso_urb_idx;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100102 int iso_buffer_used;
Hans de Goede060dc842010-11-26 11:41:08 +0100103 int max_packet_size;
balrogb9dc0332007-10-04 22:47:34 +0000104};
105
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100106struct USBAutoFilter {
107 uint32_t bus_num;
108 uint32_t addr;
Gerd Hoffmann9056a292011-05-10 12:07:42 +0200109 char *port;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100110 uint32_t vendor_id;
111 uint32_t product_id;
112};
113
bellardbb36d472005-11-05 14:22:28 +0000114typedef struct USBHostDevice {
115 USBDevice dev;
aliguori64838172008-08-21 19:31:10 +0000116 int fd;
117
118 uint8_t descr[1024];
119 int descr_len;
120 int configuration;
aliguori446ab122008-09-14 01:06:09 +0000121 int ninterfaces;
aliguori24772c12008-08-21 19:31:52 +0000122 int closing;
Shahar Havivib373a632010-06-16 15:16:11 +0300123 Notifier exit;
aliguori64838172008-08-21 19:31:10 +0000124
balrogb9dc0332007-10-04 22:47:34 +0000125 struct endp_data endp_table[MAX_ENDPOINTS];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200126 QLIST_HEAD(, AsyncURB) aurbs;
aliguori4b096fc2008-08-21 19:28:55 +0000127
aliguori4b096fc2008-08-21 19:28:55 +0000128 /* Host side address */
129 int bus_num;
130 int addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200131 char port[MAX_PORTLEN];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100132 struct USBAutoFilter match;
aliguori4b096fc2008-08-21 19:28:55 +0000133
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100134 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000135} USBHostDevice;
136
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100137static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
138
139static int usb_host_close(USBHostDevice *dev);
140static int parse_filter(const char *spec, struct USBAutoFilter *f);
141static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100142static int usb_host_read_file(char *line, size_t line_size,
143 const char *device_file, const char *device_name);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100144
aliguori64838172008-08-21 19:31:10 +0000145static int is_isoc(USBHostDevice *s, int ep)
146{
147 return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO;
148}
149
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100150static int is_valid(USBHostDevice *s, int ep)
151{
152 return s->endp_table[ep - 1].type != INVALID_EP_TYPE;
153}
154
aliguori64838172008-08-21 19:31:10 +0000155static int is_halted(USBHostDevice *s, int ep)
156{
157 return s->endp_table[ep - 1].halted;
158}
159
160static void clear_halt(USBHostDevice *s, int ep)
161{
162 s->endp_table[ep - 1].halted = 0;
163}
164
165static void set_halt(USBHostDevice *s, int ep)
166{
167 s->endp_table[ep - 1].halted = 1;
168}
169
Hans de Goedebb6d5492010-11-26 19:11:03 +0100170static int is_iso_started(USBHostDevice *s, int ep)
171{
172 return s->endp_table[ep - 1].iso_started;
173}
174
175static void clear_iso_started(USBHostDevice *s, int ep)
176{
177 s->endp_table[ep - 1].iso_started = 0;
178}
179
180static void set_iso_started(USBHostDevice *s, int ep)
181{
182 s->endp_table[ep - 1].iso_started = 1;
183}
184
Hans de Goede060dc842010-11-26 11:41:08 +0100185static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
186{
187 s->endp_table[ep - 1].iso_urb = iso_urb;
188}
189
190static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
191{
192 return s->endp_table[ep - 1].iso_urb;
193}
194
195static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
196{
197 s->endp_table[ep - 1].iso_urb_idx = i;
198}
199
200static int get_iso_urb_idx(USBHostDevice *s, int ep)
201{
202 return s->endp_table[ep - 1].iso_urb_idx;
203}
204
Hans de Goedebb6d5492010-11-26 19:11:03 +0100205static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
206{
207 s->endp_table[ep - 1].iso_buffer_used = i;
208}
209
210static int get_iso_buffer_used(USBHostDevice *s, int ep)
211{
212 return s->endp_table[ep - 1].iso_buffer_used;
213}
214
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200215static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
216{
217 int raw = descriptor[4] + (descriptor[5] << 8);
218 int size, microframes;
219
220 size = raw & 0x7ff;
221 switch ((raw >> 11) & 3) {
222 case 1: microframes = 2; break;
223 case 2: microframes = 3; break;
224 default: microframes = 1; break;
225 }
226 DPRINTF("husb: max packet size: 0x%x -> %d x %d\n",
227 raw, microframes, size);
228 s->endp_table[ep - 1].max_packet_size = size * microframes;
229}
230
Hans de Goede060dc842010-11-26 11:41:08 +0100231static int get_max_packet_size(USBHostDevice *s, int ep)
232{
233 return s->endp_table[ep - 1].max_packet_size;
234}
235
David Ahern27911042010-04-24 10:26:22 -0600236/*
aliguori64838172008-08-21 19:31:10 +0000237 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100238 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600239 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000240 */
Hans de Goede060dc842010-11-26 11:41:08 +0100241struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000242{
aliguori64838172008-08-21 19:31:10 +0000243 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100244 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200245 USBHostDevice *hdev;
246 QLIST_ENTRY(AsyncURB) next;
aliguori64838172008-08-21 19:31:10 +0000247
Hans de Goede060dc842010-11-26 11:41:08 +0100248 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000249 USBPacket *packet;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200250 int more; /* large transfer, more urbs follow */
Hans de Goede060dc842010-11-26 11:41:08 +0100251
252 /* For buffered iso handling */
253 int iso_frame_idx; /* -1 means in flight */
254};
aliguori64838172008-08-21 19:31:10 +0000255
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200256static AsyncURB *async_alloc(USBHostDevice *s)
aliguori64838172008-08-21 19:31:10 +0000257{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200258 AsyncURB *aurb = qemu_mallocz(sizeof(AsyncURB));
259 aurb->hdev = s;
260 QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
261 return aurb;
balrogb9dc0332007-10-04 22:47:34 +0000262}
263
aliguori64838172008-08-21 19:31:10 +0000264static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000265{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200266 QLIST_REMOVE(aurb, next);
aliguori64838172008-08-21 19:31:10 +0000267 qemu_free(aurb);
268}
balrogb9dc0332007-10-04 22:47:34 +0000269
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200270static void do_disconnect(USBHostDevice *s)
271{
272 printf("husb: device %d.%d disconnected\n",
273 s->bus_num, s->addr);
274 usb_host_close(s);
275 usb_host_auto_check(NULL);
276}
277
aliguori64838172008-08-21 19:31:10 +0000278static void async_complete(void *opaque)
279{
280 USBHostDevice *s = opaque;
281 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000282
aliguori64838172008-08-21 19:31:10 +0000283 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600284 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000285
David Ahern27911042010-04-24 10:26:22 -0600286 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000287 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600288 if (errno == EAGAIN) {
aliguori64838172008-08-21 19:31:10 +0000289 return;
David Ahern27911042010-04-24 10:26:22 -0600290 }
aliguori24772c12008-08-21 19:31:52 +0000291 if (errno == ENODEV && !s->closing) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200292 do_disconnect(s);
aliguori64838172008-08-21 19:31:10 +0000293 return;
294 }
295
malcd0f2c4c2010-02-07 02:03:50 +0300296 DPRINTF("husb: async. reap urb failed errno %d\n", errno);
aliguori64838172008-08-21 19:31:10 +0000297 return;
balrogb9dc0332007-10-04 22:47:34 +0000298 }
aliguori64838172008-08-21 19:31:10 +0000299
David Ahern27911042010-04-24 10:26:22 -0600300 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000301 aurb, aurb->urb.status, aurb->urb.actual_length);
302
Hans de Goede060dc842010-11-26 11:41:08 +0100303 /* If this is a buffered iso urb mark it as complete and don't do
304 anything else (it is handled further in usb_host_handle_iso_data) */
305 if (aurb->iso_frame_idx == -1) {
306 if (aurb->urb.status == -EPIPE) {
307 set_halt(s, aurb->urb.endpoint & 0xf);
308 }
309 aurb->iso_frame_idx = 0;
310 continue;
311 }
312
313 p = aurb->packet;
314
David Ahern27911042010-04-24 10:26:22 -0600315 if (p) {
aliguori64838172008-08-21 19:31:10 +0000316 switch (aurb->urb.status) {
317 case 0:
Gerd Hoffmann71138532011-05-16 10:21:51 +0200318 p->len += aurb->urb.actual_length;
aliguori64838172008-08-21 19:31:10 +0000319 break;
320
321 case -EPIPE:
322 set_halt(s, p->devep);
David Ahern27911042010-04-24 10:26:22 -0600323 p->len = USB_RET_STALL;
324 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200325
aliguori64838172008-08-21 19:31:10 +0000326 default:
327 p->len = USB_RET_NAK;
328 break;
329 }
330
Hans de Goede50b79632011-02-02 17:36:29 +0100331 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
332 usb_generic_async_ctrl_complete(&s->dev, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200333 } else if (!aurb->more) {
Hans de Goede50b79632011-02-02 17:36:29 +0100334 usb_packet_complete(&s->dev, p);
335 }
David Ahern27911042010-04-24 10:26:22 -0600336 }
aliguori64838172008-08-21 19:31:10 +0000337
338 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000339 }
balrogb9dc0332007-10-04 22:47:34 +0000340}
341
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200342static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
balrogb9dc0332007-10-04 22:47:34 +0000343{
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200344 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200345 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000346
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200347 QLIST_FOREACH(aurb, &s->aurbs, next) {
348 if (p != aurb->packet) {
349 continue;
350 }
balrogb9dc0332007-10-04 22:47:34 +0000351
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200352 DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
aliguori64838172008-08-21 19:31:10 +0000353
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200354 /* Mark it as dead (see async_complete above) */
355 aurb->packet = NULL;
356
357 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
358 if (r < 0) {
359 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
360 }
balrogb9dc0332007-10-04 22:47:34 +0000361 }
balrogb9dc0332007-10-04 22:47:34 +0000362}
363
aliguori446ab122008-09-14 01:06:09 +0000364static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000365{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200366 const char *op = NULL;
balrogb9dc0332007-10-04 22:47:34 +0000367 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000368 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000369 int ret, i;
370
371 if (configuration == 0) /* address state - ignore */
372 return 1;
373
malcd0f2c4c2010-02-07 02:03:50 +0300374 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000375
balrogb9dc0332007-10-04 22:47:34 +0000376 i = 0;
377 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600378 if (dev_descr_len > dev->descr_len) {
Hans de Goede61c11172011-05-31 11:35:20 +0200379 fprintf(stderr, "husb: update iface failed. descr too short\n");
380 return 0;
David Ahern27911042010-04-24 10:26:22 -0600381 }
balrogb9dc0332007-10-04 22:47:34 +0000382
383 i += dev_descr_len;
384 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600385 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
386 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000387 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000388
balrogb9dc0332007-10-04 22:47:34 +0000389 if (dev->descr[i+1] != USB_DT_CONFIG) {
390 i += dev->descr[i];
391 continue;
392 }
393 config_descr_len = dev->descr[i];
394
David Ahern27911042010-04-24 10:26:22 -0600395 printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000396
aliguori446ab122008-09-14 01:06:09 +0000397 if (configuration < 0 || configuration == dev->descr[i + 5]) {
398 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000399 break;
aliguori446ab122008-09-14 01:06:09 +0000400 }
balrogb9dc0332007-10-04 22:47:34 +0000401
402 i += config_descr_len;
403 }
404
405 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600406 fprintf(stderr,
407 "husb: update iface failed. no matching configuration\n");
Hans de Goede61c11172011-05-31 11:35:20 +0200408 return 0;
balrogb9dc0332007-10-04 22:47:34 +0000409 }
410 nb_interfaces = dev->descr[i + 4];
411
412#ifdef USBDEVFS_DISCONNECT
413 /* earlier Linux 2.4 do not support that */
414 {
415 struct usbdevfs_ioctl ctrl;
416 for (interface = 0; interface < nb_interfaces; interface++) {
417 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
418 ctrl.ifno = interface;
Brad Hards021730f2011-04-13 19:45:32 +1000419 ctrl.data = 0;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200420 op = "USBDEVFS_DISCONNECT";
balrogb9dc0332007-10-04 22:47:34 +0000421 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
422 if (ret < 0 && errno != ENODATA) {
balrogb9dc0332007-10-04 22:47:34 +0000423 goto fail;
424 }
425 }
426 }
427#endif
428
429 /* XXX: only grab if all interfaces are free */
430 for (interface = 0; interface < nb_interfaces; interface++) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200431 op = "USBDEVFS_CLAIMINTERFACE";
balrogb9dc0332007-10-04 22:47:34 +0000432 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
433 if (ret < 0) {
434 if (errno == EBUSY) {
aliguori64838172008-08-21 19:31:10 +0000435 printf("husb: update iface. device already grabbed\n");
balrogb9dc0332007-10-04 22:47:34 +0000436 } else {
aliguori64838172008-08-21 19:31:10 +0000437 perror("husb: failed to claim interface");
balrogb9dc0332007-10-04 22:47:34 +0000438 }
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200439 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000440 }
441 }
442
aliguori64838172008-08-21 19:31:10 +0000443 printf("husb: %d interfaces claimed for configuration %d\n",
balrogb9dc0332007-10-04 22:47:34 +0000444 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000445
aliguori446ab122008-09-14 01:06:09 +0000446 dev->ninterfaces = nb_interfaces;
447 dev->configuration = configuration;
448 return 1;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200449
450fail:
451 if (errno == ENODEV) {
452 do_disconnect(dev);
453 }
454 perror(op);
455 return 0;
aliguori446ab122008-09-14 01:06:09 +0000456}
457
458static int usb_host_release_interfaces(USBHostDevice *s)
459{
460 int ret, i;
461
malcd0f2c4c2010-02-07 02:03:50 +0300462 DPRINTF("husb: releasing interfaces\n");
aliguori446ab122008-09-14 01:06:09 +0000463
464 for (i = 0; i < s->ninterfaces; i++) {
465 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
466 if (ret < 0) {
467 perror("husb: failed to release interface");
468 return 0;
469 }
470 }
471
balrogb9dc0332007-10-04 22:47:34 +0000472 return 1;
473}
474
bellard059809e2006-07-19 18:06:15 +0000475static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000476{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100477 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000478
malcd0f2c4c2010-02-07 02:03:50 +0300479 DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000480
bellardbb36d472005-11-05 14:22:28 +0000481 ioctl(s->fd, USBDEVFS_RESET);
aliguori446ab122008-09-14 01:06:09 +0000482
483 usb_host_claim_interfaces(s, s->configuration);
ths5fafdf22007-09-16 21:08:06 +0000484}
bellardbb36d472005-11-05 14:22:28 +0000485
bellard059809e2006-07-19 18:06:15 +0000486static void usb_host_handle_destroy(USBDevice *dev)
487{
488 USBHostDevice *s = (USBHostDevice *)dev;
489
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100490 usb_host_close(s);
491 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300492 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000493}
494
balrogb9dc0332007-10-04 22:47:34 +0000495static int usb_linux_update_endp_table(USBHostDevice *s);
496
Hans de Goede060dc842010-11-26 11:41:08 +0100497/* iso data is special, we need to keep enough urbs in flight to make sure
498 that the controller never runs out of them, otherwise the device will
499 likely suffer a buffer underrun / overrun. */
500static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
501{
502 AsyncURB *aurb;
503 int i, j, len = get_max_packet_size(s, ep);
504
505 aurb = qemu_mallocz(ISO_URB_COUNT * sizeof(*aurb));
506 for (i = 0; i < ISO_URB_COUNT; i++) {
507 aurb[i].urb.endpoint = ep;
508 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
509 aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length);
510 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
511 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
512 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
513 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
514 aurb[i].urb.iso_frame_desc[j].length = len;
515 if (in) {
516 aurb[i].urb.endpoint |= 0x80;
517 /* Mark as fully consumed (idle) */
518 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
519 }
520 }
521 set_iso_urb(s, ep, aurb);
522
523 return aurb;
524}
525
526static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
527{
528 AsyncURB *aurb;
529 int i, ret, killed = 0, free = 1;
530
531 aurb = get_iso_urb(s, ep);
532 if (!aurb) {
533 return;
534 }
535
536 for (i = 0; i < ISO_URB_COUNT; i++) {
537 /* in flight? */
538 if (aurb[i].iso_frame_idx == -1) {
539 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
540 if (ret < 0) {
541 printf("husb: discard isoc in urb failed errno %d\n", errno);
542 free = 0;
543 continue;
544 }
545 killed++;
546 }
547 }
548
549 /* Make sure any urbs we've killed are reaped before we free them */
550 if (killed) {
551 async_complete(s);
552 }
553
554 for (i = 0; i < ISO_URB_COUNT; i++) {
555 qemu_free(aurb[i].urb.buffer);
556 }
557
558 if (free)
559 qemu_free(aurb);
560 else
561 printf("husb: leaking iso urbs because of discard failure\n");
562 set_iso_urb(s, ep, NULL);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100563 set_iso_urb_idx(s, ep, 0);
564 clear_iso_started(s, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100565}
566
567static int urb_status_to_usb_ret(int status)
568{
569 switch (status) {
570 case -EPIPE:
571 return USB_RET_STALL;
572 default:
573 return USB_RET_NAK;
574 }
575}
576
Hans de Goedebb6d5492010-11-26 19:11:03 +0100577static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100578{
579 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100580 int i, j, ret, max_packet_size, offset, len = 0;
Hans de Goede975f2992010-11-26 14:59:35 +0100581
582 max_packet_size = get_max_packet_size(s, p->devep);
583 if (max_packet_size == 0)
584 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100585
586 aurb = get_iso_urb(s, p->devep);
587 if (!aurb) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100588 aurb = usb_host_alloc_iso(s, p->devep, in);
Hans de Goede060dc842010-11-26 11:41:08 +0100589 }
590
591 i = get_iso_urb_idx(s, p->devep);
592 j = aurb[i].iso_frame_idx;
593 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100594 if (in) {
595 /* Check urb status */
596 if (aurb[i].urb.status) {
597 len = urb_status_to_usb_ret(aurb[i].urb.status);
598 /* Move to the next urb */
599 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
600 /* Check frame status */
601 } else if (aurb[i].urb.iso_frame_desc[j].status) {
602 len = urb_status_to_usb_ret(
603 aurb[i].urb.iso_frame_desc[j].status);
604 /* Check the frame fits */
605 } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
606 printf("husb: received iso data is larger then packet\n");
607 len = USB_RET_NAK;
608 /* All good copy data over */
609 } else {
610 len = aurb[i].urb.iso_frame_desc[j].actual_length;
611 memcpy(p->data,
612 aurb[i].urb.buffer +
613 j * aurb[i].urb.iso_frame_desc[0].length,
614 len);
615 }
Hans de Goede060dc842010-11-26 11:41:08 +0100616 } else {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100617 len = p->len;
618 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
619
620 /* Check the frame fits */
621 if (len > max_packet_size) {
622 printf("husb: send iso data is larger then max packet size\n");
623 return USB_RET_NAK;
624 }
625
626 /* All good copy data over */
627 memcpy(aurb[i].urb.buffer + offset, p->data, len);
628 aurb[i].urb.iso_frame_desc[j].length = len;
629 offset += len;
630 set_iso_buffer_used(s, p->devep, offset);
631
632 /* Start the stream once we have buffered enough data */
633 if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
634 set_iso_started(s, p->devep);
635 }
Hans de Goede060dc842010-11-26 11:41:08 +0100636 }
637 aurb[i].iso_frame_idx++;
638 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
639 i = (i + 1) % ISO_URB_COUNT;
640 set_iso_urb_idx(s, p->devep, i);
641 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100642 } else {
643 if (in) {
644 set_iso_started(s, p->devep);
645 } else {
646 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
647 }
Hans de Goede060dc842010-11-26 11:41:08 +0100648 }
649
Hans de Goedebb6d5492010-11-26 19:11:03 +0100650 if (is_iso_started(s, p->devep)) {
651 /* (Re)-submit all fully consumed / filled urbs */
652 for (i = 0; i < ISO_URB_COUNT; i++) {
653 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
654 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
655 if (ret < 0) {
656 printf("husb error submitting iso urb %d: %d\n", i, errno);
657 if (!in || len == 0) {
658 switch(errno) {
659 case ETIMEDOUT:
660 len = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200661 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100662 case EPIPE:
663 default:
664 len = USB_RET_STALL;
665 }
Hans de Goede060dc842010-11-26 11:41:08 +0100666 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100667 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100668 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100669 aurb[i].iso_frame_idx = -1;
Hans de Goede060dc842010-11-26 11:41:08 +0100670 }
Hans de Goede060dc842010-11-26 11:41:08 +0100671 }
672 }
673
674 return len;
675}
676
Hans de Goede50b79632011-02-02 17:36:29 +0100677static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000678{
Hans de Goede50b79632011-02-02 17:36:29 +0100679 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000680 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000681 AsyncURB *aurb;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200682 int ret, rem;
683 uint8_t *pbuf;
Hans de Goede060dc842010-11-26 11:41:08 +0100684 uint8_t ep;
685
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100686 if (!is_valid(s, p->devep)) {
687 return USB_RET_NAK;
688 }
689
Hans de Goede060dc842010-11-26 11:41:08 +0100690 if (p->pid == USB_TOKEN_IN) {
691 ep = p->devep | 0x80;
692 } else {
693 ep = p->devep;
694 }
695
696 if (is_halted(s, p->devep)) {
697 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
698 if (ret < 0) {
699 DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
700 ep, errno);
701 return USB_RET_NAK;
702 }
703 clear_halt(s, p->devep);
704 }
705
Hans de Goedebb6d5492010-11-26 19:11:03 +0100706 if (is_isoc(s, p->devep)) {
707 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
708 }
bellardbb36d472005-11-05 14:22:28 +0000709
Gerd Hoffmann71138532011-05-16 10:21:51 +0200710 rem = p->len;
711 pbuf = p->data;
712 p->len = 0;
713 while (rem) {
714 aurb = async_alloc(s);
715 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000716
Gerd Hoffmann71138532011-05-16 10:21:51 +0200717 urb = &aurb->urb;
718 urb->endpoint = ep;
719 urb->type = USBDEVFS_URB_TYPE_BULK;
720 urb->usercontext = s;
721 urb->buffer = pbuf;
aliguori64838172008-08-21 19:31:10 +0000722
Gerd Hoffmann71138532011-05-16 10:21:51 +0200723 if (rem > MAX_USBFS_BUFFER_SIZE) {
724 urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
725 aurb->more = 1;
726 } else {
727 urb->buffer_length = rem;
728 aurb->more = 0;
729 }
730 pbuf += urb->buffer_length;
731 rem -= urb->buffer_length;
aliguori64838172008-08-21 19:31:10 +0000732
Gerd Hoffmann71138532011-05-16 10:21:51 +0200733 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
aliguori64838172008-08-21 19:31:10 +0000734
Gerd Hoffmann71138532011-05-16 10:21:51 +0200735 DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
736 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
aliguori64838172008-08-21 19:31:10 +0000737
Gerd Hoffmann71138532011-05-16 10:21:51 +0200738 if (ret < 0) {
739 DPRINTF("husb: submit failed. errno %d\n", errno);
740 async_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000741
Gerd Hoffmann71138532011-05-16 10:21:51 +0200742 switch(errno) {
743 case ETIMEDOUT:
744 return USB_RET_NAK;
745 case EPIPE:
746 default:
747 return USB_RET_STALL;
748 }
balrogb9dc0332007-10-04 22:47:34 +0000749 }
750 }
aliguori64838172008-08-21 19:31:10 +0000751
balrogb9dc0332007-10-04 22:47:34 +0000752 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000753}
754
aliguori446ab122008-09-14 01:06:09 +0000755static int ctrl_error(void)
756{
David Ahern27911042010-04-24 10:26:22 -0600757 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000758 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600759 } else {
aliguori446ab122008-09-14 01:06:09 +0000760 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600761 }
aliguori446ab122008-09-14 01:06:09 +0000762}
763
764static int usb_host_set_address(USBHostDevice *s, int addr)
765{
malcd0f2c4c2010-02-07 02:03:50 +0300766 DPRINTF("husb: ctrl set addr %u\n", addr);
aliguori446ab122008-09-14 01:06:09 +0000767 s->dev.addr = addr;
768 return 0;
769}
770
771static int usb_host_set_config(USBHostDevice *s, int config)
772{
773 usb_host_release_interfaces(s);
774
775 int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600776
malcd0f2c4c2010-02-07 02:03:50 +0300777 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600778
779 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000780 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600781 }
aliguori446ab122008-09-14 01:06:09 +0000782 usb_host_claim_interfaces(s, config);
783 return 0;
784}
785
786static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
787{
788 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100789 int i, ret;
790
Hans de Goede3a4854b2010-11-26 15:02:16 +0100791 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100792 if (is_isoc(s, i)) {
793 usb_host_stop_n_free_iso(s, i);
794 }
795 }
aliguori446ab122008-09-14 01:06:09 +0000796
797 si.interface = iface;
798 si.altsetting = alt;
799 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000800
David Ahern27911042010-04-24 10:26:22 -0600801 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
802 iface, alt, ret, errno);
803
804 if (ret < 0) {
805 return ctrl_error();
806 }
aliguori446ab122008-09-14 01:06:09 +0000807 usb_linux_update_endp_table(s);
808 return 0;
809}
810
Hans de Goede50b79632011-02-02 17:36:29 +0100811static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
812 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +0000813{
Hans de Goede50b79632011-02-02 17:36:29 +0100814 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +0000815 struct usbdevfs_urb *urb;
816 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +0100817 int ret;
aliguori446ab122008-09-14 01:06:09 +0000818
David Ahern27911042010-04-24 10:26:22 -0600819 /*
aliguori446ab122008-09-14 01:06:09 +0000820 * Process certain standard device requests.
821 * These are infrequent and are processed synchronously.
822 */
aliguori446ab122008-09-14 01:06:09 +0000823
Hans de Goede50b79632011-02-02 17:36:29 +0100824 /* Note request is (bRequestType << 8) | bRequest */
malcd0f2c4c2010-02-07 02:03:50 +0300825 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 +0100826 request >> 8, request & 0xff, value, index, length);
aliguori446ab122008-09-14 01:06:09 +0000827
Hans de Goede50b79632011-02-02 17:36:29 +0100828 switch (request) {
829 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
830 return usb_host_set_address(s, value);
aliguori446ab122008-09-14 01:06:09 +0000831
Hans de Goede50b79632011-02-02 17:36:29 +0100832 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
833 return usb_host_set_config(s, value & 0xff);
aliguori446ab122008-09-14 01:06:09 +0000834
Hans de Goede50b79632011-02-02 17:36:29 +0100835 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
aliguori446ab122008-09-14 01:06:09 +0000836 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -0600837 }
aliguori446ab122008-09-14 01:06:09 +0000838
839 /* The rest are asynchronous */
840
Hans de Goede50b79632011-02-02 17:36:29 +0100841 if (length > sizeof(dev->data_buf)) {
842 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
843 length, sizeof(dev->data_buf));
malcb2e3b6e2009-09-12 03:18:18 +0400844 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -0400845 }
846
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200847 aurb = async_alloc(s);
aliguori446ab122008-09-14 01:06:09 +0000848 aurb->packet = p;
849
David Ahern27911042010-04-24 10:26:22 -0600850 /*
aliguori446ab122008-09-14 01:06:09 +0000851 * Setup ctrl transfer.
852 *
Brad Hardsa0102082011-04-13 19:45:33 +1000853 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +0000854 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -0600855 */
aliguori446ab122008-09-14 01:06:09 +0000856 urb = &aurb->urb;
857
858 urb->type = USBDEVFS_URB_TYPE_CONTROL;
859 urb->endpoint = p->devep;
860
Hans de Goede50b79632011-02-02 17:36:29 +0100861 urb->buffer = &dev->setup_buf;
862 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +0000863
864 urb->usercontext = s;
865
866 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
867
malcd0f2c4c2010-02-07 02:03:50 +0300868 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +0000869
870 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300871 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +0000872 async_free(aurb);
873
874 switch(errno) {
875 case ETIMEDOUT:
876 return USB_RET_NAK;
877 case EPIPE:
878 default:
879 return USB_RET_STALL;
880 }
881 }
882
aliguori446ab122008-09-14 01:06:09 +0000883 return USB_RET_ASYNC;
884}
885
Hans de Goede71d71bb2010-11-10 10:06:24 +0100886static int usb_linux_get_configuration(USBHostDevice *s)
balrogb9dc0332007-10-04 22:47:34 +0000887{
Hans de Goede71d71bb2010-11-10 10:06:24 +0100888 uint8_t configuration;
pbrooke41b3912008-10-28 18:22:59 +0000889 struct usb_ctrltransfer ct;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100890 int ret;
balrogb9dc0332007-10-04 22:47:34 +0000891
Hans de Goede2cc59d82010-11-10 10:06:25 +0100892 if (usb_fs_type == USB_FS_SYS) {
893 char device_name[32], line[1024];
894 int configuration;
895
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200896 sprintf(device_name, "%d-%s", s->bus_num, s->port);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100897
898 if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
899 device_name)) {
900 goto usbdevfs;
901 }
902 if (sscanf(line, "%d", &configuration) != 1) {
903 goto usbdevfs;
904 }
905 return configuration;
906 }
907
908usbdevfs:
balrogb9dc0332007-10-04 22:47:34 +0000909 ct.bRequestType = USB_DIR_IN;
910 ct.bRequest = USB_REQ_GET_CONFIGURATION;
911 ct.wValue = 0;
912 ct.wIndex = 0;
913 ct.wLength = 1;
914 ct.data = &configuration;
915 ct.timeout = 50;
916
917 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
918 if (ret < 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100919 perror("usb_linux_get_configuration");
920 return -1;
balrogb9dc0332007-10-04 22:47:34 +0000921 }
922
923 /* in address state */
David Ahern27911042010-04-24 10:26:22 -0600924 if (configuration == 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100925 return -1;
David Ahern27911042010-04-24 10:26:22 -0600926 }
balrogb9dc0332007-10-04 22:47:34 +0000927
Hans de Goede71d71bb2010-11-10 10:06:24 +0100928 return configuration;
929}
930
Hans de Goedeed3a3282010-11-24 12:50:00 +0100931static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
932 uint8_t configuration, uint8_t interface)
933{
934 uint8_t alt_setting;
935 struct usb_ctrltransfer ct;
936 int ret;
937
Hans de Goedec43831f2010-11-24 12:57:59 +0100938 if (usb_fs_type == USB_FS_SYS) {
939 char device_name[64], line[1024];
940 int alt_setting;
941
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200942 sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
Hans de Goedec43831f2010-11-24 12:57:59 +0100943 (int)configuration, (int)interface);
944
945 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
946 device_name)) {
947 goto usbdevfs;
948 }
949 if (sscanf(line, "%d", &alt_setting) != 1) {
950 goto usbdevfs;
951 }
952 return alt_setting;
953 }
954
955usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +0100956 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
957 ct.bRequest = USB_REQ_GET_INTERFACE;
958 ct.wValue = 0;
959 ct.wIndex = interface;
960 ct.wLength = 1;
961 ct.data = &alt_setting;
962 ct.timeout = 50;
963 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
964 if (ret < 0) {
965 /* Assume alt 0 on error */
966 return 0;
967 }
968
969 return alt_setting;
970}
971
Hans de Goede71d71bb2010-11-10 10:06:24 +0100972/* returns 1 on problem encountered or 0 for success */
973static int usb_linux_update_endp_table(USBHostDevice *s)
974{
975 uint8_t *descriptors;
976 uint8_t devep, type, configuration, alt_interface;
Hans de Goedeed3a3282010-11-24 12:50:00 +0100977 int interface, length, i;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100978
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100979 for (i = 0; i < MAX_ENDPOINTS; i++)
980 s->endp_table[i].type = INVALID_EP_TYPE;
981
Hans de Goede71d71bb2010-11-10 10:06:24 +0100982 i = usb_linux_get_configuration(s);
983 if (i < 0)
984 return 1;
985 configuration = i;
986
balrogb9dc0332007-10-04 22:47:34 +0000987 /* get the desired configuration, interface, and endpoint descriptors
988 * from device description */
989 descriptors = &s->descr[18];
990 length = s->descr_len - 18;
991 i = 0;
992
993 if (descriptors[i + 1] != USB_DT_CONFIG ||
994 descriptors[i + 5] != configuration) {
malcd0f2c4c2010-02-07 02:03:50 +0300995 DPRINTF("invalid descriptor data - configuration\n");
balrogb9dc0332007-10-04 22:47:34 +0000996 return 1;
997 }
998 i += descriptors[i];
999
1000 while (i < length) {
1001 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1002 (descriptors[i + 1] == USB_DT_INTERFACE &&
1003 descriptors[i + 4] == 0)) {
1004 i += descriptors[i];
1005 continue;
1006 }
1007
1008 interface = descriptors[i + 2];
Hans de Goedeed3a3282010-11-24 12:50:00 +01001009 alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
balrogb9dc0332007-10-04 22:47:34 +00001010
1011 /* the current interface descriptor is the active interface
1012 * and has endpoints */
1013 if (descriptors[i + 3] != alt_interface) {
1014 i += descriptors[i];
1015 continue;
1016 }
1017
1018 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001019 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001020 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001021 }
balrogb9dc0332007-10-04 22:47:34 +00001022
1023 if (i >= length)
1024 break;
1025
1026 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001027 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001028 break;
David Ahern27911042010-04-24 10:26:22 -06001029 }
balrogb9dc0332007-10-04 22:47:34 +00001030
1031 devep = descriptors[i + 2];
1032 switch (descriptors[i + 3] & 0x3) {
1033 case 0x00:
1034 type = USBDEVFS_URB_TYPE_CONTROL;
1035 break;
1036 case 0x01:
1037 type = USBDEVFS_URB_TYPE_ISO;
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +02001038 set_max_packet_size(s, (devep & 0xf), descriptors + i);
balrogb9dc0332007-10-04 22:47:34 +00001039 break;
1040 case 0x02:
1041 type = USBDEVFS_URB_TYPE_BULK;
1042 break;
1043 case 0x03:
1044 type = USBDEVFS_URB_TYPE_INTERRUPT;
1045 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -05001046 default:
1047 DPRINTF("usb_host: malformed endpoint type\n");
1048 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +00001049 }
1050 s->endp_table[(devep & 0xf) - 1].type = type;
aliguori64838172008-08-21 19:31:10 +00001051 s->endp_table[(devep & 0xf) - 1].halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001052
1053 i += descriptors[i];
1054 }
1055 }
1056 return 0;
1057}
1058
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001059static int usb_host_open(USBHostDevice *dev, int bus_num,
Hans de Goede3991c352011-05-31 11:35:18 +02001060 int addr, char *port, const char *prod_name, int speed)
bellardbb36d472005-11-05 14:22:28 +00001061{
balrogb9dc0332007-10-04 22:47:34 +00001062 int fd = -1, ret;
bellarda594cfb2005-11-06 16:13:29 +00001063 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001064
David Ahern27911042010-04-24 10:26:22 -06001065 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001066 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001067 }
aliguori64838172008-08-21 19:31:10 +00001068 printf("husb: open device %d.%d\n", bus_num, addr);
aliguori1f3870a2008-08-21 19:27:48 +00001069
aliguori0f431522008-10-07 20:06:37 +00001070 if (!usb_host_device_path) {
1071 perror("husb: USB Host Device Path not set");
1072 goto fail;
1073 }
1074 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001075 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001076 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001077 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001078 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001079 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001080 }
malcd0f2c4c2010-02-07 02:03:50 +03001081 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001082
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001083 dev->bus_num = bus_num;
1084 dev->addr = addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001085 strcpy(dev->port, port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001086 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001087
balrogb9dc0332007-10-04 22:47:34 +00001088 /* read the device description */
1089 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1090 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001091 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001092 goto fail;
1093 }
ths3b46e622007-09-17 08:09:54 +00001094
balrogb9dc0332007-10-04 22:47:34 +00001095#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001096 {
balrogb9dc0332007-10-04 22:47:34 +00001097 int x;
1098 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001099 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001100 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001101 }
balrogb9dc0332007-10-04 22:47:34 +00001102 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001103 }
1104#endif
1105
balrogb9dc0332007-10-04 22:47:34 +00001106
David Ahern27911042010-04-24 10:26:22 -06001107 /*
1108 * Initial configuration is -1 which makes us claim first
aliguori446ab122008-09-14 01:06:09 +00001109 * available config. We used to start with 1, which does not
David Ahern27911042010-04-24 10:26:22 -06001110 * always work. I've seen devices where first config starts
aliguori446ab122008-09-14 01:06:09 +00001111 * with 2.
1112 */
David Ahern27911042010-04-24 10:26:22 -06001113 if (!usb_host_claim_interfaces(dev, -1)) {
balrogb9dc0332007-10-04 22:47:34 +00001114 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001115 }
bellardbb36d472005-11-05 14:22:28 +00001116
balrogb9dc0332007-10-04 22:47:34 +00001117 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001118 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001119 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001120 }
balrogb9dc0332007-10-04 22:47:34 +00001121
Hans de Goede3991c352011-05-31 11:35:18 +02001122 if (speed == -1) {
1123 struct usbdevfs_connectinfo ci;
1124
1125 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1126 if (ret < 0) {
1127 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
1128 goto fail;
1129 }
1130
1131 if (ci.slow) {
1132 speed = USB_SPEED_LOW;
1133 } else {
1134 speed = USB_SPEED_HIGH;
1135 }
David Ahern27911042010-04-24 10:26:22 -06001136 }
Hans de Goede3991c352011-05-31 11:35:18 +02001137 dev->dev.speed = speed;
1138
1139 printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001140
David Ahern27911042010-04-24 10:26:22 -06001141 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001142 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001143 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001144 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001145 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001146 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001147 }
bellard1f6e24e2006-06-26 21:00:51 +00001148
aliguori64838172008-08-21 19:31:10 +00001149 /* USB devio uses 'write' flag to check for async completions */
1150 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001151
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001152 usb_device_attach(&dev->dev);
1153 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001154
balrogb9dc0332007-10-04 22:47:34 +00001155fail:
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001156 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001157 if (fd != -1) {
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001158 close(fd);
David Ahern27911042010-04-24 10:26:22 -06001159 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001160 return -1;
1161}
1162
1163static int usb_host_close(USBHostDevice *dev)
1164{
Hans de Goede060dc842010-11-26 11:41:08 +01001165 int i;
1166
David Ahern27911042010-04-24 10:26:22 -06001167 if (dev->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001168 return -1;
David Ahern27911042010-04-24 10:26:22 -06001169 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001170
1171 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1172 dev->closing = 1;
Hans de Goede3a4854b2010-11-26 15:02:16 +01001173 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +01001174 if (is_isoc(dev, i)) {
1175 usb_host_stop_n_free_iso(dev, i);
1176 }
1177 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001178 async_complete(dev);
1179 dev->closing = 0;
1180 usb_device_detach(&dev->dev);
Shahar Havivi00ff2272010-06-16 15:15:37 +03001181 ioctl(dev->fd, USBDEVFS_RESET);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001182 close(dev->fd);
1183 dev->fd = -1;
1184 return 0;
1185}
1186
Shahar Havivib373a632010-06-16 15:16:11 +03001187static void usb_host_exit_notifier(struct Notifier* n)
1188{
1189 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1190
1191 if (s->fd != -1) {
1192 ioctl(s->fd, USBDEVFS_RESET);
1193 }
1194}
1195
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001196static int usb_host_initfn(USBDevice *dev)
1197{
1198 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1199
1200 dev->auto_attach = 0;
1201 s->fd = -1;
1202 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001203 s->exit.notify = usb_host_exit_notifier;
1204 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001205 usb_host_auto_check(NULL);
1206 return 0;
bellardbb36d472005-11-05 14:22:28 +00001207}
1208
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001209static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001210 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001211 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001212 .qdev.size = sizeof(USBHostDevice),
1213 .init = usb_host_initfn,
Hans de Goede50b79632011-02-02 17:36:29 +01001214 .handle_packet = usb_generic_handle_packet,
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +02001215 .cancel_packet = usb_host_async_cancel,
Hans de Goede50b79632011-02-02 17:36:29 +01001216 .handle_data = usb_host_handle_data,
1217 .handle_control = usb_host_handle_control,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001218 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001219 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001220 .usbdevice_name = "host",
1221 .usbdevice_init = usb_host_device_open,
1222 .qdev.props = (Property[]) {
1223 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1224 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001225 DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001226 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1227 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
1228 DEFINE_PROP_END_OF_LIST(),
1229 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001230};
1231
1232static void usb_host_register_devices(void)
1233{
1234 usb_qdev_register(&usb_host_dev_info);
1235}
1236device_init(usb_host_register_devices)
1237
aliguori4b096fc2008-08-21 19:28:55 +00001238USBDevice *usb_host_device_open(const char *devname)
1239{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001240 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001241 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001242 char *p;
1243
Markus Armbruster556cd092009-12-09 17:07:53 +01001244 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001245
aliguori5d0c5752008-09-14 01:07:41 +00001246 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001247 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001248 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001249 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001250 } else {
1251 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001252 filter.bus_num = strtoul(devname, NULL, 0);
1253 filter.addr = strtoul(p + 1, NULL, 0);
1254 filter.vendor_id = 0;
1255 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001256 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001257 filter.bus_num = 0;
1258 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001259 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001260 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001261 } else {
1262 goto fail;
1263 }
aliguori5d0c5752008-09-14 01:07:41 +00001264 }
1265
Markus Armbruster0745eb12009-11-27 13:05:53 +01001266 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1267 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001268 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1269 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001270 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001271 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001272
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001273fail:
1274 qdev_free(&dev->qdev);
1275 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001276}
aliguori5d0c5752008-09-14 01:07:41 +00001277
1278int usb_host_device_close(const char *devname)
1279{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001280#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001281 char product_name[PRODUCT_NAME_SZ];
1282 int bus_num, addr;
1283 USBHostDevice *s;
1284
David Ahern27911042010-04-24 10:26:22 -06001285 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001286 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001287 }
1288 if (usb_host_find_device(&bus_num, &addr, product_name,
1289 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001290 return -1;
David Ahern27911042010-04-24 10:26:22 -06001291 }
aliguori5d0c5752008-09-14 01:07:41 +00001292 s = hostdev_find(bus_num, addr);
1293 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001294 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001295 return 0;
1296 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001297#endif
aliguori5d0c5752008-09-14 01:07:41 +00001298
1299 return -1;
1300}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001301
bellarda594cfb2005-11-06 16:13:29 +00001302static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001303 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001304 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001305{
bellarda594cfb2005-11-06 16:13:29 +00001306 const char *p;
1307 char *q;
1308 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001309 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001310 return -1;
David Ahern27911042010-04-24 10:26:22 -06001311 }
bellarda594cfb2005-11-06 16:13:29 +00001312 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001313 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001314 p++;
David Ahern27911042010-04-24 10:26:22 -06001315 }
bellarda594cfb2005-11-06 16:13:29 +00001316 q = buf;
1317 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001318 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001319 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001320 }
bellarda594cfb2005-11-06 16:13:29 +00001321 p++;
1322 }
1323 *q = '\0';
1324 return q - buf;
1325}
bellardbb36d472005-11-05 14:22:28 +00001326
aliguori0f431522008-10-07 20:06:37 +00001327/*
1328 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1329 * host's USB devices. This is legacy support since many distributions
1330 * are moving to /sys/bus/usb
1331 */
1332static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001333{
Blue Swirl660f11b2009-07-31 21:16:51 +00001334 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001335 char line[1024];
1336 char buf[1024];
1337 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
bellarda594cfb2005-11-06 16:13:29 +00001338 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001339 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001340
aliguori0f431522008-10-07 20:06:37 +00001341 if (!usb_host_device_path) {
1342 perror("husb: USB Host Device Path not set");
1343 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001344 }
aliguori0f431522008-10-07 20:06:37 +00001345 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1346 f = fopen(line, "r");
1347 if (!f) {
1348 perror("husb: cannot open devices file");
1349 goto the_end;
1350 }
1351
bellarda594cfb2005-11-06 16:13:29 +00001352 device_count = 0;
Hans de Goede3991c352011-05-31 11:35:18 +02001353 bus_num = addr = class_id = product_id = vendor_id = 0;
1354 speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
bellardbb36d472005-11-05 14:22:28 +00001355 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001356 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001357 break;
David Ahern27911042010-04-24 10:26:22 -06001358 }
1359 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001360 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001361 }
bellarda594cfb2005-11-06 16:13:29 +00001362 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001363 if (device_count && (vendor_id || product_id)) {
1364 /* New device. Add the previously discovered device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001365 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001366 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001367 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001368 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001369 }
bellarda594cfb2005-11-06 16:13:29 +00001370 }
David Ahern27911042010-04-24 10:26:22 -06001371 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001372 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001373 }
bellarda594cfb2005-11-06 16:13:29 +00001374 bus_num = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001375 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001376 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001377 }
bellarda594cfb2005-11-06 16:13:29 +00001378 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001379 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001380 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001381 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001382 if (!strcmp(buf, "5000")) {
1383 speed = USB_SPEED_SUPER;
1384 } else if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001385 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001386 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001387 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001388 } else {
bellarda594cfb2005-11-06 16:13:29 +00001389 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001390 }
bellarda594cfb2005-11-06 16:13:29 +00001391 product_name[0] = '\0';
1392 class_id = 0xff;
1393 device_count++;
1394 product_id = 0;
1395 vendor_id = 0;
1396 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001397 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001398 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001399 }
bellarda594cfb2005-11-06 16:13:29 +00001400 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001401 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001402 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001403 }
bellarda594cfb2005-11-06 16:13:29 +00001404 product_id = strtoul(buf, NULL, 16);
1405 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001406 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001407 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001408 }
bellarda594cfb2005-11-06 16:13:29 +00001409 pstrcpy(product_name, sizeof(product_name), buf);
1410 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001411 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001412 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001413 }
bellarda594cfb2005-11-06 16:13:29 +00001414 class_id = strtoul(buf, NULL, 16);
1415 }
1416 fail: ;
1417 }
pbrook38ca0f62006-03-11 18:03:38 +00001418 if (device_count && (vendor_id || product_id)) {
1419 /* Add the last device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001420 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001421 product_id, product_name, speed);
1422 }
1423 the_end:
David Ahern27911042010-04-24 10:26:22 -06001424 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001425 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001426 }
aliguori0f431522008-10-07 20:06:37 +00001427 return ret;
1428}
1429
1430/*
1431 * Read sys file-system device file
1432 *
1433 * @line address of buffer to put file contents in
1434 * @line_size size of line
1435 * @device_file path to device file (printf format string)
1436 * @device_name device being opened (inserted into device_file)
1437 *
1438 * @return 0 failed, 1 succeeded ('line' contains data)
1439 */
David Ahern27911042010-04-24 10:26:22 -06001440static int usb_host_read_file(char *line, size_t line_size,
1441 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001442{
1443 FILE *f;
1444 int ret = 0;
1445 char filename[PATH_MAX];
1446
blueswir1b4e237a2008-12-28 15:45:20 +00001447 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1448 device_file);
aliguori0f431522008-10-07 20:06:37 +00001449 f = fopen(filename, "r");
1450 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001451 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001452 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001453 }
1454
1455 return ret;
1456}
1457
1458/*
1459 * Use /sys/bus/usb/devices/ directory to determine host's USB
1460 * devices.
1461 *
1462 * This code is based on Robert Schiele's original patches posted to
1463 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1464 */
1465static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1466{
Blue Swirl660f11b2009-07-31 21:16:51 +00001467 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001468 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001469 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001470 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001471 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001472 char product_name[512];
1473 struct dirent *de;
1474
1475 dir = opendir(USBSYSBUS_PATH "/devices");
1476 if (!dir) {
1477 perror("husb: cannot open devices directory");
1478 goto the_end;
1479 }
1480
1481 while ((de = readdir(dir))) {
1482 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001483 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1484 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001485 }
aliguori0f431522008-10-07 20:06:37 +00001486
David Ahern27911042010-04-24 10:26:22 -06001487 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001488 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001489 }
1490 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001491 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001492 }
blueswir1b4e237a2008-12-28 15:45:20 +00001493 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001494 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001495 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001496 }
1497 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001498 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001499 }
aliguori0f431522008-10-07 20:06:37 +00001500
David Ahern27911042010-04-24 10:26:22 -06001501 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1502 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001503 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001504 }
1505 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001506 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001507 }
blueswir1b4e237a2008-12-28 15:45:20 +00001508 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001509 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001510 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001511 }
1512 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001513 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001514 }
blueswir1b4e237a2008-12-28 15:45:20 +00001515 if (!usb_host_read_file(line, sizeof(line), "product",
1516 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001517 *product_name = 0;
1518 } else {
David Ahern27911042010-04-24 10:26:22 -06001519 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001520 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001521 }
aliguori0f431522008-10-07 20:06:37 +00001522 pstrcpy(product_name, sizeof(product_name), line);
1523 }
1524
David Ahern27911042010-04-24 10:26:22 -06001525 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001526 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001527 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001528 if (!strcmp(line, "5000\n")) {
1529 speed = USB_SPEED_SUPER;
1530 } else if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001531 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001532 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001533 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001534 } else {
aliguori0f431522008-10-07 20:06:37 +00001535 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001536 }
aliguori0f431522008-10-07 20:06:37 +00001537
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001538 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001539 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001540 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001541 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001542 }
aliguori0f431522008-10-07 20:06:37 +00001543 }
1544 }
1545 the_end:
David Ahern27911042010-04-24 10:26:22 -06001546 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001547 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001548 }
aliguori0f431522008-10-07 20:06:37 +00001549 return ret;
1550}
1551
1552/*
1553 * Determine how to access the host's USB devices and call the
1554 * specific support function.
1555 */
1556static int usb_host_scan(void *opaque, USBScanFunc *func)
1557{
aliguori376253e2009-03-05 23:01:23 +00001558 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001559 FILE *f = NULL;
1560 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001561 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001562 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1563 char devpath[PATH_MAX];
1564
1565 /* only check the host once */
1566 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001567 dir = opendir(USBSYSBUS_PATH "/devices");
1568 if (dir) {
1569 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1570 strcpy(devpath, USBDEVBUS_PATH);
1571 usb_fs_type = USB_FS_SYS;
1572 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001573 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001574 goto found_devices;
1575 }
aliguori0f431522008-10-07 20:06:37 +00001576 f = fopen(USBPROCBUS_PATH "/devices", "r");
1577 if (f) {
1578 /* devices found in /proc/bus/usb/ */
1579 strcpy(devpath, USBPROCBUS_PATH);
1580 usb_fs_type = USB_FS_PROC;
1581 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001582 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001583 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001584 }
1585 /* try additional methods if an access method hasn't been found yet */
1586 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001587 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001588 /* devices found in /dev/bus/usb/ */
1589 strcpy(devpath, USBDEVBUS_PATH);
1590 usb_fs_type = USB_FS_DEV;
1591 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001592 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001593 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001594 }
aliguorif16a0db2008-10-21 16:34:20 +00001595 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001596 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001597 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001598 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001599 }
aliguorif16a0db2008-10-21 16:34:20 +00001600 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001601 }
1602
1603 /* the module setting (used later for opening devices) */
1604 usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001605 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001606 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001607 monitor_printf(mon, "husb: using %s file-system with %s\n",
1608 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001609 }
aliguori0f431522008-10-07 20:06:37 +00001610 }
1611
1612 switch (usb_fs_type) {
1613 case USB_FS_PROC:
1614 case USB_FS_DEV:
1615 ret = usb_host_scan_dev(opaque, func);
1616 break;
1617 case USB_FS_SYS:
1618 ret = usb_host_scan_sys(opaque, func);
1619 break;
aliguorif16a0db2008-10-21 16:34:20 +00001620 default:
1621 ret = -EINVAL;
1622 break;
aliguori0f431522008-10-07 20:06:37 +00001623 }
bellarda594cfb2005-11-06 16:13:29 +00001624 return ret;
1625}
1626
aliguori4b096fc2008-08-21 19:28:55 +00001627static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001628
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001629static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001630 int class_id, int vendor_id, int product_id,
1631 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001632{
1633 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001634 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001635
1636 /* Ignore hubs */
1637 if (class_id == 9)
1638 return 0;
1639
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001640 QTAILQ_FOREACH(s, &hostdevs, next) {
1641 f = &s->match;
1642
David Ahern27911042010-04-24 10:26:22 -06001643 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001644 continue;
David Ahern27911042010-04-24 10:26:22 -06001645 }
1646 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001647 continue;
David Ahern27911042010-04-24 10:26:22 -06001648 }
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001649 if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
1650 continue;
1651 }
aliguori4b096fc2008-08-21 19:28:55 +00001652
David Ahern27911042010-04-24 10:26:22 -06001653 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001654 continue;
David Ahern27911042010-04-24 10:26:22 -06001655 }
aliguori4b096fc2008-08-21 19:28:55 +00001656
David Ahern27911042010-04-24 10:26:22 -06001657 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001658 continue;
David Ahern27911042010-04-24 10:26:22 -06001659 }
aliguori4b096fc2008-08-21 19:28:55 +00001660 /* We got a match */
1661
Markus Armbruster33e66b82009-10-07 01:15:57 +02001662 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001663 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001664 return 0;
David Ahern27911042010-04-24 10:26:22 -06001665 }
malcd0f2c4c2010-02-07 02:03:50 +03001666 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001667
Hans de Goede3991c352011-05-31 11:35:18 +02001668 usb_host_open(s, bus_num, addr, port, product_name, speed);
aliguori4b096fc2008-08-21 19:28:55 +00001669 }
1670
1671 return 0;
1672}
1673
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001674static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001675{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001676 struct USBHostDevice *s;
1677 int unconnected = 0;
1678
aliguori4b096fc2008-08-21 19:28:55 +00001679 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001680
1681 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001682 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001683 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001684 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001685 }
1686
1687 if (unconnected == 0) {
1688 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001689 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001690 qemu_del_timer(usb_auto_timer);
David Ahern27911042010-04-24 10:26:22 -06001691 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001692 return;
1693 }
1694
1695 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001696 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001697 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001698 return;
David Ahern27911042010-04-24 10:26:22 -06001699 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001700 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001701 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001702}
1703
1704/*
aliguori5d0c5752008-09-14 01:07:41 +00001705 * Autoconnect filter
1706 * Format:
1707 * auto:bus:dev[:vid:pid]
1708 * auto:bus.dev[:vid:pid]
1709 *
1710 * bus - bus number (dec, * means any)
1711 * dev - device number (dec, * means any)
1712 * vid - vendor id (hex, * means any)
1713 * pid - product id (hex, * means any)
1714 *
1715 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001716 */
aliguori5d0c5752008-09-14 01:07:41 +00001717static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001718{
aliguori5d0c5752008-09-14 01:07:41 +00001719 enum { BUS, DEV, VID, PID, DONE };
1720 const char *p = spec;
1721 int i;
1722
Markus Armbruster0745eb12009-11-27 13:05:53 +01001723 f->bus_num = 0;
1724 f->addr = 0;
1725 f->vendor_id = 0;
1726 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001727
1728 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001729 p = strpbrk(p, ":.");
1730 if (!p) {
1731 break;
1732 }
aliguori5d0c5752008-09-14 01:07:41 +00001733 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001734
David Ahern27911042010-04-24 10:26:22 -06001735 if (*p == '*') {
1736 continue;
1737 }
aliguori5d0c5752008-09-14 01:07:41 +00001738 switch(i) {
1739 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1740 case DEV: f->addr = strtol(p, NULL, 10); break;
1741 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1742 case PID: f->product_id = strtol(p, NULL, 16); break;
1743 }
aliguori4b096fc2008-08-21 19:28:55 +00001744 }
1745
aliguori5d0c5752008-09-14 01:07:41 +00001746 if (i < DEV) {
1747 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1748 return -1;
1749 }
1750
1751 return 0;
1752}
1753
bellarda594cfb2005-11-06 16:13:29 +00001754/**********************/
1755/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001756
bellarda594cfb2005-11-06 16:13:29 +00001757struct usb_class_info {
1758 int class;
1759 const char *class_name;
1760};
1761
1762static const struct usb_class_info usb_class_info[] = {
1763 { USB_CLASS_AUDIO, "Audio"},
1764 { USB_CLASS_COMM, "Communication"},
1765 { USB_CLASS_HID, "HID"},
1766 { USB_CLASS_HUB, "Hub" },
1767 { USB_CLASS_PHYSICAL, "Physical" },
1768 { USB_CLASS_PRINTER, "Printer" },
1769 { USB_CLASS_MASS_STORAGE, "Storage" },
1770 { USB_CLASS_CDC_DATA, "Data" },
1771 { USB_CLASS_APP_SPEC, "Application Specific" },
1772 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1773 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001774 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001775 { USB_CLASS_CONTENT_SEC, "Content Security" },
1776 { -1, NULL }
1777};
1778
1779static const char *usb_class_str(uint8_t class)
1780{
1781 const struct usb_class_info *p;
1782 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001783 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001784 break;
David Ahern27911042010-04-24 10:26:22 -06001785 }
bellardbb36d472005-11-05 14:22:28 +00001786 }
bellarda594cfb2005-11-06 16:13:29 +00001787 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001788}
1789
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001790static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
1791 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00001792 const char *product_name,
1793 int speed)
bellardbb36d472005-11-05 14:22:28 +00001794{
bellarda594cfb2005-11-06 16:13:29 +00001795 const char *class_str, *speed_str;
1796
1797 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001798 case USB_SPEED_LOW:
1799 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001800 break;
ths5fafdf22007-09-16 21:08:06 +00001801 case USB_SPEED_FULL:
1802 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001803 break;
ths5fafdf22007-09-16 21:08:06 +00001804 case USB_SPEED_HIGH:
1805 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001806 break;
Hans de Goedef264cfb2011-05-31 11:35:19 +02001807 case USB_SPEED_SUPER:
1808 speed_str = "5000";
1809 break;
bellarda594cfb2005-11-06 16:13:29 +00001810 default:
ths5fafdf22007-09-16 21:08:06 +00001811 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001812 break;
bellardbb36d472005-11-05 14:22:28 +00001813 }
bellarda594cfb2005-11-06 16:13:29 +00001814
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001815 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
1816 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00001817 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001818 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001819 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001820 } else {
aliguori376253e2009-03-05 23:01:23 +00001821 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001822 }
aliguori376253e2009-03-05 23:01:23 +00001823 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001824 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001825 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001826 }
aliguori376253e2009-03-05 23:01:23 +00001827 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001828}
1829
ths5fafdf22007-09-16 21:08:06 +00001830static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001831 char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001832 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001833 const char *product_name,
1834 int speed)
1835{
Blue Swirl179da8a2009-09-07 19:00:18 +00001836 Monitor *mon = opaque;
1837
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001838 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001839 product_name, speed);
1840 return 0;
1841}
1842
aliguoriac4ffb52008-09-22 15:04:31 +00001843static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001844{
David Ahern27911042010-04-24 10:26:22 -06001845 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001846 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001847 } else {
1848 snprintf(str, size, "%d", val);
1849 }
aliguori5d0c5752008-09-14 01:07:41 +00001850}
1851
aliguoriac4ffb52008-09-22 15:04:31 +00001852static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001853{
David Ahern27911042010-04-24 10:26:22 -06001854 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001855 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001856 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001857 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06001858 }
aliguori5d0c5752008-09-14 01:07:41 +00001859}
1860
aliguori376253e2009-03-05 23:01:23 +00001861void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00001862{
aliguori5d0c5752008-09-14 01:07:41 +00001863 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001864 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00001865
Blue Swirl179da8a2009-09-07 19:00:18 +00001866 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00001867
David Ahern27911042010-04-24 10:26:22 -06001868 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001869 return;
David Ahern27911042010-04-24 10:26:22 -06001870 }
1871
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001872 monitor_printf(mon, " Auto filters:\n");
1873 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00001874 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001875 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00001876 dec2str(f->bus_num, bus, sizeof(bus));
1877 dec2str(f->addr, addr, sizeof(addr));
1878 hex2str(f->vendor_id, vid, sizeof(vid));
1879 hex2str(f->product_id, pid, sizeof(pid));
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001880 monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
1881 bus, addr, f->port ? f->port : "*", vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00001882 }
bellardbb36d472005-11-05 14:22:28 +00001883}