blob: 12e8772a4f8b5ba3478636b38813544a91f16343 [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"
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +020037#include "trace.h"
bellardbb36d472005-11-05 14:22:28 +000038
bellardbb36d472005-11-05 14:22:28 +000039#include <dirent.h>
40#include <sys/ioctl.h>
bellardbb36d472005-11-05 14:22:28 +000041
aliguori446ab122008-09-14 01:06:09 +000042#include <linux/usbdevice_fs.h>
43#include <linux/version.h>
44#include "hw/usb.h"
bellardbb36d472005-11-05 14:22:28 +000045
blueswir1d9cf1572008-09-15 14:57:11 +000046/* We redefine it to avoid version problems */
47struct usb_ctrltransfer {
48 uint8_t bRequestType;
49 uint8_t bRequest;
50 uint16_t wValue;
51 uint16_t wIndex;
52 uint16_t wLength;
53 uint32_t timeout;
54 void *data;
55};
56
Gerd Hoffmann5557d822011-05-10 11:43:57 +020057typedef int USBScanFunc(void *opaque, int bus_num, int addr, char *port,
Hans de Goede0f5160d2010-11-10 10:06:23 +010058 int class_id, int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +000059 const char *product_name, int speed);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010060
Markus Armbruster0745eb12009-11-27 13:05:53 +010061//#define DEBUG
aliguori64838172008-08-21 19:31:10 +000062
63#ifdef DEBUG
malcd0f2c4c2010-02-07 02:03:50 +030064#define DPRINTF printf
aliguori64838172008-08-21 19:31:10 +000065#else
malcd0f2c4c2010-02-07 02:03:50 +030066#define DPRINTF(...)
aliguori64838172008-08-21 19:31:10 +000067#endif
bellardbb36d472005-11-05 14:22:28 +000068
blueswir15be8e1f2008-10-25 11:47:20 +000069#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
70
aliguori0f431522008-10-07 20:06:37 +000071#define USBPROCBUS_PATH "/proc/bus/usb"
bellard1f6e24e2006-06-26 21:00:51 +000072#define PRODUCT_NAME_SZ 32
Hans de Goede3a4854b2010-11-26 15:02:16 +010073#define MAX_ENDPOINTS 15
Gerd Hoffmann5557d822011-05-10 11:43:57 +020074#define MAX_PORTLEN 16
aliguori0f431522008-10-07 20:06:37 +000075#define USBDEVBUS_PATH "/dev/bus/usb"
76#define USBSYSBUS_PATH "/sys/bus/usb"
77
78static char *usb_host_device_path;
79
80#define USB_FS_NONE 0
81#define USB_FS_PROC 1
82#define USB_FS_DEV 2
83#define USB_FS_SYS 3
84
85static int usb_fs_type;
bellardbb36d472005-11-05 14:22:28 +000086
balrogb9dc0332007-10-04 22:47:34 +000087/* endpoint association data */
Hans de Goede060dc842010-11-26 11:41:08 +010088#define ISO_FRAME_DESC_PER_URB 32
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;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200104 int inflight;
balrogb9dc0332007-10-04 22:47:34 +0000105};
106
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100107struct USBAutoFilter {
108 uint32_t bus_num;
109 uint32_t addr;
Gerd Hoffmann9056a292011-05-10 12:07:42 +0200110 char *port;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100111 uint32_t vendor_id;
112 uint32_t product_id;
113};
114
bellardbb36d472005-11-05 14:22:28 +0000115typedef struct USBHostDevice {
116 USBDevice dev;
aliguori64838172008-08-21 19:31:10 +0000117 int fd;
118
Hans de Goedef8ddbfb2011-05-31 11:35:26 +0200119 uint8_t descr[8192];
aliguori64838172008-08-21 19:31:10 +0000120 int descr_len;
121 int configuration;
aliguori446ab122008-09-14 01:06:09 +0000122 int ninterfaces;
aliguori24772c12008-08-21 19:31:52 +0000123 int closing;
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200124 uint32_t iso_urb_count;
Shahar Havivib373a632010-06-16 15:16:11 +0300125 Notifier exit;
aliguori64838172008-08-21 19:31:10 +0000126
balrogb9dc0332007-10-04 22:47:34 +0000127 struct endp_data endp_table[MAX_ENDPOINTS];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200128 QLIST_HEAD(, AsyncURB) aurbs;
aliguori4b096fc2008-08-21 19:28:55 +0000129
aliguori4b096fc2008-08-21 19:28:55 +0000130 /* Host side address */
131 int bus_num;
132 int addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200133 char port[MAX_PORTLEN];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100134 struct USBAutoFilter match;
aliguori4b096fc2008-08-21 19:28:55 +0000135
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100136 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000137} USBHostDevice;
138
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100139static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
140
141static int usb_host_close(USBHostDevice *dev);
142static int parse_filter(const char *spec, struct USBAutoFilter *f);
143static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100144static int usb_host_read_file(char *line, size_t line_size,
145 const char *device_file, const char *device_name);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100146
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200147static struct endp_data *get_endp(USBHostDevice *s, int ep)
148{
149 return s->endp_table + ep - 1;
150}
151
aliguori64838172008-08-21 19:31:10 +0000152static int is_isoc(USBHostDevice *s, int ep)
153{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200154 return get_endp(s, ep)->type == USBDEVFS_URB_TYPE_ISO;
aliguori64838172008-08-21 19:31:10 +0000155}
156
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100157static int is_valid(USBHostDevice *s, int ep)
158{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200159 return get_endp(s, ep)->type != INVALID_EP_TYPE;
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100160}
161
aliguori64838172008-08-21 19:31:10 +0000162static int is_halted(USBHostDevice *s, int ep)
163{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200164 return get_endp(s, ep)->halted;
aliguori64838172008-08-21 19:31:10 +0000165}
166
167static void clear_halt(USBHostDevice *s, int ep)
168{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200169 trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200170 get_endp(s, ep)->halted = 0;
aliguori64838172008-08-21 19:31:10 +0000171}
172
173static void set_halt(USBHostDevice *s, int ep)
174{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200175 trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200176 get_endp(s, ep)->halted = 1;
aliguori64838172008-08-21 19:31:10 +0000177}
178
Hans de Goedebb6d5492010-11-26 19:11:03 +0100179static int is_iso_started(USBHostDevice *s, int ep)
180{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200181 return get_endp(s, ep)->iso_started;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100182}
183
184static void clear_iso_started(USBHostDevice *s, int ep)
185{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200186 trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200187 get_endp(s, ep)->iso_started = 0;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100188}
189
190static void set_iso_started(USBHostDevice *s, int ep)
191{
Gerd Hoffmann82887262011-06-10 14:00:24 +0200192 struct endp_data *e = get_endp(s, ep);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200193
194 trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200195 if (!e->iso_started) {
196 e->iso_started = 1;
197 e->inflight = 0;
198 }
199}
200
201static int change_iso_inflight(USBHostDevice *s, int ep, int value)
202{
203 struct endp_data *e = get_endp(s, ep);
204
205 e->inflight += value;
206 return e->inflight;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100207}
208
Hans de Goede060dc842010-11-26 11:41:08 +0100209static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
210{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200211 get_endp(s, ep)->iso_urb = iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100212}
213
214static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
215{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200216 return get_endp(s, ep)->iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100217}
218
219static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
220{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200221 get_endp(s, ep)->iso_urb_idx = i;
Hans de Goede060dc842010-11-26 11:41:08 +0100222}
223
224static int get_iso_urb_idx(USBHostDevice *s, int ep)
225{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200226 return get_endp(s, ep)->iso_urb_idx;
Hans de Goede060dc842010-11-26 11:41:08 +0100227}
228
Hans de Goedebb6d5492010-11-26 19:11:03 +0100229static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
230{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200231 get_endp(s, ep)->iso_buffer_used = i;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100232}
233
234static int get_iso_buffer_used(USBHostDevice *s, int ep)
235{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200236 return get_endp(s, ep)->iso_buffer_used;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100237}
238
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200239static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
240{
241 int raw = descriptor[4] + (descriptor[5] << 8);
242 int size, microframes;
243
244 size = raw & 0x7ff;
245 switch ((raw >> 11) & 3) {
246 case 1: microframes = 2; break;
247 case 2: microframes = 3; break;
248 default: microframes = 1; break;
249 }
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200250 get_endp(s, ep)->max_packet_size = size * microframes;
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200251}
252
Hans de Goede060dc842010-11-26 11:41:08 +0100253static int get_max_packet_size(USBHostDevice *s, int ep)
254{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200255 return get_endp(s, ep)->max_packet_size;
Hans de Goede060dc842010-11-26 11:41:08 +0100256}
257
David Ahern27911042010-04-24 10:26:22 -0600258/*
aliguori64838172008-08-21 19:31:10 +0000259 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100260 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600261 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000262 */
Hans de Goede060dc842010-11-26 11:41:08 +0100263struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000264{
aliguori64838172008-08-21 19:31:10 +0000265 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100266 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200267 USBHostDevice *hdev;
268 QLIST_ENTRY(AsyncURB) next;
aliguori64838172008-08-21 19:31:10 +0000269
Hans de Goede060dc842010-11-26 11:41:08 +0100270 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000271 USBPacket *packet;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200272 int more; /* large transfer, more urbs follow */
Hans de Goede060dc842010-11-26 11:41:08 +0100273
274 /* For buffered iso handling */
275 int iso_frame_idx; /* -1 means in flight */
276};
aliguori64838172008-08-21 19:31:10 +0000277
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200278static AsyncURB *async_alloc(USBHostDevice *s)
aliguori64838172008-08-21 19:31:10 +0000279{
Anthony Liguori7267c092011-08-20 22:09:37 -0500280 AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200281 aurb->hdev = s;
282 QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
283 return aurb;
balrogb9dc0332007-10-04 22:47:34 +0000284}
285
aliguori64838172008-08-21 19:31:10 +0000286static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000287{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200288 QLIST_REMOVE(aurb, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500289 g_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000290}
balrogb9dc0332007-10-04 22:47:34 +0000291
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200292static void do_disconnect(USBHostDevice *s)
293{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200294 usb_host_close(s);
295 usb_host_auto_check(NULL);
296}
297
aliguori64838172008-08-21 19:31:10 +0000298static void async_complete(void *opaque)
299{
300 USBHostDevice *s = opaque;
301 AsyncURB *aurb;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200302 int urbs = 0;
balrogb9dc0332007-10-04 22:47:34 +0000303
aliguori64838172008-08-21 19:31:10 +0000304 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600305 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000306
David Ahern27911042010-04-24 10:26:22 -0600307 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000308 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600309 if (errno == EAGAIN) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200310 if (urbs > 2) {
311 fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);
312 }
aliguori64838172008-08-21 19:31:10 +0000313 return;
David Ahern27911042010-04-24 10:26:22 -0600314 }
Gerd Hoffmann40197c32011-08-22 14:18:21 +0200315 if (errno == ENODEV) {
316 if (!s->closing) {
317 trace_usb_host_disconnect(s->bus_num, s->addr);
318 do_disconnect(s);
319 }
aliguori64838172008-08-21 19:31:10 +0000320 return;
321 }
322
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200323 perror("USBDEVFS_REAPURBNDELAY");
aliguori64838172008-08-21 19:31:10 +0000324 return;
balrogb9dc0332007-10-04 22:47:34 +0000325 }
aliguori64838172008-08-21 19:31:10 +0000326
David Ahern27911042010-04-24 10:26:22 -0600327 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000328 aurb, aurb->urb.status, aurb->urb.actual_length);
329
Hans de Goede060dc842010-11-26 11:41:08 +0100330 /* If this is a buffered iso urb mark it as complete and don't do
331 anything else (it is handled further in usb_host_handle_iso_data) */
332 if (aurb->iso_frame_idx == -1) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200333 int inflight;
Hans de Goede060dc842010-11-26 11:41:08 +0100334 if (aurb->urb.status == -EPIPE) {
335 set_halt(s, aurb->urb.endpoint & 0xf);
336 }
337 aurb->iso_frame_idx = 0;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200338 urbs++;
339 inflight = change_iso_inflight(s, aurb->urb.endpoint & 0xf, -1);
340 if (inflight == 0 && is_iso_started(s, aurb->urb.endpoint & 0xf)) {
341 fprintf(stderr, "husb: out of buffers for iso stream\n");
342 }
Hans de Goede060dc842010-11-26 11:41:08 +0100343 continue;
344 }
345
346 p = aurb->packet;
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200347 trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
348 aurb->urb.actual_length, aurb->more);
Hans de Goede060dc842010-11-26 11:41:08 +0100349
David Ahern27911042010-04-24 10:26:22 -0600350 if (p) {
aliguori64838172008-08-21 19:31:10 +0000351 switch (aurb->urb.status) {
352 case 0:
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200353 p->result += aurb->urb.actual_length;
aliguori64838172008-08-21 19:31:10 +0000354 break;
355
356 case -EPIPE:
357 set_halt(s, p->devep);
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200358 p->result = USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600359 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200360
aliguori64838172008-08-21 19:31:10 +0000361 default:
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200362 p->result = USB_RET_NAK;
aliguori64838172008-08-21 19:31:10 +0000363 break;
364 }
365
Hans de Goede50b79632011-02-02 17:36:29 +0100366 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200367 trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
Hans de Goede50b79632011-02-02 17:36:29 +0100368 usb_generic_async_ctrl_complete(&s->dev, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200369 } else if (!aurb->more) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200370 trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
Hans de Goede50b79632011-02-02 17:36:29 +0100371 usb_packet_complete(&s->dev, p);
372 }
David Ahern27911042010-04-24 10:26:22 -0600373 }
aliguori64838172008-08-21 19:31:10 +0000374
375 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000376 }
balrogb9dc0332007-10-04 22:47:34 +0000377}
378
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200379static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
balrogb9dc0332007-10-04 22:47:34 +0000380{
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200381 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200382 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000383
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200384 QLIST_FOREACH(aurb, &s->aurbs, next) {
385 if (p != aurb->packet) {
386 continue;
387 }
balrogb9dc0332007-10-04 22:47:34 +0000388
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200389 DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
aliguori64838172008-08-21 19:31:10 +0000390
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200391 /* Mark it as dead (see async_complete above) */
392 aurb->packet = NULL;
393
394 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
395 if (r < 0) {
396 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
397 }
balrogb9dc0332007-10-04 22:47:34 +0000398 }
balrogb9dc0332007-10-04 22:47:34 +0000399}
400
aliguori446ab122008-09-14 01:06:09 +0000401static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000402{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200403 const char *op = NULL;
balrogb9dc0332007-10-04 22:47:34 +0000404 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000405 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000406 int ret, i;
407
408 if (configuration == 0) /* address state - ignore */
409 return 1;
410
malcd0f2c4c2010-02-07 02:03:50 +0300411 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000412
balrogb9dc0332007-10-04 22:47:34 +0000413 i = 0;
414 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600415 if (dev_descr_len > dev->descr_len) {
Hans de Goede61c11172011-05-31 11:35:20 +0200416 fprintf(stderr, "husb: update iface failed. descr too short\n");
417 return 0;
David Ahern27911042010-04-24 10:26:22 -0600418 }
balrogb9dc0332007-10-04 22:47:34 +0000419
420 i += dev_descr_len;
421 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600422 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
423 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000424 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000425
balrogb9dc0332007-10-04 22:47:34 +0000426 if (dev->descr[i+1] != USB_DT_CONFIG) {
427 i += dev->descr[i];
428 continue;
429 }
430 config_descr_len = dev->descr[i];
431
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200432 DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000433
aliguori446ab122008-09-14 01:06:09 +0000434 if (configuration < 0 || configuration == dev->descr[i + 5]) {
435 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000436 break;
aliguori446ab122008-09-14 01:06:09 +0000437 }
balrogb9dc0332007-10-04 22:47:34 +0000438
439 i += config_descr_len;
440 }
441
442 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600443 fprintf(stderr,
444 "husb: update iface failed. no matching configuration\n");
Hans de Goede61c11172011-05-31 11:35:20 +0200445 return 0;
balrogb9dc0332007-10-04 22:47:34 +0000446 }
447 nb_interfaces = dev->descr[i + 4];
448
449#ifdef USBDEVFS_DISCONNECT
450 /* earlier Linux 2.4 do not support that */
451 {
452 struct usbdevfs_ioctl ctrl;
453 for (interface = 0; interface < nb_interfaces; interface++) {
454 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
455 ctrl.ifno = interface;
Brad Hards021730f2011-04-13 19:45:32 +1000456 ctrl.data = 0;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200457 op = "USBDEVFS_DISCONNECT";
balrogb9dc0332007-10-04 22:47:34 +0000458 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
459 if (ret < 0 && errno != ENODATA) {
balrogb9dc0332007-10-04 22:47:34 +0000460 goto fail;
461 }
462 }
463 }
464#endif
465
466 /* XXX: only grab if all interfaces are free */
467 for (interface = 0; interface < nb_interfaces; interface++) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200468 op = "USBDEVFS_CLAIMINTERFACE";
balrogb9dc0332007-10-04 22:47:34 +0000469 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
470 if (ret < 0) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200471 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000472 }
473 }
474
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200475 trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
476 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000477
aliguori446ab122008-09-14 01:06:09 +0000478 dev->ninterfaces = nb_interfaces;
479 dev->configuration = configuration;
480 return 1;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200481
482fail:
483 if (errno == ENODEV) {
484 do_disconnect(dev);
485 }
486 perror(op);
487 return 0;
aliguori446ab122008-09-14 01:06:09 +0000488}
489
490static int usb_host_release_interfaces(USBHostDevice *s)
491{
492 int ret, i;
493
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200494 trace_usb_host_release_interfaces(s->bus_num, s->addr);
aliguori446ab122008-09-14 01:06:09 +0000495
496 for (i = 0; i < s->ninterfaces; i++) {
497 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
498 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200499 perror("USBDEVFS_RELEASEINTERFACE");
aliguori446ab122008-09-14 01:06:09 +0000500 return 0;
501 }
502 }
balrogb9dc0332007-10-04 22:47:34 +0000503 return 1;
504}
505
bellard059809e2006-07-19 18:06:15 +0000506static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000507{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100508 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000509
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200510 trace_usb_host_reset(s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000511
bellardbb36d472005-11-05 14:22:28 +0000512 ioctl(s->fd, USBDEVFS_RESET);
aliguori446ab122008-09-14 01:06:09 +0000513
514 usb_host_claim_interfaces(s, s->configuration);
ths5fafdf22007-09-16 21:08:06 +0000515}
bellardbb36d472005-11-05 14:22:28 +0000516
bellard059809e2006-07-19 18:06:15 +0000517static void usb_host_handle_destroy(USBDevice *dev)
518{
519 USBHostDevice *s = (USBHostDevice *)dev;
520
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100521 usb_host_close(s);
522 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300523 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000524}
525
balrogb9dc0332007-10-04 22:47:34 +0000526static int usb_linux_update_endp_table(USBHostDevice *s);
527
Hans de Goede060dc842010-11-26 11:41:08 +0100528/* iso data is special, we need to keep enough urbs in flight to make sure
529 that the controller never runs out of them, otherwise the device will
530 likely suffer a buffer underrun / overrun. */
531static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
532{
533 AsyncURB *aurb;
534 int i, j, len = get_max_packet_size(s, ep);
535
Anthony Liguori7267c092011-08-20 22:09:37 -0500536 aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200537 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100538 aurb[i].urb.endpoint = ep;
539 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
Anthony Liguori7267c092011-08-20 22:09:37 -0500540 aurb[i].urb.buffer = g_malloc(aurb[i].urb.buffer_length);
Hans de Goede060dc842010-11-26 11:41:08 +0100541 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
542 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
543 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
544 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
545 aurb[i].urb.iso_frame_desc[j].length = len;
546 if (in) {
547 aurb[i].urb.endpoint |= 0x80;
548 /* Mark as fully consumed (idle) */
549 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
550 }
551 }
552 set_iso_urb(s, ep, aurb);
553
554 return aurb;
555}
556
557static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
558{
559 AsyncURB *aurb;
560 int i, ret, killed = 0, free = 1;
561
562 aurb = get_iso_urb(s, ep);
563 if (!aurb) {
564 return;
565 }
566
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200567 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100568 /* in flight? */
569 if (aurb[i].iso_frame_idx == -1) {
570 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
571 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200572 perror("USBDEVFS_DISCARDURB");
Hans de Goede060dc842010-11-26 11:41:08 +0100573 free = 0;
574 continue;
575 }
576 killed++;
577 }
578 }
579
580 /* Make sure any urbs we've killed are reaped before we free them */
581 if (killed) {
582 async_complete(s);
583 }
584
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200585 for (i = 0; i < s->iso_urb_count; i++) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500586 g_free(aurb[i].urb.buffer);
Hans de Goede060dc842010-11-26 11:41:08 +0100587 }
588
589 if (free)
Anthony Liguori7267c092011-08-20 22:09:37 -0500590 g_free(aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100591 else
592 printf("husb: leaking iso urbs because of discard failure\n");
593 set_iso_urb(s, ep, NULL);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100594 set_iso_urb_idx(s, ep, 0);
595 clear_iso_started(s, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100596}
597
598static int urb_status_to_usb_ret(int status)
599{
600 switch (status) {
601 case -EPIPE:
602 return USB_RET_STALL;
603 default:
604 return USB_RET_NAK;
605 }
606}
607
Hans de Goedebb6d5492010-11-26 19:11:03 +0100608static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100609{
610 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100611 int i, j, ret, max_packet_size, offset, len = 0;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200612 uint8_t *buf;
Hans de Goede975f2992010-11-26 14:59:35 +0100613
614 max_packet_size = get_max_packet_size(s, p->devep);
615 if (max_packet_size == 0)
616 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100617
618 aurb = get_iso_urb(s, p->devep);
619 if (!aurb) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100620 aurb = usb_host_alloc_iso(s, p->devep, in);
Hans de Goede060dc842010-11-26 11:41:08 +0100621 }
622
623 i = get_iso_urb_idx(s, p->devep);
624 j = aurb[i].iso_frame_idx;
625 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100626 if (in) {
627 /* Check urb status */
628 if (aurb[i].urb.status) {
629 len = urb_status_to_usb_ret(aurb[i].urb.status);
630 /* Move to the next urb */
631 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
632 /* Check frame status */
633 } else if (aurb[i].urb.iso_frame_desc[j].status) {
634 len = urb_status_to_usb_ret(
635 aurb[i].urb.iso_frame_desc[j].status);
636 /* Check the frame fits */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200637 } else if (aurb[i].urb.iso_frame_desc[j].actual_length
638 > p->iov.size) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100639 printf("husb: received iso data is larger then packet\n");
640 len = USB_RET_NAK;
641 /* All good copy data over */
642 } else {
643 len = aurb[i].urb.iso_frame_desc[j].actual_length;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200644 buf = aurb[i].urb.buffer +
645 j * aurb[i].urb.iso_frame_desc[0].length;
646 usb_packet_copy(p, buf, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100647 }
Hans de Goede060dc842010-11-26 11:41:08 +0100648 } else {
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200649 len = p->iov.size;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100650 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
651
652 /* Check the frame fits */
653 if (len > max_packet_size) {
654 printf("husb: send iso data is larger then max packet size\n");
655 return USB_RET_NAK;
656 }
657
658 /* All good copy data over */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200659 usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100660 aurb[i].urb.iso_frame_desc[j].length = len;
661 offset += len;
662 set_iso_buffer_used(s, p->devep, offset);
663
664 /* Start the stream once we have buffered enough data */
665 if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
666 set_iso_started(s, p->devep);
667 }
Hans de Goede060dc842010-11-26 11:41:08 +0100668 }
669 aurb[i].iso_frame_idx++;
670 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200671 i = (i + 1) % s->iso_urb_count;
Hans de Goede060dc842010-11-26 11:41:08 +0100672 set_iso_urb_idx(s, p->devep, i);
673 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100674 } else {
675 if (in) {
676 set_iso_started(s, p->devep);
677 } else {
678 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
679 }
Hans de Goede060dc842010-11-26 11:41:08 +0100680 }
681
Hans de Goedebb6d5492010-11-26 19:11:03 +0100682 if (is_iso_started(s, p->devep)) {
683 /* (Re)-submit all fully consumed / filled urbs */
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200684 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100685 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
686 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
687 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200688 perror("USBDEVFS_SUBMITURB");
Hans de Goedebb6d5492010-11-26 19:11:03 +0100689 if (!in || len == 0) {
690 switch(errno) {
691 case ETIMEDOUT:
692 len = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200693 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100694 case EPIPE:
695 default:
696 len = USB_RET_STALL;
697 }
Hans de Goede060dc842010-11-26 11:41:08 +0100698 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100699 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100700 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100701 aurb[i].iso_frame_idx = -1;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200702 change_iso_inflight(s, p->devep, +1);
Hans de Goede060dc842010-11-26 11:41:08 +0100703 }
Hans de Goede060dc842010-11-26 11:41:08 +0100704 }
705 }
706
707 return len;
708}
709
Hans de Goede50b79632011-02-02 17:36:29 +0100710static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000711{
Hans de Goede50b79632011-02-02 17:36:29 +0100712 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000713 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000714 AsyncURB *aurb;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200715 int ret, rem, prem, v;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200716 uint8_t *pbuf;
Hans de Goede060dc842010-11-26 11:41:08 +0100717 uint8_t ep;
718
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200719 trace_usb_host_req_data(s->bus_num, s->addr,
720 p->pid == USB_TOKEN_IN,
721 p->devep, p->iov.size);
722
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100723 if (!is_valid(s, p->devep)) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200724 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100725 return USB_RET_NAK;
726 }
727
Hans de Goede060dc842010-11-26 11:41:08 +0100728 if (p->pid == USB_TOKEN_IN) {
729 ep = p->devep | 0x80;
730 } else {
731 ep = p->devep;
732 }
733
734 if (is_halted(s, p->devep)) {
735 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
736 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200737 perror("USBDEVFS_CLEAR_HALT");
738 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Hans de Goede060dc842010-11-26 11:41:08 +0100739 return USB_RET_NAK;
740 }
741 clear_halt(s, p->devep);
742 }
743
Hans de Goedebb6d5492010-11-26 19:11:03 +0100744 if (is_isoc(s, p->devep)) {
745 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
746 }
bellardbb36d472005-11-05 14:22:28 +0000747
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200748 v = 0;
749 prem = p->iov.iov[v].iov_len;
750 pbuf = p->iov.iov[v].iov_base;
751 rem = p->iov.size;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200752 while (rem) {
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200753 if (prem == 0) {
754 v++;
755 assert(v < p->iov.niov);
756 prem = p->iov.iov[v].iov_len;
757 pbuf = p->iov.iov[v].iov_base;
758 assert(prem <= rem);
759 }
Gerd Hoffmann71138532011-05-16 10:21:51 +0200760 aurb = async_alloc(s);
761 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000762
Gerd Hoffmann71138532011-05-16 10:21:51 +0200763 urb = &aurb->urb;
764 urb->endpoint = ep;
765 urb->type = USBDEVFS_URB_TYPE_BULK;
766 urb->usercontext = s;
767 urb->buffer = pbuf;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200768 urb->buffer_length = prem;
aliguori64838172008-08-21 19:31:10 +0000769
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200770 if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
Gerd Hoffmann71138532011-05-16 10:21:51 +0200771 urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200772 }
773 pbuf += urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200774 prem -= urb->buffer_length;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200775 rem -= urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200776 if (rem) {
777 aurb->more = 1;
778 }
aliguori64838172008-08-21 19:31:10 +0000779
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200780 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
781 urb->buffer_length, aurb->more);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200782 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
aliguori64838172008-08-21 19:31:10 +0000783
Gerd Hoffmann71138532011-05-16 10:21:51 +0200784 DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
785 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
aliguori64838172008-08-21 19:31:10 +0000786
Gerd Hoffmann71138532011-05-16 10:21:51 +0200787 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200788 perror("USBDEVFS_SUBMITURB");
Gerd Hoffmann71138532011-05-16 10:21:51 +0200789 async_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000790
Gerd Hoffmann71138532011-05-16 10:21:51 +0200791 switch(errno) {
792 case ETIMEDOUT:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200793 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200794 return USB_RET_NAK;
795 case EPIPE:
796 default:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200797 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200798 return USB_RET_STALL;
799 }
balrogb9dc0332007-10-04 22:47:34 +0000800 }
801 }
aliguori64838172008-08-21 19:31:10 +0000802
balrogb9dc0332007-10-04 22:47:34 +0000803 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000804}
805
aliguori446ab122008-09-14 01:06:09 +0000806static int ctrl_error(void)
807{
David Ahern27911042010-04-24 10:26:22 -0600808 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000809 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600810 } else {
aliguori446ab122008-09-14 01:06:09 +0000811 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600812 }
aliguori446ab122008-09-14 01:06:09 +0000813}
814
815static int usb_host_set_address(USBHostDevice *s, int addr)
816{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200817 trace_usb_host_set_address(s->bus_num, s->addr, addr);
aliguori446ab122008-09-14 01:06:09 +0000818 s->dev.addr = addr;
819 return 0;
820}
821
822static int usb_host_set_config(USBHostDevice *s, int config)
823{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200824 trace_usb_host_set_config(s->bus_num, s->addr, config);
825
aliguori446ab122008-09-14 01:06:09 +0000826 usb_host_release_interfaces(s);
827
828 int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600829
malcd0f2c4c2010-02-07 02:03:50 +0300830 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600831
832 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000833 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600834 }
aliguori446ab122008-09-14 01:06:09 +0000835 usb_host_claim_interfaces(s, config);
836 return 0;
837}
838
839static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
840{
841 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100842 int i, ret;
843
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200844 trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
845
Hans de Goede3a4854b2010-11-26 15:02:16 +0100846 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100847 if (is_isoc(s, i)) {
848 usb_host_stop_n_free_iso(s, i);
849 }
850 }
aliguori446ab122008-09-14 01:06:09 +0000851
852 si.interface = iface;
853 si.altsetting = alt;
854 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000855
David Ahern27911042010-04-24 10:26:22 -0600856 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
857 iface, alt, ret, errno);
858
859 if (ret < 0) {
860 return ctrl_error();
861 }
aliguori446ab122008-09-14 01:06:09 +0000862 usb_linux_update_endp_table(s);
863 return 0;
864}
865
Hans de Goede50b79632011-02-02 17:36:29 +0100866static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
867 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +0000868{
Hans de Goede50b79632011-02-02 17:36:29 +0100869 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +0000870 struct usbdevfs_urb *urb;
871 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +0100872 int ret;
aliguori446ab122008-09-14 01:06:09 +0000873
David Ahern27911042010-04-24 10:26:22 -0600874 /*
aliguori446ab122008-09-14 01:06:09 +0000875 * Process certain standard device requests.
876 * These are infrequent and are processed synchronously.
877 */
aliguori446ab122008-09-14 01:06:09 +0000878
Hans de Goede50b79632011-02-02 17:36:29 +0100879 /* Note request is (bRequestType << 8) | bRequest */
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200880 trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
aliguori446ab122008-09-14 01:06:09 +0000881
Hans de Goede50b79632011-02-02 17:36:29 +0100882 switch (request) {
883 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
884 return usb_host_set_address(s, value);
aliguori446ab122008-09-14 01:06:09 +0000885
Hans de Goede50b79632011-02-02 17:36:29 +0100886 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
887 return usb_host_set_config(s, value & 0xff);
aliguori446ab122008-09-14 01:06:09 +0000888
Hans de Goede50b79632011-02-02 17:36:29 +0100889 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
aliguori446ab122008-09-14 01:06:09 +0000890 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -0600891 }
aliguori446ab122008-09-14 01:06:09 +0000892
893 /* The rest are asynchronous */
894
Hans de Goede50b79632011-02-02 17:36:29 +0100895 if (length > sizeof(dev->data_buf)) {
896 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
897 length, sizeof(dev->data_buf));
malcb2e3b6e2009-09-12 03:18:18 +0400898 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -0400899 }
900
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200901 aurb = async_alloc(s);
aliguori446ab122008-09-14 01:06:09 +0000902 aurb->packet = p;
903
David Ahern27911042010-04-24 10:26:22 -0600904 /*
aliguori446ab122008-09-14 01:06:09 +0000905 * Setup ctrl transfer.
906 *
Brad Hardsa0102082011-04-13 19:45:33 +1000907 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +0000908 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -0600909 */
aliguori446ab122008-09-14 01:06:09 +0000910 urb = &aurb->urb;
911
912 urb->type = USBDEVFS_URB_TYPE_CONTROL;
913 urb->endpoint = p->devep;
914
Hans de Goede50b79632011-02-02 17:36:29 +0100915 urb->buffer = &dev->setup_buf;
916 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +0000917
918 urb->usercontext = s;
919
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200920 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
921 urb->buffer_length, aurb->more);
aliguori446ab122008-09-14 01:06:09 +0000922 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
923
malcd0f2c4c2010-02-07 02:03:50 +0300924 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +0000925
926 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300927 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +0000928 async_free(aurb);
929
930 switch(errno) {
931 case ETIMEDOUT:
932 return USB_RET_NAK;
933 case EPIPE:
934 default:
935 return USB_RET_STALL;
936 }
937 }
938
aliguori446ab122008-09-14 01:06:09 +0000939 return USB_RET_ASYNC;
940}
941
Hans de Goede71d71bb2010-11-10 10:06:24 +0100942static int usb_linux_get_configuration(USBHostDevice *s)
balrogb9dc0332007-10-04 22:47:34 +0000943{
Hans de Goede71d71bb2010-11-10 10:06:24 +0100944 uint8_t configuration;
pbrooke41b3912008-10-28 18:22:59 +0000945 struct usb_ctrltransfer ct;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100946 int ret;
balrogb9dc0332007-10-04 22:47:34 +0000947
Hans de Goede2cc59d82010-11-10 10:06:25 +0100948 if (usb_fs_type == USB_FS_SYS) {
949 char device_name[32], line[1024];
950 int configuration;
951
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200952 sprintf(device_name, "%d-%s", s->bus_num, s->port);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100953
954 if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
955 device_name)) {
956 goto usbdevfs;
957 }
958 if (sscanf(line, "%d", &configuration) != 1) {
959 goto usbdevfs;
960 }
961 return configuration;
962 }
963
964usbdevfs:
balrogb9dc0332007-10-04 22:47:34 +0000965 ct.bRequestType = USB_DIR_IN;
966 ct.bRequest = USB_REQ_GET_CONFIGURATION;
967 ct.wValue = 0;
968 ct.wIndex = 0;
969 ct.wLength = 1;
970 ct.data = &configuration;
971 ct.timeout = 50;
972
973 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
974 if (ret < 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100975 perror("usb_linux_get_configuration");
976 return -1;
balrogb9dc0332007-10-04 22:47:34 +0000977 }
978
979 /* in address state */
David Ahern27911042010-04-24 10:26:22 -0600980 if (configuration == 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100981 return -1;
David Ahern27911042010-04-24 10:26:22 -0600982 }
balrogb9dc0332007-10-04 22:47:34 +0000983
Hans de Goede71d71bb2010-11-10 10:06:24 +0100984 return configuration;
985}
986
Hans de Goedeed3a3282010-11-24 12:50:00 +0100987static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
988 uint8_t configuration, uint8_t interface)
989{
990 uint8_t alt_setting;
991 struct usb_ctrltransfer ct;
992 int ret;
993
Hans de Goedec43831f2010-11-24 12:57:59 +0100994 if (usb_fs_type == USB_FS_SYS) {
995 char device_name[64], line[1024];
996 int alt_setting;
997
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200998 sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
Hans de Goedec43831f2010-11-24 12:57:59 +0100999 (int)configuration, (int)interface);
1000
1001 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
1002 device_name)) {
1003 goto usbdevfs;
1004 }
1005 if (sscanf(line, "%d", &alt_setting) != 1) {
1006 goto usbdevfs;
1007 }
1008 return alt_setting;
1009 }
1010
1011usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +01001012 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
1013 ct.bRequest = USB_REQ_GET_INTERFACE;
1014 ct.wValue = 0;
1015 ct.wIndex = interface;
1016 ct.wLength = 1;
1017 ct.data = &alt_setting;
1018 ct.timeout = 50;
1019 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
1020 if (ret < 0) {
1021 /* Assume alt 0 on error */
1022 return 0;
1023 }
1024
1025 return alt_setting;
1026}
1027
Hans de Goede71d71bb2010-11-10 10:06:24 +01001028/* returns 1 on problem encountered or 0 for success */
1029static int usb_linux_update_endp_table(USBHostDevice *s)
1030{
1031 uint8_t *descriptors;
1032 uint8_t devep, type, configuration, alt_interface;
Hans de Goedeed3a3282010-11-24 12:50:00 +01001033 int interface, length, i;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001034
Hans de Goedea0b5fec2010-11-26 14:56:17 +01001035 for (i = 0; i < MAX_ENDPOINTS; i++)
1036 s->endp_table[i].type = INVALID_EP_TYPE;
1037
Hans de Goede71d71bb2010-11-10 10:06:24 +01001038 i = usb_linux_get_configuration(s);
1039 if (i < 0)
1040 return 1;
1041 configuration = i;
1042
balrogb9dc0332007-10-04 22:47:34 +00001043 /* get the desired configuration, interface, and endpoint descriptors
1044 * from device description */
1045 descriptors = &s->descr[18];
1046 length = s->descr_len - 18;
1047 i = 0;
1048
1049 if (descriptors[i + 1] != USB_DT_CONFIG ||
1050 descriptors[i + 5] != configuration) {
malcd0f2c4c2010-02-07 02:03:50 +03001051 DPRINTF("invalid descriptor data - configuration\n");
balrogb9dc0332007-10-04 22:47:34 +00001052 return 1;
1053 }
1054 i += descriptors[i];
1055
1056 while (i < length) {
1057 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1058 (descriptors[i + 1] == USB_DT_INTERFACE &&
1059 descriptors[i + 4] == 0)) {
1060 i += descriptors[i];
1061 continue;
1062 }
1063
1064 interface = descriptors[i + 2];
Hans de Goedeed3a3282010-11-24 12:50:00 +01001065 alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
balrogb9dc0332007-10-04 22:47:34 +00001066
1067 /* the current interface descriptor is the active interface
1068 * and has endpoints */
1069 if (descriptors[i + 3] != alt_interface) {
1070 i += descriptors[i];
1071 continue;
1072 }
1073
1074 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001075 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001076 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001077 }
balrogb9dc0332007-10-04 22:47:34 +00001078
1079 if (i >= length)
1080 break;
1081
1082 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001083 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001084 break;
David Ahern27911042010-04-24 10:26:22 -06001085 }
balrogb9dc0332007-10-04 22:47:34 +00001086
1087 devep = descriptors[i + 2];
Hans de Goede130314f2011-05-31 11:35:22 +02001088 if ((devep & 0x0f) == 0) {
1089 fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
1090 return 1;
1091 }
1092
balrogb9dc0332007-10-04 22:47:34 +00001093 switch (descriptors[i + 3] & 0x3) {
1094 case 0x00:
1095 type = USBDEVFS_URB_TYPE_CONTROL;
1096 break;
1097 case 0x01:
1098 type = USBDEVFS_URB_TYPE_ISO;
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +02001099 set_max_packet_size(s, (devep & 0xf), descriptors + i);
balrogb9dc0332007-10-04 22:47:34 +00001100 break;
1101 case 0x02:
1102 type = USBDEVFS_URB_TYPE_BULK;
1103 break;
1104 case 0x03:
1105 type = USBDEVFS_URB_TYPE_INTERRUPT;
1106 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -05001107 default:
1108 DPRINTF("usb_host: malformed endpoint type\n");
1109 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +00001110 }
1111 s->endp_table[(devep & 0xf) - 1].type = type;
aliguori64838172008-08-21 19:31:10 +00001112 s->endp_table[(devep & 0xf) - 1].halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001113
1114 i += descriptors[i];
1115 }
1116 }
1117 return 0;
1118}
1119
Hans de Goedee4b17762011-05-30 11:40:45 +02001120/*
1121 * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
1122 * this function assumes this is safe, if:
1123 * 1) There are no isoc endpoints
1124 * 2) There are no interrupt endpoints with a max_packet_size > 64
1125 * Note bulk endpoints with a max_packet_size > 64 in theory also are not
1126 * usb1 compatible, but in practice this seems to work fine.
1127 */
1128static int usb_linux_full_speed_compat(USBHostDevice *dev)
1129{
1130 int i, packet_size;
1131
1132 /*
1133 * usb_linux_update_endp_table only registers info about ep in the current
1134 * interface altsettings, so we need to parse the descriptors again.
1135 */
1136 for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
1137 if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
1138 switch (dev->descr[i + 3] & 0x3) {
1139 case 0x00: /* CONTROL */
1140 break;
1141 case 0x01: /* ISO */
1142 return 0;
1143 case 0x02: /* BULK */
1144 break;
1145 case 0x03: /* INTERRUPT */
1146 packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
1147 if (packet_size > 64)
1148 return 0;
1149 break;
1150 }
1151 }
1152 }
1153 return 1;
1154}
1155
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001156static int usb_host_open(USBHostDevice *dev, int bus_num,
Hans de Goede3991c352011-05-31 11:35:18 +02001157 int addr, char *port, const char *prod_name, int speed)
bellardbb36d472005-11-05 14:22:28 +00001158{
balrogb9dc0332007-10-04 22:47:34 +00001159 int fd = -1, ret;
bellarda594cfb2005-11-06 16:13:29 +00001160 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001161
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001162 trace_usb_host_open_started(bus_num, addr);
1163
David Ahern27911042010-04-24 10:26:22 -06001164 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001165 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001166 }
aliguori1f3870a2008-08-21 19:27:48 +00001167
aliguori0f431522008-10-07 20:06:37 +00001168 if (!usb_host_device_path) {
1169 perror("husb: USB Host Device Path not set");
1170 goto fail;
1171 }
1172 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001173 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001174 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001175 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001176 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001177 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001178 }
malcd0f2c4c2010-02-07 02:03:50 +03001179 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001180
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001181 dev->bus_num = bus_num;
1182 dev->addr = addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001183 strcpy(dev->port, port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001184 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001185
balrogb9dc0332007-10-04 22:47:34 +00001186 /* read the device description */
1187 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1188 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001189 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001190 goto fail;
1191 }
ths3b46e622007-09-17 08:09:54 +00001192
balrogb9dc0332007-10-04 22:47:34 +00001193#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001194 {
balrogb9dc0332007-10-04 22:47:34 +00001195 int x;
1196 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001197 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001198 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001199 }
balrogb9dc0332007-10-04 22:47:34 +00001200 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001201 }
1202#endif
1203
balrogb9dc0332007-10-04 22:47:34 +00001204
David Ahern27911042010-04-24 10:26:22 -06001205 /*
1206 * Initial configuration is -1 which makes us claim first
aliguori446ab122008-09-14 01:06:09 +00001207 * available config. We used to start with 1, which does not
David Ahern27911042010-04-24 10:26:22 -06001208 * always work. I've seen devices where first config starts
aliguori446ab122008-09-14 01:06:09 +00001209 * with 2.
1210 */
David Ahern27911042010-04-24 10:26:22 -06001211 if (!usb_host_claim_interfaces(dev, -1)) {
balrogb9dc0332007-10-04 22:47:34 +00001212 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001213 }
bellardbb36d472005-11-05 14:22:28 +00001214
balrogb9dc0332007-10-04 22:47:34 +00001215 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001216 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001217 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001218 }
balrogb9dc0332007-10-04 22:47:34 +00001219
Hans de Goede3991c352011-05-31 11:35:18 +02001220 if (speed == -1) {
1221 struct usbdevfs_connectinfo ci;
1222
1223 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1224 if (ret < 0) {
1225 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
1226 goto fail;
1227 }
1228
1229 if (ci.slow) {
1230 speed = USB_SPEED_LOW;
1231 } else {
1232 speed = USB_SPEED_HIGH;
1233 }
David Ahern27911042010-04-24 10:26:22 -06001234 }
Hans de Goede3991c352011-05-31 11:35:18 +02001235 dev->dev.speed = speed;
Hans de Goedeba3f9bf2011-05-27 14:27:18 +02001236 dev->dev.speedmask = (1 << speed);
Hans de Goedee4b17762011-05-30 11:40:45 +02001237 if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
1238 dev->dev.speedmask |= USB_SPEED_MASK_FULL;
1239 }
Hans de Goede3991c352011-05-31 11:35:18 +02001240
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001241 trace_usb_host_open_success(bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001242
David Ahern27911042010-04-24 10:26:22 -06001243 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001244 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001245 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001246 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001247 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001248 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001249 }
bellard1f6e24e2006-06-26 21:00:51 +00001250
Hans de Goedefa19bf82011-05-27 19:05:15 +02001251 ret = usb_device_attach(&dev->dev);
1252 if (ret) {
1253 goto fail;
1254 }
1255
aliguori64838172008-08-21 19:31:10 +00001256 /* USB devio uses 'write' flag to check for async completions */
1257 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001258
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001259 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001260
balrogb9dc0332007-10-04 22:47:34 +00001261fail:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001262 trace_usb_host_open_failure(bus_num, addr);
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001263 if (dev->fd != -1) {
1264 close(dev->fd);
1265 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001266 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001267 return -1;
1268}
1269
1270static int usb_host_close(USBHostDevice *dev)
1271{
Hans de Goede060dc842010-11-26 11:41:08 +01001272 int i;
1273
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001274 if (dev->fd == -1 || !dev->dev.attached) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001275 return -1;
David Ahern27911042010-04-24 10:26:22 -06001276 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001277
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001278 trace_usb_host_close(dev->bus_num, dev->addr);
1279
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001280 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1281 dev->closing = 1;
Hans de Goede3a4854b2010-11-26 15:02:16 +01001282 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +01001283 if (is_isoc(dev, i)) {
1284 usb_host_stop_n_free_iso(dev, i);
1285 }
1286 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001287 async_complete(dev);
1288 dev->closing = 0;
1289 usb_device_detach(&dev->dev);
Shahar Havivi00ff2272010-06-16 15:15:37 +03001290 ioctl(dev->fd, USBDEVFS_RESET);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001291 close(dev->fd);
1292 dev->fd = -1;
1293 return 0;
1294}
1295
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001296static void usb_host_exit_notifier(struct Notifier *n, void *data)
Shahar Havivib373a632010-06-16 15:16:11 +03001297{
1298 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1299
1300 if (s->fd != -1) {
1301 ioctl(s->fd, USBDEVFS_RESET);
1302 }
1303}
1304
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001305static int usb_host_initfn(USBDevice *dev)
1306{
1307 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1308
1309 dev->auto_attach = 0;
1310 s->fd = -1;
1311 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001312 s->exit.notify = usb_host_exit_notifier;
1313 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001314 usb_host_auto_check(NULL);
1315 return 0;
bellardbb36d472005-11-05 14:22:28 +00001316}
1317
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001318static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001319 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001320 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001321 .qdev.size = sizeof(USBHostDevice),
1322 .init = usb_host_initfn,
Hans de Goede50b79632011-02-02 17:36:29 +01001323 .handle_packet = usb_generic_handle_packet,
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +02001324 .cancel_packet = usb_host_async_cancel,
Hans de Goede50b79632011-02-02 17:36:29 +01001325 .handle_data = usb_host_handle_data,
1326 .handle_control = usb_host_handle_control,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001327 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001328 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001329 .usbdevice_name = "host",
1330 .usbdevice_init = usb_host_device_open,
1331 .qdev.props = (Property[]) {
1332 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1333 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001334 DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001335 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1336 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +02001337 DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001338 DEFINE_PROP_END_OF_LIST(),
1339 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001340};
1341
1342static void usb_host_register_devices(void)
1343{
1344 usb_qdev_register(&usb_host_dev_info);
1345}
1346device_init(usb_host_register_devices)
1347
aliguori4b096fc2008-08-21 19:28:55 +00001348USBDevice *usb_host_device_open(const char *devname)
1349{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001350 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001351 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001352 char *p;
1353
Markus Armbruster556cd092009-12-09 17:07:53 +01001354 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001355
aliguori5d0c5752008-09-14 01:07:41 +00001356 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001357 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001358 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001359 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001360 } else {
1361 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001362 filter.bus_num = strtoul(devname, NULL, 0);
1363 filter.addr = strtoul(p + 1, NULL, 0);
1364 filter.vendor_id = 0;
1365 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001366 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001367 filter.bus_num = 0;
1368 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001369 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001370 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001371 } else {
1372 goto fail;
1373 }
aliguori5d0c5752008-09-14 01:07:41 +00001374 }
1375
Markus Armbruster0745eb12009-11-27 13:05:53 +01001376 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1377 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001378 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1379 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001380 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001381 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001382
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001383fail:
1384 qdev_free(&dev->qdev);
1385 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001386}
aliguori5d0c5752008-09-14 01:07:41 +00001387
1388int usb_host_device_close(const char *devname)
1389{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001390#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001391 char product_name[PRODUCT_NAME_SZ];
1392 int bus_num, addr;
1393 USBHostDevice *s;
1394
David Ahern27911042010-04-24 10:26:22 -06001395 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001396 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001397 }
1398 if (usb_host_find_device(&bus_num, &addr, product_name,
1399 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001400 return -1;
David Ahern27911042010-04-24 10:26:22 -06001401 }
aliguori5d0c5752008-09-14 01:07:41 +00001402 s = hostdev_find(bus_num, addr);
1403 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001404 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001405 return 0;
1406 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001407#endif
aliguori5d0c5752008-09-14 01:07:41 +00001408
1409 return -1;
1410}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001411
bellarda594cfb2005-11-06 16:13:29 +00001412static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001413 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001414 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001415{
bellarda594cfb2005-11-06 16:13:29 +00001416 const char *p;
1417 char *q;
1418 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001419 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001420 return -1;
David Ahern27911042010-04-24 10:26:22 -06001421 }
bellarda594cfb2005-11-06 16:13:29 +00001422 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001423 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001424 p++;
David Ahern27911042010-04-24 10:26:22 -06001425 }
bellarda594cfb2005-11-06 16:13:29 +00001426 q = buf;
1427 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001428 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001429 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001430 }
bellarda594cfb2005-11-06 16:13:29 +00001431 p++;
1432 }
1433 *q = '\0';
1434 return q - buf;
1435}
bellardbb36d472005-11-05 14:22:28 +00001436
aliguori0f431522008-10-07 20:06:37 +00001437/*
1438 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1439 * host's USB devices. This is legacy support since many distributions
1440 * are moving to /sys/bus/usb
1441 */
1442static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001443{
Blue Swirl660f11b2009-07-31 21:16:51 +00001444 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001445 char line[1024];
1446 char buf[1024];
1447 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
bellarda594cfb2005-11-06 16:13:29 +00001448 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001449 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001450
aliguori0f431522008-10-07 20:06:37 +00001451 if (!usb_host_device_path) {
1452 perror("husb: USB Host Device Path not set");
1453 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001454 }
aliguori0f431522008-10-07 20:06:37 +00001455 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1456 f = fopen(line, "r");
1457 if (!f) {
1458 perror("husb: cannot open devices file");
1459 goto the_end;
1460 }
1461
bellarda594cfb2005-11-06 16:13:29 +00001462 device_count = 0;
Hans de Goede3991c352011-05-31 11:35:18 +02001463 bus_num = addr = class_id = product_id = vendor_id = 0;
1464 speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
bellardbb36d472005-11-05 14:22:28 +00001465 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001466 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001467 break;
David Ahern27911042010-04-24 10:26:22 -06001468 }
1469 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001470 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001471 }
bellarda594cfb2005-11-06 16:13:29 +00001472 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001473 if (device_count && (vendor_id || product_id)) {
1474 /* New device. Add the previously discovered device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001475 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001476 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001477 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001478 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001479 }
bellarda594cfb2005-11-06 16:13:29 +00001480 }
David Ahern27911042010-04-24 10:26:22 -06001481 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001482 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001483 }
bellarda594cfb2005-11-06 16:13:29 +00001484 bus_num = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001485 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001486 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001487 }
bellarda594cfb2005-11-06 16:13:29 +00001488 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001489 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001490 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001491 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001492 if (!strcmp(buf, "5000")) {
1493 speed = USB_SPEED_SUPER;
1494 } else if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001495 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001496 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001497 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001498 } else {
bellarda594cfb2005-11-06 16:13:29 +00001499 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001500 }
bellarda594cfb2005-11-06 16:13:29 +00001501 product_name[0] = '\0';
1502 class_id = 0xff;
1503 device_count++;
1504 product_id = 0;
1505 vendor_id = 0;
1506 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001507 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001508 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001509 }
bellarda594cfb2005-11-06 16:13:29 +00001510 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001511 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001512 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001513 }
bellarda594cfb2005-11-06 16:13:29 +00001514 product_id = strtoul(buf, NULL, 16);
1515 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001516 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001517 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001518 }
bellarda594cfb2005-11-06 16:13:29 +00001519 pstrcpy(product_name, sizeof(product_name), buf);
1520 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001521 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001522 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001523 }
bellarda594cfb2005-11-06 16:13:29 +00001524 class_id = strtoul(buf, NULL, 16);
1525 }
1526 fail: ;
1527 }
pbrook38ca0f62006-03-11 18:03:38 +00001528 if (device_count && (vendor_id || product_id)) {
1529 /* Add the last device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001530 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001531 product_id, product_name, speed);
1532 }
1533 the_end:
David Ahern27911042010-04-24 10:26:22 -06001534 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001535 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001536 }
aliguori0f431522008-10-07 20:06:37 +00001537 return ret;
1538}
1539
1540/*
1541 * Read sys file-system device file
1542 *
1543 * @line address of buffer to put file contents in
1544 * @line_size size of line
1545 * @device_file path to device file (printf format string)
1546 * @device_name device being opened (inserted into device_file)
1547 *
1548 * @return 0 failed, 1 succeeded ('line' contains data)
1549 */
David Ahern27911042010-04-24 10:26:22 -06001550static int usb_host_read_file(char *line, size_t line_size,
1551 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001552{
1553 FILE *f;
1554 int ret = 0;
1555 char filename[PATH_MAX];
1556
blueswir1b4e237a2008-12-28 15:45:20 +00001557 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1558 device_file);
aliguori0f431522008-10-07 20:06:37 +00001559 f = fopen(filename, "r");
1560 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001561 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001562 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001563 }
1564
1565 return ret;
1566}
1567
1568/*
1569 * Use /sys/bus/usb/devices/ directory to determine host's USB
1570 * devices.
1571 *
1572 * This code is based on Robert Schiele's original patches posted to
1573 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1574 */
1575static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1576{
Blue Swirl660f11b2009-07-31 21:16:51 +00001577 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001578 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001579 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001580 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001581 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001582 char product_name[512];
1583 struct dirent *de;
1584
1585 dir = opendir(USBSYSBUS_PATH "/devices");
1586 if (!dir) {
1587 perror("husb: cannot open devices directory");
1588 goto the_end;
1589 }
1590
1591 while ((de = readdir(dir))) {
1592 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001593 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1594 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001595 }
aliguori0f431522008-10-07 20:06:37 +00001596
David Ahern27911042010-04-24 10:26:22 -06001597 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001598 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001599 }
1600 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001601 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001602 }
blueswir1b4e237a2008-12-28 15:45:20 +00001603 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001604 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001605 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001606 }
1607 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001608 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001609 }
aliguori0f431522008-10-07 20:06:37 +00001610
David Ahern27911042010-04-24 10:26:22 -06001611 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1612 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001613 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001614 }
1615 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001616 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001617 }
blueswir1b4e237a2008-12-28 15:45:20 +00001618 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001619 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001620 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001621 }
1622 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001623 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001624 }
blueswir1b4e237a2008-12-28 15:45:20 +00001625 if (!usb_host_read_file(line, sizeof(line), "product",
1626 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001627 *product_name = 0;
1628 } else {
David Ahern27911042010-04-24 10:26:22 -06001629 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001630 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001631 }
aliguori0f431522008-10-07 20:06:37 +00001632 pstrcpy(product_name, sizeof(product_name), line);
1633 }
1634
David Ahern27911042010-04-24 10:26:22 -06001635 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001636 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001637 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001638 if (!strcmp(line, "5000\n")) {
1639 speed = USB_SPEED_SUPER;
1640 } else if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001641 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001642 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001643 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001644 } else {
aliguori0f431522008-10-07 20:06:37 +00001645 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001646 }
aliguori0f431522008-10-07 20:06:37 +00001647
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001648 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001649 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001650 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001651 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001652 }
aliguori0f431522008-10-07 20:06:37 +00001653 }
1654 }
1655 the_end:
David Ahern27911042010-04-24 10:26:22 -06001656 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001657 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001658 }
aliguori0f431522008-10-07 20:06:37 +00001659 return ret;
1660}
1661
1662/*
1663 * Determine how to access the host's USB devices and call the
1664 * specific support function.
1665 */
1666static int usb_host_scan(void *opaque, USBScanFunc *func)
1667{
aliguori376253e2009-03-05 23:01:23 +00001668 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001669 FILE *f = NULL;
1670 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001671 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001672 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1673 char devpath[PATH_MAX];
1674
1675 /* only check the host once */
1676 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001677 dir = opendir(USBSYSBUS_PATH "/devices");
1678 if (dir) {
1679 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1680 strcpy(devpath, USBDEVBUS_PATH);
1681 usb_fs_type = USB_FS_SYS;
1682 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001683 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001684 goto found_devices;
1685 }
aliguori0f431522008-10-07 20:06:37 +00001686 f = fopen(USBPROCBUS_PATH "/devices", "r");
1687 if (f) {
1688 /* devices found in /proc/bus/usb/ */
1689 strcpy(devpath, USBPROCBUS_PATH);
1690 usb_fs_type = USB_FS_PROC;
1691 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001692 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001693 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001694 }
1695 /* try additional methods if an access method hasn't been found yet */
1696 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001697 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001698 /* devices found in /dev/bus/usb/ */
1699 strcpy(devpath, USBDEVBUS_PATH);
1700 usb_fs_type = USB_FS_DEV;
1701 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001702 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001703 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001704 }
aliguorif16a0db2008-10-21 16:34:20 +00001705 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001706 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001707 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001708 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001709 }
aliguorif16a0db2008-10-21 16:34:20 +00001710 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001711 }
1712
1713 /* the module setting (used later for opening devices) */
Anthony Liguori7267c092011-08-20 22:09:37 -05001714 usb_host_device_path = g_malloc0(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001715 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001716 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001717 monitor_printf(mon, "husb: using %s file-system with %s\n",
1718 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001719 }
aliguori0f431522008-10-07 20:06:37 +00001720 }
1721
1722 switch (usb_fs_type) {
1723 case USB_FS_PROC:
1724 case USB_FS_DEV:
1725 ret = usb_host_scan_dev(opaque, func);
1726 break;
1727 case USB_FS_SYS:
1728 ret = usb_host_scan_sys(opaque, func);
1729 break;
aliguorif16a0db2008-10-21 16:34:20 +00001730 default:
1731 ret = -EINVAL;
1732 break;
aliguori0f431522008-10-07 20:06:37 +00001733 }
bellarda594cfb2005-11-06 16:13:29 +00001734 return ret;
1735}
1736
aliguori4b096fc2008-08-21 19:28:55 +00001737static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001738
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001739static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001740 int class_id, int vendor_id, int product_id,
1741 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001742{
1743 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001744 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001745
1746 /* Ignore hubs */
1747 if (class_id == 9)
1748 return 0;
1749
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001750 QTAILQ_FOREACH(s, &hostdevs, next) {
1751 f = &s->match;
1752
David Ahern27911042010-04-24 10:26:22 -06001753 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001754 continue;
David Ahern27911042010-04-24 10:26:22 -06001755 }
1756 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001757 continue;
David Ahern27911042010-04-24 10:26:22 -06001758 }
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001759 if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
1760 continue;
1761 }
aliguori4b096fc2008-08-21 19:28:55 +00001762
David Ahern27911042010-04-24 10:26:22 -06001763 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001764 continue;
David Ahern27911042010-04-24 10:26:22 -06001765 }
aliguori4b096fc2008-08-21 19:28:55 +00001766
David Ahern27911042010-04-24 10:26:22 -06001767 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001768 continue;
David Ahern27911042010-04-24 10:26:22 -06001769 }
aliguori4b096fc2008-08-21 19:28:55 +00001770 /* We got a match */
1771
Markus Armbruster33e66b82009-10-07 01:15:57 +02001772 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001773 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001774 return 0;
David Ahern27911042010-04-24 10:26:22 -06001775 }
malcd0f2c4c2010-02-07 02:03:50 +03001776 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001777
Hans de Goede3991c352011-05-31 11:35:18 +02001778 usb_host_open(s, bus_num, addr, port, product_name, speed);
Hans de Goede97f86162011-05-31 11:35:24 +02001779 break;
aliguori4b096fc2008-08-21 19:28:55 +00001780 }
1781
1782 return 0;
1783}
1784
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001785static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001786{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001787 struct USBHostDevice *s;
1788 int unconnected = 0;
1789
aliguori4b096fc2008-08-21 19:28:55 +00001790 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001791
1792 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001793 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001794 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001795 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001796 }
1797
1798 if (unconnected == 0) {
1799 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001800 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001801 qemu_del_timer(usb_auto_timer);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001802 trace_usb_host_auto_scan_disabled();
David Ahern27911042010-04-24 10:26:22 -06001803 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001804 return;
1805 }
1806
1807 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001808 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001809 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001810 return;
David Ahern27911042010-04-24 10:26:22 -06001811 }
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001812 trace_usb_host_auto_scan_enabled();
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001813 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001814 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001815}
1816
1817/*
aliguori5d0c5752008-09-14 01:07:41 +00001818 * Autoconnect filter
1819 * Format:
1820 * auto:bus:dev[:vid:pid]
1821 * auto:bus.dev[:vid:pid]
1822 *
1823 * bus - bus number (dec, * means any)
1824 * dev - device number (dec, * means any)
1825 * vid - vendor id (hex, * means any)
1826 * pid - product id (hex, * means any)
1827 *
1828 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001829 */
aliguori5d0c5752008-09-14 01:07:41 +00001830static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001831{
aliguori5d0c5752008-09-14 01:07:41 +00001832 enum { BUS, DEV, VID, PID, DONE };
1833 const char *p = spec;
1834 int i;
1835
Markus Armbruster0745eb12009-11-27 13:05:53 +01001836 f->bus_num = 0;
1837 f->addr = 0;
1838 f->vendor_id = 0;
1839 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001840
1841 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001842 p = strpbrk(p, ":.");
1843 if (!p) {
1844 break;
1845 }
aliguori5d0c5752008-09-14 01:07:41 +00001846 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001847
David Ahern27911042010-04-24 10:26:22 -06001848 if (*p == '*') {
1849 continue;
1850 }
aliguori5d0c5752008-09-14 01:07:41 +00001851 switch(i) {
1852 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1853 case DEV: f->addr = strtol(p, NULL, 10); break;
1854 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1855 case PID: f->product_id = strtol(p, NULL, 16); break;
1856 }
aliguori4b096fc2008-08-21 19:28:55 +00001857 }
1858
aliguori5d0c5752008-09-14 01:07:41 +00001859 if (i < DEV) {
1860 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1861 return -1;
1862 }
1863
1864 return 0;
1865}
1866
bellarda594cfb2005-11-06 16:13:29 +00001867/**********************/
1868/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001869
bellarda594cfb2005-11-06 16:13:29 +00001870struct usb_class_info {
1871 int class;
1872 const char *class_name;
1873};
1874
1875static const struct usb_class_info usb_class_info[] = {
1876 { USB_CLASS_AUDIO, "Audio"},
1877 { USB_CLASS_COMM, "Communication"},
1878 { USB_CLASS_HID, "HID"},
1879 { USB_CLASS_HUB, "Hub" },
1880 { USB_CLASS_PHYSICAL, "Physical" },
1881 { USB_CLASS_PRINTER, "Printer" },
1882 { USB_CLASS_MASS_STORAGE, "Storage" },
1883 { USB_CLASS_CDC_DATA, "Data" },
1884 { USB_CLASS_APP_SPEC, "Application Specific" },
1885 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1886 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001887 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001888 { USB_CLASS_CONTENT_SEC, "Content Security" },
1889 { -1, NULL }
1890};
1891
1892static const char *usb_class_str(uint8_t class)
1893{
1894 const struct usb_class_info *p;
1895 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001896 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001897 break;
David Ahern27911042010-04-24 10:26:22 -06001898 }
bellardbb36d472005-11-05 14:22:28 +00001899 }
bellarda594cfb2005-11-06 16:13:29 +00001900 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001901}
1902
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001903static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
1904 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00001905 const char *product_name,
1906 int speed)
bellardbb36d472005-11-05 14:22:28 +00001907{
bellarda594cfb2005-11-06 16:13:29 +00001908 const char *class_str, *speed_str;
1909
1910 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001911 case USB_SPEED_LOW:
1912 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001913 break;
ths5fafdf22007-09-16 21:08:06 +00001914 case USB_SPEED_FULL:
1915 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001916 break;
ths5fafdf22007-09-16 21:08:06 +00001917 case USB_SPEED_HIGH:
1918 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001919 break;
Hans de Goedef264cfb2011-05-31 11:35:19 +02001920 case USB_SPEED_SUPER:
1921 speed_str = "5000";
1922 break;
bellarda594cfb2005-11-06 16:13:29 +00001923 default:
ths5fafdf22007-09-16 21:08:06 +00001924 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001925 break;
bellardbb36d472005-11-05 14:22:28 +00001926 }
bellarda594cfb2005-11-06 16:13:29 +00001927
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001928 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
1929 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00001930 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001931 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001932 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001933 } else {
aliguori376253e2009-03-05 23:01:23 +00001934 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001935 }
aliguori376253e2009-03-05 23:01:23 +00001936 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001937 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001938 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001939 }
aliguori376253e2009-03-05 23:01:23 +00001940 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001941}
1942
ths5fafdf22007-09-16 21:08:06 +00001943static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001944 char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001945 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001946 const char *product_name,
1947 int speed)
1948{
Blue Swirl179da8a2009-09-07 19:00:18 +00001949 Monitor *mon = opaque;
1950
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001951 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001952 product_name, speed);
1953 return 0;
1954}
1955
aliguoriac4ffb52008-09-22 15:04:31 +00001956static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001957{
David Ahern27911042010-04-24 10:26:22 -06001958 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001959 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001960 } else {
1961 snprintf(str, size, "%d", val);
1962 }
aliguori5d0c5752008-09-14 01:07:41 +00001963}
1964
aliguoriac4ffb52008-09-22 15:04:31 +00001965static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001966{
David Ahern27911042010-04-24 10:26:22 -06001967 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001968 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001969 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001970 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06001971 }
aliguori5d0c5752008-09-14 01:07:41 +00001972}
1973
aliguori376253e2009-03-05 23:01:23 +00001974void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00001975{
aliguori5d0c5752008-09-14 01:07:41 +00001976 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001977 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00001978
Blue Swirl179da8a2009-09-07 19:00:18 +00001979 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00001980
David Ahern27911042010-04-24 10:26:22 -06001981 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001982 return;
David Ahern27911042010-04-24 10:26:22 -06001983 }
1984
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001985 monitor_printf(mon, " Auto filters:\n");
1986 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00001987 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001988 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00001989 dec2str(f->bus_num, bus, sizeof(bus));
1990 dec2str(f->addr, addr, sizeof(addr));
1991 hex2str(f->vendor_id, vid, sizeof(vid));
1992 hex2str(f->product_id, pid, sizeof(pid));
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001993 monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
1994 bus, addr, f->port ? f->port : "*", vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00001995 }
bellardbb36d472005-11-05 14:22:28 +00001996}