Revision 26a9e82a
b/usb-linux.c | ||
---|---|---|
64 | 64 |
typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id, |
65 | 65 |
int vendor_id, int product_id, |
66 | 66 |
const char *product_name, int speed); |
67 |
static int usb_host_find_device(int *pbus_num, int *paddr, |
|
68 |
char *product_name, int product_name_size, |
|
69 |
const char *devname); |
|
70 |
//#define DEBUG |
|
67 |
|
|
68 |
#define DEBUG |
|
71 | 69 |
|
72 | 70 |
#ifdef DEBUG |
73 | 71 |
#define dprintf printf |
... | ... | |
118 | 116 |
uint8_t buffer[2048]; |
119 | 117 |
}; |
120 | 118 |
|
119 |
struct USBAutoFilter { |
|
120 |
uint32_t bus_num; |
|
121 |
uint32_t addr; |
|
122 |
uint32_t vendor_id; |
|
123 |
uint32_t product_id; |
|
124 |
}; |
|
125 |
|
|
121 | 126 |
typedef struct USBHostDevice { |
122 | 127 |
USBDevice dev; |
123 | 128 |
int fd; |
... | ... | |
134 | 139 |
/* Host side address */ |
135 | 140 |
int bus_num; |
136 | 141 |
int addr; |
142 |
struct USBAutoFilter match; |
|
137 | 143 |
|
138 |
struct USBHostDevice *next;
|
|
144 |
QTAILQ_ENTRY(USBHostDevice) next;
|
|
139 | 145 |
} USBHostDevice; |
140 | 146 |
|
147 |
static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs); |
|
148 |
|
|
149 |
static int usb_host_close(USBHostDevice *dev); |
|
150 |
static int parse_filter(const char *spec, struct USBAutoFilter *f); |
|
151 |
static void usb_host_auto_check(void *unused); |
|
152 |
|
|
141 | 153 |
static int is_isoc(USBHostDevice *s, int ep) |
142 | 154 |
{ |
143 | 155 |
return s->endp_table[ep - 1].type == USBDEVFS_URB_TYPE_ISO; |
... | ... | |
158 | 170 |
s->endp_table[ep - 1].halted = 1; |
159 | 171 |
} |
160 | 172 |
|
161 |
static USBHostDevice *hostdev_list; |
|
162 |
|
|
163 |
static void hostdev_link(USBHostDevice *dev) |
|
164 |
{ |
|
165 |
dev->next = hostdev_list; |
|
166 |
hostdev_list = dev; |
|
167 |
} |
|
168 |
|
|
169 |
static void hostdev_unlink(USBHostDevice *dev) |
|
170 |
{ |
|
171 |
USBHostDevice *pdev = hostdev_list; |
|
172 |
USBHostDevice **prev = &hostdev_list; |
|
173 |
|
|
174 |
while (pdev) { |
|
175 |
if (pdev == dev) { |
|
176 |
*prev = dev->next; |
|
177 |
return; |
|
178 |
} |
|
179 |
|
|
180 |
prev = &pdev->next; |
|
181 |
pdev = pdev->next; |
|
182 |
} |
|
183 |
} |
|
184 |
|
|
185 |
static USBHostDevice *hostdev_find(int bus_num, int addr) |
|
186 |
{ |
|
187 |
USBHostDevice *s = hostdev_list; |
|
188 |
while (s) { |
|
189 |
if (s->bus_num == bus_num && s->addr == addr) |
|
190 |
return s; |
|
191 |
s = s->next; |
|
192 |
} |
|
193 |
return NULL; |
|
194 |
} |
|
195 |
|
|
196 | 173 |
/* |
197 | 174 |
* Async URB state. |
198 | 175 |
* We always allocate one isoc descriptor even for bulk transfers |
... | ... | |
252 | 229 |
|
253 | 230 |
if (errno == ENODEV && !s->closing) { |
254 | 231 |
printf("husb: device %d.%d disconnected\n", s->bus_num, s->addr); |
255 |
usb_device_delete_addr(s->bus_num, s->dev.addr); |
|
232 |
usb_host_close(s); |
|
233 |
usb_host_auto_check(NULL); |
|
256 | 234 |
return; |
257 | 235 |
} |
258 | 236 |
|
... | ... | |
407 | 385 |
|
408 | 386 |
static void usb_host_handle_reset(USBDevice *dev) |
409 | 387 |
{ |
410 |
USBHostDevice *s = (USBHostDevice *) dev;
|
|
388 |
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
|
|
411 | 389 |
|
412 | 390 |
dprintf("husb: reset device %u.%u\n", s->bus_num, s->addr); |
413 | 391 |
|
... | ... | |
420 | 398 |
{ |
421 | 399 |
USBHostDevice *s = (USBHostDevice *)dev; |
422 | 400 |
|
423 |
s->closing = 1; |
|
424 |
|
|
425 |
qemu_set_fd_handler(s->fd, NULL, NULL, NULL); |
|
426 |
|
|
427 |
hostdev_unlink(s); |
|
428 |
|
|
429 |
async_complete(s); |
|
430 |
|
|
431 |
if (s->fd >= 0) |
|
432 |
close(s->fd); |
|
433 |
|
|
434 |
qemu_free(s); |
|
401 |
usb_host_close(s); |
|
402 |
QTAILQ_REMOVE(&hostdevs, s, next); |
|
435 | 403 |
} |
436 | 404 |
|
437 | 405 |
static int usb_linux_update_endp_table(USBHostDevice *s); |
... | ... | |
891 | 859 |
return 0; |
892 | 860 |
} |
893 | 861 |
|
894 |
static int usb_host_initfn(USBDevice *dev) |
|
895 |
{ |
|
896 |
return 0; |
|
897 |
} |
|
898 |
|
|
899 |
static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *prod_name) |
|
862 |
static int usb_host_open(USBHostDevice *dev, int bus_num, |
|
863 |
int addr, const char *prod_name) |
|
900 | 864 |
{ |
901 | 865 |
int fd = -1, ret; |
902 |
USBDevice *d = NULL; |
|
903 |
USBHostDevice *dev; |
|
904 | 866 |
struct usbdevfs_connectinfo ci; |
905 | 867 |
char buf[1024]; |
906 | 868 |
|
869 |
if (dev->fd != -1) |
|
870 |
goto fail; |
|
871 |
|
|
907 | 872 |
printf("husb: open device %d.%d\n", bus_num, addr); |
908 | 873 |
|
909 | 874 |
if (!usb_host_device_path) { |
... | ... | |
919 | 884 |
} |
920 | 885 |
dprintf("husb: opened %s\n", buf); |
921 | 886 |
|
922 |
d = usb_create(NULL /* FIXME */, "USB Host Device"); |
|
923 |
dev = DO_UPCAST(USBHostDevice, dev, d); |
|
924 |
|
|
925 | 887 |
dev->bus_num = bus_num; |
926 | 888 |
dev->addr = addr; |
927 | 889 |
dev->fd = fd; |
... | ... | |
980 | 942 |
/* USB devio uses 'write' flag to check for async completions */ |
981 | 943 |
qemu_set_fd_handler(dev->fd, NULL, async_complete, dev); |
982 | 944 |
|
983 |
hostdev_link(dev); |
|
984 |
|
|
985 |
if (qdev_init(&d->qdev) < 0) |
|
986 |
goto fail_no_qdev; |
|
987 |
return (USBDevice *) dev; |
|
945 |
usb_device_attach(&dev->dev); |
|
946 |
return 0; |
|
988 | 947 |
|
989 | 948 |
fail: |
990 |
if (d) |
|
991 |
qdev_free(&d->qdev); |
|
992 |
fail_no_qdev: |
|
949 |
dev->fd = -1; |
|
993 | 950 |
if (fd != -1) |
994 | 951 |
close(fd); |
995 |
return NULL; |
|
952 |
return -1; |
|
953 |
} |
|
954 |
|
|
955 |
static int usb_host_close(USBHostDevice *dev) |
|
956 |
{ |
|
957 |
if (dev->fd == -1) |
|
958 |
return -1; |
|
959 |
|
|
960 |
qemu_set_fd_handler(dev->fd, NULL, NULL, NULL); |
|
961 |
dev->closing = 1; |
|
962 |
async_complete(dev); |
|
963 |
dev->closing = 0; |
|
964 |
usb_device_detach(&dev->dev); |
|
965 |
close(dev->fd); |
|
966 |
dev->fd = -1; |
|
967 |
return 0; |
|
968 |
} |
|
969 |
|
|
970 |
static int usb_host_initfn(USBDevice *dev) |
|
971 |
{ |
|
972 |
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); |
|
973 |
|
|
974 |
dev->auto_attach = 0; |
|
975 |
s->fd = -1; |
|
976 |
QTAILQ_INSERT_TAIL(&hostdevs, s, next); |
|
977 |
usb_host_auto_check(NULL); |
|
978 |
return 0; |
|
996 | 979 |
} |
997 | 980 |
|
998 | 981 |
static struct USBDeviceInfo usb_host_dev_info = { |
999 | 982 |
.qdev.name = "USB Host Device", |
983 |
.qdev.alias = "usb-host", |
|
1000 | 984 |
.qdev.size = sizeof(USBHostDevice), |
1001 | 985 |
.init = usb_host_initfn, |
1002 | 986 |
.handle_packet = usb_host_handle_packet, |
1003 | 987 |
.handle_reset = usb_host_handle_reset, |
1004 |
#if 0 |
|
1005 |
.handle_control = usb_host_handle_control, |
|
1006 |
.handle_data = usb_host_handle_data, |
|
1007 |
#endif |
|
1008 | 988 |
.handle_destroy = usb_host_handle_destroy, |
989 |
.usbdevice_name = "host", |
|
990 |
.usbdevice_init = usb_host_device_open, |
|
991 |
.qdev.props = (Property[]) { |
|
992 |
DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0), |
|
993 |
DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0), |
|
994 |
DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0), |
|
995 |
DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0), |
|
996 |
DEFINE_PROP_END_OF_LIST(), |
|
997 |
}, |
|
1009 | 998 |
}; |
1010 | 999 |
|
1011 | 1000 |
static void usb_host_register_devices(void) |
... | ... | |
1014 | 1003 |
} |
1015 | 1004 |
device_init(usb_host_register_devices) |
1016 | 1005 |
|
1017 |
static int usb_host_auto_add(const char *spec); |
|
1018 |
static int usb_host_auto_del(const char *spec); |
|
1019 |
|
|
1020 | 1006 |
USBDevice *usb_host_device_open(const char *devname) |
1021 | 1007 |
{ |
1022 |
Monitor *mon = cur_mon; |
|
1023 |
int bus_num, addr; |
|
1024 |
char product_name[PRODUCT_NAME_SZ]; |
|
1008 |
struct USBAutoFilter filter = { 0, 0, 0, 0 }; |
|
1009 |
USBDevice *dev; |
|
1010 |
USBHostDevice *s; |
|
1011 |
char *p; |
|
1012 |
|
|
1013 |
dev = usb_create(NULL /* FIXME */, "USB Host Device"); |
|
1014 |
s = DO_UPCAST(USBHostDevice, dev, dev); |
|
1025 | 1015 |
|
1026 | 1016 |
if (strstr(devname, "auto:")) { |
1027 |
usb_host_auto_add(devname); |
|
1028 |
return NULL; |
|
1017 |
if (parse_filter(devname+5, &filter) < 0) |
|
1018 |
goto fail; |
|
1019 |
} else { |
|
1020 |
if ((p = strchr(devname, '.'))) { |
|
1021 |
filter.bus_num = strtoul(devname, NULL, 0); |
|
1022 |
filter.addr = strtoul(devname, NULL, 0); |
|
1023 |
} else if ((p = strchr(devname, ':'))) { |
|
1024 |
filter.vendor_id = strtoul(devname, NULL, 16); |
|
1025 |
filter.product_id = strtoul(devname, NULL, 16); |
|
1026 |
} else { |
|
1027 |
goto fail; |
|
1028 |
} |
|
1029 | 1029 |
} |
1030 | 1030 |
|
1031 |
if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name), |
|
1032 |
devname) < 0) |
|
1033 |
return NULL; |
|
1031 |
qdev_prop_set_uint32(&dev->qdev, "bus", filter.bus_num); |
|
1032 |
qdev_prop_set_uint32(&dev->qdev, "addr", filter.addr); |
|
1033 |
qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id); |
|
1034 |
qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id); |
|
1035 |
qdev_init(&dev->qdev); |
|
1036 |
return dev; |
|
1034 | 1037 |
|
1035 |
if (hostdev_find(bus_num, addr)) { |
|
1036 |
monitor_printf(mon, "husb: host usb device %d.%d is already open\n", |
|
1037 |
bus_num, addr); |
|
1038 |
return NULL; |
|
1039 |
} |
|
1040 |
|
|
1041 |
return usb_host_device_open_addr(bus_num, addr, product_name); |
|
1038 |
fail: |
|
1039 |
qdev_free(&dev->qdev); |
|
1040 |
return NULL; |
|
1042 | 1041 |
} |
1043 | 1042 |
|
1044 | 1043 |
int usb_host_device_close(const char *devname) |
1045 | 1044 |
{ |
1045 |
#if 0 |
|
1046 | 1046 |
char product_name[PRODUCT_NAME_SZ]; |
1047 | 1047 |
int bus_num, addr; |
1048 | 1048 |
USBHostDevice *s; |
... | ... | |
1059 | 1059 |
usb_device_delete_addr(s->bus_num, s->dev.addr); |
1060 | 1060 |
return 0; |
1061 | 1061 |
} |
1062 |
#endif |
|
1062 | 1063 |
|
1063 | 1064 |
return -1; |
1064 | 1065 |
} |
... | ... | |
1185 | 1186 |
*/ |
1186 | 1187 |
static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name) |
1187 | 1188 |
{ |
1189 |
#if 0 |
|
1188 | 1190 |
Monitor *mon = cur_mon; |
1191 |
#endif |
|
1189 | 1192 |
FILE *f; |
1190 | 1193 |
int ret = 0; |
1191 | 1194 |
char filename[PATH_MAX]; |
... | ... | |
1197 | 1200 |
fgets(line, line_size, f); |
1198 | 1201 |
fclose(f); |
1199 | 1202 |
ret = 1; |
1203 |
#if 0 |
|
1200 | 1204 |
} else { |
1201 | 1205 |
monitor_printf(mon, "husb: could not open %s\n", filename); |
1206 |
#endif |
|
1202 | 1207 |
} |
1203 | 1208 |
|
1204 | 1209 |
return ret; |
... | ... | |
1356 | 1361 |
return ret; |
1357 | 1362 |
} |
1358 | 1363 |
|
1359 |
struct USBAutoFilter { |
|
1360 |
struct USBAutoFilter *next; |
|
1361 |
int bus_num; |
|
1362 |
int addr; |
|
1363 |
int vendor_id; |
|
1364 |
int product_id; |
|
1365 |
}; |
|
1366 |
|
|
1367 | 1364 |
static QEMUTimer *usb_auto_timer; |
1368 |
static struct USBAutoFilter *usb_auto_filter; |
|
1369 | 1365 |
|
1370 | 1366 |
static int usb_host_auto_scan(void *opaque, int bus_num, int addr, |
1371 |
int class_id, int vendor_id, int product_id, |
|
1372 |
const char *product_name, int speed) |
|
1367 |
int class_id, int vendor_id, int product_id,
|
|
1368 |
const char *product_name, int speed)
|
|
1373 | 1369 |
{ |
1374 | 1370 |
struct USBAutoFilter *f; |
1375 |
struct USBDevice *dev;
|
|
1371 |
struct USBHostDevice *s;
|
|
1376 | 1372 |
|
1377 | 1373 |
/* Ignore hubs */ |
1378 | 1374 |
if (class_id == 9) |
1379 | 1375 |
return 0; |
1380 | 1376 |
|
1381 |
for (f = usb_auto_filter; f; f = f->next) { |
|
1382 |
if (f->bus_num >= 0 && f->bus_num != bus_num) |
|
1377 |
QTAILQ_FOREACH(s, &hostdevs, next) { |
|
1378 |
f = &s->match; |
|
1379 |
|
|
1380 |
if (f->bus_num > 0 && f->bus_num != bus_num) |
|
1383 | 1381 |
continue; |
1384 | 1382 |
|
1385 |
if (f->addr >= 0 && f->addr != addr)
|
|
1383 |
if (f->addr > 0 && f->addr != addr) |
|
1386 | 1384 |
continue; |
1387 | 1385 |
|
1388 |
if (f->vendor_id >= 0 && f->vendor_id != vendor_id)
|
|
1386 |
if (f->vendor_id > 0 && f->vendor_id != vendor_id) |
|
1389 | 1387 |
continue; |
1390 | 1388 |
|
1391 |
if (f->product_id >= 0 && f->product_id != product_id)
|
|
1389 |
if (f->product_id > 0 && f->product_id != product_id) |
|
1392 | 1390 |
continue; |
1393 | 1391 |
|
1394 | 1392 |
/* We got a match */ |
1395 | 1393 |
|
1396 | 1394 |
/* Already attached ? */ |
1397 |
if (hostdev_find(bus_num, addr))
|
|
1395 |
if (s->fd != -1)
|
|
1398 | 1396 |
return 0; |
1399 | 1397 |
|
1400 | 1398 |
dprintf("husb: auto open: bus_num %d addr %d\n", bus_num, addr); |
1401 | 1399 |
|
1402 |
dev = usb_host_device_open_addr(bus_num, addr, product_name);
|
|
1400 |
usb_host_open(s, bus_num, addr, product_name);
|
|
1403 | 1401 |
} |
1404 | 1402 |
|
1405 | 1403 |
return 0; |
1406 | 1404 |
} |
1407 | 1405 |
|
1408 |
static void usb_host_auto_timer(void *unused)
|
|
1406 |
static void usb_host_auto_check(void *unused)
|
|
1409 | 1407 |
{ |
1408 |
struct USBHostDevice *s; |
|
1409 |
int unconnected = 0; |
|
1410 |
|
|
1410 | 1411 |
usb_host_scan(NULL, usb_host_auto_scan); |
1412 |
|
|
1413 |
QTAILQ_FOREACH(s, &hostdevs, next) { |
|
1414 |
if (s->fd == -1) |
|
1415 |
unconnected++; |
|
1416 |
} |
|
1417 |
|
|
1418 |
if (unconnected == 0) { |
|
1419 |
/* nothing to watch */ |
|
1420 |
if (usb_auto_timer) |
|
1421 |
qemu_del_timer(usb_auto_timer); |
|
1422 |
return; |
|
1423 |
} |
|
1424 |
|
|
1425 |
if (!usb_auto_timer) { |
|
1426 |
usb_auto_timer = qemu_new_timer(rt_clock, usb_host_auto_check, NULL); |
|
1427 |
if (!usb_auto_timer) |
|
1428 |
return; |
|
1429 |
} |
|
1411 | 1430 |
qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000); |
1412 | 1431 |
} |
1413 | 1432 |
|
... | ... | |
1459 | 1478 |
return 0; |
1460 | 1479 |
} |
1461 | 1480 |
|
1462 |
static int match_filter(const struct USBAutoFilter *f1, |
|
1463 |
const struct USBAutoFilter *f2) |
|
1464 |
{ |
|
1465 |
return f1->bus_num == f2->bus_num && |
|
1466 |
f1->addr == f2->addr && |
|
1467 |
f1->vendor_id == f2->vendor_id && |
|
1468 |
f1->product_id == f2->product_id; |
|
1469 |
} |
|
1470 |
|
|
1471 |
static int usb_host_auto_add(const char *spec) |
|
1472 |
{ |
|
1473 |
struct USBAutoFilter filter, *f; |
|
1474 |
|
|
1475 |
if (parse_filter(spec, &filter) < 0) |
|
1476 |
return -1; |
|
1477 |
|
|
1478 |
f = qemu_mallocz(sizeof(*f)); |
|
1479 |
|
|
1480 |
*f = filter; |
|
1481 |
|
|
1482 |
if (!usb_auto_filter) { |
|
1483 |
/* |
|
1484 |
* First entry. Init and start the monitor. |
|
1485 |
* Right now we're using timer to check for new devices. |
|
1486 |
* If this turns out to be too expensive we can move that into a |
|
1487 |
* separate thread. |
|
1488 |
*/ |
|
1489 |
usb_auto_timer = qemu_new_timer(rt_clock, usb_host_auto_timer, NULL); |
|
1490 |
if (!usb_auto_timer) { |
|
1491 |
fprintf(stderr, "husb: failed to allocate auto scan timer\n"); |
|
1492 |
qemu_free(f); |
|
1493 |
return -1; |
|
1494 |
} |
|
1495 |
|
|
1496 |
/* Check for new devices every two seconds */ |
|
1497 |
qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000); |
|
1498 |
} |
|
1499 |
|
|
1500 |
dprintf("husb: added auto filter: bus_num %d addr %d vid %d pid %d\n", |
|
1501 |
f->bus_num, f->addr, f->vendor_id, f->product_id); |
|
1502 |
|
|
1503 |
f->next = usb_auto_filter; |
|
1504 |
usb_auto_filter = f; |
|
1505 |
|
|
1506 |
return 0; |
|
1507 |
} |
|
1508 |
|
|
1509 |
static int usb_host_auto_del(const char *spec) |
|
1510 |
{ |
|
1511 |
struct USBAutoFilter *pf = usb_auto_filter; |
|
1512 |
struct USBAutoFilter **prev = &usb_auto_filter; |
|
1513 |
struct USBAutoFilter filter; |
|
1514 |
|
|
1515 |
if (parse_filter(spec, &filter) < 0) |
|
1516 |
return -1; |
|
1517 |
|
|
1518 |
while (pf) { |
|
1519 |
if (match_filter(pf, &filter)) { |
|
1520 |
dprintf("husb: removed auto filter: bus_num %d addr %d vid %d pid %d\n", |
|
1521 |
pf->bus_num, pf->addr, pf->vendor_id, pf->product_id); |
|
1522 |
|
|
1523 |
*prev = pf->next; |
|
1524 |
|
|
1525 |
if (!usb_auto_filter) { |
|
1526 |
/* No more filters. Stop scanning. */ |
|
1527 |
qemu_del_timer(usb_auto_timer); |
|
1528 |
qemu_free_timer(usb_auto_timer); |
|
1529 |
} |
|
1530 |
|
|
1531 |
return 0; |
|
1532 |
} |
|
1533 |
|
|
1534 |
prev = &pf->next; |
|
1535 |
pf = pf->next; |
|
1536 |
} |
|
1537 |
|
|
1538 |
return -1; |
|
1539 |
} |
|
1540 |
|
|
1541 |
typedef struct FindDeviceState { |
|
1542 |
int vendor_id; |
|
1543 |
int product_id; |
|
1544 |
int bus_num; |
|
1545 |
int addr; |
|
1546 |
char product_name[PRODUCT_NAME_SZ]; |
|
1547 |
} FindDeviceState; |
|
1548 |
|
|
1549 |
static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, |
|
1550 |
int class_id, |
|
1551 |
int vendor_id, int product_id, |
|
1552 |
const char *product_name, int speed) |
|
1553 |
{ |
|
1554 |
FindDeviceState *s = opaque; |
|
1555 |
if ((vendor_id == s->vendor_id && |
|
1556 |
product_id == s->product_id) || |
|
1557 |
(bus_num == s->bus_num && |
|
1558 |
addr == s->addr)) { |
|
1559 |
pstrcpy(s->product_name, PRODUCT_NAME_SZ, product_name); |
|
1560 |
s->bus_num = bus_num; |
|
1561 |
s->addr = addr; |
|
1562 |
return 1; |
|
1563 |
} else { |
|
1564 |
return 0; |
|
1565 |
} |
|
1566 |
} |
|
1567 |
|
|
1568 |
/* the syntax is : |
|
1569 |
'bus.addr' (decimal numbers) or |
|
1570 |
'vendor_id:product_id' (hexa numbers) */ |
|
1571 |
static int usb_host_find_device(int *pbus_num, int *paddr, |
|
1572 |
char *product_name, int product_name_size, |
|
1573 |
const char *devname) |
|
1574 |
{ |
|
1575 |
const char *p; |
|
1576 |
int ret; |
|
1577 |
FindDeviceState fs; |
|
1578 |
|
|
1579 |
p = strchr(devname, '.'); |
|
1580 |
if (p) { |
|
1581 |
*pbus_num = strtoul(devname, NULL, 0); |
|
1582 |
*paddr = strtoul(p + 1, NULL, 0); |
|
1583 |
fs.bus_num = *pbus_num; |
|
1584 |
fs.addr = *paddr; |
|
1585 |
ret = usb_host_scan(&fs, usb_host_find_device_scan); |
|
1586 |
if (ret) |
|
1587 |
pstrcpy(product_name, product_name_size, fs.product_name); |
|
1588 |
return 0; |
|
1589 |
} |
|
1590 |
|
|
1591 |
p = strchr(devname, ':'); |
|
1592 |
if (p) { |
|
1593 |
fs.vendor_id = strtoul(devname, NULL, 16); |
|
1594 |
fs.product_id = strtoul(p + 1, NULL, 16); |
|
1595 |
ret = usb_host_scan(&fs, usb_host_find_device_scan); |
|
1596 |
if (ret) { |
|
1597 |
*pbus_num = fs.bus_num; |
|
1598 |
*paddr = fs.addr; |
|
1599 |
pstrcpy(product_name, product_name_size, fs.product_name); |
|
1600 |
return 0; |
|
1601 |
} |
|
1602 |
} |
|
1603 |
return -1; |
|
1604 |
} |
|
1605 |
|
|
1606 | 1481 |
/**********************/ |
1607 | 1482 |
/* USB host device info */ |
1608 | 1483 |
|
... | ... | |
1688 | 1563 |
|
1689 | 1564 |
static void dec2str(int val, char *str, size_t size) |
1690 | 1565 |
{ |
1691 |
if (val == -1)
|
|
1566 |
if (val == 0)
|
|
1692 | 1567 |
snprintf(str, size, "*"); |
1693 | 1568 |
else |
1694 | 1569 |
snprintf(str, size, "%d", val); |
... | ... | |
1696 | 1571 |
|
1697 | 1572 |
static void hex2str(int val, char *str, size_t size) |
1698 | 1573 |
{ |
1699 |
if (val == -1)
|
|
1574 |
if (val == 0)
|
|
1700 | 1575 |
snprintf(str, size, "*"); |
1701 | 1576 |
else |
1702 |
snprintf(str, size, "%x", val); |
|
1577 |
snprintf(str, size, "%04x", val);
|
|
1703 | 1578 |
} |
1704 | 1579 |
|
1705 | 1580 |
void usb_host_info(Monitor *mon) |
1706 | 1581 |
{ |
1707 | 1582 |
struct USBAutoFilter *f; |
1583 |
struct USBHostDevice *s; |
|
1708 | 1584 |
|
1709 | 1585 |
usb_host_scan(mon, usb_host_info_device); |
1710 | 1586 |
|
1711 |
if (usb_auto_filter) |
|
1712 |
monitor_printf(mon, " Auto filters:\n"); |
|
1713 |
for (f = usb_auto_filter; f; f = f->next) { |
|
1587 |
if (QTAILQ_EMPTY(&hostdevs)) |
|
1588 |
return; |
|
1589 |
monitor_printf(mon, " Auto filters:\n"); |
|
1590 |
QTAILQ_FOREACH(s, &hostdevs, next) { |
|
1714 | 1591 |
char bus[10], addr[10], vid[10], pid[10]; |
1592 |
f = &s->match; |
|
1715 | 1593 |
dec2str(f->bus_num, bus, sizeof(bus)); |
1716 | 1594 |
dec2str(f->addr, addr, sizeof(addr)); |
1717 | 1595 |
hex2str(f->vendor_id, vid, sizeof(vid)); |
Also available in: Unified diff