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,6 +240,7 @@ USBDevice *usb_hub_init(int nb_ports);
240 240
241 /* usb-linux.c */ 241 /* usb-linux.c */
242 USBDevice *usb_host_device_open(const char *devname); 242 USBDevice *usb_host_device_open(const char *devname);
  243 +int usb_host_device_close(const char *devname);
243 void usb_host_info(void); 244 void usb_host_info(void);
244 245
245 /* usb-hid.c */ 246 /* usb-hid.c */
usb-linux.c
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * 5 *
6 * Copyright (c) 2008 Max Krasnyansky 6 * Copyright (c) 2008 Max Krasnyansky
7 * Support for host device auto connect & disconnect 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 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal 11 * of this software and associated documentation files (the "Software"), to deal
@@ -951,23 +951,52 @@ fail: @@ -951,23 +951,52 @@ fail:
951 return NULL; 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 USBDevice *usb_host_device_open(const char *devname) 957 USBDevice *usb_host_device_open(const char *devname)
955 { 958 {
956 int bus_num, addr; 959 int bus_num, addr;
957 char product_name[PRODUCT_NAME_SZ]; 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 return NULL; 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 return NULL; 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 return usb_host_device_open_addr(bus_num, addr, product_name); 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 static int get_tag_value(char *buf, int buf_size, 1001 static int get_tag_value(char *buf, int buf_size,
973 const char *str, const char *tag, 1002 const char *str, const char *tag,
@@ -1126,21 +1155,76 @@ static void usb_host_auto_timer(void *unused) @@ -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 if (!f) { 1222 if (!f) {
1136 fprintf(stderr, "husb: failed to allocate auto filter\n"); 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 if (!usb_auto_filter) { 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,18 +1237,52 @@ static void usb_host_auto_add(int bus_num, int addr, int vendor_id, int product_
1153 if (!usb_auto_timer) { 1237 if (!usb_auto_timer) {
1154 fprintf(stderr, "husb: failed to allocate auto scan timer\n"); 1238 fprintf(stderr, "husb: failed to allocate auto scan timer\n");
1155 qemu_free(f); 1239 qemu_free(f);
1156 - return; 1240 + return -1;
1157 } 1241 }
1158 1242
1159 /* Check for new devices every two seconds */ 1243 /* Check for new devices every two seconds */
1160 qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000); 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 f->next = usb_auto_filter; 1250 f->next = usb_auto_filter;
1167 usb_auto_filter = f; 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 typedef struct FindDeviceState { 1288 typedef struct FindDeviceState {
@@ -1208,12 +1326,6 @@ static int usb_host_find_device(int *pbus_num, int *paddr, @@ -1208,12 +1326,6 @@ static int usb_host_find_device(int *pbus_num, int *paddr,
1208 p = strchr(devname, '.'); 1326 p = strchr(devname, '.');
1209 if (p) { 1327 if (p) {
1210 *pbus_num = strtoul(devname, NULL, 0); 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 *paddr = strtoul(p + 1, NULL, 0); 1329 *paddr = strtoul(p + 1, NULL, 0);
1218 fs.bus_num = *pbus_num; 1330 fs.bus_num = *pbus_num;
1219 fs.addr = *paddr; 1331 fs.addr = *paddr;
@@ -1222,15 +1334,10 @@ static int usb_host_find_device(int *pbus_num, int *paddr, @@ -1222,15 +1334,10 @@ static int usb_host_find_device(int *pbus_num, int *paddr,
1222 pstrcpy(product_name, product_name_size, fs.product_name); 1334 pstrcpy(product_name, product_name_size, fs.product_name);
1223 return 0; 1335 return 0;
1224 } 1336 }
  1337 +
1225 p = strchr(devname, ':'); 1338 p = strchr(devname, ':');
1226 if (p) { 1339 if (p) {
1227 fs.vendor_id = strtoul(devname, NULL, 16); 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 fs.product_id = strtoul(p + 1, NULL, 16); 1341 fs.product_id = strtoul(p + 1, NULL, 16);
1235 ret = usb_host_scan(&fs, usb_host_find_device_scan); 1342 ret = usb_host_scan(&fs, usb_host_find_device_scan);
1236 if (ret) { 1343 if (ret) {
@@ -1324,9 +1431,38 @@ static int usb_host_info_device(void *opaque, int bus_num, int addr, @@ -1324,9 +1431,38 @@ static int usb_host_info_device(void *opaque, int bus_num, int addr,
1324 return 0; 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 void usb_host_info(void) 1450 void usb_host_info(void)
1328 { 1451 {
  1452 + struct USBAutoFilter *f;
  1453 +
1329 usb_host_scan(NULL, usb_host_info_device); 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 #else 1468 #else
@@ -1344,4 +1480,9 @@ USBDevice *usb_host_device_open(const char *devname) @@ -1344,4 +1480,9 @@ USBDevice *usb_host_device_open(const char *devname)
1344 return NULL; 1480 return NULL;
1345 } 1481 }
1346 1482
  1483 +int usb_host_device_close(const char *devname)
  1484 +{
  1485 + return 0;
  1486 +}
  1487 +
1347 #endif 1488 #endif
@@ -5866,6 +5866,9 @@ static int usb_device_del(const char *devname) @@ -5866,6 +5866,9 @@ static int usb_device_del(const char *devname)
5866 int bus_num, addr; 5866 int bus_num, addr;
5867 const char *p; 5867 const char *p;
5868 5868
  5869 + if (strstart(devname, "host:", &p))
  5870 + return usb_host_device_close(p);
  5871 +
5869 if (!used_usb_ports) 5872 if (!used_usb_ports)
5870 return -1; 5873 return -1;
5871 5874