blob: 730eac2ca62c97ada6ee56eb84b81720c56fde4d [file] [log] [blame]
bellardbb36d472005-11-05 14:22:28 +00001/*
2 * Linux host USB redirector
3 *
4 * Copyright (c) 2005 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
aliguori64838172008-08-21 19:31:10 +00006 * Copyright (c) 2008 Max Krasnyansky
7 * Support for host device auto connect & disconnect
aliguori5d0c5752008-09-14 01:07:41 +00008 * Major rewrite to support fully async operation
aliguori4b096fc2008-08-21 19:28:55 +00009 *
aliguori0f431522008-10-07 20:06:37 +000010 * Copyright 2008 TJ <linux@tjworld.net>
11 * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
12 * to the legacy /proc/bus/usb USB device discovery and handling
13 *
bellardbb36d472005-11-05 14:22:28 +000014 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to deal
16 * in the Software without restriction, including without limitation the rights
17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 * copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 * THE SOFTWARE.
31 */
aliguori446ab122008-09-14 01:06:09 +000032
pbrook87ecb682007-11-17 17:14:51 +000033#include "qemu-common.h"
aliguori1f3870a2008-08-21 19:27:48 +000034#include "qemu-timer.h"
aliguori376253e2009-03-05 23:01:23 +000035#include "monitor.h"
Shahar Havivib373a632010-06-16 15:16:11 +030036#include "sysemu.h"
bellardbb36d472005-11-05 14:22:28 +000037
bellardbb36d472005-11-05 14:22:28 +000038#include <dirent.h>
39#include <sys/ioctl.h>
balrogb9dc0332007-10-04 22:47:34 +000040#include <signal.h>
bellardbb36d472005-11-05 14:22:28 +000041
aliguori446ab122008-09-14 01:06:09 +000042#include <linux/usbdevice_fs.h>
43#include <linux/version.h>
44#include "hw/usb.h"
bellardbb36d472005-11-05 14:22:28 +000045
blueswir1d9cf1572008-09-15 14:57:11 +000046/* We redefine it to avoid version problems */
47struct usb_ctrltransfer {
48 uint8_t bRequestType;
49 uint8_t bRequest;
50 uint16_t wValue;
51 uint16_t wIndex;
52 uint16_t wLength;
53 uint32_t timeout;
54 void *data;
55};
56
57struct usb_ctrlrequest {
58 uint8_t bRequestType;
59 uint8_t bRequest;
60 uint16_t wValue;
61 uint16_t wIndex;
62 uint16_t wLength;
63};
64
Hans de Goede0f5160d2010-11-10 10:06:23 +010065typedef int USBScanFunc(void *opaque, int bus_num, int addr, int devpath,
66 int class_id, int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +000067 const char *product_name, int speed);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010068
Markus Armbruster0745eb12009-11-27 13:05:53 +010069//#define DEBUG
aliguori64838172008-08-21 19:31:10 +000070
71#ifdef DEBUG
malcd0f2c4c2010-02-07 02:03:50 +030072#define DPRINTF printf
aliguori64838172008-08-21 19:31:10 +000073#else
malcd0f2c4c2010-02-07 02:03:50 +030074#define DPRINTF(...)
aliguori64838172008-08-21 19:31:10 +000075#endif
bellardbb36d472005-11-05 14:22:28 +000076
blueswir15be8e1f2008-10-25 11:47:20 +000077#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
78
aliguori0f431522008-10-07 20:06:37 +000079#define USBPROCBUS_PATH "/proc/bus/usb"
bellard1f6e24e2006-06-26 21:00:51 +000080#define PRODUCT_NAME_SZ 32
Hans de Goede3a4854b2010-11-26 15:02:16 +010081#define MAX_ENDPOINTS 15
aliguori0f431522008-10-07 20:06:37 +000082#define USBDEVBUS_PATH "/dev/bus/usb"
83#define USBSYSBUS_PATH "/sys/bus/usb"
84
85static char *usb_host_device_path;
86
87#define USB_FS_NONE 0
88#define USB_FS_PROC 1
89#define USB_FS_DEV 2
90#define USB_FS_SYS 3
91
92static int usb_fs_type;
bellardbb36d472005-11-05 14:22:28 +000093
balrogb9dc0332007-10-04 22:47:34 +000094/* endpoint association data */
Hans de Goede060dc842010-11-26 11:41:08 +010095#define ISO_FRAME_DESC_PER_URB 32
96#define ISO_URB_COUNT 3
Hans de Goedea0b5fec2010-11-26 14:56:17 +010097#define INVALID_EP_TYPE 255
Hans de Goede060dc842010-11-26 11:41:08 +010098
99typedef struct AsyncURB AsyncURB;
100
balrogb9dc0332007-10-04 22:47:34 +0000101struct endp_data {
102 uint8_t type;
aliguori64838172008-08-21 19:31:10 +0000103 uint8_t halted;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100104 uint8_t iso_started;
Hans de Goede060dc842010-11-26 11:41:08 +0100105 AsyncURB *iso_urb;
106 int iso_urb_idx;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100107 int iso_buffer_used;
Hans de Goede060dc842010-11-26 11:41:08 +0100108 int max_packet_size;
balrogb9dc0332007-10-04 22:47:34 +0000109};
110
aliguori446ab122008-09-14 01:06:09 +0000111enum {
112 CTRL_STATE_IDLE = 0,
113 CTRL_STATE_SETUP,
114 CTRL_STATE_DATA,
115 CTRL_STATE_ACK
116};
117
118/*
119 * Control transfer state.
David Ahern27911042010-04-24 10:26:22 -0600120 * Note that 'buffer' _must_ follow 'req' field because
Brad Hardsa0102082011-04-13 19:45:33 +1000121 * we need contiguous buffer when we submit control URB.
David Ahern27911042010-04-24 10:26:22 -0600122 */
aliguori446ab122008-09-14 01:06:09 +0000123struct ctrl_struct {
124 uint16_t len;
125 uint16_t offset;
126 uint8_t state;
127 struct usb_ctrlrequest req;
Christian Krausefd7a4462010-01-24 17:34:52 +0100128 uint8_t buffer[8192];
aliguori446ab122008-09-14 01:06:09 +0000129};
130
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100131struct USBAutoFilter {
132 uint32_t bus_num;
133 uint32_t addr;
134 uint32_t vendor_id;
135 uint32_t product_id;
136};
137
bellardbb36d472005-11-05 14:22:28 +0000138typedef struct USBHostDevice {
139 USBDevice dev;
aliguori64838172008-08-21 19:31:10 +0000140 int fd;
141
142 uint8_t descr[1024];
143 int descr_len;
144 int configuration;
aliguori446ab122008-09-14 01:06:09 +0000145 int ninterfaces;
aliguori24772c12008-08-21 19:31:52 +0000146 int closing;
Shahar Havivib373a632010-06-16 15:16:11 +0300147 Notifier exit;
aliguori64838172008-08-21 19:31:10 +0000148
aliguori446ab122008-09-14 01:06:09 +0000149 struct ctrl_struct ctrl;
balrogb9dc0332007-10-04 22:47:34 +0000150 struct endp_data endp_table[MAX_ENDPOINTS];
aliguori4b096fc2008-08-21 19:28:55 +0000151
aliguori4b096fc2008-08-21 19:28:55 +0000152 /* Host side address */
153 int bus_num;
154 int addr;
Hans de Goede0f5160d2010-11-10 10:06:23 +0100155 int devpath;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100156 struct USBAutoFilter match;
aliguori4b096fc2008-08-21 19:28:55 +0000157
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100158 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000159} USBHostDevice;
160
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100161static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
162
163static int usb_host_close(USBHostDevice *dev);
164static int parse_filter(const char *spec, struct USBAutoFilter *f);
165static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100166static int usb_host_read_file(char *line, size_t line_size,
167 const char *device_file, const char *device_name);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100168
aliguori64838172008-08-21 19:31:10 +0000169static int is_isoc(USBHostDevice *s, int ep)
170{
171 return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO;
172}
173
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100174static int is_valid(USBHostDevice *s, int ep)
175{
176 return s->endp_table[ep - 1].type != INVALID_EP_TYPE;
177}
178
aliguori64838172008-08-21 19:31:10 +0000179static int is_halted(USBHostDevice *s, int ep)
180{
181 return s->endp_table[ep - 1].halted;
182}
183
184static void clear_halt(USBHostDevice *s, int ep)
185{
186 s->endp_table[ep - 1].halted = 0;
187}
188
189static void set_halt(USBHostDevice *s, int ep)
190{
191 s->endp_table[ep - 1].halted = 1;
192}
193
Hans de Goedebb6d5492010-11-26 19:11:03 +0100194static int is_iso_started(USBHostDevice *s, int ep)
195{
196 return s->endp_table[ep - 1].iso_started;
197}
198
199static void clear_iso_started(USBHostDevice *s, int ep)
200{
201 s->endp_table[ep - 1].iso_started = 0;
202}
203
204static void set_iso_started(USBHostDevice *s, int ep)
205{
206 s->endp_table[ep - 1].iso_started = 1;
207}
208
Hans de Goede060dc842010-11-26 11:41:08 +0100209static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
210{
211 s->endp_table[ep - 1].iso_urb = iso_urb;
212}
213
214static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
215{
216 return s->endp_table[ep - 1].iso_urb;
217}
218
219static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
220{
221 s->endp_table[ep - 1].iso_urb_idx = i;
222}
223
224static int get_iso_urb_idx(USBHostDevice *s, int ep)
225{
226 return s->endp_table[ep - 1].iso_urb_idx;
227}
228
Hans de Goedebb6d5492010-11-26 19:11:03 +0100229static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
230{
231 s->endp_table[ep - 1].iso_buffer_used = i;
232}
233
234static int get_iso_buffer_used(USBHostDevice *s, int ep)
235{
236 return s->endp_table[ep - 1].iso_buffer_used;
237}
238
Hans de Goede060dc842010-11-26 11:41:08 +0100239static int get_max_packet_size(USBHostDevice *s, int ep)
240{
241 return s->endp_table[ep - 1].max_packet_size;
242}
243
David Ahern27911042010-04-24 10:26:22 -0600244/*
aliguori64838172008-08-21 19:31:10 +0000245 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100246 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600247 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000248 */
Hans de Goede060dc842010-11-26 11:41:08 +0100249struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000250{
aliguori64838172008-08-21 19:31:10 +0000251 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100252 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
aliguori64838172008-08-21 19:31:10 +0000253
Hans de Goede060dc842010-11-26 11:41:08 +0100254 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000255 USBPacket *packet;
256 USBHostDevice *hdev;
Hans de Goede060dc842010-11-26 11:41:08 +0100257
258 /* For buffered iso handling */
259 int iso_frame_idx; /* -1 means in flight */
260};
aliguori64838172008-08-21 19:31:10 +0000261
262static AsyncURB *async_alloc(void)
263{
264 return (AsyncURB *) qemu_mallocz(sizeof(AsyncURB));
balrogb9dc0332007-10-04 22:47:34 +0000265}
266
aliguori64838172008-08-21 19:31:10 +0000267static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000268{
aliguori64838172008-08-21 19:31:10 +0000269 qemu_free(aurb);
270}
balrogb9dc0332007-10-04 22:47:34 +0000271
aliguori446ab122008-09-14 01:06:09 +0000272static void async_complete_ctrl(USBHostDevice *s, USBPacket *p)
273{
274 switch(s->ctrl.state) {
275 case CTRL_STATE_SETUP:
276 if (p->len < s->ctrl.len)
277 s->ctrl.len = p->len;
278 s->ctrl.state = CTRL_STATE_DATA;
279 p->len = 8;
280 break;
281
282 case CTRL_STATE_ACK:
283 s->ctrl.state = CTRL_STATE_IDLE;
284 p->len = 0;
285 break;
286
287 default:
288 break;
289 }
290}
291
aliguori64838172008-08-21 19:31:10 +0000292static void async_complete(void *opaque)
293{
294 USBHostDevice *s = opaque;
295 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000296
aliguori64838172008-08-21 19:31:10 +0000297 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600298 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000299
David Ahern27911042010-04-24 10:26:22 -0600300 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000301 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600302 if (errno == EAGAIN) {
aliguori64838172008-08-21 19:31:10 +0000303 return;
David Ahern27911042010-04-24 10:26:22 -0600304 }
aliguori24772c12008-08-21 19:31:52 +0000305 if (errno == ENODEV && !s->closing) {
David Ahern27911042010-04-24 10:26:22 -0600306 printf("husb: device %d.%d disconnected\n",
307 s->bus_num, s->addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100308 usb_host_close(s);
309 usb_host_auto_check(NULL);
aliguori64838172008-08-21 19:31:10 +0000310 return;
311 }
312
malcd0f2c4c2010-02-07 02:03:50 +0300313 DPRINTF("husb: async. reap urb failed errno %d\n", errno);
aliguori64838172008-08-21 19:31:10 +0000314 return;
balrogb9dc0332007-10-04 22:47:34 +0000315 }
aliguori64838172008-08-21 19:31:10 +0000316
David Ahern27911042010-04-24 10:26:22 -0600317 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000318 aurb, aurb->urb.status, aurb->urb.actual_length);
319
Hans de Goede060dc842010-11-26 11:41:08 +0100320 /* If this is a buffered iso urb mark it as complete and don't do
321 anything else (it is handled further in usb_host_handle_iso_data) */
322 if (aurb->iso_frame_idx == -1) {
323 if (aurb->urb.status == -EPIPE) {
324 set_halt(s, aurb->urb.endpoint & 0xf);
325 }
326 aurb->iso_frame_idx = 0;
327 continue;
328 }
329
330 p = aurb->packet;
331
David Ahern27911042010-04-24 10:26:22 -0600332 if (p) {
aliguori64838172008-08-21 19:31:10 +0000333 switch (aurb->urb.status) {
334 case 0:
335 p->len = aurb->urb.actual_length;
David Ahern27911042010-04-24 10:26:22 -0600336 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
aliguori446ab122008-09-14 01:06:09 +0000337 async_complete_ctrl(s, p);
David Ahern27911042010-04-24 10:26:22 -0600338 }
aliguori64838172008-08-21 19:31:10 +0000339 break;
340
341 case -EPIPE:
342 set_halt(s, p->devep);
David Ahern27911042010-04-24 10:26:22 -0600343 p->len = USB_RET_STALL;
344 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200345
aliguori64838172008-08-21 19:31:10 +0000346 default:
347 p->len = USB_RET_NAK;
348 break;
349 }
350
351 usb_packet_complete(p);
David Ahern27911042010-04-24 10:26:22 -0600352 }
aliguori64838172008-08-21 19:31:10 +0000353
354 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000355 }
balrogb9dc0332007-10-04 22:47:34 +0000356}
357
aliguori64838172008-08-21 19:31:10 +0000358static void async_cancel(USBPacket *unused, void *opaque)
balrogb9dc0332007-10-04 22:47:34 +0000359{
aliguori64838172008-08-21 19:31:10 +0000360 AsyncURB *aurb = opaque;
361 USBHostDevice *s = aurb->hdev;
balrogb9dc0332007-10-04 22:47:34 +0000362
malcd0f2c4c2010-02-07 02:03:50 +0300363 DPRINTF("husb: async cancel. aurb %p\n", aurb);
balrogb9dc0332007-10-04 22:47:34 +0000364
aliguori64838172008-08-21 19:31:10 +0000365 /* Mark it as dead (see async_complete above) */
366 aurb->packet = NULL;
367
368 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
369 if (r < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300370 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
balrogb9dc0332007-10-04 22:47:34 +0000371 }
balrogb9dc0332007-10-04 22:47:34 +0000372}
373
aliguori446ab122008-09-14 01:06:09 +0000374static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000375{
376 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000377 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000378 int ret, i;
379
380 if (configuration == 0) /* address state - ignore */
381 return 1;
382
malcd0f2c4c2010-02-07 02:03:50 +0300383 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000384
balrogb9dc0332007-10-04 22:47:34 +0000385 i = 0;
386 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600387 if (dev_descr_len > dev->descr_len) {
balrogb9dc0332007-10-04 22:47:34 +0000388 goto fail;
David Ahern27911042010-04-24 10:26:22 -0600389 }
balrogb9dc0332007-10-04 22:47:34 +0000390
391 i += dev_descr_len;
392 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600393 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
394 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000395 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000396
balrogb9dc0332007-10-04 22:47:34 +0000397 if (dev->descr[i+1] != USB_DT_CONFIG) {
398 i += dev->descr[i];
399 continue;
400 }
401 config_descr_len = dev->descr[i];
402
David Ahern27911042010-04-24 10:26:22 -0600403 printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000404
aliguori446ab122008-09-14 01:06:09 +0000405 if (configuration < 0 || configuration == dev->descr[i + 5]) {
406 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000407 break;
aliguori446ab122008-09-14 01:06:09 +0000408 }
balrogb9dc0332007-10-04 22:47:34 +0000409
410 i += config_descr_len;
411 }
412
413 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600414 fprintf(stderr,
415 "husb: update iface failed. no matching configuration\n");
balrogb9dc0332007-10-04 22:47:34 +0000416 goto fail;
417 }
418 nb_interfaces = dev->descr[i + 4];
419
420#ifdef USBDEVFS_DISCONNECT
421 /* earlier Linux 2.4 do not support that */
422 {
423 struct usbdevfs_ioctl ctrl;
424 for (interface = 0; interface < nb_interfaces; interface++) {
425 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
426 ctrl.ifno = interface;
Brad Hards021730f2011-04-13 19:45:32 +1000427 ctrl.data = 0;
balrogb9dc0332007-10-04 22:47:34 +0000428 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
429 if (ret < 0 && errno != ENODATA) {
430 perror("USBDEVFS_DISCONNECT");
431 goto fail;
432 }
433 }
434 }
435#endif
436
437 /* XXX: only grab if all interfaces are free */
438 for (interface = 0; interface < nb_interfaces; interface++) {
439 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
440 if (ret < 0) {
441 if (errno == EBUSY) {
aliguori64838172008-08-21 19:31:10 +0000442 printf("husb: update iface. device already grabbed\n");
balrogb9dc0332007-10-04 22:47:34 +0000443 } else {
aliguori64838172008-08-21 19:31:10 +0000444 perror("husb: failed to claim interface");
balrogb9dc0332007-10-04 22:47:34 +0000445 }
446 fail:
447 return 0;
448 }
449 }
450
aliguori64838172008-08-21 19:31:10 +0000451 printf("husb: %d interfaces claimed for configuration %d\n",
balrogb9dc0332007-10-04 22:47:34 +0000452 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000453
aliguori446ab122008-09-14 01:06:09 +0000454 dev->ninterfaces = nb_interfaces;
455 dev->configuration = configuration;
456 return 1;
457}
458
459static int usb_host_release_interfaces(USBHostDevice *s)
460{
461 int ret, i;
462
malcd0f2c4c2010-02-07 02:03:50 +0300463 DPRINTF("husb: releasing interfaces\n");
aliguori446ab122008-09-14 01:06:09 +0000464
465 for (i = 0; i < s->ninterfaces; i++) {
466 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
467 if (ret < 0) {
468 perror("husb: failed to release interface");
469 return 0;
470 }
471 }
472
balrogb9dc0332007-10-04 22:47:34 +0000473 return 1;
474}
475
bellard059809e2006-07-19 18:06:15 +0000476static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000477{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100478 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000479
malcd0f2c4c2010-02-07 02:03:50 +0300480 DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000481
bellardbb36d472005-11-05 14:22:28 +0000482 ioctl(s->fd, USBDEVFS_RESET);
aliguori446ab122008-09-14 01:06:09 +0000483
484 usb_host_claim_interfaces(s, s->configuration);
ths5fafdf22007-09-16 21:08:06 +0000485}
bellardbb36d472005-11-05 14:22:28 +0000486
bellard059809e2006-07-19 18:06:15 +0000487static void usb_host_handle_destroy(USBDevice *dev)
488{
489 USBHostDevice *s = (USBHostDevice *)dev;
490
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100491 usb_host_close(s);
492 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300493 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000494}
495
balrogb9dc0332007-10-04 22:47:34 +0000496static int usb_linux_update_endp_table(USBHostDevice *s);
497
Hans de Goede060dc842010-11-26 11:41:08 +0100498/* iso data is special, we need to keep enough urbs in flight to make sure
499 that the controller never runs out of them, otherwise the device will
500 likely suffer a buffer underrun / overrun. */
501static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
502{
503 AsyncURB *aurb;
504 int i, j, len = get_max_packet_size(s, ep);
505
506 aurb = qemu_mallocz(ISO_URB_COUNT * sizeof(*aurb));
507 for (i = 0; i < ISO_URB_COUNT; i++) {
508 aurb[i].urb.endpoint = ep;
509 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
510 aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length);
511 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
512 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
513 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
514 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
515 aurb[i].urb.iso_frame_desc[j].length = len;
516 if (in) {
517 aurb[i].urb.endpoint |= 0x80;
518 /* Mark as fully consumed (idle) */
519 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
520 }
521 }
522 set_iso_urb(s, ep, aurb);
523
524 return aurb;
525}
526
527static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
528{
529 AsyncURB *aurb;
530 int i, ret, killed = 0, free = 1;
531
532 aurb = get_iso_urb(s, ep);
533 if (!aurb) {
534 return;
535 }
536
537 for (i = 0; i < ISO_URB_COUNT; i++) {
538 /* in flight? */
539 if (aurb[i].iso_frame_idx == -1) {
540 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
541 if (ret < 0) {
542 printf("husb: discard isoc in urb failed errno %d\n", errno);
543 free = 0;
544 continue;
545 }
546 killed++;
547 }
548 }
549
550 /* Make sure any urbs we've killed are reaped before we free them */
551 if (killed) {
552 async_complete(s);
553 }
554
555 for (i = 0; i < ISO_URB_COUNT; i++) {
556 qemu_free(aurb[i].urb.buffer);
557 }
558
559 if (free)
560 qemu_free(aurb);
561 else
562 printf("husb: leaking iso urbs because of discard failure\n");
563 set_iso_urb(s, ep, NULL);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100564 set_iso_urb_idx(s, ep, 0);
565 clear_iso_started(s, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100566}
567
568static int urb_status_to_usb_ret(int status)
569{
570 switch (status) {
571 case -EPIPE:
572 return USB_RET_STALL;
573 default:
574 return USB_RET_NAK;
575 }
576}
577
Hans de Goedebb6d5492010-11-26 19:11:03 +0100578static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100579{
580 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100581 int i, j, ret, max_packet_size, offset, len = 0;
Hans de Goede975f2992010-11-26 14:59:35 +0100582
583 max_packet_size = get_max_packet_size(s, p->devep);
584 if (max_packet_size == 0)
585 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100586
587 aurb = get_iso_urb(s, p->devep);
588 if (!aurb) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100589 aurb = usb_host_alloc_iso(s, p->devep, in);
Hans de Goede060dc842010-11-26 11:41:08 +0100590 }
591
592 i = get_iso_urb_idx(s, p->devep);
593 j = aurb[i].iso_frame_idx;
594 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100595 if (in) {
596 /* Check urb status */
597 if (aurb[i].urb.status) {
598 len = urb_status_to_usb_ret(aurb[i].urb.status);
599 /* Move to the next urb */
600 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
601 /* Check frame status */
602 } else if (aurb[i].urb.iso_frame_desc[j].status) {
603 len = urb_status_to_usb_ret(
604 aurb[i].urb.iso_frame_desc[j].status);
605 /* Check the frame fits */
606 } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
607 printf("husb: received iso data is larger then packet\n");
608 len = USB_RET_NAK;
609 /* All good copy data over */
610 } else {
611 len = aurb[i].urb.iso_frame_desc[j].actual_length;
612 memcpy(p->data,
613 aurb[i].urb.buffer +
614 j * aurb[i].urb.iso_frame_desc[0].length,
615 len);
616 }
Hans de Goede060dc842010-11-26 11:41:08 +0100617 } else {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100618 len = p->len;
619 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
620
621 /* Check the frame fits */
622 if (len > max_packet_size) {
623 printf("husb: send iso data is larger then max packet size\n");
624 return USB_RET_NAK;
625 }
626
627 /* All good copy data over */
628 memcpy(aurb[i].urb.buffer + offset, p->data, len);
629 aurb[i].urb.iso_frame_desc[j].length = len;
630 offset += len;
631 set_iso_buffer_used(s, p->devep, offset);
632
633 /* Start the stream once we have buffered enough data */
634 if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
635 set_iso_started(s, p->devep);
636 }
Hans de Goede060dc842010-11-26 11:41:08 +0100637 }
638 aurb[i].iso_frame_idx++;
639 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
640 i = (i + 1) % ISO_URB_COUNT;
641 set_iso_urb_idx(s, p->devep, i);
642 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100643 } else {
644 if (in) {
645 set_iso_started(s, p->devep);
646 } else {
647 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
648 }
Hans de Goede060dc842010-11-26 11:41:08 +0100649 }
650
Hans de Goedebb6d5492010-11-26 19:11:03 +0100651 if (is_iso_started(s, p->devep)) {
652 /* (Re)-submit all fully consumed / filled urbs */
653 for (i = 0; i < ISO_URB_COUNT; i++) {
654 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
655 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
656 if (ret < 0) {
657 printf("husb error submitting iso urb %d: %d\n", i, errno);
658 if (!in || len == 0) {
659 switch(errno) {
660 case ETIMEDOUT:
661 len = USB_RET_NAK;
662 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
aliguori446ab122008-09-14 01:06:09 +0000677static int usb_host_handle_data(USBHostDevice *s, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000678{
aliguori64838172008-08-21 19:31:10 +0000679 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000680 AsyncURB *aurb;
bellardbb36d472005-11-05 14:22:28 +0000681 int ret;
Hans de Goede060dc842010-11-26 11:41:08 +0100682 uint8_t ep;
683
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100684 if (!is_valid(s, p->devep)) {
685 return USB_RET_NAK;
686 }
687
Hans de Goede060dc842010-11-26 11:41:08 +0100688 if (p->pid == USB_TOKEN_IN) {
689 ep = p->devep | 0x80;
690 } else {
691 ep = p->devep;
692 }
693
694 if (is_halted(s, p->devep)) {
695 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
696 if (ret < 0) {
697 DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
698 ep, errno);
699 return USB_RET_NAK;
700 }
701 clear_halt(s, p->devep);
702 }
703
Hans de Goedebb6d5492010-11-26 19:11:03 +0100704 if (is_isoc(s, p->devep)) {
705 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
706 }
bellardbb36d472005-11-05 14:22:28 +0000707
aliguori64838172008-08-21 19:31:10 +0000708 aurb = async_alloc();
aliguori64838172008-08-21 19:31:10 +0000709 aurb->hdev = s;
710 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000711
aliguori64838172008-08-21 19:31:10 +0000712 urb = &aurb->urb;
713
Hans de Goede060dc842010-11-26 11:41:08 +0100714 urb->endpoint = ep;
aliguori64838172008-08-21 19:31:10 +0000715 urb->buffer = p->data;
balrogb9dc0332007-10-04 22:47:34 +0000716 urb->buffer_length = p->len;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100717 urb->type = USBDEVFS_URB_TYPE_BULK;
718 urb->usercontext = s;
aliguori64838172008-08-21 19:31:10 +0000719
720 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
721
David Ahern27911042010-04-24 10:26:22 -0600722 DPRINTF("husb: data submit. ep 0x%x len %u aurb %p\n",
723 urb->endpoint, p->len, aurb);
aliguori64838172008-08-21 19:31:10 +0000724
725 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300726 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori64838172008-08-21 19:31:10 +0000727 async_free(aurb);
728
balrogb9dc0332007-10-04 22:47:34 +0000729 switch(errno) {
730 case ETIMEDOUT:
731 return USB_RET_NAK;
732 case EPIPE:
733 default:
734 return USB_RET_STALL;
735 }
736 }
aliguori64838172008-08-21 19:31:10 +0000737
738 usb_defer_packet(p, async_cancel, aurb);
balrogb9dc0332007-10-04 22:47:34 +0000739 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000740}
741
aliguori446ab122008-09-14 01:06:09 +0000742static int ctrl_error(void)
743{
David Ahern27911042010-04-24 10:26:22 -0600744 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000745 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600746 } else {
aliguori446ab122008-09-14 01:06:09 +0000747 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600748 }
aliguori446ab122008-09-14 01:06:09 +0000749}
750
751static int usb_host_set_address(USBHostDevice *s, int addr)
752{
malcd0f2c4c2010-02-07 02:03:50 +0300753 DPRINTF("husb: ctrl set addr %u\n", addr);
aliguori446ab122008-09-14 01:06:09 +0000754 s->dev.addr = addr;
755 return 0;
756}
757
758static int usb_host_set_config(USBHostDevice *s, int config)
759{
760 usb_host_release_interfaces(s);
761
762 int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600763
malcd0f2c4c2010-02-07 02:03:50 +0300764 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600765
766 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000767 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600768 }
aliguori446ab122008-09-14 01:06:09 +0000769 usb_host_claim_interfaces(s, config);
770 return 0;
771}
772
773static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
774{
775 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100776 int i, ret;
777
Hans de Goede3a4854b2010-11-26 15:02:16 +0100778 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100779 if (is_isoc(s, i)) {
780 usb_host_stop_n_free_iso(s, i);
781 }
782 }
aliguori446ab122008-09-14 01:06:09 +0000783
784 si.interface = iface;
785 si.altsetting = alt;
786 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000787
David Ahern27911042010-04-24 10:26:22 -0600788 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
789 iface, alt, ret, errno);
790
791 if (ret < 0) {
792 return ctrl_error();
793 }
aliguori446ab122008-09-14 01:06:09 +0000794 usb_linux_update_endp_table(s);
795 return 0;
796}
797
798static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
799{
800 struct usbdevfs_urb *urb;
801 AsyncURB *aurb;
802 int ret, value, index;
Jim Parisc4c0e232009-08-24 14:56:12 -0400803 int buffer_len;
aliguori446ab122008-09-14 01:06:09 +0000804
David Ahern27911042010-04-24 10:26:22 -0600805 /*
aliguori446ab122008-09-14 01:06:09 +0000806 * Process certain standard device requests.
807 * These are infrequent and are processed synchronously.
808 */
809 value = le16_to_cpu(s->ctrl.req.wValue);
810 index = le16_to_cpu(s->ctrl.req.wIndex);
811
malcd0f2c4c2010-02-07 02:03:50 +0300812 DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
David Ahern27911042010-04-24 10:26:22 -0600813 s->ctrl.req.bRequestType, s->ctrl.req.bRequest, value, index,
814 s->ctrl.len);
aliguori446ab122008-09-14 01:06:09 +0000815
816 if (s->ctrl.req.bRequestType == 0) {
817 switch (s->ctrl.req.bRequest) {
818 case USB_REQ_SET_ADDRESS:
819 return usb_host_set_address(s, value);
820
821 case USB_REQ_SET_CONFIGURATION:
822 return usb_host_set_config(s, value & 0xff);
823 }
824 }
825
826 if (s->ctrl.req.bRequestType == 1 &&
David Ahern27911042010-04-24 10:26:22 -0600827 s->ctrl.req.bRequest == USB_REQ_SET_INTERFACE) {
aliguori446ab122008-09-14 01:06:09 +0000828 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -0600829 }
aliguori446ab122008-09-14 01:06:09 +0000830
831 /* The rest are asynchronous */
832
Jim Parisc4c0e232009-08-24 14:56:12 -0400833 buffer_len = 8 + s->ctrl.len;
834 if (buffer_len > sizeof(s->ctrl.buffer)) {
malcb2e3b6e2009-09-12 03:18:18 +0400835 fprintf(stderr, "husb: ctrl buffer too small (%u > %zu)\n",
836 buffer_len, sizeof(s->ctrl.buffer));
837 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -0400838 }
839
aliguori446ab122008-09-14 01:06:09 +0000840 aurb = async_alloc();
aliguori446ab122008-09-14 01:06:09 +0000841 aurb->hdev = s;
842 aurb->packet = p;
843
David Ahern27911042010-04-24 10:26:22 -0600844 /*
aliguori446ab122008-09-14 01:06:09 +0000845 * Setup ctrl transfer.
846 *
Brad Hardsa0102082011-04-13 19:45:33 +1000847 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +0000848 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -0600849 */
aliguori446ab122008-09-14 01:06:09 +0000850 urb = &aurb->urb;
851
852 urb->type = USBDEVFS_URB_TYPE_CONTROL;
853 urb->endpoint = p->devep;
854
855 urb->buffer = &s->ctrl.req;
Jim Parisc4c0e232009-08-24 14:56:12 -0400856 urb->buffer_length = buffer_len;
aliguori446ab122008-09-14 01:06:09 +0000857
858 urb->usercontext = s;
859
860 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
861
malcd0f2c4c2010-02-07 02:03:50 +0300862 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +0000863
864 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300865 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +0000866 async_free(aurb);
867
868 switch(errno) {
869 case ETIMEDOUT:
870 return USB_RET_NAK;
871 case EPIPE:
872 default:
873 return USB_RET_STALL;
874 }
875 }
876
877 usb_defer_packet(p, async_cancel, aurb);
878 return USB_RET_ASYNC;
879}
880
881static int do_token_setup(USBDevice *dev, USBPacket *p)
882{
883 USBHostDevice *s = (USBHostDevice *) dev;
884 int ret = 0;
885
David Ahern27911042010-04-24 10:26:22 -0600886 if (p->len != 8) {
aliguori446ab122008-09-14 01:06:09 +0000887 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600888 }
889
aliguori446ab122008-09-14 01:06:09 +0000890 memcpy(&s->ctrl.req, p->data, 8);
891 s->ctrl.len = le16_to_cpu(s->ctrl.req.wLength);
892 s->ctrl.offset = 0;
893 s->ctrl.state = CTRL_STATE_SETUP;
894
895 if (s->ctrl.req.bRequestType & USB_DIR_IN) {
896 ret = usb_host_handle_control(s, p);
David Ahern27911042010-04-24 10:26:22 -0600897 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000898 return ret;
David Ahern27911042010-04-24 10:26:22 -0600899 }
aliguori446ab122008-09-14 01:06:09 +0000900
David Ahern27911042010-04-24 10:26:22 -0600901 if (ret < s->ctrl.len) {
aliguori446ab122008-09-14 01:06:09 +0000902 s->ctrl.len = ret;
David Ahern27911042010-04-24 10:26:22 -0600903 }
aliguori446ab122008-09-14 01:06:09 +0000904 s->ctrl.state = CTRL_STATE_DATA;
905 } else {
David Ahern27911042010-04-24 10:26:22 -0600906 if (s->ctrl.len == 0) {
aliguori446ab122008-09-14 01:06:09 +0000907 s->ctrl.state = CTRL_STATE_ACK;
David Ahern27911042010-04-24 10:26:22 -0600908 } else {
aliguori446ab122008-09-14 01:06:09 +0000909 s->ctrl.state = CTRL_STATE_DATA;
David Ahern27911042010-04-24 10:26:22 -0600910 }
aliguori446ab122008-09-14 01:06:09 +0000911 }
912
913 return ret;
914}
915
916static int do_token_in(USBDevice *dev, USBPacket *p)
917{
918 USBHostDevice *s = (USBHostDevice *) dev;
919 int ret = 0;
920
David Ahern27911042010-04-24 10:26:22 -0600921 if (p->devep != 0) {
aliguori446ab122008-09-14 01:06:09 +0000922 return usb_host_handle_data(s, p);
David Ahern27911042010-04-24 10:26:22 -0600923 }
aliguori446ab122008-09-14 01:06:09 +0000924
925 switch(s->ctrl.state) {
926 case CTRL_STATE_ACK:
927 if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
928 ret = usb_host_handle_control(s, p);
David Ahern27911042010-04-24 10:26:22 -0600929 if (ret == USB_RET_ASYNC) {
aliguori446ab122008-09-14 01:06:09 +0000930 return USB_RET_ASYNC;
David Ahern27911042010-04-24 10:26:22 -0600931 }
aliguori446ab122008-09-14 01:06:09 +0000932 s->ctrl.state = CTRL_STATE_IDLE;
933 return ret > 0 ? 0 : ret;
934 }
935
936 return 0;
937
938 case CTRL_STATE_DATA:
939 if (s->ctrl.req.bRequestType & USB_DIR_IN) {
940 int len = s->ctrl.len - s->ctrl.offset;
David Ahern27911042010-04-24 10:26:22 -0600941 if (len > p->len) {
aliguori446ab122008-09-14 01:06:09 +0000942 len = p->len;
David Ahern27911042010-04-24 10:26:22 -0600943 }
aliguori446ab122008-09-14 01:06:09 +0000944 memcpy(p->data, s->ctrl.buffer + s->ctrl.offset, len);
945 s->ctrl.offset += len;
David Ahern27911042010-04-24 10:26:22 -0600946 if (s->ctrl.offset >= s->ctrl.len) {
aliguori446ab122008-09-14 01:06:09 +0000947 s->ctrl.state = CTRL_STATE_ACK;
David Ahern27911042010-04-24 10:26:22 -0600948 }
aliguori446ab122008-09-14 01:06:09 +0000949 return len;
950 }
951
952 s->ctrl.state = CTRL_STATE_IDLE;
953 return USB_RET_STALL;
954
955 default:
956 return USB_RET_STALL;
957 }
958}
959
960static int do_token_out(USBDevice *dev, USBPacket *p)
961{
962 USBHostDevice *s = (USBHostDevice *) dev;
963
David Ahern27911042010-04-24 10:26:22 -0600964 if (p->devep != 0) {
aliguori446ab122008-09-14 01:06:09 +0000965 return usb_host_handle_data(s, p);
David Ahern27911042010-04-24 10:26:22 -0600966 }
aliguori446ab122008-09-14 01:06:09 +0000967
968 switch(s->ctrl.state) {
969 case CTRL_STATE_ACK:
970 if (s->ctrl.req.bRequestType & USB_DIR_IN) {
971 s->ctrl.state = CTRL_STATE_IDLE;
972 /* transfer OK */
973 } else {
974 /* ignore additional output */
975 }
976 return 0;
977
978 case CTRL_STATE_DATA:
979 if (!(s->ctrl.req.bRequestType & USB_DIR_IN)) {
980 int len = s->ctrl.len - s->ctrl.offset;
David Ahern27911042010-04-24 10:26:22 -0600981 if (len > p->len) {
aliguori446ab122008-09-14 01:06:09 +0000982 len = p->len;
David Ahern27911042010-04-24 10:26:22 -0600983 }
aliguori446ab122008-09-14 01:06:09 +0000984 memcpy(s->ctrl.buffer + s->ctrl.offset, p->data, len);
985 s->ctrl.offset += len;
David Ahern27911042010-04-24 10:26:22 -0600986 if (s->ctrl.offset >= s->ctrl.len) {
aliguori446ab122008-09-14 01:06:09 +0000987 s->ctrl.state = CTRL_STATE_ACK;
David Ahern27911042010-04-24 10:26:22 -0600988 }
aliguori446ab122008-09-14 01:06:09 +0000989 return len;
990 }
991
992 s->ctrl.state = CTRL_STATE_IDLE;
993 return USB_RET_STALL;
994
995 default:
996 return USB_RET_STALL;
997 }
998}
999
1000/*
1001 * Packet handler.
1002 * Called by the HC (host controller).
1003 *
1004 * Returns length of the transaction or one of the USB_RET_XXX codes.
1005 */
blueswir1d9cf1572008-09-15 14:57:11 +00001006static int usb_host_handle_packet(USBDevice *s, USBPacket *p)
aliguori446ab122008-09-14 01:06:09 +00001007{
1008 switch(p->pid) {
1009 case USB_MSG_ATTACH:
1010 s->state = USB_STATE_ATTACHED;
1011 return 0;
1012
1013 case USB_MSG_DETACH:
1014 s->state = USB_STATE_NOTATTACHED;
1015 return 0;
1016
1017 case USB_MSG_RESET:
1018 s->remote_wakeup = 0;
1019 s->addr = 0;
1020 s->state = USB_STATE_DEFAULT;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001021 s->info->handle_reset(s);
aliguori446ab122008-09-14 01:06:09 +00001022 return 0;
1023 }
1024
1025 /* Rest of the PIDs must match our address */
David Ahern27911042010-04-24 10:26:22 -06001026 if (s->state < USB_STATE_DEFAULT || p->devaddr != s->addr) {
aliguori446ab122008-09-14 01:06:09 +00001027 return USB_RET_NODEV;
David Ahern27911042010-04-24 10:26:22 -06001028 }
aliguori446ab122008-09-14 01:06:09 +00001029
1030 switch (p->pid) {
1031 case USB_TOKEN_SETUP:
1032 return do_token_setup(s, p);
1033
1034 case USB_TOKEN_IN:
1035 return do_token_in(s, p);
1036
1037 case USB_TOKEN_OUT:
1038 return do_token_out(s, p);
David Ahern27911042010-04-24 10:26:22 -06001039
aliguori446ab122008-09-14 01:06:09 +00001040 default:
1041 return USB_RET_STALL;
1042 }
1043}
1044
Hans de Goede71d71bb2010-11-10 10:06:24 +01001045static int usb_linux_get_configuration(USBHostDevice *s)
balrogb9dc0332007-10-04 22:47:34 +00001046{
Hans de Goede71d71bb2010-11-10 10:06:24 +01001047 uint8_t configuration;
pbrooke41b3912008-10-28 18:22:59 +00001048 struct usb_ctrltransfer ct;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001049 int ret;
balrogb9dc0332007-10-04 22:47:34 +00001050
Hans de Goede2cc59d82010-11-10 10:06:25 +01001051 if (usb_fs_type == USB_FS_SYS) {
1052 char device_name[32], line[1024];
1053 int configuration;
1054
1055 sprintf(device_name, "%d-%d", s->bus_num, s->devpath);
1056
1057 if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
1058 device_name)) {
1059 goto usbdevfs;
1060 }
1061 if (sscanf(line, "%d", &configuration) != 1) {
1062 goto usbdevfs;
1063 }
1064 return configuration;
1065 }
1066
1067usbdevfs:
balrogb9dc0332007-10-04 22:47:34 +00001068 ct.bRequestType = USB_DIR_IN;
1069 ct.bRequest = USB_REQ_GET_CONFIGURATION;
1070 ct.wValue = 0;
1071 ct.wIndex = 0;
1072 ct.wLength = 1;
1073 ct.data = &configuration;
1074 ct.timeout = 50;
1075
1076 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
1077 if (ret < 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +01001078 perror("usb_linux_get_configuration");
1079 return -1;
balrogb9dc0332007-10-04 22:47:34 +00001080 }
1081
1082 /* in address state */
David Ahern27911042010-04-24 10:26:22 -06001083 if (configuration == 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +01001084 return -1;
David Ahern27911042010-04-24 10:26:22 -06001085 }
balrogb9dc0332007-10-04 22:47:34 +00001086
Hans de Goede71d71bb2010-11-10 10:06:24 +01001087 return configuration;
1088}
1089
Hans de Goedeed3a3282010-11-24 12:50:00 +01001090static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
1091 uint8_t configuration, uint8_t interface)
1092{
1093 uint8_t alt_setting;
1094 struct usb_ctrltransfer ct;
1095 int ret;
1096
Hans de Goedec43831f2010-11-24 12:57:59 +01001097 if (usb_fs_type == USB_FS_SYS) {
1098 char device_name[64], line[1024];
1099 int alt_setting;
1100
1101 sprintf(device_name, "%d-%d:%d.%d", s->bus_num, s->devpath,
1102 (int)configuration, (int)interface);
1103
1104 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
1105 device_name)) {
1106 goto usbdevfs;
1107 }
1108 if (sscanf(line, "%d", &alt_setting) != 1) {
1109 goto usbdevfs;
1110 }
1111 return alt_setting;
1112 }
1113
1114usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +01001115 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
1116 ct.bRequest = USB_REQ_GET_INTERFACE;
1117 ct.wValue = 0;
1118 ct.wIndex = interface;
1119 ct.wLength = 1;
1120 ct.data = &alt_setting;
1121 ct.timeout = 50;
1122 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
1123 if (ret < 0) {
1124 /* Assume alt 0 on error */
1125 return 0;
1126 }
1127
1128 return alt_setting;
1129}
1130
Hans de Goede71d71bb2010-11-10 10:06:24 +01001131/* returns 1 on problem encountered or 0 for success */
1132static int usb_linux_update_endp_table(USBHostDevice *s)
1133{
1134 uint8_t *descriptors;
1135 uint8_t devep, type, configuration, alt_interface;
Hans de Goedeed3a3282010-11-24 12:50:00 +01001136 int interface, length, i;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001137
Hans de Goedea0b5fec2010-11-26 14:56:17 +01001138 for (i = 0; i < MAX_ENDPOINTS; i++)
1139 s->endp_table[i].type = INVALID_EP_TYPE;
1140
Hans de Goede71d71bb2010-11-10 10:06:24 +01001141 i = usb_linux_get_configuration(s);
1142 if (i < 0)
1143 return 1;
1144 configuration = i;
1145
balrogb9dc0332007-10-04 22:47:34 +00001146 /* get the desired configuration, interface, and endpoint descriptors
1147 * from device description */
1148 descriptors = &s->descr[18];
1149 length = s->descr_len - 18;
1150 i = 0;
1151
1152 if (descriptors[i + 1] != USB_DT_CONFIG ||
1153 descriptors[i + 5] != configuration) {
malcd0f2c4c2010-02-07 02:03:50 +03001154 DPRINTF("invalid descriptor data - configuration\n");
balrogb9dc0332007-10-04 22:47:34 +00001155 return 1;
1156 }
1157 i += descriptors[i];
1158
1159 while (i < length) {
1160 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1161 (descriptors[i + 1] == USB_DT_INTERFACE &&
1162 descriptors[i + 4] == 0)) {
1163 i += descriptors[i];
1164 continue;
1165 }
1166
1167 interface = descriptors[i + 2];
Hans de Goedeed3a3282010-11-24 12:50:00 +01001168 alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
balrogb9dc0332007-10-04 22:47:34 +00001169
1170 /* the current interface descriptor is the active interface
1171 * and has endpoints */
1172 if (descriptors[i + 3] != alt_interface) {
1173 i += descriptors[i];
1174 continue;
1175 }
1176
1177 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001178 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001179 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001180 }
balrogb9dc0332007-10-04 22:47:34 +00001181
1182 if (i >= length)
1183 break;
1184
1185 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001186 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001187 break;
David Ahern27911042010-04-24 10:26:22 -06001188 }
balrogb9dc0332007-10-04 22:47:34 +00001189
1190 devep = descriptors[i + 2];
1191 switch (descriptors[i + 3] & 0x3) {
1192 case 0x00:
1193 type = USBDEVFS_URB_TYPE_CONTROL;
1194 break;
1195 case 0x01:
1196 type = USBDEVFS_URB_TYPE_ISO;
Hans de Goede060dc842010-11-26 11:41:08 +01001197 s->endp_table[(devep & 0xf) - 1].max_packet_size =
1198 descriptors[i + 4] + (descriptors[i + 5] << 8);
balrogb9dc0332007-10-04 22:47:34 +00001199 break;
1200 case 0x02:
1201 type = USBDEVFS_URB_TYPE_BULK;
1202 break;
1203 case 0x03:
1204 type = USBDEVFS_URB_TYPE_INTERRUPT;
1205 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -05001206 default:
1207 DPRINTF("usb_host: malformed endpoint type\n");
1208 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +00001209 }
1210 s->endp_table[(devep & 0xf) - 1].type = type;
aliguori64838172008-08-21 19:31:10 +00001211 s->endp_table[(devep & 0xf) - 1].halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001212
1213 i += descriptors[i];
1214 }
1215 }
1216 return 0;
1217}
1218
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001219static int usb_host_open(USBHostDevice *dev, int bus_num,
Hans de Goede0f5160d2010-11-10 10:06:23 +01001220 int addr, int devpath, const char *prod_name)
bellardbb36d472005-11-05 14:22:28 +00001221{
balrogb9dc0332007-10-04 22:47:34 +00001222 int fd = -1, ret;
bellardbb36d472005-11-05 14:22:28 +00001223 struct usbdevfs_connectinfo ci;
bellarda594cfb2005-11-06 16:13:29 +00001224 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001225
David Ahern27911042010-04-24 10:26:22 -06001226 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001227 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001228 }
aliguori64838172008-08-21 19:31:10 +00001229 printf("husb: open device %d.%d\n", bus_num, addr);
aliguori1f3870a2008-08-21 19:27:48 +00001230
aliguori0f431522008-10-07 20:06:37 +00001231 if (!usb_host_device_path) {
1232 perror("husb: USB Host Device Path not set");
1233 goto fail;
1234 }
1235 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001236 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001237 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001238 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001239 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001240 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001241 }
malcd0f2c4c2010-02-07 02:03:50 +03001242 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001243
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001244 dev->bus_num = bus_num;
1245 dev->addr = addr;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001246 dev->devpath = devpath;
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001247 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001248
balrogb9dc0332007-10-04 22:47:34 +00001249 /* read the device description */
1250 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1251 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001252 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001253 goto fail;
1254 }
ths3b46e622007-09-17 08:09:54 +00001255
balrogb9dc0332007-10-04 22:47:34 +00001256#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001257 {
balrogb9dc0332007-10-04 22:47:34 +00001258 int x;
1259 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001260 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001261 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001262 }
balrogb9dc0332007-10-04 22:47:34 +00001263 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001264 }
1265#endif
1266
balrogb9dc0332007-10-04 22:47:34 +00001267
David Ahern27911042010-04-24 10:26:22 -06001268 /*
1269 * Initial configuration is -1 which makes us claim first
aliguori446ab122008-09-14 01:06:09 +00001270 * available config. We used to start with 1, which does not
David Ahern27911042010-04-24 10:26:22 -06001271 * always work. I've seen devices where first config starts
aliguori446ab122008-09-14 01:06:09 +00001272 * with 2.
1273 */
David Ahern27911042010-04-24 10:26:22 -06001274 if (!usb_host_claim_interfaces(dev, -1)) {
balrogb9dc0332007-10-04 22:47:34 +00001275 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001276 }
bellardbb36d472005-11-05 14:22:28 +00001277
1278 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1279 if (ret < 0) {
balrog046833e2007-10-31 00:27:50 +00001280 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
bellardbb36d472005-11-05 14:22:28 +00001281 goto fail;
1282 }
1283
aliguori64838172008-08-21 19:31:10 +00001284 printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001285
balrogb9dc0332007-10-04 22:47:34 +00001286 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001287 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001288 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001289 }
balrogb9dc0332007-10-04 22:47:34 +00001290
David Ahern27911042010-04-24 10:26:22 -06001291 if (ci.slow) {
bellardbb36d472005-11-05 14:22:28 +00001292 dev->dev.speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001293 } else {
bellardbb36d472005-11-05 14:22:28 +00001294 dev->dev.speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001295 }
bellardbb36d472005-11-05 14:22:28 +00001296
David Ahern27911042010-04-24 10:26:22 -06001297 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001298 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001299 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001300 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001301 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001302 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001303 }
bellard1f6e24e2006-06-26 21:00:51 +00001304
aliguori64838172008-08-21 19:31:10 +00001305 /* USB devio uses 'write' flag to check for async completions */
1306 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001307
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001308 usb_device_attach(&dev->dev);
1309 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001310
balrogb9dc0332007-10-04 22:47:34 +00001311fail:
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001312 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001313 if (fd != -1) {
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001314 close(fd);
David Ahern27911042010-04-24 10:26:22 -06001315 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001316 return -1;
1317}
1318
1319static int usb_host_close(USBHostDevice *dev)
1320{
Hans de Goede060dc842010-11-26 11:41:08 +01001321 int i;
1322
David Ahern27911042010-04-24 10:26:22 -06001323 if (dev->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001324 return -1;
David Ahern27911042010-04-24 10:26:22 -06001325 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001326
1327 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1328 dev->closing = 1;
Hans de Goede3a4854b2010-11-26 15:02:16 +01001329 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +01001330 if (is_isoc(dev, i)) {
1331 usb_host_stop_n_free_iso(dev, i);
1332 }
1333 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001334 async_complete(dev);
1335 dev->closing = 0;
1336 usb_device_detach(&dev->dev);
Shahar Havivi00ff2272010-06-16 15:15:37 +03001337 ioctl(dev->fd, USBDEVFS_RESET);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001338 close(dev->fd);
1339 dev->fd = -1;
1340 return 0;
1341}
1342
Shahar Havivib373a632010-06-16 15:16:11 +03001343static void usb_host_exit_notifier(struct Notifier* n)
1344{
1345 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1346
1347 if (s->fd != -1) {
1348 ioctl(s->fd, USBDEVFS_RESET);
1349 }
1350}
1351
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001352static int usb_host_initfn(USBDevice *dev)
1353{
1354 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1355
1356 dev->auto_attach = 0;
1357 s->fd = -1;
1358 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001359 s->exit.notify = usb_host_exit_notifier;
1360 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001361 usb_host_auto_check(NULL);
1362 return 0;
bellardbb36d472005-11-05 14:22:28 +00001363}
1364
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001365static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001366 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001367 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001368 .qdev.size = sizeof(USBHostDevice),
1369 .init = usb_host_initfn,
1370 .handle_packet = usb_host_handle_packet,
1371 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001372 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001373 .usbdevice_name = "host",
1374 .usbdevice_init = usb_host_device_open,
1375 .qdev.props = (Property[]) {
1376 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1377 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
1378 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1379 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
1380 DEFINE_PROP_END_OF_LIST(),
1381 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001382};
1383
1384static void usb_host_register_devices(void)
1385{
1386 usb_qdev_register(&usb_host_dev_info);
1387}
1388device_init(usb_host_register_devices)
1389
aliguori4b096fc2008-08-21 19:28:55 +00001390USBDevice *usb_host_device_open(const char *devname)
1391{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001392 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001393 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001394 char *p;
1395
Markus Armbruster556cd092009-12-09 17:07:53 +01001396 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001397
aliguori5d0c5752008-09-14 01:07:41 +00001398 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001399 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001400 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001401 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001402 } else {
1403 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001404 filter.bus_num = strtoul(devname, NULL, 0);
1405 filter.addr = strtoul(p + 1, NULL, 0);
1406 filter.vendor_id = 0;
1407 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001408 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001409 filter.bus_num = 0;
1410 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001411 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001412 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001413 } else {
1414 goto fail;
1415 }
aliguori5d0c5752008-09-14 01:07:41 +00001416 }
1417
Markus Armbruster0745eb12009-11-27 13:05:53 +01001418 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1419 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001420 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1421 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001422 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001423 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001424
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001425fail:
1426 qdev_free(&dev->qdev);
1427 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001428}
aliguori5d0c5752008-09-14 01:07:41 +00001429
1430int usb_host_device_close(const char *devname)
1431{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001432#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001433 char product_name[PRODUCT_NAME_SZ];
1434 int bus_num, addr;
1435 USBHostDevice *s;
1436
David Ahern27911042010-04-24 10:26:22 -06001437 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001438 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001439 }
1440 if (usb_host_find_device(&bus_num, &addr, product_name,
1441 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001442 return -1;
David Ahern27911042010-04-24 10:26:22 -06001443 }
aliguori5d0c5752008-09-14 01:07:41 +00001444 s = hostdev_find(bus_num, addr);
1445 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001446 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001447 return 0;
1448 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001449#endif
aliguori5d0c5752008-09-14 01:07:41 +00001450
1451 return -1;
1452}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001453
bellarda594cfb2005-11-06 16:13:29 +00001454static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001455 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001456 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001457{
bellarda594cfb2005-11-06 16:13:29 +00001458 const char *p;
1459 char *q;
1460 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001461 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001462 return -1;
David Ahern27911042010-04-24 10:26:22 -06001463 }
bellarda594cfb2005-11-06 16:13:29 +00001464 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001465 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001466 p++;
David Ahern27911042010-04-24 10:26:22 -06001467 }
bellarda594cfb2005-11-06 16:13:29 +00001468 q = buf;
1469 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001470 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001471 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001472 }
bellarda594cfb2005-11-06 16:13:29 +00001473 p++;
1474 }
1475 *q = '\0';
1476 return q - buf;
1477}
bellardbb36d472005-11-05 14:22:28 +00001478
aliguori0f431522008-10-07 20:06:37 +00001479/*
1480 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1481 * host's USB devices. This is legacy support since many distributions
1482 * are moving to /sys/bus/usb
1483 */
1484static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001485{
Blue Swirl660f11b2009-07-31 21:16:51 +00001486 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001487 char line[1024];
1488 char buf[1024];
1489 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
bellarda594cfb2005-11-06 16:13:29 +00001490 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001491 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001492
aliguori0f431522008-10-07 20:06:37 +00001493 if (!usb_host_device_path) {
1494 perror("husb: USB Host Device Path not set");
1495 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001496 }
aliguori0f431522008-10-07 20:06:37 +00001497 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1498 f = fopen(line, "r");
1499 if (!f) {
1500 perror("husb: cannot open devices file");
1501 goto the_end;
1502 }
1503
bellarda594cfb2005-11-06 16:13:29 +00001504 device_count = 0;
1505 bus_num = addr = speed = class_id = product_id = vendor_id = 0;
bellardbb36d472005-11-05 14:22:28 +00001506 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001507 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001508 break;
David Ahern27911042010-04-24 10:26:22 -06001509 }
1510 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001511 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001512 }
bellarda594cfb2005-11-06 16:13:29 +00001513 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001514 if (device_count && (vendor_id || product_id)) {
1515 /* New device. Add the previously discovered device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001516 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001517 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001518 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001519 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001520 }
bellarda594cfb2005-11-06 16:13:29 +00001521 }
David Ahern27911042010-04-24 10:26:22 -06001522 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001523 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001524 }
bellarda594cfb2005-11-06 16:13:29 +00001525 bus_num = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001526 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001527 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001528 }
bellarda594cfb2005-11-06 16:13:29 +00001529 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001530 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001531 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001532 }
1533 if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001534 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001535 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001536 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001537 } else {
bellarda594cfb2005-11-06 16:13:29 +00001538 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001539 }
bellarda594cfb2005-11-06 16:13:29 +00001540 product_name[0] = '\0';
1541 class_id = 0xff;
1542 device_count++;
1543 product_id = 0;
1544 vendor_id = 0;
1545 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001546 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001547 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001548 }
bellarda594cfb2005-11-06 16:13:29 +00001549 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001550 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001551 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001552 }
bellarda594cfb2005-11-06 16:13:29 +00001553 product_id = strtoul(buf, NULL, 16);
1554 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001555 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001556 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001557 }
bellarda594cfb2005-11-06 16:13:29 +00001558 pstrcpy(product_name, sizeof(product_name), buf);
1559 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001560 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001561 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001562 }
bellarda594cfb2005-11-06 16:13:29 +00001563 class_id = strtoul(buf, NULL, 16);
1564 }
1565 fail: ;
1566 }
pbrook38ca0f62006-03-11 18:03:38 +00001567 if (device_count && (vendor_id || product_id)) {
1568 /* Add the last device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001569 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001570 product_id, product_name, speed);
1571 }
1572 the_end:
David Ahern27911042010-04-24 10:26:22 -06001573 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001574 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001575 }
aliguori0f431522008-10-07 20:06:37 +00001576 return ret;
1577}
1578
1579/*
1580 * Read sys file-system device file
1581 *
1582 * @line address of buffer to put file contents in
1583 * @line_size size of line
1584 * @device_file path to device file (printf format string)
1585 * @device_name device being opened (inserted into device_file)
1586 *
1587 * @return 0 failed, 1 succeeded ('line' contains data)
1588 */
David Ahern27911042010-04-24 10:26:22 -06001589static int usb_host_read_file(char *line, size_t line_size,
1590 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001591{
1592 FILE *f;
1593 int ret = 0;
1594 char filename[PATH_MAX];
1595
blueswir1b4e237a2008-12-28 15:45:20 +00001596 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1597 device_file);
aliguori0f431522008-10-07 20:06:37 +00001598 f = fopen(filename, "r");
1599 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001600 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001601 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001602 }
1603
1604 return ret;
1605}
1606
1607/*
1608 * Use /sys/bus/usb/devices/ directory to determine host's USB
1609 * devices.
1610 *
1611 * This code is based on Robert Schiele's original patches posted to
1612 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1613 */
1614static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1615{
Blue Swirl660f11b2009-07-31 21:16:51 +00001616 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001617 char line[1024];
Hans de Goede0f5160d2010-11-10 10:06:23 +01001618 int bus_num, addr, devpath, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001619 int ret = 0;
1620 char product_name[512];
1621 struct dirent *de;
1622
1623 dir = opendir(USBSYSBUS_PATH "/devices");
1624 if (!dir) {
1625 perror("husb: cannot open devices directory");
1626 goto the_end;
1627 }
1628
1629 while ((de = readdir(dir))) {
1630 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
1631 char *tmpstr = de->d_name;
David Ahern27911042010-04-24 10:26:22 -06001632 if (!strncmp(de->d_name, "usb", 3)) {
aliguori0f431522008-10-07 20:06:37 +00001633 tmpstr += 3;
David Ahern27911042010-04-24 10:26:22 -06001634 }
Hans de Goede0f5160d2010-11-10 10:06:23 +01001635 if (sscanf(tmpstr, "%d-%d", &bus_num, &devpath) < 1) {
1636 goto the_end;
1637 }
aliguori0f431522008-10-07 20:06:37 +00001638
David Ahern27911042010-04-24 10:26:22 -06001639 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001640 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001641 }
1642 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001643 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001644 }
blueswir1b4e237a2008-12-28 15:45:20 +00001645 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001646 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001647 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001648 }
1649 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001650 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001651 }
aliguori0f431522008-10-07 20:06:37 +00001652
David Ahern27911042010-04-24 10:26:22 -06001653 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1654 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001655 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001656 }
1657 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001658 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001659 }
blueswir1b4e237a2008-12-28 15:45:20 +00001660 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001661 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001662 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001663 }
1664 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001665 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001666 }
blueswir1b4e237a2008-12-28 15:45:20 +00001667 if (!usb_host_read_file(line, sizeof(line), "product",
1668 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001669 *product_name = 0;
1670 } else {
David Ahern27911042010-04-24 10:26:22 -06001671 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001672 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001673 }
aliguori0f431522008-10-07 20:06:37 +00001674 pstrcpy(product_name, sizeof(product_name), line);
1675 }
1676
David Ahern27911042010-04-24 10:26:22 -06001677 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001678 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001679 }
1680 if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001681 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001682 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001683 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001684 } else {
aliguori0f431522008-10-07 20:06:37 +00001685 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001686 }
aliguori0f431522008-10-07 20:06:37 +00001687
Hans de Goede0f5160d2010-11-10 10:06:23 +01001688 ret = func(opaque, bus_num, addr, devpath, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001689 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001690 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001691 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001692 }
aliguori0f431522008-10-07 20:06:37 +00001693 }
1694 }
1695 the_end:
David Ahern27911042010-04-24 10:26:22 -06001696 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001697 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001698 }
aliguori0f431522008-10-07 20:06:37 +00001699 return ret;
1700}
1701
1702/*
1703 * Determine how to access the host's USB devices and call the
1704 * specific support function.
1705 */
1706static int usb_host_scan(void *opaque, USBScanFunc *func)
1707{
aliguori376253e2009-03-05 23:01:23 +00001708 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001709 FILE *f = NULL;
1710 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001711 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001712 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1713 char devpath[PATH_MAX];
1714
1715 /* only check the host once */
1716 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001717 dir = opendir(USBSYSBUS_PATH "/devices");
1718 if (dir) {
1719 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1720 strcpy(devpath, USBDEVBUS_PATH);
1721 usb_fs_type = USB_FS_SYS;
1722 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001723 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001724 goto found_devices;
1725 }
aliguori0f431522008-10-07 20:06:37 +00001726 f = fopen(USBPROCBUS_PATH "/devices", "r");
1727 if (f) {
1728 /* devices found in /proc/bus/usb/ */
1729 strcpy(devpath, USBPROCBUS_PATH);
1730 usb_fs_type = USB_FS_PROC;
1731 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001732 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001733 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001734 }
1735 /* try additional methods if an access method hasn't been found yet */
1736 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001737 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001738 /* devices found in /dev/bus/usb/ */
1739 strcpy(devpath, USBDEVBUS_PATH);
1740 usb_fs_type = USB_FS_DEV;
1741 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001742 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001743 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001744 }
aliguorif16a0db2008-10-21 16:34:20 +00001745 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001746 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001747 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001748 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001749 }
aliguorif16a0db2008-10-21 16:34:20 +00001750 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001751 }
1752
1753 /* the module setting (used later for opening devices) */
1754 usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001755 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001756 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001757 monitor_printf(mon, "husb: using %s file-system with %s\n",
1758 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001759 }
aliguori0f431522008-10-07 20:06:37 +00001760 }
1761
1762 switch (usb_fs_type) {
1763 case USB_FS_PROC:
1764 case USB_FS_DEV:
1765 ret = usb_host_scan_dev(opaque, func);
1766 break;
1767 case USB_FS_SYS:
1768 ret = usb_host_scan_sys(opaque, func);
1769 break;
aliguorif16a0db2008-10-21 16:34:20 +00001770 default:
1771 ret = -EINVAL;
1772 break;
aliguori0f431522008-10-07 20:06:37 +00001773 }
bellarda594cfb2005-11-06 16:13:29 +00001774 return ret;
1775}
1776
aliguori4b096fc2008-08-21 19:28:55 +00001777static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001778
Hans de Goede0f5160d2010-11-10 10:06:23 +01001779static int usb_host_auto_scan(void *opaque, int bus_num, int addr, int devpath,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001780 int class_id, int vendor_id, int product_id,
1781 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001782{
1783 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001784 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001785
1786 /* Ignore hubs */
1787 if (class_id == 9)
1788 return 0;
1789
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001790 QTAILQ_FOREACH(s, &hostdevs, next) {
1791 f = &s->match;
1792
David Ahern27911042010-04-24 10:26:22 -06001793 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001794 continue;
David Ahern27911042010-04-24 10:26:22 -06001795 }
1796 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001797 continue;
David Ahern27911042010-04-24 10:26:22 -06001798 }
aliguori4b096fc2008-08-21 19:28:55 +00001799
David Ahern27911042010-04-24 10:26:22 -06001800 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001801 continue;
David Ahern27911042010-04-24 10:26:22 -06001802 }
aliguori4b096fc2008-08-21 19:28:55 +00001803
David Ahern27911042010-04-24 10:26:22 -06001804 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001805 continue;
David Ahern27911042010-04-24 10:26:22 -06001806 }
aliguori4b096fc2008-08-21 19:28:55 +00001807 /* We got a match */
1808
Markus Armbruster33e66b82009-10-07 01:15:57 +02001809 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001810 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001811 return 0;
David Ahern27911042010-04-24 10:26:22 -06001812 }
malcd0f2c4c2010-02-07 02:03:50 +03001813 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001814
Hans de Goede0f5160d2010-11-10 10:06:23 +01001815 usb_host_open(s, bus_num, addr, devpath, product_name);
aliguori4b096fc2008-08-21 19:28:55 +00001816 }
1817
1818 return 0;
1819}
1820
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001821static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001822{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001823 struct USBHostDevice *s;
1824 int unconnected = 0;
1825
aliguori4b096fc2008-08-21 19:28:55 +00001826 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001827
1828 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001829 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001830 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001831 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001832 }
1833
1834 if (unconnected == 0) {
1835 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001836 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001837 qemu_del_timer(usb_auto_timer);
David Ahern27911042010-04-24 10:26:22 -06001838 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001839 return;
1840 }
1841
1842 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001843 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001844 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001845 return;
David Ahern27911042010-04-24 10:26:22 -06001846 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001847 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001848 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001849}
1850
1851/*
aliguori5d0c5752008-09-14 01:07:41 +00001852 * Autoconnect filter
1853 * Format:
1854 * auto:bus:dev[:vid:pid]
1855 * auto:bus.dev[:vid:pid]
1856 *
1857 * bus - bus number (dec, * means any)
1858 * dev - device number (dec, * means any)
1859 * vid - vendor id (hex, * means any)
1860 * pid - product id (hex, * means any)
1861 *
1862 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001863 */
aliguori5d0c5752008-09-14 01:07:41 +00001864static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001865{
aliguori5d0c5752008-09-14 01:07:41 +00001866 enum { BUS, DEV, VID, PID, DONE };
1867 const char *p = spec;
1868 int i;
1869
Markus Armbruster0745eb12009-11-27 13:05:53 +01001870 f->bus_num = 0;
1871 f->addr = 0;
1872 f->vendor_id = 0;
1873 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001874
1875 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001876 p = strpbrk(p, ":.");
1877 if (!p) {
1878 break;
1879 }
aliguori5d0c5752008-09-14 01:07:41 +00001880 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001881
David Ahern27911042010-04-24 10:26:22 -06001882 if (*p == '*') {
1883 continue;
1884 }
aliguori5d0c5752008-09-14 01:07:41 +00001885 switch(i) {
1886 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1887 case DEV: f->addr = strtol(p, NULL, 10); break;
1888 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1889 case PID: f->product_id = strtol(p, NULL, 16); break;
1890 }
aliguori4b096fc2008-08-21 19:28:55 +00001891 }
1892
aliguori5d0c5752008-09-14 01:07:41 +00001893 if (i < DEV) {
1894 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1895 return -1;
1896 }
1897
1898 return 0;
1899}
1900
bellarda594cfb2005-11-06 16:13:29 +00001901/**********************/
1902/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001903
bellarda594cfb2005-11-06 16:13:29 +00001904struct usb_class_info {
1905 int class;
1906 const char *class_name;
1907};
1908
1909static const struct usb_class_info usb_class_info[] = {
1910 { USB_CLASS_AUDIO, "Audio"},
1911 { USB_CLASS_COMM, "Communication"},
1912 { USB_CLASS_HID, "HID"},
1913 { USB_CLASS_HUB, "Hub" },
1914 { USB_CLASS_PHYSICAL, "Physical" },
1915 { USB_CLASS_PRINTER, "Printer" },
1916 { USB_CLASS_MASS_STORAGE, "Storage" },
1917 { USB_CLASS_CDC_DATA, "Data" },
1918 { USB_CLASS_APP_SPEC, "Application Specific" },
1919 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1920 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001921 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001922 { USB_CLASS_CONTENT_SEC, "Content Security" },
1923 { -1, NULL }
1924};
1925
1926static const char *usb_class_str(uint8_t class)
1927{
1928 const struct usb_class_info *p;
1929 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001930 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001931 break;
David Ahern27911042010-04-24 10:26:22 -06001932 }
bellardbb36d472005-11-05 14:22:28 +00001933 }
bellarda594cfb2005-11-06 16:13:29 +00001934 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001935}
1936
Blue Swirl179da8a2009-09-07 19:00:18 +00001937static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
pbrook9596ebb2007-11-18 01:44:38 +00001938 int vendor_id, int product_id,
1939 const char *product_name,
1940 int speed)
bellardbb36d472005-11-05 14:22:28 +00001941{
bellarda594cfb2005-11-06 16:13:29 +00001942 const char *class_str, *speed_str;
1943
1944 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001945 case USB_SPEED_LOW:
1946 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001947 break;
ths5fafdf22007-09-16 21:08:06 +00001948 case USB_SPEED_FULL:
1949 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001950 break;
ths5fafdf22007-09-16 21:08:06 +00001951 case USB_SPEED_HIGH:
1952 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001953 break;
1954 default:
ths5fafdf22007-09-16 21:08:06 +00001955 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001956 break;
bellardbb36d472005-11-05 14:22:28 +00001957 }
bellarda594cfb2005-11-06 16:13:29 +00001958
aliguori376253e2009-03-05 23:01:23 +00001959 monitor_printf(mon, " Device %d.%d, speed %s Mb/s\n",
bellarda594cfb2005-11-06 16:13:29 +00001960 bus_num, addr, speed_str);
1961 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001962 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001963 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001964 } else {
aliguori376253e2009-03-05 23:01:23 +00001965 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001966 }
aliguori376253e2009-03-05 23:01:23 +00001967 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001968 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001969 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001970 }
aliguori376253e2009-03-05 23:01:23 +00001971 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001972}
1973
ths5fafdf22007-09-16 21:08:06 +00001974static int usb_host_info_device(void *opaque, int bus_num, int addr,
Hans de Goede0f5160d2010-11-10 10:06:23 +01001975 int devpath, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001976 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001977 const char *product_name,
1978 int speed)
1979{
Blue Swirl179da8a2009-09-07 19:00:18 +00001980 Monitor *mon = opaque;
1981
1982 usb_info_device(mon, bus_num, addr, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001983 product_name, speed);
1984 return 0;
1985}
1986
aliguoriac4ffb52008-09-22 15:04:31 +00001987static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001988{
David Ahern27911042010-04-24 10:26:22 -06001989 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001990 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001991 } else {
1992 snprintf(str, size, "%d", val);
1993 }
aliguori5d0c5752008-09-14 01:07:41 +00001994}
1995
aliguoriac4ffb52008-09-22 15:04:31 +00001996static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001997{
David Ahern27911042010-04-24 10:26:22 -06001998 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001999 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06002000 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002001 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06002002 }
aliguori5d0c5752008-09-14 01:07:41 +00002003}
2004
aliguori376253e2009-03-05 23:01:23 +00002005void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00002006{
aliguori5d0c5752008-09-14 01:07:41 +00002007 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002008 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00002009
Blue Swirl179da8a2009-09-07 19:00:18 +00002010 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00002011
David Ahern27911042010-04-24 10:26:22 -06002012 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002013 return;
David Ahern27911042010-04-24 10:26:22 -06002014 }
2015
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002016 monitor_printf(mon, " Auto filters:\n");
2017 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00002018 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002019 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00002020 dec2str(f->bus_num, bus, sizeof(bus));
2021 dec2str(f->addr, addr, sizeof(addr));
2022 hex2str(f->vendor_id, vid, sizeof(vid));
2023 hex2str(f->product_id, pid, sizeof(pid));
aliguori376253e2009-03-05 23:01:23 +00002024 monitor_printf(mon, " Device %s.%s ID %s:%s\n",
2025 bus, addr, vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00002026 }
bellardbb36d472005-11-05 14:22:28 +00002027}