Commit 5d0c5750bb19212c8ecfb9660956611baf6aa861

Authored by aliguori
1 parent 446ab128

usb: Support for removing device by host addr, improved auto filter syntax (Max Krasnyansky)

This patch adds support for removing USB devices by host address.
Which is usefull for things like libvirtd because there is no easy way to
find guest USB address of the host device.
In other words you can now do:
   usb_add host:3.5
   ...
   usb_del host:3.5
Before the patch 'usb_del' did not support 'host:' notation.

----
Syntax for specifying auto connect filters has been improved.
Old syntax was
    host:bus.dev
    host:pid:vid
New syntax is
    host:auto:bus.dev[:pid:vid]
In both the cases any attribute can be set to "*".

New syntax is more flexible and lets you do things like
    host:3.*:5533:* /* grab any device on bus 3 with vendor id 5533 */

It's now possible to remove auto filters. For example:
    usb_del host:auto:3.*:5533:*

Active filters are printed after all host devices in 'info usb' output.
Which now looks like this:

  Device 1.1, speed 480 Mb/s
    Hub: USB device 1d6b:0002, EHCI Host Controller
  Device 1.4, speed 480 Mb/s
    Class 00: USB device 1058:0704, External HDD
  Auto filters:
    Device 3.* ID *:*

Signed-off-by: Max Krasnyansky <maxk@kernel.org>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5205 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 3 changed files with 176 additions and 31 deletions
hw/usb.h
... ... @@ -240,6 +240,7 @@ USBDevice *usb_hub_init(int nb_ports);
240 240  
241 241 /* usb-linux.c */
242 242 USBDevice *usb_host_device_open(const char *devname);
  243 +int usb_host_device_close(const char *devname);
243 244 void usb_host_info(void);
244 245  
245 246 /* usb-hid.c */
... ...
usb-linux.c
... ... @@ -5,7 +5,7 @@
5 5 *
6 6 * Copyright (c) 2008 Max Krasnyansky
7 7 * Support for host device auto connect & disconnect
8   - * Magor rewrite to support fully async operation
  8 + * Major rewrite to support fully async operation
9 9 *
10 10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 11 * of this software and associated documentation files (the "Software"), to deal
... ... @@ -951,23 +951,52 @@ fail:
951 951 return NULL;
952 952 }
953 953  
  954 +static int usb_host_auto_add(const char *spec);
  955 +static int usb_host_auto_del(const char *spec);
  956 +
954 957 USBDevice *usb_host_device_open(const char *devname)
955 958 {
956 959 int bus_num, addr;
957 960 char product_name[PRODUCT_NAME_SZ];
958 961  
959   - if (usb_host_find_device(&bus_num, &addr,
960   - product_name, sizeof(product_name),
961   - devname) < 0)
  962 + if (strstr(devname, "auto:")) {
  963 + usb_host_auto_add(devname);
962 964 return NULL;
  965 + }
963 966  
964   - if (hostdev_find(bus_num, addr)) {
965   - term_printf("husb: host usb device %d.%d is already open\n", bus_num, addr);
  967 + if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name),
  968 + devname) < 0)
966 969 return NULL;
967   - }
  970 +
  971 + if (hostdev_find(bus_num, addr)) {
  972 + term_printf("husb: host usb device %d.%d is already open\n", bus_num, addr);
  973 + return NULL;
  974 + }
968 975  
969 976 return usb_host_device_open_addr(bus_num, addr, product_name);
970 977 }
  978 +
  979 +int usb_host_device_close(const char *devname)
  980 +{
  981 + char product_name[PRODUCT_NAME_SZ];
  982 + int bus_num, addr;
  983 + USBHostDevice *s;
  984 +
  985 + if (strstr(devname, "auto:"))
  986 + return usb_host_auto_del(devname);
  987 +
  988 + if (usb_host_find_device(&bus_num, &addr, product_name, sizeof(product_name),
  989 + devname) < 0)
  990 + return -1;
  991 +
  992 + s = hostdev_find(bus_num, addr);
  993 + if (s) {
  994 + usb_device_del_addr(0, s->dev.addr);
  995 + return 0;
  996 + }
  997 +
  998 + return -1;
  999 +}
971 1000  
972 1001 static int get_tag_value(char *buf, int buf_size,
973 1002 const char *str, const char *tag,
... ... @@ -1126,21 +1155,76 @@ static void usb_host_auto_timer(void *unused)
1126 1155 }
1127 1156  
1128 1157 /*
1129   - * Add autoconnect filter
1130   - * -1 means 'any' (device, vendor, etc)
  1158 + * Autoconnect filter
  1159 + * Format:
  1160 + * auto:bus:dev[:vid:pid]
  1161 + * auto:bus.dev[:vid:pid]
  1162 + *
  1163 + * bus - bus number (dec, * means any)
  1164 + * dev - device number (dec, * means any)
  1165 + * vid - vendor id (hex, * means any)
  1166 + * pid - product id (hex, * means any)
  1167 + *
  1168 + * See 'lsusb' output.
1131 1169 */
1132   -static void usb_host_auto_add(int bus_num, int addr, int vendor_id, int product_id)
  1170 +static int parse_filter(const char *spec, struct USBAutoFilter *f)
1133 1171 {
1134   - struct USBAutoFilter *f = qemu_mallocz(sizeof(*f));
  1172 + enum { BUS, DEV, VID, PID, DONE };
  1173 + const char *p = spec;
  1174 + int i;
  1175 +
  1176 + f->bus_num = -1;
  1177 + f->addr = -1;
  1178 + f->vendor_id = -1;
  1179 + f->product_id = -1;
  1180 +
  1181 + for (i = BUS; i < DONE; i++) {
  1182 + p = strpbrk(p, ":.");
  1183 + if (!p) break;
  1184 + p++;
  1185 +
  1186 + if (*p == '*')
  1187 + continue;
  1188 +
  1189 + switch(i) {
  1190 + case BUS: f->bus_num = strtol(p, NULL, 10); break;
  1191 + case DEV: f->addr = strtol(p, NULL, 10); break;
  1192 + case VID: f->vendor_id = strtol(p, NULL, 16); break;
  1193 + case PID: f->product_id = strtol(p, NULL, 16); break;
  1194 + }
  1195 + }
  1196 +
  1197 + if (i < DEV) {
  1198 + fprintf(stderr, "husb: invalid auto filter spec %s\n", spec);
  1199 + return -1;
  1200 + }
  1201 +
  1202 + return 0;
  1203 +}
  1204 +
  1205 +static int match_filter(const struct USBAutoFilter *f1,
  1206 + const struct USBAutoFilter *f2)
  1207 +{
  1208 + return f1->bus_num == f2->bus_num &&
  1209 + f1->addr == f2->addr &&
  1210 + f1->vendor_id == f2->vendor_id &&
  1211 + f1->product_id == f2->product_id;
  1212 +}
  1213 +
  1214 +static int usb_host_auto_add(const char *spec)
  1215 +{
  1216 + struct USBAutoFilter filter, *f;
  1217 +
  1218 + if (parse_filter(spec, &filter) < 0)
  1219 + return -1;
  1220 +
  1221 + f = qemu_mallocz(sizeof(*f));
1135 1222 if (!f) {
1136 1223 fprintf(stderr, "husb: failed to allocate auto filter\n");
1137   - return;
  1224 + return -1;
1138 1225 }
1139 1226  
1140   - f->bus_num = bus_num;
1141   - f->addr = addr;
1142   - f->vendor_id = vendor_id;
1143   - f->product_id = product_id;
  1227 + *f = filter;
1144 1228  
1145 1229 if (!usb_auto_filter) {
1146 1230 /*
... ... @@ -1153,18 +1237,52 @@ static void usb_host_auto_add(int bus_num, int addr, int vendor_id, int product_
1153 1237 if (!usb_auto_timer) {
1154 1238 fprintf(stderr, "husb: failed to allocate auto scan timer\n");
1155 1239 qemu_free(f);
1156   - return;
  1240 + return -1;
1157 1241 }
1158 1242  
1159 1243 /* Check for new devices every two seconds */
1160 1244 qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000);
1161 1245 }
1162 1246  
1163   - dprintf("husb: auto filter: bus_num %d addr %d vid %d pid %d\n",
1164   - bus_num, addr, vendor_id, product_id);
  1247 + dprintf("husb: added auto filter: bus_num %d addr %d vid %d pid %d\n",
  1248 + f->bus_num, f->addr, f->vendor_id, f->product_id);
1165 1249  
1166 1250 f->next = usb_auto_filter;
1167 1251 usb_auto_filter = f;
  1252 +
  1253 + return 0;
  1254 +}
  1255 +
  1256 +static int usb_host_auto_del(const char *spec)
  1257 +{
  1258 + struct USBAutoFilter *pf = usb_auto_filter;
  1259 + struct USBAutoFilter **prev = &usb_auto_filter;
  1260 + struct USBAutoFilter filter;
  1261 +
  1262 + if (parse_filter(spec, &filter) < 0)
  1263 + return -1;
  1264 +
  1265 + while (pf) {
  1266 + if (match_filter(pf, &filter)) {
  1267 + dprintf("husb: removed auto filter: bus_num %d addr %d vid %d pid %d\n",
  1268 + pf->bus_num, pf->addr, pf->vendor_id, pf->product_id);
  1269 +
  1270 + *prev = pf->next;
  1271 +
  1272 + if (!usb_auto_filter) {
  1273 + /* No more filters. Stop scanning. */
  1274 + qemu_del_timer(usb_auto_timer);
  1275 + qemu_free_timer(usb_auto_timer);
  1276 + }
  1277 +
  1278 + return 0;
  1279 + }
  1280 +
  1281 + prev = &pf->next;
  1282 + pf = pf->next;
  1283 + }
  1284 +
  1285 + return -1;
1168 1286 }
1169 1287  
1170 1288 typedef struct FindDeviceState {
... ... @@ -1208,12 +1326,6 @@ static int usb_host_find_device(int *pbus_num, int *paddr,
1208 1326 p = strchr(devname, '.');
1209 1327 if (p) {
1210 1328 *pbus_num = strtoul(devname, NULL, 0);
1211   -
1212   - if (*(p + 1) == '*') {
1213   - usb_host_auto_add(*pbus_num, -1, -1, -1);
1214   - return -1;
1215   - }
1216   -
1217 1329 *paddr = strtoul(p + 1, NULL, 0);
1218 1330 fs.bus_num = *pbus_num;
1219 1331 fs.addr = *paddr;
... ... @@ -1222,15 +1334,10 @@ static int usb_host_find_device(int *pbus_num, int *paddr,
1222 1334 pstrcpy(product_name, product_name_size, fs.product_name);
1223 1335 return 0;
1224 1336 }
  1337 +
1225 1338 p = strchr(devname, ':');
1226 1339 if (p) {
1227 1340 fs.vendor_id = strtoul(devname, NULL, 16);
1228   -
1229   - if (*(p + 1) == '*') {
1230   - usb_host_auto_add(-1, -1, fs.vendor_id, -1);
1231   - return -1;
1232   - }
1233   -
1234 1341 fs.product_id = strtoul(p + 1, NULL, 16);
1235 1342 ret = usb_host_scan(&fs, usb_host_find_device_scan);
1236 1343 if (ret) {
... ... @@ -1324,9 +1431,38 @@ static int usb_host_info_device(void *opaque, int bus_num, int addr,
1324 1431 return 0;
1325 1432 }
1326 1433  
  1434 +static void dec2str(int val, char *str)
  1435 +{
  1436 + if (val == -1)
  1437 + strcpy(str, "*");
  1438 + else
  1439 + sprintf(str, "%d", val);
  1440 +}
  1441 +
  1442 +static void hex2str(int val, char *str)
  1443 +{
  1444 + if (val == -1)
  1445 + strcpy(str, "*");
  1446 + else
  1447 + sprintf(str, "%x", val);
  1448 +}
  1449 +
1327 1450 void usb_host_info(void)
1328 1451 {
  1452 + struct USBAutoFilter *f;
  1453 +
1329 1454 usb_host_scan(NULL, usb_host_info_device);
  1455 +
  1456 + if (usb_auto_filter)
  1457 + term_printf(" Auto filters:\n");
  1458 + for (f = usb_auto_filter; f; f = f->next) {
  1459 + char bus[10], addr[10], vid[10], pid[10];
  1460 + dec2str(f->bus_num, bus);
  1461 + dec2str(f->addr, addr);
  1462 + hex2str(f->vendor_id, vid);
  1463 + hex2str(f->product_id, pid);
  1464 + term_printf(" Device %s.%s ID %s:%s\n", bus, addr, vid, pid);
  1465 + }
1330 1466 }
1331 1467  
1332 1468 #else
... ... @@ -1344,4 +1480,9 @@ USBDevice *usb_host_device_open(const char *devname)
1344 1480 return NULL;
1345 1481 }
1346 1482  
  1483 +int usb_host_device_close(const char *devname)
  1484 +{
  1485 + return 0;
  1486 +}
  1487 +
1347 1488 #endif
... ...
... ... @@ -5866,6 +5866,9 @@ static int usb_device_del(const char *devname)
5866 5866 int bus_num, addr;
5867 5867 const char *p;
5868 5868  
  5869 + if (strstart(devname, "host:", &p))
  5870 + return usb_host_device_close(p);
  5871 +
5869 5872 if (!used_usb_ports)
5870 5873 return -1;
5871 5874  
... ...