blob: ab4c6930ca2d46dfe22c7382c134fb905ad3c9be [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 Hoffmannc7662da2011-11-16 12:37:17 +0100151static int usb_host_do_reset(USBHostDevice *dev)
152{
153 struct timeval s, e;
154 uint32_t usecs;
155 int ret;
156
157 gettimeofday(&s, NULL);
158 ret = ioctl(dev->fd, USBDEVFS_RESET);
159 gettimeofday(&e, NULL);
160 usecs = (e.tv_sec - s.tv_sec) * 1000000;
161 usecs += e.tv_usec - s.tv_usec;
162 if (usecs > 1000000) {
163 /* more than a second, something is fishy, broken usb device? */
164 fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n",
165 dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000);
166 }
167 return ret;
168}
169
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200170static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200171{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200172 struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
173 assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
174 assert(ep > 0 && ep <= MAX_ENDPOINTS);
175 return eps + ep - 1;
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200176}
177
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200178static int is_isoc(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000179{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200180 return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
aliguori64838172008-08-21 19:31:10 +0000181}
182
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200183static int is_valid(USBHostDevice *s, int pid, int ep)
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100184{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200185 return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100186}
187
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200188static int is_halted(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000189{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200190 return get_endp(s, pid, ep)->halted;
aliguori64838172008-08-21 19:31:10 +0000191}
192
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200193static void clear_halt(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000194{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200195 trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200196 get_endp(s, pid, ep)->halted = 0;
aliguori64838172008-08-21 19:31:10 +0000197}
198
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200199static void set_halt(USBHostDevice *s, int pid, int ep)
aliguori64838172008-08-21 19:31:10 +0000200{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200201 if (ep != 0) {
202 trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
203 get_endp(s, pid, ep)->halted = 1;
204 }
aliguori64838172008-08-21 19:31:10 +0000205}
206
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200207static int is_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100208{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200209 return get_endp(s, pid, ep)->iso_started;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100210}
211
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200212static void clear_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100213{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200214 trace_usb_host_ep_stop_iso(s->bus_num, s->addr, ep);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200215 get_endp(s, pid, ep)->iso_started = 0;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100216}
217
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200218static void set_iso_started(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100219{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200220 struct endp_data *e = get_endp(s, pid, ep);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200221
222 trace_usb_host_ep_start_iso(s->bus_num, s->addr, ep);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200223 if (!e->iso_started) {
224 e->iso_started = 1;
225 e->inflight = 0;
226 }
227}
228
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200229static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
Gerd Hoffmann82887262011-06-10 14:00:24 +0200230{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200231 struct endp_data *e = get_endp(s, pid, ep);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200232
233 e->inflight += value;
234 return e->inflight;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100235}
236
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200237static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
Hans de Goede060dc842010-11-26 11:41:08 +0100238{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200239 get_endp(s, pid, ep)->iso_urb = iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100240}
241
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200242static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100243{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200244 return get_endp(s, pid, ep)->iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100245}
246
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200247static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
Hans de Goede060dc842010-11-26 11:41:08 +0100248{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200249 get_endp(s, pid, ep)->iso_urb_idx = i;
Hans de Goede060dc842010-11-26 11:41:08 +0100250}
251
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200252static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100253{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200254 return get_endp(s, pid, ep)->iso_urb_idx;
Hans de Goede060dc842010-11-26 11:41:08 +0100255}
256
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200257static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100258{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200259 get_endp(s, pid, ep)->iso_buffer_used = i;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100260}
261
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200262static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
Hans de Goedebb6d5492010-11-26 19:11:03 +0100263{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200264 return get_endp(s, pid, ep)->iso_buffer_used;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100265}
266
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200267static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
268 uint8_t *descriptor)
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200269{
270 int raw = descriptor[4] + (descriptor[5] << 8);
271 int size, microframes;
272
273 size = raw & 0x7ff;
274 switch ((raw >> 11) & 3) {
275 case 1: microframes = 2; break;
276 case 2: microframes = 3; break;
277 default: microframes = 1; break;
278 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200279 get_endp(s, pid, ep)->max_packet_size = size * microframes;
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200280}
281
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200282static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100283{
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200284 return get_endp(s, pid, ep)->max_packet_size;
Hans de Goede060dc842010-11-26 11:41:08 +0100285}
286
David Ahern27911042010-04-24 10:26:22 -0600287/*
aliguori64838172008-08-21 19:31:10 +0000288 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100289 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600290 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000291 */
Hans de Goede060dc842010-11-26 11:41:08 +0100292struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000293{
aliguori64838172008-08-21 19:31:10 +0000294 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100295 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200296 USBHostDevice *hdev;
297 QLIST_ENTRY(AsyncURB) next;
aliguori64838172008-08-21 19:31:10 +0000298
Hans de Goede060dc842010-11-26 11:41:08 +0100299 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000300 USBPacket *packet;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200301 int more; /* large transfer, more urbs follow */
Hans de Goede060dc842010-11-26 11:41:08 +0100302
303 /* For buffered iso handling */
304 int iso_frame_idx; /* -1 means in flight */
305};
aliguori64838172008-08-21 19:31:10 +0000306
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200307static AsyncURB *async_alloc(USBHostDevice *s)
aliguori64838172008-08-21 19:31:10 +0000308{
Anthony Liguori7267c092011-08-20 22:09:37 -0500309 AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200310 aurb->hdev = s;
311 QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
312 return aurb;
balrogb9dc0332007-10-04 22:47:34 +0000313}
314
aliguori64838172008-08-21 19:31:10 +0000315static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000316{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200317 QLIST_REMOVE(aurb, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500318 g_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000319}
balrogb9dc0332007-10-04 22:47:34 +0000320
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200321static void do_disconnect(USBHostDevice *s)
322{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200323 usb_host_close(s);
324 usb_host_auto_check(NULL);
325}
326
aliguori64838172008-08-21 19:31:10 +0000327static void async_complete(void *opaque)
328{
329 USBHostDevice *s = opaque;
330 AsyncURB *aurb;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200331 int urbs = 0;
balrogb9dc0332007-10-04 22:47:34 +0000332
aliguori64838172008-08-21 19:31:10 +0000333 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600334 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000335
David Ahern27911042010-04-24 10:26:22 -0600336 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000337 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600338 if (errno == EAGAIN) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200339 if (urbs > 2) {
340 fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);
341 }
aliguori64838172008-08-21 19:31:10 +0000342 return;
David Ahern27911042010-04-24 10:26:22 -0600343 }
Gerd Hoffmann40197c32011-08-22 14:18:21 +0200344 if (errno == ENODEV) {
345 if (!s->closing) {
346 trace_usb_host_disconnect(s->bus_num, s->addr);
347 do_disconnect(s);
348 }
aliguori64838172008-08-21 19:31:10 +0000349 return;
350 }
351
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200352 perror("USBDEVFS_REAPURBNDELAY");
aliguori64838172008-08-21 19:31:10 +0000353 return;
balrogb9dc0332007-10-04 22:47:34 +0000354 }
aliguori64838172008-08-21 19:31:10 +0000355
David Ahern27911042010-04-24 10:26:22 -0600356 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000357 aurb, aurb->urb.status, aurb->urb.actual_length);
358
Hans de Goede060dc842010-11-26 11:41:08 +0100359 /* If this is a buffered iso urb mark it as complete and don't do
360 anything else (it is handled further in usb_host_handle_iso_data) */
361 if (aurb->iso_frame_idx == -1) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200362 int inflight;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200363 int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
364 USB_TOKEN_IN : USB_TOKEN_OUT;
365 int ep = aurb->urb.endpoint & 0xf;
Hans de Goede060dc842010-11-26 11:41:08 +0100366 if (aurb->urb.status == -EPIPE) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200367 set_halt(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100368 }
369 aurb->iso_frame_idx = 0;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200370 urbs++;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200371 inflight = change_iso_inflight(s, pid, ep, -1);
372 if (inflight == 0 && is_iso_started(s, pid, ep)) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200373 fprintf(stderr, "husb: out of buffers for iso stream\n");
374 }
Hans de Goede060dc842010-11-26 11:41:08 +0100375 continue;
376 }
377
378 p = aurb->packet;
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200379 trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
380 aurb->urb.actual_length, aurb->more);
Hans de Goede060dc842010-11-26 11:41:08 +0100381
David Ahern27911042010-04-24 10:26:22 -0600382 if (p) {
aliguori64838172008-08-21 19:31:10 +0000383 switch (aurb->urb.status) {
384 case 0:
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200385 p->result += aurb->urb.actual_length;
aliguori64838172008-08-21 19:31:10 +0000386 break;
387
388 case -EPIPE:
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200389 set_halt(s, p->pid, p->devep);
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200390 p->result = USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600391 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200392
aliguori64838172008-08-21 19:31:10 +0000393 default:
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200394 p->result = USB_RET_NAK;
aliguori64838172008-08-21 19:31:10 +0000395 break;
396 }
397
Hans de Goede50b79632011-02-02 17:36:29 +0100398 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200399 trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
Hans de Goede50b79632011-02-02 17:36:29 +0100400 usb_generic_async_ctrl_complete(&s->dev, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200401 } else if (!aurb->more) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200402 trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
Hans de Goede50b79632011-02-02 17:36:29 +0100403 usb_packet_complete(&s->dev, p);
404 }
David Ahern27911042010-04-24 10:26:22 -0600405 }
aliguori64838172008-08-21 19:31:10 +0000406
407 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000408 }
balrogb9dc0332007-10-04 22:47:34 +0000409}
410
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200411static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
balrogb9dc0332007-10-04 22:47:34 +0000412{
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200413 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200414 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000415
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200416 QLIST_FOREACH(aurb, &s->aurbs, next) {
417 if (p != aurb->packet) {
418 continue;
419 }
balrogb9dc0332007-10-04 22:47:34 +0000420
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200421 DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
aliguori64838172008-08-21 19:31:10 +0000422
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200423 /* Mark it as dead (see async_complete above) */
424 aurb->packet = NULL;
425
426 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
427 if (r < 0) {
428 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
429 }
balrogb9dc0332007-10-04 22:47:34 +0000430 }
balrogb9dc0332007-10-04 22:47:34 +0000431}
432
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200433static int usb_host_claim_port(USBHostDevice *s)
434{
435#ifdef USBDEVFS_CLAIM_PORT
436 char *h, hub_name[64], line[1024];
437 int hub_addr, portnr, ret;
438
439 snprintf(hub_name, sizeof(hub_name), "%d-%s",
440 s->match.bus_num, s->match.port);
441
442 /* try strip off last ".$portnr" to get hub */
443 h = strrchr(hub_name, '.');
444 if (h != NULL) {
445 portnr = atoi(h+1);
446 *h = '\0';
447 } else {
448 /* no dot in there -> it is the root hub */
449 snprintf(hub_name, sizeof(hub_name), "usb%d",
450 s->match.bus_num);
451 portnr = atoi(s->match.port);
452 }
453
454 if (!usb_host_read_file(line, sizeof(line), "devnum",
455 hub_name)) {
456 return -1;
457 }
458 if (sscanf(line, "%d", &hub_addr) != 1) {
459 return -1;
460 }
461
462 if (!usb_host_device_path) {
463 return -1;
464 }
465 snprintf(line, sizeof(line), "%s/%03d/%03d",
466 usb_host_device_path, s->match.bus_num, hub_addr);
467 s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
468 if (s->hub_fd < 0) {
469 return -1;
470 }
471
472 ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
473 if (ret < 0) {
474 close(s->hub_fd);
475 s->hub_fd = -1;
476 return -1;
477 }
478
479 trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
480 return 0;
481#else
482 return -1;
483#endif
484}
485
486static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
487{
488 /* earlier Linux 2.4 do not support that */
489#ifdef USBDEVFS_DISCONNECT
490 struct usbdevfs_ioctl ctrl;
491 int ret, interface;
492
493 for (interface = 0; interface < nb_interfaces; interface++) {
494 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
495 ctrl.ifno = interface;
496 ctrl.data = 0;
497 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
498 if (ret < 0 && errno != ENODATA) {
499 perror("USBDEVFS_DISCONNECT");
500 return -1;
501 }
502 }
503#endif
504 return 0;
505}
506
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200507static int usb_linux_get_num_interfaces(USBHostDevice *s)
508{
509 char device_name[64], line[1024];
510 int num_interfaces = 0;
511
512 if (usb_fs_type != USB_FS_SYS) {
513 return -1;
514 }
515
516 sprintf(device_name, "%d-%s", s->bus_num, s->port);
517 if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
518 device_name)) {
519 return -1;
520 }
521 if (sscanf(line, "%d", &num_interfaces) != 1) {
522 return -1;
523 }
524 return num_interfaces;
525}
526
aliguori446ab122008-09-14 01:06:09 +0000527static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000528{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200529 const char *op = NULL;
balrogb9dc0332007-10-04 22:47:34 +0000530 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000531 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000532 int ret, i;
533
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200534 if (configuration == 0) { /* address state - ignore */
535 dev->ninterfaces = 0;
536 dev->configuration = 0;
balrogb9dc0332007-10-04 22:47:34 +0000537 return 1;
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200538 }
balrogb9dc0332007-10-04 22:47:34 +0000539
malcd0f2c4c2010-02-07 02:03:50 +0300540 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000541
balrogb9dc0332007-10-04 22:47:34 +0000542 i = 0;
543 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600544 if (dev_descr_len > dev->descr_len) {
Hans de Goede61c11172011-05-31 11:35:20 +0200545 fprintf(stderr, "husb: update iface failed. descr too short\n");
546 return 0;
David Ahern27911042010-04-24 10:26:22 -0600547 }
balrogb9dc0332007-10-04 22:47:34 +0000548
549 i += dev_descr_len;
550 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600551 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
552 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000553 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000554
balrogb9dc0332007-10-04 22:47:34 +0000555 if (dev->descr[i+1] != USB_DT_CONFIG) {
556 i += dev->descr[i];
557 continue;
558 }
559 config_descr_len = dev->descr[i];
560
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200561 DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000562
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200563 if (configuration == dev->descr[i + 5]) {
aliguori446ab122008-09-14 01:06:09 +0000564 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000565 break;
aliguori446ab122008-09-14 01:06:09 +0000566 }
balrogb9dc0332007-10-04 22:47:34 +0000567
568 i += config_descr_len;
569 }
570
571 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600572 fprintf(stderr,
573 "husb: update iface failed. no matching configuration\n");
Hans de Goede61c11172011-05-31 11:35:20 +0200574 return 0;
balrogb9dc0332007-10-04 22:47:34 +0000575 }
576 nb_interfaces = dev->descr[i + 4];
577
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200578 if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
579 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000580 }
balrogb9dc0332007-10-04 22:47:34 +0000581
582 /* XXX: only grab if all interfaces are free */
583 for (interface = 0; interface < nb_interfaces; interface++) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200584 op = "USBDEVFS_CLAIMINTERFACE";
balrogb9dc0332007-10-04 22:47:34 +0000585 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
586 if (ret < 0) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200587 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000588 }
589 }
590
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200591 trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
592 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000593
aliguori446ab122008-09-14 01:06:09 +0000594 dev->ninterfaces = nb_interfaces;
595 dev->configuration = configuration;
596 return 1;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200597
598fail:
599 if (errno == ENODEV) {
600 do_disconnect(dev);
601 }
602 perror(op);
603 return 0;
aliguori446ab122008-09-14 01:06:09 +0000604}
605
606static int usb_host_release_interfaces(USBHostDevice *s)
607{
608 int ret, i;
609
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200610 trace_usb_host_release_interfaces(s->bus_num, s->addr);
aliguori446ab122008-09-14 01:06:09 +0000611
612 for (i = 0; i < s->ninterfaces; i++) {
613 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
614 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200615 perror("USBDEVFS_RELEASEINTERFACE");
aliguori446ab122008-09-14 01:06:09 +0000616 return 0;
617 }
618 }
balrogb9dc0332007-10-04 22:47:34 +0000619 return 1;
620}
621
bellard059809e2006-07-19 18:06:15 +0000622static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000623{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100624 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000625
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200626 trace_usb_host_reset(s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000627
Gerd Hoffmannc7662da2011-11-16 12:37:17 +0100628 usb_host_do_reset(s);;
aliguori446ab122008-09-14 01:06:09 +0000629
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200630 usb_host_claim_interfaces(s, 0);
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200631 usb_linux_update_endp_table(s);
ths5fafdf22007-09-16 21:08:06 +0000632}
bellardbb36d472005-11-05 14:22:28 +0000633
bellard059809e2006-07-19 18:06:15 +0000634static void usb_host_handle_destroy(USBDevice *dev)
635{
636 USBHostDevice *s = (USBHostDevice *)dev;
637
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100638 usb_host_close(s);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +0200639 if (s->hub_fd != -1) {
640 close(s->hub_fd);
641 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100642 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300643 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000644}
645
Hans de Goede060dc842010-11-26 11:41:08 +0100646/* iso data is special, we need to keep enough urbs in flight to make sure
647 that the controller never runs out of them, otherwise the device will
648 likely suffer a buffer underrun / overrun. */
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200649static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100650{
651 AsyncURB *aurb;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200652 int i, j, len = get_max_packet_size(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100653
Anthony Liguori7267c092011-08-20 22:09:37 -0500654 aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200655 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100656 aurb[i].urb.endpoint = ep;
657 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
Anthony Liguori7267c092011-08-20 22:09:37 -0500658 aurb[i].urb.buffer = g_malloc(aurb[i].urb.buffer_length);
Hans de Goede060dc842010-11-26 11:41:08 +0100659 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
660 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
661 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
662 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
663 aurb[i].urb.iso_frame_desc[j].length = len;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200664 if (pid == USB_TOKEN_IN) {
Hans de Goede060dc842010-11-26 11:41:08 +0100665 aurb[i].urb.endpoint |= 0x80;
666 /* Mark as fully consumed (idle) */
667 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
668 }
669 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200670 set_iso_urb(s, pid, ep, aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100671
672 return aurb;
673}
674
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200675static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100676{
677 AsyncURB *aurb;
678 int i, ret, killed = 0, free = 1;
679
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200680 aurb = get_iso_urb(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100681 if (!aurb) {
682 return;
683 }
684
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200685 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100686 /* in flight? */
687 if (aurb[i].iso_frame_idx == -1) {
688 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
689 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200690 perror("USBDEVFS_DISCARDURB");
Hans de Goede060dc842010-11-26 11:41:08 +0100691 free = 0;
692 continue;
693 }
694 killed++;
695 }
696 }
697
698 /* Make sure any urbs we've killed are reaped before we free them */
699 if (killed) {
700 async_complete(s);
701 }
702
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200703 for (i = 0; i < s->iso_urb_count; i++) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500704 g_free(aurb[i].urb.buffer);
Hans de Goede060dc842010-11-26 11:41:08 +0100705 }
706
707 if (free)
Anthony Liguori7267c092011-08-20 22:09:37 -0500708 g_free(aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100709 else
710 printf("husb: leaking iso urbs because of discard failure\n");
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200711 set_iso_urb(s, pid, ep, NULL);
712 set_iso_urb_idx(s, pid, ep, 0);
713 clear_iso_started(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100714}
715
716static int urb_status_to_usb_ret(int status)
717{
718 switch (status) {
719 case -EPIPE:
720 return USB_RET_STALL;
721 default:
722 return USB_RET_NAK;
723 }
724}
725
Hans de Goedebb6d5492010-11-26 19:11:03 +0100726static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100727{
728 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100729 int i, j, ret, max_packet_size, offset, len = 0;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200730 uint8_t *buf;
Hans de Goede975f2992010-11-26 14:59:35 +0100731
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200732 max_packet_size = get_max_packet_size(s, p->pid, p->devep);
Hans de Goede975f2992010-11-26 14:59:35 +0100733 if (max_packet_size == 0)
734 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100735
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200736 aurb = get_iso_urb(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100737 if (!aurb) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200738 aurb = usb_host_alloc_iso(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100739 }
740
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200741 i = get_iso_urb_idx(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100742 j = aurb[i].iso_frame_idx;
743 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100744 if (in) {
745 /* Check urb status */
746 if (aurb[i].urb.status) {
747 len = urb_status_to_usb_ret(aurb[i].urb.status);
748 /* Move to the next urb */
749 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
750 /* Check frame status */
751 } else if (aurb[i].urb.iso_frame_desc[j].status) {
752 len = urb_status_to_usb_ret(
753 aurb[i].urb.iso_frame_desc[j].status);
754 /* Check the frame fits */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200755 } else if (aurb[i].urb.iso_frame_desc[j].actual_length
756 > p->iov.size) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100757 printf("husb: received iso data is larger then packet\n");
758 len = USB_RET_NAK;
759 /* All good copy data over */
760 } else {
761 len = aurb[i].urb.iso_frame_desc[j].actual_length;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200762 buf = aurb[i].urb.buffer +
763 j * aurb[i].urb.iso_frame_desc[0].length;
764 usb_packet_copy(p, buf, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100765 }
Hans de Goede060dc842010-11-26 11:41:08 +0100766 } else {
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200767 len = p->iov.size;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200768 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100769
770 /* Check the frame fits */
771 if (len > max_packet_size) {
772 printf("husb: send iso data is larger then max packet size\n");
773 return USB_RET_NAK;
774 }
775
776 /* All good copy data over */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200777 usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100778 aurb[i].urb.iso_frame_desc[j].length = len;
779 offset += len;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200780 set_iso_buffer_used(s, p->pid, p->devep, offset);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100781
782 /* Start the stream once we have buffered enough data */
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200783 if (!is_iso_started(s, p->pid, p->devep) && i == 1 && j == 8) {
784 set_iso_started(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100785 }
Hans de Goede060dc842010-11-26 11:41:08 +0100786 }
787 aurb[i].iso_frame_idx++;
788 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200789 i = (i + 1) % s->iso_urb_count;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200790 set_iso_urb_idx(s, p->pid, p->devep, i);
Hans de Goede060dc842010-11-26 11:41:08 +0100791 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100792 } else {
793 if (in) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200794 set_iso_started(s, p->pid, p->devep);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100795 } else {
796 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
797 }
Hans de Goede060dc842010-11-26 11:41:08 +0100798 }
799
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200800 if (is_iso_started(s, p->pid, p->devep)) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100801 /* (Re)-submit all fully consumed / filled urbs */
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200802 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100803 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
804 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
805 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200806 perror("USBDEVFS_SUBMITURB");
Hans de Goedebb6d5492010-11-26 19:11:03 +0100807 if (!in || len == 0) {
808 switch(errno) {
809 case ETIMEDOUT:
810 len = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200811 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100812 case EPIPE:
813 default:
814 len = USB_RET_STALL;
815 }
Hans de Goede060dc842010-11-26 11:41:08 +0100816 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100817 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100818 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100819 aurb[i].iso_frame_idx = -1;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200820 change_iso_inflight(s, p->pid, p->devep, 1);
Hans de Goede060dc842010-11-26 11:41:08 +0100821 }
Hans de Goede060dc842010-11-26 11:41:08 +0100822 }
823 }
824
825 return len;
826}
827
Hans de Goede50b79632011-02-02 17:36:29 +0100828static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000829{
Hans de Goede50b79632011-02-02 17:36:29 +0100830 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000831 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000832 AsyncURB *aurb;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200833 int ret, rem, prem, v;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200834 uint8_t *pbuf;
Hans de Goede060dc842010-11-26 11:41:08 +0100835 uint8_t ep;
836
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200837 trace_usb_host_req_data(s->bus_num, s->addr,
838 p->pid == USB_TOKEN_IN,
839 p->devep, p->iov.size);
840
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200841 if (!is_valid(s, p->pid, p->devep)) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200842 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100843 return USB_RET_NAK;
844 }
845
Hans de Goede060dc842010-11-26 11:41:08 +0100846 if (p->pid == USB_TOKEN_IN) {
847 ep = p->devep | 0x80;
848 } else {
849 ep = p->devep;
850 }
851
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200852 if (is_halted(s, p->pid, p->devep)) {
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200853 unsigned int arg = ep;
854 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
Hans de Goede060dc842010-11-26 11:41:08 +0100855 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200856 perror("USBDEVFS_CLEAR_HALT");
857 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Hans de Goede060dc842010-11-26 11:41:08 +0100858 return USB_RET_NAK;
859 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200860 clear_halt(s, p->pid, p->devep);
Hans de Goede060dc842010-11-26 11:41:08 +0100861 }
862
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200863 if (is_isoc(s, p->pid, p->devep)) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100864 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
865 }
bellardbb36d472005-11-05 14:22:28 +0000866
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200867 v = 0;
868 prem = p->iov.iov[v].iov_len;
869 pbuf = p->iov.iov[v].iov_base;
870 rem = p->iov.size;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200871 while (rem) {
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200872 if (prem == 0) {
873 v++;
874 assert(v < p->iov.niov);
875 prem = p->iov.iov[v].iov_len;
876 pbuf = p->iov.iov[v].iov_base;
877 assert(prem <= rem);
878 }
Gerd Hoffmann71138532011-05-16 10:21:51 +0200879 aurb = async_alloc(s);
880 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000881
Gerd Hoffmann71138532011-05-16 10:21:51 +0200882 urb = &aurb->urb;
883 urb->endpoint = ep;
884 urb->type = USBDEVFS_URB_TYPE_BULK;
885 urb->usercontext = s;
886 urb->buffer = pbuf;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200887 urb->buffer_length = prem;
aliguori64838172008-08-21 19:31:10 +0000888
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200889 if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
Gerd Hoffmann71138532011-05-16 10:21:51 +0200890 urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200891 }
892 pbuf += urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200893 prem -= urb->buffer_length;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200894 rem -= urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200895 if (rem) {
896 aurb->more = 1;
897 }
aliguori64838172008-08-21 19:31:10 +0000898
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200899 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
900 urb->buffer_length, aurb->more);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200901 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
aliguori64838172008-08-21 19:31:10 +0000902
Gerd Hoffmann71138532011-05-16 10:21:51 +0200903 DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
904 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
aliguori64838172008-08-21 19:31:10 +0000905
Gerd Hoffmann71138532011-05-16 10:21:51 +0200906 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200907 perror("USBDEVFS_SUBMITURB");
Gerd Hoffmann71138532011-05-16 10:21:51 +0200908 async_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000909
Gerd Hoffmann71138532011-05-16 10:21:51 +0200910 switch(errno) {
911 case ETIMEDOUT:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200912 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200913 return USB_RET_NAK;
914 case EPIPE:
915 default:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200916 trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200917 return USB_RET_STALL;
918 }
balrogb9dc0332007-10-04 22:47:34 +0000919 }
920 }
aliguori64838172008-08-21 19:31:10 +0000921
balrogb9dc0332007-10-04 22:47:34 +0000922 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000923}
924
aliguori446ab122008-09-14 01:06:09 +0000925static int ctrl_error(void)
926{
David Ahern27911042010-04-24 10:26:22 -0600927 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000928 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600929 } else {
aliguori446ab122008-09-14 01:06:09 +0000930 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600931 }
aliguori446ab122008-09-14 01:06:09 +0000932}
933
934static int usb_host_set_address(USBHostDevice *s, int addr)
935{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200936 trace_usb_host_set_address(s->bus_num, s->addr, addr);
aliguori446ab122008-09-14 01:06:09 +0000937 s->dev.addr = addr;
938 return 0;
939}
940
941static int usb_host_set_config(USBHostDevice *s, int config)
942{
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200943 int ret, first = 1;
944
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200945 trace_usb_host_set_config(s->bus_num, s->addr, config);
946
aliguori446ab122008-09-14 01:06:09 +0000947 usb_host_release_interfaces(s);
948
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200949again:
950 ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600951
malcd0f2c4c2010-02-07 02:03:50 +0300952 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600953
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200954 if (ret < 0 && errno == EBUSY && first) {
955 /* happens if usb device is in use by host drivers */
956 int count = usb_linux_get_num_interfaces(s);
957 if (count > 0) {
958 DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
959 usb_host_disconnect_ifaces(s, count);
960 first = 0;
961 goto again;
962 }
963 }
964
David Ahern27911042010-04-24 10:26:22 -0600965 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000966 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600967 }
aliguori446ab122008-09-14 01:06:09 +0000968 usb_host_claim_interfaces(s, config);
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200969 usb_linux_update_endp_table(s);
aliguori446ab122008-09-14 01:06:09 +0000970 return 0;
971}
972
973static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
974{
975 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100976 int i, ret;
977
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200978 trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
979
Hans de Goede3a4854b2010-11-26 15:02:16 +0100980 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200981 if (is_isoc(s, USB_TOKEN_IN, i)) {
982 usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
983 }
984 if (is_isoc(s, USB_TOKEN_OUT, i)) {
985 usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
Hans de Goede060dc842010-11-26 11:41:08 +0100986 }
987 }
aliguori446ab122008-09-14 01:06:09 +0000988
989 si.interface = iface;
990 si.altsetting = alt;
991 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000992
David Ahern27911042010-04-24 10:26:22 -0600993 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
994 iface, alt, ret, errno);
995
996 if (ret < 0) {
997 return ctrl_error();
998 }
aliguori446ab122008-09-14 01:06:09 +0000999 usb_linux_update_endp_table(s);
1000 return 0;
1001}
1002
Hans de Goede50b79632011-02-02 17:36:29 +01001003static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
1004 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +00001005{
Hans de Goede50b79632011-02-02 17:36:29 +01001006 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +00001007 struct usbdevfs_urb *urb;
1008 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +01001009 int ret;
aliguori446ab122008-09-14 01:06:09 +00001010
David Ahern27911042010-04-24 10:26:22 -06001011 /*
aliguori446ab122008-09-14 01:06:09 +00001012 * Process certain standard device requests.
1013 * These are infrequent and are processed synchronously.
1014 */
aliguori446ab122008-09-14 01:06:09 +00001015
Hans de Goede50b79632011-02-02 17:36:29 +01001016 /* Note request is (bRequestType << 8) | bRequest */
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001017 trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
aliguori446ab122008-09-14 01:06:09 +00001018
Hans de Goede50b79632011-02-02 17:36:29 +01001019 switch (request) {
1020 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
1021 return usb_host_set_address(s, value);
aliguori446ab122008-09-14 01:06:09 +00001022
Hans de Goede50b79632011-02-02 17:36:29 +01001023 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
1024 return usb_host_set_config(s, value & 0xff);
aliguori446ab122008-09-14 01:06:09 +00001025
Hans de Goede50b79632011-02-02 17:36:29 +01001026 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
aliguori446ab122008-09-14 01:06:09 +00001027 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -06001028 }
aliguori446ab122008-09-14 01:06:09 +00001029
1030 /* The rest are asynchronous */
1031
Hans de Goede50b79632011-02-02 17:36:29 +01001032 if (length > sizeof(dev->data_buf)) {
1033 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
1034 length, sizeof(dev->data_buf));
malcb2e3b6e2009-09-12 03:18:18 +04001035 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -04001036 }
1037
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +02001038 aurb = async_alloc(s);
aliguori446ab122008-09-14 01:06:09 +00001039 aurb->packet = p;
1040
David Ahern27911042010-04-24 10:26:22 -06001041 /*
aliguori446ab122008-09-14 01:06:09 +00001042 * Setup ctrl transfer.
1043 *
Brad Hardsa0102082011-04-13 19:45:33 +10001044 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +00001045 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -06001046 */
aliguori446ab122008-09-14 01:06:09 +00001047 urb = &aurb->urb;
1048
1049 urb->type = USBDEVFS_URB_TYPE_CONTROL;
1050 urb->endpoint = p->devep;
1051
Hans de Goede50b79632011-02-02 17:36:29 +01001052 urb->buffer = &dev->setup_buf;
1053 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +00001054
1055 urb->usercontext = s;
1056
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001057 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
1058 urb->buffer_length, aurb->more);
aliguori446ab122008-09-14 01:06:09 +00001059 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
1060
malcd0f2c4c2010-02-07 02:03:50 +03001061 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +00001062
1063 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +03001064 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +00001065 async_free(aurb);
1066
1067 switch(errno) {
1068 case ETIMEDOUT:
1069 return USB_RET_NAK;
1070 case EPIPE:
1071 default:
1072 return USB_RET_STALL;
1073 }
1074 }
1075
aliguori446ab122008-09-14 01:06:09 +00001076 return USB_RET_ASYNC;
1077}
1078
Hans de Goedeed3a3282010-11-24 12:50:00 +01001079static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
1080 uint8_t configuration, uint8_t interface)
1081{
1082 uint8_t alt_setting;
1083 struct usb_ctrltransfer ct;
1084 int ret;
1085
Hans de Goedec43831f2010-11-24 12:57:59 +01001086 if (usb_fs_type == USB_FS_SYS) {
1087 char device_name[64], line[1024];
1088 int alt_setting;
1089
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001090 sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
Hans de Goedec43831f2010-11-24 12:57:59 +01001091 (int)configuration, (int)interface);
1092
1093 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
1094 device_name)) {
1095 goto usbdevfs;
1096 }
1097 if (sscanf(line, "%d", &alt_setting) != 1) {
1098 goto usbdevfs;
1099 }
1100 return alt_setting;
1101 }
1102
1103usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +01001104 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
1105 ct.bRequest = USB_REQ_GET_INTERFACE;
1106 ct.wValue = 0;
1107 ct.wIndex = interface;
1108 ct.wLength = 1;
1109 ct.data = &alt_setting;
1110 ct.timeout = 50;
1111 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
1112 if (ret < 0) {
1113 /* Assume alt 0 on error */
1114 return 0;
1115 }
1116
1117 return alt_setting;
1118}
1119
Hans de Goede71d71bb2010-11-10 10:06:24 +01001120/* returns 1 on problem encountered or 0 for success */
1121static int usb_linux_update_endp_table(USBHostDevice *s)
1122{
1123 uint8_t *descriptors;
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001124 uint8_t devep, type, alt_interface;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001125 int interface, length, i, ep, pid;
1126 struct endp_data *epd;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001127
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001128 for (i = 0; i < MAX_ENDPOINTS; i++) {
1129 s->ep_in[i].type = INVALID_EP_TYPE;
1130 s->ep_out[i].type = INVALID_EP_TYPE;
1131 }
Hans de Goedea0b5fec2010-11-26 14:56:17 +01001132
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001133 if (s->configuration == 0) {
1134 /* not configured yet -- leave all endpoints disabled */
1135 return 0;
1136 }
Hans de Goede71d71bb2010-11-10 10:06:24 +01001137
balrogb9dc0332007-10-04 22:47:34 +00001138 /* get the desired configuration, interface, and endpoint descriptors
1139 * from device description */
1140 descriptors = &s->descr[18];
1141 length = s->descr_len - 18;
1142 i = 0;
1143
1144 if (descriptors[i + 1] != USB_DT_CONFIG ||
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001145 descriptors[i + 5] != s->configuration) {
1146 fprintf(stderr, "invalid descriptor data - configuration %d\n",
1147 s->configuration);
balrogb9dc0332007-10-04 22:47:34 +00001148 return 1;
1149 }
1150 i += descriptors[i];
1151
1152 while (i < length) {
1153 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1154 (descriptors[i + 1] == USB_DT_INTERFACE &&
1155 descriptors[i + 4] == 0)) {
1156 i += descriptors[i];
1157 continue;
1158 }
1159
1160 interface = descriptors[i + 2];
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001161 alt_interface = usb_linux_get_alt_setting(s, s->configuration,
1162 interface);
balrogb9dc0332007-10-04 22:47:34 +00001163
1164 /* the current interface descriptor is the active interface
1165 * and has endpoints */
1166 if (descriptors[i + 3] != alt_interface) {
1167 i += descriptors[i];
1168 continue;
1169 }
1170
1171 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001172 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001173 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001174 }
balrogb9dc0332007-10-04 22:47:34 +00001175
1176 if (i >= length)
1177 break;
1178
1179 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001180 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001181 break;
David Ahern27911042010-04-24 10:26:22 -06001182 }
balrogb9dc0332007-10-04 22:47:34 +00001183
1184 devep = descriptors[i + 2];
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001185 pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
1186 ep = devep & 0xf;
1187 if (ep == 0) {
Hans de Goede130314f2011-05-31 11:35:22 +02001188 fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
1189 return 1;
1190 }
1191
balrogb9dc0332007-10-04 22:47:34 +00001192 switch (descriptors[i + 3] & 0x3) {
1193 case 0x00:
1194 type = USBDEVFS_URB_TYPE_CONTROL;
1195 break;
1196 case 0x01:
1197 type = USBDEVFS_URB_TYPE_ISO;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001198 set_max_packet_size(s, pid, ep, descriptors + i);
balrogb9dc0332007-10-04 22:47:34 +00001199 break;
1200 case 0x02:
1201 type = USBDEVFS_URB_TYPE_BULK;
1202 break;
1203 case 0x03:
1204 type = USBDEVFS_URB_TYPE_INTERRUPT;
1205 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -05001206 default:
1207 DPRINTF("usb_host: malformed endpoint type\n");
1208 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +00001209 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001210 epd = get_endp(s, pid, ep);
1211 assert(epd->type == INVALID_EP_TYPE);
1212 epd->type = type;
1213 epd->halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001214
1215 i += descriptors[i];
1216 }
1217 }
1218 return 0;
1219}
1220
Hans de Goedee4b17762011-05-30 11:40:45 +02001221/*
1222 * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
1223 * this function assumes this is safe, if:
1224 * 1) There are no isoc endpoints
1225 * 2) There are no interrupt endpoints with a max_packet_size > 64
1226 * Note bulk endpoints with a max_packet_size > 64 in theory also are not
1227 * usb1 compatible, but in practice this seems to work fine.
1228 */
1229static int usb_linux_full_speed_compat(USBHostDevice *dev)
1230{
1231 int i, packet_size;
1232
1233 /*
1234 * usb_linux_update_endp_table only registers info about ep in the current
1235 * interface altsettings, so we need to parse the descriptors again.
1236 */
1237 for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
1238 if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
1239 switch (dev->descr[i + 3] & 0x3) {
1240 case 0x00: /* CONTROL */
1241 break;
1242 case 0x01: /* ISO */
1243 return 0;
1244 case 0x02: /* BULK */
1245 break;
1246 case 0x03: /* INTERRUPT */
1247 packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
1248 if (packet_size > 64)
1249 return 0;
1250 break;
1251 }
1252 }
1253 }
1254 return 1;
1255}
1256
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001257static int usb_host_open(USBHostDevice *dev, int bus_num,
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001258 int addr, const char *port,
1259 const char *prod_name, int speed)
bellardbb36d472005-11-05 14:22:28 +00001260{
balrogb9dc0332007-10-04 22:47:34 +00001261 int fd = -1, ret;
bellarda594cfb2005-11-06 16:13:29 +00001262 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001263
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001264 trace_usb_host_open_started(bus_num, addr);
1265
David Ahern27911042010-04-24 10:26:22 -06001266 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001267 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001268 }
aliguori1f3870a2008-08-21 19:27:48 +00001269
aliguori0f431522008-10-07 20:06:37 +00001270 if (!usb_host_device_path) {
1271 perror("husb: USB Host Device Path not set");
1272 goto fail;
1273 }
1274 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001275 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001276 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001277 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001278 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001279 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001280 }
malcd0f2c4c2010-02-07 02:03:50 +03001281 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001282
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001283 dev->bus_num = bus_num;
1284 dev->addr = addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001285 strcpy(dev->port, port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001286 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001287
balrogb9dc0332007-10-04 22:47:34 +00001288 /* read the device description */
1289 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1290 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001291 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001292 goto fail;
1293 }
ths3b46e622007-09-17 08:09:54 +00001294
balrogb9dc0332007-10-04 22:47:34 +00001295#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001296 {
balrogb9dc0332007-10-04 22:47:34 +00001297 int x;
1298 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001299 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001300 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001301 }
balrogb9dc0332007-10-04 22:47:34 +00001302 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001303 }
1304#endif
1305
balrogb9dc0332007-10-04 22:47:34 +00001306
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001307 /* start unconfigured -- we'll wait for the guest to set a configuration */
1308 if (!usb_host_claim_interfaces(dev, 0)) {
balrogb9dc0332007-10-04 22:47:34 +00001309 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001310 }
bellardbb36d472005-11-05 14:22:28 +00001311
balrogb9dc0332007-10-04 22:47:34 +00001312 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001313 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001314 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001315 }
balrogb9dc0332007-10-04 22:47:34 +00001316
Hans de Goede3991c352011-05-31 11:35:18 +02001317 if (speed == -1) {
1318 struct usbdevfs_connectinfo ci;
1319
1320 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1321 if (ret < 0) {
1322 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
1323 goto fail;
1324 }
1325
1326 if (ci.slow) {
1327 speed = USB_SPEED_LOW;
1328 } else {
1329 speed = USB_SPEED_HIGH;
1330 }
David Ahern27911042010-04-24 10:26:22 -06001331 }
Hans de Goede3991c352011-05-31 11:35:18 +02001332 dev->dev.speed = speed;
Hans de Goedeba3f9bf2011-05-27 14:27:18 +02001333 dev->dev.speedmask = (1 << speed);
Hans de Goedee4b17762011-05-30 11:40:45 +02001334 if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
1335 dev->dev.speedmask |= USB_SPEED_MASK_FULL;
1336 }
Hans de Goede3991c352011-05-31 11:35:18 +02001337
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001338 trace_usb_host_open_success(bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001339
David Ahern27911042010-04-24 10:26:22 -06001340 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001341 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001342 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001343 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001344 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001345 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001346 }
bellard1f6e24e2006-06-26 21:00:51 +00001347
Hans de Goedefa19bf82011-05-27 19:05:15 +02001348 ret = usb_device_attach(&dev->dev);
1349 if (ret) {
1350 goto fail;
1351 }
1352
aliguori64838172008-08-21 19:31:10 +00001353 /* USB devio uses 'write' flag to check for async completions */
1354 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001355
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001356 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001357
balrogb9dc0332007-10-04 22:47:34 +00001358fail:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001359 trace_usb_host_open_failure(bus_num, addr);
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001360 if (dev->fd != -1) {
1361 close(dev->fd);
1362 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001363 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001364 return -1;
1365}
1366
1367static int usb_host_close(USBHostDevice *dev)
1368{
Hans de Goede060dc842010-11-26 11:41:08 +01001369 int i;
1370
Gerd Hoffmann39fba3a2011-10-28 16:13:50 +02001371 if (dev->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001372 return -1;
David Ahern27911042010-04-24 10:26:22 -06001373 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001374
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001375 trace_usb_host_close(dev->bus_num, dev->addr);
1376
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001377 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1378 dev->closing = 1;
Hans de Goede3a4854b2010-11-26 15:02:16 +01001379 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001380 if (is_isoc(dev, USB_TOKEN_IN, i)) {
1381 usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
1382 }
1383 if (is_isoc(dev, USB_TOKEN_OUT, i)) {
1384 usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
Hans de Goede060dc842010-11-26 11:41:08 +01001385 }
1386 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001387 async_complete(dev);
1388 dev->closing = 0;
Gerd Hoffmann39fba3a2011-10-28 16:13:50 +02001389 if (dev->dev.attached) {
1390 usb_device_detach(&dev->dev);
1391 }
Gerd Hoffmannc7662da2011-11-16 12:37:17 +01001392 usb_host_do_reset(dev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001393 close(dev->fd);
1394 dev->fd = -1;
1395 return 0;
1396}
1397
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001398static void usb_host_exit_notifier(struct Notifier *n, void *data)
Shahar Havivib373a632010-06-16 15:16:11 +03001399{
1400 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1401
1402 if (s->fd != -1) {
Gerd Hoffmannc7662da2011-11-16 12:37:17 +01001403 usb_host_do_reset(s);;
Shahar Havivib373a632010-06-16 15:16:11 +03001404 }
1405}
1406
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001407static int usb_host_initfn(USBDevice *dev)
1408{
1409 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1410
1411 dev->auto_attach = 0;
1412 s->fd = -1;
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001413 s->hub_fd = -1;
1414
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001415 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001416 s->exit.notify = usb_host_exit_notifier;
1417 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001418 usb_host_auto_check(NULL);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001419
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001420 if (s->match.bus_num != 0 && s->match.port != NULL) {
Gerd Hoffmanne6274722011-09-13 11:37:47 +02001421 usb_host_claim_port(s);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001422 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001423 return 0;
bellardbb36d472005-11-05 14:22:28 +00001424}
1425
Gerd Hoffmannd6791572011-08-31 11:44:24 +02001426static const VMStateDescription vmstate_usb_host = {
1427 .name = "usb-host",
1428 .unmigratable = 1,
1429};
1430
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001431static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001432 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001433 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001434 .qdev.size = sizeof(USBHostDevice),
Gerd Hoffmannd6791572011-08-31 11:44:24 +02001435 .qdev.vmsd = &vmstate_usb_host,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001436 .init = usb_host_initfn,
Hans de Goede50b79632011-02-02 17:36:29 +01001437 .handle_packet = usb_generic_handle_packet,
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +02001438 .cancel_packet = usb_host_async_cancel,
Hans de Goede50b79632011-02-02 17:36:29 +01001439 .handle_data = usb_host_handle_data,
1440 .handle_control = usb_host_handle_control,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001441 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001442 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001443 .usbdevice_name = "host",
1444 .usbdevice_init = usb_host_device_open,
1445 .qdev.props = (Property[]) {
1446 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1447 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001448 DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001449 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1450 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +02001451 DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001452 DEFINE_PROP_END_OF_LIST(),
1453 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001454};
1455
1456static void usb_host_register_devices(void)
1457{
1458 usb_qdev_register(&usb_host_dev_info);
1459}
1460device_init(usb_host_register_devices)
1461
aliguori4b096fc2008-08-21 19:28:55 +00001462USBDevice *usb_host_device_open(const char *devname)
1463{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001464 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001465 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001466 char *p;
1467
Markus Armbruster556cd092009-12-09 17:07:53 +01001468 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001469
aliguori5d0c5752008-09-14 01:07:41 +00001470 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001471 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001472 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001473 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001474 } else {
1475 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001476 filter.bus_num = strtoul(devname, NULL, 0);
1477 filter.addr = strtoul(p + 1, NULL, 0);
1478 filter.vendor_id = 0;
1479 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001480 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001481 filter.bus_num = 0;
1482 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001483 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001484 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001485 } else {
1486 goto fail;
1487 }
aliguori5d0c5752008-09-14 01:07:41 +00001488 }
1489
Markus Armbruster0745eb12009-11-27 13:05:53 +01001490 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1491 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001492 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1493 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001494 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001495 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001496
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001497fail:
1498 qdev_free(&dev->qdev);
1499 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001500}
aliguori5d0c5752008-09-14 01:07:41 +00001501
1502int usb_host_device_close(const char *devname)
1503{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001504#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001505 char product_name[PRODUCT_NAME_SZ];
1506 int bus_num, addr;
1507 USBHostDevice *s;
1508
David Ahern27911042010-04-24 10:26:22 -06001509 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001510 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001511 }
1512 if (usb_host_find_device(&bus_num, &addr, product_name,
1513 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001514 return -1;
David Ahern27911042010-04-24 10:26:22 -06001515 }
aliguori5d0c5752008-09-14 01:07:41 +00001516 s = hostdev_find(bus_num, addr);
1517 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001518 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001519 return 0;
1520 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001521#endif
aliguori5d0c5752008-09-14 01:07:41 +00001522
1523 return -1;
1524}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001525
bellarda594cfb2005-11-06 16:13:29 +00001526static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001527 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001528 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001529{
bellarda594cfb2005-11-06 16:13:29 +00001530 const char *p;
1531 char *q;
1532 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001533 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001534 return -1;
David Ahern27911042010-04-24 10:26:22 -06001535 }
bellarda594cfb2005-11-06 16:13:29 +00001536 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001537 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001538 p++;
David Ahern27911042010-04-24 10:26:22 -06001539 }
bellarda594cfb2005-11-06 16:13:29 +00001540 q = buf;
1541 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001542 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001543 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001544 }
bellarda594cfb2005-11-06 16:13:29 +00001545 p++;
1546 }
1547 *q = '\0';
1548 return q - buf;
1549}
bellardbb36d472005-11-05 14:22:28 +00001550
aliguori0f431522008-10-07 20:06:37 +00001551/*
1552 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1553 * host's USB devices. This is legacy support since many distributions
1554 * are moving to /sys/bus/usb
1555 */
1556static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001557{
Blue Swirl660f11b2009-07-31 21:16:51 +00001558 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001559 char line[1024];
1560 char buf[1024];
Gerd Hoffmann0c402e52011-08-17 23:36:46 +02001561 int bus_num, addr, speed, device_count;
1562 int class_id, product_id, vendor_id, port;
bellarda594cfb2005-11-06 16:13:29 +00001563 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001564 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001565
aliguori0f431522008-10-07 20:06:37 +00001566 if (!usb_host_device_path) {
1567 perror("husb: USB Host Device Path not set");
1568 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001569 }
aliguori0f431522008-10-07 20:06:37 +00001570 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1571 f = fopen(line, "r");
1572 if (!f) {
1573 perror("husb: cannot open devices file");
1574 goto the_end;
1575 }
1576
bellarda594cfb2005-11-06 16:13:29 +00001577 device_count = 0;
Gerd Hoffmann0c402e52011-08-17 23:36:46 +02001578 bus_num = addr = class_id = product_id = vendor_id = port = 0;
Hans de Goede3991c352011-05-31 11:35:18 +02001579 speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
bellardbb36d472005-11-05 14:22:28 +00001580 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001581 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001582 break;
David Ahern27911042010-04-24 10:26:22 -06001583 }
1584 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001585 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001586 }
bellarda594cfb2005-11-06 16:13:29 +00001587 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001588 if (device_count && (vendor_id || product_id)) {
1589 /* New device. Add the previously discovered device. */
Gerd Hoffmann0cd0fd02011-11-11 17:14:15 +01001590 if (port > 0) {
1591 snprintf(buf, sizeof(buf), "%d", port);
1592 } else {
1593 snprintf(buf, sizeof(buf), "?");
1594 }
1595 ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001596 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001597 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001598 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001599 }
bellarda594cfb2005-11-06 16:13:29 +00001600 }
David Ahern27911042010-04-24 10:26:22 -06001601 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001602 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001603 }
bellarda594cfb2005-11-06 16:13:29 +00001604 bus_num = atoi(buf);
Gerd Hoffmann0c402e52011-08-17 23:36:46 +02001605 if (get_tag_value(buf, sizeof(buf), line, "Port=", " ") < 0) {
1606 goto fail;
1607 }
1608 port = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001609 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 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 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001613 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001614 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001615 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001616 if (!strcmp(buf, "5000")) {
1617 speed = USB_SPEED_SUPER;
1618 } else if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001619 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001620 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001621 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001622 } else {
bellarda594cfb2005-11-06 16:13:29 +00001623 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001624 }
bellarda594cfb2005-11-06 16:13:29 +00001625 product_name[0] = '\0';
1626 class_id = 0xff;
1627 device_count++;
1628 product_id = 0;
1629 vendor_id = 0;
1630 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001631 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001632 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001633 }
bellarda594cfb2005-11-06 16:13:29 +00001634 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001635 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001636 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001637 }
bellarda594cfb2005-11-06 16:13:29 +00001638 product_id = strtoul(buf, NULL, 16);
1639 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001640 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001641 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001642 }
bellarda594cfb2005-11-06 16:13:29 +00001643 pstrcpy(product_name, sizeof(product_name), buf);
1644 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001645 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001646 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001647 }
bellarda594cfb2005-11-06 16:13:29 +00001648 class_id = strtoul(buf, NULL, 16);
1649 }
1650 fail: ;
1651 }
pbrook38ca0f62006-03-11 18:03:38 +00001652 if (device_count && (vendor_id || product_id)) {
1653 /* Add the last device. */
Gerd Hoffmann0c402e52011-08-17 23:36:46 +02001654 if (port > 0) {
1655 snprintf(buf, sizeof(buf), "%d", port);
1656 } else {
1657 snprintf(buf, sizeof(buf), "?");
1658 }
1659 ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001660 product_id, product_name, speed);
1661 }
1662 the_end:
David Ahern27911042010-04-24 10:26:22 -06001663 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001664 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001665 }
aliguori0f431522008-10-07 20:06:37 +00001666 return ret;
1667}
1668
1669/*
1670 * Read sys file-system device file
1671 *
1672 * @line address of buffer to put file contents in
1673 * @line_size size of line
1674 * @device_file path to device file (printf format string)
1675 * @device_name device being opened (inserted into device_file)
1676 *
1677 * @return 0 failed, 1 succeeded ('line' contains data)
1678 */
David Ahern27911042010-04-24 10:26:22 -06001679static int usb_host_read_file(char *line, size_t line_size,
1680 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001681{
1682 FILE *f;
1683 int ret = 0;
1684 char filename[PATH_MAX];
1685
blueswir1b4e237a2008-12-28 15:45:20 +00001686 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1687 device_file);
aliguori0f431522008-10-07 20:06:37 +00001688 f = fopen(filename, "r");
1689 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001690 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001691 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001692 }
1693
1694 return ret;
1695}
1696
1697/*
1698 * Use /sys/bus/usb/devices/ directory to determine host's USB
1699 * devices.
1700 *
1701 * This code is based on Robert Schiele's original patches posted to
1702 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1703 */
1704static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1705{
Blue Swirl660f11b2009-07-31 21:16:51 +00001706 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001707 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001708 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001709 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001710 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001711 char product_name[512];
1712 struct dirent *de;
1713
1714 dir = opendir(USBSYSBUS_PATH "/devices");
1715 if (!dir) {
1716 perror("husb: cannot open devices directory");
1717 goto the_end;
1718 }
1719
1720 while ((de = readdir(dir))) {
1721 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001722 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1723 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001724 }
aliguori0f431522008-10-07 20:06:37 +00001725
David Ahern27911042010-04-24 10:26:22 -06001726 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001727 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001728 }
1729 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001730 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001731 }
blueswir1b4e237a2008-12-28 15:45:20 +00001732 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001733 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001734 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001735 }
1736 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001737 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001738 }
aliguori0f431522008-10-07 20:06:37 +00001739
David Ahern27911042010-04-24 10:26:22 -06001740 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1741 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001742 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001743 }
1744 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001745 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001746 }
blueswir1b4e237a2008-12-28 15:45:20 +00001747 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001748 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001749 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001750 }
1751 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001752 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001753 }
blueswir1b4e237a2008-12-28 15:45:20 +00001754 if (!usb_host_read_file(line, sizeof(line), "product",
1755 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001756 *product_name = 0;
1757 } else {
David Ahern27911042010-04-24 10:26:22 -06001758 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001759 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001760 }
aliguori0f431522008-10-07 20:06:37 +00001761 pstrcpy(product_name, sizeof(product_name), line);
1762 }
1763
David Ahern27911042010-04-24 10:26:22 -06001764 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001765 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001766 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001767 if (!strcmp(line, "5000\n")) {
1768 speed = USB_SPEED_SUPER;
1769 } else if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001770 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001771 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001772 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001773 } else {
aliguori0f431522008-10-07 20:06:37 +00001774 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001775 }
aliguori0f431522008-10-07 20:06:37 +00001776
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001777 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001778 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001779 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001780 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001781 }
aliguori0f431522008-10-07 20:06:37 +00001782 }
1783 }
1784 the_end:
David Ahern27911042010-04-24 10:26:22 -06001785 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001786 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001787 }
aliguori0f431522008-10-07 20:06:37 +00001788 return ret;
1789}
1790
1791/*
1792 * Determine how to access the host's USB devices and call the
1793 * specific support function.
1794 */
1795static int usb_host_scan(void *opaque, USBScanFunc *func)
1796{
aliguori376253e2009-03-05 23:01:23 +00001797 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001798 FILE *f = NULL;
1799 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001800 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001801 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1802 char devpath[PATH_MAX];
1803
1804 /* only check the host once */
1805 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001806 dir = opendir(USBSYSBUS_PATH "/devices");
1807 if (dir) {
1808 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1809 strcpy(devpath, USBDEVBUS_PATH);
1810 usb_fs_type = USB_FS_SYS;
1811 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001812 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001813 goto found_devices;
1814 }
aliguori0f431522008-10-07 20:06:37 +00001815 f = fopen(USBPROCBUS_PATH "/devices", "r");
1816 if (f) {
1817 /* devices found in /proc/bus/usb/ */
1818 strcpy(devpath, USBPROCBUS_PATH);
1819 usb_fs_type = USB_FS_PROC;
1820 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001821 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001822 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001823 }
1824 /* try additional methods if an access method hasn't been found yet */
1825 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001826 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001827 /* devices found in /dev/bus/usb/ */
1828 strcpy(devpath, USBDEVBUS_PATH);
1829 usb_fs_type = USB_FS_DEV;
1830 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001831 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001832 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001833 }
aliguorif16a0db2008-10-21 16:34:20 +00001834 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001835 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001836 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001837 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001838 }
aliguorif16a0db2008-10-21 16:34:20 +00001839 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001840 }
1841
1842 /* the module setting (used later for opening devices) */
Anthony Liguori7267c092011-08-20 22:09:37 -05001843 usb_host_device_path = g_malloc0(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001844 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001845 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001846 monitor_printf(mon, "husb: using %s file-system with %s\n",
1847 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001848 }
aliguori0f431522008-10-07 20:06:37 +00001849 }
1850
1851 switch (usb_fs_type) {
1852 case USB_FS_PROC:
1853 case USB_FS_DEV:
1854 ret = usb_host_scan_dev(opaque, func);
1855 break;
1856 case USB_FS_SYS:
1857 ret = usb_host_scan_sys(opaque, func);
1858 break;
aliguorif16a0db2008-10-21 16:34:20 +00001859 default:
1860 ret = -EINVAL;
1861 break;
aliguori0f431522008-10-07 20:06:37 +00001862 }
bellarda594cfb2005-11-06 16:13:29 +00001863 return ret;
1864}
1865
aliguori4b096fc2008-08-21 19:28:55 +00001866static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001867
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001868static int usb_host_auto_scan(void *opaque, int bus_num,
1869 int addr, const char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001870 int class_id, int vendor_id, int product_id,
1871 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001872{
1873 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001874 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001875
1876 /* Ignore hubs */
1877 if (class_id == 9)
1878 return 0;
1879
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001880 QTAILQ_FOREACH(s, &hostdevs, next) {
1881 f = &s->match;
1882
David Ahern27911042010-04-24 10:26:22 -06001883 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001884 continue;
David Ahern27911042010-04-24 10:26:22 -06001885 }
1886 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001887 continue;
David Ahern27911042010-04-24 10:26:22 -06001888 }
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001889 if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
1890 continue;
1891 }
aliguori4b096fc2008-08-21 19:28:55 +00001892
David Ahern27911042010-04-24 10:26:22 -06001893 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001894 continue;
David Ahern27911042010-04-24 10:26:22 -06001895 }
aliguori4b096fc2008-08-21 19:28:55 +00001896
David Ahern27911042010-04-24 10:26:22 -06001897 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001898 continue;
David Ahern27911042010-04-24 10:26:22 -06001899 }
aliguori4b096fc2008-08-21 19:28:55 +00001900 /* We got a match */
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001901 s->seen++;
1902 if (s->errcount >= 3) {
1903 return 0;
1904 }
aliguori4b096fc2008-08-21 19:28:55 +00001905
Markus Armbruster33e66b82009-10-07 01:15:57 +02001906 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001907 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001908 return 0;
David Ahern27911042010-04-24 10:26:22 -06001909 }
malcd0f2c4c2010-02-07 02:03:50 +03001910 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001911
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001912 if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
1913 s->errcount++;
1914 }
Hans de Goede97f86162011-05-31 11:35:24 +02001915 break;
aliguori4b096fc2008-08-21 19:28:55 +00001916 }
1917
1918 return 0;
1919}
1920
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001921static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001922{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001923 struct USBHostDevice *s;
1924 int unconnected = 0;
1925
aliguori4b096fc2008-08-21 19:28:55 +00001926 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001927
1928 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001929 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001930 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001931 }
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001932 if (s->seen == 0) {
1933 s->errcount = 0;
1934 }
1935 s->seen = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001936 }
1937
1938 if (unconnected == 0) {
1939 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001940 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001941 qemu_del_timer(usb_auto_timer);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001942 trace_usb_host_auto_scan_disabled();
David Ahern27911042010-04-24 10:26:22 -06001943 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001944 return;
1945 }
1946
1947 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001948 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001949 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001950 return;
David Ahern27911042010-04-24 10:26:22 -06001951 }
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001952 trace_usb_host_auto_scan_enabled();
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001953 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001954 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001955}
1956
1957/*
aliguori5d0c5752008-09-14 01:07:41 +00001958 * Autoconnect filter
1959 * Format:
1960 * auto:bus:dev[:vid:pid]
1961 * auto:bus.dev[:vid:pid]
1962 *
1963 * bus - bus number (dec, * means any)
1964 * dev - device number (dec, * means any)
1965 * vid - vendor id (hex, * means any)
1966 * pid - product id (hex, * means any)
1967 *
1968 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001969 */
aliguori5d0c5752008-09-14 01:07:41 +00001970static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001971{
aliguori5d0c5752008-09-14 01:07:41 +00001972 enum { BUS, DEV, VID, PID, DONE };
1973 const char *p = spec;
1974 int i;
1975
Markus Armbruster0745eb12009-11-27 13:05:53 +01001976 f->bus_num = 0;
1977 f->addr = 0;
1978 f->vendor_id = 0;
1979 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001980
1981 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001982 p = strpbrk(p, ":.");
1983 if (!p) {
1984 break;
1985 }
aliguori5d0c5752008-09-14 01:07:41 +00001986 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001987
David Ahern27911042010-04-24 10:26:22 -06001988 if (*p == '*') {
1989 continue;
1990 }
aliguori5d0c5752008-09-14 01:07:41 +00001991 switch(i) {
1992 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1993 case DEV: f->addr = strtol(p, NULL, 10); break;
1994 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1995 case PID: f->product_id = strtol(p, NULL, 16); break;
1996 }
aliguori4b096fc2008-08-21 19:28:55 +00001997 }
1998
aliguori5d0c5752008-09-14 01:07:41 +00001999 if (i < DEV) {
2000 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
2001 return -1;
2002 }
2003
2004 return 0;
2005}
2006
bellarda594cfb2005-11-06 16:13:29 +00002007/**********************/
2008/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00002009
bellarda594cfb2005-11-06 16:13:29 +00002010struct usb_class_info {
2011 int class;
2012 const char *class_name;
2013};
2014
2015static const struct usb_class_info usb_class_info[] = {
2016 { USB_CLASS_AUDIO, "Audio"},
2017 { USB_CLASS_COMM, "Communication"},
2018 { USB_CLASS_HID, "HID"},
2019 { USB_CLASS_HUB, "Hub" },
2020 { USB_CLASS_PHYSICAL, "Physical" },
2021 { USB_CLASS_PRINTER, "Printer" },
2022 { USB_CLASS_MASS_STORAGE, "Storage" },
2023 { USB_CLASS_CDC_DATA, "Data" },
2024 { USB_CLASS_APP_SPEC, "Application Specific" },
2025 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
2026 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00002027 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00002028 { USB_CLASS_CONTENT_SEC, "Content Security" },
2029 { -1, NULL }
2030};
2031
2032static const char *usb_class_str(uint8_t class)
2033{
2034 const struct usb_class_info *p;
2035 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06002036 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00002037 break;
David Ahern27911042010-04-24 10:26:22 -06002038 }
bellardbb36d472005-11-05 14:22:28 +00002039 }
bellarda594cfb2005-11-06 16:13:29 +00002040 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00002041}
2042
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02002043static void usb_info_device(Monitor *mon, int bus_num,
2044 int addr, const char *port,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02002045 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00002046 const char *product_name,
2047 int speed)
bellardbb36d472005-11-05 14:22:28 +00002048{
bellarda594cfb2005-11-06 16:13:29 +00002049 const char *class_str, *speed_str;
2050
2051 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00002052 case USB_SPEED_LOW:
2053 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00002054 break;
ths5fafdf22007-09-16 21:08:06 +00002055 case USB_SPEED_FULL:
2056 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00002057 break;
ths5fafdf22007-09-16 21:08:06 +00002058 case USB_SPEED_HIGH:
2059 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00002060 break;
Hans de Goedef264cfb2011-05-31 11:35:19 +02002061 case USB_SPEED_SUPER:
2062 speed_str = "5000";
2063 break;
bellarda594cfb2005-11-06 16:13:29 +00002064 default:
ths5fafdf22007-09-16 21:08:06 +00002065 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00002066 break;
bellardbb36d472005-11-05 14:22:28 +00002067 }
bellarda594cfb2005-11-06 16:13:29 +00002068
Gerd Hoffmann5557d822011-05-10 11:43:57 +02002069 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
2070 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00002071 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06002072 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00002073 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06002074 } else {
aliguori376253e2009-03-05 23:01:23 +00002075 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06002076 }
aliguori376253e2009-03-05 23:01:23 +00002077 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06002078 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00002079 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06002080 }
aliguori376253e2009-03-05 23:01:23 +00002081 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00002082}
2083
ths5fafdf22007-09-16 21:08:06 +00002084static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02002085 const char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00002086 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00002087 const char *product_name,
2088 int speed)
2089{
Blue Swirl179da8a2009-09-07 19:00:18 +00002090 Monitor *mon = opaque;
2091
Gerd Hoffmann5557d822011-05-10 11:43:57 +02002092 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00002093 product_name, speed);
2094 return 0;
2095}
2096
aliguoriac4ffb52008-09-22 15:04:31 +00002097static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00002098{
David Ahern27911042010-04-24 10:26:22 -06002099 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00002100 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06002101 } else {
2102 snprintf(str, size, "%d", val);
2103 }
aliguori5d0c5752008-09-14 01:07:41 +00002104}
2105
aliguoriac4ffb52008-09-22 15:04:31 +00002106static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00002107{
David Ahern27911042010-04-24 10:26:22 -06002108 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00002109 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06002110 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002111 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06002112 }
aliguori5d0c5752008-09-14 01:07:41 +00002113}
2114
aliguori376253e2009-03-05 23:01:23 +00002115void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00002116{
aliguori5d0c5752008-09-14 01:07:41 +00002117 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002118 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00002119
Blue Swirl179da8a2009-09-07 19:00:18 +00002120 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00002121
David Ahern27911042010-04-24 10:26:22 -06002122 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002123 return;
David Ahern27911042010-04-24 10:26:22 -06002124 }
2125
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002126 monitor_printf(mon, " Auto filters:\n");
2127 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00002128 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01002129 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00002130 dec2str(f->bus_num, bus, sizeof(bus));
2131 dec2str(f->addr, addr, sizeof(addr));
2132 hex2str(f->vendor_id, vid, sizeof(vid));
2133 hex2str(f->product_id, pid, sizeof(pid));
Gerd Hoffmann9056a292011-05-10 12:07:42 +02002134 monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
2135 bus, addr, f->port ? f->port : "*", vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00002136 }
bellardbb36d472005-11-05 14:22:28 +00002137}