root / hw / usb / host-libusb.c @ c3268cc1
History | View | Annotate | Download (44.1 kB)
1 |
/*
|
---|---|
2 |
* Linux host USB redirector
|
3 |
*
|
4 |
* Copyright (c) 2005 Fabrice Bellard
|
5 |
*
|
6 |
* Copyright (c) 2008 Max Krasnyansky
|
7 |
* Support for host device auto connect & disconnect
|
8 |
* Major rewrite to support fully async operation
|
9 |
*
|
10 |
* 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 |
*
|
14 |
* (c) 2012 Gerd Hoffmann <kraxel@redhat.com>
|
15 |
* Completely rewritten to use libusb instead of usbfs ioctls.
|
16 |
*
|
17 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
18 |
* of this software and associated documentation files (the "Software"), to deal
|
19 |
* in the Software without restriction, including without limitation the rights
|
20 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
21 |
* copies of the Software, and to permit persons to whom the Software is
|
22 |
* furnished to do so, subject to the following conditions:
|
23 |
*
|
24 |
* The above copyright notice and this permission notice shall be included in
|
25 |
* all copies or substantial portions of the Software.
|
26 |
*
|
27 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
28 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
29 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
30 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
31 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
32 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
33 |
* THE SOFTWARE.
|
34 |
*/
|
35 |
|
36 |
#include <poll.h> |
37 |
#include <libusb.h> |
38 |
|
39 |
#include "qemu-common.h" |
40 |
#include "monitor/monitor.h" |
41 |
#include "sysemu/sysemu.h" |
42 |
#include "trace.h" |
43 |
|
44 |
#include "hw/usb.h" |
45 |
|
46 |
/* ------------------------------------------------------------------------ */
|
47 |
|
48 |
#define TYPE_USB_HOST_DEVICE "usb-host" |
49 |
#define USB_HOST_DEVICE(obj) \
|
50 |
OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE) |
51 |
|
52 |
typedef struct USBHostDevice USBHostDevice; |
53 |
typedef struct USBHostRequest USBHostRequest; |
54 |
typedef struct USBHostIsoXfer USBHostIsoXfer; |
55 |
typedef struct USBHostIsoRing USBHostIsoRing; |
56 |
|
57 |
struct USBAutoFilter {
|
58 |
uint32_t bus_num; |
59 |
uint32_t addr; |
60 |
char *port;
|
61 |
uint32_t vendor_id; |
62 |
uint32_t product_id; |
63 |
}; |
64 |
|
65 |
enum USBHostDeviceOptions {
|
66 |
USB_HOST_OPT_PIPELINE, |
67 |
}; |
68 |
|
69 |
struct USBHostDevice {
|
70 |
USBDevice parent_obj; |
71 |
|
72 |
/* properties */
|
73 |
struct USBAutoFilter match;
|
74 |
int32_t bootindex; |
75 |
uint32_t iso_urb_count; |
76 |
uint32_t iso_urb_frames; |
77 |
uint32_t options; |
78 |
uint32_t loglevel; |
79 |
|
80 |
/* state */
|
81 |
QTAILQ_ENTRY(USBHostDevice) next; |
82 |
int seen, errcount;
|
83 |
int bus_num;
|
84 |
int addr;
|
85 |
char port[16]; |
86 |
|
87 |
libusb_device *dev; |
88 |
libusb_device_handle *dh; |
89 |
struct libusb_device_descriptor ddesc;
|
90 |
|
91 |
struct {
|
92 |
bool detached;
|
93 |
bool claimed;
|
94 |
} ifs[USB_MAX_INTERFACES]; |
95 |
|
96 |
/* callbacks & friends */
|
97 |
QEMUBH *bh_nodev; |
98 |
QEMUBH *bh_postld; |
99 |
Notifier exit; |
100 |
|
101 |
/* request queues */
|
102 |
QTAILQ_HEAD(, USBHostRequest) requests; |
103 |
QTAILQ_HEAD(, USBHostIsoRing) isorings; |
104 |
}; |
105 |
|
106 |
struct USBHostRequest {
|
107 |
USBHostDevice *host; |
108 |
USBPacket *p; |
109 |
bool in;
|
110 |
struct libusb_transfer *xfer;
|
111 |
unsigned char *buffer; |
112 |
unsigned char *cbuf; |
113 |
unsigned int clen; |
114 |
QTAILQ_ENTRY(USBHostRequest) next; |
115 |
}; |
116 |
|
117 |
struct USBHostIsoXfer {
|
118 |
USBHostIsoRing *ring; |
119 |
struct libusb_transfer *xfer;
|
120 |
bool copy_complete;
|
121 |
unsigned int packet; |
122 |
QTAILQ_ENTRY(USBHostIsoXfer) next; |
123 |
}; |
124 |
|
125 |
struct USBHostIsoRing {
|
126 |
USBHostDevice *host; |
127 |
USBEndpoint *ep; |
128 |
QTAILQ_HEAD(, USBHostIsoXfer) unused; |
129 |
QTAILQ_HEAD(, USBHostIsoXfer) inflight; |
130 |
QTAILQ_HEAD(, USBHostIsoXfer) copy; |
131 |
QTAILQ_ENTRY(USBHostIsoRing) next; |
132 |
}; |
133 |
|
134 |
static QTAILQ_HEAD(, USBHostDevice) hostdevs =
|
135 |
QTAILQ_HEAD_INITIALIZER(hostdevs); |
136 |
|
137 |
static void usb_host_auto_check(void *unused); |
138 |
static void usb_host_release_interfaces(USBHostDevice *s); |
139 |
static void usb_host_nodev(USBHostDevice *s); |
140 |
static void usb_host_attach_kernel(USBHostDevice *s); |
141 |
|
142 |
/* ------------------------------------------------------------------------ */
|
143 |
|
144 |
#define CONTROL_TIMEOUT 10000 /* 10 sec */ |
145 |
#define BULK_TIMEOUT 0 /* unlimited */ |
146 |
#define INTR_TIMEOUT 0 /* unlimited */ |
147 |
|
148 |
static const char *speed_name[] = { |
149 |
[LIBUSB_SPEED_UNKNOWN] = "?",
|
150 |
[LIBUSB_SPEED_LOW] = "1.5",
|
151 |
[LIBUSB_SPEED_FULL] = "12",
|
152 |
[LIBUSB_SPEED_HIGH] = "480",
|
153 |
[LIBUSB_SPEED_SUPER] = "5000",
|
154 |
}; |
155 |
|
156 |
static const unsigned int speed_map[] = { |
157 |
[LIBUSB_SPEED_LOW] = USB_SPEED_LOW, |
158 |
[LIBUSB_SPEED_FULL] = USB_SPEED_FULL, |
159 |
[LIBUSB_SPEED_HIGH] = USB_SPEED_HIGH, |
160 |
[LIBUSB_SPEED_SUPER] = USB_SPEED_SUPER, |
161 |
}; |
162 |
|
163 |
static const unsigned int status_map[] = { |
164 |
[LIBUSB_TRANSFER_COMPLETED] = USB_RET_SUCCESS, |
165 |
[LIBUSB_TRANSFER_ERROR] = USB_RET_IOERROR, |
166 |
[LIBUSB_TRANSFER_TIMED_OUT] = USB_RET_IOERROR, |
167 |
[LIBUSB_TRANSFER_CANCELLED] = USB_RET_IOERROR, |
168 |
[LIBUSB_TRANSFER_STALL] = USB_RET_STALL, |
169 |
[LIBUSB_TRANSFER_NO_DEVICE] = USB_RET_NODEV, |
170 |
[LIBUSB_TRANSFER_OVERFLOW] = USB_RET_BABBLE, |
171 |
}; |
172 |
|
173 |
static const char *err_names[] = { |
174 |
[-LIBUSB_ERROR_IO] = "IO",
|
175 |
[-LIBUSB_ERROR_INVALID_PARAM] = "INVALID_PARAM",
|
176 |
[-LIBUSB_ERROR_ACCESS] = "ACCESS",
|
177 |
[-LIBUSB_ERROR_NO_DEVICE] = "NO_DEVICE",
|
178 |
[-LIBUSB_ERROR_NOT_FOUND] = "NOT_FOUND",
|
179 |
[-LIBUSB_ERROR_BUSY] = "BUSY",
|
180 |
[-LIBUSB_ERROR_TIMEOUT] = "TIMEOUT",
|
181 |
[-LIBUSB_ERROR_OVERFLOW] = "OVERFLOW",
|
182 |
[-LIBUSB_ERROR_PIPE] = "PIPE",
|
183 |
[-LIBUSB_ERROR_INTERRUPTED] = "INTERRUPTED",
|
184 |
[-LIBUSB_ERROR_NO_MEM] = "NO_MEM",
|
185 |
[-LIBUSB_ERROR_NOT_SUPPORTED] = "NOT_SUPPORTED",
|
186 |
[-LIBUSB_ERROR_OTHER] = "OTHER",
|
187 |
}; |
188 |
|
189 |
static libusb_context *ctx;
|
190 |
static uint32_t loglevel;
|
191 |
|
192 |
static void usb_host_handle_fd(void *opaque) |
193 |
{ |
194 |
struct timeval tv = { 0, 0 }; |
195 |
libusb_handle_events_timeout(ctx, &tv); |
196 |
} |
197 |
|
198 |
static void usb_host_add_fd(int fd, short events, void *user_data) |
199 |
{ |
200 |
qemu_set_fd_handler(fd, |
201 |
(events & POLLIN) ? usb_host_handle_fd : NULL,
|
202 |
(events & POLLOUT) ? usb_host_handle_fd : NULL,
|
203 |
ctx); |
204 |
} |
205 |
|
206 |
static void usb_host_del_fd(int fd, void *user_data) |
207 |
{ |
208 |
qemu_set_fd_handler(fd, NULL, NULL, NULL); |
209 |
} |
210 |
|
211 |
static int usb_host_init(void) |
212 |
{ |
213 |
const struct libusb_pollfd **poll; |
214 |
int i, rc;
|
215 |
|
216 |
if (ctx) {
|
217 |
return 0; |
218 |
} |
219 |
rc = libusb_init(&ctx); |
220 |
if (rc != 0) { |
221 |
return -1; |
222 |
} |
223 |
libusb_set_debug(ctx, loglevel); |
224 |
|
225 |
libusb_set_pollfd_notifiers(ctx, usb_host_add_fd, |
226 |
usb_host_del_fd, |
227 |
ctx); |
228 |
poll = libusb_get_pollfds(ctx); |
229 |
if (poll) {
|
230 |
for (i = 0; poll[i] != NULL; i++) { |
231 |
usb_host_add_fd(poll[i]->fd, poll[i]->events, ctx); |
232 |
} |
233 |
} |
234 |
free(poll); |
235 |
return 0; |
236 |
} |
237 |
|
238 |
static int usb_host_get_port(libusb_device *dev, char *port, size_t len) |
239 |
{ |
240 |
uint8_t path[7];
|
241 |
size_t off; |
242 |
int rc, i;
|
243 |
|
244 |
rc = libusb_get_port_path(ctx, dev, path, 7);
|
245 |
if (rc < 0) { |
246 |
return 0; |
247 |
} |
248 |
off = snprintf(port, len, "%d", path[0]); |
249 |
for (i = 1; i < rc; i++) { |
250 |
off += snprintf(port+off, len-off, ".%d", path[i]);
|
251 |
} |
252 |
return off;
|
253 |
} |
254 |
|
255 |
static void usb_host_libusb_error(const char *func, int rc) |
256 |
{ |
257 |
const char *errname; |
258 |
|
259 |
if (rc >= 0) { |
260 |
return;
|
261 |
} |
262 |
|
263 |
if (-rc < ARRAY_SIZE(err_names) && err_names[-rc]) {
|
264 |
errname = err_names[-rc]; |
265 |
} else {
|
266 |
errname = "?";
|
267 |
} |
268 |
fprintf(stderr, "%s: %d [%s]\n", func, rc, errname);
|
269 |
} |
270 |
|
271 |
/* ------------------------------------------------------------------------ */
|
272 |
|
273 |
static bool usb_host_use_combining(USBEndpoint *ep) |
274 |
{ |
275 |
int type;
|
276 |
|
277 |
if (!ep->pipeline) {
|
278 |
return false; |
279 |
} |
280 |
if (ep->pid != USB_TOKEN_IN) {
|
281 |
return false; |
282 |
} |
283 |
type = usb_ep_get_type(ep->dev, ep->pid, ep->nr); |
284 |
if (type != USB_ENDPOINT_XFER_BULK) {
|
285 |
return false; |
286 |
} |
287 |
return true; |
288 |
} |
289 |
|
290 |
/* ------------------------------------------------------------------------ */
|
291 |
|
292 |
static USBHostRequest *usb_host_req_alloc(USBHostDevice *s, USBPacket *p,
|
293 |
bool in, size_t bufsize)
|
294 |
{ |
295 |
USBHostRequest *r = g_new0(USBHostRequest, 1);
|
296 |
|
297 |
r->host = s; |
298 |
r->p = p; |
299 |
r->in = in; |
300 |
r->xfer = libusb_alloc_transfer(0);
|
301 |
if (bufsize) {
|
302 |
r->buffer = g_malloc(bufsize); |
303 |
} |
304 |
QTAILQ_INSERT_TAIL(&s->requests, r, next); |
305 |
return r;
|
306 |
} |
307 |
|
308 |
static void usb_host_req_free(USBHostRequest *r) |
309 |
{ |
310 |
if (r->host) {
|
311 |
QTAILQ_REMOVE(&r->host->requests, r, next); |
312 |
} |
313 |
libusb_free_transfer(r->xfer); |
314 |
g_free(r->buffer); |
315 |
g_free(r); |
316 |
} |
317 |
|
318 |
static USBHostRequest *usb_host_req_find(USBHostDevice *s, USBPacket *p)
|
319 |
{ |
320 |
USBHostRequest *r; |
321 |
|
322 |
QTAILQ_FOREACH(r, &s->requests, next) { |
323 |
if (r->p == p) {
|
324 |
return r;
|
325 |
} |
326 |
} |
327 |
return NULL; |
328 |
} |
329 |
|
330 |
static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer) |
331 |
{ |
332 |
USBHostRequest *r = xfer->user_data; |
333 |
USBHostDevice *s = r->host; |
334 |
bool disconnect = (xfer->status == LIBUSB_TRANSFER_NO_DEVICE);
|
335 |
|
336 |
if (r->p == NULL) { |
337 |
goto out; /* request was canceled */ |
338 |
} |
339 |
|
340 |
r->p->status = status_map[xfer->status]; |
341 |
r->p->actual_length = xfer->actual_length; |
342 |
if (r->in && xfer->actual_length) {
|
343 |
memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
|
344 |
} |
345 |
trace_usb_host_req_complete(s->bus_num, s->addr, r->p, |
346 |
r->p->status, r->p->actual_length); |
347 |
usb_generic_async_ctrl_complete(USB_DEVICE(s), r->p); |
348 |
|
349 |
out:
|
350 |
usb_host_req_free(r); |
351 |
if (disconnect) {
|
352 |
usb_host_nodev(s); |
353 |
} |
354 |
} |
355 |
|
356 |
static void usb_host_req_complete_data(struct libusb_transfer *xfer) |
357 |
{ |
358 |
USBHostRequest *r = xfer->user_data; |
359 |
USBHostDevice *s = r->host; |
360 |
bool disconnect = (xfer->status == LIBUSB_TRANSFER_NO_DEVICE);
|
361 |
|
362 |
if (r->p == NULL) { |
363 |
goto out; /* request was canceled */ |
364 |
} |
365 |
|
366 |
r->p->status = status_map[xfer->status]; |
367 |
if (r->in && xfer->actual_length) {
|
368 |
usb_packet_copy(r->p, r->buffer, xfer->actual_length); |
369 |
} |
370 |
trace_usb_host_req_complete(s->bus_num, s->addr, r->p, |
371 |
r->p->status, r->p->actual_length); |
372 |
if (usb_host_use_combining(r->p->ep)) {
|
373 |
usb_combined_input_packet_complete(USB_DEVICE(s), r->p); |
374 |
} else {
|
375 |
usb_packet_complete(USB_DEVICE(s), r->p); |
376 |
} |
377 |
|
378 |
out:
|
379 |
usb_host_req_free(r); |
380 |
if (disconnect) {
|
381 |
usb_host_nodev(s); |
382 |
} |
383 |
} |
384 |
|
385 |
static void usb_host_req_abort(USBHostRequest *r) |
386 |
{ |
387 |
USBHostDevice *s = r->host; |
388 |
bool inflight = (r->p && r->p->state == USB_RET_ASYNC);
|
389 |
|
390 |
if (inflight) {
|
391 |
r->p->status = USB_RET_NODEV; |
392 |
trace_usb_host_req_complete(s->bus_num, s->addr, r->p, |
393 |
r->p->status, r->p->actual_length); |
394 |
if (r->p->ep->nr == 0) { |
395 |
usb_generic_async_ctrl_complete(USB_DEVICE(s), r->p); |
396 |
} else {
|
397 |
usb_packet_complete(USB_DEVICE(s), r->p); |
398 |
} |
399 |
r->p = NULL;
|
400 |
} |
401 |
|
402 |
QTAILQ_REMOVE(&r->host->requests, r, next); |
403 |
r->host = NULL;
|
404 |
|
405 |
if (inflight) {
|
406 |
libusb_cancel_transfer(r->xfer); |
407 |
} |
408 |
} |
409 |
|
410 |
/* ------------------------------------------------------------------------ */
|
411 |
|
412 |
static void usb_host_req_complete_iso(struct libusb_transfer *transfer) |
413 |
{ |
414 |
USBHostIsoXfer *xfer = transfer->user_data; |
415 |
|
416 |
if (!xfer) {
|
417 |
/* USBHostIsoXfer released while inflight */
|
418 |
g_free(transfer->buffer); |
419 |
libusb_free_transfer(transfer); |
420 |
return;
|
421 |
} |
422 |
|
423 |
QTAILQ_REMOVE(&xfer->ring->inflight, xfer, next); |
424 |
if (QTAILQ_EMPTY(&xfer->ring->inflight)) {
|
425 |
USBHostDevice *s = xfer->ring->host; |
426 |
trace_usb_host_iso_stop(s->bus_num, s->addr, xfer->ring->ep->nr); |
427 |
} |
428 |
if (xfer->ring->ep->pid == USB_TOKEN_IN) {
|
429 |
QTAILQ_INSERT_TAIL(&xfer->ring->copy, xfer, next); |
430 |
} else {
|
431 |
QTAILQ_INSERT_TAIL(&xfer->ring->unused, xfer, next); |
432 |
} |
433 |
} |
434 |
|
435 |
static USBHostIsoRing *usb_host_iso_alloc(USBHostDevice *s, USBEndpoint *ep)
|
436 |
{ |
437 |
USBHostIsoRing *ring = g_new0(USBHostIsoRing, 1);
|
438 |
USBHostIsoXfer *xfer; |
439 |
/* FIXME: check interval (for now assume one xfer per frame) */
|
440 |
int packets = s->iso_urb_frames;
|
441 |
int i;
|
442 |
|
443 |
ring->host = s; |
444 |
ring->ep = ep; |
445 |
QTAILQ_INIT(&ring->unused); |
446 |
QTAILQ_INIT(&ring->inflight); |
447 |
QTAILQ_INIT(&ring->copy); |
448 |
QTAILQ_INSERT_TAIL(&s->isorings, ring, next); |
449 |
|
450 |
for (i = 0; i < s->iso_urb_count; i++) { |
451 |
xfer = g_new0(USBHostIsoXfer, 1);
|
452 |
xfer->ring = ring; |
453 |
xfer->xfer = libusb_alloc_transfer(packets); |
454 |
xfer->xfer->dev_handle = s->dh; |
455 |
xfer->xfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; |
456 |
|
457 |
xfer->xfer->endpoint = ring->ep->nr; |
458 |
if (ring->ep->pid == USB_TOKEN_IN) {
|
459 |
xfer->xfer->endpoint |= USB_DIR_IN; |
460 |
} |
461 |
xfer->xfer->callback = usb_host_req_complete_iso; |
462 |
xfer->xfer->user_data = xfer; |
463 |
|
464 |
xfer->xfer->num_iso_packets = packets; |
465 |
xfer->xfer->length = ring->ep->max_packet_size * packets; |
466 |
xfer->xfer->buffer = g_malloc0(xfer->xfer->length); |
467 |
|
468 |
QTAILQ_INSERT_TAIL(&ring->unused, xfer, next); |
469 |
} |
470 |
|
471 |
return ring;
|
472 |
} |
473 |
|
474 |
static USBHostIsoRing *usb_host_iso_find(USBHostDevice *s, USBEndpoint *ep)
|
475 |
{ |
476 |
USBHostIsoRing *ring; |
477 |
|
478 |
QTAILQ_FOREACH(ring, &s->isorings, next) { |
479 |
if (ring->ep == ep) {
|
480 |
return ring;
|
481 |
} |
482 |
} |
483 |
return NULL; |
484 |
} |
485 |
|
486 |
static void usb_host_iso_reset_xfer(USBHostIsoXfer *xfer) |
487 |
{ |
488 |
libusb_set_iso_packet_lengths(xfer->xfer, |
489 |
xfer->ring->ep->max_packet_size); |
490 |
xfer->packet = 0;
|
491 |
xfer->copy_complete = false;
|
492 |
} |
493 |
|
494 |
static void usb_host_iso_free_xfer(USBHostIsoXfer *xfer, bool inflight) |
495 |
{ |
496 |
if (inflight) {
|
497 |
xfer->xfer->user_data = NULL;
|
498 |
} else {
|
499 |
g_free(xfer->xfer->buffer); |
500 |
libusb_free_transfer(xfer->xfer); |
501 |
} |
502 |
g_free(xfer); |
503 |
} |
504 |
|
505 |
static void usb_host_iso_free(USBHostIsoRing *ring) |
506 |
{ |
507 |
USBHostIsoXfer *xfer; |
508 |
|
509 |
while ((xfer = QTAILQ_FIRST(&ring->inflight)) != NULL) { |
510 |
QTAILQ_REMOVE(&ring->inflight, xfer, next); |
511 |
usb_host_iso_free_xfer(xfer, true);
|
512 |
} |
513 |
while ((xfer = QTAILQ_FIRST(&ring->unused)) != NULL) { |
514 |
QTAILQ_REMOVE(&ring->unused, xfer, next); |
515 |
usb_host_iso_free_xfer(xfer, false);
|
516 |
} |
517 |
while ((xfer = QTAILQ_FIRST(&ring->copy)) != NULL) { |
518 |
QTAILQ_REMOVE(&ring->copy, xfer, next); |
519 |
usb_host_iso_free_xfer(xfer, false);
|
520 |
} |
521 |
|
522 |
QTAILQ_REMOVE(&ring->host->isorings, ring, next); |
523 |
g_free(ring); |
524 |
} |
525 |
|
526 |
static void usb_host_iso_free_all(USBHostDevice *s) |
527 |
{ |
528 |
USBHostIsoRing *ring; |
529 |
|
530 |
while ((ring = QTAILQ_FIRST(&s->isorings)) != NULL) { |
531 |
usb_host_iso_free(ring); |
532 |
} |
533 |
} |
534 |
|
535 |
static bool usb_host_iso_data_copy(USBHostIsoXfer *xfer, USBPacket *p) |
536 |
{ |
537 |
unsigned int psize; |
538 |
unsigned char *buf; |
539 |
|
540 |
buf = libusb_get_iso_packet_buffer_simple(xfer->xfer, xfer->packet); |
541 |
if (p->pid == USB_TOKEN_OUT) {
|
542 |
psize = p->iov.size; |
543 |
if (psize > xfer->ring->ep->max_packet_size) {
|
544 |
/* should not happen (guest bug) */
|
545 |
psize = xfer->ring->ep->max_packet_size; |
546 |
} |
547 |
xfer->xfer->iso_packet_desc[xfer->packet].length = psize; |
548 |
} else {
|
549 |
psize = xfer->xfer->iso_packet_desc[xfer->packet].actual_length; |
550 |
if (psize > p->iov.size) {
|
551 |
/* should not happen (guest bug) */
|
552 |
psize = p->iov.size; |
553 |
} |
554 |
} |
555 |
usb_packet_copy(p, buf, psize); |
556 |
xfer->packet++; |
557 |
xfer->copy_complete = (xfer->packet == xfer->xfer->num_iso_packets); |
558 |
return xfer->copy_complete;
|
559 |
} |
560 |
|
561 |
static void usb_host_iso_data_in(USBHostDevice *s, USBPacket *p) |
562 |
{ |
563 |
USBHostIsoRing *ring; |
564 |
USBHostIsoXfer *xfer; |
565 |
bool disconnect = false; |
566 |
int rc;
|
567 |
|
568 |
ring = usb_host_iso_find(s, p->ep); |
569 |
if (ring == NULL) { |
570 |
ring = usb_host_iso_alloc(s, p->ep); |
571 |
} |
572 |
|
573 |
/* copy data to guest */
|
574 |
xfer = QTAILQ_FIRST(&ring->copy); |
575 |
if (xfer != NULL) { |
576 |
if (usb_host_iso_data_copy(xfer, p)) {
|
577 |
QTAILQ_REMOVE(&ring->copy, xfer, next); |
578 |
QTAILQ_INSERT_TAIL(&ring->unused, xfer, next); |
579 |
} |
580 |
} |
581 |
|
582 |
/* submit empty bufs to host */
|
583 |
while ((xfer = QTAILQ_FIRST(&ring->unused)) != NULL) { |
584 |
QTAILQ_REMOVE(&ring->unused, xfer, next); |
585 |
usb_host_iso_reset_xfer(xfer); |
586 |
rc = libusb_submit_transfer(xfer->xfer); |
587 |
if (rc != 0) { |
588 |
usb_host_libusb_error("libusb_submit_transfer [iso]", rc);
|
589 |
QTAILQ_INSERT_TAIL(&ring->unused, xfer, next); |
590 |
if (rc == LIBUSB_ERROR_NO_DEVICE) {
|
591 |
disconnect = true;
|
592 |
} |
593 |
break;
|
594 |
} |
595 |
if (QTAILQ_EMPTY(&ring->inflight)) {
|
596 |
trace_usb_host_iso_start(s->bus_num, s->addr, p->ep->nr); |
597 |
} |
598 |
QTAILQ_INSERT_TAIL(&ring->inflight, xfer, next); |
599 |
} |
600 |
|
601 |
if (disconnect) {
|
602 |
usb_host_nodev(s); |
603 |
} |
604 |
} |
605 |
|
606 |
static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p) |
607 |
{ |
608 |
USBHostIsoRing *ring; |
609 |
USBHostIsoXfer *xfer; |
610 |
bool disconnect = false; |
611 |
int rc, filled = 0; |
612 |
|
613 |
ring = usb_host_iso_find(s, p->ep); |
614 |
if (ring == NULL) { |
615 |
ring = usb_host_iso_alloc(s, p->ep); |
616 |
} |
617 |
|
618 |
/* copy data from guest */
|
619 |
xfer = QTAILQ_FIRST(&ring->copy); |
620 |
while (xfer != NULL && xfer->copy_complete) { |
621 |
filled++; |
622 |
xfer = QTAILQ_NEXT(xfer, next); |
623 |
} |
624 |
if (xfer == NULL) { |
625 |
xfer = QTAILQ_FIRST(&ring->unused); |
626 |
if (xfer == NULL) { |
627 |
trace_usb_host_iso_out_of_bufs(s->bus_num, s->addr, p->ep->nr); |
628 |
return;
|
629 |
} |
630 |
QTAILQ_REMOVE(&ring->unused, xfer, next); |
631 |
usb_host_iso_reset_xfer(xfer); |
632 |
QTAILQ_INSERT_TAIL(&ring->copy, xfer, next); |
633 |
} |
634 |
usb_host_iso_data_copy(xfer, p); |
635 |
|
636 |
if (QTAILQ_EMPTY(&ring->inflight)) {
|
637 |
/* wait until half of our buffers are filled
|
638 |
before kicking the iso out stream */
|
639 |
if (filled*2 < s->iso_urb_count) { |
640 |
return;
|
641 |
} |
642 |
} |
643 |
|
644 |
/* submit filled bufs to host */
|
645 |
while ((xfer = QTAILQ_FIRST(&ring->copy)) != NULL && |
646 |
xfer->copy_complete) { |
647 |
QTAILQ_REMOVE(&ring->copy, xfer, next); |
648 |
rc = libusb_submit_transfer(xfer->xfer); |
649 |
if (rc != 0) { |
650 |
usb_host_libusb_error("libusb_submit_transfer [iso]", rc);
|
651 |
QTAILQ_INSERT_TAIL(&ring->unused, xfer, next); |
652 |
if (rc == LIBUSB_ERROR_NO_DEVICE) {
|
653 |
disconnect = true;
|
654 |
} |
655 |
break;
|
656 |
} |
657 |
if (QTAILQ_EMPTY(&ring->inflight)) {
|
658 |
trace_usb_host_iso_start(s->bus_num, s->addr, p->ep->nr); |
659 |
} |
660 |
QTAILQ_INSERT_TAIL(&ring->inflight, xfer, next); |
661 |
} |
662 |
|
663 |
if (disconnect) {
|
664 |
usb_host_nodev(s); |
665 |
} |
666 |
} |
667 |
|
668 |
/* ------------------------------------------------------------------------ */
|
669 |
|
670 |
static bool usb_host_full_speed_compat(USBHostDevice *s) |
671 |
{ |
672 |
struct libusb_config_descriptor *conf;
|
673 |
const struct libusb_interface_descriptor *intf; |
674 |
const struct libusb_endpoint_descriptor *endp; |
675 |
uint8_t type; |
676 |
int rc, c, i, a, e;
|
677 |
|
678 |
for (c = 0;; c++) { |
679 |
rc = libusb_get_config_descriptor(s->dev, c, &conf); |
680 |
if (rc != 0) { |
681 |
break;
|
682 |
} |
683 |
for (i = 0; i < conf->bNumInterfaces; i++) { |
684 |
for (a = 0; a < conf->interface[i].num_altsetting; a++) { |
685 |
intf = &conf->interface[i].altsetting[a]; |
686 |
for (e = 0; e < intf->bNumEndpoints; e++) { |
687 |
endp = &intf->endpoint[e]; |
688 |
type = endp->bmAttributes & 0x3;
|
689 |
switch (type) {
|
690 |
case 0x01: /* ISO */ |
691 |
return false; |
692 |
case 0x03: /* INTERRUPT */ |
693 |
if (endp->wMaxPacketSize > 64) { |
694 |
return false; |
695 |
} |
696 |
break;
|
697 |
} |
698 |
} |
699 |
} |
700 |
} |
701 |
libusb_free_config_descriptor(conf); |
702 |
} |
703 |
return true; |
704 |
} |
705 |
|
706 |
static void usb_host_ep_update(USBHostDevice *s) |
707 |
{ |
708 |
static const char *tname[] = { |
709 |
[USB_ENDPOINT_XFER_CONTROL] = "control",
|
710 |
[USB_ENDPOINT_XFER_ISOC] = "isoc",
|
711 |
[USB_ENDPOINT_XFER_BULK] = "bulk",
|
712 |
[USB_ENDPOINT_XFER_INT] = "int",
|
713 |
}; |
714 |
USBDevice *udev = USB_DEVICE(s); |
715 |
struct libusb_config_descriptor *conf;
|
716 |
const struct libusb_interface_descriptor *intf; |
717 |
const struct libusb_endpoint_descriptor *endp; |
718 |
uint8_t devep, type; |
719 |
int pid, ep;
|
720 |
int rc, i, e;
|
721 |
|
722 |
usb_ep_reset(udev); |
723 |
rc = libusb_get_active_config_descriptor(s->dev, &conf); |
724 |
if (rc != 0) { |
725 |
return;
|
726 |
} |
727 |
trace_usb_host_parse_config(s->bus_num, s->addr, |
728 |
conf->bConfigurationValue, true);
|
729 |
|
730 |
for (i = 0; i < conf->bNumInterfaces; i++) { |
731 |
assert(udev->altsetting[i] < conf->interface[i].num_altsetting); |
732 |
intf = &conf->interface[i].altsetting[udev->altsetting[i]]; |
733 |
trace_usb_host_parse_interface(s->bus_num, s->addr, |
734 |
intf->bInterfaceNumber, |
735 |
intf->bAlternateSetting, true);
|
736 |
for (e = 0; e < intf->bNumEndpoints; e++) { |
737 |
endp = &intf->endpoint[e]; |
738 |
|
739 |
devep = endp->bEndpointAddress; |
740 |
pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; |
741 |
ep = devep & 0xf;
|
742 |
type = endp->bmAttributes & 0x3;
|
743 |
|
744 |
if (ep == 0) { |
745 |
trace_usb_host_parse_error(s->bus_num, s->addr, |
746 |
"invalid endpoint address");
|
747 |
return;
|
748 |
} |
749 |
if (usb_ep_get_type(udev, pid, ep) != USB_ENDPOINT_XFER_INVALID) {
|
750 |
trace_usb_host_parse_error(s->bus_num, s->addr, |
751 |
"duplicate endpoint address");
|
752 |
return;
|
753 |
} |
754 |
|
755 |
trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep, |
756 |
(devep & USB_DIR_IN) ? "in" : "out", |
757 |
tname[type], true);
|
758 |
usb_ep_set_max_packet_size(udev, pid, ep, |
759 |
endp->wMaxPacketSize); |
760 |
usb_ep_set_type(udev, pid, ep, type); |
761 |
usb_ep_set_ifnum(udev, pid, ep, i); |
762 |
usb_ep_set_halted(udev, pid, ep, 0);
|
763 |
} |
764 |
} |
765 |
|
766 |
libusb_free_config_descriptor(conf); |
767 |
} |
768 |
|
769 |
static int usb_host_open(USBHostDevice *s, libusb_device *dev) |
770 |
{ |
771 |
USBDevice *udev = USB_DEVICE(s); |
772 |
int bus_num = libusb_get_bus_number(dev);
|
773 |
int addr = libusb_get_device_address(dev);
|
774 |
int rc;
|
775 |
|
776 |
trace_usb_host_open_started(bus_num, addr); |
777 |
|
778 |
if (s->dh != NULL) { |
779 |
goto fail;
|
780 |
} |
781 |
rc = libusb_open(dev, &s->dh); |
782 |
if (rc != 0) { |
783 |
goto fail;
|
784 |
} |
785 |
|
786 |
libusb_get_device_descriptor(dev, &s->ddesc); |
787 |
s->dev = dev; |
788 |
s->bus_num = bus_num; |
789 |
s->addr = addr; |
790 |
usb_host_get_port(s->dev, s->port, sizeof(s->port));
|
791 |
|
792 |
usb_ep_init(udev); |
793 |
usb_host_ep_update(s); |
794 |
|
795 |
udev->speed = speed_map[libusb_get_device_speed(dev)]; |
796 |
udev->speedmask = (1 << udev->speed);
|
797 |
if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) {
|
798 |
udev->speedmask |= USB_SPEED_MASK_FULL; |
799 |
} |
800 |
|
801 |
if (s->ddesc.iProduct) {
|
802 |
libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct, |
803 |
(unsigned char *)udev->product_desc, |
804 |
sizeof(udev->product_desc));
|
805 |
} else {
|
806 |
snprintf(udev->product_desc, sizeof(udev->product_desc),
|
807 |
"host:%d.%d", bus_num, addr);
|
808 |
} |
809 |
|
810 |
rc = usb_device_attach(udev); |
811 |
if (rc) {
|
812 |
goto fail;
|
813 |
} |
814 |
|
815 |
trace_usb_host_open_success(bus_num, addr); |
816 |
return 0; |
817 |
|
818 |
fail:
|
819 |
trace_usb_host_open_failure(bus_num, addr); |
820 |
if (s->dh != NULL) { |
821 |
libusb_close(s->dh); |
822 |
s->dh = NULL;
|
823 |
s->dev = NULL;
|
824 |
} |
825 |
return -1; |
826 |
} |
827 |
|
828 |
static void usb_host_abort_xfers(USBHostDevice *s) |
829 |
{ |
830 |
USBHostRequest *r, *rtmp; |
831 |
|
832 |
QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) { |
833 |
usb_host_req_abort(r); |
834 |
} |
835 |
} |
836 |
|
837 |
static int usb_host_close(USBHostDevice *s) |
838 |
{ |
839 |
USBDevice *udev = USB_DEVICE(s); |
840 |
|
841 |
if (s->dh == NULL) { |
842 |
return -1; |
843 |
} |
844 |
|
845 |
trace_usb_host_close(s->bus_num, s->addr); |
846 |
|
847 |
usb_host_abort_xfers(s); |
848 |
usb_host_iso_free_all(s); |
849 |
|
850 |
if (udev->attached) {
|
851 |
usb_device_detach(udev); |
852 |
} |
853 |
|
854 |
usb_host_release_interfaces(s); |
855 |
libusb_reset_device(s->dh); |
856 |
usb_host_attach_kernel(s); |
857 |
libusb_close(s->dh); |
858 |
s->dh = NULL;
|
859 |
s->dev = NULL;
|
860 |
|
861 |
usb_host_auto_check(NULL);
|
862 |
return 0; |
863 |
} |
864 |
|
865 |
static void usb_host_nodev_bh(void *opaque) |
866 |
{ |
867 |
USBHostDevice *s = opaque; |
868 |
usb_host_close(s); |
869 |
} |
870 |
|
871 |
static void usb_host_nodev(USBHostDevice *s) |
872 |
{ |
873 |
if (!s->bh_nodev) {
|
874 |
s->bh_nodev = qemu_bh_new(usb_host_nodev_bh, s); |
875 |
} |
876 |
qemu_bh_schedule(s->bh_nodev); |
877 |
} |
878 |
|
879 |
static void usb_host_exit_notifier(struct Notifier *n, void *data) |
880 |
{ |
881 |
USBHostDevice *s = container_of(n, USBHostDevice, exit); |
882 |
|
883 |
if (s->dh) {
|
884 |
usb_host_release_interfaces(s); |
885 |
usb_host_attach_kernel(s); |
886 |
} |
887 |
} |
888 |
|
889 |
static int usb_host_initfn(USBDevice *udev) |
890 |
{ |
891 |
USBHostDevice *s = USB_HOST_DEVICE(udev); |
892 |
|
893 |
loglevel = s->loglevel; |
894 |
udev->auto_attach = 0;
|
895 |
QTAILQ_INIT(&s->requests); |
896 |
QTAILQ_INIT(&s->isorings); |
897 |
|
898 |
s->exit.notify = usb_host_exit_notifier; |
899 |
qemu_add_exit_notifier(&s->exit); |
900 |
|
901 |
QTAILQ_INSERT_TAIL(&hostdevs, s, next); |
902 |
add_boot_device_path(s->bootindex, &udev->qdev, NULL);
|
903 |
usb_host_auto_check(NULL);
|
904 |
return 0; |
905 |
} |
906 |
|
907 |
static void usb_host_handle_destroy(USBDevice *udev) |
908 |
{ |
909 |
USBHostDevice *s = USB_HOST_DEVICE(udev); |
910 |
|
911 |
qemu_remove_exit_notifier(&s->exit); |
912 |
QTAILQ_REMOVE(&hostdevs, s, next); |
913 |
usb_host_close(s); |
914 |
} |
915 |
|
916 |
static void usb_host_cancel_packet(USBDevice *udev, USBPacket *p) |
917 |
{ |
918 |
USBHostDevice *s = USB_HOST_DEVICE(udev); |
919 |
USBHostRequest *r; |
920 |
|
921 |
if (p->combined) {
|
922 |
usb_combined_packet_cancel(udev, p); |
923 |
return;
|
924 |
} |
925 |
|
926 |
trace_usb_host_req_canceled(s->bus_num, s->addr, p); |
927 |
|
928 |
r = usb_host_req_find(s, p); |
929 |
if (r && r->p) {
|
930 |
r->p = NULL; /* mark as dead */ |
931 |
libusb_cancel_transfer(r->xfer); |
932 |
} |
933 |
} |
934 |
|
935 |
static void usb_host_detach_kernel(USBHostDevice *s) |
936 |
{ |
937 |
struct libusb_config_descriptor *conf;
|
938 |
int rc, i;
|
939 |
|
940 |
rc = libusb_get_active_config_descriptor(s->dev, &conf); |
941 |
if (rc != 0) { |
942 |
return;
|
943 |
} |
944 |
for (i = 0; i < conf->bNumInterfaces; i++) { |
945 |
rc = libusb_kernel_driver_active(s->dh, i); |
946 |
usb_host_libusb_error("libusb_kernel_driver_active", rc);
|
947 |
if (rc != 1) { |
948 |
continue;
|
949 |
} |
950 |
trace_usb_host_detach_kernel(s->bus_num, s->addr, i); |
951 |
rc = libusb_detach_kernel_driver(s->dh, i); |
952 |
usb_host_libusb_error("libusb_detach_kernel_driver", rc);
|
953 |
s->ifs[i].detached = true;
|
954 |
} |
955 |
libusb_free_config_descriptor(conf); |
956 |
} |
957 |
|
958 |
static void usb_host_attach_kernel(USBHostDevice *s) |
959 |
{ |
960 |
struct libusb_config_descriptor *conf;
|
961 |
int rc, i;
|
962 |
|
963 |
rc = libusb_get_active_config_descriptor(s->dev, &conf); |
964 |
if (rc != 0) { |
965 |
return;
|
966 |
} |
967 |
for (i = 0; i < conf->bNumInterfaces; i++) { |
968 |
if (!s->ifs[i].detached) {
|
969 |
continue;
|
970 |
} |
971 |
trace_usb_host_attach_kernel(s->bus_num, s->addr, i); |
972 |
libusb_attach_kernel_driver(s->dh, i); |
973 |
s->ifs[i].detached = false;
|
974 |
} |
975 |
libusb_free_config_descriptor(conf); |
976 |
} |
977 |
|
978 |
static int usb_host_claim_interfaces(USBHostDevice *s, int configuration) |
979 |
{ |
980 |
USBDevice *udev = USB_DEVICE(s); |
981 |
struct libusb_config_descriptor *conf;
|
982 |
int rc, i;
|
983 |
|
984 |
for (i = 0; i < USB_MAX_INTERFACES; i++) { |
985 |
udev->altsetting[i] = 0;
|
986 |
} |
987 |
udev->ninterfaces = 0;
|
988 |
udev->configuration = 0;
|
989 |
|
990 |
if (configuration == 0) { |
991 |
/* address state - ignore */
|
992 |
return USB_RET_SUCCESS;
|
993 |
} |
994 |
|
995 |
usb_host_detach_kernel(s); |
996 |
|
997 |
rc = libusb_get_active_config_descriptor(s->dev, &conf); |
998 |
if (rc != 0) { |
999 |
return USB_RET_STALL;
|
1000 |
} |
1001 |
|
1002 |
for (i = 0; i < conf->bNumInterfaces; i++) { |
1003 |
trace_usb_host_claim_interface(s->bus_num, s->addr, configuration, i); |
1004 |
rc = libusb_claim_interface(s->dh, i); |
1005 |
usb_host_libusb_error("libusb_claim_interface", rc);
|
1006 |
if (rc != 0) { |
1007 |
return USB_RET_STALL;
|
1008 |
} |
1009 |
s->ifs[i].claimed = true;
|
1010 |
} |
1011 |
|
1012 |
udev->ninterfaces = conf->bNumInterfaces; |
1013 |
udev->configuration = configuration; |
1014 |
|
1015 |
libusb_free_config_descriptor(conf); |
1016 |
return USB_RET_SUCCESS;
|
1017 |
} |
1018 |
|
1019 |
static void usb_host_release_interfaces(USBHostDevice *s) |
1020 |
{ |
1021 |
USBDevice *udev = USB_DEVICE(s); |
1022 |
int i, rc;
|
1023 |
|
1024 |
for (i = 0; i < udev->ninterfaces; i++) { |
1025 |
if (!s->ifs[i].claimed) {
|
1026 |
continue;
|
1027 |
} |
1028 |
trace_usb_host_release_interface(s->bus_num, s->addr, i); |
1029 |
rc = libusb_release_interface(s->dh, i); |
1030 |
usb_host_libusb_error("libusb_release_interface", rc);
|
1031 |
s->ifs[i].claimed = false;
|
1032 |
} |
1033 |
} |
1034 |
|
1035 |
static void usb_host_set_address(USBHostDevice *s, int addr) |
1036 |
{ |
1037 |
USBDevice *udev = USB_DEVICE(s); |
1038 |
|
1039 |
trace_usb_host_set_address(s->bus_num, s->addr, addr); |
1040 |
udev->addr = addr; |
1041 |
} |
1042 |
|
1043 |
static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p) |
1044 |
{ |
1045 |
int rc;
|
1046 |
|
1047 |
trace_usb_host_set_config(s->bus_num, s->addr, config); |
1048 |
|
1049 |
usb_host_release_interfaces(s); |
1050 |
usb_host_detach_kernel(s); |
1051 |
rc = libusb_set_configuration(s->dh, config); |
1052 |
if (rc != 0) { |
1053 |
usb_host_libusb_error("libusb_set_configuration", rc);
|
1054 |
p->status = USB_RET_STALL; |
1055 |
if (rc == LIBUSB_ERROR_NO_DEVICE) {
|
1056 |
usb_host_nodev(s); |
1057 |
} |
1058 |
return;
|
1059 |
} |
1060 |
p->status = usb_host_claim_interfaces(s, config); |
1061 |
if (p->status != USB_RET_SUCCESS) {
|
1062 |
return;
|
1063 |
} |
1064 |
usb_host_ep_update(s); |
1065 |
} |
1066 |
|
1067 |
static void usb_host_set_interface(USBHostDevice *s, int iface, int alt, |
1068 |
USBPacket *p) |
1069 |
{ |
1070 |
USBDevice *udev = USB_DEVICE(s); |
1071 |
int rc;
|
1072 |
|
1073 |
trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt); |
1074 |
|
1075 |
usb_host_iso_free_all(s); |
1076 |
|
1077 |
if (iface >= USB_MAX_INTERFACES) {
|
1078 |
p->status = USB_RET_STALL; |
1079 |
return;
|
1080 |
} |
1081 |
|
1082 |
rc = libusb_set_interface_alt_setting(s->dh, iface, alt); |
1083 |
if (rc != 0) { |
1084 |
usb_host_libusb_error("libusb_set_interface_alt_setting", rc);
|
1085 |
p->status = USB_RET_STALL; |
1086 |
if (rc == LIBUSB_ERROR_NO_DEVICE) {
|
1087 |
usb_host_nodev(s); |
1088 |
} |
1089 |
return;
|
1090 |
} |
1091 |
|
1092 |
udev->altsetting[iface] = alt; |
1093 |
usb_host_ep_update(s); |
1094 |
} |
1095 |
|
1096 |
static void usb_host_handle_control(USBDevice *udev, USBPacket *p, |
1097 |
int request, int value, int index, |
1098 |
int length, uint8_t *data)
|
1099 |
{ |
1100 |
USBHostDevice *s = USB_HOST_DEVICE(udev); |
1101 |
USBHostRequest *r; |
1102 |
int rc;
|
1103 |
|
1104 |
trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); |
1105 |
|
1106 |
if (s->dh == NULL) { |
1107 |
p->status = USB_RET_NODEV; |
1108 |
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); |
1109 |
return;
|
1110 |
} |
1111 |
|
1112 |
switch (request) {
|
1113 |
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
1114 |
usb_host_set_address(s, value); |
1115 |
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); |
1116 |
return;
|
1117 |
|
1118 |
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
1119 |
usb_host_set_config(s, value & 0xff, p);
|
1120 |
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); |
1121 |
return;
|
1122 |
|
1123 |
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
|
1124 |
usb_host_set_interface(s, index, value, p); |
1125 |
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); |
1126 |
return;
|
1127 |
|
1128 |
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
1129 |
if (value == 0) { /* clear halt */ |
1130 |
int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
|
1131 |
libusb_clear_halt(s->dh, index); |
1132 |
usb_ep_set_halted(udev, pid, index & 0x0f, 0); |
1133 |
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); |
1134 |
return;
|
1135 |
} |
1136 |
} |
1137 |
|
1138 |
r = usb_host_req_alloc(s, p, (request >> 8) & USB_DIR_IN, length + 8); |
1139 |
r->cbuf = data; |
1140 |
r->clen = length; |
1141 |
memcpy(r->buffer, udev->setup_buf, 8);
|
1142 |
if (!r->in) {
|
1143 |
memcpy(r->buffer + 8, r->cbuf, r->clen);
|
1144 |
} |
1145 |
|
1146 |
libusb_fill_control_transfer(r->xfer, s->dh, r->buffer, |
1147 |
usb_host_req_complete_ctrl, r, |
1148 |
CONTROL_TIMEOUT); |
1149 |
rc = libusb_submit_transfer(r->xfer); |
1150 |
if (rc != 0) { |
1151 |
p->status = USB_RET_NODEV; |
1152 |
trace_usb_host_req_complete(s->bus_num, s->addr, p, |
1153 |
p->status, p->actual_length); |
1154 |
if (rc == LIBUSB_ERROR_NO_DEVICE) {
|
1155 |
usb_host_nodev(s); |
1156 |
} |
1157 |
return;
|
1158 |
} |
1159 |
|
1160 |
p->status = USB_RET_ASYNC; |
1161 |
} |
1162 |
|
1163 |
static void usb_host_handle_data(USBDevice *udev, USBPacket *p) |
1164 |
{ |
1165 |
USBHostDevice *s = USB_HOST_DEVICE(udev); |
1166 |
USBHostRequest *r; |
1167 |
size_t size; |
1168 |
int ep, rc;
|
1169 |
|
1170 |
if (usb_host_use_combining(p->ep) && p->state == USB_PACKET_SETUP) {
|
1171 |
p->status = USB_RET_ADD_TO_QUEUE; |
1172 |
return;
|
1173 |
} |
1174 |
|
1175 |
trace_usb_host_req_data(s->bus_num, s->addr, p, |
1176 |
p->pid == USB_TOKEN_IN, |
1177 |
p->ep->nr, p->iov.size); |
1178 |
|
1179 |
if (s->dh == NULL) { |
1180 |
p->status = USB_RET_NODEV; |
1181 |
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); |
1182 |
return;
|
1183 |
} |
1184 |
if (p->ep->halted) {
|
1185 |
p->status = USB_RET_STALL; |
1186 |
trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); |
1187 |
return;
|
1188 |
} |
1189 |
|
1190 |
switch (usb_ep_get_type(udev, p->pid, p->ep->nr)) {
|
1191 |
case USB_ENDPOINT_XFER_BULK:
|
1192 |
size = usb_packet_size(p); |
1193 |
r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, size); |
1194 |
if (!r->in) {
|
1195 |
usb_packet_copy(p, r->buffer, size); |
1196 |
} |
1197 |
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
|
1198 |
libusb_fill_bulk_transfer(r->xfer, s->dh, ep, |
1199 |
r->buffer, size, |
1200 |
usb_host_req_complete_data, r, |
1201 |
BULK_TIMEOUT); |
1202 |
break;
|
1203 |
case USB_ENDPOINT_XFER_INT:
|
1204 |
r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size); |
1205 |
if (!r->in) {
|
1206 |
usb_packet_copy(p, r->buffer, p->iov.size); |
1207 |
} |
1208 |
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
|
1209 |
libusb_fill_interrupt_transfer(r->xfer, s->dh, ep, |
1210 |
r->buffer, p->iov.size, |
1211 |
usb_host_req_complete_data, r, |
1212 |
INTR_TIMEOUT); |
1213 |
break;
|
1214 |
case USB_ENDPOINT_XFER_ISOC:
|
1215 |
if (p->pid == USB_TOKEN_IN) {
|
1216 |
usb_host_iso_data_in(s, p); |
1217 |
} else {
|
1218 |
usb_host_iso_data_out(s, p); |
1219 |
} |
1220 |
trace_usb_host_req_complete(s->bus_num, s->addr, p, |
1221 |
p->status, p->actual_length); |
1222 |
return;
|
1223 |
default:
|
1224 |
p->status = USB_RET_STALL; |
1225 |
trace_usb_host_req_complete(s->bus_num, s->addr, p, |
1226 |
p->status, p->actual_length); |
1227 |
return;
|
1228 |
} |
1229 |
|
1230 |
rc = libusb_submit_transfer(r->xfer); |
1231 |
if (rc != 0) { |
1232 |
p->status = USB_RET_NODEV; |
1233 |
trace_usb_host_req_complete(s->bus_num, s->addr, p, |
1234 |
p->status, p->actual_length); |
1235 |
if (rc == LIBUSB_ERROR_NO_DEVICE) {
|
1236 |
usb_host_nodev(s); |
1237 |
} |
1238 |
return;
|
1239 |
} |
1240 |
|
1241 |
p->status = USB_RET_ASYNC; |
1242 |
} |
1243 |
|
1244 |
static void usb_host_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) |
1245 |
{ |
1246 |
if (usb_host_use_combining(ep)) {
|
1247 |
usb_ep_combine_input_packets(ep); |
1248 |
} |
1249 |
} |
1250 |
|
1251 |
static void usb_host_handle_reset(USBDevice *udev) |
1252 |
{ |
1253 |
USBHostDevice *s = USB_HOST_DEVICE(udev); |
1254 |
|
1255 |
trace_usb_host_reset(s->bus_num, s->addr); |
1256 |
|
1257 |
if (udev->configuration == 0) { |
1258 |
return;
|
1259 |
} |
1260 |
usb_host_release_interfaces(s); |
1261 |
libusb_reset_device(s->dh); |
1262 |
usb_host_claim_interfaces(s, 0);
|
1263 |
usb_host_ep_update(s); |
1264 |
} |
1265 |
|
1266 |
/*
|
1267 |
* This is *NOT* about restoring state. We have absolutely no idea
|
1268 |
* what state the host device is in at the moment and whenever it is
|
1269 |
* still present in the first place. Attemping to contine where we
|
1270 |
* left off is impossible.
|
1271 |
*
|
1272 |
* What we are going to to to here is emulate a surprise removal of
|
1273 |
* the usb device passed through, then kick host scan so the device
|
1274 |
* will get re-attached (and re-initialized by the guest) in case it
|
1275 |
* is still present.
|
1276 |
*
|
1277 |
* As the device removal will change the state of other devices (usb
|
1278 |
* host controller, most likely interrupt controller too) we have to
|
1279 |
* wait with it until *all* vmstate is loaded. Thus post_load just
|
1280 |
* kicks a bottom half which then does the actual work.
|
1281 |
*/
|
1282 |
static void usb_host_post_load_bh(void *opaque) |
1283 |
{ |
1284 |
USBHostDevice *dev = opaque; |
1285 |
USBDevice *udev = USB_DEVICE(dev); |
1286 |
|
1287 |
if (dev->dh != NULL) { |
1288 |
usb_host_close(dev); |
1289 |
} |
1290 |
if (udev->attached) {
|
1291 |
usb_device_detach(udev); |
1292 |
} |
1293 |
usb_host_auto_check(NULL);
|
1294 |
} |
1295 |
|
1296 |
static int usb_host_post_load(void *opaque, int version_id) |
1297 |
{ |
1298 |
USBHostDevice *dev = opaque; |
1299 |
|
1300 |
if (!dev->bh_postld) {
|
1301 |
dev->bh_postld = qemu_bh_new(usb_host_post_load_bh, dev); |
1302 |
} |
1303 |
qemu_bh_schedule(dev->bh_postld); |
1304 |
return 0; |
1305 |
} |
1306 |
|
1307 |
static const VMStateDescription vmstate_usb_host = { |
1308 |
.name = "usb-host",
|
1309 |
.version_id = 1,
|
1310 |
.minimum_version_id = 1,
|
1311 |
.post_load = usb_host_post_load, |
1312 |
.fields = (VMStateField[]) { |
1313 |
VMSTATE_USB_DEVICE(parent_obj, USBHostDevice), |
1314 |
VMSTATE_END_OF_LIST() |
1315 |
} |
1316 |
}; |
1317 |
|
1318 |
static Property usb_host_dev_properties[] = {
|
1319 |
DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0), |
1320 |
DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0), |
1321 |
DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
|
1322 |
DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0), |
1323 |
DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0), |
1324 |
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4), |
1325 |
DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32), |
1326 |
DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex, -1), |
1327 |
DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel,
|
1328 |
LIBUSB_LOG_LEVEL_WARNING), |
1329 |
DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
|
1330 |
USB_HOST_OPT_PIPELINE, true),
|
1331 |
DEFINE_PROP_END_OF_LIST(), |
1332 |
}; |
1333 |
|
1334 |
static void usb_host_class_initfn(ObjectClass *klass, void *data) |
1335 |
{ |
1336 |
DeviceClass *dc = DEVICE_CLASS(klass); |
1337 |
USBDeviceClass *uc = USB_DEVICE_CLASS(klass); |
1338 |
|
1339 |
uc->init = usb_host_initfn; |
1340 |
uc->product_desc = "USB Host Device";
|
1341 |
uc->cancel_packet = usb_host_cancel_packet; |
1342 |
uc->handle_data = usb_host_handle_data; |
1343 |
uc->handle_control = usb_host_handle_control; |
1344 |
uc->handle_reset = usb_host_handle_reset; |
1345 |
uc->handle_destroy = usb_host_handle_destroy; |
1346 |
uc->flush_ep_queue = usb_host_flush_ep_queue; |
1347 |
dc->vmsd = &vmstate_usb_host; |
1348 |
dc->props = usb_host_dev_properties; |
1349 |
} |
1350 |
|
1351 |
static TypeInfo usb_host_dev_info = {
|
1352 |
.name = TYPE_USB_HOST_DEVICE, |
1353 |
.parent = TYPE_USB_DEVICE, |
1354 |
.instance_size = sizeof(USBHostDevice),
|
1355 |
.class_init = usb_host_class_initfn, |
1356 |
}; |
1357 |
|
1358 |
static void usb_host_register_types(void) |
1359 |
{ |
1360 |
type_register_static(&usb_host_dev_info); |
1361 |
} |
1362 |
|
1363 |
type_init(usb_host_register_types) |
1364 |
|
1365 |
/* ------------------------------------------------------------------------ */
|
1366 |
|
1367 |
static QEMUTimer *usb_auto_timer;
|
1368 |
static VMChangeStateEntry *usb_vmstate;
|
1369 |
|
1370 |
static void usb_host_vm_state(void *unused, int running, RunState state) |
1371 |
{ |
1372 |
if (running) {
|
1373 |
usb_host_auto_check(unused); |
1374 |
} |
1375 |
} |
1376 |
|
1377 |
static void usb_host_auto_check(void *unused) |
1378 |
{ |
1379 |
struct USBHostDevice *s;
|
1380 |
struct USBAutoFilter *f;
|
1381 |
libusb_device **devs; |
1382 |
struct libusb_device_descriptor ddesc;
|
1383 |
int unconnected = 0; |
1384 |
int i, n;
|
1385 |
|
1386 |
if (usb_host_init() != 0) { |
1387 |
return;
|
1388 |
} |
1389 |
|
1390 |
if (runstate_is_running()) {
|
1391 |
n = libusb_get_device_list(ctx, &devs); |
1392 |
for (i = 0; i < n; i++) { |
1393 |
if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) { |
1394 |
continue;
|
1395 |
} |
1396 |
if (ddesc.bDeviceClass == LIBUSB_CLASS_HUB) {
|
1397 |
continue;
|
1398 |
} |
1399 |
QTAILQ_FOREACH(s, &hostdevs, next) { |
1400 |
f = &s->match; |
1401 |
if (f->bus_num > 0 && |
1402 |
f->bus_num != libusb_get_bus_number(devs[i])) { |
1403 |
continue;
|
1404 |
} |
1405 |
if (f->addr > 0 && |
1406 |
f->addr != libusb_get_device_address(devs[i])) { |
1407 |
continue;
|
1408 |
} |
1409 |
if (f->port != NULL) { |
1410 |
char port[16] = "-"; |
1411 |
usb_host_get_port(devs[i], port, sizeof(port));
|
1412 |
if (strcmp(f->port, port) != 0) { |
1413 |
continue;
|
1414 |
} |
1415 |
} |
1416 |
if (f->vendor_id > 0 && |
1417 |
f->vendor_id != ddesc.idVendor) { |
1418 |
continue;
|
1419 |
} |
1420 |
if (f->product_id > 0 && |
1421 |
f->product_id != ddesc.idProduct) { |
1422 |
continue;
|
1423 |
} |
1424 |
|
1425 |
/* We got a match */
|
1426 |
s->seen++; |
1427 |
if (s->errcount >= 3) { |
1428 |
continue;
|
1429 |
} |
1430 |
if (s->dh != NULL) { |
1431 |
continue;
|
1432 |
} |
1433 |
if (usb_host_open(s, devs[i]) < 0) { |
1434 |
s->errcount++; |
1435 |
continue;
|
1436 |
} |
1437 |
break;
|
1438 |
} |
1439 |
} |
1440 |
libusb_free_device_list(devs, 1);
|
1441 |
|
1442 |
QTAILQ_FOREACH(s, &hostdevs, next) { |
1443 |
if (s->dh == NULL) { |
1444 |
unconnected++; |
1445 |
} |
1446 |
if (s->seen == 0) { |
1447 |
if (s->dh) {
|
1448 |
usb_host_close(s); |
1449 |
} |
1450 |
s->errcount = 0;
|
1451 |
} |
1452 |
s->seen = 0;
|
1453 |
} |
1454 |
|
1455 |
#if 0
|
1456 |
if (unconnected == 0) {
|
1457 |
/* nothing to watch */
|
1458 |
if (usb_auto_timer) {
|
1459 |
qemu_del_timer(usb_auto_timer);
|
1460 |
trace_usb_host_auto_scan_disabled();
|
1461 |
}
|
1462 |
return;
|
1463 |
}
|
1464 |
#endif
|
1465 |
} |
1466 |
|
1467 |
if (!usb_vmstate) {
|
1468 |
usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL);
|
1469 |
} |
1470 |
if (!usb_auto_timer) {
|
1471 |
usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL);
|
1472 |
if (!usb_auto_timer) {
|
1473 |
return;
|
1474 |
} |
1475 |
trace_usb_host_auto_scan_enabled(); |
1476 |
} |
1477 |
qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000);
|
1478 |
} |
1479 |
|
1480 |
void usb_host_info(Monitor *mon, const QDict *qdict) |
1481 |
{ |
1482 |
libusb_device **devs; |
1483 |
struct libusb_device_descriptor ddesc;
|
1484 |
char port[16]; |
1485 |
int i, n;
|
1486 |
|
1487 |
if (usb_host_init() != 0) { |
1488 |
return;
|
1489 |
} |
1490 |
|
1491 |
n = libusb_get_device_list(ctx, &devs); |
1492 |
for (i = 0; i < n; i++) { |
1493 |
if (libusb_get_device_descriptor(devs[i], &ddesc) != 0) { |
1494 |
continue;
|
1495 |
} |
1496 |
if (ddesc.bDeviceClass == LIBUSB_CLASS_HUB) {
|
1497 |
continue;
|
1498 |
} |
1499 |
usb_host_get_port(devs[i], port, sizeof(port));
|
1500 |
monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
|
1501 |
libusb_get_bus_number(devs[i]), |
1502 |
libusb_get_device_address(devs[i]), |
1503 |
port, |
1504 |
speed_name[libusb_get_device_speed(devs[i])]); |
1505 |
monitor_printf(mon, " Class %02x:", ddesc.bDeviceClass);
|
1506 |
monitor_printf(mon, " USB device %04x:%04x",
|
1507 |
ddesc.idVendor, ddesc.idProduct); |
1508 |
if (ddesc.iProduct) {
|
1509 |
libusb_device_handle *handle; |
1510 |
if (libusb_open(devs[i], &handle) == 0) { |
1511 |
unsigned char name[64] = ""; |
1512 |
libusb_get_string_descriptor_ascii(handle, |
1513 |
ddesc.iProduct, |
1514 |
name, sizeof(name));
|
1515 |
libusb_close(handle); |
1516 |
monitor_printf(mon, ", %s", name);
|
1517 |
} |
1518 |
} |
1519 |
monitor_printf(mon, "\n");
|
1520 |
} |
1521 |
libusb_free_device_list(devs, 1);
|
1522 |
} |