ia64/xen-unstable

view tools/ioemu/usb-linux.c @ 15841:c5f735271e22

[IA64] Foreign p2m: Fix vti domain builder.

It should set arch_domain::convmem_end.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Alex Williamson <alex.williamson@hp.com>
date Thu Sep 06 13:48:43 2007 -0600 (2007-09-06)
parents 00618037d37d
children 04cc0e22a20a
line source
1 /*
2 * Linux host USB redirector
3 *
4 * Copyright (c) 2005 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "vl.h"
26 #if defined(__linux__)
27 #include <dirent.h>
28 #include <sys/ioctl.h>
29 /* Some versions of usbdevice_fs.h need __user to be defined for them. */
30 /* This may (harmlessly) conflict with a definition in linux/compiler.h. */
31 #define __user
32 #include <linux/usbdevice_fs.h>
33 #include <linux/version.h>
35 /* We redefine it to avoid version problems */
36 struct usb_ctrltransfer {
37 uint8_t bRequestType;
38 uint8_t bRequest;
39 uint16_t wValue;
40 uint16_t wIndex;
41 uint16_t wLength;
42 uint32_t timeout;
43 void *data;
44 };
46 typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
47 int vendor_id, int product_id,
48 const char *product_name, int speed);
49 static int usb_host_find_device(int *pbus_num, int *paddr,
50 char *product_name, int product_name_size,
51 const char *devname);
53 //#define DEBUG
55 #define USBDEVFS_PATH "/proc/bus/usb"
56 #define PRODUCT_NAME_SZ 32
58 typedef struct USBHostDevice {
59 USBDevice dev;
60 int fd;
61 } USBHostDevice;
63 static void usb_host_handle_reset(USBDevice *dev)
64 {
65 #if 0
66 USBHostDevice *s = (USBHostDevice *)dev;
67 /* USBDEVFS_RESET, but not the first time as it has already be
68 done by the host OS */
69 ioctl(s->fd, USBDEVFS_RESET);
70 #endif
71 }
73 static void usb_host_handle_destroy(USBDevice *dev)
74 {
75 USBHostDevice *s = (USBHostDevice *)dev;
77 if (s->fd >= 0)
78 close(s->fd);
79 qemu_free(s);
80 }
82 static int usb_host_handle_control(USBDevice *dev,
83 int request,
84 int value,
85 int index,
86 int length,
87 uint8_t *data)
88 {
89 USBHostDevice *s = (USBHostDevice *)dev;
90 struct usb_ctrltransfer ct;
91 int ret;
93 if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
94 /* specific SET_ADDRESS support */
95 dev->addr = value;
96 return 0;
97 } else {
98 ct.bRequestType = request >> 8;
99 ct.bRequest = request;
100 ct.wValue = value;
101 ct.wIndex = index;
102 ct.wLength = length;
103 ct.timeout = 50;
104 ct.data = data;
105 ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
106 if (ret < 0) {
107 switch(errno) {
108 case ETIMEDOUT:
109 return USB_RET_NAK;
110 default:
111 return USB_RET_STALL;
112 }
113 } else {
114 return ret;
115 }
116 }
117 }
119 static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
120 {
121 USBHostDevice *s = (USBHostDevice *)dev;
122 struct usbdevfs_bulktransfer bt;
123 int ret;
124 uint8_t devep = p->devep;
126 /* XXX: optimize and handle all data types by looking at the
127 config descriptor */
128 if (p->pid == USB_TOKEN_IN)
129 devep |= 0x80;
130 bt.ep = devep;
131 bt.len = p->len;
132 bt.timeout = 50;
133 bt.data = p->data;
134 ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
135 if (ret < 0) {
136 switch(errno) {
137 case ETIMEDOUT:
138 return USB_RET_NAK;
139 case EPIPE:
140 default:
141 #ifdef DEBUG
142 printf("handle_data: errno=%d\n", errno);
143 #endif
144 return USB_RET_STALL;
145 }
146 } else {
147 return ret;
148 }
149 }
151 /* XXX: exclude high speed devices or implement EHCI */
152 USBDevice *usb_host_device_open(const char *devname)
153 {
154 int fd, interface, ret, i;
155 USBHostDevice *dev;
156 struct usbdevfs_connectinfo ci;
157 uint8_t descr[1024];
158 char buf[1024];
159 int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
160 int bus_num, addr;
161 char product_name[PRODUCT_NAME_SZ];
163 if (usb_host_find_device(&bus_num, &addr,
164 product_name, sizeof(product_name),
165 devname) < 0)
166 return NULL;
168 snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
169 bus_num, addr);
170 fd = open(buf, O_RDWR);
171 if (fd < 0) {
172 perror(buf);
173 return NULL;
174 }
176 /* read the config description */
177 descr_len = read(fd, descr, sizeof(descr));
178 if (descr_len <= 0) {
179 perror("read descr");
180 goto fail;
181 }
183 i = 0;
184 dev_descr_len = descr[0];
185 if (dev_descr_len > descr_len)
186 goto fail;
187 i += dev_descr_len;
188 config_descr_len = descr[i];
189 if (i + config_descr_len > descr_len)
190 goto fail;
191 nb_interfaces = descr[i + 4];
192 if (nb_interfaces != 1) {
193 /* NOTE: currently we grab only one interface */
194 fprintf(stderr, "usb_host: only one interface supported\n");
195 goto fail;
196 }
198 #ifdef USBDEVFS_DISCONNECT
199 /* earlier Linux 2.4 do not support that */
200 {
201 struct usbdevfs_ioctl ctrl;
202 ctrl.ioctl_code = USBDEVFS_DISCONNECT;
203 ctrl.ifno = 0;
204 ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl);
205 if (ret < 0 && errno != ENODATA) {
206 perror("USBDEVFS_DISCONNECT");
207 goto fail;
208 }
209 }
210 #endif
212 /* XXX: only grab if all interfaces are free */
213 interface = 0;
214 ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
215 if (ret < 0) {
216 if (errno == EBUSY) {
217 fprintf(stderr, "usb_host: device already grabbed\n");
218 } else {
219 perror("USBDEVFS_CLAIMINTERFACE");
220 }
221 fail:
222 close(fd);
223 return NULL;
224 }
226 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
227 if (ret < 0) {
228 perror("USBDEVFS_CONNECTINFO");
229 goto fail;
230 }
232 #ifdef DEBUG
233 printf("host USB device %d.%d grabbed\n", bus_num, addr);
234 #endif
236 dev = qemu_mallocz(sizeof(USBHostDevice));
237 if (!dev)
238 goto fail;
239 dev->fd = fd;
240 if (ci.slow)
241 dev->dev.speed = USB_SPEED_LOW;
242 else
243 dev->dev.speed = USB_SPEED_HIGH;
244 dev->dev.handle_packet = usb_generic_handle_packet;
246 dev->dev.handle_reset = usb_host_handle_reset;
247 dev->dev.handle_control = usb_host_handle_control;
248 dev->dev.handle_data = usb_host_handle_data;
249 dev->dev.handle_destroy = usb_host_handle_destroy;
251 if (product_name[0] == '\0')
252 snprintf(dev->dev.devname, sizeof(dev->dev.devname),
253 "host:%s", devname);
254 else
255 pstrcpy(dev->dev.devname, sizeof(dev->dev.devname),
256 product_name);
258 return (USBDevice *)dev;
259 }
261 static int get_tag_value(char *buf, int buf_size,
262 const char *str, const char *tag,
263 const char *stopchars)
264 {
265 const char *p;
266 char *q;
267 p = strstr(str, tag);
268 if (!p)
269 return -1;
270 p += strlen(tag);
271 while (isspace(*p))
272 p++;
273 q = buf;
274 while (*p != '\0' && !strchr(stopchars, *p)) {
275 if ((q - buf) < (buf_size - 1))
276 *q++ = *p;
277 p++;
278 }
279 *q = '\0';
280 return q - buf;
281 }
283 static int usb_host_scan(void *opaque, USBScanFunc *func)
284 {
285 FILE *f;
286 char line[1024];
287 char buf[1024];
288 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
289 int ret;
290 char product_name[512];
292 f = fopen(USBDEVFS_PATH "/devices", "r");
293 if (!f) {
294 term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
295 return 0;
296 }
297 device_count = 0;
298 bus_num = addr = speed = class_id = product_id = vendor_id = 0;
299 ret = 0;
300 for(;;) {
301 if (fgets(line, sizeof(line), f) == NULL)
302 break;
303 if (strlen(line) > 0)
304 line[strlen(line) - 1] = '\0';
305 if (line[0] == 'T' && line[1] == ':') {
306 if (device_count && (vendor_id || product_id)) {
307 /* New device. Add the previously discovered device. */
308 ret = func(opaque, bus_num, addr, class_id, vendor_id,
309 product_id, product_name, speed);
310 if (ret)
311 goto the_end;
312 }
313 if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
314 goto fail;
315 bus_num = atoi(buf);
316 if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
317 goto fail;
318 addr = atoi(buf);
319 if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
320 goto fail;
321 if (!strcmp(buf, "480"))
322 speed = USB_SPEED_HIGH;
323 else if (!strcmp(buf, "1.5"))
324 speed = USB_SPEED_LOW;
325 else
326 speed = USB_SPEED_FULL;
327 product_name[0] = '\0';
328 class_id = 0xff;
329 device_count++;
330 product_id = 0;
331 vendor_id = 0;
332 } else if (line[0] == 'P' && line[1] == ':') {
333 if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
334 goto fail;
335 vendor_id = strtoul(buf, NULL, 16);
336 if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
337 goto fail;
338 product_id = strtoul(buf, NULL, 16);
339 } else if (line[0] == 'S' && line[1] == ':') {
340 if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
341 goto fail;
342 pstrcpy(product_name, sizeof(product_name), buf);
343 } else if (line[0] == 'D' && line[1] == ':') {
344 if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
345 goto fail;
346 class_id = strtoul(buf, NULL, 16);
347 }
348 fail: ;
349 }
350 if (device_count && (vendor_id || product_id)) {
351 /* Add the last device. */
352 ret = func(opaque, bus_num, addr, class_id, vendor_id,
353 product_id, product_name, speed);
354 }
355 the_end:
356 fclose(f);
357 return ret;
358 }
360 typedef struct FindDeviceState {
361 int vendor_id;
362 int product_id;
363 int bus_num;
364 int addr;
365 char product_name[PRODUCT_NAME_SZ];
366 } FindDeviceState;
368 static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
369 int class_id,
370 int vendor_id, int product_id,
371 const char *product_name, int speed)
372 {
373 FindDeviceState *s = opaque;
374 if ((vendor_id == s->vendor_id &&
375 product_id == s->product_id) ||
376 (bus_num == s->bus_num &&
377 addr == s->addr)) {
378 pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name);
379 s->bus_num = bus_num;
380 s->addr = addr;
381 return 1;
382 } else {
383 return 0;
384 }
385 }
387 /* the syntax is :
388 'bus.addr' (decimal numbers) or
389 'vendor_id:product_id' (hexa numbers) */
390 static int usb_host_find_device(int *pbus_num, int *paddr,
391 char *product_name, int product_name_size,
392 const char *devname)
393 {
394 const char *p;
395 int ret;
396 FindDeviceState fs;
398 p = strchr(devname, '.');
399 if (p) {
400 *pbus_num = strtoul(devname, NULL, 0);
401 *paddr = strtoul(p + 1, NULL, 0);
402 fs.bus_num = *pbus_num;
403 fs.addr = *paddr;
404 ret = usb_host_scan(&fs, usb_host_find_device_scan);
405 if (ret)
406 pstrcpy(product_name, product_name_size, fs.product_name);
407 return 0;
408 }
409 p = strchr(devname, ':');
410 if (p) {
411 fs.vendor_id = strtoul(devname, NULL, 16);
412 fs.product_id = strtoul(p + 1, NULL, 16);
413 ret = usb_host_scan(&fs, usb_host_find_device_scan);
414 if (ret) {
415 *pbus_num = fs.bus_num;
416 *paddr = fs.addr;
417 pstrcpy(product_name, product_name_size, fs.product_name);
418 return 0;
419 }
420 }
421 return -1;
422 }
424 /**********************/
425 /* USB host device info */
427 struct usb_class_info {
428 int class;
429 const char *class_name;
430 };
432 static const struct usb_class_info usb_class_info[] = {
433 { USB_CLASS_AUDIO, "Audio"},
434 { USB_CLASS_COMM, "Communication"},
435 { USB_CLASS_HID, "HID"},
436 { USB_CLASS_HUB, "Hub" },
437 { USB_CLASS_PHYSICAL, "Physical" },
438 { USB_CLASS_PRINTER, "Printer" },
439 { USB_CLASS_MASS_STORAGE, "Storage" },
440 { USB_CLASS_CDC_DATA, "Data" },
441 { USB_CLASS_APP_SPEC, "Application Specific" },
442 { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
443 { USB_CLASS_STILL_IMAGE, "Still Image" },
444 { USB_CLASS_CSCID, "Smart Card" },
445 { USB_CLASS_CONTENT_SEC, "Content Security" },
446 { -1, NULL }
447 };
449 static const char *usb_class_str(uint8_t class)
450 {
451 const struct usb_class_info *p;
452 for(p = usb_class_info; p->class != -1; p++) {
453 if (p->class == class)
454 break;
455 }
456 return p->class_name;
457 }
459 void usb_info_device(int bus_num, int addr, int class_id,
460 int vendor_id, int product_id,
461 const char *product_name,
462 int speed)
463 {
464 const char *class_str, *speed_str;
466 switch(speed) {
467 case USB_SPEED_LOW:
468 speed_str = "1.5";
469 break;
470 case USB_SPEED_FULL:
471 speed_str = "12";
472 break;
473 case USB_SPEED_HIGH:
474 speed_str = "480";
475 break;
476 default:
477 speed_str = "?";
478 break;
479 }
481 term_printf(" Device %d.%d, speed %s Mb/s\n",
482 bus_num, addr, speed_str);
483 class_str = usb_class_str(class_id);
484 if (class_str)
485 term_printf(" %s:", class_str);
486 else
487 term_printf(" Class %02x:", class_id);
488 term_printf(" USB device %04x:%04x", vendor_id, product_id);
489 if (product_name[0] != '\0')
490 term_printf(", %s", product_name);
491 term_printf("\n");
492 }
494 static int usb_host_info_device(void *opaque, int bus_num, int addr,
495 int class_id,
496 int vendor_id, int product_id,
497 const char *product_name,
498 int speed)
499 {
500 usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
501 product_name, speed);
502 return 0;
503 }
505 void usb_host_info(void)
506 {
507 usb_host_scan(NULL, usb_host_info_device);
508 }
510 #else
512 void usb_host_info(void)
513 {
514 term_printf("USB host devices not supported\n");
515 }
517 /* XXX: modify configure to compile the right host driver */
518 USBDevice *usb_host_device_open(const char *devname)
519 {
520 return NULL;
521 }
523 #endif