Revision 64838171
b/usb-linux.c | ||
---|---|---|
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2005 Fabrice Bellard |
5 | 5 |
* |
6 |
* Support for host device auto connect & disconnect |
|
7 |
* Copyright (c) 2008 Max Krasnyansky |
|
6 |
* Copyright (c) 2008 Max Krasnyansky |
|
7 |
* Support for host device auto connect & disconnect |
|
8 |
* Magor rewrite to support fully async operation |
|
8 | 9 |
* |
9 | 10 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | 11 |
* of this software and associated documentation files (the "Software"), to deal |
... | ... | |
55 | 56 |
const char *devname); |
56 | 57 |
|
57 | 58 |
//#define DEBUG |
58 |
//#define DEBUG_ISOCH |
|
59 |
//#define USE_ASYNCIO |
|
59 |
|
|
60 |
#ifdef DEBUG |
|
61 |
#define dprintf printf |
|
62 |
#else |
|
63 |
#define dprintf(...) |
|
64 |
#endif |
|
60 | 65 |
|
61 | 66 |
#define USBDEVFS_PATH "/proc/bus/usb" |
62 | 67 |
#define PRODUCT_NAME_SZ 32 |
63 |
#define SIG_ISOCOMPLETE (SIGRTMIN+7) |
|
64 | 68 |
#define MAX_ENDPOINTS 16 |
65 | 69 |
|
66 | 70 |
struct sigaction sigact; |
... | ... | |
68 | 72 |
/* endpoint association data */ |
69 | 73 |
struct endp_data { |
70 | 74 |
uint8_t type; |
75 |
uint8_t halted; |
|
71 | 76 |
}; |
72 | 77 |
|
73 |
|
|
74 |
|
|
75 |
/* FIXME: move USBPacket to PendingURB */ |
|
76 | 78 |
typedef struct USBHostDevice { |
77 | 79 |
USBDevice dev; |
78 |
int fd; |
|
79 |
int pipe_fds[2]; |
|
80 |
USBPacket *packet; |
|
80 |
int fd; |
|
81 |
|
|
82 |
uint8_t descr[1024]; |
|
83 |
int descr_len; |
|
84 |
int configuration; |
|
85 |
|
|
81 | 86 |
struct endp_data endp_table[MAX_ENDPOINTS]; |
82 |
int configuration; |
|
83 |
uint8_t descr[1024]; |
|
84 |
int descr_len; |
|
85 |
int urbs_ready; |
|
86 | 87 |
|
87 | 88 |
QEMUTimer *timer; |
88 | 89 |
|
... | ... | |
93 | 94 |
struct USBHostDevice *next; |
94 | 95 |
} USBHostDevice; |
95 | 96 |
|
97 |
static int is_isoc(USBHostDevice *s, int ep) |
|
98 |
{ |
|
99 |
return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO; |
|
100 |
} |
|
101 |
|
|
102 |
static int is_halted(USBHostDevice *s, int ep) |
|
103 |
{ |
|
104 |
return s->endp_table[ep - 1].halted; |
|
105 |
} |
|
106 |
|
|
107 |
static void clear_halt(USBHostDevice *s, int ep) |
|
108 |
{ |
|
109 |
s->endp_table[ep - 1].halted = 0; |
|
110 |
} |
|
111 |
|
|
112 |
static void set_halt(USBHostDevice *s, int ep) |
|
113 |
{ |
|
114 |
s->endp_table[ep - 1].halted = 1; |
|
115 |
} |
|
116 |
|
|
96 | 117 |
static USBHostDevice *hostdev_list; |
97 | 118 |
|
98 | 119 |
static void hostdev_link(USBHostDevice *dev) |
... | ... | |
128 | 149 |
return NULL; |
129 | 150 |
} |
130 | 151 |
|
131 |
typedef struct PendingURB { |
|
132 |
struct usbdevfs_urb *urb; |
|
133 |
int status; |
|
134 |
struct PendingURB *next; |
|
135 |
} PendingURB; |
|
152 |
/* |
|
153 |
* Async URB state. |
|
154 |
* We always allocate one isoc descriptor even for bulk transfers |
|
155 |
* to simplify allocation and casts. |
|
156 |
*/ |
|
157 |
typedef struct AsyncURB |
|
158 |
{ |
|
159 |
struct usbdevfs_urb urb; |
|
160 |
struct usbdevfs_iso_packet_desc isocpd; |
|
136 | 161 |
|
137 |
static PendingURB *pending_urbs = NULL; |
|
162 |
USBPacket *packet; |
|
163 |
USBHostDevice *hdev; |
|
164 |
} AsyncURB; |
|
138 | 165 |
|
139 |
static int add_pending_urb(struct usbdevfs_urb *urb)
|
|
166 |
static AsyncURB *async_alloc(void)
|
|
140 | 167 |
{ |
141 |
PendingURB *purb = qemu_mallocz(sizeof(PendingURB)); |
|
142 |
if (purb) { |
|
143 |
purb->urb = urb; |
|
144 |
purb->status = 0; |
|
145 |
purb->next = pending_urbs; |
|
146 |
pending_urbs = purb; |
|
147 |
return 1; |
|
148 |
} |
|
149 |
return 0; |
|
168 |
return (AsyncURB *) qemu_mallocz(sizeof(AsyncURB)); |
|
150 | 169 |
} |
151 | 170 |
|
152 |
static int del_pending_urb(struct usbdevfs_urb *urb)
|
|
171 |
static void async_free(AsyncURB *aurb)
|
|
153 | 172 |
{ |
154 |
PendingURB *purb = pending_urbs;
|
|
155 |
PendingURB *prev = NULL;
|
|
173 |
qemu_free(aurb);
|
|
174 |
}
|
|
156 | 175 |
|
157 |
while (purb && purb->urb != urb) { |
|
158 |
prev = purb; |
|
159 |
purb = purb->next; |
|
160 |
} |
|
176 |
static void async_complete(void *opaque) |
|
177 |
{ |
|
178 |
USBHostDevice *s = opaque; |
|
179 |
AsyncURB *aurb; |
|
180 |
|
|
181 |
while (1) { |
|
182 |
USBPacket *p; |
|
161 | 183 |
|
162 |
if (purb && purb->urb == urb) { |
|
163 |
if (prev) { |
|
164 |
prev->next = purb->next; |
|
165 |
} else { |
|
166 |
pending_urbs = purb->next; |
|
184 |
int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb); |
|
185 |
if (r < 0) { |
|
186 |
if (errno == EAGAIN) |
|
187 |
return; |
|
188 |
|
|
189 |
if (errno == ENODEV) { |
|
190 |
printf("husb: device %d.%d disconnected\n", s->bus_num, s->addr); |
|
191 |
usb_device_del_addr(0, s->dev.addr); |
|
192 |
return; |
|
193 |
} |
|
194 |
|
|
195 |
dprintf("husb: async. reap urb failed errno %d\n", errno); |
|
196 |
return; |
|
167 | 197 |
} |
168 |
qemu_free(purb); |
|
169 |
return 1; |
|
198 |
|
|
199 |
p = aurb->packet; |
|
200 |
|
|
201 |
dprintf("husb: async completed. aurb %p status %d alen %d\n", |
|
202 |
aurb, aurb->urb.status, aurb->urb.actual_length); |
|
203 |
|
|
204 |
if (p) { |
|
205 |
switch (aurb->urb.status) { |
|
206 |
case 0: |
|
207 |
p->len = aurb->urb.actual_length; |
|
208 |
break; |
|
209 |
|
|
210 |
case -EPIPE: |
|
211 |
set_halt(s, p->devep); |
|
212 |
/* fall through */ |
|
213 |
default: |
|
214 |
p->len = USB_RET_NAK; |
|
215 |
break; |
|
216 |
} |
|
217 |
|
|
218 |
usb_packet_complete(p); |
|
219 |
} |
|
220 |
|
|
221 |
async_free(aurb); |
|
170 | 222 |
} |
171 |
return 0; |
|
172 | 223 |
} |
173 | 224 |
|
174 |
#ifdef USE_ASYNCIO |
|
175 |
static PendingURB *get_pending_urb(struct usbdevfs_urb *urb) |
|
225 |
static void async_cancel(USBPacket *unused, void *opaque) |
|
176 | 226 |
{ |
177 |
PendingURB *purb = pending_urbs; |
|
227 |
AsyncURB *aurb = opaque; |
|
228 |
USBHostDevice *s = aurb->hdev; |
|
178 | 229 |
|
179 |
while (purb && purb->urb != urb) { |
|
180 |
purb = purb->next; |
|
181 |
} |
|
230 |
dprintf("husb: async cancel. aurb %p\n", aurb); |
|
231 |
|
|
232 |
/* Mark it as dead (see async_complete above) */ |
|
233 |
aurb->packet = NULL; |
|
182 | 234 |
|
183 |
if (purb && purb->urb == urb) { |
|
184 |
return purb; |
|
235 |
int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb); |
|
236 |
if (r < 0) { |
|
237 |
dprintf("husb: async. discard urb failed errno %d\n", errno); |
|
185 | 238 |
} |
186 |
return NULL; |
|
187 | 239 |
} |
188 |
#endif |
|
189 | 240 |
|
190 | 241 |
static int usb_host_update_interfaces(USBHostDevice *dev, int configuration) |
191 | 242 |
{ |
... | ... | |
204 | 255 |
|
205 | 256 |
i += dev_descr_len; |
206 | 257 |
while (i < dev->descr_len) { |
207 |
#ifdef DEBUG |
|
208 |
printf("i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len, |
|
258 |
dprintf("husb: i is %d, descr_len is %d, dl %d, dt %d\n", i, dev->descr_len, |
|
209 | 259 |
dev->descr[i], dev->descr[i+1]); |
210 |
#endif |
|
260 |
|
|
211 | 261 |
if (dev->descr[i+1] != USB_DT_CONFIG) { |
212 | 262 |
i += dev->descr[i]; |
213 | 263 |
continue; |
214 | 264 |
} |
215 | 265 |
config_descr_len = dev->descr[i]; |
216 | 266 |
|
217 |
#ifdef DEBUG |
|
218 |
printf("config #%d need %d\n", dev->descr[i + 5], configuration); |
|
219 |
#endif |
|
267 |
printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration); |
|
220 | 268 |
|
221 | 269 |
if (configuration < 0 || configuration == dev->descr[i + 5]) |
222 | 270 |
break; |
... | ... | |
225 | 273 |
} |
226 | 274 |
|
227 | 275 |
if (i >= dev->descr_len) { |
228 |
printf("usb_host: error - device has no matching configuration\n");
|
|
276 |
printf("husb: update iface failed. no matching configuration\n");
|
|
229 | 277 |
goto fail; |
230 | 278 |
} |
231 | 279 |
nb_interfaces = dev->descr[i + 4]; |
... | ... | |
251 | 299 |
ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface); |
252 | 300 |
if (ret < 0) { |
253 | 301 |
if (errno == EBUSY) { |
254 |
fprintf(stderr, |
|
255 |
"usb_host: warning - device already grabbed\n"); |
|
302 |
printf("husb: update iface. device already grabbed\n"); |
|
256 | 303 |
} else { |
257 |
perror("USBDEVFS_CLAIMINTERFACE");
|
|
304 |
perror("husb: failed to claim interface");
|
|
258 | 305 |
} |
259 | 306 |
fail: |
260 | 307 |
return 0; |
261 | 308 |
} |
262 | 309 |
} |
263 | 310 |
|
264 |
#ifdef DEBUG |
|
265 |
printf("usb_host: %d interfaces claimed for configuration %d\n", |
|
311 |
printf("husb: %d interfaces claimed for configuration %d\n", |
|
266 | 312 |
nb_interfaces, configuration); |
267 |
#endif |
|
268 | 313 |
|
269 | 314 |
return 1; |
270 | 315 |
} |
271 | 316 |
|
272 | 317 |
static void usb_host_handle_reset(USBDevice *dev) |
273 | 318 |
{ |
274 |
#if 0 |
|
275 | 319 |
USBHostDevice *s = (USBHostDevice *)dev; |
276 |
/* USBDEVFS_RESET, but not the first time as it has already be |
|
277 |
done by the host OS */ |
|
320 |
|
|
321 |
dprintf("husb: reset device %u.%u\n", s->bus_num, s->addr); |
|
322 |
|
|
278 | 323 |
ioctl(s->fd, USBDEVFS_RESET); |
279 |
#endif
|
|
324 |
usb_host_update_interfaces(s, s->configuration);
|
|
280 | 325 |
} |
281 | 326 |
|
282 | 327 |
static void usb_host_handle_destroy(USBDevice *dev) |
... | ... | |
284 | 329 |
USBHostDevice *s = (USBHostDevice *)dev; |
285 | 330 |
|
286 | 331 |
qemu_del_timer(s->timer); |
332 |
qemu_set_fd_handler(s->fd, NULL, NULL, NULL); |
|
287 | 333 |
|
288 | 334 |
hostdev_unlink(s); |
289 | 335 |
|
336 |
async_complete(s); |
|
337 |
|
|
290 | 338 |
if (s->fd >= 0) |
291 | 339 |
close(s->fd); |
292 | 340 |
|
... | ... | |
320 | 368 |
ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si); |
321 | 369 |
usb_linux_update_endp_table(s); |
322 | 370 |
} else if (request == (DeviceOutRequest | USB_REQ_SET_CONFIGURATION)) { |
323 |
#ifdef DEBUG |
|
324 |
printf("usb_host_handle_control: SET_CONFIGURATION request - " |
|
325 |
"config %d\n", value & 0xff); |
|
326 |
#endif |
|
371 |
dprintf("husb: ctrl set config %d\n", value & 0xff); |
|
327 | 372 |
if (s->configuration != (value & 0xff)) { |
328 | 373 |
s->configuration = (value & 0xff); |
329 | 374 |
intf_update_required = 1; |
... | ... | |
339 | 384 |
ct.timeout = 50; |
340 | 385 |
ct.data = data; |
341 | 386 |
ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct); |
387 |
|
|
388 |
dprintf("husb: ctrl req 0x%x val 0x%x index %u len %u ret %d\n", |
|
389 |
ct.bRequest, ct.wValue, ct.wIndex, ct.wLength, ret); |
|
342 | 390 |
} |
343 | 391 |
|
344 | 392 |
if (ret < 0) { |
... | ... | |
350 | 398 |
} |
351 | 399 |
} else { |
352 | 400 |
if (intf_update_required) { |
353 |
#ifdef DEBUG |
|
354 |
printf("usb_host_handle_control: updating interfaces\n"); |
|
355 |
#endif |
|
401 |
dprintf("husb: updating interfaces\n"); |
|
356 | 402 |
usb_host_update_interfaces(s, value & 0xff); |
357 | 403 |
} |
358 | 404 |
return ret; |
359 | 405 |
} |
360 | 406 |
} |
361 | 407 |
|
362 |
static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p); |
|
363 |
|
|
364 | 408 |
static int usb_host_handle_data(USBDevice *dev, USBPacket *p) |
365 | 409 |
{ |
366 |
USBHostDevice *s = (USBHostDevice *)dev; |
|
367 |
struct usbdevfs_bulktransfer bt; |
|
410 |
USBHostDevice *s = (USBHostDevice *) dev; |
|
411 |
AsyncURB *aurb; |
|
412 |
struct usbdevfs_urb *urb; |
|
368 | 413 |
int ret; |
369 |
uint8_t devep = p->devep; |
|
370 | 414 |
|
371 |
if (s->endp_table[p->devep - 1].type == USBDEVFS_URB_TYPE_ISO) { |
|
372 |
return usb_host_handle_isoch(dev, p); |
|
415 |
aurb = async_alloc(); |
|
416 |
if (!aurb) { |
|
417 |
dprintf("husb: async malloc failed\n"); |
|
418 |
return USB_RET_NAK; |
|
373 | 419 |
} |
420 |
aurb->hdev = s; |
|
421 |
aurb->packet = p; |
|
422 |
|
|
423 |
urb = &aurb->urb; |
|
374 | 424 |
|
375 |
/* XXX: optimize and handle all data types by looking at the |
|
376 |
config descriptor */ |
|
377 | 425 |
if (p->pid == USB_TOKEN_IN) |
378 |
devep |= 0x80;
|
|
379 |
bt.ep = devep;
|
|
380 |
bt.len = p->len;
|
|
381 |
bt.timeout = 50; |
|
382 |
bt.data = p->data;
|
|
383 |
ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
|
|
384 |
if (ret < 0) { |
|
385 |
switch(errno) {
|
|
386 |
case ETIMEDOUT:
|
|
426 |
urb->endpoint = p->devep | 0x80;
|
|
427 |
else
|
|
428 |
urb->endpoint = p->devep;
|
|
429 |
|
|
430 |
if (is_halted(s, p->devep)) {
|
|
431 |
ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
|
|
432 |
if (ret < 0) {
|
|
433 |
dprintf("husb: failed to clear halt. ep 0x%x errno %d\n",
|
|
434 |
urb->endpoint, errno);
|
|
387 | 435 |
return USB_RET_NAK; |
388 |
case EPIPE: |
|
389 |
default: |
|
390 |
#ifdef DEBUG |
|
391 |
printf("handle_data: errno=%d\n", errno); |
|
392 |
#endif |
|
393 |
return USB_RET_STALL; |
|
394 | 436 |
} |
395 |
} else { |
|
396 |
return ret; |
|
397 |
} |
|
398 |
} |
|
399 |
|
|
400 |
#ifdef USE_ASYNCIO |
|
401 |
static void urb_completion_pipe_read(void *opaque) |
|
402 |
{ |
|
403 |
USBHostDevice *s = opaque; |
|
404 |
USBPacket *p = s->packet; |
|
405 |
PendingURB *pending_urb = NULL; |
|
406 |
struct usbdevfs_urb *purb = NULL; |
|
407 |
int len, ret; |
|
408 |
|
|
409 |
len = read(s->pipe_fds[0], &pending_urb, sizeof(pending_urb)); |
|
410 |
if (len != sizeof(pending_urb)) { |
|
411 |
printf("urb_completion: error reading pending_urb, len=%d\n", len); |
|
412 |
return; |
|
413 |
} |
|
414 |
|
|
415 |
/* FIXME: handle pending_urb->status */ |
|
416 |
del_pending_urb(pending_urb->urb); |
|
417 |
|
|
418 |
if (!p) { |
|
419 |
s->urbs_ready++; |
|
420 |
return; |
|
437 |
clear_halt(s, p->devep); |
|
421 | 438 |
} |
422 | 439 |
|
423 |
ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); |
|
424 |
if (ret < 0) { |
|
425 |
printf("urb_completion: REAPURBNDELAY ioctl=%d errno=%d\n", |
|
426 |
ret, errno); |
|
427 |
return; |
|
428 |
} |
|
429 |
|
|
430 |
#ifdef DEBUG_ISOCH |
|
431 |
if (purb == pending_urb->urb) { |
|
432 |
printf("urb_completion: urb mismatch reaped=%p pending=%p\n", |
|
433 |
purb, urb); |
|
434 |
} |
|
435 |
#endif |
|
436 |
|
|
437 |
p->len = purb->actual_length; |
|
438 |
usb_packet_complete(p); |
|
439 |
qemu_free(purb); |
|
440 |
s->packet = NULL; |
|
441 |
} |
|
442 |
|
|
443 |
static void isoch_done(int signum, siginfo_t *info, void *context) |
|
444 |
{ |
|
445 |
struct usbdevfs_urb *urb = (struct usbdevfs_urb *)info->si_addr; |
|
446 |
USBHostDevice *s = (USBHostDevice *)urb->usercontext; |
|
447 |
PendingURB *purb; |
|
440 |
urb->buffer = p->data; |
|
441 |
urb->buffer_length = p->len; |
|
448 | 442 |
|
449 |
if (info->si_code != SI_ASYNCIO || |
|
450 |
info->si_signo != SIG_ISOCOMPLETE) { |
|
451 |
return; |
|
443 |
if (is_isoc(s, p->devep)) { |
|
444 |
/* Setup ISOC transfer */ |
|
445 |
urb->type = USBDEVFS_URB_TYPE_ISO; |
|
446 |
urb->flags = USBDEVFS_URB_ISO_ASAP; |
|
447 |
urb->number_of_packets = 1; |
|
448 |
urb->iso_frame_desc[0].length = p->len; |
|
449 |
} else { |
|
450 |
/* Setup bulk transfer */ |
|
451 |
urb->type = USBDEVFS_URB_TYPE_BULK; |
|
452 | 452 |
} |
453 | 453 |
|
454 |
purb = get_pending_urb(urb); |
|
455 |
if (purb) { |
|
456 |
purb->status = info->si_errno; |
|
457 |
write(s->pipe_fds[1], &purb, sizeof(purb)); |
|
458 |
} |
|
459 |
} |
|
460 |
#endif |
|
454 |
urb->usercontext = s; |
|
461 | 455 |
|
462 |
static int usb_host_handle_isoch(USBDevice *dev, USBPacket *p) |
|
463 |
{ |
|
464 |
USBHostDevice *s = (USBHostDevice *)dev; |
|
465 |
struct usbdevfs_urb *urb, *purb = NULL; |
|
466 |
int ret; |
|
467 |
uint8_t devep = p->devep; |
|
456 |
ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); |
|
468 | 457 |
|
469 |
if (p->pid == USB_TOKEN_IN) |
|
470 |
devep |= 0x80; |
|
458 |
dprintf("husb: data submit. ep 0x%x len %u aurb %p\n", urb->endpoint, p->len, aurb); |
|
471 | 459 |
|
472 |
urb = qemu_mallocz(sizeof(struct usbdevfs_urb) + |
|
473 |
sizeof(struct usbdevfs_iso_packet_desc)); |
|
474 |
if (!urb) { |
|
475 |
printf("usb_host_handle_isoch: malloc failed\n"); |
|
476 |
return 0; |
|
477 |
} |
|
460 |
if (ret < 0) { |
|
461 |
dprintf("husb: submit failed. errno %d\n", errno); |
|
462 |
async_free(aurb); |
|
478 | 463 |
|
479 |
urb->type = USBDEVFS_URB_TYPE_ISO; |
|
480 |
urb->endpoint = devep; |
|
481 |
urb->status = 0; |
|
482 |
urb->flags = USBDEVFS_URB_ISO_ASAP; |
|
483 |
urb->buffer = p->data; |
|
484 |
urb->buffer_length = p->len; |
|
485 |
urb->actual_length = 0; |
|
486 |
urb->start_frame = 0; |
|
487 |
urb->error_count = 0; |
|
488 |
#ifdef USE_ASYNCIO |
|
489 |
urb->signr = SIG_ISOCOMPLETE; |
|
490 |
#else |
|
491 |
urb->signr = 0; |
|
492 |
#endif |
|
493 |
urb->usercontext = s; |
|
494 |
urb->number_of_packets = 1; |
|
495 |
urb->iso_frame_desc[0].length = p->len; |
|
496 |
urb->iso_frame_desc[0].actual_length = 0; |
|
497 |
urb->iso_frame_desc[0].status = 0; |
|
498 |
ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb); |
|
499 |
if (ret == 0) { |
|
500 |
if (!add_pending_urb(urb)) { |
|
501 |
printf("usb_host_handle_isoch: add_pending_urb failed %p\n", urb); |
|
502 |
} |
|
503 |
} else { |
|
504 |
printf("usb_host_handle_isoch: SUBMITURB ioctl=%d errno=%d\n", |
|
505 |
ret, errno); |
|
506 |
qemu_free(urb); |
|
507 | 464 |
switch(errno) { |
508 | 465 |
case ETIMEDOUT: |
509 | 466 |
return USB_RET_NAK; |
... | ... | |
512 | 469 |
return USB_RET_STALL; |
513 | 470 |
} |
514 | 471 |
} |
515 |
#ifdef USE_ASYNCIO |
|
516 |
/* FIXME: handle urbs_ready together with sync io |
|
517 |
* workaround for injecting the signaled urbs into current frame */ |
|
518 |
if (s->urbs_ready > 0) { |
|
519 |
ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); |
|
520 |
if (ret == 0) { |
|
521 |
ret = purb->actual_length; |
|
522 |
qemu_free(purb); |
|
523 |
s->urbs_ready--; |
|
524 |
} |
|
525 |
return ret; |
|
526 |
} |
|
527 |
s->packet = p; |
|
472 |
|
|
473 |
usb_defer_packet(p, async_cancel, aurb); |
|
528 | 474 |
return USB_RET_ASYNC; |
529 |
#else |
|
530 |
ret = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &purb); |
|
531 |
if (ret == 0) { |
|
532 |
if (del_pending_urb(purb)) { |
|
533 |
ret = purb->actual_length; |
|
534 |
qemu_free(purb); |
|
535 |
} else { |
|
536 |
printf("usb_host_handle_isoch: del_pending_urb failed %p\n", purb); |
|
537 |
} |
|
538 |
} else { |
|
539 |
#ifdef DEBUG_ISOCH |
|
540 |
printf("usb_host_handle_isoch: REAPURBNDELAY ioctl=%d errno=%d\n", |
|
541 |
ret, errno); |
|
542 |
#endif |
|
543 |
} |
|
544 |
return ret; |
|
545 |
#endif |
|
546 | 475 |
} |
547 | 476 |
|
548 | 477 |
/* returns 1 on problem encountered or 0 for success */ |
... | ... | |
579 | 508 |
|
580 | 509 |
if (descriptors[i + 1] != USB_DT_CONFIG || |
581 | 510 |
descriptors[i + 5] != configuration) { |
582 |
printf("invalid descriptor data - configuration\n"); |
|
511 |
dprintf("invalid descriptor data - configuration\n");
|
|
583 | 512 |
return 1; |
584 | 513 |
} |
585 | 514 |
i += descriptors[i]; |
... | ... | |
641 | 570 |
type = USBDEVFS_URB_TYPE_INTERRUPT; |
642 | 571 |
break; |
643 | 572 |
default: |
644 |
printf("usb_host: malformed endpoint type\n"); |
|
573 |
dprintf("usb_host: malformed endpoint type\n");
|
|
645 | 574 |
type = USBDEVFS_URB_TYPE_BULK; |
646 | 575 |
} |
647 | 576 |
s->endp_table[(devep & 0xf) - 1].type = type; |
577 |
s->endp_table[(devep & 0xf) - 1].halted = 0; |
|
648 | 578 |
|
649 | 579 |
i += descriptors[i]; |
650 | 580 |
} |
... | ... | |
660 | 590 |
|
661 | 591 |
err = ioctl(s->fd, USBDEVFS_CONNECTINFO, &ci); |
662 | 592 |
if (err < 0) { |
663 |
printf("usb device %d.%d disconnected\n", 0, s->dev.addr);
|
|
593 |
printf("husb: device %d.%d disconnected\n", s->bus_num, s->addr);
|
|
664 | 594 |
usb_device_del_addr(0, s->dev.addr); |
665 | 595 |
return; |
666 | 596 |
} |
... | ... | |
686 | 616 |
if (!dev->timer) |
687 | 617 |
goto fail; |
688 | 618 |
|
689 |
#ifdef DEBUG |
|
690 |
printf("usb_host_device_open %d.%d\n", bus_num, addr); |
|
691 |
#endif |
|
619 |
printf("husb: open device %d.%d\n", bus_num, addr); |
|
692 | 620 |
|
693 | 621 |
snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", |
694 | 622 |
bus_num, addr); |
... | ... | |
701 | 629 |
/* read the device description */ |
702 | 630 |
dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); |
703 | 631 |
if (dev->descr_len <= 0) { |
704 |
perror("usb_host_device_open: reading device data failed");
|
|
632 |
perror("husb: reading device data failed");
|
|
705 | 633 |
goto fail; |
706 | 634 |
} |
707 | 635 |
|
... | ... | |
728 | 656 |
goto fail; |
729 | 657 |
} |
730 | 658 |
|
731 |
#ifdef DEBUG |
|
732 |
printf("host USB device %d.%d grabbed\n", bus_num, addr); |
|
733 |
#endif |
|
659 |
printf("husb: grabbed usb device %d.%d\n", bus_num, addr); |
|
734 | 660 |
|
735 | 661 |
ret = usb_linux_update_endp_table(dev); |
736 | 662 |
if (ret) |
... | ... | |
754 | 680 |
pstrcpy(dev->dev.devname, sizeof(dev->dev.devname), |
755 | 681 |
prod_name); |
756 | 682 |
|
757 |
#ifdef USE_ASYNCIO |
|
758 |
/* set up the signal handlers */ |
|
759 |
sigemptyset(&sigact.sa_mask); |
|
760 |
sigact.sa_sigaction = isoch_done; |
|
761 |
sigact.sa_flags = SA_SIGINFO; |
|
762 |
sigact.sa_restorer = 0; |
|
763 |
ret = sigaction(SIG_ISOCOMPLETE, &sigact, NULL); |
|
764 |
if (ret < 0) { |
|
765 |
perror("usb_host_device_open: sigaction failed"); |
|
766 |
goto fail; |
|
767 |
} |
|
768 |
|
|
769 |
if (pipe(dev->pipe_fds) < 0) { |
|
770 |
perror("usb_host_device_open: pipe creation failed"); |
|
771 |
goto fail; |
|
772 |
} |
|
773 |
fcntl(dev->pipe_fds[0], F_SETFL, O_NONBLOCK | O_ASYNC); |
|
774 |
fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK); |
|
775 |
qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev); |
|
776 |
#endif |
|
683 |
/* USB devio uses 'write' flag to check for async completions */ |
|
684 |
qemu_set_fd_handler(dev->fd, NULL, async_complete, dev); |
|
777 | 685 |
|
778 | 686 |
/* Start the timer to detect disconnect */ |
779 | 687 |
qemu_mod_timer(dev->timer, qemu_get_clock(rt_clock) + 1000); |
780 | 688 |
|
781 | 689 |
hostdev_link(dev); |
782 | 690 |
|
783 |
dev->urbs_ready = 0; |
|
784 |
return (USBDevice *)dev; |
|
691 |
return (USBDevice *) dev; |
|
785 | 692 |
|
786 | 693 |
fail: |
787 | 694 |
if (dev) { |
... | ... | |
804 | 711 |
return NULL; |
805 | 712 |
|
806 | 713 |
if (hostdev_find(bus_num, addr)) { |
807 |
printf("host usb device %d.%d is already open\n", bus_num, addr);
|
|
714 |
term_printf("husb: host usb device %d.%d is already open\n", bus_num, addr);
|
|
808 | 715 |
return NULL; |
809 | 716 |
} |
810 | 717 |
|
... | ... | |
844 | 751 |
|
845 | 752 |
f = fopen(USBDEVFS_PATH "/devices", "r"); |
846 | 753 |
if (!f) { |
847 |
term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
|
|
754 |
term_printf("husb: could not open %s\n", USBDEVFS_PATH "/devices");
|
|
848 | 755 |
return 0; |
849 | 756 |
} |
850 | 757 |
device_count = 0; |
... | ... | |
954 | 861 |
if (hostdev_find(bus_num, addr)) |
955 | 862 |
return 0; |
956 | 863 |
|
957 |
printf("Auto open: bus_num %d addr %d\n", bus_num, addr);
|
|
864 |
dprintf("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
|
|
958 | 865 |
|
959 | 866 |
dev = usb_host_device_open_addr(bus_num, addr, product_name); |
960 | 867 |
if (dev) |
... | ... | |
978 | 885 |
{ |
979 | 886 |
struct USBAutoFilter *f = qemu_mallocz(sizeof(*f)); |
980 | 887 |
if (!f) { |
981 |
printf("Failed to allocate auto filter\n");
|
|
888 |
printf("husb: failed to allocate auto filter\n");
|
|
982 | 889 |
return; |
983 | 890 |
} |
984 | 891 |
|
... | ... | |
996 | 903 |
*/ |
997 | 904 |
usb_auto_timer = qemu_new_timer(rt_clock, usb_host_auto_timer, NULL); |
998 | 905 |
if (!usb_auto_timer) { |
999 |
printf("Failed to allocate timer\n");
|
|
906 |
printf("husb: failed to allocate timer\n");
|
|
1000 | 907 |
qemu_free(f); |
1001 | 908 |
return; |
1002 | 909 |
} |
... | ... | |
1005 | 912 |
qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000); |
1006 | 913 |
} |
1007 | 914 |
|
1008 |
printf("Auto filter: bus_num %d addr %d vid %d pid %d\n",
|
|
915 |
dprintf("husb: auto filter: bus_num %d addr %d vid %d pid %d\n",
|
|
1009 | 916 |
bus_num, addr, vendor_id, product_id); |
1010 | 917 |
|
1011 | 918 |
f->next = usb_auto_filter; |
... | ... | |
1174 | 1081 |
usb_host_scan(NULL, usb_host_info_device); |
1175 | 1082 |
} |
1176 | 1083 |
|
1177 |
|
|
1178 |
|
|
1179 |
|
|
1180 | 1084 |
#else |
1181 | 1085 |
|
1182 | 1086 |
void usb_host_info(void) |
Also available in: Unified diff