blob: e7fc9ecd5c3a73bc4add03b775e2c9c18f1fd06f [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 Hoffmannba9acab2011-08-17 23:35:45 +020057typedef int USBScanFunc(void *opaque, int bus_num, int addr, const 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
bellard1f6e24e2006-06-26 21:00:51 +000069#define PRODUCT_NAME_SZ 32
Gerd Hoffmann5557d822011-05-10 11:43:57 +020070#define MAX_PORTLEN 16
bellardbb36d472005-11-05 14:22:28 +000071
balrogb9dc0332007-10-04 22:47:34 +000072/* endpoint association data */
Hans de Goede060dc842010-11-26 11:41:08 +010073#define ISO_FRAME_DESC_PER_URB 32
Hans de Goede060dc842010-11-26 11:41:08 +010074
Gerd Hoffmann71138532011-05-16 10:21:51 +020075/* devio.c limits single requests to 16k */
76#define MAX_USBFS_BUFFER_SIZE 16384
77
Hans de Goede060dc842010-11-26 11:41:08 +010078typedef struct AsyncURB AsyncURB;
79
balrogb9dc0332007-10-04 22:47:34 +000080struct endp_data {
aliguori64838172008-08-21 19:31:10 +000081 uint8_t halted;
Hans de Goedebb6d5492010-11-26 19:11:03 +010082 uint8_t iso_started;
Hans de Goede060dc842010-11-26 11:41:08 +010083 AsyncURB *iso_urb;
84 int iso_urb_idx;
Hans de Goedebb6d5492010-11-26 19:11:03 +010085 int iso_buffer_used;
Gerd Hoffmann82887262011-06-10 14:00:24 +020086 int inflight;
balrogb9dc0332007-10-04 22:47:34 +000087};
88
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010089struct USBAutoFilter {
90 uint32_t bus_num;
91 uint32_t addr;
Gerd Hoffmann9056a292011-05-10 12:07:42 +020092 char *port;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010093 uint32_t vendor_id;
94 uint32_t product_id;
95};
96
bellardbb36d472005-11-05 14:22:28 +000097typedef struct USBHostDevice {
98 USBDevice dev;
aliguori64838172008-08-21 19:31:10 +000099 int fd;
Gerd Hoffmann9516bb42011-08-24 13:34:17 +0200100 int hub_fd;
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100101 int hub_port;
aliguori64838172008-08-21 19:31:10 +0000102
Hans de Goedef8ddbfb2011-05-31 11:35:26 +0200103 uint8_t descr[8192];
aliguori64838172008-08-21 19:31:10 +0000104 int descr_len;
aliguori24772c12008-08-21 19:31:52 +0000105 int closing;
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200106 uint32_t iso_urb_count;
Shahar Havivib373a632010-06-16 15:16:11 +0300107 Notifier exit;
aliguori64838172008-08-21 19:31:10 +0000108
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200109 struct endp_data ep_in[USB_MAX_ENDPOINTS];
110 struct endp_data ep_out[USB_MAX_ENDPOINTS];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200111 QLIST_HEAD(, AsyncURB) aurbs;
aliguori4b096fc2008-08-21 19:28:55 +0000112
aliguori4b096fc2008-08-21 19:28:55 +0000113 /* Host side address */
114 int bus_num;
115 int addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200116 char port[MAX_PORTLEN];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100117 struct USBAutoFilter match;
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +0200118 int seen, errcount;
aliguori4b096fc2008-08-21 19:28:55 +0000119
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100120 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000121} USBHostDevice;
122
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100123static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
124
125static int usb_host_close(USBHostDevice *dev);
126static int parse_filter(const char *spec, struct USBAutoFilter *f);
127static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100128static int usb_host_read_file(char *line, size_t line_size,
129 const char *device_file, const char *device_name);
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200130static int usb_linux_update_endp_table(USBHostDevice *s);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100131
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200132static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
133{
134 static const int usbfs[] = {
135 [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL,
136 [USB_ENDPOINT_XFER_ISOC] = USBDEVFS_URB_TYPE_ISO,
137 [USB_ENDPOINT_XFER_BULK] = USBDEVFS_URB_TYPE_BULK,
138 [USB_ENDPOINT_XFER_INT] = USBDEVFS_URB_TYPE_INTERRUPT,
139 };
140 uint8_t type = usb_ep_get_type(&s->dev, p->pid, p->devep);
141 assert(type < ARRAY_SIZE(usbfs));
142 return usbfs[type];
143}
144
Gerd Hoffmannc7662da2011-11-16 12:37:17 +0100145static int usb_host_do_reset(USBHostDevice *dev)
146{
147 struct timeval s, e;
148 uint32_t usecs;
149 int ret;
150
151 gettimeofday(&s, NULL);
152 ret = ioctl(dev->fd, USBDEVFS_RESET);
153 gettimeofday(&e, NULL);
154 usecs = (e.tv_sec - s.tv_sec) * 1000000;
155 usecs += e.tv_usec - s.tv_usec;
156 if (usecs > 1000000) {
157 /* more than a second, something is fishy, broken usb device? */
158 fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n",
159 dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000);
160 }
161 return ret;
162}
163
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200164static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200165{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200166 struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
167 assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200168 assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200169 return eps + ep - 1;
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200170}
171
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200172static int is_isoc(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000173{
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200174 return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC;
aliguori64838172008-08-21 19:31:10 +0000175}
176
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200177static int is_valid(USBHostDevice *s, int pid, int ep)
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100178{
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200179 return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID;
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100180}
181
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200182static int is_halted(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000183{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200184 return get_endp(s, pid, ep)->halted;
aliguori64838172008-08-21 19:31:10 +0000185}
186
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200187static void clear_halt(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000188{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200189 trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200190 get_endp(s, pid, ep)->halted = 0;
aliguori64838172008-08-21 19:31:10 +0000191}
192
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200193static void set_halt(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000194{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200195 if (ep != 0) {
196 trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
197 get_endp(s, pid, ep)->halted = 1;
198 }
aliguori64838172008-08-21 19:31:10 +0000199}
200
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200201static int is_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100202{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200203 return get_endp(s, pid, ep)->iso_started;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100204}
205
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200206static void clear_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100207{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200208 trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200209 get_endp(s, pid, ep)->iso_started = 0;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100210}
211
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200212static void set_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100213{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200214 struct endp_data *e = get_endp(s, pid, ep);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200215
216 trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200217 if (!e->iso_started) {
218 e->iso_started = 1;
219 e->inflight = 0;
220 }
221}
222
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200223static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
Gerd Hoffmann82887262011-06-10 14:00:24 +0200224{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200225 struct endp_data *e = get_endp(s, pid, ep);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200226
227 e->inflight += value;
228 return e->inflight;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100229}
230
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200231static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
Hans de Goede060dc842010-11-26 11:41:08 +0100232{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200233 get_endp(s, pid, ep)->iso_urb = iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100234}
235
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200236static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100237{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200238 return get_endp(s, pid, ep)->iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100239}
240
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200241static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
Hans de Goede060dc842010-11-26 11:41:08 +0100242{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200243 get_endp(s, pid, ep)->iso_urb_idx = i;
Hans de Goede060dc842010-11-26 11:41:08 +0100244}
245
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200246static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100247{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200248 return get_endp(s, pid, ep)->iso_urb_idx;
Hans de Goede060dc842010-11-26 11:41:08 +0100249}
250
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200251static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100252{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200253 get_endp(s, pid, ep)->iso_buffer_used = i;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100254}
255
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200256static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100257{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200258 return get_endp(s, pid, ep)->iso_buffer_used;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100259}
260
David Ahern27911042010-04-24 10:26:22 -0600261/*
aliguori64838172008-08-21 19:31:10 +0000262 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100263 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600264 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000265 */
Hans de Goede060dc842010-11-26 11:41:08 +0100266struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000267{
aliguori64838172008-08-21 19:31:10 +0000268 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100269 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200270 USBHostDevice *hdev;
271 QLIST_ENTRY(AsyncURB) next;
aliguori64838172008-08-21 19:31:10 +0000272
Hans de Goede060dc842010-11-26 11:41:08 +0100273 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000274 USBPacket *packet;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200275 int more; /* large transfer, more urbs follow */
Hans de Goede060dc842010-11-26 11:41:08 +0100276
277 /* For buffered iso handling */
278 int iso_frame_idx; /* -1 means in flight */
279};
aliguori64838172008-08-21 19:31:10 +0000280
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200281static AsyncURB *async_alloc(USBHostDevice *s)
aliguori64838172008-08-21 19:31:10 +0000282{
Anthony Liguori7267c092011-08-20 22:09:37 -0500283 AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200284 aurb->hdev = s;
285 QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
286 return aurb;
balrogb9dc0332007-10-04 22:47:34 +0000287}
288
aliguori64838172008-08-21 19:31:10 +0000289static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000290{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200291 QLIST_REMOVE(aurb, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500292 g_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000293}
balrogb9dc0332007-10-04 22:47:34 +0000294
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200295static void do_disconnect(USBHostDevice *s)
296{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200297 usb_host_close(s);
298 usb_host_auto_check(NULL);
299}
300
aliguori64838172008-08-21 19:31:10 +0000301static void async_complete(void *opaque)
302{
303 USBHostDevice *s = opaque;
304 AsyncURB *aurb;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200305 int urbs = 0;
balrogb9dc0332007-10-04 22:47:34 +0000306
aliguori64838172008-08-21 19:31:10 +0000307 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600308 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000309
David Ahern27911042010-04-24 10:26:22 -0600310 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000311 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600312 if (errno == EAGAIN) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200313 if (urbs > 2) {
314 fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);
315 }
aliguori64838172008-08-21 19:31:10 +0000316 return;
David Ahern27911042010-04-24 10:26:22 -0600317 }
Gerd Hoffmann40197c32011-08-22 14:18:21 +0200318 if (errno == ENODEV) {
319 if (!s->closing) {
320 trace_usb_host_disconnect(s->bus_num, s->addr);
321 do_disconnect(s);
322 }
aliguori64838172008-08-21 19:31:10 +0000323 return;
324 }
325
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200326 perror("USBDEVFS_REAPURBNDELAY");
aliguori64838172008-08-21 19:31:10 +0000327 return;
balrogb9dc0332007-10-04 22:47:34 +0000328 }
aliguori64838172008-08-21 19:31:10 +0000329
David Ahern27911042010-04-24 10:26:22 -0600330 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000331 aurb, aurb->urb.status, aurb->urb.actual_length);
332
Hans de Goede060dc842010-11-26 11:41:08 +0100333 /* If this is a buffered iso urb mark it as complete and don't do
334 anything else (it is handled further in usb_host_handle_iso_data) */
335 if (aurb->iso_frame_idx == -1) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200336 int inflight;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200337 int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
338 USB_TOKEN_IN : USB_TOKEN_OUT;
339 int ep = aurb->urb.endpoint & 0xf;
Hans de Goede060dc842010-11-26 11:41:08 +0100340 if (aurb->urb.status == -EPIPE) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200341 set_halt(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100342 }
343 aurb->iso_frame_idx = 0;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200344 urbs++;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200345 inflight = change_iso_inflight(s, pid, ep, -1);
346 if (inflight == 0 && is_iso_started(s, pid, ep)) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200347 fprintf(stderr, "husb: out of buffers for iso stream\n");
348 }
Hans de Goede060dc842010-11-26 11:41:08 +0100349 continue;
350 }
351
352 p = aurb->packet;
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200353 trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
354 aurb->urb.actual_length, aurb->more);
Hans de Goede060dc842010-11-26 11:41:08 +0100355
David Ahern27911042010-04-24 10:26:22 -0600356 if (p) {
aliguori64838172008-08-21 19:31:10 +0000357 switch (aurb->urb.status) {
358 case 0:
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200359 p->result += aurb->urb.actual_length;
aliguori64838172008-08-21 19:31:10 +0000360 break;
361
362 case -EPIPE:
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200363 set_halt(s, p->pid, p->devep);
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200364 p->result = USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600365 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200366
aliguori64838172008-08-21 19:31:10 +0000367 default:
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200368 p->result = USB_RET_NAK;
aliguori64838172008-08-21 19:31:10 +0000369 break;
370 }
371
Hans de Goede50b79632011-02-02 17:36:29 +0100372 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200373 trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
Hans de Goede50b79632011-02-02 17:36:29 +0100374 usb_generic_async_ctrl_complete(&s->dev, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200375 } else if (!aurb->more) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200376 trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
Hans de Goede50b79632011-02-02 17:36:29 +0100377 usb_packet_complete(&s->dev, p);
378 }
David Ahern27911042010-04-24 10:26:22 -0600379 }
aliguori64838172008-08-21 19:31:10 +0000380
381 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000382 }
balrogb9dc0332007-10-04 22:47:34 +0000383}
384
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200385static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
balrogb9dc0332007-10-04 22:47:34 +0000386{
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200387 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200388 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000389
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200390 QLIST_FOREACH(aurb, &s->aurbs, next) {
391 if (p != aurb->packet) {
392 continue;
393 }
balrogb9dc0332007-10-04 22:47:34 +0000394
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200395 DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
aliguori64838172008-08-21 19:31:10 +0000396
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200397 /* Mark it as dead (see async_complete above) */
398 aurb->packet = NULL;
399
400 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
401 if (r < 0) {
402 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
403 }
balrogb9dc0332007-10-04 22:47:34 +0000404 }
balrogb9dc0332007-10-04 22:47:34 +0000405}
406
Gerd Hoffmann097db432011-12-16 11:54:11 +0100407static int usb_host_open_device(int bus, int addr)
408{
409 const char *usbfs = NULL;
410 char filename[32];
411 struct stat st;
412 int fd, rc;
413
414 rc = stat("/dev/bus/usb", &st);
415 if (rc == 0 && S_ISDIR(st.st_mode)) {
416 /* udev-created device nodes available */
417 usbfs = "/dev/bus/usb";
418 } else {
419 /* fallback: usbfs mounted below /proc */
420 usbfs = "/proc/bus/usb";
421 }
422
423 snprintf(filename, sizeof(filename), "%s/%03d/%03d",
424 usbfs, bus, addr);
425 fd = open(filename, O_RDWR | O_NONBLOCK);
426 if (fd < 0) {
427 fprintf(stderr, "husb: open %s: %s\n", filename, strerror(errno));
428 }
429 return fd;
430}
431
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200432static int usb_host_claim_port(USBHostDevice *s)
433{
434#ifdef USBDEVFS_CLAIM_PORT
435 char *h, hub_name[64], line[1024];
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100436 int hub_addr, ret;
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200437
438 snprintf(hub_name, sizeof(hub_name), "%d-%s",
439 s->match.bus_num, s->match.port);
440
441 /* try strip off last ".$portnr" to get hub */
442 h = strrchr(hub_name, '.');
443 if (h != NULL) {
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100444 s->hub_port = atoi(h+1);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200445 *h = '\0';
446 } else {
447 /* no dot in there -> it is the root hub */
448 snprintf(hub_name, sizeof(hub_name), "usb%d",
449 s->match.bus_num);
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100450 s->hub_port = atoi(s->match.port);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200451 }
452
453 if (!usb_host_read_file(line, sizeof(line), "devnum",
454 hub_name)) {
455 return -1;
456 }
457 if (sscanf(line, "%d", &hub_addr) != 1) {
458 return -1;
459 }
460
Gerd Hoffmann097db432011-12-16 11:54:11 +0100461 s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200462 if (s->hub_fd < 0) {
463 return -1;
464 }
465
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100466 ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200467 if (ret < 0) {
468 close(s->hub_fd);
469 s->hub_fd = -1;
470 return -1;
471 }
472
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100473 trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200474 return 0;
475#else
476 return -1;
477#endif
478}
479
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100480static void usb_host_release_port(USBHostDevice *s)
481{
482 if (s->hub_fd == -1) {
483 return;
484 }
485#ifdef USBDEVFS_RELEASE_PORT
486 ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
487#endif
488 close(s->hub_fd);
489 s->hub_fd = -1;
490}
491
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200492static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
493{
494 /* earlier Linux 2.4 do not support that */
495#ifdef USBDEVFS_DISCONNECT
496 struct usbdevfs_ioctl ctrl;
497 int ret, interface;
498
499 for (interface = 0; interface < nb_interfaces; interface++) {
500 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
501 ctrl.ifno = interface;
502 ctrl.data = 0;
503 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
504 if (ret < 0 && errno != ENODATA) {
505 perror("USBDEVFS_DISCONNECT");
506 return -1;
507 }
508 }
509#endif
510 return 0;
511}
512
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200513static int usb_linux_get_num_interfaces(USBHostDevice *s)
514{
515 char device_name[64], line[1024];
516 int num_interfaces = 0;
517
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200518 sprintf(device_name, "%d-%s", s->bus_num, s->port);
519 if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
520 device_name)) {
521 return -1;
522 }
523 if (sscanf(line, "%d", &num_interfaces) != 1) {
524 return -1;
525 }
526 return num_interfaces;
527}
528
aliguori446ab122008-09-14 01:06:09 +0000529static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000530{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200531 const char *op = NULL;
balrogb9dc0332007-10-04 22:47:34 +0000532 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000533 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000534 int ret, i;
535
Gerd Hoffmann1de14d42011-08-30 13:21:27 +0200536 for (i = 0; i < USB_MAX_INTERFACES; i++) {
537 dev->dev.altsetting[i] = 0;
538 }
539
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200540 if (configuration == 0) { /* address state - ignore */
Gerd Hoffmann65360512011-08-30 11:11:29 +0200541 dev->dev.ninterfaces = 0;
542 dev->dev.configuration = 0;
balrogb9dc0332007-10-04 22:47:34 +0000543 return 1;
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200544 }
balrogb9dc0332007-10-04 22:47:34 +0000545
malcd0f2c4c2010-02-07 02:03:50 +0300546 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000547
balrogb9dc0332007-10-04 22:47:34 +0000548 i = 0;
549 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600550 if (dev_descr_len > dev->descr_len) {
Hans de Goede61c11172011-05-31 11:35:20 +0200551 fprintf(stderr, "husb: update iface failed. descr too short\n");
552 return 0;
David Ahern27911042010-04-24 10:26:22 -0600553 }
balrogb9dc0332007-10-04 22:47:34 +0000554
555 i += dev_descr_len;
556 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600557 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
558 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000559 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000560
balrogb9dc0332007-10-04 22:47:34 +0000561 if (dev->descr[i+1] != USB_DT_CONFIG) {
562 i += dev->descr[i];
563 continue;
564 }
565 config_descr_len = dev->descr[i];
566
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200567 DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000568
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200569 if (configuration == dev->descr[i + 5]) {
aliguori446ab122008-09-14 01:06:09 +0000570 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000571 break;
aliguori446ab122008-09-14 01:06:09 +0000572 }
balrogb9dc0332007-10-04 22:47:34 +0000573
574 i += config_descr_len;
575 }
576
577 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600578 fprintf(stderr,
579 "husb: update iface failed. no matching configuration\n");
Hans de Goede61c11172011-05-31 11:35:20 +0200580 return 0;
balrogb9dc0332007-10-04 22:47:34 +0000581 }
582 nb_interfaces = dev->descr[i + 4];
583
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200584 if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
585 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000586 }
balrogb9dc0332007-10-04 22:47:34 +0000587
588 /* XXX: only grab if all interfaces are free */
589 for (interface = 0; interface < nb_interfaces; interface++) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200590 op = "USBDEVFS_CLAIMINTERFACE";
balrogb9dc0332007-10-04 22:47:34 +0000591 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
592 if (ret < 0) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200593 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000594 }
595 }
596
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200597 trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
598 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000599
Gerd Hoffmann65360512011-08-30 11:11:29 +0200600 dev->dev.ninterfaces = nb_interfaces;
601 dev->dev.configuration = configuration;
aliguori446ab122008-09-14 01:06:09 +0000602 return 1;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200603
604fail:
605 if (errno == ENODEV) {
606 do_disconnect(dev);
607 }
608 perror(op);
609 return 0;
aliguori446ab122008-09-14 01:06:09 +0000610}
611
612static int usb_host_release_interfaces(USBHostDevice *s)
613{
614 int ret, i;
615
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200616 trace_usb_host_release_interfaces(s->bus_num, s->addr);
aliguori446ab122008-09-14 01:06:09 +0000617
Gerd Hoffmann65360512011-08-30 11:11:29 +0200618 for (i = 0; i < s->dev.ninterfaces; i++) {
aliguori446ab122008-09-14 01:06:09 +0000619 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
620 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200621 perror("USBDEVFS_RELEASEINTERFACE");
aliguori446ab122008-09-14 01:06:09 +0000622 return 0;
623 }
624 }
balrogb9dc0332007-10-04 22:47:34 +0000625 return 1;
626}
627
bellard059809e2006-07-19 18:06:15 +0000628static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000629{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100630 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000631
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200632 trace_usb_host_reset(s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000633
Gerd Hoffmannc7662da2011-11-16 12:37:17 +0100634 usb_host_do_reset(s);;
aliguori446ab122008-09-14 01:06:09 +0000635
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200636 usb_host_claim_interfaces(s, 0);
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200637 usb_linux_update_endp_table(s);
ths5fafdf22007-09-16 21:08:06 +0000638}
bellardbb36d472005-11-05 14:22:28 +0000639
bellard059809e2006-07-19 18:06:15 +0000640static void usb_host_handle_destroy(USBDevice *dev)
641{
642 USBHostDevice *s = (USBHostDevice *)dev;
643
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100644 usb_host_release_port(s);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100645 usb_host_close(s);
646 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300647 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000648}
649
Hans de Goede060dc842010-11-26 11:41:08 +0100650/* iso data is special, we need to keep enough urbs in flight to make sure
651 that the controller never runs out of them, otherwise the device will
652 likely suffer a buffer underrun / overrun. */
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200653static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100654{
655 AsyncURB *aurb;
Gerd Hoffmannf0033972011-08-31 16:09:27 +0200656 int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100657
Anthony Liguori7267c092011-08-20 22:09:37 -0500658 aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200659 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100660 aurb[i].urb.endpoint = ep;
661 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
Anthony Liguori7267c092011-08-20 22:09:37 -0500662 aurb[i].urb.buffer = g_malloc(aurb[i].urb.buffer_length);
Hans de Goede060dc842010-11-26 11:41:08 +0100663 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
664 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
665 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
666 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
667 aurb[i].urb.iso_frame_desc[j].length = len;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200668 if (pid == USB_TOKEN_IN) {
Hans de Goede060dc842010-11-26 11:41:08 +0100669 aurb[i].urb.endpoint |= 0x80;
670 /* Mark as fully consumed (idle) */
671 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
672 }
673 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200674 set_iso_urb(s, pid, ep, aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100675
676 return aurb;
677}
678
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200679static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100680{
681 AsyncURB *aurb;
682 int i, ret, killed = 0, free = 1;
683
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200684 aurb = get_iso_urb(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100685 if (!aurb) {
686 return;
687 }
688
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200689 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100690 /* in flight? */
691 if (aurb[i].iso_frame_idx == -1) {
692 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
693 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200694 perror("USBDEVFS_DISCARDURB");
Hans de Goede060dc842010-11-26 11:41:08 +0100695 free = 0;
696 continue;
697 }
698 killed++;
699 }
700 }
701
702 /* Make sure any urbs we've killed are reaped before we free them */
703 if (killed) {
704 async_complete(s);
705 }
706
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200707 for (i = 0; i < s->iso_urb_count; i++) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500708 g_free(aurb[i].urb.buffer);
Hans de Goede060dc842010-11-26 11:41:08 +0100709 }
710
711 if (free)
Anthony Liguori7267c092011-08-20 22:09:37 -0500712 g_free(aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100713 else
714 printf("husb: leaking iso urbs because of discard failure\n");
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200715 set_iso_urb(s, pid, ep, NULL);
716 set_iso_urb_idx(s, pid, ep, 0);
717 clear_iso_started(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100718}
719
720static int urb_status_to_usb_ret(int status)
721{
722 switch (status) {
723 case -EPIPE:
724 return USB_RET_STALL;
725 default:
726 return USB_RET_NAK;
727 }
728}
729
Hans de Goedebb6d5492010-11-26 19:11:03 +0100730static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100731{
732 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100733 int i, j, ret, max_packet_size, offset, len = 0;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200734 uint8_t *buf;
Hans de Goede975f2992010-11-26 14:59:35 +0100735
Gerd Hoffmannf0033972011-08-31 16:09:27 +0200736 max_packet_size = usb_ep_get_max_packet_size(&s->dev, p->pid, p->devep);
Hans de Goede975f2992010-11-26 14:59:35 +0100737 if (max_packet_size == 0)
738 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100739
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200740 aurb = get_iso_urb(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100741 if (!aurb) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200742 aurb = usb_host_alloc_iso(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100743 }
744
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200745 i = get_iso_urb_idx(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100746 j = aurb[i].iso_frame_idx;
747 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100748 if (in) {
749 /* Check urb status */
750 if (aurb[i].urb.status) {
751 len = urb_status_to_usb_ret(aurb[i].urb.status);
752 /* Move to the next urb */
753 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
754 /* Check frame status */
755 } else if (aurb[i].urb.iso_frame_desc[j].status) {
756 len = urb_status_to_usb_ret(
757 aurb[i].urb.iso_frame_desc[j].status);
758 /* Check the frame fits */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200759 } else if (aurb[i].urb.iso_frame_desc[j].actual_length
760 > p->iov.size) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100761 printf("husb: received iso data is larger then packet\n");
762 len = USB_RET_NAK;
763 /* All good copy data over */
764 } else {
765 len = aurb[i].urb.iso_frame_desc[j].actual_length;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200766 buf = aurb[i].urb.buffer +
767 j * aurb[i].urb.iso_frame_desc[0].length;
768 usb_packet_copy(p, buf, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100769 }
Hans de Goede060dc842010-11-26 11:41:08 +0100770 } else {
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200771 len = p->iov.size;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200772 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100773
774 /* Check the frame fits */
775 if (len > max_packet_size) {
776 printf("husb: send iso data is larger then max packet size\n");
777 return USB_RET_NAK;
778 }
779
780 /* All good copy data over */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200781 usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100782 aurb[i].urb.iso_frame_desc[j].length = len;
783 offset += len;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200784 set_iso_buffer_used(s, p->pid, p->devep, offset);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100785
786 /* Start the stream once we have buffered enough data */
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200787 if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
788 set_iso_started(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100789 }
Hans de Goede060dc842010-11-26 11:41:08 +0100790 }
791 aurb[i].iso_frame_idx++;
792 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200793 i = (i + 1) % s->iso_urb_count;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200794 set_iso_urb_idx(s, p->pid, p->devep, i);
Hans de Goede060dc842010-11-26 11:41:08 +0100795 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100796 } else {
797 if (in) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200798 set_iso_started(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100799 } else {
800 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
801 }
Hans de Goede060dc842010-11-26 11:41:08 +0100802 }
803
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200804 if (is_iso_started(s, p->pid, p->devep)) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100805 /* (Re)-submit all fully consumed / filled urbs */
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200806 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100807 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
808 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
809 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200810 perror("USBDEVFS_SUBMITURB");
Hans de Goedebb6d5492010-11-26 19:11:03 +0100811 if (!in || len == 0) {
812 switch(errno) {
813 case ETIMEDOUT:
814 len = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200815 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100816 case EPIPE:
817 default:
818 len = USB_RET_STALL;
819 }
Hans de Goede060dc842010-11-26 11:41:08 +0100820 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100821 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100822 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100823 aurb[i].iso_frame_idx = -1;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200824 change_iso_inflight(s, p->pid, p->devep, 1);
Hans de Goede060dc842010-11-26 11:41:08 +0100825 }
Hans de Goede060dc842010-11-26 11:41:08 +0100826 }
827 }
828
829 return len;
830}
831
Hans de Goede50b79632011-02-02 17:36:29 +0100832static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000833{
Hans de Goede50b79632011-02-02 17:36:29 +0100834 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000835 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000836 AsyncURB *aurb;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200837 int ret, rem, prem, v;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200838 uint8_t *pbuf;
Hans de Goede060dc842010-11-26 11:41:08 +0100839 uint8_t ep;
840
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200841 trace_usb_host_req_data(s->bus_num, s->addr,
842 p->pid == USB_TOKEN_IN,
843 p->devep, p->iov.size);
844
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200845 if (!is_valid(s, p->pid, p->devep)) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200846 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100847 return USB_RET_NAK;
848 }
849
Hans de Goede060dc842010-11-26 11:41:08 +0100850 if (p->pid == USB_TOKEN_IN) {
851 ep = p->devep | 0x80;
852 } else {
853 ep = p->devep;
854 }
855
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200856 if (is_halted(s, p->pid, p->devep)) {
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200857 unsigned int arg = ep;
858 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
Hans de Goede060dc842010-11-26 11:41:08 +0100859 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200860 perror("USBDEVFS_CLEAR_HALT");
861 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Hans de Goede060dc842010-11-26 11:41:08 +0100862 return USB_RET_NAK;
863 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200864 clear_halt(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100865 }
866
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200867 if (is_isoc(s, p->pid, p->devep)) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100868 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
869 }
bellardbb36d472005-11-05 14:22:28 +0000870
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200871 v = 0;
872 prem = p->iov.iov[v].iov_len;
873 pbuf = p->iov.iov[v].iov_base;
874 rem = p->iov.size;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200875 while (rem) {
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200876 if (prem == 0) {
877 v++;
878 assert(v < p->iov.niov);
879 prem = p->iov.iov[v].iov_len;
880 pbuf = p->iov.iov[v].iov_base;
881 assert(prem <= rem);
882 }
Gerd Hoffmann71138532011-05-16 10:21:51 +0200883 aurb = async_alloc(s);
884 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000885
Gerd Hoffmann71138532011-05-16 10:21:51 +0200886 urb = &aurb->urb;
887 urb->endpoint = ep;
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200888 urb->type = usb_host_usbfs_type(s, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200889 urb->usercontext = s;
890 urb->buffer = pbuf;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200891 urb->buffer_length = prem;
aliguori64838172008-08-21 19:31:10 +0000892
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200893 if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
Gerd Hoffmann71138532011-05-16 10:21:51 +0200894 urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200895 }
896 pbuf += urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200897 prem -= urb->buffer_length;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200898 rem -= urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200899 if (rem) {
900 aurb->more = 1;
901 }
aliguori64838172008-08-21 19:31:10 +0000902
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200903 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
904 urb->buffer_length, aurb->more);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200905 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
aliguori64838172008-08-21 19:31:10 +0000906
Gerd Hoffmann71138532011-05-16 10:21:51 +0200907 DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
908 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
aliguori64838172008-08-21 19:31:10 +0000909
Gerd Hoffmann71138532011-05-16 10:21:51 +0200910 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200911 perror("USBDEVFS_SUBMITURB");
Gerd Hoffmann71138532011-05-16 10:21:51 +0200912 async_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000913
Gerd Hoffmann71138532011-05-16 10:21:51 +0200914 switch(errno) {
915 case ETIMEDOUT:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200916 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200917 return USB_RET_NAK;
918 case EPIPE:
919 default:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200920 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200921 return USB_RET_STALL;
922 }
balrogb9dc0332007-10-04 22:47:34 +0000923 }
924 }
aliguori64838172008-08-21 19:31:10 +0000925
balrogb9dc0332007-10-04 22:47:34 +0000926 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000927}
928
aliguori446ab122008-09-14 01:06:09 +0000929static int ctrl_error(void)
930{
David Ahern27911042010-04-24 10:26:22 -0600931 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000932 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600933 } else {
aliguori446ab122008-09-14 01:06:09 +0000934 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600935 }
aliguori446ab122008-09-14 01:06:09 +0000936}
937
938static int usb_host_set_address(USBHostDevice *s, int addr)
939{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200940 trace_usb_host_set_address(s->bus_num, s->addr, addr);
aliguori446ab122008-09-14 01:06:09 +0000941 s->dev.addr = addr;
942 return 0;
943}
944
945static int usb_host_set_config(USBHostDevice *s, int config)
946{
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200947 int ret, first = 1;
948
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200949 trace_usb_host_set_config(s->bus_num, s->addr, config);
950
aliguori446ab122008-09-14 01:06:09 +0000951 usb_host_release_interfaces(s);
952
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200953again:
954 ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600955
malcd0f2c4c2010-02-07 02:03:50 +0300956 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600957
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200958 if (ret < 0 && errno == EBUSY && first) {
959 /* happens if usb device is in use by host drivers */
960 int count = usb_linux_get_num_interfaces(s);
961 if (count > 0) {
962 DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
963 usb_host_disconnect_ifaces(s, count);
964 first = 0;
965 goto again;
966 }
967 }
968
David Ahern27911042010-04-24 10:26:22 -0600969 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000970 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600971 }
aliguori446ab122008-09-14 01:06:09 +0000972 usb_host_claim_interfaces(s, config);
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200973 usb_linux_update_endp_table(s);
aliguori446ab122008-09-14 01:06:09 +0000974 return 0;
975}
976
977static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
978{
979 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100980 int i, ret;
981
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200982 trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
983
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200984 for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200985 if (is_isoc(s, USB_TOKEN_IN, i)) {
986 usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
987 }
988 if (is_isoc(s, USB_TOKEN_OUT, i)) {
989 usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
Hans de Goede060dc842010-11-26 11:41:08 +0100990 }
991 }
aliguori446ab122008-09-14 01:06:09 +0000992
Gerd Hoffmann1de14d42011-08-30 13:21:27 +0200993 if (iface >= USB_MAX_INTERFACES) {
994 return USB_RET_STALL;
995 }
996
aliguori446ab122008-09-14 01:06:09 +0000997 si.interface = iface;
998 si.altsetting = alt;
999 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +00001000
David Ahern27911042010-04-24 10:26:22 -06001001 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
1002 iface, alt, ret, errno);
1003
1004 if (ret < 0) {
1005 return ctrl_error();
1006 }
Gerd Hoffmann1de14d42011-08-30 13:21:27 +02001007
1008 s->dev.altsetting[iface] = alt;
aliguori446ab122008-09-14 01:06:09 +00001009 usb_linux_update_endp_table(s);
1010 return 0;
1011}
1012
Hans de Goede50b79632011-02-02 17:36:29 +01001013static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
1014 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +00001015{
Hans de Goede50b79632011-02-02 17:36:29 +01001016 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +00001017 struct usbdevfs_urb *urb;
1018 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +01001019 int ret;
aliguori446ab122008-09-14 01:06:09 +00001020
David Ahern27911042010-04-24 10:26:22 -06001021 /*
aliguori446ab122008-09-14 01:06:09 +00001022 * Process certain standard device requests.
1023 * These are infrequent and are processed synchronously.
1024 */
aliguori446ab122008-09-14 01:06:09 +00001025
Hans de Goede50b79632011-02-02 17:36:29 +01001026 /* Note request is (bRequestType << 8) | bRequest */
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001027 trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
aliguori446ab122008-09-14 01:06:09 +00001028
Hans de Goede50b79632011-02-02 17:36:29 +01001029 switch (request) {
1030 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
1031 return usb_host_set_address(s, value);
aliguori446ab122008-09-14 01:06:09 +00001032
Hans de Goede50b79632011-02-02 17:36:29 +01001033 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
1034 return usb_host_set_config(s, value & 0xff);
aliguori446ab122008-09-14 01:06:09 +00001035
Hans de Goede50b79632011-02-02 17:36:29 +01001036 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
aliguori446ab122008-09-14 01:06:09 +00001037 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -06001038 }
aliguori446ab122008-09-14 01:06:09 +00001039
1040 /* The rest are asynchronous */
1041
Hans de Goede50b79632011-02-02 17:36:29 +01001042 if (length > sizeof(dev->data_buf)) {
1043 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
1044 length, sizeof(dev->data_buf));
malcb2e3b6e2009-09-12 03:18:18 +04001045 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -04001046 }
1047
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +02001048 aurb = async_alloc(s);
aliguori446ab122008-09-14 01:06:09 +00001049 aurb->packet = p;
1050
David Ahern27911042010-04-24 10:26:22 -06001051 /*
aliguori446ab122008-09-14 01:06:09 +00001052 * Setup ctrl transfer.
1053 *
Brad Hardsa0102082011-04-13 19:45:33 +10001054 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +00001055 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -06001056 */
aliguori446ab122008-09-14 01:06:09 +00001057 urb = &aurb->urb;
1058
1059 urb->type = USBDEVFS_URB_TYPE_CONTROL;
1060 urb->endpoint = p->devep;
1061
Hans de Goede50b79632011-02-02 17:36:29 +01001062 urb->buffer = &dev->setup_buf;
1063 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +00001064
1065 urb->usercontext = s;
1066
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001067 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
1068 urb->buffer_length, aurb->more);
aliguori446ab122008-09-14 01:06:09 +00001069 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
1070
malcd0f2c4c2010-02-07 02:03:50 +03001071 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +00001072
1073 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +03001074 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +00001075 async_free(aurb);
1076
1077 switch(errno) {
1078 case ETIMEDOUT:
1079 return USB_RET_NAK;
1080 case EPIPE:
1081 default:
1082 return USB_RET_STALL;
1083 }
1084 }
1085
aliguori446ab122008-09-14 01:06:09 +00001086 return USB_RET_ASYNC;
1087}
1088
Hans de Goedeed3a3282010-11-24 12:50:00 +01001089static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
1090 uint8_t configuration, uint8_t interface)
1091{
Gerd Hoffmann097db432011-12-16 11:54:11 +01001092 char device_name[64], line[1024];
1093 int alt_setting;
Hans de Goedeed3a3282010-11-24 12:50:00 +01001094
Gerd Hoffmann097db432011-12-16 11:54:11 +01001095 sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
1096 (int)configuration, (int)interface);
Hans de Goedec43831f2010-11-24 12:57:59 +01001097
Gerd Hoffmann097db432011-12-16 11:54:11 +01001098 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
1099 device_name)) {
Hans de Goedeed3a3282010-11-24 12:50:00 +01001100 /* Assume alt 0 on error */
1101 return 0;
1102 }
Gerd Hoffmann097db432011-12-16 11:54:11 +01001103 if (sscanf(line, "%d", &alt_setting) != 1) {
1104 /* Assume alt 0 on error */
1105 return 0;
1106 }
Hans de Goedeed3a3282010-11-24 12:50:00 +01001107 return alt_setting;
1108}
1109
Hans de Goede71d71bb2010-11-10 10:06:24 +01001110/* returns 1 on problem encountered or 0 for success */
1111static int usb_linux_update_endp_table(USBHostDevice *s)
1112{
1113 uint8_t *descriptors;
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001114 uint8_t devep, type, alt_interface;
Gerd Hoffmannf0033972011-08-31 16:09:27 +02001115 uint16_t raw;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001116 int interface, length, i, ep, pid;
1117 struct endp_data *epd;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001118
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +02001119 usb_ep_init(&s->dev);
Hans de Goedea0b5fec2010-11-26 14:56:17 +01001120
Gerd Hoffmann65360512011-08-30 11:11:29 +02001121 if (s->dev.configuration == 0) {
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001122 /* not configured yet -- leave all endpoints disabled */
1123 return 0;
1124 }
Hans de Goede71d71bb2010-11-10 10:06:24 +01001125
balrogb9dc0332007-10-04 22:47:34 +00001126 /* get the desired configuration, interface, and endpoint descriptors
1127 * from device description */
1128 descriptors = &s->descr[18];
1129 length = s->descr_len - 18;
1130 i = 0;
1131
balrogb9dc0332007-10-04 22:47:34 +00001132 while (i < length) {
Cao,Bing Bu7279a852011-12-13 09:22:20 +08001133 if (descriptors[i + 1] != USB_DT_CONFIG) {
1134 fprintf(stderr, "invalid descriptor data\n");
1135 return 1;
Gerd Hoffmann65360512011-08-30 11:11:29 +02001136 } else if (descriptors[i + 5] != s->dev.configuration) {
1137 DPRINTF("not requested configuration %d\n", s->dev.configuration);
Cao,Bing Bu7279a852011-12-13 09:22:20 +08001138 i += (descriptors[i + 3] << 8) + descriptors[i + 2];
1139 continue;
1140 }
Cao,Bing Bu7279a852011-12-13 09:22:20 +08001141 i += descriptors[i];
1142
balrogb9dc0332007-10-04 22:47:34 +00001143 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1144 (descriptors[i + 1] == USB_DT_INTERFACE &&
1145 descriptors[i + 4] == 0)) {
1146 i += descriptors[i];
1147 continue;
1148 }
1149
1150 interface = descriptors[i + 2];
Gerd Hoffmann65360512011-08-30 11:11:29 +02001151 alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001152 interface);
balrogb9dc0332007-10-04 22:47:34 +00001153
1154 /* the current interface descriptor is the active interface
1155 * and has endpoints */
1156 if (descriptors[i + 3] != alt_interface) {
1157 i += descriptors[i];
1158 continue;
1159 }
1160
1161 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001162 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001163 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001164 }
balrogb9dc0332007-10-04 22:47:34 +00001165
1166 if (i >= length)
1167 break;
1168
1169 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001170 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001171 break;
David Ahern27911042010-04-24 10:26:22 -06001172 }
balrogb9dc0332007-10-04 22:47:34 +00001173
1174 devep = descriptors[i + 2];
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001175 pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
1176 ep = devep & 0xf;
1177 if (ep == 0) {
Hans de Goede130314f2011-05-31 11:35:22 +02001178 fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
1179 return 1;
1180 }
1181
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +02001182 type = descriptors[i + 3] & 0x3;
Gerd Hoffmannf0033972011-08-31 16:09:27 +02001183 raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
1184 usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +02001185 assert(usb_ep_get_type(&s->dev, pid, ep) ==
1186 USB_ENDPOINT_XFER_INVALID);
1187 usb_ep_set_type(&s->dev, pid, ep, type);
Gerd Hoffmann82f02fe2011-08-29 12:57:48 +02001188 usb_ep_set_ifnum(&s->dev, pid, ep, interface);
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +02001189
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001190 epd = get_endp(s, pid, ep);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001191 epd->halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001192
1193 i += descriptors[i];
1194 }
1195 }
Gerd Hoffmann5b6780d2011-08-29 13:45:25 +02001196#ifdef DEBUG
1197 usb_ep_dump(&s->dev);
1198#endif
balrogb9dc0332007-10-04 22:47:34 +00001199 return 0;
1200}
1201
Hans de Goedee4b17762011-05-30 11:40:45 +02001202/*
1203 * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
1204 * this function assumes this is safe, if:
1205 * 1) There are no isoc endpoints
1206 * 2) There are no interrupt endpoints with a max_packet_size > 64
1207 * Note bulk endpoints with a max_packet_size > 64 in theory also are not
1208 * usb1 compatible, but in practice this seems to work fine.
1209 */
1210static int usb_linux_full_speed_compat(USBHostDevice *dev)
1211{
1212 int i, packet_size;
1213
1214 /*
1215 * usb_linux_update_endp_table only registers info about ep in the current
1216 * interface altsettings, so we need to parse the descriptors again.
1217 */
1218 for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
1219 if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
1220 switch (dev->descr[i + 3] & 0x3) {
1221 case 0x00: /* CONTROL */
1222 break;
1223 case 0x01: /* ISO */
1224 return 0;
1225 case 0x02: /* BULK */
1226 break;
1227 case 0x03: /* INTERRUPT */
1228 packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
1229 if (packet_size > 64)
1230 return 0;
1231 break;
1232 }
1233 }
1234 }
1235 return 1;
1236}
1237
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001238static int usb_host_open(USBHostDevice *dev, int bus_num,
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001239 int addr, const char *port,
1240 const char *prod_name, int speed)
bellardbb36d472005-11-05 14:22:28 +00001241{
balrogb9dc0332007-10-04 22:47:34 +00001242 int fd = -1, ret;
aliguori1f3870a2008-08-21 19:27:48 +00001243
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001244 trace_usb_host_open_started(bus_num, addr);
1245
David Ahern27911042010-04-24 10:26:22 -06001246 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001247 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001248 }
aliguori1f3870a2008-08-21 19:27:48 +00001249
Gerd Hoffmann097db432011-12-16 11:54:11 +01001250 fd = usb_host_open_device(bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001251 if (fd < 0) {
aliguori1f3870a2008-08-21 19:27:48 +00001252 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001253 }
malcd0f2c4c2010-02-07 02:03:50 +03001254 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001255
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001256 dev->bus_num = bus_num;
1257 dev->addr = addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001258 strcpy(dev->port, port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001259 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001260
balrogb9dc0332007-10-04 22:47:34 +00001261 /* read the device description */
1262 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1263 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001264 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001265 goto fail;
1266 }
ths3b46e622007-09-17 08:09:54 +00001267
balrogb9dc0332007-10-04 22:47:34 +00001268#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001269 {
balrogb9dc0332007-10-04 22:47:34 +00001270 int x;
1271 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001272 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001273 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001274 }
balrogb9dc0332007-10-04 22:47:34 +00001275 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001276 }
1277#endif
1278
balrogb9dc0332007-10-04 22:47:34 +00001279
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001280 /* start unconfigured -- we'll wait for the guest to set a configuration */
1281 if (!usb_host_claim_interfaces(dev, 0)) {
balrogb9dc0332007-10-04 22:47:34 +00001282 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001283 }
bellardbb36d472005-11-05 14:22:28 +00001284
balrogb9dc0332007-10-04 22:47:34 +00001285 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001286 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001287 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001288 }
balrogb9dc0332007-10-04 22:47:34 +00001289
Hans de Goede3991c352011-05-31 11:35:18 +02001290 if (speed == -1) {
1291 struct usbdevfs_connectinfo ci;
1292
1293 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1294 if (ret < 0) {
1295 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
1296 goto fail;
1297 }
1298
1299 if (ci.slow) {
1300 speed = USB_SPEED_LOW;
1301 } else {
1302 speed = USB_SPEED_HIGH;
1303 }
David Ahern27911042010-04-24 10:26:22 -06001304 }
Hans de Goede3991c352011-05-31 11:35:18 +02001305 dev->dev.speed = speed;
Hans de Goedeba3f9bf2011-05-27 14:27:18 +02001306 dev->dev.speedmask = (1 << speed);
Hans de Goedee4b17762011-05-30 11:40:45 +02001307 if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
1308 dev->dev.speedmask |= USB_SPEED_MASK_FULL;
1309 }
Hans de Goede3991c352011-05-31 11:35:18 +02001310
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001311 trace_usb_host_open_success(bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001312
David Ahern27911042010-04-24 10:26:22 -06001313 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001314 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001315 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001316 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001317 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001318 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001319 }
bellard1f6e24e2006-06-26 21:00:51 +00001320
Hans de Goedefa19bf82011-05-27 19:05:15 +02001321 ret = usb_device_attach(&dev->dev);
1322 if (ret) {
1323 goto fail;
1324 }
1325
aliguori64838172008-08-21 19:31:10 +00001326 /* USB devio uses 'write' flag to check for async completions */
1327 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001328
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001329 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001330
balrogb9dc0332007-10-04 22:47:34 +00001331fail:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001332 trace_usb_host_open_failure(bus_num, addr);
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001333 if (dev->fd != -1) {
1334 close(dev->fd);
1335 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001336 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001337 return -1;
1338}
1339
1340static int usb_host_close(USBHostDevice *dev)
1341{
Hans de Goede060dc842010-11-26 11:41:08 +01001342 int i;
1343
Gerd Hoffmann39fba3a2011-10-28 16:13:50 +02001344 if (dev->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001345 return -1;
David Ahern27911042010-04-24 10:26:22 -06001346 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001347
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001348 trace_usb_host_close(dev->bus_num, dev->addr);
1349
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001350 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1351 dev->closing = 1;
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +02001352 for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001353 if (is_isoc(dev, USB_TOKEN_IN, i)) {
1354 usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
1355 }
1356 if (is_isoc(dev, USB_TOKEN_OUT, i)) {
1357 usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
Hans de Goede060dc842010-11-26 11:41:08 +01001358 }
1359 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001360 async_complete(dev);
1361 dev->closing = 0;
Gerd Hoffmann39fba3a2011-10-28 16:13:50 +02001362 if (dev->dev.attached) {
1363 usb_device_detach(&dev->dev);
1364 }
Gerd Hoffmannc7662da2011-11-16 12:37:17 +01001365 usb_host_do_reset(dev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001366 close(dev->fd);
1367 dev->fd = -1;
1368 return 0;
1369}
1370
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001371static void usb_host_exit_notifier(struct Notifier *n, void *data)
Shahar Havivib373a632010-06-16 15:16:11 +03001372{
1373 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1374
Gerd Hoffmannc75fead2012-01-05 15:49:18 +01001375 usb_host_release_port(s);
Shahar Havivib373a632010-06-16 15:16:11 +03001376 if (s->fd != -1) {
Gerd Hoffmannc7662da2011-11-16 12:37:17 +01001377 usb_host_do_reset(s);;
Shahar Havivib373a632010-06-16 15:16:11 +03001378 }
1379}
1380
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001381static int usb_host_initfn(USBDevice *dev)
1382{
1383 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1384
1385 dev->auto_attach = 0;
1386 s->fd = -1;
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001387 s->hub_fd = -1;
1388
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001389 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001390 s->exit.notify = usb_host_exit_notifier;
1391 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001392 usb_host_auto_check(NULL);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001393
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001394 if (s->match.bus_num != 0 && s->match.port != NULL) {
Gerd Hoffmanne6274722011-09-13 11:37:47 +02001395 usb_host_claim_port(s);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001396 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001397 return 0;
bellardbb36d472005-11-05 14:22:28 +00001398}
1399
Gerd Hoffmannd6791572011-08-31 11:44:24 +02001400static const VMStateDescription vmstate_usb_host = {
1401 .name = "usb-host",
1402 .unmigratable = 1,
1403};
1404
Anthony Liguori39bffca2011-12-07 21:34:16 -06001405static Property usb_host_dev_properties[] = {
1406 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1407 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
1408 DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
1409 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1410 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
1411 DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
1412 DEFINE_PROP_END_OF_LIST(),
1413};
1414
Anthony Liguori62aed762011-12-15 14:53:10 -06001415static void usb_host_class_initfn(ObjectClass *klass, void *data)
1416{
Anthony Liguori39bffca2011-12-07 21:34:16 -06001417 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori62aed762011-12-15 14:53:10 -06001418 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
1419
1420 uc->init = usb_host_initfn;
1421 uc->product_desc = "USB Host Device";
1422 uc->handle_packet = usb_generic_handle_packet;
1423 uc->cancel_packet = usb_host_async_cancel;
1424 uc->handle_data = usb_host_handle_data;
1425 uc->handle_control = usb_host_handle_control;
1426 uc->handle_reset = usb_host_handle_reset;
1427 uc->handle_destroy = usb_host_handle_destroy;
Anthony Liguori39bffca2011-12-07 21:34:16 -06001428 dc->vmsd = &vmstate_usb_host;
1429 dc->props = usb_host_dev_properties;
Anthony Liguori62aed762011-12-15 14:53:10 -06001430}
1431
Anthony Liguori39bffca2011-12-07 21:34:16 -06001432static TypeInfo usb_host_dev_info = {
1433 .name = "usb-host",
1434 .parent = TYPE_USB_DEVICE,
1435 .instance_size = sizeof(USBHostDevice),
1436 .class_init = usb_host_class_initfn,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001437};
1438
1439static void usb_host_register_devices(void)
1440{
Anthony Liguori39bffca2011-12-07 21:34:16 -06001441 type_register_static(&usb_host_dev_info);
Anthony Liguoriba024302011-12-08 14:56:53 -06001442 usb_legacy_register("usb-host", "host", usb_host_device_open);
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001443}
1444device_init(usb_host_register_devices)
1445
aliguori4b096fc2008-08-21 19:28:55 +00001446USBDevice *usb_host_device_open(const char *devname)
1447{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001448 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001449 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001450 char *p;
1451
Markus Armbruster556cd092009-12-09 17:07:53 +01001452 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001453
aliguori5d0c5752008-09-14 01:07:41 +00001454 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001455 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001456 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001457 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001458 } else {
1459 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001460 filter.bus_num = strtoul(devname, NULL, 0);
1461 filter.addr = strtoul(p + 1, NULL, 0);
1462 filter.vendor_id = 0;
1463 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001464 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001465 filter.bus_num = 0;
1466 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001467 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001468 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001469 } else {
1470 goto fail;
1471 }
aliguori5d0c5752008-09-14 01:07:41 +00001472 }
1473
Markus Armbruster0745eb12009-11-27 13:05:53 +01001474 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1475 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001476 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1477 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001478 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001479 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001480
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001481fail:
1482 qdev_free(&dev->qdev);
1483 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001484}
aliguori5d0c5752008-09-14 01:07:41 +00001485
1486int usb_host_device_close(const char *devname)
1487{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001488#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001489 char product_name[PRODUCT_NAME_SZ];
1490 int bus_num, addr;
1491 USBHostDevice *s;
1492
David Ahern27911042010-04-24 10:26:22 -06001493 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001494 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001495 }
1496 if (usb_host_find_device(&bus_num, &addr, product_name,
1497 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001498 return -1;
David Ahern27911042010-04-24 10:26:22 -06001499 }
aliguori5d0c5752008-09-14 01:07:41 +00001500 s = hostdev_find(bus_num, addr);
1501 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001502 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001503 return 0;
1504 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001505#endif
aliguori5d0c5752008-09-14 01:07:41 +00001506
1507 return -1;
1508}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001509
aliguori0f431522008-10-07 20:06:37 +00001510/*
1511 * Read sys file-system device file
1512 *
1513 * @line address of buffer to put file contents in
1514 * @line_size size of line
1515 * @device_file path to device file (printf format string)
1516 * @device_name device being opened (inserted into device_file)
1517 *
1518 * @return 0 failed, 1 succeeded ('line' contains data)
1519 */
David Ahern27911042010-04-24 10:26:22 -06001520static int usb_host_read_file(char *line, size_t line_size,
1521 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001522{
1523 FILE *f;
1524 int ret = 0;
1525 char filename[PATH_MAX];
1526
Gerd Hoffmann097db432011-12-16 11:54:11 +01001527 snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name,
blueswir1b4e237a2008-12-28 15:45:20 +00001528 device_file);
aliguori0f431522008-10-07 20:06:37 +00001529 f = fopen(filename, "r");
1530 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001531 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001532 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001533 }
1534
1535 return ret;
1536}
1537
1538/*
1539 * Use /sys/bus/usb/devices/ directory to determine host's USB
1540 * devices.
1541 *
1542 * This code is based on Robert Schiele's original patches posted to
1543 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1544 */
Gerd Hoffmann097db432011-12-16 11:54:11 +01001545static int usb_host_scan(void *opaque, USBScanFunc *func)
aliguori0f431522008-10-07 20:06:37 +00001546{
Blue Swirl660f11b2009-07-31 21:16:51 +00001547 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001548 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001549 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001550 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001551 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001552 char product_name[512];
1553 struct dirent *de;
1554
Gerd Hoffmann097db432011-12-16 11:54:11 +01001555 dir = opendir("/sys/bus/usb/devices");
aliguori0f431522008-10-07 20:06:37 +00001556 if (!dir) {
Gerd Hoffmann097db432011-12-16 11:54:11 +01001557 perror("husb: opendir /sys/bus/usb/devices");
1558 fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n");
aliguori0f431522008-10-07 20:06:37 +00001559 goto the_end;
1560 }
1561
1562 while ((de = readdir(dir))) {
1563 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001564 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1565 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001566 }
aliguori0f431522008-10-07 20:06:37 +00001567
David Ahern27911042010-04-24 10:26:22 -06001568 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001569 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001570 }
1571 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001572 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001573 }
blueswir1b4e237a2008-12-28 15:45:20 +00001574 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001575 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001576 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001577 }
1578 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001579 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001580 }
aliguori0f431522008-10-07 20:06:37 +00001581
David Ahern27911042010-04-24 10:26:22 -06001582 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1583 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001584 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001585 }
1586 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001587 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001588 }
blueswir1b4e237a2008-12-28 15:45:20 +00001589 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001590 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001591 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001592 }
1593 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001594 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001595 }
blueswir1b4e237a2008-12-28 15:45:20 +00001596 if (!usb_host_read_file(line, sizeof(line), "product",
1597 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001598 *product_name = 0;
1599 } else {
David Ahern27911042010-04-24 10:26:22 -06001600 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001601 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001602 }
aliguori0f431522008-10-07 20:06:37 +00001603 pstrcpy(product_name, sizeof(product_name), line);
1604 }
1605
David Ahern27911042010-04-24 10:26:22 -06001606 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001607 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001608 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001609 if (!strcmp(line, "5000\n")) {
1610 speed = USB_SPEED_SUPER;
1611 } else if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001612 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001613 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001614 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001615 } else {
aliguori0f431522008-10-07 20:06:37 +00001616 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001617 }
aliguori0f431522008-10-07 20:06:37 +00001618
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001619 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001620 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001621 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001622 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001623 }
aliguori0f431522008-10-07 20:06:37 +00001624 }
1625 }
1626 the_end:
David Ahern27911042010-04-24 10:26:22 -06001627 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001628 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001629 }
aliguori0f431522008-10-07 20:06:37 +00001630 return ret;
1631}
1632
aliguori4b096fc2008-08-21 19:28:55 +00001633static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001634
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001635static int usb_host_auto_scan(void *opaque, int bus_num,
1636 int addr, const char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001637 int class_id, int vendor_id, int product_id,
1638 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001639{
1640 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001641 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001642
1643 /* Ignore hubs */
1644 if (class_id == 9)
1645 return 0;
1646
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001647 QTAILQ_FOREACH(s, &hostdevs, next) {
1648 f = &s->match;
1649
David Ahern27911042010-04-24 10:26:22 -06001650 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001651 continue;
David Ahern27911042010-04-24 10:26:22 -06001652 }
1653 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001654 continue;
David Ahern27911042010-04-24 10:26:22 -06001655 }
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001656 if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
1657 continue;
1658 }
aliguori4b096fc2008-08-21 19:28:55 +00001659
David Ahern27911042010-04-24 10:26:22 -06001660 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001661 continue;
David Ahern27911042010-04-24 10:26:22 -06001662 }
aliguori4b096fc2008-08-21 19:28:55 +00001663
David Ahern27911042010-04-24 10:26:22 -06001664 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001665 continue;
David Ahern27911042010-04-24 10:26:22 -06001666 }
aliguori4b096fc2008-08-21 19:28:55 +00001667 /* We got a match */
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001668 s->seen++;
1669 if (s->errcount >= 3) {
1670 return 0;
1671 }
aliguori4b096fc2008-08-21 19:28:55 +00001672
Markus Armbruster33e66b82009-10-07 01:15:57 +02001673 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001674 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001675 return 0;
David Ahern27911042010-04-24 10:26:22 -06001676 }
malcd0f2c4c2010-02-07 02:03:50 +03001677 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001678
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001679 if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
1680 s->errcount++;
1681 }
Hans de Goede97f86162011-05-31 11:35:24 +02001682 break;
aliguori4b096fc2008-08-21 19:28:55 +00001683 }
1684
1685 return 0;
1686}
1687
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001688static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001689{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001690 struct USBHostDevice *s;
1691 int unconnected = 0;
1692
aliguori4b096fc2008-08-21 19:28:55 +00001693 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001694
1695 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001696 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001697 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001698 }
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001699 if (s->seen == 0) {
1700 s->errcount = 0;
1701 }
1702 s->seen = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001703 }
1704
1705 if (unconnected == 0) {
1706 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001707 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001708 qemu_del_timer(usb_auto_timer);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001709 trace_usb_host_auto_scan_disabled();
David Ahern27911042010-04-24 10:26:22 -06001710 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001711 return;
1712 }
1713
1714 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001715 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001716 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001717 return;
David Ahern27911042010-04-24 10:26:22 -06001718 }
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001719 trace_usb_host_auto_scan_enabled();
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001720 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001721 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001722}
1723
1724/*
aliguori5d0c5752008-09-14 01:07:41 +00001725 * Autoconnect filter
1726 * Format:
1727 * auto:bus:dev[:vid:pid]
1728 * auto:bus.dev[:vid:pid]
1729 *
1730 * bus - bus number (dec, * means any)
1731 * dev - device number (dec, * means any)
1732 * vid - vendor id (hex, * means any)
1733 * pid - product id (hex, * means any)
1734 *
1735 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001736 */
aliguori5d0c5752008-09-14 01:07:41 +00001737static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001738{
aliguori5d0c5752008-09-14 01:07:41 +00001739 enum { BUS, DEV, VID, PID, DONE };
1740 const char *p = spec;
1741 int i;
1742
Markus Armbruster0745eb12009-11-27 13:05:53 +01001743 f->bus_num = 0;
1744 f->addr = 0;
1745 f->vendor_id = 0;
1746 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001747
1748 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001749 p = strpbrk(p, ":.");
1750 if (!p) {
1751 break;
1752 }
aliguori5d0c5752008-09-14 01:07:41 +00001753 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001754
David Ahern27911042010-04-24 10:26:22 -06001755 if (*p == '*') {
1756 continue;
1757 }
aliguori5d0c5752008-09-14 01:07:41 +00001758 switch(i) {
1759 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1760 case DEV: f->addr = strtol(p, NULL, 10); break;
1761 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1762 case PID: f->product_id = strtol(p, NULL, 16); break;
1763 }
aliguori4b096fc2008-08-21 19:28:55 +00001764 }
1765
aliguori5d0c5752008-09-14 01:07:41 +00001766 if (i < DEV) {
1767 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1768 return -1;
1769 }
1770
1771 return 0;
1772}
1773
bellarda594cfb2005-11-06 16:13:29 +00001774/**********************/
1775/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001776
bellarda594cfb2005-11-06 16:13:29 +00001777struct usb_class_info {
1778 int class;
1779 const char *class_name;
1780};
1781
1782static const struct usb_class_info usb_class_info[] = {
1783 { USB_CLASS_AUDIO, "Audio"},
1784 { USB_CLASS_COMM, "Communication"},
1785 { USB_CLASS_HID, "HID"},
1786 { USB_CLASS_HUB, "Hub" },
1787 { USB_CLASS_PHYSICAL, "Physical" },
1788 { USB_CLASS_PRINTER, "Printer" },
1789 { USB_CLASS_MASS_STORAGE, "Storage" },
1790 { USB_CLASS_CDC_DATA, "Data" },
1791 { USB_CLASS_APP_SPEC, "Application Specific" },
1792 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1793 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001794 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001795 { USB_CLASS_CONTENT_SEC, "Content Security" },
1796 { -1, NULL }
1797};
1798
1799static const char *usb_class_str(uint8_t class)
1800{
1801 const struct usb_class_info *p;
1802 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001803 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001804 break;
David Ahern27911042010-04-24 10:26:22 -06001805 }
bellardbb36d472005-11-05 14:22:28 +00001806 }
bellarda594cfb2005-11-06 16:13:29 +00001807 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001808}
1809
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001810static void usb_info_device(Monitor *mon, int bus_num,
1811 int addr, const char *port,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001812 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00001813 const char *product_name,
1814 int speed)
bellardbb36d472005-11-05 14:22:28 +00001815{
bellarda594cfb2005-11-06 16:13:29 +00001816 const char *class_str, *speed_str;
1817
1818 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001819 case USB_SPEED_LOW:
1820 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001821 break;
ths5fafdf22007-09-16 21:08:06 +00001822 case USB_SPEED_FULL:
1823 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001824 break;
ths5fafdf22007-09-16 21:08:06 +00001825 case USB_SPEED_HIGH:
1826 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001827 break;
Hans de Goedef264cfb2011-05-31 11:35:19 +02001828 case USB_SPEED_SUPER:
1829 speed_str = "5000";
1830 break;
bellarda594cfb2005-11-06 16:13:29 +00001831 default:
ths5fafdf22007-09-16 21:08:06 +00001832 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001833 break;
bellardbb36d472005-11-05 14:22:28 +00001834 }
bellarda594cfb2005-11-06 16:13:29 +00001835
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001836 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
1837 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00001838 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001839 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001840 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001841 } else {
aliguori376253e2009-03-05 23:01:23 +00001842 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001843 }
aliguori376253e2009-03-05 23:01:23 +00001844 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001845 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001846 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001847 }
aliguori376253e2009-03-05 23:01:23 +00001848 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001849}
1850
ths5fafdf22007-09-16 21:08:06 +00001851static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001852 const char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001853 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001854 const char *product_name,
1855 int speed)
1856{
Blue Swirl179da8a2009-09-07 19:00:18 +00001857 Monitor *mon = opaque;
1858
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001859 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001860 product_name, speed);
1861 return 0;
1862}
1863
aliguoriac4ffb52008-09-22 15:04:31 +00001864static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001865{
David Ahern27911042010-04-24 10:26:22 -06001866 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001867 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001868 } else {
1869 snprintf(str, size, "%d", val);
1870 }
aliguori5d0c5752008-09-14 01:07:41 +00001871}
1872
aliguoriac4ffb52008-09-22 15:04:31 +00001873static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001874{
David Ahern27911042010-04-24 10:26:22 -06001875 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001876 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001877 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001878 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06001879 }
aliguori5d0c5752008-09-14 01:07:41 +00001880}
1881
aliguori376253e2009-03-05 23:01:23 +00001882void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00001883{
aliguori5d0c5752008-09-14 01:07:41 +00001884 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001885 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00001886
Blue Swirl179da8a2009-09-07 19:00:18 +00001887 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00001888
David Ahern27911042010-04-24 10:26:22 -06001889 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001890 return;
David Ahern27911042010-04-24 10:26:22 -06001891 }
1892
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001893 monitor_printf(mon, " Auto filters:\n");
1894 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00001895 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001896 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00001897 dec2str(f->bus_num, bus, sizeof(bus));
1898 dec2str(f->addr, addr, sizeof(addr));
1899 hex2str(f->vendor_id, vid, sizeof(vid));
1900 hex2str(f->product_id, pid, sizeof(pid));
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001901 monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
1902 bus, addr, f->port ? f->port : "*", vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00001903 }
bellardbb36d472005-11-05 14:22:28 +00001904}