blob: 53cc5fc00eba5b2a361939c7abf58ac960709eee [file] [log] [blame]
bellardbb36d472005-11-05 14:22:28 +00001/*
2 * Linux host USB redirector
3 *
4 * Copyright (c) 2005 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
aliguori64838172008-08-21 19:31:10 +00006 * Copyright (c) 2008 Max Krasnyansky
7 * Support for host device auto connect & disconnect
aliguori5d0c5752008-09-14 01:07:41 +00008 * Major rewrite to support fully async operation
aliguori4b096fc2008-08-21 19:28:55 +00009 *
aliguori0f431522008-10-07 20:06:37 +000010 * Copyright 2008 TJ <linux@tjworld.net>
11 * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
12 * to the legacy /proc/bus/usb USB device discovery and handling
13 *
bellardbb36d472005-11-05 14:22:28 +000014 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to deal
16 * in the Software without restriction, including without limitation the rights
17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 * copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 * THE SOFTWARE.
31 */
aliguori446ab122008-09-14 01:06:09 +000032
pbrook87ecb682007-11-17 17:14:51 +000033#include "qemu-common.h"
aliguori1f3870a2008-08-21 19:27:48 +000034#include "qemu-timer.h"
aliguori376253e2009-03-05 23:01:23 +000035#include "monitor.h"
Shahar Havivib373a632010-06-16 15:16:11 +030036#include "sysemu.h"
bellardbb36d472005-11-05 14:22:28 +000037
bellardbb36d472005-11-05 14:22:28 +000038#include <dirent.h>
39#include <sys/ioctl.h>
bellardbb36d472005-11-05 14:22:28 +000040
aliguori446ab122008-09-14 01:06:09 +000041#include <linux/usbdevice_fs.h>
42#include <linux/version.h>
43#include "hw/usb.h"
bellardbb36d472005-11-05 14:22:28 +000044
blueswir1d9cf1572008-09-15 14:57:11 +000045/* We redefine it to avoid version problems */
46struct usb_ctrltransfer {
47 uint8_t bRequestType;
48 uint8_t bRequest;
49 uint16_t wValue;
50 uint16_t wIndex;
51 uint16_t wLength;
52 uint32_t timeout;
53 void *data;
54};
55
Gerd Hoffmann5557d822011-05-10 11:43:57 +020056typedef int USBScanFunc(void *opaque, int bus_num, int addr, char *port,
Hans de Goede0f5160d2010-11-10 10:06:23 +010057 int class_id, int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +000058 const char *product_name, int speed);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +010059
Markus Armbruster0745eb12009-11-27 13:05:53 +010060//#define DEBUG
aliguori64838172008-08-21 19:31:10 +000061
62#ifdef DEBUG
malcd0f2c4c2010-02-07 02:03:50 +030063#define DPRINTF printf
aliguori64838172008-08-21 19:31:10 +000064#else
malcd0f2c4c2010-02-07 02:03:50 +030065#define DPRINTF(...)
aliguori64838172008-08-21 19:31:10 +000066#endif
bellardbb36d472005-11-05 14:22:28 +000067
blueswir15be8e1f2008-10-25 11:47:20 +000068#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
69
aliguori0f431522008-10-07 20:06:37 +000070#define USBPROCBUS_PATH "/proc/bus/usb"
bellard1f6e24e2006-06-26 21:00:51 +000071#define PRODUCT_NAME_SZ 32
Hans de Goede3a4854b2010-11-26 15:02:16 +010072#define MAX_ENDPOINTS 15
Gerd Hoffmann5557d822011-05-10 11:43:57 +020073#define MAX_PORTLEN 16
aliguori0f431522008-10-07 20:06:37 +000074#define USBDEVBUS_PATH "/dev/bus/usb"
75#define USBSYSBUS_PATH "/sys/bus/usb"
76
77static char *usb_host_device_path;
78
79#define USB_FS_NONE 0
80#define USB_FS_PROC 1
81#define USB_FS_DEV 2
82#define USB_FS_SYS 3
83
84static int usb_fs_type;
bellardbb36d472005-11-05 14:22:28 +000085
balrogb9dc0332007-10-04 22:47:34 +000086/* endpoint association data */
Hans de Goede060dc842010-11-26 11:41:08 +010087#define ISO_FRAME_DESC_PER_URB 32
Hans de Goedea0b5fec2010-11-26 14:56:17 +010088#define INVALID_EP_TYPE 255
Hans de Goede060dc842010-11-26 11:41:08 +010089
Gerd Hoffmann71138532011-05-16 10:21:51 +020090/* devio.c limits single requests to 16k */
91#define MAX_USBFS_BUFFER_SIZE 16384
92
Hans de Goede060dc842010-11-26 11:41:08 +010093typedef struct AsyncURB AsyncURB;
94
balrogb9dc0332007-10-04 22:47:34 +000095struct endp_data {
96 uint8_t type;
aliguori64838172008-08-21 19:31:10 +000097 uint8_t halted;
Hans de Goedebb6d5492010-11-26 19:11:03 +010098 uint8_t iso_started;
Hans de Goede060dc842010-11-26 11:41:08 +010099 AsyncURB *iso_urb;
100 int iso_urb_idx;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100101 int iso_buffer_used;
Hans de Goede060dc842010-11-26 11:41:08 +0100102 int max_packet_size;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200103 int inflight;
balrogb9dc0332007-10-04 22:47:34 +0000104};
105
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100106struct USBAutoFilter {
107 uint32_t bus_num;
108 uint32_t addr;
Gerd Hoffmann9056a292011-05-10 12:07:42 +0200109 char *port;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100110 uint32_t vendor_id;
111 uint32_t product_id;
112};
113
bellardbb36d472005-11-05 14:22:28 +0000114typedef struct USBHostDevice {
115 USBDevice dev;
aliguori64838172008-08-21 19:31:10 +0000116 int fd;
117
Hans de Goedef8ddbfb2011-05-31 11:35:26 +0200118 uint8_t descr[8192];
aliguori64838172008-08-21 19:31:10 +0000119 int descr_len;
120 int configuration;
aliguori446ab122008-09-14 01:06:09 +0000121 int ninterfaces;
aliguori24772c12008-08-21 19:31:52 +0000122 int closing;
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200123 uint32_t iso_urb_count;
Shahar Havivib373a632010-06-16 15:16:11 +0300124 Notifier exit;
aliguori64838172008-08-21 19:31:10 +0000125
balrogb9dc0332007-10-04 22:47:34 +0000126 struct endp_data endp_table[MAX_ENDPOINTS];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200127 QLIST_HEAD(, AsyncURB) aurbs;
aliguori4b096fc2008-08-21 19:28:55 +0000128
aliguori4b096fc2008-08-21 19:28:55 +0000129 /* Host side address */
130 int bus_num;
131 int addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200132 char port[MAX_PORTLEN];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100133 struct USBAutoFilter match;
aliguori4b096fc2008-08-21 19:28:55 +0000134
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100135 QTAILQ_ENTRY(USBHostDevice) next;
bellardbb36d472005-11-05 14:22:28 +0000136} USBHostDevice;
137
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100138static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
139
140static int usb_host_close(USBHostDevice *dev);
141static int parse_filter(const char *spec, struct USBAutoFilter *f);
142static void usb_host_auto_check(void *unused);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100143static int usb_host_read_file(char *line, size_t line_size,
144 const char *device_file, const char *device_name);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100145
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200146static struct endp_data *get_endp(USBHostDevice *s, int ep)
147{
148 return s->endp_table + ep - 1;
149}
150
aliguori64838172008-08-21 19:31:10 +0000151static int is_isoc(USBHostDevice *s, int ep)
152{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200153 return get_endp(s, ep)->type == USBDEVFS_URB_TYPE_ISO;
aliguori64838172008-08-21 19:31:10 +0000154}
155
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100156static int is_valid(USBHostDevice *s, int ep)
157{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200158 return get_endp(s, ep)->type != INVALID_EP_TYPE;
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100159}
160
aliguori64838172008-08-21 19:31:10 +0000161static int is_halted(USBHostDevice *s, int ep)
162{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200163 return get_endp(s, ep)->halted;
aliguori64838172008-08-21 19:31:10 +0000164}
165
166static void clear_halt(USBHostDevice *s, int ep)
167{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200168 get_endp(s, ep)->halted = 0;
aliguori64838172008-08-21 19:31:10 +0000169}
170
171static void set_halt(USBHostDevice *s, int ep)
172{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200173 get_endp(s, ep)->halted = 1;
aliguori64838172008-08-21 19:31:10 +0000174}
175
Hans de Goedebb6d5492010-11-26 19:11:03 +0100176static int is_iso_started(USBHostDevice *s, int ep)
177{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200178 return get_endp(s, ep)->iso_started;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100179}
180
181static void clear_iso_started(USBHostDevice *s, int ep)
182{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200183 get_endp(s, ep)->iso_started = 0;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100184}
185
186static void set_iso_started(USBHostDevice *s, int ep)
187{
Gerd Hoffmann82887262011-06-10 14:00:24 +0200188 struct endp_data *e = get_endp(s, ep);
189 if (!e->iso_started) {
190 e->iso_started = 1;
191 e->inflight = 0;
192 }
193}
194
195static int change_iso_inflight(USBHostDevice *s, int ep, int value)
196{
197 struct endp_data *e = get_endp(s, ep);
198
199 e->inflight += value;
200 return e->inflight;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100201}
202
Hans de Goede060dc842010-11-26 11:41:08 +0100203static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb)
204{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200205 get_endp(s, ep)->iso_urb = iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100206}
207
208static AsyncURB *get_iso_urb(USBHostDevice *s, int ep)
209{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200210 return get_endp(s, ep)->iso_urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100211}
212
213static void set_iso_urb_idx(USBHostDevice *s, int ep, int i)
214{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200215 get_endp(s, ep)->iso_urb_idx = i;
Hans de Goede060dc842010-11-26 11:41:08 +0100216}
217
218static int get_iso_urb_idx(USBHostDevice *s, int ep)
219{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200220 return get_endp(s, ep)->iso_urb_idx;
Hans de Goede060dc842010-11-26 11:41:08 +0100221}
222
Hans de Goedebb6d5492010-11-26 19:11:03 +0100223static void set_iso_buffer_used(USBHostDevice *s, int ep, int i)
224{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200225 get_endp(s, ep)->iso_buffer_used = i;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100226}
227
228static int get_iso_buffer_used(USBHostDevice *s, int ep)
229{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200230 return get_endp(s, ep)->iso_buffer_used;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100231}
232
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200233static void set_max_packet_size(USBHostDevice *s, int ep, uint8_t *descriptor)
234{
235 int raw = descriptor[4] + (descriptor[5] << 8);
236 int size, microframes;
237
238 size = raw & 0x7ff;
239 switch ((raw >> 11) & 3) {
240 case 1: microframes = 2; break;
241 case 2: microframes = 3; break;
242 default: microframes = 1; break;
243 }
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200244 get_endp(s, ep)->max_packet_size = size * microframes;
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +0200245}
246
Hans de Goede060dc842010-11-26 11:41:08 +0100247static int get_max_packet_size(USBHostDevice *s, int ep)
248{
Gerd Hoffmannca3a36c2011-06-10 13:34:10 +0200249 return get_endp(s, ep)->max_packet_size;
Hans de Goede060dc842010-11-26 11:41:08 +0100250}
251
David Ahern27911042010-04-24 10:26:22 -0600252/*
aliguori64838172008-08-21 19:31:10 +0000253 * Async URB state.
Hans de Goede060dc842010-11-26 11:41:08 +0100254 * We always allocate iso packet descriptors even for bulk transfers
David Ahern27911042010-04-24 10:26:22 -0600255 * to simplify allocation and casts.
aliguori64838172008-08-21 19:31:10 +0000256 */
Hans de Goede060dc842010-11-26 11:41:08 +0100257struct AsyncURB
balrogb9dc0332007-10-04 22:47:34 +0000258{
aliguori64838172008-08-21 19:31:10 +0000259 struct usbdevfs_urb urb;
Hans de Goede060dc842010-11-26 11:41:08 +0100260 struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200261 USBHostDevice *hdev;
262 QLIST_ENTRY(AsyncURB) next;
aliguori64838172008-08-21 19:31:10 +0000263
Hans de Goede060dc842010-11-26 11:41:08 +0100264 /* For regular async urbs */
aliguori64838172008-08-21 19:31:10 +0000265 USBPacket *packet;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200266 int more; /* large transfer, more urbs follow */
Hans de Goede060dc842010-11-26 11:41:08 +0100267
268 /* For buffered iso handling */
269 int iso_frame_idx; /* -1 means in flight */
270};
aliguori64838172008-08-21 19:31:10 +0000271
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200272static AsyncURB *async_alloc(USBHostDevice *s)
aliguori64838172008-08-21 19:31:10 +0000273{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200274 AsyncURB *aurb = qemu_mallocz(sizeof(AsyncURB));
275 aurb->hdev = s;
276 QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
277 return aurb;
balrogb9dc0332007-10-04 22:47:34 +0000278}
279
aliguori64838172008-08-21 19:31:10 +0000280static void async_free(AsyncURB *aurb)
balrogb9dc0332007-10-04 22:47:34 +0000281{
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200282 QLIST_REMOVE(aurb, next);
aliguori64838172008-08-21 19:31:10 +0000283 qemu_free(aurb);
284}
balrogb9dc0332007-10-04 22:47:34 +0000285
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200286static void do_disconnect(USBHostDevice *s)
287{
288 printf("husb: device %d.%d disconnected\n",
289 s->bus_num, s->addr);
290 usb_host_close(s);
291 usb_host_auto_check(NULL);
292}
293
aliguori64838172008-08-21 19:31:10 +0000294static void async_complete(void *opaque)
295{
296 USBHostDevice *s = opaque;
297 AsyncURB *aurb;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200298 int urbs = 0;
balrogb9dc0332007-10-04 22:47:34 +0000299
aliguori64838172008-08-21 19:31:10 +0000300 while (1) {
David Ahern27911042010-04-24 10:26:22 -0600301 USBPacket *p;
aliguori64838172008-08-21 19:31:10 +0000302
David Ahern27911042010-04-24 10:26:22 -0600303 int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
aliguori64838172008-08-21 19:31:10 +0000304 if (r < 0) {
David Ahern27911042010-04-24 10:26:22 -0600305 if (errno == EAGAIN) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200306 if (urbs > 2) {
307 fprintf(stderr, "husb: %d iso urbs finished at once\n", urbs);
308 }
aliguori64838172008-08-21 19:31:10 +0000309 return;
David Ahern27911042010-04-24 10:26:22 -0600310 }
aliguori24772c12008-08-21 19:31:52 +0000311 if (errno == ENODEV && !s->closing) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200312 do_disconnect(s);
aliguori64838172008-08-21 19:31:10 +0000313 return;
314 }
315
malcd0f2c4c2010-02-07 02:03:50 +0300316 DPRINTF("husb: async. reap urb failed errno %d\n", errno);
aliguori64838172008-08-21 19:31:10 +0000317 return;
balrogb9dc0332007-10-04 22:47:34 +0000318 }
aliguori64838172008-08-21 19:31:10 +0000319
David Ahern27911042010-04-24 10:26:22 -0600320 DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
aliguori64838172008-08-21 19:31:10 +0000321 aurb, aurb->urb.status, aurb->urb.actual_length);
322
Hans de Goede060dc842010-11-26 11:41:08 +0100323 /* If this is a buffered iso urb mark it as complete and don't do
324 anything else (it is handled further in usb_host_handle_iso_data) */
325 if (aurb->iso_frame_idx == -1) {
Gerd Hoffmann82887262011-06-10 14:00:24 +0200326 int inflight;
Hans de Goede060dc842010-11-26 11:41:08 +0100327 if (aurb->urb.status == -EPIPE) {
328 set_halt(s, aurb->urb.endpoint & 0xf);
329 }
330 aurb->iso_frame_idx = 0;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200331 urbs++;
332 inflight = change_iso_inflight(s, aurb->urb.endpoint & 0xf, -1);
333 if (inflight == 0 && is_iso_started(s, aurb->urb.endpoint & 0xf)) {
334 fprintf(stderr, "husb: out of buffers for iso stream\n");
335 }
Hans de Goede060dc842010-11-26 11:41:08 +0100336 continue;
337 }
338
339 p = aurb->packet;
340
David Ahern27911042010-04-24 10:26:22 -0600341 if (p) {
aliguori64838172008-08-21 19:31:10 +0000342 switch (aurb->urb.status) {
343 case 0:
Gerd Hoffmann71138532011-05-16 10:21:51 +0200344 p->len += aurb->urb.actual_length;
aliguori64838172008-08-21 19:31:10 +0000345 break;
346
347 case -EPIPE:
348 set_halt(s, p->devep);
David Ahern27911042010-04-24 10:26:22 -0600349 p->len = USB_RET_STALL;
350 break;
Paul Bolledcc7e252009-10-13 13:40:08 +0200351
aliguori64838172008-08-21 19:31:10 +0000352 default:
353 p->len = USB_RET_NAK;
354 break;
355 }
356
Hans de Goede50b79632011-02-02 17:36:29 +0100357 if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
358 usb_generic_async_ctrl_complete(&s->dev, p);
Gerd Hoffmann71138532011-05-16 10:21:51 +0200359 } else if (!aurb->more) {
Hans de Goede50b79632011-02-02 17:36:29 +0100360 usb_packet_complete(&s->dev, p);
361 }
David Ahern27911042010-04-24 10:26:22 -0600362 }
aliguori64838172008-08-21 19:31:10 +0000363
364 async_free(aurb);
balrogb9dc0332007-10-04 22:47:34 +0000365 }
balrogb9dc0332007-10-04 22:47:34 +0000366}
367
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200368static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
balrogb9dc0332007-10-04 22:47:34 +0000369{
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +0200370 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200371 AsyncURB *aurb;
balrogb9dc0332007-10-04 22:47:34 +0000372
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200373 QLIST_FOREACH(aurb, &s->aurbs, next) {
374 if (p != aurb->packet) {
375 continue;
376 }
balrogb9dc0332007-10-04 22:47:34 +0000377
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200378 DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
aliguori64838172008-08-21 19:31:10 +0000379
Gerd Hoffmann227ebeb2011-05-16 09:20:06 +0200380 /* Mark it as dead (see async_complete above) */
381 aurb->packet = NULL;
382
383 int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
384 if (r < 0) {
385 DPRINTF("husb: async. discard urb failed errno %d\n", errno);
386 }
balrogb9dc0332007-10-04 22:47:34 +0000387 }
balrogb9dc0332007-10-04 22:47:34 +0000388}
389
aliguori446ab122008-09-14 01:06:09 +0000390static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
balrogb9dc0332007-10-04 22:47:34 +0000391{
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200392 const char *op = NULL;
balrogb9dc0332007-10-04 22:47:34 +0000393 int dev_descr_len, config_descr_len;
Blue Swirld4c4e6f2010-04-25 18:23:04 +0000394 int interface, nb_interfaces;
balrogb9dc0332007-10-04 22:47:34 +0000395 int ret, i;
396
397 if (configuration == 0) /* address state - ignore */
398 return 1;
399
malcd0f2c4c2010-02-07 02:03:50 +0300400 DPRINTF("husb: claiming interfaces. config %d\n", configuration);
aliguori446ab122008-09-14 01:06:09 +0000401
balrogb9dc0332007-10-04 22:47:34 +0000402 i = 0;
403 dev_descr_len = dev->descr[0];
David Ahern27911042010-04-24 10:26:22 -0600404 if (dev_descr_len > dev->descr_len) {
Hans de Goede61c11172011-05-31 11:35:20 +0200405 fprintf(stderr, "husb: update iface failed. descr too short\n");
406 return 0;
David Ahern27911042010-04-24 10:26:22 -0600407 }
balrogb9dc0332007-10-04 22:47:34 +0000408
409 i += dev_descr_len;
410 while (i < dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600411 DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
412 i, dev->descr_len,
balrogb9dc0332007-10-04 22:47:34 +0000413 dev->descr[i], dev->descr[i+1]);
aliguori64838172008-08-21 19:31:10 +0000414
balrogb9dc0332007-10-04 22:47:34 +0000415 if (dev->descr[i+1] != USB_DT_CONFIG) {
416 i += dev->descr[i];
417 continue;
418 }
419 config_descr_len = dev->descr[i];
420
David Ahern27911042010-04-24 10:26:22 -0600421 printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
aliguori1f3870a2008-08-21 19:27:48 +0000422
aliguori446ab122008-09-14 01:06:09 +0000423 if (configuration < 0 || configuration == dev->descr[i + 5]) {
424 configuration = dev->descr[i + 5];
balrogb9dc0332007-10-04 22:47:34 +0000425 break;
aliguori446ab122008-09-14 01:06:09 +0000426 }
balrogb9dc0332007-10-04 22:47:34 +0000427
428 i += config_descr_len;
429 }
430
431 if (i >= dev->descr_len) {
David Ahern27911042010-04-24 10:26:22 -0600432 fprintf(stderr,
433 "husb: update iface failed. no matching configuration\n");
Hans de Goede61c11172011-05-31 11:35:20 +0200434 return 0;
balrogb9dc0332007-10-04 22:47:34 +0000435 }
436 nb_interfaces = dev->descr[i + 4];
437
438#ifdef USBDEVFS_DISCONNECT
439 /* earlier Linux 2.4 do not support that */
440 {
441 struct usbdevfs_ioctl ctrl;
442 for (interface = 0; interface < nb_interfaces; interface++) {
443 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
444 ctrl.ifno = interface;
Brad Hards021730f2011-04-13 19:45:32 +1000445 ctrl.data = 0;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200446 op = "USBDEVFS_DISCONNECT";
balrogb9dc0332007-10-04 22:47:34 +0000447 ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
448 if (ret < 0 && errno != ENODATA) {
balrogb9dc0332007-10-04 22:47:34 +0000449 goto fail;
450 }
451 }
452 }
453#endif
454
455 /* XXX: only grab if all interfaces are free */
456 for (interface = 0; interface < nb_interfaces; interface++) {
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200457 op = "USBDEVFS_CLAIMINTERFACE";
balrogb9dc0332007-10-04 22:47:34 +0000458 ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
459 if (ret < 0) {
460 if (errno == EBUSY) {
aliguori64838172008-08-21 19:31:10 +0000461 printf("husb: update iface. device already grabbed\n");
balrogb9dc0332007-10-04 22:47:34 +0000462 } else {
aliguori64838172008-08-21 19:31:10 +0000463 perror("husb: failed to claim interface");
balrogb9dc0332007-10-04 22:47:34 +0000464 }
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200465 goto fail;
balrogb9dc0332007-10-04 22:47:34 +0000466 }
467 }
468
aliguori64838172008-08-21 19:31:10 +0000469 printf("husb: %d interfaces claimed for configuration %d\n",
balrogb9dc0332007-10-04 22:47:34 +0000470 nb_interfaces, configuration);
balrogb9dc0332007-10-04 22:47:34 +0000471
aliguori446ab122008-09-14 01:06:09 +0000472 dev->ninterfaces = nb_interfaces;
473 dev->configuration = configuration;
474 return 1;
Gerd Hoffmann41c01ee2011-05-24 16:12:31 +0200475
476fail:
477 if (errno == ENODEV) {
478 do_disconnect(dev);
479 }
480 perror(op);
481 return 0;
aliguori446ab122008-09-14 01:06:09 +0000482}
483
484static int usb_host_release_interfaces(USBHostDevice *s)
485{
486 int ret, i;
487
malcd0f2c4c2010-02-07 02:03:50 +0300488 DPRINTF("husb: releasing interfaces\n");
aliguori446ab122008-09-14 01:06:09 +0000489
490 for (i = 0; i < s->ninterfaces; i++) {
491 ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
492 if (ret < 0) {
493 perror("husb: failed to release interface");
494 return 0;
495 }
496 }
497
balrogb9dc0332007-10-04 22:47:34 +0000498 return 1;
499}
500
bellard059809e2006-07-19 18:06:15 +0000501static void usb_host_handle_reset(USBDevice *dev)
bellardbb36d472005-11-05 14:22:28 +0000502{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100503 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000504
malcd0f2c4c2010-02-07 02:03:50 +0300505 DPRINTF("husb: reset device %u.%u\n", s->bus_num, s->addr);
aliguori64838172008-08-21 19:31:10 +0000506
bellardbb36d472005-11-05 14:22:28 +0000507 ioctl(s->fd, USBDEVFS_RESET);
aliguori446ab122008-09-14 01:06:09 +0000508
509 usb_host_claim_interfaces(s, s->configuration);
ths5fafdf22007-09-16 21:08:06 +0000510}
bellardbb36d472005-11-05 14:22:28 +0000511
bellard059809e2006-07-19 18:06:15 +0000512static void usb_host_handle_destroy(USBDevice *dev)
513{
514 USBHostDevice *s = (USBHostDevice *)dev;
515
Gerd Hoffmann26a9e822009-10-26 15:56:50 +0100516 usb_host_close(s);
517 QTAILQ_REMOVE(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +0300518 qemu_remove_exit_notifier(&s->exit);
bellard059809e2006-07-19 18:06:15 +0000519}
520
balrogb9dc0332007-10-04 22:47:34 +0000521static int usb_linux_update_endp_table(USBHostDevice *s);
522
Hans de Goede060dc842010-11-26 11:41:08 +0100523/* iso data is special, we need to keep enough urbs in flight to make sure
524 that the controller never runs out of them, otherwise the device will
525 likely suffer a buffer underrun / overrun. */
526static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in)
527{
528 AsyncURB *aurb;
529 int i, j, len = get_max_packet_size(s, ep);
530
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200531 aurb = qemu_mallocz(s->iso_urb_count * sizeof(*aurb));
532 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100533 aurb[i].urb.endpoint = ep;
534 aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
535 aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length);
536 aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
537 aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
538 aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
539 for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
540 aurb[i].urb.iso_frame_desc[j].length = len;
541 if (in) {
542 aurb[i].urb.endpoint |= 0x80;
543 /* Mark as fully consumed (idle) */
544 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
545 }
546 }
547 set_iso_urb(s, ep, aurb);
548
549 return aurb;
550}
551
552static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep)
553{
554 AsyncURB *aurb;
555 int i, ret, killed = 0, free = 1;
556
557 aurb = get_iso_urb(s, ep);
558 if (!aurb) {
559 return;
560 }
561
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200562 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100563 /* in flight? */
564 if (aurb[i].iso_frame_idx == -1) {
565 ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
566 if (ret < 0) {
567 printf("husb: discard isoc in urb failed errno %d\n", errno);
568 free = 0;
569 continue;
570 }
571 killed++;
572 }
573 }
574
575 /* Make sure any urbs we've killed are reaped before we free them */
576 if (killed) {
577 async_complete(s);
578 }
579
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200580 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100581 qemu_free(aurb[i].urb.buffer);
582 }
583
584 if (free)
585 qemu_free(aurb);
586 else
587 printf("husb: leaking iso urbs because of discard failure\n");
588 set_iso_urb(s, ep, NULL);
Hans de Goedebb6d5492010-11-26 19:11:03 +0100589 set_iso_urb_idx(s, ep, 0);
590 clear_iso_started(s, ep);
Hans de Goede060dc842010-11-26 11:41:08 +0100591}
592
593static int urb_status_to_usb_ret(int status)
594{
595 switch (status) {
596 case -EPIPE:
597 return USB_RET_STALL;
598 default:
599 return USB_RET_NAK;
600 }
601}
602
Hans de Goedebb6d5492010-11-26 19:11:03 +0100603static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
Hans de Goede060dc842010-11-26 11:41:08 +0100604{
605 AsyncURB *aurb;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100606 int i, j, ret, max_packet_size, offset, len = 0;
Hans de Goede975f2992010-11-26 14:59:35 +0100607
608 max_packet_size = get_max_packet_size(s, p->devep);
609 if (max_packet_size == 0)
610 return USB_RET_NAK;
Hans de Goede060dc842010-11-26 11:41:08 +0100611
612 aurb = get_iso_urb(s, p->devep);
613 if (!aurb) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100614 aurb = usb_host_alloc_iso(s, p->devep, in);
Hans de Goede060dc842010-11-26 11:41:08 +0100615 }
616
617 i = get_iso_urb_idx(s, p->devep);
618 j = aurb[i].iso_frame_idx;
619 if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100620 if (in) {
621 /* Check urb status */
622 if (aurb[i].urb.status) {
623 len = urb_status_to_usb_ret(aurb[i].urb.status);
624 /* Move to the next urb */
625 aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
626 /* Check frame status */
627 } else if (aurb[i].urb.iso_frame_desc[j].status) {
628 len = urb_status_to_usb_ret(
629 aurb[i].urb.iso_frame_desc[j].status);
630 /* Check the frame fits */
631 } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) {
632 printf("husb: received iso data is larger then packet\n");
633 len = USB_RET_NAK;
634 /* All good copy data over */
635 } else {
636 len = aurb[i].urb.iso_frame_desc[j].actual_length;
637 memcpy(p->data,
638 aurb[i].urb.buffer +
639 j * aurb[i].urb.iso_frame_desc[0].length,
640 len);
641 }
Hans de Goede060dc842010-11-26 11:41:08 +0100642 } else {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100643 len = p->len;
644 offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->devep);
645
646 /* Check the frame fits */
647 if (len > max_packet_size) {
648 printf("husb: send iso data is larger then max packet size\n");
649 return USB_RET_NAK;
650 }
651
652 /* All good copy data over */
653 memcpy(aurb[i].urb.buffer + offset, p->data, len);
654 aurb[i].urb.iso_frame_desc[j].length = len;
655 offset += len;
656 set_iso_buffer_used(s, p->devep, offset);
657
658 /* Start the stream once we have buffered enough data */
659 if (!is_iso_started(s, p->devep) && i == 1 && j == 8) {
660 set_iso_started(s, p->devep);
661 }
Hans de Goede060dc842010-11-26 11:41:08 +0100662 }
663 aurb[i].iso_frame_idx++;
664 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200665 i = (i + 1) % s->iso_urb_count;
Hans de Goede060dc842010-11-26 11:41:08 +0100666 set_iso_urb_idx(s, p->devep, i);
667 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100668 } else {
669 if (in) {
670 set_iso_started(s, p->devep);
671 } else {
672 DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
673 }
Hans de Goede060dc842010-11-26 11:41:08 +0100674 }
675
Hans de Goedebb6d5492010-11-26 19:11:03 +0100676 if (is_iso_started(s, p->devep)) {
677 /* (Re)-submit all fully consumed / filled urbs */
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +0200678 for (i = 0; i < s->iso_urb_count; i++) {
Hans de Goedebb6d5492010-11-26 19:11:03 +0100679 if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
680 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]);
681 if (ret < 0) {
682 printf("husb error submitting iso urb %d: %d\n", i, errno);
683 if (!in || len == 0) {
684 switch(errno) {
685 case ETIMEDOUT:
686 len = USB_RET_NAK;
Stefan Weil0225e252011-05-07 22:10:53 +0200687 break;
Hans de Goedebb6d5492010-11-26 19:11:03 +0100688 case EPIPE:
689 default:
690 len = USB_RET_STALL;
691 }
Hans de Goede060dc842010-11-26 11:41:08 +0100692 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100693 break;
Hans de Goede060dc842010-11-26 11:41:08 +0100694 }
Hans de Goedebb6d5492010-11-26 19:11:03 +0100695 aurb[i].iso_frame_idx = -1;
Gerd Hoffmann82887262011-06-10 14:00:24 +0200696 change_iso_inflight(s, p->devep, +1);
Hans de Goede060dc842010-11-26 11:41:08 +0100697 }
Hans de Goede060dc842010-11-26 11:41:08 +0100698 }
699 }
700
701 return len;
702}
703
Hans de Goede50b79632011-02-02 17:36:29 +0100704static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
bellardbb36d472005-11-05 14:22:28 +0000705{
Hans de Goede50b79632011-02-02 17:36:29 +0100706 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori64838172008-08-21 19:31:10 +0000707 struct usbdevfs_urb *urb;
aliguori446ab122008-09-14 01:06:09 +0000708 AsyncURB *aurb;
Gerd Hoffmann71138532011-05-16 10:21:51 +0200709 int ret, rem;
710 uint8_t *pbuf;
Hans de Goede060dc842010-11-26 11:41:08 +0100711 uint8_t ep;
712
Hans de Goedea0b5fec2010-11-26 14:56:17 +0100713 if (!is_valid(s, p->devep)) {
714 return USB_RET_NAK;
715 }
716
Hans de Goede060dc842010-11-26 11:41:08 +0100717 if (p->pid == USB_TOKEN_IN) {
718 ep = p->devep | 0x80;
719 } else {
720 ep = p->devep;
721 }
722
723 if (is_halted(s, p->devep)) {
724 ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
725 if (ret < 0) {
726 DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n",
727 ep, errno);
728 return USB_RET_NAK;
729 }
730 clear_halt(s, p->devep);
731 }
732
Hans de Goedebb6d5492010-11-26 19:11:03 +0100733 if (is_isoc(s, p->devep)) {
734 return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
735 }
bellardbb36d472005-11-05 14:22:28 +0000736
Gerd Hoffmann71138532011-05-16 10:21:51 +0200737 rem = p->len;
738 pbuf = p->data;
739 p->len = 0;
740 while (rem) {
741 aurb = async_alloc(s);
742 aurb->packet = p;
balrogb9dc0332007-10-04 22:47:34 +0000743
Gerd Hoffmann71138532011-05-16 10:21:51 +0200744 urb = &aurb->urb;
745 urb->endpoint = ep;
746 urb->type = USBDEVFS_URB_TYPE_BULK;
747 urb->usercontext = s;
748 urb->buffer = pbuf;
aliguori64838172008-08-21 19:31:10 +0000749
Gerd Hoffmann71138532011-05-16 10:21:51 +0200750 if (rem > MAX_USBFS_BUFFER_SIZE) {
751 urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
752 aurb->more = 1;
753 } else {
754 urb->buffer_length = rem;
755 aurb->more = 0;
756 }
757 pbuf += urb->buffer_length;
758 rem -= urb->buffer_length;
aliguori64838172008-08-21 19:31:10 +0000759
Gerd Hoffmann71138532011-05-16 10:21:51 +0200760 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
aliguori64838172008-08-21 19:31:10 +0000761
Gerd Hoffmann71138532011-05-16 10:21:51 +0200762 DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
763 urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
aliguori64838172008-08-21 19:31:10 +0000764
Gerd Hoffmann71138532011-05-16 10:21:51 +0200765 if (ret < 0) {
766 DPRINTF("husb: submit failed. errno %d\n", errno);
767 async_free(aurb);
aliguori64838172008-08-21 19:31:10 +0000768
Gerd Hoffmann71138532011-05-16 10:21:51 +0200769 switch(errno) {
770 case ETIMEDOUT:
771 return USB_RET_NAK;
772 case EPIPE:
773 default:
774 return USB_RET_STALL;
775 }
balrogb9dc0332007-10-04 22:47:34 +0000776 }
777 }
aliguori64838172008-08-21 19:31:10 +0000778
balrogb9dc0332007-10-04 22:47:34 +0000779 return USB_RET_ASYNC;
balrogb9dc0332007-10-04 22:47:34 +0000780}
781
aliguori446ab122008-09-14 01:06:09 +0000782static int ctrl_error(void)
783{
David Ahern27911042010-04-24 10:26:22 -0600784 if (errno == ETIMEDOUT) {
aliguori446ab122008-09-14 01:06:09 +0000785 return USB_RET_NAK;
David Ahern27911042010-04-24 10:26:22 -0600786 } else {
aliguori446ab122008-09-14 01:06:09 +0000787 return USB_RET_STALL;
David Ahern27911042010-04-24 10:26:22 -0600788 }
aliguori446ab122008-09-14 01:06:09 +0000789}
790
791static int usb_host_set_address(USBHostDevice *s, int addr)
792{
malcd0f2c4c2010-02-07 02:03:50 +0300793 DPRINTF("husb: ctrl set addr %u\n", addr);
aliguori446ab122008-09-14 01:06:09 +0000794 s->dev.addr = addr;
795 return 0;
796}
797
798static int usb_host_set_config(USBHostDevice *s, int config)
799{
800 usb_host_release_interfaces(s);
801
802 int ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
David Ahern27911042010-04-24 10:26:22 -0600803
malcd0f2c4c2010-02-07 02:03:50 +0300804 DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
David Ahern27911042010-04-24 10:26:22 -0600805
806 if (ret < 0) {
aliguori446ab122008-09-14 01:06:09 +0000807 return ctrl_error();
David Ahern27911042010-04-24 10:26:22 -0600808 }
aliguori446ab122008-09-14 01:06:09 +0000809 usb_host_claim_interfaces(s, config);
810 return 0;
811}
812
813static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
814{
815 struct usbdevfs_setinterface si;
Hans de Goede060dc842010-11-26 11:41:08 +0100816 int i, ret;
817
Hans de Goede3a4854b2010-11-26 15:02:16 +0100818 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +0100819 if (is_isoc(s, i)) {
820 usb_host_stop_n_free_iso(s, i);
821 }
822 }
aliguori446ab122008-09-14 01:06:09 +0000823
824 si.interface = iface;
825 si.altsetting = alt;
826 ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
aliguori446ab122008-09-14 01:06:09 +0000827
David Ahern27911042010-04-24 10:26:22 -0600828 DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
829 iface, alt, ret, errno);
830
831 if (ret < 0) {
832 return ctrl_error();
833 }
aliguori446ab122008-09-14 01:06:09 +0000834 usb_linux_update_endp_table(s);
835 return 0;
836}
837
Hans de Goede50b79632011-02-02 17:36:29 +0100838static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
839 int request, int value, int index, int length, uint8_t *data)
aliguori446ab122008-09-14 01:06:09 +0000840{
Hans de Goede50b79632011-02-02 17:36:29 +0100841 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
aliguori446ab122008-09-14 01:06:09 +0000842 struct usbdevfs_urb *urb;
843 AsyncURB *aurb;
Hans de Goede50b79632011-02-02 17:36:29 +0100844 int ret;
aliguori446ab122008-09-14 01:06:09 +0000845
David Ahern27911042010-04-24 10:26:22 -0600846 /*
aliguori446ab122008-09-14 01:06:09 +0000847 * Process certain standard device requests.
848 * These are infrequent and are processed synchronously.
849 */
aliguori446ab122008-09-14 01:06:09 +0000850
Hans de Goede50b79632011-02-02 17:36:29 +0100851 /* Note request is (bRequestType << 8) | bRequest */
malcd0f2c4c2010-02-07 02:03:50 +0300852 DPRINTF("husb: ctrl type 0x%x req 0x%x val 0x%x index %u len %u\n",
Hans de Goede50b79632011-02-02 17:36:29 +0100853 request >> 8, request & 0xff, value, index, length);
aliguori446ab122008-09-14 01:06:09 +0000854
Hans de Goede50b79632011-02-02 17:36:29 +0100855 switch (request) {
856 case DeviceOutRequest | USB_REQ_SET_ADDRESS:
857 return usb_host_set_address(s, value);
aliguori446ab122008-09-14 01:06:09 +0000858
Hans de Goede50b79632011-02-02 17:36:29 +0100859 case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
860 return usb_host_set_config(s, value & 0xff);
aliguori446ab122008-09-14 01:06:09 +0000861
Hans de Goede50b79632011-02-02 17:36:29 +0100862 case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
aliguori446ab122008-09-14 01:06:09 +0000863 return usb_host_set_interface(s, index, value);
David Ahern27911042010-04-24 10:26:22 -0600864 }
aliguori446ab122008-09-14 01:06:09 +0000865
866 /* The rest are asynchronous */
867
Hans de Goede50b79632011-02-02 17:36:29 +0100868 if (length > sizeof(dev->data_buf)) {
869 fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
870 length, sizeof(dev->data_buf));
malcb2e3b6e2009-09-12 03:18:18 +0400871 return USB_RET_STALL;
Jim Parisc4c0e232009-08-24 14:56:12 -0400872 }
873
Gerd Hoffmann7a8fc832011-05-16 09:13:05 +0200874 aurb = async_alloc(s);
aliguori446ab122008-09-14 01:06:09 +0000875 aurb->packet = p;
876
David Ahern27911042010-04-24 10:26:22 -0600877 /*
aliguori446ab122008-09-14 01:06:09 +0000878 * Setup ctrl transfer.
879 *
Brad Hardsa0102082011-04-13 19:45:33 +1000880 * s->ctrl is laid out such that data buffer immediately follows
aliguori446ab122008-09-14 01:06:09 +0000881 * 'req' struct which is exactly what usbdevfs expects.
David Ahern27911042010-04-24 10:26:22 -0600882 */
aliguori446ab122008-09-14 01:06:09 +0000883 urb = &aurb->urb;
884
885 urb->type = USBDEVFS_URB_TYPE_CONTROL;
886 urb->endpoint = p->devep;
887
Hans de Goede50b79632011-02-02 17:36:29 +0100888 urb->buffer = &dev->setup_buf;
889 urb->buffer_length = length + 8;
aliguori446ab122008-09-14 01:06:09 +0000890
891 urb->usercontext = s;
892
893 ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
894
malcd0f2c4c2010-02-07 02:03:50 +0300895 DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
aliguori446ab122008-09-14 01:06:09 +0000896
897 if (ret < 0) {
malcd0f2c4c2010-02-07 02:03:50 +0300898 DPRINTF("husb: submit failed. errno %d\n", errno);
aliguori446ab122008-09-14 01:06:09 +0000899 async_free(aurb);
900
901 switch(errno) {
902 case ETIMEDOUT:
903 return USB_RET_NAK;
904 case EPIPE:
905 default:
906 return USB_RET_STALL;
907 }
908 }
909
aliguori446ab122008-09-14 01:06:09 +0000910 return USB_RET_ASYNC;
911}
912
Hans de Goede71d71bb2010-11-10 10:06:24 +0100913static int usb_linux_get_configuration(USBHostDevice *s)
balrogb9dc0332007-10-04 22:47:34 +0000914{
Hans de Goede71d71bb2010-11-10 10:06:24 +0100915 uint8_t configuration;
pbrooke41b3912008-10-28 18:22:59 +0000916 struct usb_ctrltransfer ct;
Hans de Goede71d71bb2010-11-10 10:06:24 +0100917 int ret;
balrogb9dc0332007-10-04 22:47:34 +0000918
Hans de Goede2cc59d82010-11-10 10:06:25 +0100919 if (usb_fs_type == USB_FS_SYS) {
920 char device_name[32], line[1024];
921 int configuration;
922
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200923 sprintf(device_name, "%d-%s", s->bus_num, s->port);
Hans de Goede2cc59d82010-11-10 10:06:25 +0100924
925 if (!usb_host_read_file(line, sizeof(line), "bConfigurationValue",
926 device_name)) {
927 goto usbdevfs;
928 }
929 if (sscanf(line, "%d", &configuration) != 1) {
930 goto usbdevfs;
931 }
932 return configuration;
933 }
934
935usbdevfs:
balrogb9dc0332007-10-04 22:47:34 +0000936 ct.bRequestType = USB_DIR_IN;
937 ct.bRequest = USB_REQ_GET_CONFIGURATION;
938 ct.wValue = 0;
939 ct.wIndex = 0;
940 ct.wLength = 1;
941 ct.data = &configuration;
942 ct.timeout = 50;
943
944 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
945 if (ret < 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100946 perror("usb_linux_get_configuration");
947 return -1;
balrogb9dc0332007-10-04 22:47:34 +0000948 }
949
950 /* in address state */
David Ahern27911042010-04-24 10:26:22 -0600951 if (configuration == 0) {
Hans de Goede71d71bb2010-11-10 10:06:24 +0100952 return -1;
David Ahern27911042010-04-24 10:26:22 -0600953 }
balrogb9dc0332007-10-04 22:47:34 +0000954
Hans de Goede71d71bb2010-11-10 10:06:24 +0100955 return configuration;
956}
957
Hans de Goedeed3a3282010-11-24 12:50:00 +0100958static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
959 uint8_t configuration, uint8_t interface)
960{
961 uint8_t alt_setting;
962 struct usb_ctrltransfer ct;
963 int ret;
964
Hans de Goedec43831f2010-11-24 12:57:59 +0100965 if (usb_fs_type == USB_FS_SYS) {
966 char device_name[64], line[1024];
967 int alt_setting;
968
Gerd Hoffmann5557d822011-05-10 11:43:57 +0200969 sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
Hans de Goedec43831f2010-11-24 12:57:59 +0100970 (int)configuration, (int)interface);
971
972 if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
973 device_name)) {
974 goto usbdevfs;
975 }
976 if (sscanf(line, "%d", &alt_setting) != 1) {
977 goto usbdevfs;
978 }
979 return alt_setting;
980 }
981
982usbdevfs:
Hans de Goedeed3a3282010-11-24 12:50:00 +0100983 ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
984 ct.bRequest = USB_REQ_GET_INTERFACE;
985 ct.wValue = 0;
986 ct.wIndex = interface;
987 ct.wLength = 1;
988 ct.data = &alt_setting;
989 ct.timeout = 50;
990 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
991 if (ret < 0) {
992 /* Assume alt 0 on error */
993 return 0;
994 }
995
996 return alt_setting;
997}
998
Hans de Goede71d71bb2010-11-10 10:06:24 +0100999/* returns 1 on problem encountered or 0 for success */
1000static int usb_linux_update_endp_table(USBHostDevice *s)
1001{
1002 uint8_t *descriptors;
1003 uint8_t devep, type, configuration, alt_interface;
Hans de Goedeed3a3282010-11-24 12:50:00 +01001004 int interface, length, i;
Hans de Goede71d71bb2010-11-10 10:06:24 +01001005
Hans de Goedea0b5fec2010-11-26 14:56:17 +01001006 for (i = 0; i < MAX_ENDPOINTS; i++)
1007 s->endp_table[i].type = INVALID_EP_TYPE;
1008
Hans de Goede71d71bb2010-11-10 10:06:24 +01001009 i = usb_linux_get_configuration(s);
1010 if (i < 0)
1011 return 1;
1012 configuration = i;
1013
balrogb9dc0332007-10-04 22:47:34 +00001014 /* get the desired configuration, interface, and endpoint descriptors
1015 * from device description */
1016 descriptors = &s->descr[18];
1017 length = s->descr_len - 18;
1018 i = 0;
1019
1020 if (descriptors[i + 1] != USB_DT_CONFIG ||
1021 descriptors[i + 5] != configuration) {
malcd0f2c4c2010-02-07 02:03:50 +03001022 DPRINTF("invalid descriptor data - configuration\n");
balrogb9dc0332007-10-04 22:47:34 +00001023 return 1;
1024 }
1025 i += descriptors[i];
1026
1027 while (i < length) {
1028 if (descriptors[i + 1] != USB_DT_INTERFACE ||
1029 (descriptors[i + 1] == USB_DT_INTERFACE &&
1030 descriptors[i + 4] == 0)) {
1031 i += descriptors[i];
1032 continue;
1033 }
1034
1035 interface = descriptors[i + 2];
Hans de Goedeed3a3282010-11-24 12:50:00 +01001036 alt_interface = usb_linux_get_alt_setting(s, configuration, interface);
balrogb9dc0332007-10-04 22:47:34 +00001037
1038 /* the current interface descriptor is the active interface
1039 * and has endpoints */
1040 if (descriptors[i + 3] != alt_interface) {
1041 i += descriptors[i];
1042 continue;
1043 }
1044
1045 /* advance to the endpoints */
David Ahern27911042010-04-24 10:26:22 -06001046 while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001047 i += descriptors[i];
David Ahern27911042010-04-24 10:26:22 -06001048 }
balrogb9dc0332007-10-04 22:47:34 +00001049
1050 if (i >= length)
1051 break;
1052
1053 while (i < length) {
David Ahern27911042010-04-24 10:26:22 -06001054 if (descriptors[i + 1] != USB_DT_ENDPOINT) {
balrogb9dc0332007-10-04 22:47:34 +00001055 break;
David Ahern27911042010-04-24 10:26:22 -06001056 }
balrogb9dc0332007-10-04 22:47:34 +00001057
1058 devep = descriptors[i + 2];
Hans de Goede130314f2011-05-31 11:35:22 +02001059 if ((devep & 0x0f) == 0) {
1060 fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
1061 return 1;
1062 }
1063
balrogb9dc0332007-10-04 22:47:34 +00001064 switch (descriptors[i + 3] & 0x3) {
1065 case 0x00:
1066 type = USBDEVFS_URB_TYPE_CONTROL;
1067 break;
1068 case 0x01:
1069 type = USBDEVFS_URB_TYPE_ISO;
Gerd Hoffmann6dfcdcc2011-05-16 11:30:57 +02001070 set_max_packet_size(s, (devep & 0xf), descriptors + i);
balrogb9dc0332007-10-04 22:47:34 +00001071 break;
1072 case 0x02:
1073 type = USBDEVFS_URB_TYPE_BULK;
1074 break;
1075 case 0x03:
1076 type = USBDEVFS_URB_TYPE_INTERRUPT;
1077 break;
Anthony Liguoriddbda432010-03-17 16:00:24 -05001078 default:
1079 DPRINTF("usb_host: malformed endpoint type\n");
1080 type = USBDEVFS_URB_TYPE_BULK;
balrogb9dc0332007-10-04 22:47:34 +00001081 }
1082 s->endp_table[(devep & 0xf) - 1].type = type;
aliguori64838172008-08-21 19:31:10 +00001083 s->endp_table[(devep & 0xf) - 1].halted = 0;
balrogb9dc0332007-10-04 22:47:34 +00001084
1085 i += descriptors[i];
1086 }
1087 }
1088 return 0;
1089}
1090
Hans de Goedee4b17762011-05-30 11:40:45 +02001091/*
1092 * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
1093 * this function assumes this is safe, if:
1094 * 1) There are no isoc endpoints
1095 * 2) There are no interrupt endpoints with a max_packet_size > 64
1096 * Note bulk endpoints with a max_packet_size > 64 in theory also are not
1097 * usb1 compatible, but in practice this seems to work fine.
1098 */
1099static int usb_linux_full_speed_compat(USBHostDevice *dev)
1100{
1101 int i, packet_size;
1102
1103 /*
1104 * usb_linux_update_endp_table only registers info about ep in the current
1105 * interface altsettings, so we need to parse the descriptors again.
1106 */
1107 for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
1108 if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
1109 switch (dev->descr[i + 3] & 0x3) {
1110 case 0x00: /* CONTROL */
1111 break;
1112 case 0x01: /* ISO */
1113 return 0;
1114 case 0x02: /* BULK */
1115 break;
1116 case 0x03: /* INTERRUPT */
1117 packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
1118 if (packet_size > 64)
1119 return 0;
1120 break;
1121 }
1122 }
1123 }
1124 return 1;
1125}
1126
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001127static int usb_host_open(USBHostDevice *dev, int bus_num,
Hans de Goede3991c352011-05-31 11:35:18 +02001128 int addr, char *port, const char *prod_name, int speed)
bellardbb36d472005-11-05 14:22:28 +00001129{
balrogb9dc0332007-10-04 22:47:34 +00001130 int fd = -1, ret;
bellarda594cfb2005-11-06 16:13:29 +00001131 char buf[1024];
aliguori1f3870a2008-08-21 19:27:48 +00001132
David Ahern27911042010-04-24 10:26:22 -06001133 if (dev->fd != -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001134 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001135 }
aliguori64838172008-08-21 19:31:10 +00001136 printf("husb: open device %d.%d\n", bus_num, addr);
aliguori1f3870a2008-08-21 19:27:48 +00001137
aliguori0f431522008-10-07 20:06:37 +00001138 if (!usb_host_device_path) {
1139 perror("husb: USB Host Device Path not set");
1140 goto fail;
1141 }
1142 snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
bellarda594cfb2005-11-06 16:13:29 +00001143 bus_num, addr);
balrogb9dc0332007-10-04 22:47:34 +00001144 fd = open(buf, O_RDWR | O_NONBLOCK);
bellardbb36d472005-11-05 14:22:28 +00001145 if (fd < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001146 perror(buf);
aliguori1f3870a2008-08-21 19:27:48 +00001147 goto fail;
bellardbb36d472005-11-05 14:22:28 +00001148 }
malcd0f2c4c2010-02-07 02:03:50 +03001149 DPRINTF("husb: opened %s\n", buf);
bellardbb36d472005-11-05 14:22:28 +00001150
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001151 dev->bus_num = bus_num;
1152 dev->addr = addr;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001153 strcpy(dev->port, port);
Gerd Hoffmann22f84e72009-09-25 16:55:28 +02001154 dev->fd = fd;
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001155
balrogb9dc0332007-10-04 22:47:34 +00001156 /* read the device description */
1157 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
1158 if (dev->descr_len <= 0) {
aliguori64838172008-08-21 19:31:10 +00001159 perror("husb: reading device data failed");
bellardbb36d472005-11-05 14:22:28 +00001160 goto fail;
1161 }
ths3b46e622007-09-17 08:09:54 +00001162
balrogb9dc0332007-10-04 22:47:34 +00001163#ifdef DEBUG
bellard868bfe22005-11-13 21:53:15 +00001164 {
balrogb9dc0332007-10-04 22:47:34 +00001165 int x;
1166 printf("=== begin dumping device descriptor data ===\n");
David Ahern27911042010-04-24 10:26:22 -06001167 for (x = 0; x < dev->descr_len; x++) {
balrogb9dc0332007-10-04 22:47:34 +00001168 printf("%02x ", dev->descr[x]);
David Ahern27911042010-04-24 10:26:22 -06001169 }
balrogb9dc0332007-10-04 22:47:34 +00001170 printf("\n=== end dumping device descriptor data ===\n");
bellarda594cfb2005-11-06 16:13:29 +00001171 }
1172#endif
1173
balrogb9dc0332007-10-04 22:47:34 +00001174
David Ahern27911042010-04-24 10:26:22 -06001175 /*
1176 * Initial configuration is -1 which makes us claim first
aliguori446ab122008-09-14 01:06:09 +00001177 * available config. We used to start with 1, which does not
David Ahern27911042010-04-24 10:26:22 -06001178 * always work. I've seen devices where first config starts
aliguori446ab122008-09-14 01:06:09 +00001179 * with 2.
1180 */
David Ahern27911042010-04-24 10:26:22 -06001181 if (!usb_host_claim_interfaces(dev, -1)) {
balrogb9dc0332007-10-04 22:47:34 +00001182 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001183 }
bellardbb36d472005-11-05 14:22:28 +00001184
balrogb9dc0332007-10-04 22:47:34 +00001185 ret = usb_linux_update_endp_table(dev);
David Ahern27911042010-04-24 10:26:22 -06001186 if (ret) {
bellardbb36d472005-11-05 14:22:28 +00001187 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001188 }
balrogb9dc0332007-10-04 22:47:34 +00001189
Hans de Goede3991c352011-05-31 11:35:18 +02001190 if (speed == -1) {
1191 struct usbdevfs_connectinfo ci;
1192
1193 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
1194 if (ret < 0) {
1195 perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
1196 goto fail;
1197 }
1198
1199 if (ci.slow) {
1200 speed = USB_SPEED_LOW;
1201 } else {
1202 speed = USB_SPEED_HIGH;
1203 }
David Ahern27911042010-04-24 10:26:22 -06001204 }
Hans de Goede3991c352011-05-31 11:35:18 +02001205 dev->dev.speed = speed;
Hans de Goedeba3f9bf2011-05-27 14:27:18 +02001206 dev->dev.speedmask = (1 << speed);
Hans de Goedee4b17762011-05-30 11:40:45 +02001207 if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
1208 dev->dev.speedmask |= USB_SPEED_MASK_FULL;
1209 }
Hans de Goede3991c352011-05-31 11:35:18 +02001210
1211 printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
bellardbb36d472005-11-05 14:22:28 +00001212
David Ahern27911042010-04-24 10:26:22 -06001213 if (!prod_name || prod_name[0] == '\0') {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001214 snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001215 "host:%d.%d", bus_num, addr);
David Ahern27911042010-04-24 10:26:22 -06001216 } else {
Markus Armbruster0fe6d122009-12-09 17:07:51 +01001217 pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
aliguori4b096fc2008-08-21 19:28:55 +00001218 prod_name);
David Ahern27911042010-04-24 10:26:22 -06001219 }
bellard1f6e24e2006-06-26 21:00:51 +00001220
Hans de Goedefa19bf82011-05-27 19:05:15 +02001221 ret = usb_device_attach(&dev->dev);
1222 if (ret) {
1223 goto fail;
1224 }
1225
aliguori64838172008-08-21 19:31:10 +00001226 /* USB devio uses 'write' flag to check for async completions */
1227 qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
aliguori1f3870a2008-08-21 19:27:48 +00001228
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001229 return 0;
aliguori4b096fc2008-08-21 19:28:55 +00001230
balrogb9dc0332007-10-04 22:47:34 +00001231fail:
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001232 if (dev->fd != -1) {
1233 close(dev->fd);
1234 dev->fd = -1;
David Ahern27911042010-04-24 10:26:22 -06001235 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001236 return -1;
1237}
1238
1239static int usb_host_close(USBHostDevice *dev)
1240{
Hans de Goede060dc842010-11-26 11:41:08 +01001241 int i;
1242
Gerd Hoffmann1f45a812011-06-06 09:45:20 +02001243 if (dev->fd == -1 || !dev->dev.attached) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001244 return -1;
David Ahern27911042010-04-24 10:26:22 -06001245 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001246
1247 qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
1248 dev->closing = 1;
Hans de Goede3a4854b2010-11-26 15:02:16 +01001249 for (i = 1; i <= MAX_ENDPOINTS; i++) {
Hans de Goede060dc842010-11-26 11:41:08 +01001250 if (is_isoc(dev, i)) {
1251 usb_host_stop_n_free_iso(dev, i);
1252 }
1253 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001254 async_complete(dev);
1255 dev->closing = 0;
1256 usb_device_detach(&dev->dev);
Shahar Havivi00ff2272010-06-16 15:15:37 +03001257 ioctl(dev->fd, USBDEVFS_RESET);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001258 close(dev->fd);
1259 dev->fd = -1;
1260 return 0;
1261}
1262
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001263static void usb_host_exit_notifier(struct Notifier *n, void *data)
Shahar Havivib373a632010-06-16 15:16:11 +03001264{
1265 USBHostDevice *s = container_of(n, USBHostDevice, exit);
1266
1267 if (s->fd != -1) {
1268 ioctl(s->fd, USBDEVFS_RESET);
1269 }
1270}
1271
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001272static int usb_host_initfn(USBDevice *dev)
1273{
1274 USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
1275
1276 dev->auto_attach = 0;
1277 s->fd = -1;
1278 QTAILQ_INSERT_TAIL(&hostdevs, s, next);
Shahar Havivib373a632010-06-16 15:16:11 +03001279 s->exit.notify = usb_host_exit_notifier;
1280 qemu_add_exit_notifier(&s->exit);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001281 usb_host_auto_check(NULL);
1282 return 0;
bellardbb36d472005-11-05 14:22:28 +00001283}
1284
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001285static struct USBDeviceInfo usb_host_dev_info = {
Markus Armbruster06384692009-12-09 17:07:52 +01001286 .product_desc = "USB Host Device",
Markus Armbruster556cd092009-12-09 17:07:53 +01001287 .qdev.name = "usb-host",
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001288 .qdev.size = sizeof(USBHostDevice),
1289 .init = usb_host_initfn,
Hans de Goede50b79632011-02-02 17:36:29 +01001290 .handle_packet = usb_generic_handle_packet,
Gerd Hoffmanneb5e6802011-05-16 10:34:53 +02001291 .cancel_packet = usb_host_async_cancel,
Hans de Goede50b79632011-02-02 17:36:29 +01001292 .handle_data = usb_host_handle_data,
1293 .handle_control = usb_host_handle_control,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001294 .handle_reset = usb_host_handle_reset,
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001295 .handle_destroy = usb_host_handle_destroy,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001296 .usbdevice_name = "host",
1297 .usbdevice_init = usb_host_device_open,
1298 .qdev.props = (Property[]) {
1299 DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
1300 DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001301 DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001302 DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
1303 DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
Gerd Hoffmannb81bcd82011-06-10 14:03:56 +02001304 DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001305 DEFINE_PROP_END_OF_LIST(),
1306 },
Gerd Hoffmann806b6022009-08-31 14:23:59 +02001307};
1308
1309static void usb_host_register_devices(void)
1310{
1311 usb_qdev_register(&usb_host_dev_info);
1312}
1313device_init(usb_host_register_devices)
1314
aliguori4b096fc2008-08-21 19:28:55 +00001315USBDevice *usb_host_device_open(const char *devname)
1316{
Markus Armbruster0745eb12009-11-27 13:05:53 +01001317 struct USBAutoFilter filter;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001318 USBDevice *dev;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001319 char *p;
1320
Markus Armbruster556cd092009-12-09 17:07:53 +01001321 dev = usb_create(NULL /* FIXME */, "usb-host");
aliguori4b096fc2008-08-21 19:28:55 +00001322
aliguori5d0c5752008-09-14 01:07:41 +00001323 if (strstr(devname, "auto:")) {
David Ahern27911042010-04-24 10:26:22 -06001324 if (parse_filter(devname, &filter) < 0) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001325 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001326 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001327 } else {
1328 if ((p = strchr(devname, '.'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001329 filter.bus_num = strtoul(devname, NULL, 0);
1330 filter.addr = strtoul(p + 1, NULL, 0);
1331 filter.vendor_id = 0;
1332 filter.product_id = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001333 } else if ((p = strchr(devname, ':'))) {
Markus Armbruster0745eb12009-11-27 13:05:53 +01001334 filter.bus_num = 0;
1335 filter.addr = 0;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001336 filter.vendor_id = strtoul(devname, NULL, 16);
Markus Armbruster0745eb12009-11-27 13:05:53 +01001337 filter.product_id = strtoul(p + 1, NULL, 16);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001338 } else {
1339 goto fail;
1340 }
aliguori5d0c5752008-09-14 01:07:41 +00001341 }
1342
Markus Armbruster0745eb12009-11-27 13:05:53 +01001343 qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num);
1344 qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001345 qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
1346 qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
Kevin Wolfbeb6f0d2010-01-15 12:56:41 +01001347 qdev_init_nofail(&dev->qdev);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001348 return dev;
aliguori4b096fc2008-08-21 19:28:55 +00001349
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001350fail:
1351 qdev_free(&dev->qdev);
1352 return NULL;
aliguori4b096fc2008-08-21 19:28:55 +00001353}
aliguori5d0c5752008-09-14 01:07:41 +00001354
1355int usb_host_device_close(const char *devname)
1356{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001357#if 0
aliguori5d0c5752008-09-14 01:07:41 +00001358 char product_name[PRODUCT_NAME_SZ];
1359 int bus_num, addr;
1360 USBHostDevice *s;
1361
David Ahern27911042010-04-24 10:26:22 -06001362 if (strstr(devname, "auto:")) {
aliguori5d0c5752008-09-14 01:07:41 +00001363 return usb_host_auto_del(devname);
David Ahern27911042010-04-24 10:26:22 -06001364 }
1365 if (usb_host_find_device(&bus_num, &addr, product_name,
1366 sizeof(product_name), devname) < 0) {
aliguori5d0c5752008-09-14 01:07:41 +00001367 return -1;
David Ahern27911042010-04-24 10:26:22 -06001368 }
aliguori5d0c5752008-09-14 01:07:41 +00001369 s = hostdev_find(bus_num, addr);
1370 if (s) {
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001371 usb_device_delete_addr(s->bus_num, s->dev.addr);
aliguori5d0c5752008-09-14 01:07:41 +00001372 return 0;
1373 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001374#endif
aliguori5d0c5752008-09-14 01:07:41 +00001375
1376 return -1;
1377}
Gerd Hoffmanna5d2f722009-08-31 14:24:00 +02001378
bellarda594cfb2005-11-06 16:13:29 +00001379static int get_tag_value(char *buf, int buf_size,
ths5fafdf22007-09-16 21:08:06 +00001380 const char *str, const char *tag,
bellarda594cfb2005-11-06 16:13:29 +00001381 const char *stopchars)
bellardbb36d472005-11-05 14:22:28 +00001382{
bellarda594cfb2005-11-06 16:13:29 +00001383 const char *p;
1384 char *q;
1385 p = strstr(str, tag);
David Ahern27911042010-04-24 10:26:22 -06001386 if (!p) {
bellarda594cfb2005-11-06 16:13:29 +00001387 return -1;
David Ahern27911042010-04-24 10:26:22 -06001388 }
bellarda594cfb2005-11-06 16:13:29 +00001389 p += strlen(tag);
David Ahern27911042010-04-24 10:26:22 -06001390 while (qemu_isspace(*p)) {
bellarda594cfb2005-11-06 16:13:29 +00001391 p++;
David Ahern27911042010-04-24 10:26:22 -06001392 }
bellarda594cfb2005-11-06 16:13:29 +00001393 q = buf;
1394 while (*p != '\0' && !strchr(stopchars, *p)) {
David Ahern27911042010-04-24 10:26:22 -06001395 if ((q - buf) < (buf_size - 1)) {
bellarda594cfb2005-11-06 16:13:29 +00001396 *q++ = *p;
David Ahern27911042010-04-24 10:26:22 -06001397 }
bellarda594cfb2005-11-06 16:13:29 +00001398 p++;
1399 }
1400 *q = '\0';
1401 return q - buf;
1402}
bellardbb36d472005-11-05 14:22:28 +00001403
aliguori0f431522008-10-07 20:06:37 +00001404/*
1405 * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
1406 * host's USB devices. This is legacy support since many distributions
1407 * are moving to /sys/bus/usb
1408 */
1409static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
bellarda594cfb2005-11-06 16:13:29 +00001410{
Blue Swirl660f11b2009-07-31 21:16:51 +00001411 FILE *f = NULL;
bellarda594cfb2005-11-06 16:13:29 +00001412 char line[1024];
1413 char buf[1024];
1414 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
bellarda594cfb2005-11-06 16:13:29 +00001415 char product_name[512];
aliguori0f431522008-10-07 20:06:37 +00001416 int ret = 0;
ths3b46e622007-09-17 08:09:54 +00001417
aliguori0f431522008-10-07 20:06:37 +00001418 if (!usb_host_device_path) {
1419 perror("husb: USB Host Device Path not set");
1420 goto the_end;
bellarda594cfb2005-11-06 16:13:29 +00001421 }
aliguori0f431522008-10-07 20:06:37 +00001422 snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
1423 f = fopen(line, "r");
1424 if (!f) {
1425 perror("husb: cannot open devices file");
1426 goto the_end;
1427 }
1428
bellarda594cfb2005-11-06 16:13:29 +00001429 device_count = 0;
Hans de Goede3991c352011-05-31 11:35:18 +02001430 bus_num = addr = class_id = product_id = vendor_id = 0;
1431 speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
bellardbb36d472005-11-05 14:22:28 +00001432 for(;;) {
David Ahern27911042010-04-24 10:26:22 -06001433 if (fgets(line, sizeof(line), f) == NULL) {
bellardbb36d472005-11-05 14:22:28 +00001434 break;
David Ahern27911042010-04-24 10:26:22 -06001435 }
1436 if (strlen(line) > 0) {
bellarda594cfb2005-11-06 16:13:29 +00001437 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001438 }
bellarda594cfb2005-11-06 16:13:29 +00001439 if (line[0] == 'T' && line[1] == ':') {
pbrook38ca0f62006-03-11 18:03:38 +00001440 if (device_count && (vendor_id || product_id)) {
1441 /* New device. Add the previously discovered device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001442 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001443 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001444 if (ret) {
bellarda594cfb2005-11-06 16:13:29 +00001445 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001446 }
bellarda594cfb2005-11-06 16:13:29 +00001447 }
David Ahern27911042010-04-24 10:26:22 -06001448 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001449 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001450 }
bellarda594cfb2005-11-06 16:13:29 +00001451 bus_num = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001452 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001453 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001454 }
bellarda594cfb2005-11-06 16:13:29 +00001455 addr = atoi(buf);
David Ahern27911042010-04-24 10:26:22 -06001456 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001457 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001458 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001459 if (!strcmp(buf, "5000")) {
1460 speed = USB_SPEED_SUPER;
1461 } else if (!strcmp(buf, "480")) {
bellarda594cfb2005-11-06 16:13:29 +00001462 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001463 } else if (!strcmp(buf, "1.5")) {
bellarda594cfb2005-11-06 16:13:29 +00001464 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001465 } else {
bellarda594cfb2005-11-06 16:13:29 +00001466 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001467 }
bellarda594cfb2005-11-06 16:13:29 +00001468 product_name[0] = '\0';
1469 class_id = 0xff;
1470 device_count++;
1471 product_id = 0;
1472 vendor_id = 0;
1473 } else if (line[0] == 'P' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001474 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001475 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001476 }
bellarda594cfb2005-11-06 16:13:29 +00001477 vendor_id = strtoul(buf, NULL, 16);
David Ahern27911042010-04-24 10:26:22 -06001478 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001479 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001480 }
bellarda594cfb2005-11-06 16:13:29 +00001481 product_id = strtoul(buf, NULL, 16);
1482 } else if (line[0] == 'S' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001483 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001484 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001485 }
bellarda594cfb2005-11-06 16:13:29 +00001486 pstrcpy(product_name, sizeof(product_name), buf);
1487 } else if (line[0] == 'D' && line[1] == ':') {
David Ahern27911042010-04-24 10:26:22 -06001488 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
bellarda594cfb2005-11-06 16:13:29 +00001489 goto fail;
David Ahern27911042010-04-24 10:26:22 -06001490 }
bellarda594cfb2005-11-06 16:13:29 +00001491 class_id = strtoul(buf, NULL, 16);
1492 }
1493 fail: ;
1494 }
pbrook38ca0f62006-03-11 18:03:38 +00001495 if (device_count && (vendor_id || product_id)) {
1496 /* Add the last device. */
Hans de Goede0f5160d2010-11-10 10:06:23 +01001497 ret = func(opaque, bus_num, addr, 0, class_id, vendor_id,
bellarda594cfb2005-11-06 16:13:29 +00001498 product_id, product_name, speed);
1499 }
1500 the_end:
David Ahern27911042010-04-24 10:26:22 -06001501 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001502 fclose(f);
David Ahern27911042010-04-24 10:26:22 -06001503 }
aliguori0f431522008-10-07 20:06:37 +00001504 return ret;
1505}
1506
1507/*
1508 * Read sys file-system device file
1509 *
1510 * @line address of buffer to put file contents in
1511 * @line_size size of line
1512 * @device_file path to device file (printf format string)
1513 * @device_name device being opened (inserted into device_file)
1514 *
1515 * @return 0 failed, 1 succeeded ('line' contains data)
1516 */
David Ahern27911042010-04-24 10:26:22 -06001517static int usb_host_read_file(char *line, size_t line_size,
1518 const char *device_file, const char *device_name)
aliguori0f431522008-10-07 20:06:37 +00001519{
1520 FILE *f;
1521 int ret = 0;
1522 char filename[PATH_MAX];
1523
blueswir1b4e237a2008-12-28 15:45:20 +00001524 snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
1525 device_file);
aliguori0f431522008-10-07 20:06:37 +00001526 f = fopen(filename, "r");
1527 if (f) {
Kirill A. Shutemov9f99cee2010-01-20 00:56:17 +01001528 ret = fgets(line, line_size, f) != NULL;
aliguori0f431522008-10-07 20:06:37 +00001529 fclose(f);
aliguori0f431522008-10-07 20:06:37 +00001530 }
1531
1532 return ret;
1533}
1534
1535/*
1536 * Use /sys/bus/usb/devices/ directory to determine host's USB
1537 * devices.
1538 *
1539 * This code is based on Robert Schiele's original patches posted to
1540 * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
1541 */
1542static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
1543{
Blue Swirl660f11b2009-07-31 21:16:51 +00001544 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001545 char line[1024];
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001546 int bus_num, addr, speed, class_id, product_id, vendor_id;
aliguori0f431522008-10-07 20:06:37 +00001547 int ret = 0;
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001548 char port[MAX_PORTLEN];
aliguori0f431522008-10-07 20:06:37 +00001549 char product_name[512];
1550 struct dirent *de;
1551
1552 dir = opendir(USBSYSBUS_PATH "/devices");
1553 if (!dir) {
1554 perror("husb: cannot open devices directory");
1555 goto the_end;
1556 }
1557
1558 while ((de = readdir(dir))) {
1559 if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001560 if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
1561 continue;
Hans de Goede0f5160d2010-11-10 10:06:23 +01001562 }
aliguori0f431522008-10-07 20:06:37 +00001563
David Ahern27911042010-04-24 10:26:22 -06001564 if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001565 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001566 }
1567 if (sscanf(line, "%d", &addr) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001568 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001569 }
blueswir1b4e237a2008-12-28 15:45:20 +00001570 if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
David Ahern27911042010-04-24 10:26:22 -06001571 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001572 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001573 }
1574 if (sscanf(line, "%x", &class_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001575 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001576 }
aliguori0f431522008-10-07 20:06:37 +00001577
David Ahern27911042010-04-24 10:26:22 -06001578 if (!usb_host_read_file(line, sizeof(line), "idVendor",
1579 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001580 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001581 }
1582 if (sscanf(line, "%x", &vendor_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001583 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001584 }
blueswir1b4e237a2008-12-28 15:45:20 +00001585 if (!usb_host_read_file(line, sizeof(line), "idProduct",
David Ahern27911042010-04-24 10:26:22 -06001586 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001587 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001588 }
1589 if (sscanf(line, "%x", &product_id) != 1) {
aliguori0f431522008-10-07 20:06:37 +00001590 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001591 }
blueswir1b4e237a2008-12-28 15:45:20 +00001592 if (!usb_host_read_file(line, sizeof(line), "product",
1593 de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001594 *product_name = 0;
1595 } else {
David Ahern27911042010-04-24 10:26:22 -06001596 if (strlen(line) > 0) {
aliguori0f431522008-10-07 20:06:37 +00001597 line[strlen(line) - 1] = '\0';
David Ahern27911042010-04-24 10:26:22 -06001598 }
aliguori0f431522008-10-07 20:06:37 +00001599 pstrcpy(product_name, sizeof(product_name), line);
1600 }
1601
David Ahern27911042010-04-24 10:26:22 -06001602 if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
aliguori0f431522008-10-07 20:06:37 +00001603 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001604 }
Hans de Goedef264cfb2011-05-31 11:35:19 +02001605 if (!strcmp(line, "5000\n")) {
1606 speed = USB_SPEED_SUPER;
1607 } else if (!strcmp(line, "480\n")) {
aliguori0f431522008-10-07 20:06:37 +00001608 speed = USB_SPEED_HIGH;
David Ahern27911042010-04-24 10:26:22 -06001609 } else if (!strcmp(line, "1.5\n")) {
aliguori0f431522008-10-07 20:06:37 +00001610 speed = USB_SPEED_LOW;
David Ahern27911042010-04-24 10:26:22 -06001611 } else {
aliguori0f431522008-10-07 20:06:37 +00001612 speed = USB_SPEED_FULL;
David Ahern27911042010-04-24 10:26:22 -06001613 }
aliguori0f431522008-10-07 20:06:37 +00001614
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001615 ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
aliguori0f431522008-10-07 20:06:37 +00001616 product_id, product_name, speed);
David Ahern27911042010-04-24 10:26:22 -06001617 if (ret) {
aliguori0f431522008-10-07 20:06:37 +00001618 goto the_end;
David Ahern27911042010-04-24 10:26:22 -06001619 }
aliguori0f431522008-10-07 20:06:37 +00001620 }
1621 }
1622 the_end:
David Ahern27911042010-04-24 10:26:22 -06001623 if (dir) {
aliguori0f431522008-10-07 20:06:37 +00001624 closedir(dir);
David Ahern27911042010-04-24 10:26:22 -06001625 }
aliguori0f431522008-10-07 20:06:37 +00001626 return ret;
1627}
1628
1629/*
1630 * Determine how to access the host's USB devices and call the
1631 * specific support function.
1632 */
1633static int usb_host_scan(void *opaque, USBScanFunc *func)
1634{
aliguori376253e2009-03-05 23:01:23 +00001635 Monitor *mon = cur_mon;
Blue Swirl660f11b2009-07-31 21:16:51 +00001636 FILE *f = NULL;
1637 DIR *dir = NULL;
aliguori0f431522008-10-07 20:06:37 +00001638 int ret = 0;
aliguori0f431522008-10-07 20:06:37 +00001639 const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
1640 char devpath[PATH_MAX];
1641
1642 /* only check the host once */
1643 if (!usb_fs_type) {
Mark McLoughlin55496242009-07-03 09:28:02 +01001644 dir = opendir(USBSYSBUS_PATH "/devices");
1645 if (dir) {
1646 /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
1647 strcpy(devpath, USBDEVBUS_PATH);
1648 usb_fs_type = USB_FS_SYS;
1649 closedir(dir);
malcd0f2c4c2010-02-07 02:03:50 +03001650 DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
Mark McLoughlin55496242009-07-03 09:28:02 +01001651 goto found_devices;
1652 }
aliguori0f431522008-10-07 20:06:37 +00001653 f = fopen(USBPROCBUS_PATH "/devices", "r");
1654 if (f) {
1655 /* devices found in /proc/bus/usb/ */
1656 strcpy(devpath, USBPROCBUS_PATH);
1657 usb_fs_type = USB_FS_PROC;
1658 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001659 DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001660 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001661 }
1662 /* try additional methods if an access method hasn't been found yet */
1663 f = fopen(USBDEVBUS_PATH "/devices", "r");
aliguorif16a0db2008-10-21 16:34:20 +00001664 if (f) {
aliguori0f431522008-10-07 20:06:37 +00001665 /* devices found in /dev/bus/usb/ */
1666 strcpy(devpath, USBDEVBUS_PATH);
1667 usb_fs_type = USB_FS_DEV;
1668 fclose(f);
malcd0f2c4c2010-02-07 02:03:50 +03001669 DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
aliguorif16a0db2008-10-21 16:34:20 +00001670 goto found_devices;
aliguori0f431522008-10-07 20:06:37 +00001671 }
aliguorif16a0db2008-10-21 16:34:20 +00001672 found_devices:
aliguori22babeb2008-10-21 16:27:28 +00001673 if (!usb_fs_type) {
David Ahern27911042010-04-24 10:26:22 -06001674 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001675 monitor_printf(mon, "husb: unable to access USB devices\n");
David Ahern27911042010-04-24 10:26:22 -06001676 }
aliguorif16a0db2008-10-21 16:34:20 +00001677 return -ENOENT;
aliguori0f431522008-10-07 20:06:37 +00001678 }
1679
1680 /* the module setting (used later for opening devices) */
1681 usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
aliguori1eec6142009-02-05 22:06:18 +00001682 strcpy(usb_host_device_path, devpath);
David Ahern27911042010-04-24 10:26:22 -06001683 if (mon) {
Gerd Hoffmanneba6fe82009-12-15 11:43:02 +01001684 monitor_printf(mon, "husb: using %s file-system with %s\n",
1685 fs_type[usb_fs_type], usb_host_device_path);
David Ahern27911042010-04-24 10:26:22 -06001686 }
aliguori0f431522008-10-07 20:06:37 +00001687 }
1688
1689 switch (usb_fs_type) {
1690 case USB_FS_PROC:
1691 case USB_FS_DEV:
1692 ret = usb_host_scan_dev(opaque, func);
1693 break;
1694 case USB_FS_SYS:
1695 ret = usb_host_scan_sys(opaque, func);
1696 break;
aliguorif16a0db2008-10-21 16:34:20 +00001697 default:
1698 ret = -EINVAL;
1699 break;
aliguori0f431522008-10-07 20:06:37 +00001700 }
bellarda594cfb2005-11-06 16:13:29 +00001701 return ret;
1702}
1703
aliguori4b096fc2008-08-21 19:28:55 +00001704static QEMUTimer *usb_auto_timer;
aliguori4b096fc2008-08-21 19:28:55 +00001705
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001706static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001707 int class_id, int vendor_id, int product_id,
1708 const char *product_name, int speed)
aliguori4b096fc2008-08-21 19:28:55 +00001709{
1710 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001711 struct USBHostDevice *s;
aliguori4b096fc2008-08-21 19:28:55 +00001712
1713 /* Ignore hubs */
1714 if (class_id == 9)
1715 return 0;
1716
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001717 QTAILQ_FOREACH(s, &hostdevs, next) {
1718 f = &s->match;
1719
David Ahern27911042010-04-24 10:26:22 -06001720 if (f->bus_num > 0 && f->bus_num != bus_num) {
aliguori4b096fc2008-08-21 19:28:55 +00001721 continue;
David Ahern27911042010-04-24 10:26:22 -06001722 }
1723 if (f->addr > 0 && f->addr != addr) {
aliguori4b096fc2008-08-21 19:28:55 +00001724 continue;
David Ahern27911042010-04-24 10:26:22 -06001725 }
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001726 if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) {
1727 continue;
1728 }
aliguori4b096fc2008-08-21 19:28:55 +00001729
David Ahern27911042010-04-24 10:26:22 -06001730 if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001731 continue;
David Ahern27911042010-04-24 10:26:22 -06001732 }
aliguori4b096fc2008-08-21 19:28:55 +00001733
David Ahern27911042010-04-24 10:26:22 -06001734 if (f->product_id > 0 && f->product_id != product_id) {
aliguori4b096fc2008-08-21 19:28:55 +00001735 continue;
David Ahern27911042010-04-24 10:26:22 -06001736 }
aliguori4b096fc2008-08-21 19:28:55 +00001737 /* We got a match */
1738
Markus Armbruster33e66b82009-10-07 01:15:57 +02001739 /* Already attached ? */
David Ahern27911042010-04-24 10:26:22 -06001740 if (s->fd != -1) {
aliguori4b096fc2008-08-21 19:28:55 +00001741 return 0;
David Ahern27911042010-04-24 10:26:22 -06001742 }
malcd0f2c4c2010-02-07 02:03:50 +03001743 DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
aliguori4b096fc2008-08-21 19:28:55 +00001744
Hans de Goede3991c352011-05-31 11:35:18 +02001745 usb_host_open(s, bus_num, addr, port, product_name, speed);
Hans de Goede97f86162011-05-31 11:35:24 +02001746 break;
aliguori4b096fc2008-08-21 19:28:55 +00001747 }
1748
1749 return 0;
1750}
1751
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001752static void usb_host_auto_check(void *unused)
aliguori4b096fc2008-08-21 19:28:55 +00001753{
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001754 struct USBHostDevice *s;
1755 int unconnected = 0;
1756
aliguori4b096fc2008-08-21 19:28:55 +00001757 usb_host_scan(NULL, usb_host_auto_scan);
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001758
1759 QTAILQ_FOREACH(s, &hostdevs, next) {
David Ahern27911042010-04-24 10:26:22 -06001760 if (s->fd == -1) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001761 unconnected++;
David Ahern27911042010-04-24 10:26:22 -06001762 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001763 }
1764
1765 if (unconnected == 0) {
1766 /* nothing to watch */
David Ahern27911042010-04-24 10:26:22 -06001767 if (usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001768 qemu_del_timer(usb_auto_timer);
David Ahern27911042010-04-24 10:26:22 -06001769 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001770 return;
1771 }
1772
1773 if (!usb_auto_timer) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001774 usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
David Ahern27911042010-04-24 10:26:22 -06001775 if (!usb_auto_timer) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001776 return;
David Ahern27911042010-04-24 10:26:22 -06001777 }
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001778 }
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001779 qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
aliguori4b096fc2008-08-21 19:28:55 +00001780}
1781
1782/*
aliguori5d0c5752008-09-14 01:07:41 +00001783 * Autoconnect filter
1784 * Format:
1785 * auto:bus:dev[:vid:pid]
1786 * auto:bus.dev[:vid:pid]
1787 *
1788 * bus - bus number (dec, * means any)
1789 * dev - device number (dec, * means any)
1790 * vid - vendor id (hex, * means any)
1791 * pid - product id (hex, * means any)
1792 *
1793 * See 'lsusb' output.
aliguori4b096fc2008-08-21 19:28:55 +00001794 */
aliguori5d0c5752008-09-14 01:07:41 +00001795static int parse_filter(const char *spec, struct USBAutoFilter *f)
aliguori4b096fc2008-08-21 19:28:55 +00001796{
aliguori5d0c5752008-09-14 01:07:41 +00001797 enum { BUS, DEV, VID, PID, DONE };
1798 const char *p = spec;
1799 int i;
1800
Markus Armbruster0745eb12009-11-27 13:05:53 +01001801 f->bus_num = 0;
1802 f->addr = 0;
1803 f->vendor_id = 0;
1804 f->product_id = 0;
aliguori5d0c5752008-09-14 01:07:41 +00001805
1806 for (i = BUS; i < DONE; i++) {
David Ahern27911042010-04-24 10:26:22 -06001807 p = strpbrk(p, ":.");
1808 if (!p) {
1809 break;
1810 }
aliguori5d0c5752008-09-14 01:07:41 +00001811 p++;
aliguori5d0c5752008-09-14 01:07:41 +00001812
David Ahern27911042010-04-24 10:26:22 -06001813 if (*p == '*') {
1814 continue;
1815 }
aliguori5d0c5752008-09-14 01:07:41 +00001816 switch(i) {
1817 case BUS: f->bus_num = strtol(p, NULL, 10); break;
1818 case DEV: f->addr = strtol(p, NULL, 10); break;
1819 case VID: f->vendor_id = strtol(p, NULL, 16); break;
1820 case PID: f->product_id = strtol(p, NULL, 16); break;
1821 }
aliguori4b096fc2008-08-21 19:28:55 +00001822 }
1823
aliguori5d0c5752008-09-14 01:07:41 +00001824 if (i < DEV) {
1825 fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
1826 return -1;
1827 }
1828
1829 return 0;
1830}
1831
bellarda594cfb2005-11-06 16:13:29 +00001832/**********************/
1833/* USB host device info */
bellardbb36d472005-11-05 14:22:28 +00001834
bellarda594cfb2005-11-06 16:13:29 +00001835struct usb_class_info {
1836 int class;
1837 const char *class_name;
1838};
1839
1840static const struct usb_class_info usb_class_info[] = {
1841 { USB_CLASS_AUDIO, "Audio"},
1842 { USB_CLASS_COMM, "Communication"},
1843 { USB_CLASS_HID, "HID"},
1844 { USB_CLASS_HUB, "Hub" },
1845 { USB_CLASS_PHYSICAL, "Physical" },
1846 { USB_CLASS_PRINTER, "Printer" },
1847 { USB_CLASS_MASS_STORAGE, "Storage" },
1848 { USB_CLASS_CDC_DATA, "Data" },
1849 { USB_CLASS_APP_SPEC, "Application Specific" },
1850 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
1851 { USB_CLASS_STILL_IMAGE, "Still Image" },
balrogb9dc0332007-10-04 22:47:34 +00001852 { USB_CLASS_CSCID, "Smart Card" },
bellarda594cfb2005-11-06 16:13:29 +00001853 { USB_CLASS_CONTENT_SEC, "Content Security" },
1854 { -1, NULL }
1855};
1856
1857static const char *usb_class_str(uint8_t class)
1858{
1859 const struct usb_class_info *p;
1860 for(p = usb_class_info; p->class != -1; p++) {
David Ahern27911042010-04-24 10:26:22 -06001861 if (p->class == class) {
bellardbb36d472005-11-05 14:22:28 +00001862 break;
David Ahern27911042010-04-24 10:26:22 -06001863 }
bellardbb36d472005-11-05 14:22:28 +00001864 }
bellarda594cfb2005-11-06 16:13:29 +00001865 return p->class_name;
bellardbb36d472005-11-05 14:22:28 +00001866}
1867
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001868static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
1869 int class_id, int vendor_id, int product_id,
pbrook9596ebb2007-11-18 01:44:38 +00001870 const char *product_name,
1871 int speed)
bellardbb36d472005-11-05 14:22:28 +00001872{
bellarda594cfb2005-11-06 16:13:29 +00001873 const char *class_str, *speed_str;
1874
1875 switch(speed) {
ths5fafdf22007-09-16 21:08:06 +00001876 case USB_SPEED_LOW:
1877 speed_str = "1.5";
bellarda594cfb2005-11-06 16:13:29 +00001878 break;
ths5fafdf22007-09-16 21:08:06 +00001879 case USB_SPEED_FULL:
1880 speed_str = "12";
bellarda594cfb2005-11-06 16:13:29 +00001881 break;
ths5fafdf22007-09-16 21:08:06 +00001882 case USB_SPEED_HIGH:
1883 speed_str = "480";
bellarda594cfb2005-11-06 16:13:29 +00001884 break;
Hans de Goedef264cfb2011-05-31 11:35:19 +02001885 case USB_SPEED_SUPER:
1886 speed_str = "5000";
1887 break;
bellarda594cfb2005-11-06 16:13:29 +00001888 default:
ths5fafdf22007-09-16 21:08:06 +00001889 speed_str = "?";
bellarda594cfb2005-11-06 16:13:29 +00001890 break;
bellardbb36d472005-11-05 14:22:28 +00001891 }
bellarda594cfb2005-11-06 16:13:29 +00001892
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001893 monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
1894 bus_num, addr, port, speed_str);
bellarda594cfb2005-11-06 16:13:29 +00001895 class_str = usb_class_str(class_id);
David Ahern27911042010-04-24 10:26:22 -06001896 if (class_str) {
aliguori376253e2009-03-05 23:01:23 +00001897 monitor_printf(mon, " %s:", class_str);
David Ahern27911042010-04-24 10:26:22 -06001898 } else {
aliguori376253e2009-03-05 23:01:23 +00001899 monitor_printf(mon, " Class %02x:", class_id);
David Ahern27911042010-04-24 10:26:22 -06001900 }
aliguori376253e2009-03-05 23:01:23 +00001901 monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
David Ahern27911042010-04-24 10:26:22 -06001902 if (product_name[0] != '\0') {
aliguori376253e2009-03-05 23:01:23 +00001903 monitor_printf(mon, ", %s", product_name);
David Ahern27911042010-04-24 10:26:22 -06001904 }
aliguori376253e2009-03-05 23:01:23 +00001905 monitor_printf(mon, "\n");
bellarda594cfb2005-11-06 16:13:29 +00001906}
1907
ths5fafdf22007-09-16 21:08:06 +00001908static int usb_host_info_device(void *opaque, int bus_num, int addr,
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001909 char *path, int class_id,
ths5fafdf22007-09-16 21:08:06 +00001910 int vendor_id, int product_id,
bellarda594cfb2005-11-06 16:13:29 +00001911 const char *product_name,
1912 int speed)
1913{
Blue Swirl179da8a2009-09-07 19:00:18 +00001914 Monitor *mon = opaque;
1915
Gerd Hoffmann5557d822011-05-10 11:43:57 +02001916 usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
bellarda594cfb2005-11-06 16:13:29 +00001917 product_name, speed);
1918 return 0;
1919}
1920
aliguoriac4ffb52008-09-22 15:04:31 +00001921static void dec2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001922{
David Ahern27911042010-04-24 10:26:22 -06001923 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001924 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001925 } else {
1926 snprintf(str, size, "%d", val);
1927 }
aliguori5d0c5752008-09-14 01:07:41 +00001928}
1929
aliguoriac4ffb52008-09-22 15:04:31 +00001930static void hex2str(int val, char *str, size_t size)
aliguori5d0c5752008-09-14 01:07:41 +00001931{
David Ahern27911042010-04-24 10:26:22 -06001932 if (val == 0) {
aliguoriac4ffb52008-09-22 15:04:31 +00001933 snprintf(str, size, "*");
David Ahern27911042010-04-24 10:26:22 -06001934 } else {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001935 snprintf(str, size, "%04x", val);
David Ahern27911042010-04-24 10:26:22 -06001936 }
aliguori5d0c5752008-09-14 01:07:41 +00001937}
1938
aliguori376253e2009-03-05 23:01:23 +00001939void usb_host_info(Monitor *mon)
bellarda594cfb2005-11-06 16:13:29 +00001940{
aliguori5d0c5752008-09-14 01:07:41 +00001941 struct USBAutoFilter *f;
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001942 struct USBHostDevice *s;
aliguori5d0c5752008-09-14 01:07:41 +00001943
Blue Swirl179da8a2009-09-07 19:00:18 +00001944 usb_host_scan(mon, usb_host_info_device);
aliguori5d0c5752008-09-14 01:07:41 +00001945
David Ahern27911042010-04-24 10:26:22 -06001946 if (QTAILQ_EMPTY(&hostdevs)) {
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001947 return;
David Ahern27911042010-04-24 10:26:22 -06001948 }
1949
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001950 monitor_printf(mon, " Auto filters:\n");
1951 QTAILQ_FOREACH(s, &hostdevs, next) {
aliguori5d0c5752008-09-14 01:07:41 +00001952 char bus[10], addr[10], vid[10], pid[10];
Gerd Hoffmann26a9e822009-10-26 15:56:50 +01001953 f = &s->match;
aliguoriac4ffb52008-09-22 15:04:31 +00001954 dec2str(f->bus_num, bus, sizeof(bus));
1955 dec2str(f->addr, addr, sizeof(addr));
1956 hex2str(f->vendor_id, vid, sizeof(vid));
1957 hex2str(f->product_id, pid, sizeof(pid));
Gerd Hoffmann9056a292011-05-10 12:07:42 +02001958 monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
1959 bus, addr, f->port ? f->port : "*", vid, pid);
aliguori5d0c5752008-09-14 01:07:41 +00001960 }
bellardbb36d472005-11-05 14:22:28 +00001961}