Commit 0f431527b79fbd28fb9fcd898ff379331258354a

Authored by aliguori
1 parent 03b4fe7d

Add USB sys file-system support (v8) (TJ)

This patch adds support for host USB devices discovered via:

/sys/bus/usb/devices/* and opened from /dev/bus/usb/*/*
/dev/bus/usb/devices and opened from /dev/bus/usb/*/*

in addition to the existing discovery via:

/proc/bus/usb/devices and opened from /proc/bus/usb/*/*

Signed-off-by: TJ <linux@tjworld.net>
Signed-off-by: Anthony Liguori <aliguori>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5441 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 218 additions and 10 deletions
usb-linux.c
@@ -7,6 +7,10 @@ @@ -7,6 +7,10 @@
7 * Support for host device auto connect & disconnect 7 * Support for host device auto connect & disconnect
8 * Major rewrite to support fully async operation 8 * Major rewrite to support fully async operation
9 * 9 *
  10 + * Copyright 2008 TJ <linux@tjworld.net>
  11 + * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
  12 + * to the legacy /proc/bus/usb USB device discovery and handling
  13 + *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy 14 * 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 15 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights 16 * in the Software without restriction, including without limitation the rights
@@ -72,9 +76,20 @@ static int usb_host_find_device(int *pbus_num, int *paddr, @@ -72,9 +76,20 @@ static int usb_host_find_device(int *pbus_num, int *paddr,
72 #define dprintf(...) 76 #define dprintf(...)
73 #endif 77 #endif
74 78
75 -#define USBDEVFS_PATH "/proc/bus/usb" 79 +#define USBPROCBUS_PATH "/proc/bus/usb"
76 #define PRODUCT_NAME_SZ 32 80 #define PRODUCT_NAME_SZ 32
77 #define MAX_ENDPOINTS 16 81 #define MAX_ENDPOINTS 16
  82 +#define USBDEVBUS_PATH "/dev/bus/usb"
  83 +#define USBSYSBUS_PATH "/sys/bus/usb"
  84 +
  85 +static char *usb_host_device_path;
  86 +
  87 +#define USB_FS_NONE 0
  88 +#define USB_FS_PROC 1
  89 +#define USB_FS_DEV 2
  90 +#define USB_FS_SYS 3
  91 +
  92 +static int usb_fs_type;
78 93
79 /* endpoint association data */ 94 /* endpoint association data */
80 struct endp_data { 95 struct endp_data {
@@ -890,13 +905,18 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p @@ -890,13 +905,18 @@ static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *p
890 905
891 printf("husb: open device %d.%d\n", bus_num, addr); 906 printf("husb: open device %d.%d\n", bus_num, addr);
892 907
893 - snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", 908 + if (!usb_host_device_path) {
  909 + perror("husb: USB Host Device Path not set");
  910 + goto fail;
  911 + }
  912 + snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
894 bus_num, addr); 913 bus_num, addr);
895 fd = open(buf, O_RDWR | O_NONBLOCK); 914 fd = open(buf, O_RDWR | O_NONBLOCK);
896 if (fd < 0) { 915 if (fd < 0) {
897 perror(buf); 916 perror(buf);
898 goto fail; 917 goto fail;
899 } 918 }
  919 + dprintf("husb: opened %s\n", buf);
900 920
901 /* read the device description */ 921 /* read the device description */
902 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr)); 922 dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
@@ -1038,23 +1058,33 @@ static int get_tag_value(char *buf, int buf_size, @@ -1038,23 +1058,33 @@ static int get_tag_value(char *buf, int buf_size,
1038 return q - buf; 1058 return q - buf;
1039 } 1059 }
1040 1060
1041 -static int usb_host_scan(void *opaque, USBScanFunc *func) 1061 +/*
  1062 + * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
  1063 + * host's USB devices. This is legacy support since many distributions
  1064 + * are moving to /sys/bus/usb
  1065 + */
  1066 +static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
1042 { 1067 {
1043 - FILE *f; 1068 + FILE *f = 0;
1044 char line[1024]; 1069 char line[1024];
1045 char buf[1024]; 1070 char buf[1024];
1046 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id; 1071 int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
1047 - int ret;  
1048 char product_name[512]; 1072 char product_name[512];
  1073 + int ret = 0;
1049 1074
1050 - f = fopen(USBDEVFS_PATH "/devices", "r"); 1075 + if (!usb_host_device_path) {
  1076 + perror("husb: USB Host Device Path not set");
  1077 + goto the_end;
  1078 + }
  1079 + snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
  1080 + f = fopen(line, "r");
1051 if (!f) { 1081 if (!f) {
1052 - term_printf("husb: could not open %s\n", USBDEVFS_PATH "/devices");  
1053 - return 0; 1082 + perror("husb: cannot open devices file");
  1083 + goto the_end;
1054 } 1084 }
  1085 +
1055 device_count = 0; 1086 device_count = 0;
1056 bus_num = addr = speed = class_id = product_id = vendor_id = 0; 1087 bus_num = addr = speed = class_id = product_id = vendor_id = 0;
1057 - ret = 0;  
1058 for(;;) { 1088 for(;;) {
1059 if (fgets(line, sizeof(line), f) == NULL) 1089 if (fgets(line, sizeof(line), f) == NULL)
1060 break; 1090 break;
@@ -1111,7 +1141,185 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) @@ -1111,7 +1141,185 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
1111 product_id, product_name, speed); 1141 product_id, product_name, speed);
1112 } 1142 }
1113 the_end: 1143 the_end:
1114 - fclose(f); 1144 + if (f)
  1145 + fclose(f);
  1146 + return ret;
  1147 +}
  1148 +
  1149 +/*
  1150 + * Read sys file-system device file
  1151 + *
  1152 + * @line address of buffer to put file contents in
  1153 + * @line_size size of line
  1154 + * @device_file path to device file (printf format string)
  1155 + * @device_name device being opened (inserted into device_file)
  1156 + *
  1157 + * @return 0 failed, 1 succeeded ('line' contains data)
  1158 + */
  1159 +static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name)
  1160 +{
  1161 + FILE *f;
  1162 + int ret = 0;
  1163 + char filename[PATH_MAX];
  1164 +
  1165 + snprintf(filename, PATH_MAX, device_file, device_name);
  1166 + f = fopen(filename, "r");
  1167 + if (f) {
  1168 + fgets(line, line_size, f);
  1169 + fclose(f);
  1170 + ret = 1;
  1171 + } else {
  1172 + term_printf("husb: could not open %s\n", filename);
  1173 + }
  1174 +
  1175 + return ret;
  1176 +}
  1177 +
  1178 +/*
  1179 + * Use /sys/bus/usb/devices/ directory to determine host's USB
  1180 + * devices.
  1181 + *
  1182 + * This code is based on Robert Schiele's original patches posted to
  1183 + * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
  1184 + */
  1185 +static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
  1186 +{
  1187 + DIR *dir = 0;
  1188 + char line[1024];
  1189 + int bus_num, addr, speed, class_id, product_id, vendor_id;
  1190 + int ret = 0;
  1191 + char product_name[512];
  1192 + struct dirent *de;
  1193 +
  1194 + dir = opendir(USBSYSBUS_PATH "/devices");
  1195 + if (!dir) {
  1196 + perror("husb: cannot open devices directory");
  1197 + goto the_end;
  1198 + }
  1199 +
  1200 + while ((de = readdir(dir))) {
  1201 + if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
  1202 + char *tmpstr = de->d_name;
  1203 + if (!strncmp(de->d_name, "usb", 3))
  1204 + tmpstr += 3;
  1205 + bus_num = atoi(tmpstr);
  1206 +
  1207 + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/devnum", de->d_name))
  1208 + goto the_end;
  1209 + if (sscanf(line, "%d", &addr) != 1)
  1210 + goto the_end;
  1211 +
  1212 + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/bDeviceClass", de->d_name))
  1213 + goto the_end;
  1214 + if (sscanf(line, "%x", &class_id) != 1)
  1215 + goto the_end;
  1216 +
  1217 + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/idVendor", de->d_name))
  1218 + goto the_end;
  1219 + if (sscanf(line, "%x", &vendor_id) != 1)
  1220 + goto the_end;
  1221 +
  1222 + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/idProduct", de->d_name))
  1223 + goto the_end;
  1224 + if (sscanf(line, "%x", &product_id) != 1)
  1225 + goto the_end;
  1226 +
  1227 + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/product", de->d_name)) {
  1228 + *product_name = 0;
  1229 + } else {
  1230 + if (strlen(line) > 0)
  1231 + line[strlen(line) - 1] = '\0';
  1232 + pstrcpy(product_name, sizeof(product_name), line);
  1233 + }
  1234 +
  1235 + if (!usb_host_read_file(line, sizeof(line), USBSYSBUS_PATH "/devices/%s/speed", de->d_name))
  1236 + goto the_end;
  1237 + if (!strcmp(line, "480\n"))
  1238 + speed = USB_SPEED_HIGH;
  1239 + else if (!strcmp(line, "1.5\n"))
  1240 + speed = USB_SPEED_LOW;
  1241 + else
  1242 + speed = USB_SPEED_FULL;
  1243 +
  1244 + ret = func(opaque, bus_num, addr, class_id, vendor_id,
  1245 + product_id, product_name, speed);
  1246 + if (ret)
  1247 + goto the_end;
  1248 + }
  1249 + }
  1250 + the_end:
  1251 + if (dir)
  1252 + closedir(dir);
  1253 + return ret;
  1254 +}
  1255 +
  1256 +/*
  1257 + * Determine how to access the host's USB devices and call the
  1258 + * specific support function.
  1259 + */
  1260 +static int usb_host_scan(void *opaque, USBScanFunc *func)
  1261 +{
  1262 + FILE *f = 0;
  1263 + DIR *dir = 0;
  1264 + int ret = 0;
  1265 + const char *devices = "/devices";
  1266 + const char *opened = "husb: opened %s%s\n";
  1267 + const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
  1268 + char devpath[PATH_MAX];
  1269 +
  1270 + /* only check the host once */
  1271 + if (!usb_fs_type) {
  1272 + f = fopen(USBPROCBUS_PATH "/devices", "r");
  1273 + if (f) {
  1274 + /* devices found in /proc/bus/usb/ */
  1275 + strcpy(devpath, USBPROCBUS_PATH);
  1276 + usb_fs_type = USB_FS_PROC;
  1277 + fclose(f);
  1278 + dprintf(opened, USBPROCBUS_PATH, devices);
  1279 + }
  1280 + /* try additional methods if an access method hasn't been found yet */
  1281 + f = fopen(USBDEVBUS_PATH "/devices", "r");
  1282 + if (!usb_fs_type && f) {
  1283 + /* devices found in /dev/bus/usb/ */
  1284 + strcpy(devpath, USBDEVBUS_PATH);
  1285 + usb_fs_type = USB_FS_DEV;
  1286 + fclose(f);
  1287 + dprintf(opened, USBDEVBUS_PATH, devices);
  1288 + }
  1289 + dir = opendir(USBSYSBUS_PATH "/devices");
  1290 + if (!usb_fs_type && dir) {
  1291 + /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
  1292 + strcpy(devpath, USBDEVBUS_PATH);
  1293 + usb_fs_type = USB_FS_SYS;
  1294 + closedir(dir);
  1295 + dprintf(opened, USBSYSBUS_PATH, devices);
  1296 + } else {
  1297 + term_printf("husb: unable to access USB devices\n");
  1298 + goto the_end;
  1299 + }
  1300 +
  1301 + /* the module setting (used later for opening devices) */
  1302 + usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
  1303 + if (usb_host_device_path) {
  1304 + strcpy(usb_host_device_path, devpath);
  1305 + term_printf("husb: using %s file-system with %s\n", fs_type[usb_fs_type], usb_host_device_path);
  1306 + } else {
  1307 + /* out of memory? */
  1308 + perror("husb: unable to allocate memory for device path");
  1309 + goto the_end;
  1310 + }
  1311 + }
  1312 +
  1313 + switch (usb_fs_type) {
  1314 + case USB_FS_PROC:
  1315 + case USB_FS_DEV:
  1316 + ret = usb_host_scan_dev(opaque, func);
  1317 + break;
  1318 + case USB_FS_SYS:
  1319 + ret = usb_host_scan_sys(opaque, func);
  1320 + break;
  1321 + }
  1322 + the_end:
1115 return ret; 1323 return ret;
1116 } 1324 }
1117 1325