blob: 65cd3b444c9f06d75c78e7cd656057631650ed93 [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"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010034#include "qemu/timer.h"
Paolo Bonzini83c90892012-12-17 18:19:49 +010035#include "monitor/monitor.h"
Paolo Bonzini9c17d612012-12-17 18:20:04 +010036#include "sysemu/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"
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +020045#include "hw/usb/desc.h"
Gerd Hoffmann40759752013-01-23 14:15:38 +010046#include "hw/usb/host.h"
bellardbb36d472005-11-05 14:22:28 +000047
Gerd Hoffmann2b2325f2012-11-30 16:02:11 +010048#ifdef CONFIG_USB_LIBUSB
49# define DEVNAME "usb-host-linux"
50#else
51# define DEVNAME "usb-host"
52#endif
53
blueswir1d9cf1572008-09-15 14:57:11 +000054/* We redefine it to avoid version problems */
55struct usb_ctrltransfer {
56 uint8_t bRequestType;
57 uint8_t bRequest;
58 uint16_t wValue;
59 uint16_t wIndex;
60 uint16_t wLength;
61 uint32_t timeout;
62 void *data;
63};
64
Gerd Hoffmannba9acab2011-08-17 23:35:45 +020065typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
Hans de Goede0f5160d2010-11-10 10:06:23 +010066 int class_id, int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +000067 const char *product_name, int speed);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010068
Markus Armbruster0745eb12009-11-27 13:05:53 +010069//#define DEBUG
aliguori64838172008-08-21 19:31:10 +000070
71#ifdef DEBUG
malcd0f2c4c2010-02-07 02:03:50 +030072#define DPRINTF printf
aliguori64838172008-08-21 19:31:10 +000073#else
malcd0f2c4c2010-02-07 02:03:50 +030074#define DPRINTF(...)
aliguori64838172008-08-21 19:31:10 +000075#endif
bellardbb36d472005-11-05 14:22:28 +000076
bellard1f6e24e2006-06-26 21:00:51 +000077#define PRODUCT_NAME_SZ 32
Gerd Hoffmann5557d822011-05-10 11:43:57 +020078#define MAX_PORTLEN 16
bellardbb36d472005-11-05 14:22:28 +000079
balrogb9dc0332007-10-04 22:47:34 +000080/* endpoint association data */
Hans de Goede060dc842010-11-26 11:41:08 +010081#define ISO_FRAME_DESC_PER_URB 32
Hans de Goede060dc842010-11-26 11:41:08 +010082
Gerd Hoffmann71138532011-05-16 10:21:51 +020083/* devio.c limits single requests to 16k */
84#define MAX_USBFS_BUFFER_SIZE 16384
85
Hans de Goede060dc842010-11-26 11:41:08 +010086typedef struct AsyncURB AsyncURB;
87
balrogb9dc0332007-10-04 22:47:34 +000088struct endp_data {
aliguori64838172008-08-21 19:31:10 +000089 uint8_t halted;
Hans de Goedebb6d5492010-11-26 19:11:03 +010090 uint8_t iso_started;
Hans de Goede060dc842010-11-26 11:41:08 +010091 AsyncURB *iso_urb;
92 int iso_urb_idx;
Hans de Goedebb6d5492010-11-26 19:11:03 +010093 int iso_buffer_used;
Gerd Hoffmann82887262011-06-10 14:00:24 +020094 int inflight;
balrogb9dc0332007-10-04 22:47:34 +000095};
96
Gerd Hoffmann39c20572012-03-22 15:28:45 +010097enum USBHostDeviceOptions {
98 USB_HOST_OPT_PIPELINE,
99};
100
bellardbb36d472005-11-05 14:22:28 +0000101typedef struct USBHostDevice {
102 USBDevice dev;
aliguori64838172008-08-21 19:31:10 +0000103 int fd;
Gerd Hoffmann9516bb42011-08-24 13:34:17 +0200104 int hub_fd;
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100105 int hub_port;
aliguori64838172008-08-21 19:31:10 +0000106
Hans de Goedef8ddbfb2011-05-31 11:35:26 +0200107 uint8_t descr[8192];
aliguori64838172008-08-21 19:31:10 +0000108 int descr_len;
aliguori24772c12008-08-21 19:31:52 +0000109 int closing;
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200110 uint32_t iso_urb_count;
Gerd Hoffmann39c20572012-03-22 15:28:45 +0100111 uint32_t options;
Shahar Havivib373a632010-06-16 15:16:11 +0300112 Notifier exit;
Gerd Hoffmanna229c052012-06-08 13:02:16 +0200113 QEMUBH *bh;
aliguori64838172008-08-21 19:31:10 +0000114
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200115 struct endp_data ep_in[USB_MAX_ENDPOINTS];
116 struct endp_data ep_out[USB_MAX_ENDPOINTS];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200117 QLIST_HEAD(, AsyncURB) aurbs;
aliguori4b096fc2008-08-21 19:28:55 +0000118
aliguori4b096fc2008-08-21 19:28:55 +0000119 /* Host side address */
120 int bus_num;
121 int addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200122 char port[MAX_PORTLEN];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100123 struct USBAutoFilter match;
Gerd Hoffmann65bb3a52012-03-22 10:48:03 +0100124 int32_t bootindex;
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +0200125 int seen, errcount;
aliguori4b096fc2008-08-21 19:28:55 +0000126
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100127 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000128} USBHostDevice;
129
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100130static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
131
132static int usb_host_close(USBHostDevice *dev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100133static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100134static int usb_host_read_file(char *line, size_t line_size,
135 const char *device_file, const char *device_name);
Jan Kiszka537e8f12012-11-15 09:23:30 +0100136static void usb_linux_update_endp_table(USBHostDevice *s);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100137
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200138static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
139{
140 static const int usbfs[] = {
141 [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL,
142 [USB_ENDPOINT_XFER_ISOC] = USBDEVFS_URB_TYPE_ISO,
143 [USB_ENDPOINT_XFER_BULK] = USBDEVFS_URB_TYPE_BULK,
144 [USB_ENDPOINT_XFER_INT] = USBDEVFS_URB_TYPE_INTERRUPT,
145 };
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100146 uint8_t type = p->ep->type;
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200147 assert(type < ARRAY_SIZE(usbfs));
148 return usbfs[type];
149}
150
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);
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200174 assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200175 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 Hoffmannd8e17ef2011-08-29 12:49:46 +0200180 return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC;
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 Hoffmannd8e17ef2011-08-29 12:49:46 +0200185 return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID;
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 Hoffmannc32da152012-07-03 15:43:49 +0200214 trace_usb_host_iso_stop(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
Gerd Hoffmannc32da152012-07-03 15:43:49 +0200222 trace_usb_host_iso_start(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
David Ahern27911042010-04-24 10:26:22 -0600267/*
aliguori64838172008-08-21 19:31:10 +0000268 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100269 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600270 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000271 */
Hans de Goede060dc842010-11-26 11:41:08 +0100272struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000273{
aliguori64838172008-08-21 19:31:10 +0000274 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100275 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200276 USBHostDevice *hdev;
277 QLIST_ENTRY(AsyncURB) next;
aliguori64838172008-08-21 19:31:10 +0000278
Hans de Goede060dc842010-11-26 11:41:08 +0100279 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000280 USBPacket *packet;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200281 int more; /* large transfer, more urbs follow */
Hans de Goede060dc842010-11-26 11:41:08 +0100282
283 /* For buffered iso handling */
284 int iso_frame_idx; /* -1 means in flight */
285};
aliguori64838172008-08-21 19:31:10 +0000286
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200287static AsyncURB *async_alloc(USBHostDevice *s)
aliguori64838172008-08-21 19:31:10 +0000288{
Anthony Liguori7267c092011-08-20 22:09:37 -0500289 AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200290 aurb->hdev = s;
291 QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
292 return aurb;
balrogb9dc0332007-10-04 22:47:34 +0000293}
294
aliguori64838172008-08-21 19:31:10 +0000295static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000296{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200297 QLIST_REMOVE(aurb, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500298 g_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000299}
balrogb9dc0332007-10-04 22:47:34 +0000300
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200301static void do_disconnect(USBHostDevice *s)
302{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200303 usb_host_close(s);
304 usb_host_auto_check(NULL);
305}
306
aliguori64838172008-08-21 19:31:10 +0000307static void async_complete(void *opaque)
308{
309 USBHostDevice *s = opaque;
310 AsyncURB *aurb;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200311 int urbs = 0;
balrogb9dc0332007-10-04 22:47:34 +0000312
aliguori64838172008-08-21 19:31:10 +0000313 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600314 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000315
David Ahern27911042010-04-24 10:26:22 -0600316 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000317 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600318 if (errno == EAGAIN) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200319 if (urbs > 2) {
Gerd Hoffmannc32da152012-07-03 15:43:49 +0200320 /* indicates possible latency issues */
321 trace_usb_host_iso_many_urbs(s->bus_num, s->addr, urbs);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200322 }
aliguori64838172008-08-21 19:31:10 +0000323 return;
David Ahern27911042010-04-24 10:26:22 -0600324 }
Gerd Hoffmann40197c32011-08-22 14:18:21 +0200325 if (errno == ENODEV) {
326 if (!s->closing) {
327 trace_usb_host_disconnect(s->bus_num, s->addr);
328 do_disconnect(s);
329 }
aliguori64838172008-08-21 19:31:10 +0000330 return;
331 }
332
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200333 perror("USBDEVFS_REAPURBNDELAY");
aliguori64838172008-08-21 19:31:10 +0000334 return;
balrogb9dc0332007-10-04 22:47:34 +0000335 }
aliguori64838172008-08-21 19:31:10 +0000336
David Ahern27911042010-04-24 10:26:22 -0600337 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000338 aurb, aurb->urb.status, aurb->urb.actual_length);
339
Hans de Goede060dc842010-11-26 11:41:08 +0100340 /* If this is a buffered iso urb mark it as complete and don't do
341 anything else (it is handled further in usb_host_handle_iso_data) */
342 if (aurb->iso_frame_idx == -1) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200343 int inflight;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200344 int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
345 USB_TOKEN_IN : USB_TOKEN_OUT;
346 int ep = aurb->urb.endpoint & 0xf;
Hans de Goede060dc842010-11-26 11:41:08 +0100347 if (aurb->urb.status == -EPIPE) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200348 set_halt(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100349 }
350 aurb->iso_frame_idx = 0;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200351 urbs++;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200352 inflight = change_iso_inflight(s, pid, ep, -1);
353 if (inflight == 0 && is_iso_started(s, pid, ep)) {
Gerd Hoffmannc32da152012-07-03 15:43:49 +0200354 /* can be latency issues, or simply end of stream */
355 trace_usb_host_iso_out_of_bufs(s->bus_num, s->addr, ep);
Gerd Hoffmann82887262011-06-10 14:00:24 +0200356 }
Hans de Goede060dc842010-11-26 11:41:08 +0100357 continue;
358 }
359
360 p = aurb->packet;
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200361 trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
362 aurb->urb.actual_length, aurb->more);
Hans de Goede060dc842010-11-26 11:41:08 +0100363
David Ahern27911042010-04-24 10:26:22 -0600364 if (p) {
aliguori64838172008-08-21 19:31:10 +0000365 switch (aurb->urb.status) {
366 case 0:
Gerd Hoffmann71e0aa32012-11-15 16:11:49 +0100367 p->actual_length += aurb->urb.actual_length;
368 if (!aurb->more) {
369 /* Clear previous ASYNC status */
370 p->status = USB_RET_SUCCESS;
371 }
aliguori64838172008-08-21 19:31:10 +0000372 break;
373
374 case -EPIPE:
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100375 set_halt(s, p->pid, p->ep->nr);
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100376 p->status = USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600377 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200378
Hans de Goede4d819a92012-03-02 21:27:19 +0100379 case -EOVERFLOW:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100380 p->status = USB_RET_BABBLE;
Hans de Goede4d819a92012-03-02 21:27:19 +0100381 break;
382
aliguori64838172008-08-21 19:31:10 +0000383 default:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100384 p->status = USB_RET_IOERROR;
aliguori64838172008-08-21 19:31:10 +0000385 break;
386 }
387
Hans de Goede50b79632011-02-02 17:36:29 +0100388 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
Gerd Hoffmann8c908fc2012-11-15 16:11:20 +0100389 trace_usb_host_req_complete(s->bus_num, s->addr, p,
390 p->status, aurb->urb.actual_length);
Hans de Goede50b79632011-02-02 17:36:29 +0100391 usb_generic_async_ctrl_complete(&s->dev, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200392 } else if (!aurb->more) {
Gerd Hoffmann8c908fc2012-11-15 16:11:20 +0100393 trace_usb_host_req_complete(s->bus_num, s->addr, p,
394 p->status, aurb->urb.actual_length);
Hans de Goede50b79632011-02-02 17:36:29 +0100395 usb_packet_complete(&s->dev, p);
396 }
David Ahern27911042010-04-24 10:26:22 -0600397 }
aliguori64838172008-08-21 19:31:10 +0000398
399 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000400 }
balrogb9dc0332007-10-04 22:47:34 +0000401}
402
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200403static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
balrogb9dc0332007-10-04 22:47:34 +0000404{
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200405 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200406 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000407
Gerd Hoffmann19b89252012-03-23 12:35:55 +0100408 trace_usb_host_req_canceled(s->bus_num, s->addr, p);
Gerd Hoffmann6aebe402012-03-23 12:26:59 +0100409
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200410 QLIST_FOREACH(aurb, &s->aurbs, next) {
411 if (p != aurb->packet) {
412 continue;
413 }
balrogb9dc0332007-10-04 22:47:34 +0000414
Gerd Hoffmann6aebe402012-03-23 12:26:59 +0100415 trace_usb_host_urb_canceled(s->bus_num, s->addr, aurb);
aliguori64838172008-08-21 19:31:10 +0000416
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200417 /* Mark it as dead (see async_complete above) */
418 aurb->packet = NULL;
419
420 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
421 if (r < 0) {
422 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
423 }
balrogb9dc0332007-10-04 22:47:34 +0000424 }
balrogb9dc0332007-10-04 22:47:34 +0000425}
426
Gerd Hoffmann097db432011-12-16 11:54:11 +0100427static int usb_host_open_device(int bus, int addr)
428{
429 const char *usbfs = NULL;
430 char filename[32];
431 struct stat st;
432 int fd, rc;
433
434 rc = stat("/dev/bus/usb", &st);
435 if (rc == 0 && S_ISDIR(st.st_mode)) {
436 /* udev-created device nodes available */
437 usbfs = "/dev/bus/usb";
438 } else {
439 /* fallback: usbfs mounted below /proc */
440 usbfs = "/proc/bus/usb";
441 }
442
443 snprintf(filename, sizeof(filename), "%s/%03d/%03d",
444 usbfs, bus, addr);
445 fd = open(filename, O_RDWR | O_NONBLOCK);
446 if (fd < 0) {
447 fprintf(stderr, "husb: open %s: %s\n", filename, strerror(errno));
448 }
449 return fd;
450}
451
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200452static int usb_host_claim_port(USBHostDevice *s)
453{
454#ifdef USBDEVFS_CLAIM_PORT
455 char *h, hub_name[64], line[1024];
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100456 int hub_addr, ret;
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200457
458 snprintf(hub_name, sizeof(hub_name), "%d-%s",
459 s->match.bus_num, s->match.port);
460
461 /* try strip off last ".$portnr" to get hub */
462 h = strrchr(hub_name, '.');
463 if (h != NULL) {
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100464 s->hub_port = atoi(h+1);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200465 *h = '\0';
466 } else {
467 /* no dot in there -> it is the root hub */
468 snprintf(hub_name, sizeof(hub_name), "usb%d",
469 s->match.bus_num);
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100470 s->hub_port = atoi(s->match.port);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200471 }
472
473 if (!usb_host_read_file(line, sizeof(line), "devnum",
474 hub_name)) {
475 return -1;
476 }
477 if (sscanf(line, "%d", &hub_addr) != 1) {
478 return -1;
479 }
480
Gerd Hoffmann097db432011-12-16 11:54:11 +0100481 s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200482 if (s->hub_fd < 0) {
483 return -1;
484 }
485
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100486 ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200487 if (ret < 0) {
488 close(s->hub_fd);
489 s->hub_fd = -1;
490 return -1;
491 }
492
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100493 trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200494 return 0;
495#else
496 return -1;
497#endif
498}
499
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100500static void usb_host_release_port(USBHostDevice *s)
501{
502 if (s->hub_fd == -1) {
503 return;
504 }
505#ifdef USBDEVFS_RELEASE_PORT
506 ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
507#endif
508 close(s->hub_fd);
509 s->hub_fd = -1;
510}
511
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200512static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
513{
514 /* earlier Linux 2.4 do not support that */
515#ifdef USBDEVFS_DISCONNECT
516 struct usbdevfs_ioctl ctrl;
517 int ret, interface;
518
519 for (interface = 0; interface < nb_interfaces; interface++) {
520 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
521 ctrl.ifno = interface;
522 ctrl.data = 0;
523 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
524 if (ret < 0 && errno != ENODATA) {
525 perror("USBDEVFS_DISCONNECT");
526 return -1;
527 }
528 }
529#endif
530 return 0;
531}
532
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200533static int usb_linux_get_num_interfaces(USBHostDevice *s)
534{
535 char device_name[64], line[1024];
536 int num_interfaces = 0;
537
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200538 sprintf(device_name, "%d-%s", s->bus_num, s->port);
539 if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
540 device_name)) {
541 return -1;
542 }
543 if (sscanf(line, "%d", &num_interfaces) != 1) {
544 return -1;
545 }
546 return num_interfaces;
547}
548
aliguori446ab122008-09-14 01:06:09 +0000549static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000550{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200551 const char *op = NULL;
balrogb9dc0332007-10-04 22:47:34 +0000552 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000553 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000554 int ret, i;
555
Gerd Hoffmann1de14d42011-08-30 13:21:27 +0200556 for (i = 0; i < USB_MAX_INTERFACES; i++) {
557 dev->dev.altsetting[i] = 0;
558 }
559
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200560 if (configuration == 0) { /* address state - ignore */
Gerd Hoffmann65360512011-08-30 11:11:29 +0200561 dev->dev.ninterfaces = 0;
562 dev->dev.configuration = 0;
balrogb9dc0332007-10-04 22:47:34 +0000563 return 1;
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200564 }
balrogb9dc0332007-10-04 22:47:34 +0000565
malcd0f2c4c2010-02-07 02:03:50 +0300566 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000567
balrogb9dc0332007-10-04 22:47:34 +0000568 i = 0;
569 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600570 if (dev_descr_len > dev->descr_len) {
Hans de Goede61c11172011-05-31 11:35:20 +0200571 fprintf(stderr, "husb: update iface failed. descr too short\n");
572 return 0;
David Ahern27911042010-04-24 10:26:22 -0600573 }
balrogb9dc0332007-10-04 22:47:34 +0000574
575 i += dev_descr_len;
576 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600577 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
578 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000579 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000580
balrogb9dc0332007-10-04 22:47:34 +0000581 if (dev->descr[i+1] != USB_DT_CONFIG) {
582 i += dev->descr[i];
583 continue;
584 }
585 config_descr_len = dev->descr[i];
586
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200587 DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000588
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200589 if (configuration == dev->descr[i + 5]) {
aliguori446ab122008-09-14 01:06:09 +0000590 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000591 break;
aliguori446ab122008-09-14 01:06:09 +0000592 }
balrogb9dc0332007-10-04 22:47:34 +0000593
594 i += config_descr_len;
595 }
596
597 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600598 fprintf(stderr,
599 "husb: update iface failed. no matching configuration\n");
Hans de Goede61c11172011-05-31 11:35:20 +0200600 return 0;
balrogb9dc0332007-10-04 22:47:34 +0000601 }
602 nb_interfaces = dev->descr[i + 4];
603
Gerd Hoffmanne6274722011-09-13 11:37:47 +0200604 if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
605 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000606 }
balrogb9dc0332007-10-04 22:47:34 +0000607
608 /* XXX: only grab if all interfaces are free */
609 for (interface = 0; interface < nb_interfaces; interface++) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200610 op = "USBDEVFS_CLAIMINTERFACE";
balrogb9dc0332007-10-04 22:47:34 +0000611 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
612 if (ret < 0) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200613 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000614 }
615 }
616
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200617 trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
618 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000619
Gerd Hoffmann65360512011-08-30 11:11:29 +0200620 dev->dev.ninterfaces = nb_interfaces;
621 dev->dev.configuration = configuration;
aliguori446ab122008-09-14 01:06:09 +0000622 return 1;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200623
624fail:
625 if (errno == ENODEV) {
626 do_disconnect(dev);
627 }
628 perror(op);
629 return 0;
aliguori446ab122008-09-14 01:06:09 +0000630}
631
632static int usb_host_release_interfaces(USBHostDevice *s)
633{
634 int ret, i;
635
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200636 trace_usb_host_release_interfaces(s->bus_num, s->addr);
aliguori446ab122008-09-14 01:06:09 +0000637
Gerd Hoffmann65360512011-08-30 11:11:29 +0200638 for (i = 0; i < s->dev.ninterfaces; i++) {
aliguori446ab122008-09-14 01:06:09 +0000639 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
640 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200641 perror("USBDEVFS_RELEASEINTERFACE");
aliguori446ab122008-09-14 01:06:09 +0000642 return 0;
643 }
644 }
balrogb9dc0332007-10-04 22:47:34 +0000645 return 1;
646}
647
bellard059809e2006-07-19 18:06:15 +0000648static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000649{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100650 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000651
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200652 trace_usb_host_reset(s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000653
Dong Xu Wangc7e775e2013-05-09 15:53:50 +0800654 usb_host_do_reset(s);
aliguori446ab122008-09-14 01:06:09 +0000655
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +0200656 usb_host_claim_interfaces(s, 0);
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200657 usb_linux_update_endp_table(s);
ths5fafdf22007-09-16 21:08:06 +0000658}
bellardbb36d472005-11-05 14:22:28 +0000659
bellard059809e2006-07-19 18:06:15 +0000660static void usb_host_handle_destroy(USBDevice *dev)
661{
662 USBHostDevice *s = (USBHostDevice *)dev;
663
Gerd Hoffmannc75fead2012-01-05 15:49:18 +0100664 usb_host_release_port(s);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100665 usb_host_close(s);
666 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300667 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000668}
669
Hans de Goede060dc842010-11-26 11:41:08 +0100670/* iso data is special, we need to keep enough urbs in flight to make sure
671 that the controller never runs out of them, otherwise the device will
672 likely suffer a buffer underrun / overrun. */
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200673static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100674{
675 AsyncURB *aurb;
Gerd Hoffmannf0033972011-08-31 16:09:27 +0200676 int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100677
Anthony Liguori7267c092011-08-20 22:09:37 -0500678 aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200679 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100680 aurb[i].urb.endpoint = ep;
681 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
Anthony Liguori7267c092011-08-20 22:09:37 -0500682 aurb[i].urb.buffer = g_malloc(aurb[i].urb.buffer_length);
Hans de Goede060dc842010-11-26 11:41:08 +0100683 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
684 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
685 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
686 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
687 aurb[i].urb.iso_frame_desc[j].length = len;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200688 if (pid == USB_TOKEN_IN) {
Hans de Goede060dc842010-11-26 11:41:08 +0100689 aurb[i].urb.endpoint |= 0x80;
690 /* Mark as fully consumed (idle) */
691 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
692 }
693 }
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200694 set_iso_urb(s, pid, ep, aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100695
696 return aurb;
697}
698
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200699static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
Hans de Goede060dc842010-11-26 11:41:08 +0100700{
701 AsyncURB *aurb;
702 int i, ret, killed = 0, free = 1;
703
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200704 aurb = get_iso_urb(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100705 if (!aurb) {
706 return;
707 }
708
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200709 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100710 /* in flight? */
711 if (aurb[i].iso_frame_idx == -1) {
712 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
713 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200714 perror("USBDEVFS_DISCARDURB");
Hans de Goede060dc842010-11-26 11:41:08 +0100715 free = 0;
716 continue;
717 }
718 killed++;
719 }
720 }
721
722 /* Make sure any urbs we've killed are reaped before we free them */
723 if (killed) {
724 async_complete(s);
725 }
726
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200727 for (i = 0; i < s->iso_urb_count; i++) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500728 g_free(aurb[i].urb.buffer);
Hans de Goede060dc842010-11-26 11:41:08 +0100729 }
730
731 if (free)
Anthony Liguori7267c092011-08-20 22:09:37 -0500732 g_free(aurb);
Hans de Goede060dc842010-11-26 11:41:08 +0100733 else
734 printf("husb: leaking iso urbs because of discard failure\n");
Gerd Hoffmannc0e57502011-08-26 16:27:41 +0200735 set_iso_urb(s, pid, ep, NULL);
736 set_iso_urb_idx(s, pid, ep, 0);
737 clear_iso_started(s, pid, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100738}
739
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100740static void urb_status_to_usb_ret(int status, USBPacket *p)
Hans de Goede060dc842010-11-26 11:41:08 +0100741{
742 switch (status) {
743 case -EPIPE:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100744 p->status = USB_RET_STALL;
745 break;
Hans de Goede4d819a92012-03-02 21:27:19 +0100746 case -EOVERFLOW:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100747 p->status = USB_RET_BABBLE;
748 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100749 default:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100750 p->status = USB_RET_IOERROR;
Hans de Goede060dc842010-11-26 11:41:08 +0100751 }
752}
753
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100754static void usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100755{
756 AsyncURB *aurb;
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100757 int i, j, max_packet_size, offset, len;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200758 uint8_t *buf;
Hans de Goede975f2992010-11-26 14:59:35 +0100759
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100760 max_packet_size = p->ep->max_packet_size;
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100761 if (max_packet_size == 0) {
762 p->status = USB_RET_NAK;
763 return;
764 }
Hans de Goede060dc842010-11-26 11:41:08 +0100765
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100766 aurb = get_iso_urb(s, p->pid, p->ep->nr);
Hans de Goede060dc842010-11-26 11:41:08 +0100767 if (!aurb) {
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100768 aurb = usb_host_alloc_iso(s, p->pid, p->ep->nr);
Hans de Goede060dc842010-11-26 11:41:08 +0100769 }
770
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100771 i = get_iso_urb_idx(s, p->pid, p->ep->nr);
Hans de Goede060dc842010-11-26 11:41:08 +0100772 j = aurb[i].iso_frame_idx;
773 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100774 if (in) {
775 /* Check urb status */
776 if (aurb[i].urb.status) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100777 urb_status_to_usb_ret(aurb[i].urb.status, p);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100778 /* Move to the next urb */
779 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
780 /* Check frame status */
781 } else if (aurb[i].urb.iso_frame_desc[j].status) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100782 urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status, p);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100783 /* Check the frame fits */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200784 } else if (aurb[i].urb.iso_frame_desc[j].actual_length
785 > p->iov.size) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100786 printf("husb: received iso data is larger then packet\n");
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100787 p->status = USB_RET_BABBLE;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100788 /* All good copy data over */
789 } else {
790 len = aurb[i].urb.iso_frame_desc[j].actual_length;
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200791 buf = aurb[i].urb.buffer +
792 j * aurb[i].urb.iso_frame_desc[0].length;
793 usb_packet_copy(p, buf, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100794 }
Hans de Goede060dc842010-11-26 11:41:08 +0100795 } else {
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200796 len = p->iov.size;
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100797 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->ep->nr);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100798
799 /* Check the frame fits */
800 if (len > max_packet_size) {
801 printf("husb: send iso data is larger then max packet size\n");
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100802 p->status = USB_RET_NAK;
803 return;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100804 }
805
806 /* All good copy data over */
Gerd Hoffmann4f4321c2011-07-12 15:22:25 +0200807 usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100808 aurb[i].urb.iso_frame_desc[j].length = len;
809 offset += len;
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100810 set_iso_buffer_used(s, p->pid, p->ep->nr, offset);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100811
812 /* Start the stream once we have buffered enough data */
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100813 if (!is_iso_started(s, p->pid, p->ep->nr) && i == 1 && j == 8) {
814 set_iso_started(s, p->pid, p->ep->nr);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100815 }
Hans de Goede060dc842010-11-26 11:41:08 +0100816 }
817 aurb[i].iso_frame_idx++;
818 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200819 i = (i + 1) % s->iso_urb_count;
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100820 set_iso_urb_idx(s, p->pid, p->ep->nr, i);
Hans de Goede060dc842010-11-26 11:41:08 +0100821 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100822 } else {
823 if (in) {
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100824 set_iso_started(s, p->pid, p->ep->nr);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100825 } else {
826 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
827 }
Hans de Goede060dc842010-11-26 11:41:08 +0100828 }
829
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100830 if (is_iso_started(s, p->pid, p->ep->nr)) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100831 /* (Re)-submit all fully consumed / filled urbs */
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200832 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100833 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100834 if (ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]) < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200835 perror("USBDEVFS_SUBMITURB");
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100836 if (!in || p->status == USB_RET_SUCCESS) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100837 switch(errno) {
838 case ETIMEDOUT:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100839 p->status = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200840 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100841 case EPIPE:
842 default:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100843 p->status = USB_RET_STALL;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100844 }
Hans de Goede060dc842010-11-26 11:41:08 +0100845 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100846 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100847 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100848 aurb[i].iso_frame_idx = -1;
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100849 change_iso_inflight(s, p->pid, p->ep->nr, 1);
Hans de Goede060dc842010-11-26 11:41:08 +0100850 }
Hans de Goede060dc842010-11-26 11:41:08 +0100851 }
852 }
Hans de Goede060dc842010-11-26 11:41:08 +0100853}
854
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100855static void usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000856{
Hans de Goede50b79632011-02-02 17:36:29 +0100857 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000858 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000859 AsyncURB *aurb;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200860 int ret, rem, prem, v;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200861 uint8_t *pbuf;
Hans de Goede060dc842010-11-26 11:41:08 +0100862 uint8_t ep;
863
Gerd Hoffmann19b89252012-03-23 12:35:55 +0100864 trace_usb_host_req_data(s->bus_num, s->addr, p,
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200865 p->pid == USB_TOKEN_IN,
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100866 p->ep->nr, p->iov.size);
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200867
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100868 if (!is_valid(s, p->pid, p->ep->nr)) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100869 p->status = USB_RET_NAK;
Gerd Hoffmann8c908fc2012-11-15 16:11:20 +0100870 trace_usb_host_req_complete(s->bus_num, s->addr, p,
871 p->status, p->actual_length);
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100872 return;
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100873 }
874
Hans de Goede060dc842010-11-26 11:41:08 +0100875 if (p->pid == USB_TOKEN_IN) {
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100876 ep = p->ep->nr | 0x80;
Hans de Goede060dc842010-11-26 11:41:08 +0100877 } else {
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100878 ep = p->ep->nr;
Hans de Goede060dc842010-11-26 11:41:08 +0100879 }
880
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100881 if (is_halted(s, p->pid, p->ep->nr)) {
Gerd Hoffmann9b87e192011-08-24 10:55:40 +0200882 unsigned int arg = ep;
883 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
Hans de Goede060dc842010-11-26 11:41:08 +0100884 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200885 perror("USBDEVFS_CLEAR_HALT");
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100886 p->status = USB_RET_NAK;
Gerd Hoffmann8c908fc2012-11-15 16:11:20 +0100887 trace_usb_host_req_complete(s->bus_num, s->addr, p,
888 p->status, p->actual_length);
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100889 return;
Hans de Goede060dc842010-11-26 11:41:08 +0100890 }
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100891 clear_halt(s, p->pid, p->ep->nr);
Hans de Goede060dc842010-11-26 11:41:08 +0100892 }
893
Gerd Hoffmann079d0b72012-01-12 13:23:01 +0100894 if (is_isoc(s, p->pid, p->ep->nr)) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100895 usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
896 return;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100897 }
bellardbb36d472005-11-05 14:22:28 +0000898
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200899 v = 0;
Gerd Hoffmann818d59d2012-04-19 13:35:07 +0200900 prem = 0;
901 pbuf = NULL;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200902 rem = p->iov.size;
Gerd Hoffmann0b377162012-04-19 13:36:40 +0200903 do {
904 if (prem == 0 && rem > 0) {
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200905 assert(v < p->iov.niov);
906 prem = p->iov.iov[v].iov_len;
907 pbuf = p->iov.iov[v].iov_base;
908 assert(prem <= rem);
Gerd Hoffmann818d59d2012-04-19 13:35:07 +0200909 v++;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200910 }
Gerd Hoffmann71138532011-05-16 10:21:51 +0200911 aurb = async_alloc(s);
912 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000913
Gerd Hoffmann71138532011-05-16 10:21:51 +0200914 urb = &aurb->urb;
915 urb->endpoint = ep;
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +0200916 urb->type = usb_host_usbfs_type(s, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200917 urb->usercontext = s;
918 urb->buffer = pbuf;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200919 urb->buffer_length = prem;
aliguori64838172008-08-21 19:31:10 +0000920
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200921 if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
Gerd Hoffmann71138532011-05-16 10:21:51 +0200922 urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200923 }
924 pbuf += urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200925 prem -= urb->buffer_length;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200926 rem -= urb->buffer_length;
Gerd Hoffmannb621bab2011-07-13 11:28:17 +0200927 if (rem) {
928 aurb->more = 1;
929 }
aliguori64838172008-08-21 19:31:10 +0000930
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200931 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
932 urb->buffer_length, aurb->more);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200933 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
aliguori64838172008-08-21 19:31:10 +0000934
Gerd Hoffmann71138532011-05-16 10:21:51 +0200935 DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
936 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
aliguori64838172008-08-21 19:31:10 +0000937
Gerd Hoffmann71138532011-05-16 10:21:51 +0200938 if (ret < 0) {
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200939 perror("USBDEVFS_SUBMITURB");
Gerd Hoffmann71138532011-05-16 10:21:51 +0200940 async_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000941
Gerd Hoffmann71138532011-05-16 10:21:51 +0200942 switch(errno) {
943 case ETIMEDOUT:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100944 p->status = USB_RET_NAK;
Gerd Hoffmann8c908fc2012-11-15 16:11:20 +0100945 trace_usb_host_req_complete(s->bus_num, s->addr, p,
946 p->status, p->actual_length);
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100947 break;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200948 case EPIPE:
949 default:
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100950 p->status = USB_RET_STALL;
Gerd Hoffmann8c908fc2012-11-15 16:11:20 +0100951 trace_usb_host_req_complete(s->bus_num, s->addr, p,
952 p->status, p->actual_length);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200953 }
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100954 return;
balrogb9dc0332007-10-04 22:47:34 +0000955 }
Gerd Hoffmann0b377162012-04-19 13:36:40 +0200956 } while (rem > 0);
aliguori64838172008-08-21 19:31:10 +0000957
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100958 p->status = USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000959}
960
aliguori446ab122008-09-14 01:06:09 +0000961static int ctrl_error(void)
962{
David Ahern27911042010-04-24 10:26:22 -0600963 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000964 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600965 } else {
aliguori446ab122008-09-14 01:06:09 +0000966 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600967 }
aliguori446ab122008-09-14 01:06:09 +0000968}
969
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100970static void usb_host_set_address(USBHostDevice *s, int addr)
aliguori446ab122008-09-14 01:06:09 +0000971{
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200972 trace_usb_host_set_address(s->bus_num, s->addr, addr);
aliguori446ab122008-09-14 01:06:09 +0000973 s->dev.addr = addr;
aliguori446ab122008-09-14 01:06:09 +0000974}
975
Hans de Goede9a77a0f2012-11-01 17:15:01 +0100976static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p)
aliguori446ab122008-09-14 01:06:09 +0000977{
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200978 int ret, first = 1;
979
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +0200980 trace_usb_host_set_config(s->bus_num, s->addr, config);
981
aliguori446ab122008-09-14 01:06:09 +0000982 usb_host_release_interfaces(s);
983
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200984again:
985 ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600986
malcd0f2c4c2010-02-07 02:03:50 +0300987 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600988
Gerd Hoffmann0fcc3bf2011-09-13 11:55:15 +0200989 if (ret < 0 && errno == EBUSY && first) {
990 /* happens if usb device is in use by host drivers */
991 int count = usb_linux_get_num_interfaces(s);
992 if (count > 0) {
993 DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
994 usb_host_disconnect_ifaces(s, count);
995 first = 0;
996 goto again;
997 }
998 }
999
David Ahern27911042010-04-24 10:26:22 -06001000 if (ret < 0) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001001 p->status = ctrl_error();
1002 return;
David Ahern27911042010-04-24 10:26:22 -06001003 }
aliguori446ab122008-09-14 01:06:09 +00001004 usb_host_claim_interfaces(s, config);
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001005 usb_linux_update_endp_table(s);
aliguori446ab122008-09-14 01:06:09 +00001006}
1007
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001008static void usb_host_set_interface(USBHostDevice *s, int iface, int alt,
1009 USBPacket *p)
aliguori446ab122008-09-14 01:06:09 +00001010{
1011 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +01001012 int i, ret;
1013
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001014 trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
1015
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +02001016 for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001017 if (is_isoc(s, USB_TOKEN_IN, i)) {
1018 usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
1019 }
1020 if (is_isoc(s, USB_TOKEN_OUT, i)) {
1021 usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
Hans de Goede060dc842010-11-26 11:41:08 +01001022 }
1023 }
aliguori446ab122008-09-14 01:06:09 +00001024
Gerd Hoffmann1de14d42011-08-30 13:21:27 +02001025 if (iface >= USB_MAX_INTERFACES) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001026 p->status = USB_RET_STALL;
1027 return;
Gerd Hoffmann1de14d42011-08-30 13:21:27 +02001028 }
1029
aliguori446ab122008-09-14 01:06:09 +00001030 si.interface = iface;
1031 si.altsetting = alt;
1032 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +00001033
David Ahern27911042010-04-24 10:26:22 -06001034 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
1035 iface, alt, ret, errno);
1036
1037 if (ret < 0) {
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001038 p->status = ctrl_error();
1039 return;
David Ahern27911042010-04-24 10:26:22 -06001040 }
Gerd Hoffmann1de14d42011-08-30 13:21:27 +02001041
1042 s->dev.altsetting[iface] = alt;
aliguori446ab122008-09-14 01:06:09 +00001043 usb_linux_update_endp_table(s);
aliguori446ab122008-09-14 01:06:09 +00001044}
1045
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001046static void usb_host_handle_control(USBDevice *dev, USBPacket *p,
Hans de Goede50b79632011-02-02 17:36:29 +01001047 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +00001048{
Hans de Goede50b79632011-02-02 17:36:29 +01001049 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +00001050 struct usbdevfs_urb *urb;
1051 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +01001052 int ret;
aliguori446ab122008-09-14 01:06:09 +00001053
David Ahern27911042010-04-24 10:26:22 -06001054 /*
aliguori446ab122008-09-14 01:06:09 +00001055 * Process certain standard device requests.
1056 * These are infrequent and are processed synchronously.
1057 */
aliguori446ab122008-09-14 01:06:09 +00001058
Hans de Goede50b79632011-02-02 17:36:29 +01001059 /* Note request is (bRequestType << 8) | bRequest */
Gerd Hoffmann19b89252012-03-23 12:35:55 +01001060 trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
aliguori446ab122008-09-14 01:06:09 +00001061
Hans de Goede50b79632011-02-02 17:36:29 +01001062 switch (request) {
1063 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001064 usb_host_set_address(s, value);
1065 trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
1066 return;
aliguori446ab122008-09-14 01:06:09 +00001067
Hans de Goede50b79632011-02-02 17:36:29 +01001068 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001069 usb_host_set_config(s, value & 0xff, p);
1070 trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
1071 return;
aliguori446ab122008-09-14 01:06:09 +00001072
Hans de Goede50b79632011-02-02 17:36:29 +01001073 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001074 usb_host_set_interface(s, index, value, p);
1075 trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
1076 return;
Gerd Hoffmanna2498f72012-05-08 13:54:45 +02001077
1078 case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
1079 if (value == 0) { /* clear halt */
1080 int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
1081 ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index);
1082 clear_halt(s, pid, index & 0x0f);
1083 trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0);
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001084 return;
Gerd Hoffmanna2498f72012-05-08 13:54:45 +02001085 }
David Ahern27911042010-04-24 10:26:22 -06001086 }
aliguori446ab122008-09-14 01:06:09 +00001087
1088 /* The rest are asynchronous */
Hans de Goede50b79632011-02-02 17:36:29 +01001089 if (length > sizeof(dev->data_buf)) {
1090 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
1091 length, sizeof(dev->data_buf));
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001092 p->status = USB_RET_STALL;
1093 return;
Jim Parisc4c0e232009-08-24 14:56:12 -04001094 }
1095
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +02001096 aurb = async_alloc(s);
aliguori446ab122008-09-14 01:06:09 +00001097 aurb->packet = p;
1098
David Ahern27911042010-04-24 10:26:22 -06001099 /*
aliguori446ab122008-09-14 01:06:09 +00001100 * Setup ctrl transfer.
1101 *
Brad Hardsa0102082011-04-13 19:45:33 +10001102 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +00001103 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -06001104 */
aliguori446ab122008-09-14 01:06:09 +00001105 urb = &aurb->urb;
1106
1107 urb->type = USBDEVFS_URB_TYPE_CONTROL;
Gerd Hoffmann079d0b72012-01-12 13:23:01 +01001108 urb->endpoint = p->ep->nr;
aliguori446ab122008-09-14 01:06:09 +00001109
Hans de Goede50b79632011-02-02 17:36:29 +01001110 urb->buffer = &dev->setup_buf;
1111 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +00001112
1113 urb->usercontext = s;
1114
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001115 trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
1116 urb->buffer_length, aurb->more);
aliguori446ab122008-09-14 01:06:09 +00001117 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
1118
malcd0f2c4c2010-02-07 02:03:50 +03001119 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +00001120
1121 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +03001122 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +00001123 async_free(aurb);
1124
1125 switch(errno) {
1126 case ETIMEDOUT:
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001127 p->status = USB_RET_NAK;
1128 break;
aliguori446ab122008-09-14 01:06:09 +00001129 case EPIPE:
1130 default:
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001131 p->status = USB_RET_STALL;
1132 break;
aliguori446ab122008-09-14 01:06:09 +00001133 }
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001134 return;
aliguori446ab122008-09-14 01:06:09 +00001135 }
1136
Hans de Goede9a77a0f2012-11-01 17:15:01 +01001137 p->status = USB_RET_ASYNC;
aliguori446ab122008-09-14 01:06:09 +00001138}
1139
Jan Kiszka537e8f12012-11-15 09:23:30 +01001140static void usb_linux_update_endp_table(USBHostDevice *s)
Hans de Goede71d71bb2010-11-10 10:06:24 +01001141{
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001142 static const char *tname[] = {
1143 [USB_ENDPOINT_XFER_CONTROL] = "control",
1144 [USB_ENDPOINT_XFER_ISOC] = "isoc",
1145 [USB_ENDPOINT_XFER_BULK] = "bulk",
1146 [USB_ENDPOINT_XFER_INT] = "int",
1147 };
1148 uint8_t devep, type;
1149 uint16_t mps, v, p;
1150 int ep, pid;
1151 unsigned int i, configuration = -1, interface = -1, altsetting = -1;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001152 struct endp_data *epd;
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001153 USBDescriptor *d;
1154 bool active = false;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001155
Gerd Hoffmann19deaa02012-07-03 10:11:21 +02001156 usb_ep_reset(&s->dev);
Hans de Goedea0b5fec2010-11-26 14:56:17 +01001157
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001158 for (i = 0;; i += d->bLength) {
1159 if (i+2 >= s->descr_len) {
balrogb9dc0332007-10-04 22:47:34 +00001160 break;
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001161 }
1162 d = (void *)(s->descr + i);
1163 if (d->bLength < 2) {
1164 trace_usb_host_parse_error(s->bus_num, s->addr,
1165 "descriptor too short");
Jan Kiszka537e8f12012-11-15 09:23:30 +01001166 return;
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001167 }
1168 if (i + d->bLength > s->descr_len) {
1169 trace_usb_host_parse_error(s->bus_num, s->addr,
1170 "descriptor too long");
Jan Kiszka537e8f12012-11-15 09:23:30 +01001171 return;
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001172 }
1173 switch (d->bDescriptorType) {
1174 case 0:
1175 trace_usb_host_parse_error(s->bus_num, s->addr,
1176 "invalid descriptor type");
Jan Kiszka537e8f12012-11-15 09:23:30 +01001177 return;
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001178 case USB_DT_DEVICE:
1179 if (d->bLength < 0x12) {
1180 trace_usb_host_parse_error(s->bus_num, s->addr,
1181 "device descriptor too short");
Jan Kiszka537e8f12012-11-15 09:23:30 +01001182 return;
David Ahern27911042010-04-24 10:26:22 -06001183 }
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001184 v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo;
1185 p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo;
1186 trace_usb_host_parse_device(s->bus_num, s->addr, v, p);
1187 break;
1188 case USB_DT_CONFIG:
1189 if (d->bLength < 0x09) {
1190 trace_usb_host_parse_error(s->bus_num, s->addr,
1191 "config descriptor too short");
Jan Kiszka537e8f12012-11-15 09:23:30 +01001192 return;
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001193 }
1194 configuration = d->u.config.bConfigurationValue;
1195 active = (configuration == s->dev.configuration);
1196 trace_usb_host_parse_config(s->bus_num, s->addr,
1197 configuration, active);
1198 break;
1199 case USB_DT_INTERFACE:
1200 if (d->bLength < 0x09) {
1201 trace_usb_host_parse_error(s->bus_num, s->addr,
1202 "interface descriptor too short");
Jan Kiszka537e8f12012-11-15 09:23:30 +01001203 return;
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001204 }
1205 interface = d->u.interface.bInterfaceNumber;
1206 altsetting = d->u.interface.bAlternateSetting;
1207 active = (configuration == s->dev.configuration) &&
1208 (altsetting == s->dev.altsetting[interface]);
1209 trace_usb_host_parse_interface(s->bus_num, s->addr,
1210 interface, altsetting, active);
1211 break;
1212 case USB_DT_ENDPOINT:
1213 if (d->bLength < 0x07) {
1214 trace_usb_host_parse_error(s->bus_num, s->addr,
1215 "endpoint descriptor too short");
Jan Kiszka537e8f12012-11-15 09:23:30 +01001216 return;
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001217 }
1218 devep = d->u.endpoint.bEndpointAddress;
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001219 pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
1220 ep = devep & 0xf;
1221 if (ep == 0) {
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001222 trace_usb_host_parse_error(s->bus_num, s->addr,
1223 "invalid endpoint address");
Jan Kiszka537e8f12012-11-15 09:23:30 +01001224 return;
Hans de Goede130314f2011-05-31 11:35:22 +02001225 }
1226
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001227 type = d->u.endpoint.bmAttributes & 0x3;
1228 mps = d->u.endpoint.wMaxPacketSize_lo |
1229 (d->u.endpoint.wMaxPacketSize_hi << 8);
1230 trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep,
1231 (devep & USB_DIR_IN) ? "in" : "out",
1232 tname[type], active);
1233
1234 if (active) {
1235 usb_ep_set_max_packet_size(&s->dev, pid, ep, mps);
1236 assert(usb_ep_get_type(&s->dev, pid, ep) ==
1237 USB_ENDPOINT_XFER_INVALID);
1238 usb_ep_set_type(&s->dev, pid, ep, type);
1239 usb_ep_set_ifnum(&s->dev, pid, ep, interface);
1240 if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
Hans de Goede6ba43f12012-10-24 18:14:09 +02001241 (type == USB_ENDPOINT_XFER_BULK) &&
1242 (pid == USB_TOKEN_OUT)) {
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001243 usb_ep_set_pipeline(&s->dev, pid, ep, true);
1244 }
1245
1246 epd = get_endp(s, pid, ep);
1247 epd->halted = 0;
Gerd Hoffmann9424d4e2012-03-01 14:42:34 +01001248 }
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +02001249
Gerd Hoffmann96dd9aa2012-03-29 16:06:28 +02001250 break;
1251 default:
1252 trace_usb_host_parse_unknown(s->bus_num, s->addr,
1253 d->bLength, d->bDescriptorType);
1254 break;
balrogb9dc0332007-10-04 22:47:34 +00001255 }
1256 }
balrogb9dc0332007-10-04 22:47:34 +00001257}
1258
Hans de Goedee4b17762011-05-30 11:40:45 +02001259/*
1260 * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
1261 * this function assumes this is safe, if:
1262 * 1) There are no isoc endpoints
1263 * 2) There are no interrupt endpoints with a max_packet_size > 64
1264 * Note bulk endpoints with a max_packet_size > 64 in theory also are not
1265 * usb1 compatible, but in practice this seems to work fine.
1266 */
1267static int usb_linux_full_speed_compat(USBHostDevice *dev)
1268{
1269 int i, packet_size;
1270
1271 /*
1272 * usb_linux_update_endp_table only registers info about ep in the current
1273 * interface altsettings, so we need to parse the descriptors again.
1274 */
1275 for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
1276 if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
1277 switch (dev->descr[i + 3] & 0x3) {
1278 case 0x00: /* CONTROL */
1279 break;
1280 case 0x01: /* ISO */
1281 return 0;
1282 case 0x02: /* BULK */
1283 break;
1284 case 0x03: /* INTERRUPT */
1285 packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
1286 if (packet_size > 64)
1287 return 0;
1288 break;
1289 }
1290 }
1291 }
1292 return 1;
1293}
1294
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001295static int usb_host_open(USBHostDevice *dev, int bus_num,
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001296 int addr, const char *port,
1297 const char *prod_name, int speed)
bellardbb36d472005-11-05 14:22:28 +00001298{
balrogb9dc0332007-10-04 22:47:34 +00001299 int fd = -1, ret;
aliguori1f3870a2008-08-21 19:27:48 +00001300
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001301 trace_usb_host_open_started(bus_num, addr);
1302
David Ahern27911042010-04-24 10:26:22 -06001303 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001304 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001305 }
aliguori1f3870a2008-08-21 19:27:48 +00001306
Gerd Hoffmann097db432011-12-16 11:54:11 +01001307 fd = usb_host_open_device(bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001308 if (fd < 0) {
aliguori1f3870a2008-08-21 19:27:48 +00001309 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001310 }
malcd0f2c4c2010-02-07 02:03:50 +03001311 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001312
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001313 dev->bus_num = bus_num;
1314 dev->addr = addr;
Markus Armbruster03607842013-01-10 14:33:25 +01001315 pstrcpy(dev->port, sizeof(dev->port), port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001316 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001317
balrogb9dc0332007-10-04 22:47:34 +00001318 /* read the device description */
1319 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1320 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001321 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001322 goto fail;
1323 }
ths3b46e622007-09-17 08:09:54 +00001324
balrogb9dc0332007-10-04 22:47:34 +00001325#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001326 {
balrogb9dc0332007-10-04 22:47:34 +00001327 int x;
1328 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001329 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001330 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001331 }
balrogb9dc0332007-10-04 22:47:34 +00001332 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001333 }
1334#endif
1335
balrogb9dc0332007-10-04 22:47:34 +00001336
Gerd Hoffmanneb7700b2011-08-24 14:45:07 +02001337 /* start unconfigured -- we'll wait for the guest to set a configuration */
1338 if (!usb_host_claim_interfaces(dev, 0)) {
balrogb9dc0332007-10-04 22:47:34 +00001339 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001340 }
bellardbb36d472005-11-05 14:22:28 +00001341
Gerd Hoffmann19deaa02012-07-03 10:11:21 +02001342 usb_ep_init(&dev->dev);
Jan Kiszka537e8f12012-11-15 09:23:30 +01001343 usb_linux_update_endp_table(dev);
balrogb9dc0332007-10-04 22:47:34 +00001344
Hans de Goede3991c352011-05-31 11:35:18 +02001345 if (speed == -1) {
1346 struct usbdevfs_connectinfo ci;
1347
1348 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1349 if (ret < 0) {
1350 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
1351 goto fail;
1352 }
1353
1354 if (ci.slow) {
1355 speed = USB_SPEED_LOW;
1356 } else {
1357 speed = USB_SPEED_HIGH;
1358 }
David Ahern27911042010-04-24 10:26:22 -06001359 }
Hans de Goede3991c352011-05-31 11:35:18 +02001360 dev->dev.speed = speed;
Hans de Goedeba3f9bf2011-05-27 14:27:18 +02001361 dev->dev.speedmask = (1 << speed);
Hans de Goedee4b17762011-05-30 11:40:45 +02001362 if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
1363 dev->dev.speedmask |= USB_SPEED_MASK_FULL;
1364 }
Hans de Goede3991c352011-05-31 11:35:18 +02001365
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001366 trace_usb_host_open_success(bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001367
David Ahern27911042010-04-24 10:26:22 -06001368 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001369 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001370 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001371 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001372 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001373 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001374 }
bellard1f6e24e2006-06-26 21:00:51 +00001375
Hans de Goedefa19bf82011-05-27 19:05:15 +02001376 ret = usb_device_attach(&dev->dev);
1377 if (ret) {
1378 goto fail;
1379 }
1380
aliguori64838172008-08-21 19:31:10 +00001381 /* USB devio uses 'write' flag to check for async completions */
1382 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001383
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001384 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001385
balrogb9dc0332007-10-04 22:47:34 +00001386fail:
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001387 trace_usb_host_open_failure(bus_num, addr);
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001388 if (dev->fd != -1) {
1389 close(dev->fd);
1390 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001391 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001392 return -1;
1393}
1394
1395static int usb_host_close(USBHostDevice *dev)
1396{
Hans de Goede060dc842010-11-26 11:41:08 +01001397 int i;
1398
Gerd Hoffmann39fba3a2011-10-28 16:13:50 +02001399 if (dev->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001400 return -1;
David Ahern27911042010-04-24 10:26:22 -06001401 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001402
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001403 trace_usb_host_close(dev->bus_num, dev->addr);
1404
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001405 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1406 dev->closing = 1;
Gerd Hoffmannd8e17ef2011-08-29 12:49:46 +02001407 for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
Gerd Hoffmannc0e57502011-08-26 16:27:41 +02001408 if (is_isoc(dev, USB_TOKEN_IN, i)) {
1409 usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
1410 }
1411 if (is_isoc(dev, USB_TOKEN_OUT, i)) {
1412 usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
Hans de Goede060dc842010-11-26 11:41:08 +01001413 }
1414 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001415 async_complete(dev);
1416 dev->closing = 0;
Gerd Hoffmann39fba3a2011-10-28 16:13:50 +02001417 if (dev->dev.attached) {
1418 usb_device_detach(&dev->dev);
1419 }
Gerd Hoffmannc7662da2011-11-16 12:37:17 +01001420 usb_host_do_reset(dev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001421 close(dev->fd);
1422 dev->fd = -1;
1423 return 0;
1424}
1425
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001426static void usb_host_exit_notifier(struct Notifier *n, void *data)
Shahar Havivib373a632010-06-16 15:16:11 +03001427{
1428 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1429
Gerd Hoffmannc75fead2012-01-05 15:49:18 +01001430 usb_host_release_port(s);
Shahar Havivib373a632010-06-16 15:16:11 +03001431 if (s->fd != -1) {
Dong Xu Wangc7e775e2013-05-09 15:53:50 +08001432 usb_host_do_reset(s);
Shahar Havivib373a632010-06-16 15:16:11 +03001433 }
1434}
1435
Gerd Hoffmanna229c052012-06-08 13:02:16 +02001436/*
1437 * This is *NOT* about restoring state. We have absolutely no idea
1438 * what state the host device is in at the moment and whenever it is
1439 * still present in the first place. Attemping to contine where we
1440 * left off is impossible.
1441 *
1442 * What we are going to to to here is emulate a surprise removal of
1443 * the usb device passed through, then kick host scan so the device
1444 * will get re-attached (and re-initialized by the guest) in case it
1445 * is still present.
1446 *
1447 * As the device removal will change the state of other devices (usb
1448 * host controller, most likely interrupt controller too) we have to
1449 * wait with it until *all* vmstate is loaded. Thus post_load just
1450 * kicks a bottom half which then does the actual work.
1451 */
1452static void usb_host_post_load_bh(void *opaque)
1453{
1454 USBHostDevice *dev = opaque;
1455
1456 if (dev->fd != -1) {
1457 usb_host_close(dev);
1458 }
1459 if (dev->dev.attached) {
1460 usb_device_detach(&dev->dev);
1461 }
1462 usb_host_auto_check(NULL);
1463}
1464
1465static int usb_host_post_load(void *opaque, int version_id)
1466{
1467 USBHostDevice *dev = opaque;
1468
1469 qemu_bh_schedule(dev->bh);
1470 return 0;
1471}
1472
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001473static int usb_host_initfn(USBDevice *dev)
1474{
1475 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1476
Hans de Goedebe41efd2012-11-17 12:47:15 +01001477 dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001478 dev->auto_attach = 0;
1479 s->fd = -1;
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001480 s->hub_fd = -1;
1481
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001482 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001483 s->exit.notify = usb_host_exit_notifier;
1484 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmanna229c052012-06-08 13:02:16 +02001485 s->bh = qemu_bh_new(usb_host_post_load_bh, s);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001486 usb_host_auto_check(NULL);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001487
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001488 if (s->match.bus_num != 0 && s->match.port != NULL) {
Gerd Hoffmanne6274722011-09-13 11:37:47 +02001489 usb_host_claim_port(s);
Gerd Hoffmann9516bb42011-08-24 13:34:17 +02001490 }
Gerd Hoffmann65bb3a52012-03-22 10:48:03 +01001491 add_boot_device_path(s->bootindex, &dev->qdev, NULL);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001492 return 0;
bellardbb36d472005-11-05 14:22:28 +00001493}
1494
Gerd Hoffmannd6791572011-08-31 11:44:24 +02001495static const VMStateDescription vmstate_usb_host = {
Gerd Hoffmann2b2325f2012-11-30 16:02:11 +01001496 .name = DEVNAME,
Gerd Hoffmanna229c052012-06-08 13:02:16 +02001497 .version_id = 1,
1498 .minimum_version_id = 1,
1499 .post_load = usb_host_post_load,
1500 .fields = (VMStateField[]) {
1501 VMSTATE_USB_DEVICE(dev, USBHostDevice),
1502 VMSTATE_END_OF_LIST()
1503 }
Gerd Hoffmannd6791572011-08-31 11:44:24 +02001504};
1505
Anthony Liguori39bffca2011-12-07 21:34:16 -06001506static Property usb_host_dev_properties[] = {
1507 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1508 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
1509 DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
1510 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1511 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
1512 DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
Gerd Hoffmann65bb3a52012-03-22 10:48:03 +01001513 DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex, -1),
Gerd Hoffmann39c20572012-03-22 15:28:45 +01001514 DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
1515 USB_HOST_OPT_PIPELINE, true),
Anthony Liguori39bffca2011-12-07 21:34:16 -06001516 DEFINE_PROP_END_OF_LIST(),
1517};
1518
Anthony Liguori62aed762011-12-15 14:53:10 -06001519static void usb_host_class_initfn(ObjectClass *klass, void *data)
1520{
Anthony Liguori39bffca2011-12-07 21:34:16 -06001521 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori62aed762011-12-15 14:53:10 -06001522 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
1523
1524 uc->init = usb_host_initfn;
1525 uc->product_desc = "USB Host Device";
Anthony Liguori62aed762011-12-15 14:53:10 -06001526 uc->cancel_packet = usb_host_async_cancel;
1527 uc->handle_data = usb_host_handle_data;
1528 uc->handle_control = usb_host_handle_control;
1529 uc->handle_reset = usb_host_handle_reset;
1530 uc->handle_destroy = usb_host_handle_destroy;
Anthony Liguori39bffca2011-12-07 21:34:16 -06001531 dc->vmsd = &vmstate_usb_host;
1532 dc->props = usb_host_dev_properties;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +03001533 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
Anthony Liguori62aed762011-12-15 14:53:10 -06001534}
1535
Andreas Färber8c43a6f2013-01-10 16:19:07 +01001536static const TypeInfo usb_host_dev_info = {
Gerd Hoffmann2b2325f2012-11-30 16:02:11 +01001537 .name = DEVNAME,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001538 .parent = TYPE_USB_DEVICE,
1539 .instance_size = sizeof(USBHostDevice),
1540 .class_init = usb_host_class_initfn,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001541};
1542
Andreas Färber83f7d432012-02-09 15:20:55 +01001543static void usb_host_register_types(void)
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001544{
Anthony Liguori39bffca2011-12-07 21:34:16 -06001545 type_register_static(&usb_host_dev_info);
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001546}
Andreas Färber83f7d432012-02-09 15:20:55 +01001547
1548type_init(usb_host_register_types)
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001549
aliguori0f431522008-10-07 20:06:37 +00001550/*
1551 * Read sys file-system device file
1552 *
1553 * @line address of buffer to put file contents in
1554 * @line_size size of line
1555 * @device_file path to device file (printf format string)
1556 * @device_name device being opened (inserted into device_file)
1557 *
1558 * @return 0 failed, 1 succeeded ('line' contains data)
1559 */
David Ahern27911042010-04-24 10:26:22 -06001560static int usb_host_read_file(char *line, size_t line_size,
1561 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001562{
1563 FILE *f;
1564 int ret = 0;
1565 char filename[PATH_MAX];
1566
Gerd Hoffmann097db432011-12-16 11:54:11 +01001567 snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name,
blueswir1b4e237a2008-12-28 15:45:20 +00001568 device_file);
aliguori0f431522008-10-07 20:06:37 +00001569 f = fopen(filename, "r");
1570 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001571 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001572 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001573 }
1574
1575 return ret;
1576}
1577
1578/*
1579 * Use /sys/bus/usb/devices/ directory to determine host's USB
1580 * devices.
1581 *
1582 * This code is based on Robert Schiele's original patches posted to
1583 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1584 */
Gerd Hoffmann097db432011-12-16 11:54:11 +01001585static int usb_host_scan(void *opaque, USBScanFunc *func)
aliguori0f431522008-10-07 20:06:37 +00001586{
Blue Swirl660f11b2009-07-31 21:16:51 +00001587 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001588 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001589 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001590 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001591 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001592 char product_name[512];
1593 struct dirent *de;
1594
Gerd Hoffmann097db432011-12-16 11:54:11 +01001595 dir = opendir("/sys/bus/usb/devices");
aliguori0f431522008-10-07 20:06:37 +00001596 if (!dir) {
Gerd Hoffmann097db432011-12-16 11:54:11 +01001597 perror("husb: opendir /sys/bus/usb/devices");
1598 fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n");
aliguori0f431522008-10-07 20:06:37 +00001599 goto the_end;
1600 }
1601
1602 while ((de = readdir(dir))) {
1603 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001604 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1605 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001606 }
aliguori0f431522008-10-07 20:06:37 +00001607
David Ahern27911042010-04-24 10:26:22 -06001608 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001609 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001610 }
1611 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001612 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001613 }
blueswir1b4e237a2008-12-28 15:45:20 +00001614 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001615 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001616 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001617 }
1618 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001619 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001620 }
aliguori0f431522008-10-07 20:06:37 +00001621
David Ahern27911042010-04-24 10:26:22 -06001622 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1623 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001624 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001625 }
1626 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001627 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001628 }
blueswir1b4e237a2008-12-28 15:45:20 +00001629 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001630 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001631 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001632 }
1633 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001634 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001635 }
blueswir1b4e237a2008-12-28 15:45:20 +00001636 if (!usb_host_read_file(line, sizeof(line), "product",
1637 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001638 *product_name = 0;
1639 } else {
David Ahern27911042010-04-24 10:26:22 -06001640 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001641 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001642 }
aliguori0f431522008-10-07 20:06:37 +00001643 pstrcpy(product_name, sizeof(product_name), line);
1644 }
1645
David Ahern27911042010-04-24 10:26:22 -06001646 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001647 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001648 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001649 if (!strcmp(line, "5000\n")) {
1650 speed = USB_SPEED_SUPER;
1651 } else if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001652 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001653 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001654 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001655 } else {
aliguori0f431522008-10-07 20:06:37 +00001656 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001657 }
aliguori0f431522008-10-07 20:06:37 +00001658
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001659 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001660 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001661 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001662 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001663 }
aliguori0f431522008-10-07 20:06:37 +00001664 }
1665 }
1666 the_end:
David Ahern27911042010-04-24 10:26:22 -06001667 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001668 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001669 }
aliguori0f431522008-10-07 20:06:37 +00001670 return ret;
1671}
1672
aliguori4b096fc2008-08-21 19:28:55 +00001673static QEMUTimer *usb_auto_timer;
Gerd Hoffmannc06c68c2012-11-14 15:51:18 +01001674static VMChangeStateEntry *usb_vmstate;
aliguori4b096fc2008-08-21 19:28:55 +00001675
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001676static int usb_host_auto_scan(void *opaque, int bus_num,
1677 int addr, const char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001678 int class_id, int vendor_id, int product_id,
1679 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001680{
1681 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001682 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001683
1684 /* Ignore hubs */
1685 if (class_id == 9)
1686 return 0;
1687
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001688 QTAILQ_FOREACH(s, &hostdevs, next) {
1689 f = &s->match;
1690
David Ahern27911042010-04-24 10:26:22 -06001691 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001692 continue;
David Ahern27911042010-04-24 10:26:22 -06001693 }
1694 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001695 continue;
David Ahern27911042010-04-24 10:26:22 -06001696 }
Markus Armbruster46635302013-01-10 14:33:24 +01001697 if (f->port != NULL && strcmp(f->port, port) != 0) {
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001698 continue;
1699 }
aliguori4b096fc2008-08-21 19:28:55 +00001700
David Ahern27911042010-04-24 10:26:22 -06001701 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001702 continue;
David Ahern27911042010-04-24 10:26:22 -06001703 }
aliguori4b096fc2008-08-21 19:28:55 +00001704
David Ahern27911042010-04-24 10:26:22 -06001705 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001706 continue;
David Ahern27911042010-04-24 10:26:22 -06001707 }
aliguori4b096fc2008-08-21 19:28:55 +00001708 /* We got a match */
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001709 s->seen++;
1710 if (s->errcount >= 3) {
1711 return 0;
1712 }
aliguori4b096fc2008-08-21 19:28:55 +00001713
Markus Armbruster33e66b82009-10-07 01:15:57 +02001714 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001715 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001716 return 0;
David Ahern27911042010-04-24 10:26:22 -06001717 }
malcd0f2c4c2010-02-07 02:03:50 +03001718 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001719
Gerd Hoffmann3ee886c2011-08-24 13:45:06 +02001720 if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
1721 s->errcount++;
1722 }
Hans de Goede97f86162011-05-31 11:35:24 +02001723 break;
aliguori4b096fc2008-08-21 19:28:55 +00001724 }
1725
1726 return 0;
1727}
1728
Gerd Hoffmannc06c68c2012-11-14 15:51:18 +01001729static void usb_host_vm_state(void *unused, int running, RunState state)
1730{
1731 if (running) {
1732 usb_host_auto_check(unused);
1733 }
1734}
1735
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001736static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001737{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001738 struct USBHostDevice *s;
1739 int unconnected = 0;
1740
Gerd Hoffmanna844ed82012-06-08 13:02:52 +02001741 if (runstate_is_running()) {
1742 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001743
Gerd Hoffmanna844ed82012-06-08 13:02:52 +02001744 QTAILQ_FOREACH(s, &hostdevs, next) {
1745 if (s->fd == -1) {
1746 unconnected++;
1747 }
1748 if (s->seen == 0) {
1749 s->errcount = 0;
1750 }
1751 s->seen = 0;
David Ahern27911042010-04-24 10:26:22 -06001752 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001753
Gerd Hoffmanna844ed82012-06-08 13:02:52 +02001754 if (unconnected == 0) {
1755 /* nothing to watch */
1756 if (usb_auto_timer) {
Alex Blighbc72ad62013-08-21 16:03:08 +01001757 timer_del(usb_auto_timer);
Gerd Hoffmanna844ed82012-06-08 13:02:52 +02001758 trace_usb_host_auto_scan_disabled();
1759 }
1760 return;
David Ahern27911042010-04-24 10:26:22 -06001761 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001762 }
1763
Gerd Hoffmannc06c68c2012-11-14 15:51:18 +01001764 if (!usb_vmstate) {
1765 usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL);
1766 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001767 if (!usb_auto_timer) {
Alex Blighbc72ad62013-08-21 16:03:08 +01001768 usb_auto_timer = timer_new_ms(QEMU_CLOCK_REALTIME, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001769 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001770 return;
David Ahern27911042010-04-24 10:26:22 -06001771 }
Gerd Hoffmanne6a2f502011-08-22 14:13:20 +02001772 trace_usb_host_auto_scan_enabled();
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001773 }
Alex Blighbc72ad62013-08-21 16:03:08 +01001774 timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001775}
1776
Gerd Hoffmann2b2325f2012-11-30 16:02:11 +01001777#ifndef CONFIG_USB_LIBUSB
1778
bellarda594cfb2005-11-06 16:13:29 +00001779/**********************/
1780/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001781
bellarda594cfb2005-11-06 16:13:29 +00001782struct usb_class_info {
1783 int class;
1784 const char *class_name;
1785};
1786
1787static const struct usb_class_info usb_class_info[] = {
1788 { USB_CLASS_AUDIO, "Audio"},
1789 { USB_CLASS_COMM, "Communication"},
1790 { USB_CLASS_HID, "HID"},
1791 { USB_CLASS_HUB, "Hub" },
1792 { USB_CLASS_PHYSICAL, "Physical" },
1793 { USB_CLASS_PRINTER, "Printer" },
1794 { USB_CLASS_MASS_STORAGE, "Storage" },
1795 { USB_CLASS_CDC_DATA, "Data" },
1796 { USB_CLASS_APP_SPEC, "Application Specific" },
1797 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1798 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001799 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001800 { USB_CLASS_CONTENT_SEC, "Content Security" },
1801 { -1, NULL }
1802};
1803
1804static const char *usb_class_str(uint8_t class)
1805{
1806 const struct usb_class_info *p;
1807 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001808 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001809 break;
David Ahern27911042010-04-24 10:26:22 -06001810 }
bellardbb36d472005-11-05 14:22:28 +00001811 }
bellarda594cfb2005-11-06 16:13:29 +00001812 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001813}
1814
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001815static void usb_info_device(Monitor *mon, int bus_num,
1816 int addr, const char *port,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001817 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00001818 const char *product_name,
1819 int speed)
bellardbb36d472005-11-05 14:22:28 +00001820{
bellarda594cfb2005-11-06 16:13:29 +00001821 const char *class_str, *speed_str;
1822
1823 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001824 case USB_SPEED_LOW:
1825 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001826 break;
ths5fafdf22007-09-16 21:08:06 +00001827 case USB_SPEED_FULL:
1828 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001829 break;
ths5fafdf22007-09-16 21:08:06 +00001830 case USB_SPEED_HIGH:
1831 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001832 break;
Hans de Goedef264cfb2011-05-31 11:35:19 +02001833 case USB_SPEED_SUPER:
1834 speed_str = "5000";
1835 break;
bellarda594cfb2005-11-06 16:13:29 +00001836 default:
ths5fafdf22007-09-16 21:08:06 +00001837 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001838 break;
bellardbb36d472005-11-05 14:22:28 +00001839 }
bellarda594cfb2005-11-06 16:13:29 +00001840
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001841 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
1842 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00001843 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001844 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001845 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001846 } else {
aliguori376253e2009-03-05 23:01:23 +00001847 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001848 }
aliguori376253e2009-03-05 23:01:23 +00001849 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001850 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001851 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001852 }
aliguori376253e2009-03-05 23:01:23 +00001853 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001854}
1855
ths5fafdf22007-09-16 21:08:06 +00001856static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmannba9acab2011-08-17 23:35:45 +02001857 const char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001858 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001859 const char *product_name,
1860 int speed)
1861{
Blue Swirl179da8a2009-09-07 19:00:18 +00001862 Monitor *mon = opaque;
1863
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001864 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001865 product_name, speed);
1866 return 0;
1867}
1868
aliguoriac4ffb52008-09-22 15:04:31 +00001869static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001870{
David Ahern27911042010-04-24 10:26:22 -06001871 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001872 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001873 } else {
1874 snprintf(str, size, "%d", val);
1875 }
aliguori5d0c5752008-09-14 01:07:41 +00001876}
1877
aliguoriac4ffb52008-09-22 15:04:31 +00001878static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001879{
David Ahern27911042010-04-24 10:26:22 -06001880 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001881 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001882 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001883 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06001884 }
aliguori5d0c5752008-09-14 01:07:41 +00001885}
1886
Wenchao Xia84f2d0e2013-01-14 14:06:25 +08001887void usb_host_info(Monitor *mon, const QDict *qdict)
bellarda594cfb2005-11-06 16:13:29 +00001888{
aliguori5d0c5752008-09-14 01:07:41 +00001889 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001890 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00001891
Blue Swirl179da8a2009-09-07 19:00:18 +00001892 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00001893
David Ahern27911042010-04-24 10:26:22 -06001894 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001895 return;
David Ahern27911042010-04-24 10:26:22 -06001896 }
1897
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001898 monitor_printf(mon, " Auto filters:\n");
1899 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00001900 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001901 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00001902 dec2str(f->bus_num, bus, sizeof(bus));
1903 dec2str(f->addr, addr, sizeof(addr));
1904 hex2str(f->vendor_id, vid, sizeof(vid));
1905 hex2str(f->product_id, pid, sizeof(pid));
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001906 monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
1907 bus, addr, f->port ? f->port : "*", vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00001908 }
bellardbb36d472005-11-05 14:22:28 +00001909}
Gerd Hoffmann2b2325f2012-11-30 16:02:11 +01001910
1911#endif