blob: 7d4d1d7bcf9ad8f70239df63fb47eaa00bb6d612 [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
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;
Gerd Hoffmann9516bb42011-08-24 13:34:17 +0200118 int hub_fd;
aliguori64838172008-08-21 19:31:10 +0000119
Hans de Goedef8ddbfb2011-05-31 11:35:26 +0200120 uint8_t descr[8192];
aliguori64838172008-08-21 19:31:10 +0000121 int descr_len;
122 int configuration;
aliguori446ab122008-09-14 01:06:09 +0000123 int ninterfaces;
aliguori24772c12008-08-21 19:31:52 +0000124 int closing;
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200125 uint32_t iso_urb_count;
Shahar Havivib373a632010-06-16 15:16:11 +0300126 Notifier exit;
aliguori64838172008-08-21 19:31:10 +0000127
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200128 struct endp_data ep_in[MAX_ENDPOINTS];
129 struct endp_data ep_out[MAX_ENDPOINTS];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200130 QLIST_HEAD(, AsyncURB) aurbs;
aliguori4b096fc2008-08-21 19:28:55 +0000131
aliguori4b096fc2008-08-21 19:28:55 +0000132 /* Host side address */
133 int bus_num;
134 int addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200135 char port[MAX_PORTLEN];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100136 struct USBAutoFilter match;
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +0200137 int seen, errcount;
aliguori4b096fc2008-08-21 19:28:55 +0000138
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100139 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000140} USBHostDevice;
141
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100142static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
143
144static int usb_host_close(USBHostDevice *dev);
145static int parse_filter(const char *spec, struct USBAutoFilter *f);
146static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100147static int usb_host_read_file(char *line, size_t line_size,
148 const char *device_file, const char *device_name);
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200149static int usb_linux_update_endp_table(USBHostDevice *s);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100150
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200151static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200152{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200153 struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
154 assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
155 assert(ep > 0 && ep <= MAX_ENDPOINTS);
156 return eps + ep - 1;
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200157}
158
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200159static int is_isoc(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000160{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200161 return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
aliguori64838172008-08-21 19:31:10 +0000162}
163
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200164static int is_valid(USBHostDevice *s, int pid, int ep)
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100165{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200166 return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100167}
168
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200169static int is_halted(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000170{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200171 return get_endp(s, pid, ep)->halted;
aliguori64838172008-08-21 19:31:10 +0000172}
173
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200174static void clear_halt(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000175{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200176 trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200177 get_endp(s, pid, ep)->halted = 0;
aliguori64838172008-08-21 19:31:10 +0000178}
179
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200180static void set_halt(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000181{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200182 if (ep != 0) {
183 trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
184 get_endp(s, pid, ep)->halted = 1;
185 }
aliguori64838172008-08-21 19:31:10 +0000186}
187
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200188static int is_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100189{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200190 return get_endp(s, pid, ep)->iso_started;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100191}
192
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200193static void clear_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100194{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200195 trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200196 get_endp(s, pid, ep)->iso_started = 0;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100197}
198
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200199static void set_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100200{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200201 struct endp_data *e = get_endp(s, pid, ep);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200202
203 trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200204 if (!e->iso_started) {
205 e->iso_started = 1;
206 e->inflight = 0;
207 }
208}
209
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200210static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
Gerd Hoffmann82887262011-06-10 14:00:24 +0200211{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200212 struct endp_data *e = get_endp(s, pid, ep);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200213
214 e->inflight += value;
215 return e->inflight;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100216}
217
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200218static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
Hans de Goede060dc842010-11-26 11:41:08 +0100219{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200220 get_endp(s, pid, ep)->iso_urb = iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100221}
222
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200223static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100224{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200225 return get_endp(s, pid, ep)->iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100226}
227
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200228static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
Hans de Goede060dc842010-11-26 11:41:08 +0100229{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200230 get_endp(s, pid, ep)->iso_urb_idx = i;
Hans de Goede060dc842010-11-26 11:41:08 +0100231}
232
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200233static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100234{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200235 return get_endp(s, pid, ep)->iso_urb_idx;
Hans de Goede060dc842010-11-26 11:41:08 +0100236}
237
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200238static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100239{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200240 get_endp(s, pid, ep)->iso_buffer_used = i;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100241}
242
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200243static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100244{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200245 return get_endp(s, pid, ep)->iso_buffer_used;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100246}
247
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200248static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
249 uint8_t *descriptor)
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200250{
251 int raw = descriptor[4] + (descriptor[5] << 8);
252 int size, microframes;
253
254 size = raw & 0x7ff;
255 switch ((raw >> 11) & 3) {
256 case 1: microframes = 2; break;
257 case 2: microframes = 3; break;
258 default: microframes = 1; break;
259 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200260 get_endp(s, pid, ep)->max_packet_size = size * microframes;
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200261}
262
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200263static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100264{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200265 return get_endp(s, pid, ep)->max_packet_size;
Hans de Goede060dc842010-11-26 11:41:08 +0100266}
267
David Ahern27911042010-04-24 10:26:22 -0600268/*
aliguori64838172008-08-21 19:31:10 +0000269 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100270 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600271 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000272 */
Hans de Goede060dc842010-11-26 11:41:08 +0100273struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000274{
aliguori64838172008-08-21 19:31:10 +0000275 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100276 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200277 USBHostDevice *hdev;
278 QLIST_ENTRY(AsyncURB) next;
aliguori64838172008-08-21 19:31:10 +0000279
Hans de Goede060dc842010-11-26 11:41:08 +0100280 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000281 USBPacket *packet;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200282 int more; /* large transfer, more urbs follow */
Hans de Goede060dc842010-11-26 11:41:08 +0100283
284 /* For buffered iso handling */
285 int iso_frame_idx; /* -1 means in flight */
286};
aliguori64838172008-08-21 19:31:10 +0000287
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200288static AsyncURB *async_alloc(USBHostDevice *s)
aliguori64838172008-08-21 19:31:10 +0000289{
Anthony Liguori7267c092011-08-20 22:09:37 -0500290 AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200291 aurb->hdev = s;
292 QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
293 return aurb;
balrogb9dc0332007-10-04 22:47:34 +0000294}
295
aliguori64838172008-08-21 19:31:10 +0000296static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000297{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200298 QLIST_REMOVE(aurb, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500299 g_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000300}
balrogb9dc0332007-10-04 22:47:34 +0000301
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200302static void do_disconnect(USBHostDevice *s)
303{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200304 usb_host_close(s);
305 usb_host_auto_check(NULL);
306}
307
aliguori64838172008-08-21 19:31:10 +0000308static void async_complete(void *opaque)
309{
310 USBHostDevice *s = opaque;
311 AsyncURB *aurb;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200312 int urbs = 0;
balrogb9dc0332007-10-04 22:47:34 +0000313
aliguori64838172008-08-21 19:31:10 +0000314 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600315 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000316
David Ahern27911042010-04-24 10:26:22 -0600317 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000318 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600319 if (errno == EAGAIN) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200320 if (urbs > 2) {
321 fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);
322 }
aliguori64838172008-08-21 19:31:10 +0000323 return;
David Ahern27911042010-04-24 10:26:22 -0600324 }
Gerd Hoffmann40197c32011-08-22 14:18:21 +0200325 if (errno == ENODEV) {
326 if (!s->closing) {
327 trace_usb_host_disconnect(s->bus_num, s->addr);
328 do_disconnect(s);
329 }
aliguori64838172008-08-21 19:31:10 +0000330 return;
331 }
332
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200333 perror("USBDEVFS_REAPURBNDELAY");
aliguori64838172008-08-21 19:31:10 +0000334 return;
balrogb9dc0332007-10-04 22:47:34 +0000335 }
aliguori64838172008-08-21 19:31:10 +0000336
David Ahern27911042010-04-24 10:26:22 -0600337 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000338 aurb, aurb->urb.status, aurb->urb.actual_length);
339
Hans de Goede060dc842010-11-26 11:41:08 +0100340 /* If this is a buffered iso urb mark it as complete and don't do
341 anything else (it is handled further in usb_host_handle_iso_data) */
342 if (aurb->iso_frame_idx == -1) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200343 int inflight;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200344 int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
345 USB_TOKEN_IN : USB_TOKEN_OUT;
346 int ep = aurb->urb.endpoint & 0xf;
Hans de Goede060dc842010-11-26 11:41:08 +0100347 if (aurb->urb.status == -EPIPE) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200348 set_halt(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100349 }
350 aurb->iso_frame_idx = 0;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200351 urbs++;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200352 inflight = change_iso_inflight(s, pid, ep, -1);
353 if (inflight == 0 && is_iso_started(s, pid, ep)) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200354 fprintf(stderr, "husb: out of buffers for iso stream\n");
355 }
Hans de Goede060dc842010-11-26 11:41:08 +0100356 continue;
357 }
358
359 p = aurb->packet;
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200360 trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
361 aurb->urb.actual_length, aurb->more);
Hans de Goede060dc842010-11-26 11:41:08 +0100362
David Ahern27911042010-04-24 10:26:22 -0600363 if (p) {
aliguori64838172008-08-21 19:31:10 +0000364 switch (aurb->urb.status) {
365 case 0:
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200366 p->result += aurb->urb.actual_length;
aliguori64838172008-08-21 19:31:10 +0000367 break;
368
369 case -EPIPE:
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200370 set_halt(s, p->pid, p->devep);
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200371 p->result = USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600372 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200373
aliguori64838172008-08-21 19:31:10 +0000374 default:
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200375 p->result = USB_RET_NAK;
aliguori64838172008-08-21 19:31:10 +0000376 break;
377 }
378
Hans de Goede50b79632011-02-02 17:36:29 +0100379 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200380 trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
Hans de Goede50b79632011-02-02 17:36:29 +0100381 usb_generic_async_ctrl_complete(&s->dev, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200382 } else if (!aurb->more) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200383 trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
Hans de Goede50b79632011-02-02 17:36:29 +0100384 usb_packet_complete(&s->dev, p);
385 }
David Ahern27911042010-04-24 10:26:22 -0600386 }
aliguori64838172008-08-21 19:31:10 +0000387
388 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000389 }
balrogb9dc0332007-10-04 22:47:34 +0000390}
391
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200392static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
balrogb9dc0332007-10-04 22:47:34 +0000393{
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200394 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200395 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000396
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200397 QLIST_FOREACH(aurb, &s->aurbs, next) {
398 if (p != aurb->packet) {
399 continue;
400 }
balrogb9dc0332007-10-04 22:47:34 +0000401
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200402 DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
aliguori64838172008-08-21 19:31:10 +0000403
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200404 /* Mark it as dead (see async_complete above) */
405 aurb->packet = NULL;
406
407 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
408 if (r < 0) {
409 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
410 }
balrogb9dc0332007-10-04 22:47:34 +0000411 }
balrogb9dc0332007-10-04 22:47:34 +0000412}
413
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200414static int usb_host_claim_port(USBHostDevice *s)
415{
416#ifdef USBDEVFS_CLAIM_PORT
417 char *h, hub_name[64], line[1024];
418 int hub_addr, portnr, ret;
419
420 snprintf(hub_name, sizeof(hub_name), "%d-%s",
421 s->match.bus_num, s->match.port);
422
423 /* try strip off last ".$portnr" to get hub */
424 h = strrchr(hub_name, '.');
425 if (h != NULL) {
426 portnr = atoi(h+1);
427 *h = '\0';
428 } else {
429 /* no dot in there -> it is the root hub */
430 snprintf(hub_name, sizeof(hub_name), "usb%d",
431 s->match.bus_num);
432 portnr = atoi(s->match.port);
433 }
434
435 if (!usb_host_read_file(line, sizeof(line), "devnum",
436 hub_name)) {
437 return -1;
438 }
439 if (sscanf(line, "%d", &hub_addr) != 1) {
440 return -1;
441 }
442
443 if (!usb_host_device_path) {
444 return -1;
445 }
446 snprintf(line, sizeof(line), "%s/%03d/%03d",
447 usb_host_device_path, s->match.bus_num, hub_addr);
448 s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
449 if (s->hub_fd < 0) {
450 return -1;
451 }
452
453 ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
454 if (ret < 0) {
455 close(s->hub_fd);
456 s->hub_fd = -1;
457 return -1;
458 }
459
460 trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
461 return 0;
462#else
463 return -1;
464#endif
465}
466
467static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
468{
469 /* earlier Linux 2.4 do not support that */
470#ifdef USBDEVFS_DISCONNECT
471 struct usbdevfs_ioctl ctrl;
472 int ret, interface;
473
474 for (interface = 0; interface < nb_interfaces; interface++) {
475 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
476 ctrl.ifno = interface;
477 ctrl.data = 0;
478 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
479 if (ret < 0 && errno != ENODATA) {
480 perror("USBDEVFS_DISCONNECT");
481 return -1;
482 }
483 }
484#endif
485 return 0;
486}
487
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200488static int usb_linux_get_num_interfaces(USBHostDevice *s)
489{
490 char device_name[64], line[1024];
491 int num_interfaces = 0;
492
493 if (usb_fs_type != USB_FS_SYS) {
494 return -1;
495 }
496
497 sprintf(device_name, "%d-%s", s->bus_num, s->port);
498 if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
499 device_name)) {
500 return -1;
501 }
502 if (sscanf(line, "%d", &num_interfaces) != 1) {
503 return -1;
504 }
505 return num_interfaces;
506}
507
aliguori446ab122008-09-14 01:06:09 +0000508static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000509{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200510 const char *op = NULL;
balrogb9dc0332007-10-04 22:47:34 +0000511 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000512 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000513 int ret, i;
514
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200515 if (configuration == 0) { /* address state - ignore */
516 dev->ninterfaces = 0;
517 dev->configuration = 0;
balrogb9dc0332007-10-04 22:47:34 +0000518 return 1;
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200519 }
balrogb9dc0332007-10-04 22:47:34 +0000520
malcd0f2c4c2010-02-07 02:03:50 +0300521 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000522
balrogb9dc0332007-10-04 22:47:34 +0000523 i = 0;
524 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600525 if (dev_descr_len > dev->descr_len) {
Hans de Goede61c11172011-05-31 11:35:20 +0200526 fprintf(stderr, "husb: update iface failed. descr too short\n");
527 return 0;
David Ahern27911042010-04-24 10:26:22 -0600528 }
balrogb9dc0332007-10-04 22:47:34 +0000529
530 i += dev_descr_len;
531 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600532 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
533 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000534 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000535
balrogb9dc0332007-10-04 22:47:34 +0000536 if (dev->descr[i+1] != USB_DT_CONFIG) {
537 i += dev->descr[i];
538 continue;
539 }
540 config_descr_len = dev->descr[i];
541
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200542 DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000543
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200544 if (configuration == dev->descr[i + 5]) {
aliguori446ab122008-09-14 01:06:09 +0000545 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000546 break;
aliguori446ab122008-09-14 01:06:09 +0000547 }
balrogb9dc0332007-10-04 22:47:34 +0000548
549 i += config_descr_len;
550 }
551
552 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600553 fprintf(stderr,
554 "husb: update iface failed. no matching configuration\n");
Hans de Goede61c11172011-05-31 11:35:20 +0200555 return 0;
balrogb9dc0332007-10-04 22:47:34 +0000556 }
557 nb_interfaces = dev->descr[i + 4];
558
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200559 if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
560 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000561 }
balrogb9dc0332007-10-04 22:47:34 +0000562
563 /* XXX: only grab if all interfaces are free */
564 for (interface = 0; interface < nb_interfaces; interface++) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200565 op = "USBDEVFS_CLAIMINTERFACE";
balrogb9dc0332007-10-04 22:47:34 +0000566 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
567 if (ret < 0) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200568 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000569 }
570 }
571
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200572 trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
573 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000574
aliguori446ab122008-09-14 01:06:09 +0000575 dev->ninterfaces = nb_interfaces;
576 dev->configuration = configuration;
577 return 1;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200578
579fail:
580 if (errno == ENODEV) {
581 do_disconnect(dev);
582 }
583 perror(op);
584 return 0;
aliguori446ab122008-09-14 01:06:09 +0000585}
586
587static int usb_host_release_interfaces(USBHostDevice *s)
588{
589 int ret, i;
590
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200591 trace_usb_host_release_interfaces(s->bus_num, s->addr);
aliguori446ab122008-09-14 01:06:09 +0000592
593 for (i = 0; i < s->ninterfaces; i++) {
594 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
595 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200596 perror("USBDEVFS_RELEASEINTERFACE");
aliguori446ab122008-09-14 01:06:09 +0000597 return 0;
598 }
599 }
balrogb9dc0332007-10-04 22:47:34 +0000600 return 1;
601}
602
bellard059809e2006-07-19 18:06:15 +0000603static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000604{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100605 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000606
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200607 trace_usb_host_reset(s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000608
bellardbb36d472005-11-05 14:22:28 +0000609 ioctl(s->fd, USBDEVFS_RESET);
aliguori446ab122008-09-14 01:06:09 +0000610
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200611 usb_host_claim_interfaces(s, 0);
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200612 usb_linux_update_endp_table(s);
ths5fafdf22007-09-16 21:08:06 +0000613}
bellardbb36d472005-11-05 14:22:28 +0000614
bellard059809e2006-07-19 18:06:15 +0000615static void usb_host_handle_destroy(USBDevice *dev)
616{
617 USBHostDevice *s = (USBHostDevice *)dev;
618
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100619 usb_host_close(s);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +0200620 if (s->hub_fd != -1) {
621 close(s->hub_fd);
622 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100623 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300624 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000625}
626
Hans de Goede060dc842010-11-26 11:41:08 +0100627/* iso data is special, we need to keep enough urbs in flight to make sure
628 that the controller never runs out of them, otherwise the device will
629 likely suffer a buffer underrun / overrun. */
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200630static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100631{
632 AsyncURB *aurb;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200633 int i, j, len = get_max_packet_size(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100634
Anthony Liguori7267c092011-08-20 22:09:37 -0500635 aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200636 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100637 aurb[i].urb.endpoint = ep;
638 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
Anthony Liguori7267c092011-08-20 22:09:37 -0500639 aurb[i].urb.buffer = g_malloc(aurb[i].urb.buffer_length);
Hans de Goede060dc842010-11-26 11:41:08 +0100640 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
641 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
642 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
643 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
644 aurb[i].urb.iso_frame_desc[j].length = len;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200645 if (pid == USB_TOKEN_IN) {
Hans de Goede060dc842010-11-26 11:41:08 +0100646 aurb[i].urb.endpoint |= 0x80;
647 /* Mark as fully consumed (idle) */
648 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
649 }
650 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200651 set_iso_urb(s, pid, ep, aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100652
653 return aurb;
654}
655
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200656static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100657{
658 AsyncURB *aurb;
659 int i, ret, killed = 0, free = 1;
660
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200661 aurb = get_iso_urb(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100662 if (!aurb) {
663 return;
664 }
665
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200666 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100667 /* in flight? */
668 if (aurb[i].iso_frame_idx == -1) {
669 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
670 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200671 perror("USBDEVFS_DISCARDURB");
Hans de Goede060dc842010-11-26 11:41:08 +0100672 free = 0;
673 continue;
674 }
675 killed++;
676 }
677 }
678
679 /* Make sure any urbs we've killed are reaped before we free them */
680 if (killed) {
681 async_complete(s);
682 }
683
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200684 for (i = 0; i < s->iso_urb_count; i++) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500685 g_free(aurb[i].urb.buffer);
Hans de Goede060dc842010-11-26 11:41:08 +0100686 }
687
688 if (free)
Anthony Liguori7267c092011-08-20 22:09:37 -0500689 g_free(aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100690 else
691 printf("husb: leaking iso urbs because of discard failure\n");
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200692 set_iso_urb(s, pid, ep, NULL);
693 set_iso_urb_idx(s, pid, ep, 0);
694 clear_iso_started(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100695}
696
697static int urb_status_to_usb_ret(int status)
698{
699 switch (status) {
700 case -EPIPE:
701 return USB_RET_STALL;
702 default:
703 return USB_RET_NAK;
704 }
705}
706
Hans de Goedebb6d5492010-11-26 19:11:03 +0100707static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100708{
709 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100710 int i, j, ret, max_packet_size, offset, len = 0;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200711 uint8_t *buf;
Hans de Goede975f2992010-11-26 14:59:35 +0100712
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200713 max_packet_size = get_max_packet_size(s, p->pid, p->devep);
Hans de Goede975f2992010-11-26 14:59:35 +0100714 if (max_packet_size == 0)
715 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100716
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200717 aurb = get_iso_urb(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100718 if (!aurb) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200719 aurb = usb_host_alloc_iso(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100720 }
721
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200722 i = get_iso_urb_idx(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100723 j = aurb[i].iso_frame_idx;
724 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100725 if (in) {
726 /* Check urb status */
727 if (aurb[i].urb.status) {
728 len = urb_status_to_usb_ret(aurb[i].urb.status);
729 /* Move to the next urb */
730 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
731 /* Check frame status */
732 } else if (aurb[i].urb.iso_frame_desc[j].status) {
733 len = urb_status_to_usb_ret(
734 aurb[i].urb.iso_frame_desc[j].status);
735 /* Check the frame fits */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200736 } else if (aurb[i].urb.iso_frame_desc[j].actual_length
737 > p->iov.size) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100738 printf("husb: received iso data is larger then packet\n");
739 len = USB_RET_NAK;
740 /* All good copy data over */
741 } else {
742 len = aurb[i].urb.iso_frame_desc[j].actual_length;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200743 buf = aurb[i].urb.buffer +
744 j * aurb[i].urb.iso_frame_desc[0].length;
745 usb_packet_copy(p, buf, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100746 }
Hans de Goede060dc842010-11-26 11:41:08 +0100747 } else {
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200748 len = p->iov.size;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200749 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100750
751 /* Check the frame fits */
752 if (len > max_packet_size) {
753 printf("husb: send iso data is larger then max packet size\n");
754 return USB_RET_NAK;
755 }
756
757 /* All good copy data over */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200758 usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100759 aurb[i].urb.iso_frame_desc[j].length = len;
760 offset += len;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200761 set_iso_buffer_used(s, p->pid, p->devep, offset);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100762
763 /* Start the stream once we have buffered enough data */
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200764 if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
765 set_iso_started(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100766 }
Hans de Goede060dc842010-11-26 11:41:08 +0100767 }
768 aurb[i].iso_frame_idx++;
769 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200770 i = (i + 1) % s->iso_urb_count;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200771 set_iso_urb_idx(s, p->pid, p->devep, i);
Hans de Goede060dc842010-11-26 11:41:08 +0100772 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100773 } else {
774 if (in) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200775 set_iso_started(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100776 } else {
777 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
778 }
Hans de Goede060dc842010-11-26 11:41:08 +0100779 }
780
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200781 if (is_iso_started(s, p->pid, p->devep)) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100782 /* (Re)-submit all fully consumed / filled urbs */
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200783 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100784 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
785 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
786 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200787 perror("USBDEVFS_SUBMITURB");
Hans de Goedebb6d5492010-11-26 19:11:03 +0100788 if (!in || len == 0) {
789 switch(errno) {
790 case ETIMEDOUT:
791 len = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200792 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100793 case EPIPE:
794 default:
795 len = USB_RET_STALL;
796 }
Hans de Goede060dc842010-11-26 11:41:08 +0100797 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100798 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100799 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100800 aurb[i].iso_frame_idx = -1;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200801 change_iso_inflight(s, p->pid, p->devep, 1);
Hans de Goede060dc842010-11-26 11:41:08 +0100802 }
Hans de Goede060dc842010-11-26 11:41:08 +0100803 }
804 }
805
806 return len;
807}
808
Hans de Goede50b79632011-02-02 17:36:29 +0100809static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000810{
Hans de Goede50b79632011-02-02 17:36:29 +0100811 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000812 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000813 AsyncURB *aurb;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200814 int ret, rem, prem, v;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200815 uint8_t *pbuf;
Hans de Goede060dc842010-11-26 11:41:08 +0100816 uint8_t ep;
817
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200818 trace_usb_host_req_data(s->bus_num, s->addr,
819 p->pid == USB_TOKEN_IN,
820 p->devep, p->iov.size);
821
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200822 if (!is_valid(s, p->pid, p->devep)) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200823 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100824 return USB_RET_NAK;
825 }
826
Hans de Goede060dc842010-11-26 11:41:08 +0100827 if (p->pid == USB_TOKEN_IN) {
828 ep = p->devep | 0x80;
829 } else {
830 ep = p->devep;
831 }
832
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200833 if (is_halted(s, p->pid, p->devep)) {
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200834 unsigned int arg = ep;
835 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
Hans de Goede060dc842010-11-26 11:41:08 +0100836 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200837 perror("USBDEVFS_CLEAR_HALT");
838 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Hans de Goede060dc842010-11-26 11:41:08 +0100839 return USB_RET_NAK;
840 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200841 clear_halt(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100842 }
843
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200844 if (is_isoc(s, p->pid, p->devep)) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100845 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
846 }
bellardbb36d472005-11-05 14:22:28 +0000847
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200848 v = 0;
849 prem = p->iov.iov[v].iov_len;
850 pbuf = p->iov.iov[v].iov_base;
851 rem = p->iov.size;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200852 while (rem) {
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200853 if (prem == 0) {
854 v++;
855 assert(v < p->iov.niov);
856 prem = p->iov.iov[v].iov_len;
857 pbuf = p->iov.iov[v].iov_base;
858 assert(prem <= rem);
859 }
Gerd Hoffmann71138532011-05-16 10:21:51 +0200860 aurb = async_alloc(s);
861 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000862
Gerd Hoffmann71138532011-05-16 10:21:51 +0200863 urb = &aurb->urb;
864 urb->endpoint = ep;
865 urb->type = USBDEVFS_URB_TYPE_BULK;
866 urb->usercontext = s;
867 urb->buffer = pbuf;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200868 urb->buffer_length = prem;
aliguori64838172008-08-21 19:31:10 +0000869
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200870 if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
Gerd Hoffmann71138532011-05-16 10:21:51 +0200871 urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200872 }
873 pbuf += urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200874 prem -= urb->buffer_length;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200875 rem -= urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200876 if (rem) {
877 aurb->more = 1;
878 }
aliguori64838172008-08-21 19:31:10 +0000879
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200880 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
881 urb->buffer_length, aurb->more);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200882 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
aliguori64838172008-08-21 19:31:10 +0000883
Gerd Hoffmann71138532011-05-16 10:21:51 +0200884 DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
885 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
aliguori64838172008-08-21 19:31:10 +0000886
Gerd Hoffmann71138532011-05-16 10:21:51 +0200887 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200888 perror("USBDEVFS_SUBMITURB");
Gerd Hoffmann71138532011-05-16 10:21:51 +0200889 async_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000890
Gerd Hoffmann71138532011-05-16 10:21:51 +0200891 switch(errno) {
892 case ETIMEDOUT:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200893 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200894 return USB_RET_NAK;
895 case EPIPE:
896 default:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200897 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200898 return USB_RET_STALL;
899 }
balrogb9dc0332007-10-04 22:47:34 +0000900 }
901 }
aliguori64838172008-08-21 19:31:10 +0000902
balrogb9dc0332007-10-04 22:47:34 +0000903 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000904}
905
aliguori446ab122008-09-14 01:06:09 +0000906static int ctrl_error(void)
907{
David Ahern27911042010-04-24 10:26:22 -0600908 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000909 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600910 } else {
aliguori446ab122008-09-14 01:06:09 +0000911 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600912 }
aliguori446ab122008-09-14 01:06:09 +0000913}
914
915static int usb_host_set_address(USBHostDevice *s, int addr)
916{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200917 trace_usb_host_set_address(s->bus_num, s->addr, addr);
aliguori446ab122008-09-14 01:06:09 +0000918 s->dev.addr = addr;
919 return 0;
920}
921
922static int usb_host_set_config(USBHostDevice *s, int config)
923{
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200924 int ret, first = 1;
925
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200926 trace_usb_host_set_config(s->bus_num, s->addr, config);
927
aliguori446ab122008-09-14 01:06:09 +0000928 usb_host_release_interfaces(s);
929
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200930again:
931 ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600932
malcd0f2c4c2010-02-07 02:03:50 +0300933 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600934
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200935 if (ret < 0 && errno == EBUSY && first) {
936 /* happens if usb device is in use by host drivers */
937 int count = usb_linux_get_num_interfaces(s);
938 if (count > 0) {
939 DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
940 usb_host_disconnect_ifaces(s, count);
941 first = 0;
942 goto again;
943 }
944 }
945
David Ahern27911042010-04-24 10:26:22 -0600946 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000947 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600948 }
aliguori446ab122008-09-14 01:06:09 +0000949 usb_host_claim_interfaces(s, config);
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200950 usb_linux_update_endp_table(s);
aliguori446ab122008-09-14 01:06:09 +0000951 return 0;
952}
953
954static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
955{
956 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100957 int i, ret;
958
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200959 trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
960
Hans de Goede3a4854b2010-11-26 15:02:16 +0100961 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200962 if (is_isoc(s, USB_TOKEN_IN, i)) {
963 usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
964 }
965 if (is_isoc(s, USB_TOKEN_OUT, i)) {
966 usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
Hans de Goede060dc842010-11-26 11:41:08 +0100967 }
968 }
aliguori446ab122008-09-14 01:06:09 +0000969
970 si.interface = iface;
971 si.altsetting = alt;
972 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000973
David Ahern27911042010-04-24 10:26:22 -0600974 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
975 iface, alt, ret, errno);
976
977 if (ret < 0) {
978 return ctrl_error();
979 }
aliguori446ab122008-09-14 01:06:09 +0000980 usb_linux_update_endp_table(s);
981 return 0;
982}
983
Hans de Goede50b79632011-02-02 17:36:29 +0100984static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
985 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +0000986{
Hans de Goede50b79632011-02-02 17:36:29 +0100987 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +0000988 struct usbdevfs_urb *urb;
989 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +0100990 int ret;
aliguori446ab122008-09-14 01:06:09 +0000991
David Ahern27911042010-04-24 10:26:22 -0600992 /*
aliguori446ab122008-09-14 01:06:09 +0000993 * Process certain standard device requests.
994 * These are infrequent and are processed synchronously.
995 */
aliguori446ab122008-09-14 01:06:09 +0000996
Hans de Goede50b79632011-02-02 17:36:29 +0100997 /* Note request is (bRequestType << 8) | bRequest */
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200998 trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
aliguori446ab122008-09-14 01:06:09 +0000999
Hans de Goede50b79632011-02-02 17:36:29 +01001000 switch (request) {
1001 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
1002 return usb_host_set_address(s, value);
aliguori446ab122008-09-14 01:06:09 +00001003
Hans de Goede50b79632011-02-02 17:36:29 +01001004 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
1005 return usb_host_set_config(s, value & 0xff);
aliguori446ab122008-09-14 01:06:09 +00001006
Hans de Goede50b79632011-02-02 17:36:29 +01001007 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
aliguori446ab122008-09-14 01:06:09 +00001008 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -06001009 }
aliguori446ab122008-09-14 01:06:09 +00001010
1011 /* The rest are asynchronous */
1012
Hans de Goede50b79632011-02-02 17:36:29 +01001013 if (length > sizeof(dev->data_buf)) {
1014 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
1015 length, sizeof(dev->data_buf));
malcb2e3b6e2009-09-12 03:18:18 +04001016 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -04001017 }
1018
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +02001019 aurb = async_alloc(s);
aliguori446ab122008-09-14 01:06:09 +00001020 aurb->packet = p;
1021
David Ahern27911042010-04-24 10:26:22 -06001022 /*
aliguori446ab122008-09-14 01:06:09 +00001023 * Setup ctrl transfer.
1024 *
Brad Hardsa0102082011-04-13 19:45:33 +10001025 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +00001026 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -06001027 */
aliguori446ab122008-09-14 01:06:09 +00001028 urb = &aurb->urb;
1029
1030 urb->type = USBDEVFS_URB_TYPE_CONTROL;
1031 urb->endpoint = p->devep;
1032
Hans de Goede50b79632011-02-02 17:36:29 +01001033 urb->buffer = &dev->setup_buf;
1034 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +00001035
1036 urb->usercontext = s;
1037
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001038 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
1039 urb->buffer_length, aurb->more);
aliguori446ab122008-09-14 01:06:09 +00001040 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
1041
malcd0f2c4c2010-02-07 02:03:50 +03001042 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +00001043
1044 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +03001045 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +00001046 async_free(aurb);
1047
1048 switch(errno) {
1049 case ETIMEDOUT:
1050 return USB_RET_NAK;
1051 case EPIPE:
1052 default:
1053 return USB_RET_STALL;
1054 }
1055 }
1056
aliguori446ab122008-09-14 01:06:09 +00001057 return USB_RET_ASYNC;
1058}
1059
Hans de Goedeed3a3282010-11-24 12:50:00 +01001060static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
1061 uint8_t configuration, uint8_t interface)
1062{
1063 uint8_t alt_setting;
1064 struct usb_ctrltransfer ct;
1065 int ret;
1066
Hans de Goedec43831f2010-11-24 12:57:59 +01001067 if (usb_fs_type == USB_FS_SYS) {
1068 char device_name[64], line[1024];
1069 int alt_setting;
1070
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001071 sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
Hans de Goedec43831f2010-11-24 12:57:59 +01001072 (int)configuration, (int)interface);
1073
1074 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
1075 device_name)) {
1076 goto usbdevfs;
1077 }
1078 if (sscanf(line, "%d", &alt_setting) != 1) {
1079 goto usbdevfs;
1080 }
1081 return alt_setting;
1082 }
1083
1084usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +01001085 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
1086 ct.bRequest = USB_REQ_GET_INTERFACE;
1087 ct.wValue = 0;
1088 ct.wIndex = interface;
1089 ct.wLength = 1;
1090 ct.data = &alt_setting;
1091 ct.timeout = 50;
1092 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
1093 if (ret < 0) {
1094 /* Assume alt 0 on error */
1095 return 0;
1096 }
1097
1098 return alt_setting;
1099}
1100
Hans de Goede71d71bb2010-11-10 10:06:24 +01001101/* returns 1 on problem encountered or 0 for success */
1102static int usb_linux_update_endp_table(USBHostDevice *s)
1103{
1104 uint8_t *descriptors;
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001105 uint8_t devep, type, alt_interface;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001106 int interface, length, i, ep, pid;
1107 struct endp_data *epd;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001108
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001109 for (i = 0; i < MAX_ENDPOINTS; i++) {
1110 s->ep_in[i].type = INVALID_EP_TYPE;
1111 s->ep_out[i].type = INVALID_EP_TYPE;
1112 }
Hans de Goedea0b5fec2010-11-26 14:56:17 +01001113
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001114 if (s->configuration == 0) {
1115 /* not configured yet -- leave all endpoints disabled */
1116 return 0;
1117 }
Hans de Goede71d71bb2010-11-10 10:06:24 +01001118
balrogb9dc0332007-10-04 22:47:34 +00001119 /* get the desired configuration, interface, and endpoint descriptors
1120 * from device description */
1121 descriptors = &s->descr[18];
1122 length = s->descr_len - 18;
1123 i = 0;
1124
1125 if (descriptors[i + 1] != USB_DT_CONFIG ||
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001126 descriptors[i + 5] != s->configuration) {
1127 fprintf(stderr, "invalid descriptor data - configuration %d\n",
1128 s->configuration);
balrogb9dc0332007-10-04 22:47:34 +00001129 return 1;
1130 }
1131 i += descriptors[i];
1132
1133 while (i < length) {
1134 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1135 (descriptors[i + 1] == USB_DT_INTERFACE &&
1136 descriptors[i + 4] == 0)) {
1137 i += descriptors[i];
1138 continue;
1139 }
1140
1141 interface = descriptors[i + 2];
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001142 alt_interface = usb_linux_get_alt_setting(s, s->configuration,
1143 interface);
balrogb9dc0332007-10-04 22:47:34 +00001144
1145 /* the current interface descriptor is the active interface
1146 * and has endpoints */
1147 if (descriptors[i + 3] != alt_interface) {
1148 i += descriptors[i];
1149 continue;
1150 }
1151
1152 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001153 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001154 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001155 }
balrogb9dc0332007-10-04 22:47:34 +00001156
1157 if (i >= length)
1158 break;
1159
1160 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001161 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001162 break;
David Ahern27911042010-04-24 10:26:22 -06001163 }
balrogb9dc0332007-10-04 22:47:34 +00001164
1165 devep = descriptors[i + 2];
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001166 pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
1167 ep = devep & 0xf;
1168 if (ep == 0) {
Hans de Goede130314f2011-05-31 11:35:22 +02001169 fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
1170 return 1;
1171 }
1172
balrogb9dc0332007-10-04 22:47:34 +00001173 switch (descriptors[i + 3] & 0x3) {
1174 case 0x00:
1175 type = USBDEVFS_URB_TYPE_CONTROL;
1176 break;
1177 case 0x01:
1178 type = USBDEVFS_URB_TYPE_ISO;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001179 set_max_packet_size(s, pid, ep, descriptors + i);
balrogb9dc0332007-10-04 22:47:34 +00001180 break;
1181 case 0x02:
1182 type = USBDEVFS_URB_TYPE_BULK;
1183 break;
1184 case 0x03:
1185 type = USBDEVFS_URB_TYPE_INTERRUPT;
1186 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -05001187 default:
1188 DPRINTF("usb_host: malformed endpoint type\n");
1189 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +00001190 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001191 epd = get_endp(s, pid, ep);
1192 assert(epd->type == INVALID_EP_TYPE);
1193 epd->type = type;
1194 epd->halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001195
1196 i += descriptors[i];
1197 }
1198 }
1199 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;
bellarda594cfb2005-11-06 16:13:29 +00001243 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001244
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001245 trace_usb_host_open_started(bus_num, addr);
1246
David Ahern27911042010-04-24 10:26:22 -06001247 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001248 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001249 }
aliguori1f3870a2008-08-21 19:27:48 +00001250
aliguori0f431522008-10-07 20:06:37 +00001251 if (!usb_host_device_path) {
1252 perror("husb: USB Host Device Path not set");
1253 goto fail;
1254 }
1255 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001256 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001257 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001258 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001259 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001260 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001261 }
malcd0f2c4c2010-02-07 02:03:50 +03001262 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001263
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001264 dev->bus_num = bus_num;
1265 dev->addr = addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001266 strcpy(dev->port, port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001267 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001268
balrogb9dc0332007-10-04 22:47:34 +00001269 /* read the device description */
1270 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1271 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001272 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001273 goto fail;
1274 }
ths3b46e622007-09-17 08:09:54 +00001275
balrogb9dc0332007-10-04 22:47:34 +00001276#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001277 {
balrogb9dc0332007-10-04 22:47:34 +00001278 int x;
1279 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001280 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001281 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001282 }
balrogb9dc0332007-10-04 22:47:34 +00001283 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001284 }
1285#endif
1286
balrogb9dc0332007-10-04 22:47:34 +00001287
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001288 /* start unconfigured -- we'll wait for the guest to set a configuration */
1289 if (!usb_host_claim_interfaces(dev, 0)) {
balrogb9dc0332007-10-04 22:47:34 +00001290 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001291 }
bellardbb36d472005-11-05 14:22:28 +00001292
balrogb9dc0332007-10-04 22:47:34 +00001293 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001294 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001295 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001296 }
balrogb9dc0332007-10-04 22:47:34 +00001297
Hans de Goede3991c352011-05-31 11:35:18 +02001298 if (speed == -1) {
1299 struct usbdevfs_connectinfo ci;
1300
1301 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1302 if (ret < 0) {
1303 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
1304 goto fail;
1305 }
1306
1307 if (ci.slow) {
1308 speed = USB_SPEED_LOW;
1309 } else {
1310 speed = USB_SPEED_HIGH;
1311 }
David Ahern27911042010-04-24 10:26:22 -06001312 }
Hans de Goede3991c352011-05-31 11:35:18 +02001313 dev->dev.speed = speed;
Hans de Goedeba3f9bf2011-05-27 14:27:18 +02001314 dev->dev.speedmask = (1 << speed);
Hans de Goedee4b17762011-05-30 11:40:45 +02001315 if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
1316 dev->dev.speedmask |= USB_SPEED_MASK_FULL;
1317 }
Hans de Goede3991c352011-05-31 11:35:18 +02001318
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001319 trace_usb_host_open_success(bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001320
David Ahern27911042010-04-24 10:26:22 -06001321 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001322 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001323 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001324 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001325 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001326 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001327 }
bellard1f6e24e2006-06-26 21:00:51 +00001328
Hans de Goedefa19bf82011-05-27 19:05:15 +02001329 ret = usb_device_attach(&dev->dev);
1330 if (ret) {
1331 goto fail;
1332 }
1333
aliguori64838172008-08-21 19:31:10 +00001334 /* USB devio uses 'write' flag to check for async completions */
1335 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001336
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001337 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001338
balrogb9dc0332007-10-04 22:47:34 +00001339fail:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001340 trace_usb_host_open_failure(bus_num, addr);
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001341 if (dev->fd != -1) {
1342 close(dev->fd);
1343 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001344 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001345 return -1;
1346}
1347
1348static int usb_host_close(USBHostDevice *dev)
1349{
Hans de Goede060dc842010-11-26 11:41:08 +01001350 int i;
1351
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001352 if (dev->fd == -1 || !dev->dev.attached) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001353 return -1;
David Ahern27911042010-04-24 10:26:22 -06001354 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001355
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001356 trace_usb_host_close(dev->bus_num, dev->addr);
1357
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001358 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1359 dev->closing = 1;
Hans de Goede3a4854b2010-11-26 15:02:16 +01001360 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001361 if (is_isoc(dev, USB_TOKEN_IN, i)) {
1362 usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
1363 }
1364 if (is_isoc(dev, USB_TOKEN_OUT, i)) {
1365 usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
Hans de Goede060dc842010-11-26 11:41:08 +01001366 }
1367 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001368 async_complete(dev);
1369 dev->closing = 0;
1370 usb_device_detach(&dev->dev);
Shahar Havivi00ff2272010-06-16 15:15:37 +03001371 ioctl(dev->fd, USBDEVFS_RESET);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001372 close(dev->fd);
1373 dev->fd = -1;
1374 return 0;
1375}
1376
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001377static void usb_host_exit_notifier(struct Notifier *n, void *data)
Shahar Havivib373a632010-06-16 15:16:11 +03001378{
1379 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1380
1381 if (s->fd != -1) {
1382 ioctl(s->fd, USBDEVFS_RESET);
1383 }
1384}
1385
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001386static int usb_host_initfn(USBDevice *dev)
1387{
1388 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1389
1390 dev->auto_attach = 0;
1391 s->fd = -1;
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001392 s->hub_fd = -1;
1393
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001394 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001395 s->exit.notify = usb_host_exit_notifier;
1396 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001397 usb_host_auto_check(NULL);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001398
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001399 if (s->match.bus_num != 0 && s->match.port != NULL) {
Gerd Hoffmanne6274722011-09-13 11:37:47 +02001400 usb_host_claim_port(s);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001401 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001402 return 0;
bellardbb36d472005-11-05 14:22:28 +00001403}
1404
Gerd Hoffmannd6791572011-08-31 11:44:24 +02001405static const VMStateDescription vmstate_usb_host = {
1406 .name = "usb-host",
1407 .unmigratable = 1,
1408};
1409
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001410static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001411 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001412 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001413 .qdev.size = sizeof(USBHostDevice),
Gerd Hoffmannd6791572011-08-31 11:44:24 +02001414 .qdev.vmsd = &vmstate_usb_host,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001415 .init = usb_host_initfn,
Hans de Goede50b79632011-02-02 17:36:29 +01001416 .handle_packet = usb_generic_handle_packet,
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +02001417 .cancel_packet = usb_host_async_cancel,
Hans de Goede50b79632011-02-02 17:36:29 +01001418 .handle_data = usb_host_handle_data,
1419 .handle_control = usb_host_handle_control,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001420 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001421 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001422 .usbdevice_name = "host",
1423 .usbdevice_init = usb_host_device_open,
1424 .qdev.props = (Property[]) {
1425 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1426 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001427 DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001428 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1429 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +02001430 DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001431 DEFINE_PROP_END_OF_LIST(),
1432 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001433};
1434
1435static void usb_host_register_devices(void)
1436{
1437 usb_qdev_register(&usb_host_dev_info);
1438}
1439device_init(usb_host_register_devices)
1440
aliguori4b096fc2008-08-21 19:28:55 +00001441USBDevice *usb_host_device_open(const char *devname)
1442{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001443 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001444 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001445 char *p;
1446
Markus Armbruster556cd092009-12-09 17:07:53 +01001447 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001448
aliguori5d0c5752008-09-14 01:07:41 +00001449 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001450 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001451 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001452 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001453 } else {
1454 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001455 filter.bus_num = strtoul(devname, NULL, 0);
1456 filter.addr = strtoul(p + 1, NULL, 0);
1457 filter.vendor_id = 0;
1458 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001459 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001460 filter.bus_num = 0;
1461 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001462 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001463 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001464 } else {
1465 goto fail;
1466 }
aliguori5d0c5752008-09-14 01:07:41 +00001467 }
1468
Markus Armbruster0745eb12009-11-27 13:05:53 +01001469 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1470 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001471 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1472 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001473 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001474 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001475
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001476fail:
1477 qdev_free(&dev->qdev);
1478 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001479}
aliguori5d0c5752008-09-14 01:07:41 +00001480
1481int usb_host_device_close(const char *devname)
1482{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001483#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001484 char product_name[PRODUCT_NAME_SZ];
1485 int bus_num, addr;
1486 USBHostDevice *s;
1487
David Ahern27911042010-04-24 10:26:22 -06001488 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001489 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001490 }
1491 if (usb_host_find_device(&bus_num, &addr, product_name,
1492 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001493 return -1;
David Ahern27911042010-04-24 10:26:22 -06001494 }
aliguori5d0c5752008-09-14 01:07:41 +00001495 s = hostdev_find(bus_num, addr);
1496 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001497 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001498 return 0;
1499 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001500#endif
aliguori5d0c5752008-09-14 01:07:41 +00001501
1502 return -1;
1503}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001504
bellarda594cfb2005-11-06 16:13:29 +00001505static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001506 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001507 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001508{
bellarda594cfb2005-11-06 16:13:29 +00001509 const char *p;
1510 char *q;
1511 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001512 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001513 return -1;
David Ahern27911042010-04-24 10:26:22 -06001514 }
bellarda594cfb2005-11-06 16:13:29 +00001515 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001516 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001517 p++;
David Ahern27911042010-04-24 10:26:22 -06001518 }
bellarda594cfb2005-11-06 16:13:29 +00001519 q = buf;
1520 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001521 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001522 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001523 }
bellarda594cfb2005-11-06 16:13:29 +00001524 p++;
1525 }
1526 *q = '\0';
1527 return q - buf;
1528}
bellardbb36d472005-11-05 14:22:28 +00001529
aliguori0f431522008-10-07 20:06:37 +00001530/*
1531 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1532 * host's USB devices. This is legacy support since many distributions
1533 * are moving to /sys/bus/usb
1534 */
1535static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001536{
Blue Swirl660f11b2009-07-31 21:16:51 +00001537 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001538 char line[1024];
1539 char buf[1024];
Gerd Hoffmann0c402e52011-08-17 23:36:46 +02001540 int bus_num, addr, speed, device_count;
1541 int class_id, product_id, vendor_id, port;
bellarda594cfb2005-11-06 16:13:29 +00001542 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001543 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001544
aliguori0f431522008-10-07 20:06:37 +00001545 if (!usb_host_device_path) {
1546 perror("husb: USB Host Device Path not set");
1547 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001548 }
aliguori0f431522008-10-07 20:06:37 +00001549 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1550 f = fopen(line, "r");
1551 if (!f) {
1552 perror("husb: cannot open devices file");
1553 goto the_end;
1554 }
1555
bellarda594cfb2005-11-06 16:13:29 +00001556 device_count = 0;
Gerd Hoffmann0c402e52011-08-17 23:36:46 +02001557 bus_num = addr = class_id = product_id = vendor_id = port = 0;
Hans de Goede3991c352011-05-31 11:35:18 +02001558 speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
bellardbb36d472005-11-05 14:22:28 +00001559 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001560 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001561 break;
David Ahern27911042010-04-24 10:26:22 -06001562 }
1563 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001564 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001565 }
bellarda594cfb2005-11-06 16:13:29 +00001566 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001567 if (device_count && (vendor_id || product_id)) {
1568 /* New device. Add the previously discovered device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001569 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001570 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001571 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001572 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001573 }
bellarda594cfb2005-11-06 16:13:29 +00001574 }
David Ahern27911042010-04-24 10:26:22 -06001575 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001576 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001577 }
bellarda594cfb2005-11-06 16:13:29 +00001578 bus_num = atoi(buf);
Gerd Hoffmann0c402e52011-08-17 23:36:46 +02001579 if (get_tag_value(buf, sizeof(buf), line, "Port=", " ") < 0) {
1580 goto fail;
1581 }
1582 port = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001583 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001584 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001585 }
bellarda594cfb2005-11-06 16:13:29 +00001586 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001587 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001588 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001589 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001590 if (!strcmp(buf, "5000")) {
1591 speed = USB_SPEED_SUPER;
1592 } else if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001593 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001594 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001595 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001596 } else {
bellarda594cfb2005-11-06 16:13:29 +00001597 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001598 }
bellarda594cfb2005-11-06 16:13:29 +00001599 product_name[0] = '\0';
1600 class_id = 0xff;
1601 device_count++;
1602 product_id = 0;
1603 vendor_id = 0;
1604 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001605 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001606 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001607 }
bellarda594cfb2005-11-06 16:13:29 +00001608 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001609 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001610 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001611 }
bellarda594cfb2005-11-06 16:13:29 +00001612 product_id = strtoul(buf, NULL, 16);
1613 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001614 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001615 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001616 }
bellarda594cfb2005-11-06 16:13:29 +00001617 pstrcpy(product_name, sizeof(product_name), buf);
1618 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001619 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001620 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001621 }
bellarda594cfb2005-11-06 16:13:29 +00001622 class_id = strtoul(buf, NULL, 16);
1623 }
1624 fail: ;
1625 }
pbrook38ca0f62006-03-11 18:03:38 +00001626 if (device_count && (vendor_id || product_id)) {
1627 /* Add the last device. */
Gerd Hoffmann0c402e52011-08-17 23:36:46 +02001628 if (port > 0) {
1629 snprintf(buf, sizeof(buf), "%d", port);
1630 } else {
1631 snprintf(buf, sizeof(buf), "?");
1632 }
1633 ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001634 product_id, product_name, speed);
1635 }
1636 the_end:
David Ahern27911042010-04-24 10:26:22 -06001637 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001638 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001639 }
aliguori0f431522008-10-07 20:06:37 +00001640 return ret;
1641}
1642
1643/*
1644 * Read sys file-system device file
1645 *
1646 * @line address of buffer to put file contents in
1647 * @line_size size of line
1648 * @device_file path to device file (printf format string)
1649 * @device_name device being opened (inserted into device_file)
1650 *
1651 * @return 0 failed, 1 succeeded ('line' contains data)
1652 */
David Ahern27911042010-04-24 10:26:22 -06001653static int usb_host_read_file(char *line, size_t line_size,
1654 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001655{
1656 FILE *f;
1657 int ret = 0;
1658 char filename[PATH_MAX];
1659
blueswir1b4e237a2008-12-28 15:45:20 +00001660 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1661 device_file);
aliguori0f431522008-10-07 20:06:37 +00001662 f = fopen(filename, "r");
1663 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001664 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001665 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001666 }
1667
1668 return ret;
1669}
1670
1671/*
1672 * Use /sys/bus/usb/devices/ directory to determine host's USB
1673 * devices.
1674 *
1675 * This code is based on Robert Schiele's original patches posted to
1676 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1677 */
1678static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1679{
Blue Swirl660f11b2009-07-31 21:16:51 +00001680 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001681 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001682 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001683 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001684 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001685 char product_name[512];
1686 struct dirent *de;
1687
1688 dir = opendir(USBSYSBUS_PATH "/devices");
1689 if (!dir) {
1690 perror("husb: cannot open devices directory");
1691 goto the_end;
1692 }
1693
1694 while ((de = readdir(dir))) {
1695 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001696 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1697 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001698 }
aliguori0f431522008-10-07 20:06:37 +00001699
David Ahern27911042010-04-24 10:26:22 -06001700 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001701 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001702 }
1703 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001704 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001705 }
blueswir1b4e237a2008-12-28 15:45:20 +00001706 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001707 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001708 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001709 }
1710 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001711 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001712 }
aliguori0f431522008-10-07 20:06:37 +00001713
David Ahern27911042010-04-24 10:26:22 -06001714 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1715 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001716 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001717 }
1718 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001719 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001720 }
blueswir1b4e237a2008-12-28 15:45:20 +00001721 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001722 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001723 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001724 }
1725 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001726 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001727 }
blueswir1b4e237a2008-12-28 15:45:20 +00001728 if (!usb_host_read_file(line, sizeof(line), "product",
1729 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001730 *product_name = 0;
1731 } else {
David Ahern27911042010-04-24 10:26:22 -06001732 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001733 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001734 }
aliguori0f431522008-10-07 20:06:37 +00001735 pstrcpy(product_name, sizeof(product_name), line);
1736 }
1737
David Ahern27911042010-04-24 10:26:22 -06001738 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001739 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001740 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001741 if (!strcmp(line, "5000\n")) {
1742 speed = USB_SPEED_SUPER;
1743 } else if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001744 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001745 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001746 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001747 } else {
aliguori0f431522008-10-07 20:06:37 +00001748 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001749 }
aliguori0f431522008-10-07 20:06:37 +00001750
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001751 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001752 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001753 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001754 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001755 }
aliguori0f431522008-10-07 20:06:37 +00001756 }
1757 }
1758 the_end:
David Ahern27911042010-04-24 10:26:22 -06001759 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001760 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001761 }
aliguori0f431522008-10-07 20:06:37 +00001762 return ret;
1763}
1764
1765/*
1766 * Determine how to access the host's USB devices and call the
1767 * specific support function.
1768 */
1769static int usb_host_scan(void *opaque, USBScanFunc *func)
1770{
aliguori376253e2009-03-05 23:01:23 +00001771 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001772 FILE *f = NULL;
1773 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001774 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001775 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1776 char devpath[PATH_MAX];
1777
1778 /* only check the host once */
1779 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001780 dir = opendir(USBSYSBUS_PATH "/devices");
1781 if (dir) {
1782 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1783 strcpy(devpath, USBDEVBUS_PATH);
1784 usb_fs_type = USB_FS_SYS;
1785 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001786 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001787 goto found_devices;
1788 }
aliguori0f431522008-10-07 20:06:37 +00001789 f = fopen(USBPROCBUS_PATH "/devices", "r");
1790 if (f) {
1791 /* devices found in /proc/bus/usb/ */
1792 strcpy(devpath, USBPROCBUS_PATH);
1793 usb_fs_type = USB_FS_PROC;
1794 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001795 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001796 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001797 }
1798 /* try additional methods if an access method hasn't been found yet */
1799 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001800 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001801 /* devices found in /dev/bus/usb/ */
1802 strcpy(devpath, USBDEVBUS_PATH);
1803 usb_fs_type = USB_FS_DEV;
1804 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001805 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001806 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001807 }
aliguorif16a0db2008-10-21 16:34:20 +00001808 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001809 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001810 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001811 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001812 }
aliguorif16a0db2008-10-21 16:34:20 +00001813 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001814 }
1815
1816 /* the module setting (used later for opening devices) */
Anthony Liguori7267c092011-08-20 22:09:37 -05001817 usb_host_device_path = g_malloc0(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001818 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001819 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001820 monitor_printf(mon, "husb: using %s file-system with %s\n",
1821 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001822 }
aliguori0f431522008-10-07 20:06:37 +00001823 }
1824
1825 switch (usb_fs_type) {
1826 case USB_FS_PROC:
1827 case USB_FS_DEV:
1828 ret = usb_host_scan_dev(opaque, func);
1829 break;
1830 case USB_FS_SYS:
1831 ret = usb_host_scan_sys(opaque, func);
1832 break;
aliguorif16a0db2008-10-21 16:34:20 +00001833 default:
1834 ret = -EINVAL;
1835 break;
aliguori0f431522008-10-07 20:06:37 +00001836 }
bellarda594cfb2005-11-06 16:13:29 +00001837 return ret;
1838}
1839
aliguori4b096fc2008-08-21 19:28:55 +00001840static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001841
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001842static int usb_host_auto_scan(void *opaque, int bus_num,
1843 int addr, const char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001844 int class_id, int vendor_id, int product_id,
1845 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001846{
1847 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001848 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001849
1850 /* Ignore hubs */
1851 if (class_id == 9)
1852 return 0;
1853
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001854 QTAILQ_FOREACH(s, &hostdevs, next) {
1855 f = &s->match;
1856
David Ahern27911042010-04-24 10:26:22 -06001857 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001858 continue;
David Ahern27911042010-04-24 10:26:22 -06001859 }
1860 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001861 continue;
David Ahern27911042010-04-24 10:26:22 -06001862 }
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001863 if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
1864 continue;
1865 }
aliguori4b096fc2008-08-21 19:28:55 +00001866
David Ahern27911042010-04-24 10:26:22 -06001867 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001868 continue;
David Ahern27911042010-04-24 10:26:22 -06001869 }
aliguori4b096fc2008-08-21 19:28:55 +00001870
David Ahern27911042010-04-24 10:26:22 -06001871 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001872 continue;
David Ahern27911042010-04-24 10:26:22 -06001873 }
aliguori4b096fc2008-08-21 19:28:55 +00001874 /* We got a match */
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001875 s->seen++;
1876 if (s->errcount >= 3) {
1877 return 0;
1878 }
aliguori4b096fc2008-08-21 19:28:55 +00001879
Markus Armbruster33e66b82009-10-07 01:15:57 +02001880 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001881 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001882 return 0;
David Ahern27911042010-04-24 10:26:22 -06001883 }
malcd0f2c4c2010-02-07 02:03:50 +03001884 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001885
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001886 if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
1887 s->errcount++;
1888 }
Hans de Goede97f86162011-05-31 11:35:24 +02001889 break;
aliguori4b096fc2008-08-21 19:28:55 +00001890 }
1891
1892 return 0;
1893}
1894
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001895static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001896{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001897 struct USBHostDevice *s;
1898 int unconnected = 0;
1899
aliguori4b096fc2008-08-21 19:28:55 +00001900 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001901
1902 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001903 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001904 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001905 }
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001906 if (s->seen == 0) {
1907 s->errcount = 0;
1908 }
1909 s->seen = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001910 }
1911
1912 if (unconnected == 0) {
1913 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001914 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001915 qemu_del_timer(usb_auto_timer);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001916 trace_usb_host_auto_scan_disabled();
David Ahern27911042010-04-24 10:26:22 -06001917 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001918 return;
1919 }
1920
1921 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001922 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001923 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001924 return;
David Ahern27911042010-04-24 10:26:22 -06001925 }
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001926 trace_usb_host_auto_scan_enabled();
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001927 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001928 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001929}
1930
1931/*
aliguori5d0c5752008-09-14 01:07:41 +00001932 * Autoconnect filter
1933 * Format:
1934 * auto:bus:dev[:vid:pid]
1935 * auto:bus.dev[:vid:pid]
1936 *
1937 * bus - bus number (dec, * means any)
1938 * dev - device number (dec, * means any)
1939 * vid - vendor id (hex, * means any)
1940 * pid - product id (hex, * means any)
1941 *
1942 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001943 */
aliguori5d0c5752008-09-14 01:07:41 +00001944static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001945{
aliguori5d0c5752008-09-14 01:07:41 +00001946 enum { BUS, DEV, VID, PID, DONE };
1947 const char *p = spec;
1948 int i;
1949
Markus Armbruster0745eb12009-11-27 13:05:53 +01001950 f->bus_num = 0;
1951 f->addr = 0;
1952 f->vendor_id = 0;
1953 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001954
1955 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001956 p = strpbrk(p, ":.");
1957 if (!p) {
1958 break;
1959 }
aliguori5d0c5752008-09-14 01:07:41 +00001960 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001961
David Ahern27911042010-04-24 10:26:22 -06001962 if (*p == '*') {
1963 continue;
1964 }
aliguori5d0c5752008-09-14 01:07:41 +00001965 switch(i) {
1966 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1967 case DEV: f->addr = strtol(p, NULL, 10); break;
1968 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1969 case PID: f->product_id = strtol(p, NULL, 16); break;
1970 }
aliguori4b096fc2008-08-21 19:28:55 +00001971 }
1972
aliguori5d0c5752008-09-14 01:07:41 +00001973 if (i < DEV) {
1974 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1975 return -1;
1976 }
1977
1978 return 0;
1979}
1980
bellarda594cfb2005-11-06 16:13:29 +00001981/**********************/
1982/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001983
bellarda594cfb2005-11-06 16:13:29 +00001984struct usb_class_info {
1985 int class;
1986 const char *class_name;
1987};
1988
1989static const struct usb_class_info usb_class_info[] = {
1990 { USB_CLASS_AUDIO, "Audio"},
1991 { USB_CLASS_COMM, "Communication"},
1992 { USB_CLASS_HID, "HID"},
1993 { USB_CLASS_HUB, "Hub" },
1994 { USB_CLASS_PHYSICAL, "Physical" },
1995 { USB_CLASS_PRINTER, "Printer" },
1996 { USB_CLASS_MASS_STORAGE, "Storage" },
1997 { USB_CLASS_CDC_DATA, "Data" },
1998 { USB_CLASS_APP_SPEC, "Application Specific" },
1999 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
2000 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00002001 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00002002 { USB_CLASS_CONTENT_SEC, "Content Security" },
2003 { -1, NULL }
2004};
2005
2006static const char *usb_class_str(uint8_t class)
2007{
2008 const struct usb_class_info *p;
2009 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06002010 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00002011 break;
David Ahern27911042010-04-24 10:26:22 -06002012 }
bellardbb36d472005-11-05 14:22:28 +00002013 }
bellarda594cfb2005-11-06 16:13:29 +00002014 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00002015}
2016
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02002017static void usb_info_device(Monitor *mon, int bus_num,
2018 int addr, const char *port,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02002019 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00002020 const char *product_name,
2021 int speed)
bellardbb36d472005-11-05 14:22:28 +00002022{
bellarda594cfb2005-11-06 16:13:29 +00002023 const char *class_str, *speed_str;
2024
2025 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00002026 case USB_SPEED_LOW:
2027 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00002028 break;
ths5fafdf22007-09-16 21:08:06 +00002029 case USB_SPEED_FULL:
2030 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00002031 break;
ths5fafdf22007-09-16 21:08:06 +00002032 case USB_SPEED_HIGH:
2033 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00002034 break;
Hans de Goedef264cfb2011-05-31 11:35:19 +02002035 case USB_SPEED_SUPER:
2036 speed_str = "5000";
2037 break;
bellarda594cfb2005-11-06 16:13:29 +00002038 default:
ths5fafdf22007-09-16 21:08:06 +00002039 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00002040 break;
bellardbb36d472005-11-05 14:22:28 +00002041 }
bellarda594cfb2005-11-06 16:13:29 +00002042
Gerd Hoffmann5557d822011-05-10 11:43:57 +02002043 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
2044 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00002045 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06002046 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00002047 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06002048 } else {
aliguori376253e2009-03-05 23:01:23 +00002049 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06002050 }
aliguori376253e2009-03-05 23:01:23 +00002051 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06002052 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00002053 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06002054 }
aliguori376253e2009-03-05 23:01:23 +00002055 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00002056}
2057
ths5fafdf22007-09-16 21:08:06 +00002058static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02002059 const char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00002060 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00002061 const char *product_name,
2062 int speed)
2063{
Blue Swirl179da8a2009-09-07 19:00:18 +00002064 Monitor *mon = opaque;
2065
Gerd Hoffmann5557d822011-05-10 11:43:57 +02002066 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00002067 product_name, speed);
2068 return 0;
2069}
2070
aliguoriac4ffb52008-09-22 15:04:31 +00002071static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00002072{
David Ahern27911042010-04-24 10:26:22 -06002073 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00002074 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06002075 } else {
2076 snprintf(str, size, "%d", val);
2077 }
aliguori5d0c5752008-09-14 01:07:41 +00002078}
2079
aliguoriac4ffb52008-09-22 15:04:31 +00002080static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00002081{
David Ahern27911042010-04-24 10:26:22 -06002082 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00002083 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06002084 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002085 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06002086 }
aliguori5d0c5752008-09-14 01:07:41 +00002087}
2088
aliguori376253e2009-03-05 23:01:23 +00002089void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00002090{
aliguori5d0c5752008-09-14 01:07:41 +00002091 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002092 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00002093
Blue Swirl179da8a2009-09-07 19:00:18 +00002094 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00002095
David Ahern27911042010-04-24 10:26:22 -06002096 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002097 return;
David Ahern27911042010-04-24 10:26:22 -06002098 }
2099
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002100 monitor_printf(mon, " Auto filters:\n");
2101 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00002102 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002103 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00002104 dec2str(f->bus_num, bus, sizeof(bus));
2105 dec2str(f->addr, addr, sizeof(addr));
2106 hex2str(f->vendor_id, vid, sizeof(vid));
2107 hex2str(f->product_id, pid, sizeof(pid));
Gerd Hoffmann9056a292011-05-10 12:07:42 +02002108 monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
2109 bus, addr, f->port ? f->port : "*", vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00002110 }
bellardbb36d472005-11-05 14:22:28 +00002111}