root / hw / usb / redirect.c @ ae12e3a6
History | View | Annotate | Download (77.2 kB)
1 |
/*
|
---|---|
2 |
* USB redirector usb-guest
|
3 |
*
|
4 |
* Copyright (c) 2011-2012 Red Hat, Inc.
|
5 |
*
|
6 |
* Red Hat Authors:
|
7 |
* Hans de Goede <hdegoede@redhat.com>
|
8 |
*
|
9 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
10 |
* of this software and associated documentation files (the "Software"), to deal
|
11 |
* in the Software without restriction, including without limitation the rights
|
12 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13 |
* copies of the Software, and to permit persons to whom the Software is
|
14 |
* furnished to do so, subject to the following conditions:
|
15 |
*
|
16 |
* The above copyright notice and this permission notice shall be included in
|
17 |
* all copies or substantial portions of the Software.
|
18 |
*
|
19 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
22 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
25 |
* THE SOFTWARE.
|
26 |
*/
|
27 |
|
28 |
#include "qemu-common.h" |
29 |
#include "qemu/timer.h" |
30 |
#include "monitor/monitor.h" |
31 |
#include "sysemu/sysemu.h" |
32 |
#include "qemu/iov.h" |
33 |
#include "sysemu/char.h" |
34 |
|
35 |
#include <dirent.h> |
36 |
#include <sys/ioctl.h> |
37 |
#include <signal.h> |
38 |
#include <usbredirparser.h> |
39 |
#include <usbredirfilter.h> |
40 |
|
41 |
#include "hw/usb.h" |
42 |
|
43 |
#define MAX_ENDPOINTS 32 |
44 |
#define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */ |
45 |
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) |
46 |
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) |
47 |
#define USBEP2I(usb_ep) (((usb_ep)->pid == USB_TOKEN_IN) ? \
|
48 |
((usb_ep)->nr | 0x10) : ((usb_ep)->nr))
|
49 |
#define I2USBEP(d, i) (usb_ep_get(&(d)->dev, \
|
50 |
((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \
|
51 |
(i) & 0x0f))
|
52 |
|
53 |
typedef struct USBRedirDevice USBRedirDevice; |
54 |
|
55 |
/* Struct to hold buffered packets */
|
56 |
struct buf_packet {
|
57 |
uint8_t *data; |
58 |
void *free_on_destroy;
|
59 |
uint16_t len; |
60 |
uint16_t offset; |
61 |
uint8_t status; |
62 |
QTAILQ_ENTRY(buf_packet)next; |
63 |
}; |
64 |
|
65 |
struct endp_data {
|
66 |
USBRedirDevice *dev; |
67 |
uint8_t type; |
68 |
uint8_t interval; |
69 |
uint8_t interface; /* bInterfaceNumber this ep belongs to */
|
70 |
uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */
|
71 |
uint8_t iso_started; |
72 |
uint8_t iso_error; /* For reporting iso errors to the HC */
|
73 |
uint8_t interrupt_started; |
74 |
uint8_t interrupt_error; |
75 |
uint8_t bulk_receiving_enabled; |
76 |
uint8_t bulk_receiving_started; |
77 |
uint8_t bufpq_prefilled; |
78 |
uint8_t bufpq_dropping_packets; |
79 |
QTAILQ_HEAD(, buf_packet) bufpq; |
80 |
int32_t bufpq_size; |
81 |
int32_t bufpq_target_size; |
82 |
USBPacket *pending_async_packet; |
83 |
}; |
84 |
|
85 |
struct PacketIdQueueEntry {
|
86 |
uint64_t id; |
87 |
QTAILQ_ENTRY(PacketIdQueueEntry)next; |
88 |
}; |
89 |
|
90 |
struct PacketIdQueue {
|
91 |
USBRedirDevice *dev; |
92 |
const char *name; |
93 |
QTAILQ_HEAD(, PacketIdQueueEntry) head; |
94 |
int size;
|
95 |
}; |
96 |
|
97 |
struct USBRedirDevice {
|
98 |
USBDevice dev; |
99 |
/* Properties */
|
100 |
CharDriverState *cs; |
101 |
uint8_t debug; |
102 |
char *filter_str;
|
103 |
int32_t bootindex; |
104 |
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
|
105 |
const uint8_t *read_buf;
|
106 |
int read_buf_size;
|
107 |
/* Active chardev-watch-tag */
|
108 |
guint watch; |
109 |
/* For async handling of close */
|
110 |
QEMUBH *chardev_close_bh; |
111 |
/* To delay the usb attach in case of quick chardev close + open */
|
112 |
QEMUTimer *attach_timer; |
113 |
int64_t next_attach_time; |
114 |
struct usbredirparser *parser;
|
115 |
struct endp_data endpoint[MAX_ENDPOINTS];
|
116 |
struct PacketIdQueue cancelled;
|
117 |
struct PacketIdQueue already_in_flight;
|
118 |
void (*buffered_bulk_in_complete)(USBRedirDevice *, USBPacket *, uint8_t);
|
119 |
/* Data for device filtering */
|
120 |
struct usb_redir_device_connect_header device_info;
|
121 |
struct usb_redir_interface_info_header interface_info;
|
122 |
struct usbredirfilter_rule *filter_rules;
|
123 |
int filter_rules_count;
|
124 |
int compatible_speedmask;
|
125 |
}; |
126 |
|
127 |
static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); |
128 |
static void usbredir_device_connect(void *priv, |
129 |
struct usb_redir_device_connect_header *device_connect);
|
130 |
static void usbredir_device_disconnect(void *priv); |
131 |
static void usbredir_interface_info(void *priv, |
132 |
struct usb_redir_interface_info_header *interface_info);
|
133 |
static void usbredir_ep_info(void *priv, |
134 |
struct usb_redir_ep_info_header *ep_info);
|
135 |
static void usbredir_configuration_status(void *priv, uint64_t id, |
136 |
struct usb_redir_configuration_status_header *configuration_status);
|
137 |
static void usbredir_alt_setting_status(void *priv, uint64_t id, |
138 |
struct usb_redir_alt_setting_status_header *alt_setting_status);
|
139 |
static void usbredir_iso_stream_status(void *priv, uint64_t id, |
140 |
struct usb_redir_iso_stream_status_header *iso_stream_status);
|
141 |
static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, |
142 |
struct usb_redir_interrupt_receiving_status_header
|
143 |
*interrupt_receiving_status); |
144 |
static void usbredir_bulk_streams_status(void *priv, uint64_t id, |
145 |
struct usb_redir_bulk_streams_status_header *bulk_streams_status);
|
146 |
static void usbredir_bulk_receiving_status(void *priv, uint64_t id, |
147 |
struct usb_redir_bulk_receiving_status_header *bulk_receiving_status);
|
148 |
static void usbredir_control_packet(void *priv, uint64_t id, |
149 |
struct usb_redir_control_packet_header *control_packet,
|
150 |
uint8_t *data, int data_len);
|
151 |
static void usbredir_bulk_packet(void *priv, uint64_t id, |
152 |
struct usb_redir_bulk_packet_header *bulk_packet,
|
153 |
uint8_t *data, int data_len);
|
154 |
static void usbredir_iso_packet(void *priv, uint64_t id, |
155 |
struct usb_redir_iso_packet_header *iso_packet,
|
156 |
uint8_t *data, int data_len);
|
157 |
static void usbredir_interrupt_packet(void *priv, uint64_t id, |
158 |
struct usb_redir_interrupt_packet_header *interrupt_header,
|
159 |
uint8_t *data, int data_len);
|
160 |
static void usbredir_buffered_bulk_packet(void *priv, uint64_t id, |
161 |
struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet,
|
162 |
uint8_t *data, int data_len);
|
163 |
|
164 |
static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p, |
165 |
int status);
|
166 |
|
167 |
#define VERSION "qemu usb-redir guest " QEMU_VERSION |
168 |
|
169 |
/*
|
170 |
* Logging stuff
|
171 |
*/
|
172 |
|
173 |
#define ERROR(...) \
|
174 |
do { \
|
175 |
if (dev->debug >= usbredirparser_error) { \
|
176 |
error_report("usb-redir error: " __VA_ARGS__); \
|
177 |
} \ |
178 |
} while (0) |
179 |
#define WARNING(...) \
|
180 |
do { \
|
181 |
if (dev->debug >= usbredirparser_warning) { \
|
182 |
error_report("usb-redir warning: " __VA_ARGS__); \
|
183 |
} \ |
184 |
} while (0) |
185 |
#define INFO(...) \
|
186 |
do { \
|
187 |
if (dev->debug >= usbredirparser_info) { \
|
188 |
error_report("usb-redir: " __VA_ARGS__); \
|
189 |
} \ |
190 |
} while (0) |
191 |
#define DPRINTF(...) \
|
192 |
do { \
|
193 |
if (dev->debug >= usbredirparser_debug) { \
|
194 |
error_report("usb-redir: " __VA_ARGS__); \
|
195 |
} \ |
196 |
} while (0) |
197 |
#define DPRINTF2(...) \
|
198 |
do { \
|
199 |
if (dev->debug >= usbredirparser_debug_data) { \
|
200 |
error_report("usb-redir: " __VA_ARGS__); \
|
201 |
} \ |
202 |
} while (0) |
203 |
|
204 |
static void usbredir_log(void *priv, int level, const char *msg) |
205 |
{ |
206 |
USBRedirDevice *dev = priv; |
207 |
|
208 |
if (dev->debug < level) {
|
209 |
return;
|
210 |
} |
211 |
|
212 |
error_report("%s", msg);
|
213 |
} |
214 |
|
215 |
static void usbredir_log_data(USBRedirDevice *dev, const char *desc, |
216 |
const uint8_t *data, int len) |
217 |
{ |
218 |
int i, j, n;
|
219 |
|
220 |
if (dev->debug < usbredirparser_debug_data) {
|
221 |
return;
|
222 |
} |
223 |
|
224 |
for (i = 0; i < len; i += j) { |
225 |
char buf[128]; |
226 |
|
227 |
n = sprintf(buf, "%s", desc);
|
228 |
for (j = 0; j < 8 && i + j < len; j++) { |
229 |
n += sprintf(buf + n, " %02X", data[i + j]);
|
230 |
} |
231 |
error_report("%s", buf);
|
232 |
} |
233 |
} |
234 |
|
235 |
/*
|
236 |
* usbredirparser io functions
|
237 |
*/
|
238 |
|
239 |
static int usbredir_read(void *priv, uint8_t *data, int count) |
240 |
{ |
241 |
USBRedirDevice *dev = priv; |
242 |
|
243 |
if (dev->read_buf_size < count) {
|
244 |
count = dev->read_buf_size; |
245 |
} |
246 |
|
247 |
memcpy(data, dev->read_buf, count); |
248 |
|
249 |
dev->read_buf_size -= count; |
250 |
if (dev->read_buf_size) {
|
251 |
dev->read_buf += count; |
252 |
} else {
|
253 |
dev->read_buf = NULL;
|
254 |
} |
255 |
|
256 |
return count;
|
257 |
} |
258 |
|
259 |
static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
|
260 |
void *opaque)
|
261 |
{ |
262 |
USBRedirDevice *dev = opaque; |
263 |
|
264 |
dev->watch = 0;
|
265 |
usbredirparser_do_write(dev->parser); |
266 |
|
267 |
return FALSE;
|
268 |
} |
269 |
|
270 |
static int usbredir_write(void *priv, uint8_t *data, int count) |
271 |
{ |
272 |
USBRedirDevice *dev = priv; |
273 |
int r;
|
274 |
|
275 |
if (!dev->cs->be_open) {
|
276 |
return 0; |
277 |
} |
278 |
|
279 |
/* Don't send new data to the chardev until our state is fully synced */
|
280 |
if (!runstate_check(RUN_STATE_RUNNING)) {
|
281 |
return 0; |
282 |
} |
283 |
|
284 |
r = qemu_chr_fe_write(dev->cs, data, count); |
285 |
if (r < count) {
|
286 |
if (!dev->watch) {
|
287 |
dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT, |
288 |
usbredir_write_unblocked, dev); |
289 |
} |
290 |
if (r < 0) { |
291 |
r = 0;
|
292 |
} |
293 |
} |
294 |
return r;
|
295 |
} |
296 |
|
297 |
/*
|
298 |
* Cancelled and buffered packets helpers
|
299 |
*/
|
300 |
|
301 |
static void packet_id_queue_init(struct PacketIdQueue *q, |
302 |
USBRedirDevice *dev, const char *name) |
303 |
{ |
304 |
q->dev = dev; |
305 |
q->name = name; |
306 |
QTAILQ_INIT(&q->head); |
307 |
q->size = 0;
|
308 |
} |
309 |
|
310 |
static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) |
311 |
{ |
312 |
USBRedirDevice *dev = q->dev; |
313 |
struct PacketIdQueueEntry *e;
|
314 |
|
315 |
DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); |
316 |
|
317 |
e = g_malloc0(sizeof(struct PacketIdQueueEntry)); |
318 |
e->id = id; |
319 |
QTAILQ_INSERT_TAIL(&q->head, e, next); |
320 |
q->size++; |
321 |
} |
322 |
|
323 |
static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) |
324 |
{ |
325 |
USBRedirDevice *dev = q->dev; |
326 |
struct PacketIdQueueEntry *e;
|
327 |
|
328 |
QTAILQ_FOREACH(e, &q->head, next) { |
329 |
if (e->id == id) {
|
330 |
DPRINTF("removing packet id %"PRIu64" from %s queue\n", |
331 |
id, q->name); |
332 |
QTAILQ_REMOVE(&q->head, e, next); |
333 |
q->size--; |
334 |
g_free(e); |
335 |
return 1; |
336 |
} |
337 |
} |
338 |
return 0; |
339 |
} |
340 |
|
341 |
static void packet_id_queue_empty(struct PacketIdQueue *q) |
342 |
{ |
343 |
USBRedirDevice *dev = q->dev; |
344 |
struct PacketIdQueueEntry *e, *next_e;
|
345 |
|
346 |
DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name);
|
347 |
|
348 |
QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { |
349 |
QTAILQ_REMOVE(&q->head, e, next); |
350 |
g_free(e); |
351 |
} |
352 |
q->size = 0;
|
353 |
} |
354 |
|
355 |
static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) |
356 |
{ |
357 |
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); |
358 |
int i = USBEP2I(p->ep);
|
359 |
|
360 |
if (p->combined) {
|
361 |
usb_combined_packet_cancel(udev, p); |
362 |
return;
|
363 |
} |
364 |
|
365 |
if (dev->endpoint[i].pending_async_packet) {
|
366 |
assert(dev->endpoint[i].pending_async_packet == p); |
367 |
dev->endpoint[i].pending_async_packet = NULL;
|
368 |
return;
|
369 |
} |
370 |
|
371 |
packet_id_queue_add(&dev->cancelled, p->id); |
372 |
usbredirparser_send_cancel_data_packet(dev->parser, p->id); |
373 |
usbredirparser_do_write(dev->parser); |
374 |
} |
375 |
|
376 |
static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) |
377 |
{ |
378 |
if (!dev->dev.attached) {
|
379 |
return 1; /* Treat everything as cancelled after a disconnect */ |
380 |
} |
381 |
return packet_id_queue_remove(&dev->cancelled, id);
|
382 |
} |
383 |
|
384 |
static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, |
385 |
struct USBEndpoint *ep)
|
386 |
{ |
387 |
static USBPacket *p;
|
388 |
|
389 |
/* async handled packets for bulk receiving eps do not count as inflight */
|
390 |
if (dev->endpoint[USBEP2I(ep)].bulk_receiving_started) {
|
391 |
return;
|
392 |
} |
393 |
|
394 |
QTAILQ_FOREACH(p, &ep->queue, queue) { |
395 |
/* Skip combined packets, except for the first */
|
396 |
if (p->combined && p != p->combined->first) {
|
397 |
continue;
|
398 |
} |
399 |
if (p->state == USB_PACKET_ASYNC) {
|
400 |
packet_id_queue_add(&dev->already_in_flight, p->id); |
401 |
} |
402 |
} |
403 |
} |
404 |
|
405 |
static void usbredir_fill_already_in_flight(USBRedirDevice *dev) |
406 |
{ |
407 |
int ep;
|
408 |
struct USBDevice *udev = &dev->dev;
|
409 |
|
410 |
usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); |
411 |
|
412 |
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { |
413 |
usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); |
414 |
usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); |
415 |
} |
416 |
} |
417 |
|
418 |
static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) |
419 |
{ |
420 |
return packet_id_queue_remove(&dev->already_in_flight, id);
|
421 |
} |
422 |
|
423 |
static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev,
|
424 |
uint8_t ep, uint64_t id) |
425 |
{ |
426 |
USBPacket *p; |
427 |
|
428 |
if (usbredir_is_cancelled(dev, id)) {
|
429 |
return NULL; |
430 |
} |
431 |
|
432 |
p = usb_ep_find_packet_by_id(&dev->dev, |
433 |
(ep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT, |
434 |
ep & 0x0f, id);
|
435 |
if (p == NULL) { |
436 |
ERROR("could not find packet with id %"PRIu64"\n", id); |
437 |
} |
438 |
return p;
|
439 |
} |
440 |
|
441 |
static void bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len, |
442 |
uint8_t status, uint8_t ep, void *free_on_destroy)
|
443 |
{ |
444 |
struct buf_packet *bufp;
|
445 |
|
446 |
if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets &&
|
447 |
dev->endpoint[EP2I(ep)].bufpq_size > |
448 |
2 * dev->endpoint[EP2I(ep)].bufpq_target_size) {
|
449 |
DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep);
|
450 |
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1;
|
451 |
} |
452 |
/* Since we're interupting the stream anyways, drop enough packets to get
|
453 |
back to our target buffer size */
|
454 |
if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) {
|
455 |
if (dev->endpoint[EP2I(ep)].bufpq_size >
|
456 |
dev->endpoint[EP2I(ep)].bufpq_target_size) { |
457 |
free(data); |
458 |
return;
|
459 |
} |
460 |
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
|
461 |
} |
462 |
|
463 |
bufp = g_malloc(sizeof(struct buf_packet)); |
464 |
bufp->data = data; |
465 |
bufp->len = len; |
466 |
bufp->offset = 0;
|
467 |
bufp->status = status; |
468 |
bufp->free_on_destroy = free_on_destroy; |
469 |
QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); |
470 |
dev->endpoint[EP2I(ep)].bufpq_size++; |
471 |
} |
472 |
|
473 |
static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp, |
474 |
uint8_t ep) |
475 |
{ |
476 |
QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); |
477 |
dev->endpoint[EP2I(ep)].bufpq_size--; |
478 |
free(bufp->free_on_destroy); |
479 |
g_free(bufp); |
480 |
} |
481 |
|
482 |
static void usbredir_free_bufpq(USBRedirDevice *dev, uint8_t ep) |
483 |
{ |
484 |
struct buf_packet *buf, *buf_next;
|
485 |
|
486 |
QTAILQ_FOREACH_SAFE(buf, &dev->endpoint[EP2I(ep)].bufpq, next, buf_next) { |
487 |
bufp_free(dev, buf, ep); |
488 |
} |
489 |
} |
490 |
|
491 |
/*
|
492 |
* USBDevice callbacks
|
493 |
*/
|
494 |
|
495 |
static void usbredir_handle_reset(USBDevice *udev) |
496 |
{ |
497 |
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); |
498 |
|
499 |
DPRINTF("reset device\n");
|
500 |
usbredirparser_send_reset(dev->parser); |
501 |
usbredirparser_do_write(dev->parser); |
502 |
} |
503 |
|
504 |
static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, |
505 |
uint8_t ep) |
506 |
{ |
507 |
int status, len;
|
508 |
if (!dev->endpoint[EP2I(ep)].iso_started &&
|
509 |
!dev->endpoint[EP2I(ep)].iso_error) { |
510 |
struct usb_redir_start_iso_stream_header start_iso = {
|
511 |
.endpoint = ep, |
512 |
}; |
513 |
int pkts_per_sec;
|
514 |
|
515 |
if (dev->dev.speed == USB_SPEED_HIGH) {
|
516 |
pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval;
|
517 |
} else {
|
518 |
pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval;
|
519 |
} |
520 |
/* Testing has shown that we need circa 60 ms buffer */
|
521 |
dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000; |
522 |
|
523 |
/* Aim for approx 100 interrupts / second on the client to
|
524 |
balance latency and interrupt load */
|
525 |
start_iso.pkts_per_urb = pkts_per_sec / 100;
|
526 |
if (start_iso.pkts_per_urb < 1) { |
527 |
start_iso.pkts_per_urb = 1;
|
528 |
} else if (start_iso.pkts_per_urb > 32) { |
529 |
start_iso.pkts_per_urb = 32;
|
530 |
} |
531 |
|
532 |
start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size + |
533 |
start_iso.pkts_per_urb - 1) /
|
534 |
start_iso.pkts_per_urb; |
535 |
/* Output endpoints pre-fill only 1/2 of the packets, keeping the rest
|
536 |
as overflow buffer. Also see the usbredir protocol documentation */
|
537 |
if (!(ep & USB_DIR_IN)) {
|
538 |
start_iso.no_urbs *= 2;
|
539 |
} |
540 |
if (start_iso.no_urbs > 16) { |
541 |
start_iso.no_urbs = 16;
|
542 |
} |
543 |
|
544 |
/* No id, we look at the ep when receiving a status back */
|
545 |
usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
|
546 |
usbredirparser_do_write(dev->parser); |
547 |
DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n",
|
548 |
pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep); |
549 |
dev->endpoint[EP2I(ep)].iso_started = 1;
|
550 |
dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
|
551 |
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
|
552 |
} |
553 |
|
554 |
if (ep & USB_DIR_IN) {
|
555 |
struct buf_packet *isop;
|
556 |
|
557 |
if (dev->endpoint[EP2I(ep)].iso_started &&
|
558 |
!dev->endpoint[EP2I(ep)].bufpq_prefilled) { |
559 |
if (dev->endpoint[EP2I(ep)].bufpq_size <
|
560 |
dev->endpoint[EP2I(ep)].bufpq_target_size) { |
561 |
return;
|
562 |
} |
563 |
dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
|
564 |
} |
565 |
|
566 |
isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); |
567 |
if (isop == NULL) { |
568 |
DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n",
|
569 |
ep, dev->endpoint[EP2I(ep)].iso_error); |
570 |
/* Re-fill the buffer */
|
571 |
dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
|
572 |
/* Check iso_error for stream errors, otherwise its an underrun */
|
573 |
status = dev->endpoint[EP2I(ep)].iso_error; |
574 |
dev->endpoint[EP2I(ep)].iso_error = 0;
|
575 |
p->status = status ? USB_RET_IOERROR : USB_RET_SUCCESS; |
576 |
return;
|
577 |
} |
578 |
DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
|
579 |
isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); |
580 |
|
581 |
status = isop->status; |
582 |
len = isop->len; |
583 |
if (len > p->iov.size) {
|
584 |
ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
|
585 |
ep, len, (int)p->iov.size);
|
586 |
len = p->iov.size; |
587 |
status = usb_redir_babble; |
588 |
} |
589 |
usb_packet_copy(p, isop->data, len); |
590 |
bufp_free(dev, isop, ep); |
591 |
usbredir_handle_status(dev, p, status); |
592 |
} else {
|
593 |
/* If the stream was not started because of a pending error don't
|
594 |
send the packet to the usb-host */
|
595 |
if (dev->endpoint[EP2I(ep)].iso_started) {
|
596 |
struct usb_redir_iso_packet_header iso_packet = {
|
597 |
.endpoint = ep, |
598 |
.length = p->iov.size |
599 |
}; |
600 |
uint8_t buf[p->iov.size]; |
601 |
/* No id, we look at the ep when receiving a status back */
|
602 |
usb_packet_copy(p, buf, p->iov.size); |
603 |
usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet,
|
604 |
buf, p->iov.size); |
605 |
usbredirparser_do_write(dev->parser); |
606 |
} |
607 |
status = dev->endpoint[EP2I(ep)].iso_error; |
608 |
dev->endpoint[EP2I(ep)].iso_error = 0;
|
609 |
DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status,
|
610 |
p->iov.size); |
611 |
usbredir_handle_status(dev, p, status); |
612 |
} |
613 |
} |
614 |
|
615 |
static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) |
616 |
{ |
617 |
struct usb_redir_stop_iso_stream_header stop_iso_stream = {
|
618 |
.endpoint = ep |
619 |
}; |
620 |
if (dev->endpoint[EP2I(ep)].iso_started) {
|
621 |
usbredirparser_send_stop_iso_stream(dev->parser, 0, &stop_iso_stream);
|
622 |
DPRINTF("iso stream stopped ep %02X\n", ep);
|
623 |
dev->endpoint[EP2I(ep)].iso_started = 0;
|
624 |
} |
625 |
dev->endpoint[EP2I(ep)].iso_error = 0;
|
626 |
usbredir_free_bufpq(dev, ep); |
627 |
} |
628 |
|
629 |
/*
|
630 |
* The usb-host may poll the endpoint faster then our guest, resulting in lots
|
631 |
* of smaller bulkp-s. The below buffered_bulk_in_complete* functions combine
|
632 |
* data from multiple bulkp-s into a single packet, avoiding bufpq overflows.
|
633 |
*/
|
634 |
static void usbredir_buffered_bulk_add_data_to_packet(USBRedirDevice *dev, |
635 |
struct buf_packet *bulkp, int count, USBPacket *p, uint8_t ep) |
636 |
{ |
637 |
usb_packet_copy(p, bulkp->data + bulkp->offset, count); |
638 |
bulkp->offset += count; |
639 |
if (bulkp->offset == bulkp->len) {
|
640 |
/* Store status in the last packet with data from this bulkp */
|
641 |
usbredir_handle_status(dev, p, bulkp->status); |
642 |
bufp_free(dev, bulkp, ep); |
643 |
} |
644 |
} |
645 |
|
646 |
static void usbredir_buffered_bulk_in_complete_raw(USBRedirDevice *dev, |
647 |
USBPacket *p, uint8_t ep) |
648 |
{ |
649 |
struct buf_packet *bulkp;
|
650 |
int count;
|
651 |
|
652 |
while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) &&
|
653 |
p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) { |
654 |
count = bulkp->len - bulkp->offset; |
655 |
if (count > (p->iov.size - p->actual_length)) {
|
656 |
count = p->iov.size - p->actual_length; |
657 |
} |
658 |
usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep); |
659 |
} |
660 |
} |
661 |
|
662 |
static void usbredir_buffered_bulk_in_complete_ftdi(USBRedirDevice *dev, |
663 |
USBPacket *p, uint8_t ep) |
664 |
{ |
665 |
const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; |
666 |
uint8_t header[2] = { 0, 0 }; |
667 |
struct buf_packet *bulkp;
|
668 |
int count;
|
669 |
|
670 |
while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) &&
|
671 |
p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) { |
672 |
if (bulkp->len < 2) { |
673 |
WARNING("malformed ftdi bulk in packet\n");
|
674 |
bufp_free(dev, bulkp, ep); |
675 |
continue;
|
676 |
} |
677 |
|
678 |
if ((p->actual_length % maxp) == 0) { |
679 |
usb_packet_copy(p, bulkp->data, 2);
|
680 |
memcpy(header, bulkp->data, 2);
|
681 |
} else {
|
682 |
if (bulkp->data[0] != header[0] || bulkp->data[1] != header[1]) { |
683 |
break; /* Different header, add to next packet */ |
684 |
} |
685 |
} |
686 |
|
687 |
if (bulkp->offset == 0) { |
688 |
bulkp->offset = 2; /* Skip header */ |
689 |
} |
690 |
count = bulkp->len - bulkp->offset; |
691 |
/* Must repeat the header at maxp interval */
|
692 |
if (count > (maxp - (p->actual_length % maxp))) {
|
693 |
count = maxp - (p->actual_length % maxp); |
694 |
} |
695 |
usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep); |
696 |
} |
697 |
} |
698 |
|
699 |
static void usbredir_buffered_bulk_in_complete(USBRedirDevice *dev, |
700 |
USBPacket *p, uint8_t ep) |
701 |
{ |
702 |
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
|
703 |
dev->buffered_bulk_in_complete(dev, p, ep); |
704 |
DPRINTF("bulk-token-in ep %02X status %d len %d id %"PRIu64"\n", |
705 |
ep, p->status, p->actual_length, p->id); |
706 |
} |
707 |
|
708 |
static void usbredir_handle_buffered_bulk_in_data(USBRedirDevice *dev, |
709 |
USBPacket *p, uint8_t ep) |
710 |
{ |
711 |
/* Input bulk endpoint, buffered packet input */
|
712 |
if (!dev->endpoint[EP2I(ep)].bulk_receiving_started) {
|
713 |
int bpt;
|
714 |
struct usb_redir_start_bulk_receiving_header start = {
|
715 |
.endpoint = ep, |
716 |
.stream_id = 0,
|
717 |
.no_transfers = 5,
|
718 |
}; |
719 |
/* Round bytes_per_transfer up to a multiple of max_packet_size */
|
720 |
bpt = 512 + dev->endpoint[EP2I(ep)].max_packet_size - 1; |
721 |
bpt /= dev->endpoint[EP2I(ep)].max_packet_size; |
722 |
bpt *= dev->endpoint[EP2I(ep)].max_packet_size; |
723 |
start.bytes_per_transfer = bpt; |
724 |
/* No id, we look at the ep when receiving a status back */
|
725 |
usbredirparser_send_start_bulk_receiving(dev->parser, 0, &start);
|
726 |
usbredirparser_do_write(dev->parser); |
727 |
DPRINTF("bulk receiving started bytes/transfer %u count %d ep %02X\n",
|
728 |
start.bytes_per_transfer, start.no_transfers, ep); |
729 |
dev->endpoint[EP2I(ep)].bulk_receiving_started = 1;
|
730 |
/* We don't really want to drop bulk packets ever, but
|
731 |
having some upper limit to how much we buffer is good. */
|
732 |
dev->endpoint[EP2I(ep)].bufpq_target_size = 5000;
|
733 |
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
|
734 |
} |
735 |
|
736 |
if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
|
737 |
DPRINTF("bulk-token-in ep %02X, no bulkp\n", ep);
|
738 |
assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
|
739 |
dev->endpoint[EP2I(ep)].pending_async_packet = p; |
740 |
p->status = USB_RET_ASYNC; |
741 |
return;
|
742 |
} |
743 |
usbredir_buffered_bulk_in_complete(dev, p, ep); |
744 |
} |
745 |
|
746 |
static void usbredir_stop_bulk_receiving(USBRedirDevice *dev, uint8_t ep) |
747 |
{ |
748 |
struct usb_redir_stop_bulk_receiving_header stop_bulk = {
|
749 |
.endpoint = ep, |
750 |
.stream_id = 0,
|
751 |
}; |
752 |
if (dev->endpoint[EP2I(ep)].bulk_receiving_started) {
|
753 |
usbredirparser_send_stop_bulk_receiving(dev->parser, 0, &stop_bulk);
|
754 |
DPRINTF("bulk receiving stopped ep %02X\n", ep);
|
755 |
dev->endpoint[EP2I(ep)].bulk_receiving_started = 0;
|
756 |
} |
757 |
usbredir_free_bufpq(dev, ep); |
758 |
} |
759 |
|
760 |
static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, |
761 |
uint8_t ep) |
762 |
{ |
763 |
struct usb_redir_bulk_packet_header bulk_packet;
|
764 |
size_t size = usb_packet_size(p); |
765 |
const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; |
766 |
|
767 |
if (usbredir_already_in_flight(dev, p->id)) {
|
768 |
p->status = USB_RET_ASYNC; |
769 |
return;
|
770 |
} |
771 |
|
772 |
if (dev->endpoint[EP2I(ep)].bulk_receiving_enabled) {
|
773 |
if (size != 0 && (size % maxp) == 0) { |
774 |
usbredir_handle_buffered_bulk_in_data(dev, p, ep); |
775 |
return;
|
776 |
} |
777 |
WARNING("bulk recv invalid size %zd ep %02x, disabling\n", size, ep);
|
778 |
assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
|
779 |
usbredir_stop_bulk_receiving(dev, ep); |
780 |
dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0;
|
781 |
} |
782 |
|
783 |
DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id); |
784 |
|
785 |
bulk_packet.endpoint = ep; |
786 |
bulk_packet.length = size; |
787 |
bulk_packet.stream_id = 0;
|
788 |
bulk_packet.length_high = size >> 16;
|
789 |
assert(bulk_packet.length_high == 0 ||
|
790 |
usbredirparser_peer_has_cap(dev->parser, |
791 |
usb_redir_cap_32bits_bulk_length)); |
792 |
|
793 |
if (ep & USB_DIR_IN) {
|
794 |
usbredirparser_send_bulk_packet(dev->parser, p->id, |
795 |
&bulk_packet, NULL, 0); |
796 |
} else {
|
797 |
uint8_t buf[size]; |
798 |
usb_packet_copy(p, buf, size); |
799 |
usbredir_log_data(dev, "bulk data out:", buf, size);
|
800 |
usbredirparser_send_bulk_packet(dev->parser, p->id, |
801 |
&bulk_packet, buf, size); |
802 |
} |
803 |
usbredirparser_do_write(dev->parser); |
804 |
p->status = USB_RET_ASYNC; |
805 |
} |
806 |
|
807 |
static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev, |
808 |
USBPacket *p, uint8_t ep) |
809 |
{ |
810 |
/* Input interrupt endpoint, buffered packet input */
|
811 |
struct buf_packet *intp;
|
812 |
int status, len;
|
813 |
|
814 |
if (!dev->endpoint[EP2I(ep)].interrupt_started &&
|
815 |
!dev->endpoint[EP2I(ep)].interrupt_error) { |
816 |
struct usb_redir_start_interrupt_receiving_header start_int = {
|
817 |
.endpoint = ep, |
818 |
}; |
819 |
/* No id, we look at the ep when receiving a status back */
|
820 |
usbredirparser_send_start_interrupt_receiving(dev->parser, 0,
|
821 |
&start_int); |
822 |
usbredirparser_do_write(dev->parser); |
823 |
DPRINTF("interrupt recv started ep %02X\n", ep);
|
824 |
dev->endpoint[EP2I(ep)].interrupt_started = 1;
|
825 |
/* We don't really want to drop interrupt packets ever, but
|
826 |
having some upper limit to how much we buffer is good. */
|
827 |
dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
|
828 |
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
|
829 |
} |
830 |
|
831 |
intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); |
832 |
if (intp == NULL) { |
833 |
DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
|
834 |
/* Check interrupt_error for stream errors */
|
835 |
status = dev->endpoint[EP2I(ep)].interrupt_error; |
836 |
dev->endpoint[EP2I(ep)].interrupt_error = 0;
|
837 |
if (status) {
|
838 |
usbredir_handle_status(dev, p, status); |
839 |
} else {
|
840 |
p->status = USB_RET_NAK; |
841 |
} |
842 |
return;
|
843 |
} |
844 |
DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
|
845 |
intp->status, intp->len); |
846 |
|
847 |
status = intp->status; |
848 |
len = intp->len; |
849 |
if (len > p->iov.size) {
|
850 |
ERROR("received int data is larger then packet ep %02X\n", ep);
|
851 |
len = p->iov.size; |
852 |
status = usb_redir_babble; |
853 |
} |
854 |
usb_packet_copy(p, intp->data, len); |
855 |
bufp_free(dev, intp, ep); |
856 |
usbredir_handle_status(dev, p, status); |
857 |
} |
858 |
|
859 |
/*
|
860 |
* Handle interrupt out data, the usbredir protocol expects us to do this
|
861 |
* async, so that it can report back a completion status. But guests will
|
862 |
* expect immediate completion for an interrupt endpoint, and handling this
|
863 |
* async causes migration issues. So we report success directly, counting
|
864 |
* on the fact that output interrupt packets normally always succeed.
|
865 |
*/
|
866 |
static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev, |
867 |
USBPacket *p, uint8_t ep) |
868 |
{ |
869 |
struct usb_redir_interrupt_packet_header interrupt_packet;
|
870 |
uint8_t buf[p->iov.size]; |
871 |
|
872 |
DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, |
873 |
p->iov.size, p->id); |
874 |
|
875 |
interrupt_packet.endpoint = ep; |
876 |
interrupt_packet.length = p->iov.size; |
877 |
|
878 |
usb_packet_copy(p, buf, p->iov.size); |
879 |
usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size);
|
880 |
usbredirparser_send_interrupt_packet(dev->parser, p->id, |
881 |
&interrupt_packet, buf, p->iov.size); |
882 |
usbredirparser_do_write(dev->parser); |
883 |
} |
884 |
|
885 |
static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev, |
886 |
uint8_t ep) |
887 |
{ |
888 |
struct usb_redir_stop_interrupt_receiving_header stop_interrupt_recv = {
|
889 |
.endpoint = ep |
890 |
}; |
891 |
if (dev->endpoint[EP2I(ep)].interrupt_started) {
|
892 |
usbredirparser_send_stop_interrupt_receiving(dev->parser, 0,
|
893 |
&stop_interrupt_recv); |
894 |
DPRINTF("interrupt recv stopped ep %02X\n", ep);
|
895 |
dev->endpoint[EP2I(ep)].interrupt_started = 0;
|
896 |
} |
897 |
dev->endpoint[EP2I(ep)].interrupt_error = 0;
|
898 |
usbredir_free_bufpq(dev, ep); |
899 |
} |
900 |
|
901 |
static void usbredir_handle_data(USBDevice *udev, USBPacket *p) |
902 |
{ |
903 |
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); |
904 |
uint8_t ep; |
905 |
|
906 |
ep = p->ep->nr; |
907 |
if (p->pid == USB_TOKEN_IN) {
|
908 |
ep |= USB_DIR_IN; |
909 |
} |
910 |
|
911 |
switch (dev->endpoint[EP2I(ep)].type) {
|
912 |
case USB_ENDPOINT_XFER_CONTROL:
|
913 |
ERROR("handle_data called for control transfer on ep %02X\n", ep);
|
914 |
p->status = USB_RET_NAK; |
915 |
break;
|
916 |
case USB_ENDPOINT_XFER_BULK:
|
917 |
if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN &&
|
918 |
p->ep->pipeline) { |
919 |
p->status = USB_RET_ADD_TO_QUEUE; |
920 |
break;
|
921 |
} |
922 |
usbredir_handle_bulk_data(dev, p, ep); |
923 |
break;
|
924 |
case USB_ENDPOINT_XFER_ISOC:
|
925 |
usbredir_handle_iso_data(dev, p, ep); |
926 |
break;
|
927 |
case USB_ENDPOINT_XFER_INT:
|
928 |
if (ep & USB_DIR_IN) {
|
929 |
usbredir_handle_interrupt_in_data(dev, p, ep); |
930 |
} else {
|
931 |
usbredir_handle_interrupt_out_data(dev, p, ep); |
932 |
} |
933 |
break;
|
934 |
default:
|
935 |
ERROR("handle_data ep %02X has unknown type %d\n", ep,
|
936 |
dev->endpoint[EP2I(ep)].type); |
937 |
p->status = USB_RET_NAK; |
938 |
} |
939 |
} |
940 |
|
941 |
static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) |
942 |
{ |
943 |
if (ep->pid == USB_TOKEN_IN && ep->pipeline) {
|
944 |
usb_ep_combine_input_packets(ep); |
945 |
} |
946 |
} |
947 |
|
948 |
static void usbredir_stop_ep(USBRedirDevice *dev, int i) |
949 |
{ |
950 |
uint8_t ep = I2EP(i); |
951 |
|
952 |
switch (dev->endpoint[i].type) {
|
953 |
case USB_ENDPOINT_XFER_BULK:
|
954 |
if (ep & USB_DIR_IN) {
|
955 |
usbredir_stop_bulk_receiving(dev, ep); |
956 |
} |
957 |
break;
|
958 |
case USB_ENDPOINT_XFER_ISOC:
|
959 |
usbredir_stop_iso_stream(dev, ep); |
960 |
break;
|
961 |
case USB_ENDPOINT_XFER_INT:
|
962 |
if (ep & USB_DIR_IN) {
|
963 |
usbredir_stop_interrupt_receiving(dev, ep); |
964 |
} |
965 |
break;
|
966 |
} |
967 |
usbredir_free_bufpq(dev, ep); |
968 |
} |
969 |
|
970 |
static void usbredir_ep_stopped(USBDevice *udev, USBEndpoint *uep) |
971 |
{ |
972 |
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); |
973 |
|
974 |
usbredir_stop_ep(dev, USBEP2I(uep)); |
975 |
usbredirparser_do_write(dev->parser); |
976 |
} |
977 |
|
978 |
static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p, |
979 |
int config)
|
980 |
{ |
981 |
struct usb_redir_set_configuration_header set_config;
|
982 |
int i;
|
983 |
|
984 |
DPRINTF("set config %d id %"PRIu64"\n", config, p->id); |
985 |
|
986 |
for (i = 0; i < MAX_ENDPOINTS; i++) { |
987 |
usbredir_stop_ep(dev, i); |
988 |
} |
989 |
|
990 |
set_config.configuration = config; |
991 |
usbredirparser_send_set_configuration(dev->parser, p->id, &set_config); |
992 |
usbredirparser_do_write(dev->parser); |
993 |
p->status = USB_RET_ASYNC; |
994 |
} |
995 |
|
996 |
static void usbredir_get_config(USBRedirDevice *dev, USBPacket *p) |
997 |
{ |
998 |
DPRINTF("get config id %"PRIu64"\n", p->id); |
999 |
|
1000 |
usbredirparser_send_get_configuration(dev->parser, p->id); |
1001 |
usbredirparser_do_write(dev->parser); |
1002 |
p->status = USB_RET_ASYNC; |
1003 |
} |
1004 |
|
1005 |
static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, |
1006 |
int interface, int alt) |
1007 |
{ |
1008 |
struct usb_redir_set_alt_setting_header set_alt;
|
1009 |
int i;
|
1010 |
|
1011 |
DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id); |
1012 |
|
1013 |
for (i = 0; i < MAX_ENDPOINTS; i++) { |
1014 |
if (dev->endpoint[i].interface == interface) {
|
1015 |
usbredir_stop_ep(dev, i); |
1016 |
} |
1017 |
} |
1018 |
|
1019 |
set_alt.interface = interface; |
1020 |
set_alt.alt = alt; |
1021 |
usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt); |
1022 |
usbredirparser_do_write(dev->parser); |
1023 |
p->status = USB_RET_ASYNC; |
1024 |
} |
1025 |
|
1026 |
static void usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, |
1027 |
int interface)
|
1028 |
{ |
1029 |
struct usb_redir_get_alt_setting_header get_alt;
|
1030 |
|
1031 |
DPRINTF("get interface %d id %"PRIu64"\n", interface, p->id); |
1032 |
|
1033 |
get_alt.interface = interface; |
1034 |
usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt); |
1035 |
usbredirparser_do_write(dev->parser); |
1036 |
p->status = USB_RET_ASYNC; |
1037 |
} |
1038 |
|
1039 |
static void usbredir_handle_control(USBDevice *udev, USBPacket *p, |
1040 |
int request, int value, int index, int length, uint8_t *data) |
1041 |
{ |
1042 |
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); |
1043 |
struct usb_redir_control_packet_header control_packet;
|
1044 |
|
1045 |
if (usbredir_already_in_flight(dev, p->id)) {
|
1046 |
p->status = USB_RET_ASYNC; |
1047 |
return;
|
1048 |
} |
1049 |
|
1050 |
/* Special cases for certain standard device requests */
|
1051 |
switch (request) {
|
1052 |
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
1053 |
DPRINTF("set address %d\n", value);
|
1054 |
dev->dev.addr = value; |
1055 |
return;
|
1056 |
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
1057 |
usbredir_set_config(dev, p, value & 0xff);
|
1058 |
return;
|
1059 |
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
|
1060 |
usbredir_get_config(dev, p); |
1061 |
return;
|
1062 |
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
|
1063 |
usbredir_set_interface(dev, p, index, value); |
1064 |
return;
|
1065 |
case InterfaceRequest | USB_REQ_GET_INTERFACE:
|
1066 |
usbredir_get_interface(dev, p, index); |
1067 |
return;
|
1068 |
} |
1069 |
|
1070 |
/* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */
|
1071 |
DPRINTF( |
1072 |
"ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n", |
1073 |
request >> 8, request & 0xff, value, index, length, p->id); |
1074 |
|
1075 |
control_packet.request = request & 0xFF;
|
1076 |
control_packet.requesttype = request >> 8;
|
1077 |
control_packet.endpoint = control_packet.requesttype & USB_DIR_IN; |
1078 |
control_packet.value = value; |
1079 |
control_packet.index = index; |
1080 |
control_packet.length = length; |
1081 |
|
1082 |
if (control_packet.requesttype & USB_DIR_IN) {
|
1083 |
usbredirparser_send_control_packet(dev->parser, p->id, |
1084 |
&control_packet, NULL, 0); |
1085 |
} else {
|
1086 |
usbredir_log_data(dev, "ctrl data out:", data, length);
|
1087 |
usbredirparser_send_control_packet(dev->parser, p->id, |
1088 |
&control_packet, data, length); |
1089 |
} |
1090 |
usbredirparser_do_write(dev->parser); |
1091 |
p->status = USB_RET_ASYNC; |
1092 |
} |
1093 |
|
1094 |
/*
|
1095 |
* Close events can be triggered by usbredirparser_do_write which gets called
|
1096 |
* from within the USBDevice data / control packet callbacks and doing a
|
1097 |
* usb_detach from within these callbacks is not a good idea.
|
1098 |
*
|
1099 |
* So we use a bh handler to take care of close events.
|
1100 |
*/
|
1101 |
static void usbredir_chardev_close_bh(void *opaque) |
1102 |
{ |
1103 |
USBRedirDevice *dev = opaque; |
1104 |
|
1105 |
usbredir_device_disconnect(dev); |
1106 |
|
1107 |
if (dev->parser) {
|
1108 |
DPRINTF("destroying usbredirparser\n");
|
1109 |
usbredirparser_destroy(dev->parser); |
1110 |
dev->parser = NULL;
|
1111 |
} |
1112 |
if (dev->watch) {
|
1113 |
g_source_remove(dev->watch); |
1114 |
dev->watch = 0;
|
1115 |
} |
1116 |
} |
1117 |
|
1118 |
static void usbredir_create_parser(USBRedirDevice *dev) |
1119 |
{ |
1120 |
uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
|
1121 |
int flags = 0; |
1122 |
|
1123 |
DPRINTF("creating usbredirparser\n");
|
1124 |
|
1125 |
dev->parser = qemu_oom_check(usbredirparser_create()); |
1126 |
dev->parser->priv = dev; |
1127 |
dev->parser->log_func = usbredir_log; |
1128 |
dev->parser->read_func = usbredir_read; |
1129 |
dev->parser->write_func = usbredir_write; |
1130 |
dev->parser->hello_func = usbredir_hello; |
1131 |
dev->parser->device_connect_func = usbredir_device_connect; |
1132 |
dev->parser->device_disconnect_func = usbredir_device_disconnect; |
1133 |
dev->parser->interface_info_func = usbredir_interface_info; |
1134 |
dev->parser->ep_info_func = usbredir_ep_info; |
1135 |
dev->parser->configuration_status_func = usbredir_configuration_status; |
1136 |
dev->parser->alt_setting_status_func = usbredir_alt_setting_status; |
1137 |
dev->parser->iso_stream_status_func = usbredir_iso_stream_status; |
1138 |
dev->parser->interrupt_receiving_status_func = |
1139 |
usbredir_interrupt_receiving_status; |
1140 |
dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; |
1141 |
dev->parser->bulk_receiving_status_func = usbredir_bulk_receiving_status; |
1142 |
dev->parser->control_packet_func = usbredir_control_packet; |
1143 |
dev->parser->bulk_packet_func = usbredir_bulk_packet; |
1144 |
dev->parser->iso_packet_func = usbredir_iso_packet; |
1145 |
dev->parser->interrupt_packet_func = usbredir_interrupt_packet; |
1146 |
dev->parser->buffered_bulk_packet_func = usbredir_buffered_bulk_packet; |
1147 |
dev->read_buf = NULL;
|
1148 |
dev->read_buf_size = 0;
|
1149 |
|
1150 |
usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); |
1151 |
usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); |
1152 |
usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); |
1153 |
usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); |
1154 |
usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length); |
1155 |
usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving); |
1156 |
|
1157 |
if (runstate_check(RUN_STATE_INMIGRATE)) {
|
1158 |
flags |= usbredirparser_fl_no_hello; |
1159 |
} |
1160 |
usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, |
1161 |
flags); |
1162 |
usbredirparser_do_write(dev->parser); |
1163 |
} |
1164 |
|
1165 |
static void usbredir_reject_device(USBRedirDevice *dev) |
1166 |
{ |
1167 |
usbredir_device_disconnect(dev); |
1168 |
if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
|
1169 |
usbredirparser_send_filter_reject(dev->parser); |
1170 |
usbredirparser_do_write(dev->parser); |
1171 |
} |
1172 |
} |
1173 |
|
1174 |
static void usbredir_do_attach(void *opaque) |
1175 |
{ |
1176 |
USBRedirDevice *dev = opaque; |
1177 |
|
1178 |
/* In order to work properly with XHCI controllers we need these caps */
|
1179 |
if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !(
|
1180 |
usbredirparser_peer_has_cap(dev->parser, |
1181 |
usb_redir_cap_ep_info_max_packet_size) && |
1182 |
usbredirparser_peer_has_cap(dev->parser, |
1183 |
usb_redir_cap_32bits_bulk_length) && |
1184 |
usbredirparser_peer_has_cap(dev->parser, |
1185 |
usb_redir_cap_64bits_ids))) { |
1186 |
ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n");
|
1187 |
usbredir_reject_device(dev); |
1188 |
return;
|
1189 |
} |
1190 |
|
1191 |
if (usb_device_attach(&dev->dev) != 0) { |
1192 |
WARNING("rejecting device due to speed mismatch\n");
|
1193 |
usbredir_reject_device(dev); |
1194 |
} |
1195 |
} |
1196 |
|
1197 |
/*
|
1198 |
* chardev callbacks
|
1199 |
*/
|
1200 |
|
1201 |
static int usbredir_chardev_can_read(void *opaque) |
1202 |
{ |
1203 |
USBRedirDevice *dev = opaque; |
1204 |
|
1205 |
if (!dev->parser) {
|
1206 |
WARNING("chardev_can_read called on non open chardev!\n");
|
1207 |
return 0; |
1208 |
} |
1209 |
|
1210 |
/* Don't read new data from the chardev until our state is fully synced */
|
1211 |
if (!runstate_check(RUN_STATE_RUNNING)) {
|
1212 |
return 0; |
1213 |
} |
1214 |
|
1215 |
/* usbredir_parser_do_read will consume *all* data we give it */
|
1216 |
return 1024 * 1024; |
1217 |
} |
1218 |
|
1219 |
static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size) |
1220 |
{ |
1221 |
USBRedirDevice *dev = opaque; |
1222 |
|
1223 |
/* No recursion allowed! */
|
1224 |
assert(dev->read_buf == NULL);
|
1225 |
|
1226 |
dev->read_buf = buf; |
1227 |
dev->read_buf_size = size; |
1228 |
|
1229 |
usbredirparser_do_read(dev->parser); |
1230 |
/* Send any acks, etc. which may be queued now */
|
1231 |
usbredirparser_do_write(dev->parser); |
1232 |
} |
1233 |
|
1234 |
static void usbredir_chardev_event(void *opaque, int event) |
1235 |
{ |
1236 |
USBRedirDevice *dev = opaque; |
1237 |
|
1238 |
switch (event) {
|
1239 |
case CHR_EVENT_OPENED:
|
1240 |
DPRINTF("chardev open\n");
|
1241 |
/* Make sure any pending closes are handled (no-op if none pending) */
|
1242 |
usbredir_chardev_close_bh(dev); |
1243 |
qemu_bh_cancel(dev->chardev_close_bh); |
1244 |
usbredir_create_parser(dev); |
1245 |
break;
|
1246 |
case CHR_EVENT_CLOSED:
|
1247 |
DPRINTF("chardev close\n");
|
1248 |
qemu_bh_schedule(dev->chardev_close_bh); |
1249 |
break;
|
1250 |
} |
1251 |
} |
1252 |
|
1253 |
/*
|
1254 |
* init + destroy
|
1255 |
*/
|
1256 |
|
1257 |
static void usbredir_vm_state_change(void *priv, int running, RunState state) |
1258 |
{ |
1259 |
USBRedirDevice *dev = priv; |
1260 |
|
1261 |
if (state == RUN_STATE_RUNNING && dev->parser != NULL) { |
1262 |
usbredirparser_do_write(dev->parser); /* Flush any pending writes */
|
1263 |
} |
1264 |
} |
1265 |
|
1266 |
static void usbredir_init_endpoints(USBRedirDevice *dev) |
1267 |
{ |
1268 |
int i;
|
1269 |
|
1270 |
usb_ep_init(&dev->dev); |
1271 |
memset(dev->endpoint, 0, sizeof(dev->endpoint)); |
1272 |
for (i = 0; i < MAX_ENDPOINTS; i++) { |
1273 |
dev->endpoint[i].dev = dev; |
1274 |
QTAILQ_INIT(&dev->endpoint[i].bufpq); |
1275 |
} |
1276 |
} |
1277 |
|
1278 |
static int usbredir_initfn(USBDevice *udev) |
1279 |
{ |
1280 |
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); |
1281 |
int i;
|
1282 |
|
1283 |
if (dev->cs == NULL) { |
1284 |
qerror_report(QERR_MISSING_PARAMETER, "chardev");
|
1285 |
return -1; |
1286 |
} |
1287 |
|
1288 |
if (dev->filter_str) {
|
1289 |
i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|", |
1290 |
&dev->filter_rules, |
1291 |
&dev->filter_rules_count); |
1292 |
if (i) {
|
1293 |
qerror_report(QERR_INVALID_PARAMETER_VALUE, "filter",
|
1294 |
"a usb device filter string");
|
1295 |
return -1; |
1296 |
} |
1297 |
} |
1298 |
|
1299 |
dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); |
1300 |
dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); |
1301 |
|
1302 |
packet_id_queue_init(&dev->cancelled, dev, "cancelled");
|
1303 |
packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight");
|
1304 |
usbredir_init_endpoints(dev); |
1305 |
|
1306 |
/* We'll do the attach once we receive the speed from the usb-host */
|
1307 |
udev->auto_attach = 0;
|
1308 |
|
1309 |
/* Will be cleared during setup when we find conflicts */
|
1310 |
dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH; |
1311 |
|
1312 |
/* Let the backend know we are ready */
|
1313 |
qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, |
1314 |
usbredir_chardev_read, usbredir_chardev_event, dev); |
1315 |
|
1316 |
qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); |
1317 |
add_boot_device_path(dev->bootindex, &udev->qdev, NULL);
|
1318 |
return 0; |
1319 |
} |
1320 |
|
1321 |
static void usbredir_cleanup_device_queues(USBRedirDevice *dev) |
1322 |
{ |
1323 |
int i;
|
1324 |
|
1325 |
packet_id_queue_empty(&dev->cancelled); |
1326 |
packet_id_queue_empty(&dev->already_in_flight); |
1327 |
for (i = 0; i < MAX_ENDPOINTS; i++) { |
1328 |
usbredir_free_bufpq(dev, I2EP(i)); |
1329 |
} |
1330 |
} |
1331 |
|
1332 |
static void usbredir_handle_destroy(USBDevice *udev) |
1333 |
{ |
1334 |
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); |
1335 |
|
1336 |
qemu_chr_delete(dev->cs); |
1337 |
/* Note must be done after qemu_chr_close, as that causes a close event */
|
1338 |
qemu_bh_delete(dev->chardev_close_bh); |
1339 |
|
1340 |
qemu_del_timer(dev->attach_timer); |
1341 |
qemu_free_timer(dev->attach_timer); |
1342 |
|
1343 |
usbredir_cleanup_device_queues(dev); |
1344 |
|
1345 |
if (dev->parser) {
|
1346 |
usbredirparser_destroy(dev->parser); |
1347 |
} |
1348 |
if (dev->watch) {
|
1349 |
g_source_remove(dev->watch); |
1350 |
} |
1351 |
|
1352 |
free(dev->filter_rules); |
1353 |
} |
1354 |
|
1355 |
static int usbredir_check_filter(USBRedirDevice *dev) |
1356 |
{ |
1357 |
if (dev->interface_info.interface_count == NO_INTERFACE_INFO) {
|
1358 |
ERROR("No interface info for device\n");
|
1359 |
goto error;
|
1360 |
} |
1361 |
|
1362 |
if (dev->filter_rules) {
|
1363 |
if (!usbredirparser_peer_has_cap(dev->parser,
|
1364 |
usb_redir_cap_connect_device_version)) { |
1365 |
ERROR("Device filter specified and peer does not have the "
|
1366 |
"connect_device_version capability\n");
|
1367 |
goto error;
|
1368 |
} |
1369 |
|
1370 |
if (usbredirfilter_check(
|
1371 |
dev->filter_rules, |
1372 |
dev->filter_rules_count, |
1373 |
dev->device_info.device_class, |
1374 |
dev->device_info.device_subclass, |
1375 |
dev->device_info.device_protocol, |
1376 |
dev->interface_info.interface_class, |
1377 |
dev->interface_info.interface_subclass, |
1378 |
dev->interface_info.interface_protocol, |
1379 |
dev->interface_info.interface_count, |
1380 |
dev->device_info.vendor_id, |
1381 |
dev->device_info.product_id, |
1382 |
dev->device_info.device_version_bcd, |
1383 |
0) != 0) { |
1384 |
goto error;
|
1385 |
} |
1386 |
} |
1387 |
|
1388 |
return 0; |
1389 |
|
1390 |
error:
|
1391 |
usbredir_reject_device(dev); |
1392 |
return -1; |
1393 |
} |
1394 |
|
1395 |
static void usbredir_check_bulk_receiving(USBRedirDevice *dev) |
1396 |
{ |
1397 |
int i, j, quirks;
|
1398 |
|
1399 |
if (!usbredirparser_peer_has_cap(dev->parser,
|
1400 |
usb_redir_cap_bulk_receiving)) { |
1401 |
return;
|
1402 |
} |
1403 |
|
1404 |
for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) {
|
1405 |
dev->endpoint[i].bulk_receiving_enabled = 0;
|
1406 |
} |
1407 |
for (i = 0; i < dev->interface_info.interface_count; i++) { |
1408 |
quirks = usb_get_quirks(dev->device_info.vendor_id, |
1409 |
dev->device_info.product_id, |
1410 |
dev->interface_info.interface_class[i], |
1411 |
dev->interface_info.interface_subclass[i], |
1412 |
dev->interface_info.interface_protocol[i]); |
1413 |
if (!(quirks & USB_QUIRK_BUFFER_BULK_IN)) {
|
1414 |
continue;
|
1415 |
} |
1416 |
if (quirks & USB_QUIRK_IS_FTDI) {
|
1417 |
dev->buffered_bulk_in_complete = |
1418 |
usbredir_buffered_bulk_in_complete_ftdi; |
1419 |
} else {
|
1420 |
dev->buffered_bulk_in_complete = |
1421 |
usbredir_buffered_bulk_in_complete_raw; |
1422 |
} |
1423 |
|
1424 |
for (j = EP2I(USB_DIR_IN); j < MAX_ENDPOINTS; j++) {
|
1425 |
if (dev->endpoint[j].interface ==
|
1426 |
dev->interface_info.interface[i] && |
1427 |
dev->endpoint[j].type == USB_ENDPOINT_XFER_BULK && |
1428 |
dev->endpoint[j].max_packet_size != 0) {
|
1429 |
dev->endpoint[j].bulk_receiving_enabled = 1;
|
1430 |
/*
|
1431 |
* With buffering pipelining is not necessary. Also packet
|
1432 |
* combining and bulk in buffering don't play nice together!
|
1433 |
*/
|
1434 |
I2USBEP(dev, j)->pipeline = false;
|
1435 |
break; /* Only buffer for the first ep of each intf */ |
1436 |
} |
1437 |
} |
1438 |
} |
1439 |
} |
1440 |
|
1441 |
/*
|
1442 |
* usbredirparser packet complete callbacks
|
1443 |
*/
|
1444 |
|
1445 |
static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p, |
1446 |
int status)
|
1447 |
{ |
1448 |
switch (status) {
|
1449 |
case usb_redir_success:
|
1450 |
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
|
1451 |
break;
|
1452 |
case usb_redir_stall:
|
1453 |
p->status = USB_RET_STALL; |
1454 |
break;
|
1455 |
case usb_redir_cancelled:
|
1456 |
/*
|
1457 |
* When the usbredir-host unredirects a device, it will report a status
|
1458 |
* of cancelled for all pending packets, followed by a disconnect msg.
|
1459 |
*/
|
1460 |
p->status = USB_RET_IOERROR; |
1461 |
break;
|
1462 |
case usb_redir_inval:
|
1463 |
WARNING("got invalid param error from usb-host?\n");
|
1464 |
p->status = USB_RET_IOERROR; |
1465 |
break;
|
1466 |
case usb_redir_babble:
|
1467 |
p->status = USB_RET_BABBLE; |
1468 |
break;
|
1469 |
case usb_redir_ioerror:
|
1470 |
case usb_redir_timeout:
|
1471 |
default:
|
1472 |
p->status = USB_RET_IOERROR; |
1473 |
} |
1474 |
} |
1475 |
|
1476 |
static void usbredir_hello(void *priv, struct usb_redir_hello_header *h) |
1477 |
{ |
1478 |
USBRedirDevice *dev = priv; |
1479 |
|
1480 |
/* Try to send the filter info now that we've the usb-host's caps */
|
1481 |
if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter) &&
|
1482 |
dev->filter_rules) { |
1483 |
usbredirparser_send_filter_filter(dev->parser, dev->filter_rules, |
1484 |
dev->filter_rules_count); |
1485 |
usbredirparser_do_write(dev->parser); |
1486 |
} |
1487 |
} |
1488 |
|
1489 |
static void usbredir_device_connect(void *priv, |
1490 |
struct usb_redir_device_connect_header *device_connect)
|
1491 |
{ |
1492 |
USBRedirDevice *dev = priv; |
1493 |
const char *speed; |
1494 |
|
1495 |
if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
|
1496 |
ERROR("Received device connect while already connected\n");
|
1497 |
return;
|
1498 |
} |
1499 |
|
1500 |
switch (device_connect->speed) {
|
1501 |
case usb_redir_speed_low:
|
1502 |
speed = "low speed";
|
1503 |
dev->dev.speed = USB_SPEED_LOW; |
1504 |
dev->compatible_speedmask &= ~USB_SPEED_MASK_FULL; |
1505 |
dev->compatible_speedmask &= ~USB_SPEED_MASK_HIGH; |
1506 |
break;
|
1507 |
case usb_redir_speed_full:
|
1508 |
speed = "full speed";
|
1509 |
dev->dev.speed = USB_SPEED_FULL; |
1510 |
dev->compatible_speedmask &= ~USB_SPEED_MASK_HIGH; |
1511 |
break;
|
1512 |
case usb_redir_speed_high:
|
1513 |
speed = "high speed";
|
1514 |
dev->dev.speed = USB_SPEED_HIGH; |
1515 |
break;
|
1516 |
case usb_redir_speed_super:
|
1517 |
speed = "super speed";
|
1518 |
dev->dev.speed = USB_SPEED_SUPER; |
1519 |
break;
|
1520 |
default:
|
1521 |
speed = "unknown speed";
|
1522 |
dev->dev.speed = USB_SPEED_FULL; |
1523 |
} |
1524 |
|
1525 |
if (usbredirparser_peer_has_cap(dev->parser,
|
1526 |
usb_redir_cap_connect_device_version)) { |
1527 |
INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
|
1528 |
speed, device_connect->vendor_id, device_connect->product_id, |
1529 |
((device_connect->device_version_bcd & 0xf000) >> 12) * 10 + |
1530 |
((device_connect->device_version_bcd & 0x0f00) >> 8), |
1531 |
((device_connect->device_version_bcd & 0x00f0) >> 4) * 10 + |
1532 |
((device_connect->device_version_bcd & 0x000f) >> 0), |
1533 |
device_connect->device_class); |
1534 |
} else {
|
1535 |
INFO("attaching %s device %04x:%04x class %02x\n", speed,
|
1536 |
device_connect->vendor_id, device_connect->product_id, |
1537 |
device_connect->device_class); |
1538 |
} |
1539 |
|
1540 |
dev->dev.speedmask = (1 << dev->dev.speed) | dev->compatible_speedmask;
|
1541 |
dev->device_info = *device_connect; |
1542 |
|
1543 |
if (usbredir_check_filter(dev)) {
|
1544 |
WARNING("Device %04x:%04x rejected by device filter, not attaching\n",
|
1545 |
device_connect->vendor_id, device_connect->product_id); |
1546 |
return;
|
1547 |
} |
1548 |
|
1549 |
usbredir_check_bulk_receiving(dev); |
1550 |
qemu_mod_timer(dev->attach_timer, dev->next_attach_time); |
1551 |
} |
1552 |
|
1553 |
static void usbredir_device_disconnect(void *priv) |
1554 |
{ |
1555 |
USBRedirDevice *dev = priv; |
1556 |
|
1557 |
/* Stop any pending attaches */
|
1558 |
qemu_del_timer(dev->attach_timer); |
1559 |
|
1560 |
if (dev->dev.attached) {
|
1561 |
DPRINTF("detaching device\n");
|
1562 |
usb_device_detach(&dev->dev); |
1563 |
/*
|
1564 |
* Delay next usb device attach to give the guest a chance to see
|
1565 |
* see the detach / attach in case of quick close / open succession
|
1566 |
*/
|
1567 |
dev->next_attach_time = qemu_get_clock_ms(vm_clock) + 200;
|
1568 |
} |
1569 |
|
1570 |
/* Reset state so that the next dev connected starts with a clean slate */
|
1571 |
usbredir_cleanup_device_queues(dev); |
1572 |
usbredir_init_endpoints(dev); |
1573 |
dev->interface_info.interface_count = NO_INTERFACE_INFO; |
1574 |
dev->dev.addr = 0;
|
1575 |
dev->dev.speed = 0;
|
1576 |
dev->compatible_speedmask = USB_SPEED_MASK_FULL | USB_SPEED_MASK_HIGH; |
1577 |
} |
1578 |
|
1579 |
static void usbredir_interface_info(void *priv, |
1580 |
struct usb_redir_interface_info_header *interface_info)
|
1581 |
{ |
1582 |
USBRedirDevice *dev = priv; |
1583 |
|
1584 |
dev->interface_info = *interface_info; |
1585 |
|
1586 |
/*
|
1587 |
* If we receive interface info after the device has already been
|
1588 |
* connected (ie on a set_config), re-check interface dependent things.
|
1589 |
*/
|
1590 |
if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
|
1591 |
usbredir_check_bulk_receiving(dev); |
1592 |
if (usbredir_check_filter(dev)) {
|
1593 |
ERROR("Device no longer matches filter after interface info "
|
1594 |
"change, disconnecting!\n");
|
1595 |
} |
1596 |
} |
1597 |
} |
1598 |
|
1599 |
static void usbredir_mark_speed_incompatible(USBRedirDevice *dev, int speed) |
1600 |
{ |
1601 |
dev->compatible_speedmask &= ~(1 << speed);
|
1602 |
dev->dev.speedmask = (1 << dev->dev.speed) | dev->compatible_speedmask;
|
1603 |
} |
1604 |
|
1605 |
static void usbredir_set_pipeline(USBRedirDevice *dev, struct USBEndpoint *uep) |
1606 |
{ |
1607 |
if (uep->type != USB_ENDPOINT_XFER_BULK) {
|
1608 |
return;
|
1609 |
} |
1610 |
if (uep->pid == USB_TOKEN_OUT) {
|
1611 |
uep->pipeline = true;
|
1612 |
} |
1613 |
if (uep->pid == USB_TOKEN_IN && uep->max_packet_size != 0 && |
1614 |
usbredirparser_peer_has_cap(dev->parser, |
1615 |
usb_redir_cap_32bits_bulk_length)) { |
1616 |
uep->pipeline = true;
|
1617 |
} |
1618 |
} |
1619 |
|
1620 |
static void usbredir_setup_usb_eps(USBRedirDevice *dev) |
1621 |
{ |
1622 |
struct USBEndpoint *usb_ep;
|
1623 |
int i;
|
1624 |
|
1625 |
for (i = 0; i < MAX_ENDPOINTS; i++) { |
1626 |
usb_ep = I2USBEP(dev, i); |
1627 |
usb_ep->type = dev->endpoint[i].type; |
1628 |
usb_ep->ifnum = dev->endpoint[i].interface; |
1629 |
usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; |
1630 |
usbredir_set_pipeline(dev, usb_ep); |
1631 |
} |
1632 |
} |
1633 |
|
1634 |
static void usbredir_ep_info(void *priv, |
1635 |
struct usb_redir_ep_info_header *ep_info)
|
1636 |
{ |
1637 |
USBRedirDevice *dev = priv; |
1638 |
int i;
|
1639 |
|
1640 |
for (i = 0; i < MAX_ENDPOINTS; i++) { |
1641 |
dev->endpoint[i].type = ep_info->type[i]; |
1642 |
dev->endpoint[i].interval = ep_info->interval[i]; |
1643 |
dev->endpoint[i].interface = ep_info->interface[i]; |
1644 |
if (usbredirparser_peer_has_cap(dev->parser,
|
1645 |
usb_redir_cap_ep_info_max_packet_size)) { |
1646 |
dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i]; |
1647 |
} |
1648 |
switch (dev->endpoint[i].type) {
|
1649 |
case usb_redir_type_invalid:
|
1650 |
break;
|
1651 |
case usb_redir_type_iso:
|
1652 |
usbredir_mark_speed_incompatible(dev, USB_SPEED_FULL); |
1653 |
usbredir_mark_speed_incompatible(dev, USB_SPEED_HIGH); |
1654 |
/* Fall through */
|
1655 |
case usb_redir_type_interrupt:
|
1656 |
if (!usbredirparser_peer_has_cap(dev->parser,
|
1657 |
usb_redir_cap_ep_info_max_packet_size) || |
1658 |
ep_info->max_packet_size[i] > 64) {
|
1659 |
usbredir_mark_speed_incompatible(dev, USB_SPEED_FULL); |
1660 |
} |
1661 |
if (!usbredirparser_peer_has_cap(dev->parser,
|
1662 |
usb_redir_cap_ep_info_max_packet_size) || |
1663 |
ep_info->max_packet_size[i] > 1024) {
|
1664 |
usbredir_mark_speed_incompatible(dev, USB_SPEED_HIGH); |
1665 |
} |
1666 |
if (dev->endpoint[i].interval == 0) { |
1667 |
ERROR("Received 0 interval for isoc or irq endpoint\n");
|
1668 |
usbredir_reject_device(dev); |
1669 |
return;
|
1670 |
} |
1671 |
/* Fall through */
|
1672 |
case usb_redir_type_control:
|
1673 |
case usb_redir_type_bulk:
|
1674 |
DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
|
1675 |
dev->endpoint[i].type, dev->endpoint[i].interface); |
1676 |
break;
|
1677 |
default:
|
1678 |
ERROR("Received invalid endpoint type\n");
|
1679 |
usbredir_reject_device(dev); |
1680 |
return;
|
1681 |
} |
1682 |
} |
1683 |
/* The new ep info may have caused a speed incompatibility, recheck */
|
1684 |
if (dev->dev.attached &&
|
1685 |
!(dev->dev.port->speedmask & dev->dev.speedmask)) { |
1686 |
ERROR("Device no longer matches speed after endpoint info change, "
|
1687 |
"disconnecting!\n");
|
1688 |
usbredir_reject_device(dev); |
1689 |
return;
|
1690 |
} |
1691 |
usbredir_setup_usb_eps(dev); |
1692 |
usbredir_check_bulk_receiving(dev); |
1693 |
} |
1694 |
|
1695 |
static void usbredir_configuration_status(void *priv, uint64_t id, |
1696 |
struct usb_redir_configuration_status_header *config_status)
|
1697 |
{ |
1698 |
USBRedirDevice *dev = priv; |
1699 |
USBPacket *p; |
1700 |
|
1701 |
DPRINTF("set config status %d config %d id %"PRIu64"\n", |
1702 |
config_status->status, config_status->configuration, id); |
1703 |
|
1704 |
p = usbredir_find_packet_by_id(dev, 0, id);
|
1705 |
if (p) {
|
1706 |
if (dev->dev.setup_buf[0] & USB_DIR_IN) { |
1707 |
dev->dev.data_buf[0] = config_status->configuration;
|
1708 |
p->actual_length = 1;
|
1709 |
} |
1710 |
usbredir_handle_status(dev, p, config_status->status); |
1711 |
usb_generic_async_ctrl_complete(&dev->dev, p); |
1712 |
} |
1713 |
} |
1714 |
|
1715 |
static void usbredir_alt_setting_status(void *priv, uint64_t id, |
1716 |
struct usb_redir_alt_setting_status_header *alt_setting_status)
|
1717 |
{ |
1718 |
USBRedirDevice *dev = priv; |
1719 |
USBPacket *p; |
1720 |
|
1721 |
DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n", |
1722 |
alt_setting_status->status, alt_setting_status->interface, |
1723 |
alt_setting_status->alt, id); |
1724 |
|
1725 |
p = usbredir_find_packet_by_id(dev, 0, id);
|
1726 |
if (p) {
|
1727 |
if (dev->dev.setup_buf[0] & USB_DIR_IN) { |
1728 |
dev->dev.data_buf[0] = alt_setting_status->alt;
|
1729 |
p->actual_length = 1;
|
1730 |
} |
1731 |
usbredir_handle_status(dev, p, alt_setting_status->status); |
1732 |
usb_generic_async_ctrl_complete(&dev->dev, p); |
1733 |
} |
1734 |
} |
1735 |
|
1736 |
static void usbredir_iso_stream_status(void *priv, uint64_t id, |
1737 |
struct usb_redir_iso_stream_status_header *iso_stream_status)
|
1738 |
{ |
1739 |
USBRedirDevice *dev = priv; |
1740 |
uint8_t ep = iso_stream_status->endpoint; |
1741 |
|
1742 |
DPRINTF("iso status %d ep %02X id %"PRIu64"\n", iso_stream_status->status, |
1743 |
ep, id); |
1744 |
|
1745 |
if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) {
|
1746 |
return;
|
1747 |
} |
1748 |
|
1749 |
dev->endpoint[EP2I(ep)].iso_error = iso_stream_status->status; |
1750 |
if (iso_stream_status->status == usb_redir_stall) {
|
1751 |
DPRINTF("iso stream stopped by peer ep %02X\n", ep);
|
1752 |
dev->endpoint[EP2I(ep)].iso_started = 0;
|
1753 |
} |
1754 |
} |
1755 |
|
1756 |
static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, |
1757 |
struct usb_redir_interrupt_receiving_status_header
|
1758 |
*interrupt_receiving_status) |
1759 |
{ |
1760 |
USBRedirDevice *dev = priv; |
1761 |
uint8_t ep = interrupt_receiving_status->endpoint; |
1762 |
|
1763 |
DPRINTF("interrupt recv status %d ep %02X id %"PRIu64"\n", |
1764 |
interrupt_receiving_status->status, ep, id); |
1765 |
|
1766 |
if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) {
|
1767 |
return;
|
1768 |
} |
1769 |
|
1770 |
dev->endpoint[EP2I(ep)].interrupt_error = |
1771 |
interrupt_receiving_status->status; |
1772 |
if (interrupt_receiving_status->status == usb_redir_stall) {
|
1773 |
DPRINTF("interrupt receiving stopped by peer ep %02X\n", ep);
|
1774 |
dev->endpoint[EP2I(ep)].interrupt_started = 0;
|
1775 |
} |
1776 |
} |
1777 |
|
1778 |
static void usbredir_bulk_streams_status(void *priv, uint64_t id, |
1779 |
struct usb_redir_bulk_streams_status_header *bulk_streams_status)
|
1780 |
{ |
1781 |
} |
1782 |
|
1783 |
static void usbredir_bulk_receiving_status(void *priv, uint64_t id, |
1784 |
struct usb_redir_bulk_receiving_status_header *bulk_receiving_status)
|
1785 |
{ |
1786 |
USBRedirDevice *dev = priv; |
1787 |
uint8_t ep = bulk_receiving_status->endpoint; |
1788 |
|
1789 |
DPRINTF("bulk recv status %d ep %02X id %"PRIu64"\n", |
1790 |
bulk_receiving_status->status, ep, id); |
1791 |
|
1792 |
if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].bulk_receiving_started) {
|
1793 |
return;
|
1794 |
} |
1795 |
|
1796 |
if (bulk_receiving_status->status == usb_redir_stall) {
|
1797 |
DPRINTF("bulk receiving stopped by peer ep %02X\n", ep);
|
1798 |
dev->endpoint[EP2I(ep)].bulk_receiving_started = 0;
|
1799 |
} |
1800 |
} |
1801 |
|
1802 |
static void usbredir_control_packet(void *priv, uint64_t id, |
1803 |
struct usb_redir_control_packet_header *control_packet,
|
1804 |
uint8_t *data, int data_len)
|
1805 |
{ |
1806 |
USBRedirDevice *dev = priv; |
1807 |
USBPacket *p; |
1808 |
int len = control_packet->length;
|
1809 |
|
1810 |
DPRINTF("ctrl-in status %d len %d id %"PRIu64"\n", control_packet->status, |
1811 |
len, id); |
1812 |
|
1813 |
/* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
|
1814 |
* to work redirected to a not superspeed capable hcd */
|
1815 |
if (dev->dev.speed == USB_SPEED_SUPER &&
|
1816 |
!((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER)) && |
1817 |
control_packet->requesttype == 0x80 &&
|
1818 |
control_packet->request == 6 &&
|
1819 |
control_packet->value == 0x100 && control_packet->index == 0 && |
1820 |
data_len >= 18 && data[7] == 9) { |
1821 |
data[7] = 64; |
1822 |
} |
1823 |
|
1824 |
p = usbredir_find_packet_by_id(dev, 0, id);
|
1825 |
if (p) {
|
1826 |
usbredir_handle_status(dev, p, control_packet->status); |
1827 |
if (data_len > 0) { |
1828 |
usbredir_log_data(dev, "ctrl data in:", data, data_len);
|
1829 |
if (data_len > sizeof(dev->dev.data_buf)) { |
1830 |
ERROR("ctrl buffer too small (%d > %zu)\n",
|
1831 |
data_len, sizeof(dev->dev.data_buf));
|
1832 |
p->status = USB_RET_STALL; |
1833 |
data_len = len = sizeof(dev->dev.data_buf);
|
1834 |
} |
1835 |
memcpy(dev->dev.data_buf, data, data_len); |
1836 |
} |
1837 |
p->actual_length = len; |
1838 |
usb_generic_async_ctrl_complete(&dev->dev, p); |
1839 |
} |
1840 |
free(data); |
1841 |
} |
1842 |
|
1843 |
static void usbredir_bulk_packet(void *priv, uint64_t id, |
1844 |
struct usb_redir_bulk_packet_header *bulk_packet,
|
1845 |
uint8_t *data, int data_len)
|
1846 |
{ |
1847 |
USBRedirDevice *dev = priv; |
1848 |
uint8_t ep = bulk_packet->endpoint; |
1849 |
int len = (bulk_packet->length_high << 16) | bulk_packet->length; |
1850 |
USBPacket *p; |
1851 |
|
1852 |
DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n", |
1853 |
bulk_packet->status, ep, len, id); |
1854 |
|
1855 |
p = usbredir_find_packet_by_id(dev, ep, id); |
1856 |
if (p) {
|
1857 |
size_t size = usb_packet_size(p); |
1858 |
usbredir_handle_status(dev, p, bulk_packet->status); |
1859 |
if (data_len > 0) { |
1860 |
usbredir_log_data(dev, "bulk data in:", data, data_len);
|
1861 |
if (data_len > size) {
|
1862 |
ERROR("bulk got more data then requested (%d > %zd)\n",
|
1863 |
data_len, p->iov.size); |
1864 |
p->status = USB_RET_BABBLE; |
1865 |
data_len = len = size; |
1866 |
} |
1867 |
usb_packet_copy(p, data, data_len); |
1868 |
} |
1869 |
p->actual_length = len; |
1870 |
if (p->pid == USB_TOKEN_IN && p->ep->pipeline) {
|
1871 |
usb_combined_input_packet_complete(&dev->dev, p); |
1872 |
} else {
|
1873 |
usb_packet_complete(&dev->dev, p); |
1874 |
} |
1875 |
} |
1876 |
free(data); |
1877 |
} |
1878 |
|
1879 |
static void usbredir_iso_packet(void *priv, uint64_t id, |
1880 |
struct usb_redir_iso_packet_header *iso_packet,
|
1881 |
uint8_t *data, int data_len)
|
1882 |
{ |
1883 |
USBRedirDevice *dev = priv; |
1884 |
uint8_t ep = iso_packet->endpoint; |
1885 |
|
1886 |
DPRINTF2("iso-in status %d ep %02X len %d id %"PRIu64"\n", |
1887 |
iso_packet->status, ep, data_len, id); |
1888 |
|
1889 |
if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) {
|
1890 |
ERROR("received iso packet for non iso endpoint %02X\n", ep);
|
1891 |
free(data); |
1892 |
return;
|
1893 |
} |
1894 |
|
1895 |
if (dev->endpoint[EP2I(ep)].iso_started == 0) { |
1896 |
DPRINTF("received iso packet for non started stream ep %02X\n", ep);
|
1897 |
free(data); |
1898 |
return;
|
1899 |
} |
1900 |
|
1901 |
/* bufp_alloc also adds the packet to the ep queue */
|
1902 |
bufp_alloc(dev, data, data_len, iso_packet->status, ep, data); |
1903 |
} |
1904 |
|
1905 |
static void usbredir_interrupt_packet(void *priv, uint64_t id, |
1906 |
struct usb_redir_interrupt_packet_header *interrupt_packet,
|
1907 |
uint8_t *data, int data_len)
|
1908 |
{ |
1909 |
USBRedirDevice *dev = priv; |
1910 |
uint8_t ep = interrupt_packet->endpoint; |
1911 |
|
1912 |
DPRINTF("interrupt-in status %d ep %02X len %d id %"PRIu64"\n", |
1913 |
interrupt_packet->status, ep, data_len, id); |
1914 |
|
1915 |
if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) {
|
1916 |
ERROR("received int packet for non interrupt endpoint %02X\n", ep);
|
1917 |
free(data); |
1918 |
return;
|
1919 |
} |
1920 |
|
1921 |
if (ep & USB_DIR_IN) {
|
1922 |
if (dev->endpoint[EP2I(ep)].interrupt_started == 0) { |
1923 |
DPRINTF("received int packet while not started ep %02X\n", ep);
|
1924 |
free(data); |
1925 |
return;
|
1926 |
} |
1927 |
|
1928 |
if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
|
1929 |
usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0); |
1930 |
} |
1931 |
|
1932 |
/* bufp_alloc also adds the packet to the ep queue */
|
1933 |
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data); |
1934 |
} else {
|
1935 |
/*
|
1936 |
* We report output interrupt packets as completed directly upon
|
1937 |
* submission, so all we can do here if one failed is warn.
|
1938 |
*/
|
1939 |
if (interrupt_packet->status) {
|
1940 |
WARNING("interrupt output failed status %d ep %02X id %"PRIu64"\n", |
1941 |
interrupt_packet->status, ep, id); |
1942 |
} |
1943 |
} |
1944 |
} |
1945 |
|
1946 |
static void usbredir_buffered_bulk_packet(void *priv, uint64_t id, |
1947 |
struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet,
|
1948 |
uint8_t *data, int data_len)
|
1949 |
{ |
1950 |
USBRedirDevice *dev = priv; |
1951 |
uint8_t status, ep = buffered_bulk_packet->endpoint; |
1952 |
void *free_on_destroy;
|
1953 |
int i, len;
|
1954 |
|
1955 |
DPRINTF("buffered-bulk-in status %d ep %02X len %d id %"PRIu64"\n", |
1956 |
buffered_bulk_packet->status, ep, data_len, id); |
1957 |
|
1958 |
if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_BULK) {
|
1959 |
ERROR("received buffered-bulk packet for non bulk ep %02X\n", ep);
|
1960 |
free(data); |
1961 |
return;
|
1962 |
} |
1963 |
|
1964 |
if (dev->endpoint[EP2I(ep)].bulk_receiving_started == 0) { |
1965 |
DPRINTF("received buffered-bulk packet on not started ep %02X\n", ep);
|
1966 |
free(data); |
1967 |
return;
|
1968 |
} |
1969 |
|
1970 |
/* Data must be in maxp chunks for buffered_bulk_add_*_data_to_packet */
|
1971 |
len = dev->endpoint[EP2I(ep)].max_packet_size; |
1972 |
status = usb_redir_success; |
1973 |
free_on_destroy = NULL;
|
1974 |
for (i = 0; i < data_len; i += len) { |
1975 |
if (len >= (data_len - i)) {
|
1976 |
len = data_len - i; |
1977 |
status = buffered_bulk_packet->status; |
1978 |
free_on_destroy = data; |
1979 |
} |
1980 |
/* bufp_alloc also adds the packet to the ep queue */
|
1981 |
bufp_alloc(dev, data + i, len, status, ep, free_on_destroy); |
1982 |
} |
1983 |
|
1984 |
if (dev->endpoint[EP2I(ep)].pending_async_packet) {
|
1985 |
USBPacket *p = dev->endpoint[EP2I(ep)].pending_async_packet; |
1986 |
dev->endpoint[EP2I(ep)].pending_async_packet = NULL;
|
1987 |
usbredir_buffered_bulk_in_complete(dev, p, ep); |
1988 |
usb_packet_complete(&dev->dev, p); |
1989 |
} |
1990 |
} |
1991 |
|
1992 |
/*
|
1993 |
* Migration code
|
1994 |
*/
|
1995 |
|
1996 |
static void usbredir_pre_save(void *priv) |
1997 |
{ |
1998 |
USBRedirDevice *dev = priv; |
1999 |
|
2000 |
usbredir_fill_already_in_flight(dev); |
2001 |
} |
2002 |
|
2003 |
static int usbredir_post_load(void *priv, int version_id) |
2004 |
{ |
2005 |
USBRedirDevice *dev = priv; |
2006 |
|
2007 |
if (dev->parser == NULL) { |
2008 |
return 0; |
2009 |
} |
2010 |
|
2011 |
switch (dev->device_info.speed) {
|
2012 |
case usb_redir_speed_low:
|
2013 |
dev->dev.speed = USB_SPEED_LOW; |
2014 |
break;
|
2015 |
case usb_redir_speed_full:
|
2016 |
dev->dev.speed = USB_SPEED_FULL; |
2017 |
break;
|
2018 |
case usb_redir_speed_high:
|
2019 |
dev->dev.speed = USB_SPEED_HIGH; |
2020 |
break;
|
2021 |
case usb_redir_speed_super:
|
2022 |
dev->dev.speed = USB_SPEED_SUPER; |
2023 |
break;
|
2024 |
default:
|
2025 |
dev->dev.speed = USB_SPEED_FULL; |
2026 |
} |
2027 |
dev->dev.speedmask = (1 << dev->dev.speed);
|
2028 |
|
2029 |
usbredir_setup_usb_eps(dev); |
2030 |
usbredir_check_bulk_receiving(dev); |
2031 |
|
2032 |
return 0; |
2033 |
} |
2034 |
|
2035 |
/* For usbredirparser migration */
|
2036 |
static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) |
2037 |
{ |
2038 |
USBRedirDevice *dev = priv; |
2039 |
uint8_t *data; |
2040 |
int len;
|
2041 |
|
2042 |
if (dev->parser == NULL) { |
2043 |
qemu_put_be32(f, 0);
|
2044 |
return;
|
2045 |
} |
2046 |
|
2047 |
usbredirparser_serialize(dev->parser, &data, &len); |
2048 |
qemu_oom_check(data); |
2049 |
|
2050 |
qemu_put_be32(f, len); |
2051 |
qemu_put_buffer(f, data, len); |
2052 |
|
2053 |
free(data); |
2054 |
} |
2055 |
|
2056 |
static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) |
2057 |
{ |
2058 |
USBRedirDevice *dev = priv; |
2059 |
uint8_t *data; |
2060 |
int len, ret;
|
2061 |
|
2062 |
len = qemu_get_be32(f); |
2063 |
if (len == 0) { |
2064 |
return 0; |
2065 |
} |
2066 |
|
2067 |
/*
|
2068 |
* If our chardev is not open already at this point the usbredir connection
|
2069 |
* has been broken (non seamless migration, or restore from disk).
|
2070 |
*
|
2071 |
* In this case create a temporary parser to receive the migration data,
|
2072 |
* and schedule the close_bh to report the device as disconnected to the
|
2073 |
* guest and to destroy the parser again.
|
2074 |
*/
|
2075 |
if (dev->parser == NULL) { |
2076 |
WARNING("usb-redir connection broken during migration\n");
|
2077 |
usbredir_create_parser(dev); |
2078 |
qemu_bh_schedule(dev->chardev_close_bh); |
2079 |
} |
2080 |
|
2081 |
data = g_malloc(len); |
2082 |
qemu_get_buffer(f, data, len); |
2083 |
|
2084 |
ret = usbredirparser_unserialize(dev->parser, data, len); |
2085 |
|
2086 |
g_free(data); |
2087 |
|
2088 |
return ret;
|
2089 |
} |
2090 |
|
2091 |
static const VMStateInfo usbredir_parser_vmstate_info = { |
2092 |
.name = "usb-redir-parser",
|
2093 |
.put = usbredir_put_parser, |
2094 |
.get = usbredir_get_parser, |
2095 |
}; |
2096 |
|
2097 |
|
2098 |
/* For buffered packets (iso/irq) queue migration */
|
2099 |
static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) |
2100 |
{ |
2101 |
struct endp_data *endp = priv;
|
2102 |
USBRedirDevice *dev = endp->dev; |
2103 |
struct buf_packet *bufp;
|
2104 |
int len, i = 0; |
2105 |
|
2106 |
qemu_put_be32(f, endp->bufpq_size); |
2107 |
QTAILQ_FOREACH(bufp, &endp->bufpq, next) { |
2108 |
len = bufp->len - bufp->offset; |
2109 |
DPRINTF("put_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, |
2110 |
len, bufp->status); |
2111 |
qemu_put_be32(f, len); |
2112 |
qemu_put_be32(f, bufp->status); |
2113 |
qemu_put_buffer(f, bufp->data + bufp->offset, len); |
2114 |
i++; |
2115 |
} |
2116 |
assert(i == endp->bufpq_size); |
2117 |
} |
2118 |
|
2119 |
static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) |
2120 |
{ |
2121 |
struct endp_data *endp = priv;
|
2122 |
USBRedirDevice *dev = endp->dev; |
2123 |
struct buf_packet *bufp;
|
2124 |
int i;
|
2125 |
|
2126 |
endp->bufpq_size = qemu_get_be32(f); |
2127 |
for (i = 0; i < endp->bufpq_size; i++) { |
2128 |
bufp = g_malloc(sizeof(struct buf_packet)); |
2129 |
bufp->len = qemu_get_be32(f); |
2130 |
bufp->status = qemu_get_be32(f); |
2131 |
bufp->offset = 0;
|
2132 |
bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */
|
2133 |
bufp->free_on_destroy = bufp->data; |
2134 |
qemu_get_buffer(f, bufp->data, bufp->len); |
2135 |
QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); |
2136 |
DPRINTF("get_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, |
2137 |
bufp->len, bufp->status); |
2138 |
} |
2139 |
return 0; |
2140 |
} |
2141 |
|
2142 |
static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { |
2143 |
.name = "usb-redir-bufpq",
|
2144 |
.put = usbredir_put_bufpq, |
2145 |
.get = usbredir_get_bufpq, |
2146 |
}; |
2147 |
|
2148 |
|
2149 |
/* For endp_data migration */
|
2150 |
static const VMStateDescription usbredir_bulk_receiving_vmstate = { |
2151 |
.name = "usb-redir-ep/bulk-receiving",
|
2152 |
.version_id = 1,
|
2153 |
.minimum_version_id = 1,
|
2154 |
.fields = (VMStateField[]) { |
2155 |
VMSTATE_UINT8(bulk_receiving_started, struct endp_data),
|
2156 |
VMSTATE_END_OF_LIST() |
2157 |
} |
2158 |
}; |
2159 |
|
2160 |
static bool usbredir_bulk_receiving_needed(void *priv) |
2161 |
{ |
2162 |
struct endp_data *endp = priv;
|
2163 |
|
2164 |
return endp->bulk_receiving_started;
|
2165 |
} |
2166 |
|
2167 |
static const VMStateDescription usbredir_ep_vmstate = { |
2168 |
.name = "usb-redir-ep",
|
2169 |
.version_id = 1,
|
2170 |
.minimum_version_id = 1,
|
2171 |
.fields = (VMStateField[]) { |
2172 |
VMSTATE_UINT8(type, struct endp_data),
|
2173 |
VMSTATE_UINT8(interval, struct endp_data),
|
2174 |
VMSTATE_UINT8(interface, struct endp_data),
|
2175 |
VMSTATE_UINT16(max_packet_size, struct endp_data),
|
2176 |
VMSTATE_UINT8(iso_started, struct endp_data),
|
2177 |
VMSTATE_UINT8(iso_error, struct endp_data),
|
2178 |
VMSTATE_UINT8(interrupt_started, struct endp_data),
|
2179 |
VMSTATE_UINT8(interrupt_error, struct endp_data),
|
2180 |
VMSTATE_UINT8(bufpq_prefilled, struct endp_data),
|
2181 |
VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data),
|
2182 |
{ |
2183 |
.name = "bufpq",
|
2184 |
.version_id = 0,
|
2185 |
.field_exists = NULL,
|
2186 |
.size = 0,
|
2187 |
.info = &usbredir_ep_bufpq_vmstate_info, |
2188 |
.flags = VMS_SINGLE, |
2189 |
.offset = 0,
|
2190 |
}, |
2191 |
VMSTATE_INT32(bufpq_target_size, struct endp_data),
|
2192 |
VMSTATE_END_OF_LIST() |
2193 |
}, |
2194 |
.subsections = (VMStateSubsection[]) { |
2195 |
{ |
2196 |
.vmsd = &usbredir_bulk_receiving_vmstate, |
2197 |
.needed = usbredir_bulk_receiving_needed, |
2198 |
}, { |
2199 |
/* empty */
|
2200 |
} |
2201 |
} |
2202 |
}; |
2203 |
|
2204 |
|
2205 |
/* For PacketIdQueue migration */
|
2206 |
static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) |
2207 |
{ |
2208 |
struct PacketIdQueue *q = priv;
|
2209 |
USBRedirDevice *dev = q->dev; |
2210 |
struct PacketIdQueueEntry *e;
|
2211 |
int remain = q->size;
|
2212 |
|
2213 |
DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size);
|
2214 |
qemu_put_be32(f, q->size); |
2215 |
QTAILQ_FOREACH(e, &q->head, next) { |
2216 |
qemu_put_be64(f, e->id); |
2217 |
remain--; |
2218 |
} |
2219 |
assert(remain == 0);
|
2220 |
} |
2221 |
|
2222 |
static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) |
2223 |
{ |
2224 |
struct PacketIdQueue *q = priv;
|
2225 |
USBRedirDevice *dev = q->dev; |
2226 |
int i, size;
|
2227 |
uint64_t id; |
2228 |
|
2229 |
size = qemu_get_be32(f); |
2230 |
DPRINTF("get_packet_id_q %s size %d\n", q->name, size);
|
2231 |
for (i = 0; i < size; i++) { |
2232 |
id = qemu_get_be64(f); |
2233 |
packet_id_queue_add(q, id); |
2234 |
} |
2235 |
assert(q->size == size); |
2236 |
return 0; |
2237 |
} |
2238 |
|
2239 |
static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { |
2240 |
.name = "usb-redir-packet-id-q",
|
2241 |
.put = usbredir_put_packet_id_q, |
2242 |
.get = usbredir_get_packet_id_q, |
2243 |
}; |
2244 |
|
2245 |
static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { |
2246 |
.name = "usb-redir-packet-id-queue",
|
2247 |
.version_id = 1,
|
2248 |
.minimum_version_id = 1,
|
2249 |
.fields = (VMStateField[]) { |
2250 |
{ |
2251 |
.name = "queue",
|
2252 |
.version_id = 0,
|
2253 |
.field_exists = NULL,
|
2254 |
.size = 0,
|
2255 |
.info = &usbredir_ep_packet_id_q_vmstate_info, |
2256 |
.flags = VMS_SINGLE, |
2257 |
.offset = 0,
|
2258 |
}, |
2259 |
VMSTATE_END_OF_LIST() |
2260 |
} |
2261 |
}; |
2262 |
|
2263 |
|
2264 |
/* For usb_redir_device_connect_header migration */
|
2265 |
static const VMStateDescription usbredir_device_info_vmstate = { |
2266 |
.name = "usb-redir-device-info",
|
2267 |
.version_id = 1,
|
2268 |
.minimum_version_id = 1,
|
2269 |
.fields = (VMStateField[]) { |
2270 |
VMSTATE_UINT8(speed, struct usb_redir_device_connect_header),
|
2271 |
VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header),
|
2272 |
VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header),
|
2273 |
VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header),
|
2274 |
VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header),
|
2275 |
VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header),
|
2276 |
VMSTATE_UINT16(device_version_bcd, |
2277 |
struct usb_redir_device_connect_header),
|
2278 |
VMSTATE_END_OF_LIST() |
2279 |
} |
2280 |
}; |
2281 |
|
2282 |
|
2283 |
/* For usb_redir_interface_info_header migration */
|
2284 |
static const VMStateDescription usbredir_interface_info_vmstate = { |
2285 |
.name = "usb-redir-interface-info",
|
2286 |
.version_id = 1,
|
2287 |
.minimum_version_id = 1,
|
2288 |
.fields = (VMStateField[]) { |
2289 |
VMSTATE_UINT32(interface_count, |
2290 |
struct usb_redir_interface_info_header),
|
2291 |
VMSTATE_UINT8_ARRAY(interface, |
2292 |
struct usb_redir_interface_info_header, 32), |
2293 |
VMSTATE_UINT8_ARRAY(interface_class, |
2294 |
struct usb_redir_interface_info_header, 32), |
2295 |
VMSTATE_UINT8_ARRAY(interface_subclass, |
2296 |
struct usb_redir_interface_info_header, 32), |
2297 |
VMSTATE_UINT8_ARRAY(interface_protocol, |
2298 |
struct usb_redir_interface_info_header, 32), |
2299 |
VMSTATE_END_OF_LIST() |
2300 |
} |
2301 |
}; |
2302 |
|
2303 |
|
2304 |
/* And finally the USBRedirDevice vmstate itself */
|
2305 |
static const VMStateDescription usbredir_vmstate = { |
2306 |
.name = "usb-redir",
|
2307 |
.version_id = 1,
|
2308 |
.minimum_version_id = 1,
|
2309 |
.pre_save = usbredir_pre_save, |
2310 |
.post_load = usbredir_post_load, |
2311 |
.fields = (VMStateField[]) { |
2312 |
VMSTATE_USB_DEVICE(dev, USBRedirDevice), |
2313 |
VMSTATE_TIMER(attach_timer, USBRedirDevice), |
2314 |
{ |
2315 |
.name = "parser",
|
2316 |
.version_id = 0,
|
2317 |
.field_exists = NULL,
|
2318 |
.size = 0,
|
2319 |
.info = &usbredir_parser_vmstate_info, |
2320 |
.flags = VMS_SINGLE, |
2321 |
.offset = 0,
|
2322 |
}, |
2323 |
VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1,
|
2324 |
usbredir_ep_vmstate, struct endp_data),
|
2325 |
VMSTATE_STRUCT(cancelled, USBRedirDevice, 1,
|
2326 |
usbredir_ep_packet_id_queue_vmstate, |
2327 |
struct PacketIdQueue),
|
2328 |
VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1,
|
2329 |
usbredir_ep_packet_id_queue_vmstate, |
2330 |
struct PacketIdQueue),
|
2331 |
VMSTATE_STRUCT(device_info, USBRedirDevice, 1,
|
2332 |
usbredir_device_info_vmstate, |
2333 |
struct usb_redir_device_connect_header),
|
2334 |
VMSTATE_STRUCT(interface_info, USBRedirDevice, 1,
|
2335 |
usbredir_interface_info_vmstate, |
2336 |
struct usb_redir_interface_info_header),
|
2337 |
VMSTATE_END_OF_LIST() |
2338 |
} |
2339 |
}; |
2340 |
|
2341 |
static Property usbredir_properties[] = {
|
2342 |
DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
|
2343 |
DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning),
|
2344 |
DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
|
2345 |
DEFINE_PROP_INT32("bootindex", USBRedirDevice, bootindex, -1), |
2346 |
DEFINE_PROP_END_OF_LIST(), |
2347 |
}; |
2348 |
|
2349 |
static void usbredir_class_initfn(ObjectClass *klass, void *data) |
2350 |
{ |
2351 |
USBDeviceClass *uc = USB_DEVICE_CLASS(klass); |
2352 |
DeviceClass *dc = DEVICE_CLASS(klass); |
2353 |
|
2354 |
uc->init = usbredir_initfn; |
2355 |
uc->product_desc = "USB Redirection Device";
|
2356 |
uc->handle_destroy = usbredir_handle_destroy; |
2357 |
uc->cancel_packet = usbredir_cancel_packet; |
2358 |
uc->handle_reset = usbredir_handle_reset; |
2359 |
uc->handle_data = usbredir_handle_data; |
2360 |
uc->handle_control = usbredir_handle_control; |
2361 |
uc->flush_ep_queue = usbredir_flush_ep_queue; |
2362 |
uc->ep_stopped = usbredir_ep_stopped; |
2363 |
dc->vmsd = &usbredir_vmstate; |
2364 |
dc->props = usbredir_properties; |
2365 |
} |
2366 |
|
2367 |
static const TypeInfo usbredir_dev_info = { |
2368 |
.name = "usb-redir",
|
2369 |
.parent = TYPE_USB_DEVICE, |
2370 |
.instance_size = sizeof(USBRedirDevice),
|
2371 |
.class_init = usbredir_class_initfn, |
2372 |
}; |
2373 |
|
2374 |
static void usbredir_register_types(void) |
2375 |
{ |
2376 |
type_register_static(&usbredir_dev_info); |
2377 |
} |
2378 |
|
2379 |
type_init(usbredir_register_types) |