blob: ed1d56add7fe867b28e7837c21a954f2b716cc64 [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) {
balrogb9dc0332007-10-04 22:47:34 +0000379 goto fail;
David Ahern27911042010-04-24 10:26:22 -0600380 }
balrogb9dc0332007-10-04 22:47:34 +0000381
382 i += dev_descr_len;
383 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600384 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
385 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000386 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000387
balrogb9dc0332007-10-04 22:47:34 +0000388 if (dev->descr[i+1] != USB_DT_CONFIG) {
389 i += dev->descr[i];
390 continue;
391 }
392 config_descr_len = dev->descr[i];
393
David Ahern27911042010-04-24 10:26:22 -0600394 printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000395
aliguori446ab122008-09-14 01:06:09 +0000396 if (configuration < 0 || configuration == dev->descr[i + 5]) {
397 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000398 break;
aliguori446ab122008-09-14 01:06:09 +0000399 }
balrogb9dc0332007-10-04 22:47:34 +0000400
401 i += config_descr_len;
402 }
403
404 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600405 fprintf(stderr,
406 "husb: update iface failed. no matching configuration\n");
balrogb9dc0332007-10-04 22:47:34 +0000407 goto fail;
408 }
409 nb_interfaces = dev->descr[i + 4];
410
411#ifdef USBDEVFS_DISCONNECT
412 /* earlier Linux 2.4 do not support that */
413 {
414 struct usbdevfs_ioctl ctrl;
415 for (interface = 0; interface < nb_interfaces; interface++) {
416 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
417 ctrl.ifno = interface;
Brad Hards021730f2011-04-13 19:45:32 +1000418 ctrl.data = 0;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200419 op = "USBDEVFS_DISCONNECT";
balrogb9dc0332007-10-04 22:47:34 +0000420 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
421 if (ret < 0 && errno != ENODATA) {
balrogb9dc0332007-10-04 22:47:34 +0000422 goto fail;
423 }
424 }
425 }
426#endif
427
428 /* XXX: only grab if all interfaces are free */
429 for (interface = 0; interface < nb_interfaces; interface++) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200430 op = "USBDEVFS_CLAIMINTERFACE";
balrogb9dc0332007-10-04 22:47:34 +0000431 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
432 if (ret < 0) {
433 if (errno == EBUSY) {
aliguori64838172008-08-21 19:31:10 +0000434 printf("husb: update iface. device already grabbed\n");
balrogb9dc0332007-10-04 22:47:34 +0000435 } else {
aliguori64838172008-08-21 19:31:10 +0000436 perror("husb: failed to claim interface");
balrogb9dc0332007-10-04 22:47:34 +0000437 }
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200438 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000439 }
440 }
441
aliguori64838172008-08-21 19:31:10 +0000442 printf("husb: %d interfaces claimed for configuration %d\n",
balrogb9dc0332007-10-04 22:47:34 +0000443 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000444
aliguori446ab122008-09-14 01:06:09 +0000445 dev->ninterfaces = nb_interfaces;
446 dev->configuration = configuration;
447 return 1;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200448
449fail:
450 if (errno == ENODEV) {
451 do_disconnect(dev);
452 }
453 perror(op);
454 return 0;
aliguori446ab122008-09-14 01:06:09 +0000455}
456
457static int usb_host_release_interfaces(USBHostDevice *s)
458{
459 int ret, i;
460
malcd0f2c4c2010-02-07 02:03:50 +0300461 DPRINTF("husb: releasing interfaces\n");
aliguori446ab122008-09-14 01:06:09 +0000462
463 for (i = 0; i < s->ninterfaces; i++) {
464 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
465 if (ret < 0) {
466 perror("husb: failed to release interface");
467 return 0;
468 }
469 }
470
balrogb9dc0332007-10-04 22:47:34 +0000471 return 1;
472}
473
bellard059809e2006-07-19 18:06:15 +0000474static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000475{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100476 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000477
malcd0f2c4c2010-02-07 02:03:50 +0300478 DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000479
bellardbb36d472005-11-05 14:22:28 +0000480 ioctl(s->fd, USBDEVFS_RESET);
aliguori446ab122008-09-14 01:06:09 +0000481
482 usb_host_claim_interfaces(s, s->configuration);
ths5fafdf22007-09-16 21:08:06 +0000483}
bellardbb36d472005-11-05 14:22:28 +0000484
bellard059809e2006-07-19 18:06:15 +0000485static void usb_host_handle_destroy(USBDevice *dev)
486{
487 USBHostDevice *s = (USBHostDevice *)dev;
488
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100489 usb_host_close(s);
490 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300491 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000492}
493
balrogb9dc0332007-10-04 22:47:34 +0000494static int usb_linux_update_endp_table(USBHostDevice *s);
495
Hans de Goede060dc842010-11-26 11:41:08 +0100496/* iso data is special, we need to keep enough urbs in flight to make sure
497 that the controller never runs out of them, otherwise the device will
498 likely suffer a buffer underrun / overrun. */
499static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
500{
501 AsyncURB *aurb;
502 int i, j, len = get_max_packet_size(s, ep);
503
504 aurb = qemu_mallocz(ISO_URB_COUNT * sizeof(*aurb));
505 for (i = 0; i < ISO_URB_COUNT; i++) {
506 aurb[i].urb.endpoint = ep;
507 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
508 aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length);
509 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
510 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
511 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
512 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
513 aurb[i].urb.iso_frame_desc[j].length = len;
514 if (in) {
515 aurb[i].urb.endpoint |= 0x80;
516 /* Mark as fully consumed (idle) */
517 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
518 }
519 }
520 set_iso_urb(s, ep, aurb);
521
522 return aurb;
523}
524
525static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
526{
527 AsyncURB *aurb;
528 int i, ret, killed = 0, free = 1;
529
530 aurb = get_iso_urb(s, ep);
531 if (!aurb) {
532 return;
533 }
534
535 for (i = 0; i < ISO_URB_COUNT; i++) {
536 /* in flight? */
537 if (aurb[i].iso_frame_idx == -1) {
538 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
539 if (ret < 0) {
540 printf("husb: discard isoc in urb failed errno %d\n", errno);
541 free = 0;
542 continue;
543 }
544 killed++;
545 }
546 }
547
548 /* Make sure any urbs we've killed are reaped before we free them */
549 if (killed) {
550 async_complete(s);
551 }
552
553 for (i = 0; i < ISO_URB_COUNT; i++) {
554 qemu_free(aurb[i].urb.buffer);
555 }
556
557 if (free)
558 qemu_free(aurb);
559 else
560 printf("husb: leaking iso urbs because of discard failure\n");
561 set_iso_urb(s, ep, NULL);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100562 set_iso_urb_idx(s, ep, 0);
563 clear_iso_started(s, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100564}
565
566static int urb_status_to_usb_ret(int status)
567{
568 switch (status) {
569 case -EPIPE:
570 return USB_RET_STALL;
571 default:
572 return USB_RET_NAK;
573 }
574}
575
Hans de Goedebb6d5492010-11-26 19:11:03 +0100576static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100577{
578 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100579 int i, j, ret, max_packet_size, offset, len = 0;
Hans de Goede975f2992010-11-26 14:59:35 +0100580
581 max_packet_size = get_max_packet_size(s, p->devep);
582 if (max_packet_size == 0)
583 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100584
585 aurb = get_iso_urb(s, p->devep);
586 if (!aurb) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100587 aurb = usb_host_alloc_iso(s, p->devep, in);
Hans de Goede060dc842010-11-26 11:41:08 +0100588 }
589
590 i = get_iso_urb_idx(s, p->devep);
591 j = aurb[i].iso_frame_idx;
592 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100593 if (in) {
594 /* Check urb status */
595 if (aurb[i].urb.status) {
596 len = urb_status_to_usb_ret(aurb[i].urb.status);
597 /* Move to the next urb */
598 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
599 /* Check frame status */
600 } else if (aurb[i].urb.iso_frame_desc[j].status) {
601 len = urb_status_to_usb_ret(
602 aurb[i].urb.iso_frame_desc[j].status);
603 /* Check the frame fits */
604 } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
605 printf("husb: received iso data is larger then packet\n");
606 len = USB_RET_NAK;
607 /* All good copy data over */
608 } else {
609 len = aurb[i].urb.iso_frame_desc[j].actual_length;
610 memcpy(p->data,
611 aurb[i].urb.buffer +
612 j * aurb[i].urb.iso_frame_desc[0].length,
613 len);
614 }
Hans de Goede060dc842010-11-26 11:41:08 +0100615 } else {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100616 len = p->len;
617 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
618
619 /* Check the frame fits */
620 if (len > max_packet_size) {
621 printf("husb: send iso data is larger then max packet size\n");
622 return USB_RET_NAK;
623 }
624
625 /* All good copy data over */
626 memcpy(aurb[i].urb.buffer + offset, p->data, len);
627 aurb[i].urb.iso_frame_desc[j].length = len;
628 offset += len;
629 set_iso_buffer_used(s, p->devep, offset);
630
631 /* Start the stream once we have buffered enough data */
632 if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
633 set_iso_started(s, p->devep);
634 }
Hans de Goede060dc842010-11-26 11:41:08 +0100635 }
636 aurb[i].iso_frame_idx++;
637 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
638 i = (i + 1) % ISO_URB_COUNT;
639 set_iso_urb_idx(s, p->devep, i);
640 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100641 } else {
642 if (in) {
643 set_iso_started(s, p->devep);
644 } else {
645 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
646 }
Hans de Goede060dc842010-11-26 11:41:08 +0100647 }
648
Hans de Goedebb6d5492010-11-26 19:11:03 +0100649 if (is_iso_started(s, p->devep)) {
650 /* (Re)-submit all fully consumed / filled urbs */
651 for (i = 0; i < ISO_URB_COUNT; i++) {
652 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
653 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
654 if (ret < 0) {
655 printf("husb error submitting iso urb %d: %d\n", i, errno);
656 if (!in || len == 0) {
657 switch(errno) {
658 case ETIMEDOUT:
659 len = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200660 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100661 case EPIPE:
662 default:
663 len = USB_RET_STALL;
664 }
Hans de Goede060dc842010-11-26 11:41:08 +0100665 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100666 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100667 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100668 aurb[i].iso_frame_idx = -1;
Hans de Goede060dc842010-11-26 11:41:08 +0100669 }
Hans de Goede060dc842010-11-26 11:41:08 +0100670 }
671 }
672
673 return len;
674}
675
Hans de Goede50b79632011-02-02 17:36:29 +0100676static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000677{
Hans de Goede50b79632011-02-02 17:36:29 +0100678 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000679 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000680 AsyncURB *aurb;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200681 int ret, rem;
682 uint8_t *pbuf;
Hans de Goede060dc842010-11-26 11:41:08 +0100683 uint8_t ep;
684
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100685 if (!is_valid(s, p->devep)) {
686 return USB_RET_NAK;
687 }
688
Hans de Goede060dc842010-11-26 11:41:08 +0100689 if (p->pid == USB_TOKEN_IN) {
690 ep = p->devep | 0x80;
691 } else {
692 ep = p->devep;
693 }
694
695 if (is_halted(s, p->devep)) {
696 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
697 if (ret < 0) {
698 DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
699 ep, errno);
700 return USB_RET_NAK;
701 }
702 clear_halt(s, p->devep);
703 }
704
Hans de Goedebb6d5492010-11-26 19:11:03 +0100705 if (is_isoc(s, p->devep)) {
706 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
707 }
bellardbb36d472005-11-05 14:22:28 +0000708
Gerd Hoffmann71138532011-05-16 10:21:51 +0200709 rem = p->len;
710 pbuf = p->data;
711 p->len = 0;
712 while (rem) {
713 aurb = async_alloc(s);
714 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000715
Gerd Hoffmann71138532011-05-16 10:21:51 +0200716 urb = &aurb->urb;
717 urb->endpoint = ep;
718 urb->type = USBDEVFS_URB_TYPE_BULK;
719 urb->usercontext = s;
720 urb->buffer = pbuf;
aliguori64838172008-08-21 19:31:10 +0000721
Gerd Hoffmann71138532011-05-16 10:21:51 +0200722 if (rem > MAX_USBFS_BUFFER_SIZE) {
723 urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
724 aurb->more = 1;
725 } else {
726 urb->buffer_length = rem;
727 aurb->more = 0;
728 }
729 pbuf += urb->buffer_length;
730 rem -= urb->buffer_length;
aliguori64838172008-08-21 19:31:10 +0000731
Gerd Hoffmann71138532011-05-16 10:21:51 +0200732 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
aliguori64838172008-08-21 19:31:10 +0000733
Gerd Hoffmann71138532011-05-16 10:21:51 +0200734 DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
735 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
aliguori64838172008-08-21 19:31:10 +0000736
Gerd Hoffmann71138532011-05-16 10:21:51 +0200737 if (ret < 0) {
738 DPRINTF("husb: submit failed. errno %d\n", errno);
739 async_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000740
Gerd Hoffmann71138532011-05-16 10:21:51 +0200741 switch(errno) {
742 case ETIMEDOUT:
743 return USB_RET_NAK;
744 case EPIPE:
745 default:
746 return USB_RET_STALL;
747 }
balrogb9dc0332007-10-04 22:47:34 +0000748 }
749 }
aliguori64838172008-08-21 19:31:10 +0000750
balrogb9dc0332007-10-04 22:47:34 +0000751 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000752}
753
aliguori446ab122008-09-14 01:06:09 +0000754static int ctrl_error(void)
755{
David Ahern27911042010-04-24 10:26:22 -0600756 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000757 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600758 } else {
aliguori446ab122008-09-14 01:06:09 +0000759 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600760 }
aliguori446ab122008-09-14 01:06:09 +0000761}
762
763static int usb_host_set_address(USBHostDevice *s, int addr)
764{
malcd0f2c4c2010-02-07 02:03:50 +0300765 DPRINTF("husb: ctrl set addr %u\n", addr);
aliguori446ab122008-09-14 01:06:09 +0000766 s->dev.addr = addr;
767 return 0;
768}
769
770static int usb_host_set_config(USBHostDevice *s, int config)
771{
772 usb_host_release_interfaces(s);
773
774 int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600775
malcd0f2c4c2010-02-07 02:03:50 +0300776 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600777
778 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000779 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600780 }
aliguori446ab122008-09-14 01:06:09 +0000781 usb_host_claim_interfaces(s, config);
782 return 0;
783}
784
785static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
786{
787 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100788 int i, ret;
789
Hans de Goede3a4854b2010-11-26 15:02:16 +0100790 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100791 if (is_isoc(s, i)) {
792 usb_host_stop_n_free_iso(s, i);
793 }
794 }
aliguori446ab122008-09-14 01:06:09 +0000795
796 si.interface = iface;
797 si.altsetting = alt;
798 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000799
David Ahern27911042010-04-24 10:26:22 -0600800 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
801 iface, alt, ret, errno);
802
803 if (ret < 0) {
804 return ctrl_error();
805 }
aliguori446ab122008-09-14 01:06:09 +0000806 usb_linux_update_endp_table(s);
807 return 0;
808}
809
Hans de Goede50b79632011-02-02 17:36:29 +0100810static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
811 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +0000812{
Hans de Goede50b79632011-02-02 17:36:29 +0100813 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +0000814 struct usbdevfs_urb *urb;
815 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +0100816 int ret;
aliguori446ab122008-09-14 01:06:09 +0000817
David Ahern27911042010-04-24 10:26:22 -0600818 /*
aliguori446ab122008-09-14 01:06:09 +0000819 * Process certain standard device requests.
820 * These are infrequent and are processed synchronously.
821 */
aliguori446ab122008-09-14 01:06:09 +0000822
Hans de Goede50b79632011-02-02 17:36:29 +0100823 /* Note request is (bRequestType << 8) | bRequest */
malcd0f2c4c2010-02-07 02:03:50 +0300824 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 +0100825 request >> 8, request & 0xff, value, index, length);
aliguori446ab122008-09-14 01:06:09 +0000826
Hans de Goede50b79632011-02-02 17:36:29 +0100827 switch (request) {
828 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
829 return usb_host_set_address(s, value);
aliguori446ab122008-09-14 01:06:09 +0000830
Hans de Goede50b79632011-02-02 17:36:29 +0100831 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
832 return usb_host_set_config(s, value & 0xff);
aliguori446ab122008-09-14 01:06:09 +0000833
Hans de Goede50b79632011-02-02 17:36:29 +0100834 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
aliguori446ab122008-09-14 01:06:09 +0000835 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -0600836 }
aliguori446ab122008-09-14 01:06:09 +0000837
838 /* The rest are asynchronous */
839
Hans de Goede50b79632011-02-02 17:36:29 +0100840 if (length > sizeof(dev->data_buf)) {
841 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
842 length, sizeof(dev->data_buf));
malcb2e3b6e2009-09-12 03:18:18 +0400843 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -0400844 }
845
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200846 aurb = async_alloc(s);
aliguori446ab122008-09-14 01:06:09 +0000847 aurb->packet = p;
848
David Ahern27911042010-04-24 10:26:22 -0600849 /*
aliguori446ab122008-09-14 01:06:09 +0000850 * Setup ctrl transfer.
851 *
Brad Hardsa0102082011-04-13 19:45:33 +1000852 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +0000853 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -0600854 */
aliguori446ab122008-09-14 01:06:09 +0000855 urb = &aurb->urb;
856
857 urb->type = USBDEVFS_URB_TYPE_CONTROL;
858 urb->endpoint = p->devep;
859
Hans de Goede50b79632011-02-02 17:36:29 +0100860 urb->buffer = &dev->setup_buf;
861 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +0000862
863 urb->usercontext = s;
864
865 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
866
malcd0f2c4c2010-02-07 02:03:50 +0300867 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +0000868
869 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300870 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +0000871 async_free(aurb);
872
873 switch(errno) {
874 case ETIMEDOUT:
875 return USB_RET_NAK;
876 case EPIPE:
877 default:
878 return USB_RET_STALL;
879 }
880 }
881
aliguori446ab122008-09-14 01:06:09 +0000882 return USB_RET_ASYNC;
883}
884
Hans de Goede71d71bb2010-11-10 10:06:24 +0100885static int usb_linux_get_configuration(USBHostDevice *s)
balrogb9dc0332007-10-04 22:47:34 +0000886{
Hans de Goede71d71bb2010-11-10 10:06:24 +0100887 uint8_t configuration;
pbrooke41b3912008-10-28 18:22:59 +0000888 struct usb_ctrltransfer ct;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100889 int ret;
balrogb9dc0332007-10-04 22:47:34 +0000890
Hans de Goede2cc59d82010-11-10 10:06:25 +0100891 if (usb_fs_type == USB_FS_SYS) {
892 char device_name[32], line[1024];
893 int configuration;
894
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200895 sprintf(device_name, "%d-%s", s->bus_num, s->port);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100896
897 if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
898 device_name)) {
899 goto usbdevfs;
900 }
901 if (sscanf(line, "%d", &configuration) != 1) {
902 goto usbdevfs;
903 }
904 return configuration;
905 }
906
907usbdevfs:
balrogb9dc0332007-10-04 22:47:34 +0000908 ct.bRequestType = USB_DIR_IN;
909 ct.bRequest = USB_REQ_GET_CONFIGURATION;
910 ct.wValue = 0;
911 ct.wIndex = 0;
912 ct.wLength = 1;
913 ct.data = &configuration;
914 ct.timeout = 50;
915
916 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
917 if (ret < 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100918 perror("usb_linux_get_configuration");
919 return -1;
balrogb9dc0332007-10-04 22:47:34 +0000920 }
921
922 /* in address state */
David Ahern27911042010-04-24 10:26:22 -0600923 if (configuration == 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100924 return -1;
David Ahern27911042010-04-24 10:26:22 -0600925 }
balrogb9dc0332007-10-04 22:47:34 +0000926
Hans de Goede71d71bb2010-11-10 10:06:24 +0100927 return configuration;
928}
929
Hans de Goedeed3a3282010-11-24 12:50:00 +0100930static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
931 uint8_t configuration, uint8_t interface)
932{
933 uint8_t alt_setting;
934 struct usb_ctrltransfer ct;
935 int ret;
936
Hans de Goedec43831f2010-11-24 12:57:59 +0100937 if (usb_fs_type == USB_FS_SYS) {
938 char device_name[64], line[1024];
939 int alt_setting;
940
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200941 sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
Hans de Goedec43831f2010-11-24 12:57:59 +0100942 (int)configuration, (int)interface);
943
944 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
945 device_name)) {
946 goto usbdevfs;
947 }
948 if (sscanf(line, "%d", &alt_setting) != 1) {
949 goto usbdevfs;
950 }
951 return alt_setting;
952 }
953
954usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +0100955 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
956 ct.bRequest = USB_REQ_GET_INTERFACE;
957 ct.wValue = 0;
958 ct.wIndex = interface;
959 ct.wLength = 1;
960 ct.data = &alt_setting;
961 ct.timeout = 50;
962 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
963 if (ret < 0) {
964 /* Assume alt 0 on error */
965 return 0;
966 }
967
968 return alt_setting;
969}
970
Hans de Goede71d71bb2010-11-10 10:06:24 +0100971/* returns 1 on problem encountered or 0 for success */
972static int usb_linux_update_endp_table(USBHostDevice *s)
973{
974 uint8_t *descriptors;
975 uint8_t devep, type, configuration, alt_interface;
Hans de Goedeed3a3282010-11-24 12:50:00 +0100976 int interface, length, i;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100977
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100978 for (i = 0; i < MAX_ENDPOINTS; i++)
979 s->endp_table[i].type = INVALID_EP_TYPE;
980
Hans de Goede71d71bb2010-11-10 10:06:24 +0100981 i = usb_linux_get_configuration(s);
982 if (i < 0)
983 return 1;
984 configuration = i;
985
balrogb9dc0332007-10-04 22:47:34 +0000986 /* get the desired configuration, interface, and endpoint descriptors
987 * from device description */
988 descriptors = &s->descr[18];
989 length = s->descr_len - 18;
990 i = 0;
991
992 if (descriptors[i + 1] != USB_DT_CONFIG ||
993 descriptors[i + 5] != configuration) {
malcd0f2c4c2010-02-07 02:03:50 +0300994 DPRINTF("invalid descriptor data - configuration\n");
balrogb9dc0332007-10-04 22:47:34 +0000995 return 1;
996 }
997 i += descriptors[i];
998
999 while (i < length) {
1000 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1001 (descriptors[i + 1] == USB_DT_INTERFACE &&
1002 descriptors[i + 4] == 0)) {
1003 i += descriptors[i];
1004 continue;
1005 }
1006
1007 interface = descriptors[i + 2];
Hans de Goedeed3a3282010-11-24 12:50:00 +01001008 alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
balrogb9dc0332007-10-04 22:47:34 +00001009
1010 /* the current interface descriptor is the active interface
1011 * and has endpoints */
1012 if (descriptors[i + 3] != alt_interface) {
1013 i += descriptors[i];
1014 continue;
1015 }
1016
1017 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001018 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001019 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001020 }
balrogb9dc0332007-10-04 22:47:34 +00001021
1022 if (i >= length)
1023 break;
1024
1025 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001026 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001027 break;
David Ahern27911042010-04-24 10:26:22 -06001028 }
balrogb9dc0332007-10-04 22:47:34 +00001029
1030 devep = descriptors[i + 2];
1031 switch (descriptors[i + 3] & 0x3) {
1032 case 0x00:
1033 type = USBDEVFS_URB_TYPE_CONTROL;
1034 break;
1035 case 0x01:
1036 type = USBDEVFS_URB_TYPE_ISO;
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +02001037 set_max_packet_size(s, (devep & 0xf), descriptors + i);
balrogb9dc0332007-10-04 22:47:34 +00001038 break;
1039 case 0x02:
1040 type = USBDEVFS_URB_TYPE_BULK;
1041 break;
1042 case 0x03:
1043 type = USBDEVFS_URB_TYPE_INTERRUPT;
1044 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -05001045 default:
1046 DPRINTF("usb_host: malformed endpoint type\n");
1047 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +00001048 }
1049 s->endp_table[(devep & 0xf) - 1].type = type;
aliguori64838172008-08-21 19:31:10 +00001050 s->endp_table[(devep & 0xf) - 1].halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001051
1052 i += descriptors[i];
1053 }
1054 }
1055 return 0;
1056}
1057
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001058static int usb_host_open(USBHostDevice *dev, int bus_num,
Hans de Goede3991c352011-05-31 11:35:18 +02001059 int addr, char *port, const char *prod_name, int speed)
bellardbb36d472005-11-05 14:22:28 +00001060{
balrogb9dc0332007-10-04 22:47:34 +00001061 int fd = -1, ret;
bellarda594cfb2005-11-06 16:13:29 +00001062 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001063
David Ahern27911042010-04-24 10:26:22 -06001064 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001065 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001066 }
aliguori64838172008-08-21 19:31:10 +00001067 printf("husb: open device %d.%d\n", bus_num, addr);
aliguori1f3870a2008-08-21 19:27:48 +00001068
aliguori0f431522008-10-07 20:06:37 +00001069 if (!usb_host_device_path) {
1070 perror("husb: USB Host Device Path not set");
1071 goto fail;
1072 }
1073 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001074 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001075 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001076 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001077 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001078 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001079 }
malcd0f2c4c2010-02-07 02:03:50 +03001080 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001081
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001082 dev->bus_num = bus_num;
1083 dev->addr = addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001084 strcpy(dev->port, port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001085 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001086
balrogb9dc0332007-10-04 22:47:34 +00001087 /* read the device description */
1088 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1089 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001090 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001091 goto fail;
1092 }
ths3b46e622007-09-17 08:09:54 +00001093
balrogb9dc0332007-10-04 22:47:34 +00001094#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001095 {
balrogb9dc0332007-10-04 22:47:34 +00001096 int x;
1097 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001098 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001099 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001100 }
balrogb9dc0332007-10-04 22:47:34 +00001101 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001102 }
1103#endif
1104
balrogb9dc0332007-10-04 22:47:34 +00001105
David Ahern27911042010-04-24 10:26:22 -06001106 /*
1107 * Initial configuration is -1 which makes us claim first
aliguori446ab122008-09-14 01:06:09 +00001108 * available config. We used to start with 1, which does not
David Ahern27911042010-04-24 10:26:22 -06001109 * always work. I've seen devices where first config starts
aliguori446ab122008-09-14 01:06:09 +00001110 * with 2.
1111 */
David Ahern27911042010-04-24 10:26:22 -06001112 if (!usb_host_claim_interfaces(dev, -1)) {
balrogb9dc0332007-10-04 22:47:34 +00001113 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001114 }
bellardbb36d472005-11-05 14:22:28 +00001115
balrogb9dc0332007-10-04 22:47:34 +00001116 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001117 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001118 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001119 }
balrogb9dc0332007-10-04 22:47:34 +00001120
Hans de Goede3991c352011-05-31 11:35:18 +02001121 if (speed == -1) {
1122 struct usbdevfs_connectinfo ci;
1123
1124 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1125 if (ret < 0) {
1126 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
1127 goto fail;
1128 }
1129
1130 if (ci.slow) {
1131 speed = USB_SPEED_LOW;
1132 } else {
1133 speed = USB_SPEED_HIGH;
1134 }
David Ahern27911042010-04-24 10:26:22 -06001135 }
Hans de Goede3991c352011-05-31 11:35:18 +02001136 dev->dev.speed = speed;
1137
1138 printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001139
David Ahern27911042010-04-24 10:26:22 -06001140 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001141 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001142 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001143 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001144 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001145 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001146 }
bellard1f6e24e2006-06-26 21:00:51 +00001147
aliguori64838172008-08-21 19:31:10 +00001148 /* USB devio uses 'write' flag to check for async completions */
1149 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001150
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001151 usb_device_attach(&dev->dev);
1152 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001153
balrogb9dc0332007-10-04 22:47:34 +00001154fail:
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001155 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001156 if (fd != -1) {
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001157 close(fd);
David Ahern27911042010-04-24 10:26:22 -06001158 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001159 return -1;
1160}
1161
1162static int usb_host_close(USBHostDevice *dev)
1163{
Hans de Goede060dc842010-11-26 11:41:08 +01001164 int i;
1165
David Ahern27911042010-04-24 10:26:22 -06001166 if (dev->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001167 return -1;
David Ahern27911042010-04-24 10:26:22 -06001168 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001169
1170 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1171 dev->closing = 1;
Hans de Goede3a4854b2010-11-26 15:02:16 +01001172 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +01001173 if (is_isoc(dev, i)) {
1174 usb_host_stop_n_free_iso(dev, i);
1175 }
1176 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001177 async_complete(dev);
1178 dev->closing = 0;
1179 usb_device_detach(&dev->dev);
Shahar Havivi00ff2272010-06-16 15:15:37 +03001180 ioctl(dev->fd, USBDEVFS_RESET);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001181 close(dev->fd);
1182 dev->fd = -1;
1183 return 0;
1184}
1185
Shahar Havivib373a632010-06-16 15:16:11 +03001186static void usb_host_exit_notifier(struct Notifier* n)
1187{
1188 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1189
1190 if (s->fd != -1) {
1191 ioctl(s->fd, USBDEVFS_RESET);
1192 }
1193}
1194
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001195static int usb_host_initfn(USBDevice *dev)
1196{
1197 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1198
1199 dev->auto_attach = 0;
1200 s->fd = -1;
1201 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001202 s->exit.notify = usb_host_exit_notifier;
1203 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001204 usb_host_auto_check(NULL);
1205 return 0;
bellardbb36d472005-11-05 14:22:28 +00001206}
1207
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001208static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001209 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001210 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001211 .qdev.size = sizeof(USBHostDevice),
1212 .init = usb_host_initfn,
Hans de Goede50b79632011-02-02 17:36:29 +01001213 .handle_packet = usb_generic_handle_packet,
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +02001214 .cancel_packet = usb_host_async_cancel,
Hans de Goede50b79632011-02-02 17:36:29 +01001215 .handle_data = usb_host_handle_data,
1216 .handle_control = usb_host_handle_control,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001217 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001218 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001219 .usbdevice_name = "host",
1220 .usbdevice_init = usb_host_device_open,
1221 .qdev.props = (Property[]) {
1222 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1223 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001224 DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001225 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1226 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
1227 DEFINE_PROP_END_OF_LIST(),
1228 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001229};
1230
1231static void usb_host_register_devices(void)
1232{
1233 usb_qdev_register(&usb_host_dev_info);
1234}
1235device_init(usb_host_register_devices)
1236
aliguori4b096fc2008-08-21 19:28:55 +00001237USBDevice *usb_host_device_open(const char *devname)
1238{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001239 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001240 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001241 char *p;
1242
Markus Armbruster556cd092009-12-09 17:07:53 +01001243 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001244
aliguori5d0c5752008-09-14 01:07:41 +00001245 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001246 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001247 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001248 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001249 } else {
1250 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001251 filter.bus_num = strtoul(devname, NULL, 0);
1252 filter.addr = strtoul(p + 1, NULL, 0);
1253 filter.vendor_id = 0;
1254 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001255 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001256 filter.bus_num = 0;
1257 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001258 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001259 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001260 } else {
1261 goto fail;
1262 }
aliguori5d0c5752008-09-14 01:07:41 +00001263 }
1264
Markus Armbruster0745eb12009-11-27 13:05:53 +01001265 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1266 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001267 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1268 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001269 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001270 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001271
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001272fail:
1273 qdev_free(&dev->qdev);
1274 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001275}
aliguori5d0c5752008-09-14 01:07:41 +00001276
1277int usb_host_device_close(const char *devname)
1278{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001279#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001280 char product_name[PRODUCT_NAME_SZ];
1281 int bus_num, addr;
1282 USBHostDevice *s;
1283
David Ahern27911042010-04-24 10:26:22 -06001284 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001285 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001286 }
1287 if (usb_host_find_device(&bus_num, &addr, product_name,
1288 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001289 return -1;
David Ahern27911042010-04-24 10:26:22 -06001290 }
aliguori5d0c5752008-09-14 01:07:41 +00001291 s = hostdev_find(bus_num, addr);
1292 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001293 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001294 return 0;
1295 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001296#endif
aliguori5d0c5752008-09-14 01:07:41 +00001297
1298 return -1;
1299}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001300
bellarda594cfb2005-11-06 16:13:29 +00001301static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001302 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001303 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001304{
bellarda594cfb2005-11-06 16:13:29 +00001305 const char *p;
1306 char *q;
1307 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001308 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001309 return -1;
David Ahern27911042010-04-24 10:26:22 -06001310 }
bellarda594cfb2005-11-06 16:13:29 +00001311 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001312 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001313 p++;
David Ahern27911042010-04-24 10:26:22 -06001314 }
bellarda594cfb2005-11-06 16:13:29 +00001315 q = buf;
1316 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001317 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001318 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001319 }
bellarda594cfb2005-11-06 16:13:29 +00001320 p++;
1321 }
1322 *q = '\0';
1323 return q - buf;
1324}
bellardbb36d472005-11-05 14:22:28 +00001325
aliguori0f431522008-10-07 20:06:37 +00001326/*
1327 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1328 * host's USB devices. This is legacy support since many distributions
1329 * are moving to /sys/bus/usb
1330 */
1331static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001332{
Blue Swirl660f11b2009-07-31 21:16:51 +00001333 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001334 char line[1024];
1335 char buf[1024];
1336 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
bellarda594cfb2005-11-06 16:13:29 +00001337 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001338 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001339
aliguori0f431522008-10-07 20:06:37 +00001340 if (!usb_host_device_path) {
1341 perror("husb: USB Host Device Path not set");
1342 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001343 }
aliguori0f431522008-10-07 20:06:37 +00001344 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1345 f = fopen(line, "r");
1346 if (!f) {
1347 perror("husb: cannot open devices file");
1348 goto the_end;
1349 }
1350
bellarda594cfb2005-11-06 16:13:29 +00001351 device_count = 0;
Hans de Goede3991c352011-05-31 11:35:18 +02001352 bus_num = addr = class_id = product_id = vendor_id = 0;
1353 speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
bellardbb36d472005-11-05 14:22:28 +00001354 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001355 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001356 break;
David Ahern27911042010-04-24 10:26:22 -06001357 }
1358 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001359 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001360 }
bellarda594cfb2005-11-06 16:13:29 +00001361 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001362 if (device_count && (vendor_id || product_id)) {
1363 /* New device. Add the previously discovered device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001364 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001365 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001366 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001367 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001368 }
bellarda594cfb2005-11-06 16:13:29 +00001369 }
David Ahern27911042010-04-24 10:26:22 -06001370 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001371 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001372 }
bellarda594cfb2005-11-06 16:13:29 +00001373 bus_num = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001374 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001375 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001376 }
bellarda594cfb2005-11-06 16:13:29 +00001377 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001378 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001379 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001380 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001381 if (!strcmp(buf, "5000")) {
1382 speed = USB_SPEED_SUPER;
1383 } else if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001384 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001385 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001386 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001387 } else {
bellarda594cfb2005-11-06 16:13:29 +00001388 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001389 }
bellarda594cfb2005-11-06 16:13:29 +00001390 product_name[0] = '\0';
1391 class_id = 0xff;
1392 device_count++;
1393 product_id = 0;
1394 vendor_id = 0;
1395 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001396 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001397 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001398 }
bellarda594cfb2005-11-06 16:13:29 +00001399 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001400 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001401 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001402 }
bellarda594cfb2005-11-06 16:13:29 +00001403 product_id = strtoul(buf, NULL, 16);
1404 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001405 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001406 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001407 }
bellarda594cfb2005-11-06 16:13:29 +00001408 pstrcpy(product_name, sizeof(product_name), buf);
1409 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001410 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001411 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001412 }
bellarda594cfb2005-11-06 16:13:29 +00001413 class_id = strtoul(buf, NULL, 16);
1414 }
1415 fail: ;
1416 }
pbrook38ca0f62006-03-11 18:03:38 +00001417 if (device_count && (vendor_id || product_id)) {
1418 /* Add the last device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001419 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001420 product_id, product_name, speed);
1421 }
1422 the_end:
David Ahern27911042010-04-24 10:26:22 -06001423 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001424 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001425 }
aliguori0f431522008-10-07 20:06:37 +00001426 return ret;
1427}
1428
1429/*
1430 * Read sys file-system device file
1431 *
1432 * @line address of buffer to put file contents in
1433 * @line_size size of line
1434 * @device_file path to device file (printf format string)
1435 * @device_name device being opened (inserted into device_file)
1436 *
1437 * @return 0 failed, 1 succeeded ('line' contains data)
1438 */
David Ahern27911042010-04-24 10:26:22 -06001439static int usb_host_read_file(char *line, size_t line_size,
1440 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001441{
1442 FILE *f;
1443 int ret = 0;
1444 char filename[PATH_MAX];
1445
blueswir1b4e237a2008-12-28 15:45:20 +00001446 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1447 device_file);
aliguori0f431522008-10-07 20:06:37 +00001448 f = fopen(filename, "r");
1449 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001450 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001451 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001452 }
1453
1454 return ret;
1455}
1456
1457/*
1458 * Use /sys/bus/usb/devices/ directory to determine host's USB
1459 * devices.
1460 *
1461 * This code is based on Robert Schiele's original patches posted to
1462 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1463 */
1464static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1465{
Blue Swirl660f11b2009-07-31 21:16:51 +00001466 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001467 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001468 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001469 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001470 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001471 char product_name[512];
1472 struct dirent *de;
1473
1474 dir = opendir(USBSYSBUS_PATH "/devices");
1475 if (!dir) {
1476 perror("husb: cannot open devices directory");
1477 goto the_end;
1478 }
1479
1480 while ((de = readdir(dir))) {
1481 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001482 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1483 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001484 }
aliguori0f431522008-10-07 20:06:37 +00001485
David Ahern27911042010-04-24 10:26:22 -06001486 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001487 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001488 }
1489 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001490 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001491 }
blueswir1b4e237a2008-12-28 15:45:20 +00001492 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001493 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001494 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001495 }
1496 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001497 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001498 }
aliguori0f431522008-10-07 20:06:37 +00001499
David Ahern27911042010-04-24 10:26:22 -06001500 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1501 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001502 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001503 }
1504 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001505 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001506 }
blueswir1b4e237a2008-12-28 15:45:20 +00001507 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001508 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001509 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001510 }
1511 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001512 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001513 }
blueswir1b4e237a2008-12-28 15:45:20 +00001514 if (!usb_host_read_file(line, sizeof(line), "product",
1515 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001516 *product_name = 0;
1517 } else {
David Ahern27911042010-04-24 10:26:22 -06001518 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001519 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001520 }
aliguori0f431522008-10-07 20:06:37 +00001521 pstrcpy(product_name, sizeof(product_name), line);
1522 }
1523
David Ahern27911042010-04-24 10:26:22 -06001524 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001525 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001526 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001527 if (!strcmp(line, "5000\n")) {
1528 speed = USB_SPEED_SUPER;
1529 } else if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001530 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001531 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001532 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001533 } else {
aliguori0f431522008-10-07 20:06:37 +00001534 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001535 }
aliguori0f431522008-10-07 20:06:37 +00001536
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001537 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001538 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001539 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001540 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001541 }
aliguori0f431522008-10-07 20:06:37 +00001542 }
1543 }
1544 the_end:
David Ahern27911042010-04-24 10:26:22 -06001545 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001546 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001547 }
aliguori0f431522008-10-07 20:06:37 +00001548 return ret;
1549}
1550
1551/*
1552 * Determine how to access the host's USB devices and call the
1553 * specific support function.
1554 */
1555static int usb_host_scan(void *opaque, USBScanFunc *func)
1556{
aliguori376253e2009-03-05 23:01:23 +00001557 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001558 FILE *f = NULL;
1559 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001560 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001561 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1562 char devpath[PATH_MAX];
1563
1564 /* only check the host once */
1565 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001566 dir = opendir(USBSYSBUS_PATH "/devices");
1567 if (dir) {
1568 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1569 strcpy(devpath, USBDEVBUS_PATH);
1570 usb_fs_type = USB_FS_SYS;
1571 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001572 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001573 goto found_devices;
1574 }
aliguori0f431522008-10-07 20:06:37 +00001575 f = fopen(USBPROCBUS_PATH "/devices", "r");
1576 if (f) {
1577 /* devices found in /proc/bus/usb/ */
1578 strcpy(devpath, USBPROCBUS_PATH);
1579 usb_fs_type = USB_FS_PROC;
1580 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001581 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001582 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001583 }
1584 /* try additional methods if an access method hasn't been found yet */
1585 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001586 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001587 /* devices found in /dev/bus/usb/ */
1588 strcpy(devpath, USBDEVBUS_PATH);
1589 usb_fs_type = USB_FS_DEV;
1590 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001591 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001592 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001593 }
aliguorif16a0db2008-10-21 16:34:20 +00001594 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001595 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001596 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001597 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001598 }
aliguorif16a0db2008-10-21 16:34:20 +00001599 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001600 }
1601
1602 /* the module setting (used later for opening devices) */
1603 usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001604 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001605 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001606 monitor_printf(mon, "husb: using %s file-system with %s\n",
1607 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001608 }
aliguori0f431522008-10-07 20:06:37 +00001609 }
1610
1611 switch (usb_fs_type) {
1612 case USB_FS_PROC:
1613 case USB_FS_DEV:
1614 ret = usb_host_scan_dev(opaque, func);
1615 break;
1616 case USB_FS_SYS:
1617 ret = usb_host_scan_sys(opaque, func);
1618 break;
aliguorif16a0db2008-10-21 16:34:20 +00001619 default:
1620 ret = -EINVAL;
1621 break;
aliguori0f431522008-10-07 20:06:37 +00001622 }
bellarda594cfb2005-11-06 16:13:29 +00001623 return ret;
1624}
1625
aliguori4b096fc2008-08-21 19:28:55 +00001626static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001627
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001628static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001629 int class_id, int vendor_id, int product_id,
1630 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001631{
1632 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001633 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001634
1635 /* Ignore hubs */
1636 if (class_id == 9)
1637 return 0;
1638
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001639 QTAILQ_FOREACH(s, &hostdevs, next) {
1640 f = &s->match;
1641
David Ahern27911042010-04-24 10:26:22 -06001642 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001643 continue;
David Ahern27911042010-04-24 10:26:22 -06001644 }
1645 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001646 continue;
David Ahern27911042010-04-24 10:26:22 -06001647 }
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001648 if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
1649 continue;
1650 }
aliguori4b096fc2008-08-21 19:28:55 +00001651
David Ahern27911042010-04-24 10:26:22 -06001652 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001653 continue;
David Ahern27911042010-04-24 10:26:22 -06001654 }
aliguori4b096fc2008-08-21 19:28:55 +00001655
David Ahern27911042010-04-24 10:26:22 -06001656 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001657 continue;
David Ahern27911042010-04-24 10:26:22 -06001658 }
aliguori4b096fc2008-08-21 19:28:55 +00001659 /* We got a match */
1660
Markus Armbruster33e66b82009-10-07 01:15:57 +02001661 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001662 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001663 return 0;
David Ahern27911042010-04-24 10:26:22 -06001664 }
malcd0f2c4c2010-02-07 02:03:50 +03001665 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001666
Hans de Goede3991c352011-05-31 11:35:18 +02001667 usb_host_open(s, bus_num, addr, port, product_name, speed);
aliguori4b096fc2008-08-21 19:28:55 +00001668 }
1669
1670 return 0;
1671}
1672
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001673static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001674{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001675 struct USBHostDevice *s;
1676 int unconnected = 0;
1677
aliguori4b096fc2008-08-21 19:28:55 +00001678 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001679
1680 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001681 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001682 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001683 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001684 }
1685
1686 if (unconnected == 0) {
1687 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001688 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001689 qemu_del_timer(usb_auto_timer);
David Ahern27911042010-04-24 10:26:22 -06001690 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001691 return;
1692 }
1693
1694 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001695 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001696 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001697 return;
David Ahern27911042010-04-24 10:26:22 -06001698 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001699 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001700 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001701}
1702
1703/*
aliguori5d0c5752008-09-14 01:07:41 +00001704 * Autoconnect filter
1705 * Format:
1706 * auto:bus:dev[:vid:pid]
1707 * auto:bus.dev[:vid:pid]
1708 *
1709 * bus - bus number (dec, * means any)
1710 * dev - device number (dec, * means any)
1711 * vid - vendor id (hex, * means any)
1712 * pid - product id (hex, * means any)
1713 *
1714 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001715 */
aliguori5d0c5752008-09-14 01:07:41 +00001716static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001717{
aliguori5d0c5752008-09-14 01:07:41 +00001718 enum { BUS, DEV, VID, PID, DONE };
1719 const char *p = spec;
1720 int i;
1721
Markus Armbruster0745eb12009-11-27 13:05:53 +01001722 f->bus_num = 0;
1723 f->addr = 0;
1724 f->vendor_id = 0;
1725 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001726
1727 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001728 p = strpbrk(p, ":.");
1729 if (!p) {
1730 break;
1731 }
aliguori5d0c5752008-09-14 01:07:41 +00001732 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001733
David Ahern27911042010-04-24 10:26:22 -06001734 if (*p == '*') {
1735 continue;
1736 }
aliguori5d0c5752008-09-14 01:07:41 +00001737 switch(i) {
1738 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1739 case DEV: f->addr = strtol(p, NULL, 10); break;
1740 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1741 case PID: f->product_id = strtol(p, NULL, 16); break;
1742 }
aliguori4b096fc2008-08-21 19:28:55 +00001743 }
1744
aliguori5d0c5752008-09-14 01:07:41 +00001745 if (i < DEV) {
1746 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1747 return -1;
1748 }
1749
1750 return 0;
1751}
1752
bellarda594cfb2005-11-06 16:13:29 +00001753/**********************/
1754/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001755
bellarda594cfb2005-11-06 16:13:29 +00001756struct usb_class_info {
1757 int class;
1758 const char *class_name;
1759};
1760
1761static const struct usb_class_info usb_class_info[] = {
1762 { USB_CLASS_AUDIO, "Audio"},
1763 { USB_CLASS_COMM, "Communication"},
1764 { USB_CLASS_HID, "HID"},
1765 { USB_CLASS_HUB, "Hub" },
1766 { USB_CLASS_PHYSICAL, "Physical" },
1767 { USB_CLASS_PRINTER, "Printer" },
1768 { USB_CLASS_MASS_STORAGE, "Storage" },
1769 { USB_CLASS_CDC_DATA, "Data" },
1770 { USB_CLASS_APP_SPEC, "Application Specific" },
1771 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1772 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001773 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001774 { USB_CLASS_CONTENT_SEC, "Content Security" },
1775 { -1, NULL }
1776};
1777
1778static const char *usb_class_str(uint8_t class)
1779{
1780 const struct usb_class_info *p;
1781 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001782 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001783 break;
David Ahern27911042010-04-24 10:26:22 -06001784 }
bellardbb36d472005-11-05 14:22:28 +00001785 }
bellarda594cfb2005-11-06 16:13:29 +00001786 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001787}
1788
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001789static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
1790 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00001791 const char *product_name,
1792 int speed)
bellardbb36d472005-11-05 14:22:28 +00001793{
bellarda594cfb2005-11-06 16:13:29 +00001794 const char *class_str, *speed_str;
1795
1796 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001797 case USB_SPEED_LOW:
1798 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001799 break;
ths5fafdf22007-09-16 21:08:06 +00001800 case USB_SPEED_FULL:
1801 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001802 break;
ths5fafdf22007-09-16 21:08:06 +00001803 case USB_SPEED_HIGH:
1804 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001805 break;
Hans de Goedef264cfb2011-05-31 11:35:19 +02001806 case USB_SPEED_SUPER:
1807 speed_str = "5000";
1808 break;
bellarda594cfb2005-11-06 16:13:29 +00001809 default:
ths5fafdf22007-09-16 21:08:06 +00001810 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001811 break;
bellardbb36d472005-11-05 14:22:28 +00001812 }
bellarda594cfb2005-11-06 16:13:29 +00001813
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001814 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
1815 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00001816 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001817 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001818 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001819 } else {
aliguori376253e2009-03-05 23:01:23 +00001820 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001821 }
aliguori376253e2009-03-05 23:01:23 +00001822 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001823 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001824 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001825 }
aliguori376253e2009-03-05 23:01:23 +00001826 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001827}
1828
ths5fafdf22007-09-16 21:08:06 +00001829static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001830 char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001831 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001832 const char *product_name,
1833 int speed)
1834{
Blue Swirl179da8a2009-09-07 19:00:18 +00001835 Monitor *mon = opaque;
1836
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001837 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001838 product_name, speed);
1839 return 0;
1840}
1841
aliguoriac4ffb52008-09-22 15:04:31 +00001842static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001843{
David Ahern27911042010-04-24 10:26:22 -06001844 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001845 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001846 } else {
1847 snprintf(str, size, "%d", val);
1848 }
aliguori5d0c5752008-09-14 01:07:41 +00001849}
1850
aliguoriac4ffb52008-09-22 15:04:31 +00001851static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001852{
David Ahern27911042010-04-24 10:26:22 -06001853 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001854 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001855 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001856 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06001857 }
aliguori5d0c5752008-09-14 01:07:41 +00001858}
1859
aliguori376253e2009-03-05 23:01:23 +00001860void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00001861{
aliguori5d0c5752008-09-14 01:07:41 +00001862 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001863 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00001864
Blue Swirl179da8a2009-09-07 19:00:18 +00001865 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00001866
David Ahern27911042010-04-24 10:26:22 -06001867 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001868 return;
David Ahern27911042010-04-24 10:26:22 -06001869 }
1870
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001871 monitor_printf(mon, " Auto filters:\n");
1872 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00001873 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001874 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00001875 dec2str(f->bus_num, bus, sizeof(bus));
1876 dec2str(f->addr, addr, sizeof(addr));
1877 hex2str(f->vendor_id, vid, sizeof(vid));
1878 hex2str(f->product_id, pid, sizeof(pid));
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001879 monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
1880 bus, addr, f->port ? f->port : "*", vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00001881 }
bellardbb36d472005-11-05 14:22:28 +00001882}