├── .gitignore ├── Makefile ├── device.c ├── endpoint.c ├── extras └── lsusb.py ├── interface.c ├── list.h ├── lsusb.c ├── lsusb.h ├── raw.c ├── short_types.h └── usb.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.swp 3 | lsusb 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BINDIR=/usr/bin 2 | LOCALESDIR=/usr/share/locale 3 | MANDIR=/usr/share/man/man8 4 | WARNFLAGS=-Wall -W -Wshadow 5 | CFLAGS?=-O1 -g ${WARNFLAGS} 6 | CC?=gcc 7 | 8 | 9 | OBJS = device.o interface.o endpoint.o raw.o lsusb.o 10 | 11 | 12 | lsusb: $(OBJS) Makefile usb.h list.h 13 | $(CC) ${CFLAGS} $(LDFLAGS) $(OBJS) -ludev -o lsusb 14 | 15 | 16 | clean: 17 | rm -f *~ lsusb *.o 18 | 19 | -------------------------------------------------------------------------------- /device.c: -------------------------------------------------------------------------------- 1 | /* 2 | * device.c 3 | * 4 | * Handle all struct usb_device logic 5 | * 6 | * Copyright (C) 2009 Greg Kroah-Hartman 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License, 10 | * version 2, as published by the Free Software Foundation. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 31 | 32 | #include 33 | #include "list.h" 34 | #include "usb.h" 35 | #include "lsusb.h" 36 | 37 | 38 | 39 | static LIST_HEAD(usb_devices); 40 | 41 | static struct usb_device *new_usb_device(void) 42 | { 43 | return robust_malloc(sizeof(struct usb_device)); 44 | } 45 | 46 | static void free_usb_device(struct usb_device *usb_device) 47 | { 48 | free(usb_device->idVendor); 49 | free(usb_device->idProduct); 50 | free(usb_device->busnum); 51 | free(usb_device->devnum); 52 | free(usb_device->manufacturer); 53 | free(usb_device->bcdDevice); 54 | free(usb_device->product); 55 | free(usb_device->serial); 56 | free(usb_device->bConfigurationValue); 57 | free(usb_device->bDeviceClass); 58 | free(usb_device->bDeviceProtocol); 59 | free(usb_device->bDeviceSubClass); 60 | free(usb_device->bNumConfigurations); 61 | free(usb_device->bNumInterfaces); 62 | free(usb_device->bmAttributes); 63 | free(usb_device->bMaxPacketSize0); 64 | free(usb_device->bMaxPower); 65 | free(usb_device->maxchild); 66 | free(usb_device->quirks); 67 | free(usb_device->speed); 68 | free(usb_device->version); 69 | free(usb_device->driver); 70 | free_usb_endpoint(usb_device->ep0); 71 | free(usb_device); 72 | } 73 | 74 | void free_usb_devices(void) 75 | { 76 | struct usb_device *usb_device; 77 | struct usb_interface *usb_interface; 78 | struct usb_endpoint *usb_endpoint; 79 | struct usb_device *temp_usb; 80 | struct usb_interface *temp_intf; 81 | struct usb_endpoint *temp_endpoint; 82 | 83 | list_for_each_entry_safe(usb_device, temp_usb, &usb_devices, list) { 84 | list_del(&usb_device->list); 85 | list_for_each_entry_safe(usb_interface, temp_intf, &usb_device->interfaces, list) { 86 | list_del(&usb_interface->list); 87 | list_for_each_entry_safe(usb_endpoint, temp_endpoint, &usb_interface->endpoints, list) { 88 | list_del(&usb_endpoint->list); 89 | free_usb_endpoint(usb_endpoint); 90 | } 91 | free_usb_interface(usb_interface); 92 | } 93 | free_usb_device(usb_device); 94 | } 95 | } 96 | 97 | static int compare_usb_devices(struct usb_device *a, struct usb_device *b) 98 | { 99 | long busnum_a = strtol(a->busnum, NULL, 10); 100 | long busnum_b = strtol(b->busnum, NULL, 10); 101 | long devnum_a; 102 | long devnum_b; 103 | 104 | if (busnum_a < busnum_b) 105 | return -1; 106 | if (busnum_a > busnum_b) 107 | return 1; 108 | devnum_a = strtol(a->devnum, NULL, 10); 109 | devnum_b = strtol(b->devnum, NULL, 10); 110 | if (devnum_a < devnum_b) 111 | return -1; 112 | if (devnum_a > devnum_b) 113 | return 1; 114 | return 0; 115 | } 116 | 117 | void sort_usb_devices(void) 118 | { 119 | LIST_HEAD(sorted_devices); 120 | struct usb_device *sorted_usb_device; 121 | struct usb_device *usb_device; 122 | struct usb_device *temp; 123 | int moved; 124 | 125 | list_for_each_entry_safe(usb_device, temp, &usb_devices, list) { 126 | /* is this the first item to add to the list? */ 127 | if (list_empty(&sorted_devices)) { 128 | list_move_tail(&usb_device->list, &sorted_devices); 129 | continue; 130 | } 131 | 132 | /* 133 | * Not the first item, iterate over the sorted list and try 134 | * to find a place in it to put this device 135 | */ 136 | moved = 0; 137 | list_for_each_entry(sorted_usb_device, &sorted_devices, list) { 138 | if (compare_usb_devices(usb_device, sorted_usb_device) <= 0) { 139 | /* add usb_device before sorted_usb_device */ 140 | list_del(&usb_device->list); 141 | list_add_tail(&usb_device->list, 142 | &sorted_usb_device->list); 143 | moved = 1; 144 | break; 145 | } 146 | } 147 | if (moved == 0) { 148 | /* 149 | * Could not find a place in the list to add the 150 | * device, so add it to the end of the sorted_devices 151 | * list as that is where it belongs. 152 | */ 153 | list_move_tail(&usb_device->list, &sorted_devices); 154 | } 155 | } 156 | /* usb_devices should be empty now, so just swap the lists over. */ 157 | list_splice(&sorted_devices, &usb_devices); 158 | } 159 | 160 | void print_usb_devices(void) 161 | { 162 | struct usb_device *usb_device; 163 | struct usb_interface *usb_interface; 164 | struct usb_endpoint *usb_endpoint; 165 | 166 | list_for_each_entry(usb_device, &usb_devices, list) { 167 | printf("Bus %03ld Device %03ld: ID %s:%s %s\n", 168 | strtol(usb_device->busnum, NULL, 10), 169 | strtol(usb_device->devnum, NULL, 10), 170 | usb_device->idVendor, 171 | usb_device->idProduct, 172 | usb_device->manufacturer); 173 | list_for_each_entry(usb_interface, &usb_device->interfaces, list) { 174 | printf("\tIntf %s (%s)\n", 175 | usb_interface->sysname, 176 | usb_interface->driver); 177 | // list_for_each_entry(usb_endpoint, &usb_interface->endpoints, list) { 178 | // printf("\t\tEp (%s)\n", usb_endpoint->bEndpointAddress); 179 | // } 180 | } 181 | } 182 | } 183 | 184 | void create_usb_device(struct udev_device *device) 185 | { 186 | char file[PATH_MAX]; 187 | struct usb_device *usb_device; 188 | const char *temp; 189 | 190 | /* 191 | * Create a device and populate it with what we can find in the sysfs 192 | * directory for the USB device. 193 | */ 194 | usb_device = new_usb_device(); 195 | INIT_LIST_HEAD(&usb_device->interfaces); 196 | usb_device->bcdDevice = get_dev_string(device, "bcdDevice"); 197 | usb_device->product = get_dev_string(device, "product"); 198 | usb_device->serial = get_dev_string(device, "serial"); 199 | usb_device->manufacturer = get_dev_string(device, "manufacturer"); 200 | usb_device->idProduct = get_dev_string(device, "idProduct"); 201 | usb_device->idVendor = get_dev_string(device, "idVendor"); 202 | usb_device->busnum = get_dev_string(device, "busnum"); 203 | usb_device->devnum = get_dev_string(device, "devnum"); 204 | usb_device->bConfigurationValue = get_dev_string(device, "bConfigurationValue"); 205 | usb_device->bDeviceClass = get_dev_string(device, "bDeviceClass"); 206 | usb_device->bDeviceProtocol = get_dev_string(device, "bDeviceProtocol"); 207 | usb_device->bDeviceSubClass = get_dev_string(device, "bDeviceSubClass"); 208 | usb_device->bNumConfigurations = get_dev_string(device, "bNumConfigurations"); 209 | usb_device->bNumInterfaces = get_dev_string(device, "bNumInterfaces"); 210 | usb_device->bmAttributes = get_dev_string(device, "bmAttributes"); 211 | usb_device->bMaxPacketSize0 = get_dev_string(device, "bMaxPacketSize0"); 212 | usb_device->bMaxPower = get_dev_string(device, "bMaxPower"); 213 | usb_device->maxchild = get_dev_string(device, "maxchild"); 214 | usb_device->quirks = get_dev_string(device, "quirks"); 215 | usb_device->speed = get_dev_string(device, "speed"); 216 | usb_device->version = get_dev_string(device, "version"); 217 | temp = udev_device_get_driver(device); 218 | if (temp) 219 | usb_device->driver = strdup(temp); 220 | 221 | /* Build up endpoint 0 information */ 222 | usb_device->ep0 = create_usb_endpoint(device, "ep_00"); 223 | 224 | /* 225 | * Read the raw descriptor to get some more information (endpoint info, 226 | * configurations, interfaces, etc.) 227 | */ 228 | sprintf(file, "%s/descriptors", udev_device_get_syspath(device)); 229 | read_raw_usb_descriptor(device, usb_device); 230 | 231 | /* Add the device to the list of global devices in the system */ 232 | list_add_tail(&usb_device->list, &usb_devices); 233 | 234 | /* try to find the interfaces for this device */ 235 | create_usb_interface(device, usb_device); 236 | } 237 | 238 | -------------------------------------------------------------------------------- /endpoint.c: -------------------------------------------------------------------------------- 1 | /* 2 | * endpoint.c 3 | * 4 | * Handle all struct usb_endpoint logic 5 | * 6 | * Copyright (C) 2009 Greg Kroah-Hartman 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License, 10 | * version 2, as published by the Free Software Foundation. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 31 | 32 | #include 33 | #include "list.h" 34 | #include "usb.h" 35 | #include "lsusb.h" 36 | 37 | 38 | 39 | static struct usb_endpoint *new_usb_endpoint(void) 40 | { 41 | return robust_malloc(sizeof(struct usb_endpoint)); 42 | } 43 | 44 | void free_usb_endpoint(struct usb_endpoint *usb_endpoint) 45 | { 46 | free(usb_endpoint->bEndpointAddress); 47 | free(usb_endpoint->bInterval); 48 | free(usb_endpoint->bLength); 49 | free(usb_endpoint->bmAttributes); 50 | free(usb_endpoint->direction); 51 | free(usb_endpoint->type); 52 | free(usb_endpoint->wMaxPacketSize); 53 | free(usb_endpoint); 54 | } 55 | 56 | struct usb_endpoint *create_usb_endpoint(struct udev_device *device, const char *endpoint_name) 57 | { 58 | struct usb_endpoint *ep; 59 | char filename[PATH_MAX]; 60 | 61 | ep = new_usb_endpoint(); 62 | 63 | #define get_endpoint_string(string) \ 64 | sprintf(filename, "%s/"__stringify(string), endpoint_name); \ 65 | ep->string = get_dev_string(device, filename); 66 | 67 | get_endpoint_string(bEndpointAddress); 68 | get_endpoint_string(bInterval); 69 | get_endpoint_string(bLength); 70 | get_endpoint_string(bmAttributes); 71 | get_endpoint_string(direction); 72 | get_endpoint_string(type); 73 | get_endpoint_string(wMaxPacketSize); 74 | 75 | return ep; 76 | } 77 | -------------------------------------------------------------------------------- /extras/lsusb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # lsusb.py 3 | # Displays your USB devices in reasonable form. 4 | # (c) Kurt Garloff , 2/2009, GPL v2 or v3. 5 | # Usage: See usage() 6 | 7 | import os, sys, re, getopt 8 | 9 | # from __future__ import print_function 10 | 11 | # Global options 12 | showint = False 13 | showhubint = False 14 | noemptyhub = False 15 | nohub = False 16 | warnsort = False 17 | 18 | prefix = "/sys/bus/usb/devices/" 19 | usbids = "/usr/share/usb.ids" 20 | 21 | esc = chr(27) 22 | norm = esc + "[0;0m" 23 | bold = esc + "[0;1m" 24 | red = esc + "[0;31m" 25 | green= esc + "[0;32m" 26 | amber= esc + "[0;33m" 27 | 28 | cols = ("", "", "", "", "") 29 | 30 | def readattr(path, name): 31 | "Read attribute from sysfs and return as string" 32 | f = open(prefix + path + "/" + name); 33 | return f.readline().rstrip("\n"); 34 | 35 | def readlink(path, name): 36 | "Read symlink and return basename" 37 | return os.path.basename(os.readlink(prefix + path + "/" + name)); 38 | 39 | class UsbClass: 40 | "Container for USB Class/Subclass/Protocol" 41 | def __init__(self, cl, sc, pr, str = ""): 42 | self.pclass = cl 43 | self.subclass = sc 44 | self.proto = pr 45 | self.desc = str 46 | def __repr__(self): 47 | return self.desc 48 | def __cmp__(self, oth): 49 | # Works only on 64bit systems: 50 | #return self.pclass*0x10000+self.subclass*0x100+self.proto \ 51 | # - oth.pclass*0x10000-oth.subclass*0x100-oth.proto 52 | if self.pclass != oth.pclass: 53 | return self.pclass - oth.pclass 54 | if self.subclass != oth.subclass: 55 | return self.subclass - oth.subclass 56 | return self.proto - oth.proto 57 | 58 | class UsbVendor: 59 | "Container for USB Vendors" 60 | def __init__(self, vid, vname = ""): 61 | self.vid = vid 62 | self.vname = vname 63 | def __repr__(self): 64 | return self.vname 65 | def __cmp__(self, oth): 66 | return self.vid - oth.vid 67 | 68 | class UsbProduct: 69 | "Container for USB VID:PID devices" 70 | def __init__(self, vid, pid, pname = ""): 71 | self.vid = vid 72 | self.pid = pid 73 | self.pname = pname 74 | def __repr__(self): 75 | return self.pname 76 | def __cmp__(self, oth): 77 | # Works only on 64bit systems: 78 | # return self.vid*0x10000 + self.pid \ 79 | # - oth.vid*0x10000 - oth.pid 80 | if self.vid != oth.vid: 81 | return self.vid - oth.vid 82 | return self.pid - oth.pid 83 | 84 | usbvendors = [] 85 | usbproducts = [] 86 | usbclasses = [] 87 | 88 | def ishexdigit(str): 89 | "return True if all digits are valid hex digits" 90 | for dg in str: 91 | if not dg.isdigit() and not dg in 'abcdef': 92 | return False 93 | return True 94 | 95 | def parse_usb_ids(): 96 | "Parse /usr/share/usb.ids and fill usbvendors, usbproducts, usbclasses" 97 | id = 0 98 | sid = 0 99 | mode = 0 100 | strg = "" 101 | cstrg = "" 102 | for ln in file(usbids, "r").readlines(): 103 | if ln[0] == '#': 104 | continue 105 | ln = ln.rstrip('\n') 106 | if len(ln) == 0: 107 | continue 108 | if ishexdigit(ln[0:4]): 109 | mode = 0 110 | id = int(ln[:4], 16) 111 | usbvendors.append(UsbVendor(id, ln[6:])) 112 | continue 113 | if ln[0] == '\t' and ishexdigit(ln[1:3]): 114 | sid = int(ln[1:5], 16) 115 | # USB devices 116 | if mode == 0: 117 | usbproducts.append(UsbProduct(id, sid, ln[7:])) 118 | continue 119 | elif mode == 1: 120 | nm = ln[5:] 121 | if nm != "Unused": 122 | strg = cstrg + ":" + nm 123 | else: 124 | strg = cstrg + ":" 125 | usbclasses.append(UsbClass(id, sid, -1, strg)) 126 | continue 127 | if ln[0] == 'C': 128 | mode = 1 129 | id = int(ln[2:4], 16) 130 | cstrg = ln[6:] 131 | usbclasses.append(UsbClass(id, -1, -1, cstrg)) 132 | continue 133 | if mode == 1 and ln[0] == '\t' and ln[1] == '\t' and ishexdigit(ln[2:4]): 134 | prid = int(ln[2:4], 16) 135 | usbclasses.append(UsbClass(id, sid, prid, strg + ":" + ln[6:])) 136 | continue 137 | mode = 2 138 | 139 | def bin_search(first, last, item, list): 140 | "binary search on list, returns -1 on fail, match idx otherwise, recursive" 141 | #print "bin_search(%i,%i)" % (first, last) 142 | if first == last: 143 | return -1 144 | if first == last-1: 145 | if item == list[first]: 146 | return first 147 | else: 148 | return -1 149 | mid = (first+last) // 2 150 | if item == list[mid]: 151 | return mid 152 | elif item < list[mid]: 153 | return bin_search(first, mid, item, list) 154 | else: 155 | return bin_search(mid, last, item, list) 156 | 157 | 158 | def find_usb_prod(vid, pid): 159 | "Return device name from USB Vendor:Product list" 160 | strg = "" 161 | dev = UsbVendor(vid, "") 162 | lnvend = len(usbvendors) 163 | ix = bin_search(0, lnvend, dev, usbvendors) 164 | if ix != -1: 165 | strg = usbvendors[ix].__repr__() 166 | else: 167 | return "" 168 | dev = UsbProduct(vid, pid, "") 169 | lnprod = len(usbproducts) 170 | ix = bin_search(0, lnprod, dev, usbproducts) 171 | if ix != -1: 172 | return strg + " " + usbproducts[ix].__repr__() 173 | return strg 174 | 175 | def find_usb_class(cid, sid, pid): 176 | "Return USB protocol from usbclasses list" 177 | if cid == 0xff and sid == 0xff and pid == 0xff: 178 | return "Vendor Specific" 179 | lnlst = len(usbclasses) 180 | dev = UsbClass(cid, sid, pid, "") 181 | ix = bin_search(0, lnlst, dev, usbclasses) 182 | if ix != -1: 183 | return usbclasses[ix].__repr__() 184 | dev = UsbClass(cid, sid, -1, "") 185 | ix = bin_search(0, lnlst, dev, usbclasses) 186 | if ix != -1: 187 | return usbclasses[ix].__repr__() 188 | dev = UsbClass(cid, -1, -1, "") 189 | ix = bin_search(0, lnlst, dev, usbclasses) 190 | if ix != -1: 191 | return usbclasses[ix].__repr__() 192 | return "" 193 | 194 | 195 | devlst = ( 'usb/lp', # usblp 196 | 'host', # usb-storage 197 | 'video4linux/video', # uvcvideo et al. 198 | 'sound/card', # snd-usb-audio 199 | 'net/', # cdc_ether, ... 200 | 'input/input', # usbhid 201 | 'bluetooth/hci', # btusb 202 | 'ttyUSB', # btusb 203 | 'tty/', # cdc_acm 204 | ) 205 | 206 | def find_storage(hostno): 207 | "Return SCSI block dev names for host" 208 | res = "" 209 | for ent in os.listdir("/sys/class/scsi_device/"): 210 | (host, bus, tgt, lun) = ent.split(":") 211 | if host == hostno: 212 | try: 213 | for ent2 in os.listdir("/sys/class/scsi_device/%s/device/block" % ent): 214 | res += ent2 + " " 215 | except: 216 | pass 217 | return res 218 | 219 | def find_dev(driver, usbname): 220 | "Return pseudo devname that's driven by driver" 221 | res = "" 222 | for nm in devlst: 223 | dir = prefix + usbname 224 | prep = "" 225 | #print nm 226 | idx = nm.find('/') 227 | if idx != -1: 228 | prep = nm[:idx+1] 229 | dir += "/" + nm[:idx] 230 | nm = nm[idx+1:] 231 | ln = len(nm) 232 | try: 233 | for ent in os.listdir(dir): 234 | if ent[:ln] == nm: 235 | res += prep+ent+" " 236 | if nm == "host": 237 | res += "(" + find_storage(ent[ln:])[:-1] + ")" 238 | except: 239 | pass 240 | return res 241 | 242 | 243 | class UsbInterface: 244 | "Container for USB interface info" 245 | def __init__(self, parent = None, level = 1): 246 | self.parent = parent 247 | self.level = level 248 | self.fname = "" 249 | self.iclass = 0 250 | self.isclass = 0 251 | self.iproto = 0 252 | self.noep = 0 253 | self.driver = "" 254 | self.devname = "" 255 | self.protoname = "" 256 | def read(self, fname): 257 | fullpath = "" 258 | if self.parent: 259 | fullpath += self.parent.fname + "/" 260 | fullpath += fname 261 | #self.fname = fullpath 262 | self.fname = fname 263 | self.iclass = int(readattr(fullpath, "bInterfaceClass"),16) 264 | self.isclass = int(readattr(fullpath, "bInterfaceSubClass"),16) 265 | self.iproto = int(readattr(fullpath, "bInterfaceProtocol"),16) 266 | self.noep = int(readattr(fullpath, "bNumEndpoints")) 267 | try: 268 | self.driver = readlink(fname, "driver") 269 | self.devname = find_dev(self.driver, fname) 270 | except: 271 | pass 272 | self.protoname = find_usb_class(self.iclass, self.isclass, self.iproto) 273 | def __str__(self): 274 | return "%-16s(IF) %02x:%02x:%02x %iEPs (%s) %s%s %s%s%s\n" % \ 275 | (" " * self.level+self.fname, self.iclass, 276 | self.isclass, self.iproto, self.noep, 277 | self.protoname, 278 | cols[3], self.driver, 279 | cols[4], self.devname, cols[0]) 280 | 281 | class UsbDevice: 282 | "Container for USB device info" 283 | def __init__(self, parent = None, level = 0): 284 | self.parent = parent 285 | self.level = level 286 | self.fname = "" 287 | self.iclass = 0 288 | self.isclass = 0 289 | self.iproto = 0 290 | self.vid = 0 291 | self.pid = 0 292 | self.name = "" 293 | self.usbver = "" 294 | self.speed = "" 295 | self.maxpower = "" 296 | self.noports = 0 297 | self.nointerfaces = 0 298 | self.driver = "" 299 | self.devname = "" 300 | self.interfaces = [] 301 | self.children = [] 302 | 303 | def read(self, fname): 304 | self.fname = fname 305 | self.iclass = int(readattr(fname, "bDeviceClass"), 16) 306 | self.isclass = int(readattr(fname, "bDeviceSubClass"), 16) 307 | self.iproto = int(readattr(fname, "bDeviceProtocol"), 16) 308 | self.vid = int(readattr(fname, "idVendor"), 16) 309 | self.pid = int(readattr(fname, "idProduct"), 16) 310 | try: 311 | self.name = readattr(fname, "manufacturer") + " " \ 312 | + readattr(fname, "product") 313 | self.name += " " + readattr(fname, "serial") 314 | if self.name[:5] == "Linux": 315 | rx = re.compile(r"Linux [^ ]* (.hci_hcd) .HCI Host Controller ([0-9a-f:\.]*)") 316 | mch = rx.match(self.name) 317 | if mch: 318 | self.name = mch.group(1) + " " + mch.group(2) 319 | 320 | except: 321 | pass 322 | if not self.name: 323 | self.name = find_usb_prod(self.vid, self.pid) 324 | self.usbver = readattr(fname, "version") 325 | self.speed = readattr(fname, "speed") 326 | self.maxpower = readattr(fname, "bMaxPower") 327 | self.noports = int(readattr(fname, "maxchild")) 328 | self.nointerfaces = int(readattr(fname, "bNumInterfaces")) 329 | try: 330 | self.driver = readlink(fname, "driver") 331 | self.devname = find_dev(self.driver, fname) 332 | except: 333 | pass 334 | 335 | def readchildren(self): 336 | if self.fname[0:3] == "usb": 337 | fname = self.fname[3:] 338 | else: 339 | fname = self.fname 340 | for dirent in os.listdir(prefix + self.fname): 341 | if not dirent[0:1].isdigit(): 342 | continue 343 | #print dirent 344 | if os.access(prefix + dirent + "/bInterfaceClass", os.R_OK): 345 | iface = UsbInterface(self, self.level+1) 346 | iface.read(dirent) 347 | self.interfaces.append(iface) 348 | else: 349 | usbdev = UsbDevice(self, self.level+1) 350 | usbdev.read(dirent) 351 | usbdev.readchildren() 352 | self.children.append(usbdev) 353 | 354 | def __str__(self): 355 | #str = " " * self.level + self.fname 356 | if self.iclass == 9: 357 | col = cols[2] 358 | if noemptyhub and len(self.children) == 0: 359 | return "" 360 | if nohub: 361 | str = "" 362 | else: 363 | col = cols[1] 364 | if not nohub or self.iclass != 9: 365 | str = "%-16s%s%04x:%04x%s %02x %s %3sMBit/s %s %iIFs (%s%s%s)" % \ 366 | (" " * self.level + self.fname, 367 | cols[1], self.vid, self.pid, cols[0], 368 | self.iclass, self.usbver, self.speed, self.maxpower, 369 | self.nointerfaces, col, self.name, cols[0]) 370 | #if self.driver != "usb": 371 | # str += " %s" % self.driver 372 | if self.iclass == 9 and not showhubint: 373 | str += " %shub%s\n" % (cols[2], cols[0]) 374 | else: 375 | str += "\n" 376 | if showint: 377 | for iface in self.interfaces: 378 | str += iface.__str__() 379 | for child in self.children: 380 | str += child.__str__() 381 | return str 382 | 383 | def deepcopy(lst): 384 | "Returns a deep copy from the list lst" 385 | copy = [] 386 | for item in lst: 387 | copy.append(item) 388 | return copy 389 | 390 | def display_diff(lst1, lst2, fmtstr, args): 391 | "Compare lists (same length!) and display differences" 392 | for idx in range(0, len(lst1)): 393 | if lst1[idx] != lst2[idx]: 394 | print "Warning: " + fmtstr % args(lst2[idx]) 395 | 396 | def fix_usbvend(): 397 | "Sort USB vendor list and (optionally) display diffs" 398 | if warnsort: 399 | oldusbvend = deepcopy(usbvendors) 400 | usbvendors.sort() 401 | if warnsort: 402 | display_diff(usbvendors, oldusbvend, 403 | "Unsorted Vendor ID %04x", 404 | lambda x: (x.vid,)) 405 | 406 | def fix_usbprod(): 407 | "Sort USB products list" 408 | if warnsort: 409 | oldusbprod = deepcopy(usbproducts) 410 | usbproducts.sort() 411 | if warnsort: 412 | display_diff(usbproducts, oldusbprod, 413 | "Unsorted Vendor:Product ID %04x:%04x", 414 | lambda x: (x.vid, x.pid)) 415 | 416 | def fix_usbclass(): 417 | "Sort USB class list" 418 | if warnsort: 419 | oldusbcls = deepcopy(usbclasses) 420 | usbclasses.sort() 421 | if warnsort: 422 | display_diff(usbclasses, oldusbcls, 423 | "Unsorted USB class %02x:%02x:%02x", 424 | lambda x: (x.pclass, x.subclass, x.proto)) 425 | 426 | 427 | def usage(): 428 | "Displays usage information" 429 | print "Usage: lsusb.py [options]" 430 | print "Options:" 431 | print " -h display this help" 432 | print " -i display interface information" 433 | print " -I display interface information, even for hubs" 434 | print " -u suppress empty hubs" 435 | print " -U suppress all hubs" 436 | print " -c use colors" 437 | print " -w display warning if usb.ids is not sorted correctly" 438 | print " -f FILE override filename for /usr/share/usb.ids" 439 | return 2 440 | 441 | def read_usb(): 442 | "Read toplevel USB entries and print" 443 | for dirent in os.listdir(prefix): 444 | #print dirent, 445 | if not dirent[0:3] == "usb": 446 | continue 447 | usbdev = UsbDevice(None, 0) 448 | usbdev.read(dirent) 449 | usbdev.readchildren() 450 | os.write(sys.stdout.fileno(), usbdev.__str__()) 451 | 452 | def main(argv): 453 | "main entry point" 454 | global showint, showhubint, noemptyhub, nohub, warnsort, cols, usbids 455 | try: 456 | (optlist, args) = getopt.gnu_getopt(argv[1:], "hiIuUwcf:", ("help",)) 457 | except getopt.GetoptError, exc: 458 | print "Error:", exc 459 | sys.exit(usage()) 460 | for opt in optlist: 461 | if opt[0] == "-h" or opt[0] == "--help": 462 | usage() 463 | sys.exit(0) 464 | if opt[0] == "-i": 465 | showint = True 466 | continue 467 | if opt[0] == "-I": 468 | showint = True 469 | showhubint = True 470 | continue 471 | if opt[0] == "-u": 472 | noemptyhub = True 473 | continue 474 | if opt[0] == "-U": 475 | noemptyhub = True 476 | nohub = True 477 | continue 478 | if opt[0] == "-c": 479 | cols = (norm, bold, red, green, amber) 480 | continue 481 | if opt[0] == "-w": 482 | warnsort = True 483 | continue 484 | if opt[0] == "-f": 485 | usbids = opt[1] 486 | continue 487 | if len(args) > 0: 488 | print "Error: excess args %s ..." % args[0] 489 | sys.exit(usage()) 490 | 491 | parse_usb_ids() 492 | fix_usbvend() 493 | fix_usbprod() 494 | fix_usbclass() 495 | read_usb() 496 | 497 | # Entry point 498 | if __name__ == "__main__": 499 | main(sys.argv) 500 | 501 | 502 | -------------------------------------------------------------------------------- /interface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * interface.c 3 | * 4 | * handle all struct usb_interface logic 5 | * 6 | * Copyright (C) 2009 Greg Kroah-Hartman 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License, 10 | * version 2, as published by the Free Software Foundation. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 31 | 32 | #include 33 | #include "list.h" 34 | #include "usb.h" 35 | #include "lsusb.h" 36 | 37 | 38 | 39 | static struct usb_interface *new_usb_interface(void) 40 | { 41 | return robust_malloc(sizeof(struct usb_interface)); 42 | } 43 | 44 | void free_usb_interface(struct usb_interface *usb_intf) 45 | { 46 | free(usb_intf->driver); 47 | free(usb_intf->sysname); 48 | free(usb_intf->bAlternateSetting); 49 | free(usb_intf->bInterfaceClass); 50 | free(usb_intf->bInterfaceNumber); 51 | free(usb_intf->bInterfaceProtocol); 52 | free(usb_intf->bInterfaceSubClass); 53 | free(usb_intf->bNumEndpoints); 54 | free(usb_intf); 55 | } 56 | 57 | static void create_usb_interface_endpoints(struct udev_device *device, struct usb_interface *usb_intf) 58 | { 59 | struct usb_endpoint *ep; 60 | struct dirent *dirent; 61 | DIR *dir; 62 | 63 | dir = opendir(udev_device_get_syspath(device)); 64 | if (dir == NULL) 65 | exit(1); 66 | while ((dirent = readdir(dir)) != NULL) { 67 | if (dirent->d_type != DT_DIR) 68 | continue; 69 | /* endpoints all start with "ep_" */ 70 | if ((dirent->d_name[0] != 'e') || 71 | (dirent->d_name[1] != 'p') || 72 | (dirent->d_name[2] != '_')) 73 | continue; 74 | ep = create_usb_endpoint(device, dirent->d_name); 75 | 76 | list_add_tail(&ep->list, &usb_intf->endpoints); 77 | } 78 | closedir(dir); 79 | 80 | } 81 | 82 | void create_usb_interface(struct udev_device *device, struct usb_device *usb_device) 83 | { 84 | struct usb_interface *usb_intf; 85 | struct udev_device *interface; 86 | const char *driver_name; 87 | int temp_file; 88 | struct dirent *dirent; 89 | char file[PATH_MAX]; 90 | DIR *dir; 91 | 92 | dir = opendir(udev_device_get_syspath(device)); 93 | if (dir == NULL) 94 | exit(1); 95 | while ((dirent = readdir(dir)) != NULL) { 96 | if (dirent->d_type != DT_DIR) 97 | continue; 98 | /* 99 | * As the devnum isn't in older kernels, we need to guess to 100 | * try to find the interfaces. 101 | * 102 | * If the first char is a digit, and bInterfaceClass is in the 103 | * subdir, then odds are it's a child interface 104 | */ 105 | if (!isdigit(dirent->d_name[0])) 106 | continue; 107 | 108 | sprintf(file, "%s/%s/bInterfaceClass", 109 | udev_device_get_syspath(device), dirent->d_name); 110 | temp_file = open(file, O_RDONLY); 111 | if (temp_file == -1) 112 | continue; 113 | 114 | close(temp_file); 115 | sprintf(file, "%s/%s", udev_device_get_syspath(device), 116 | dirent->d_name); 117 | interface = udev_device_new_from_syspath(udev, file); 118 | if (interface == NULL) { 119 | fprintf(stderr, "can't get interface for %s?\n", file); 120 | continue; 121 | } 122 | usb_intf = new_usb_interface(); 123 | INIT_LIST_HEAD(&usb_intf->endpoints); 124 | usb_intf->bAlternateSetting = get_dev_string(interface, "bAlternateSetting"); 125 | usb_intf->bInterfaceClass = get_dev_string(interface, "bInterfaceClass"); 126 | usb_intf->bInterfaceNumber = get_dev_string(interface, "bInterfaceNumber"); 127 | usb_intf->bInterfaceProtocol = get_dev_string(interface, "bInterfaceProtocol"); 128 | usb_intf->bInterfaceSubClass = get_dev_string(interface, "bInterfaceSubClass"); 129 | usb_intf->bNumEndpoints = get_dev_string(interface, "bNumEndpoints"); 130 | usb_intf->sysname = strdup(udev_device_get_sysname(interface)); 131 | 132 | driver_name = udev_device_get_driver(interface); 133 | if (driver_name) 134 | usb_intf->driver = strdup(driver_name); 135 | list_add_tail(&usb_intf->list, &usb_device->interfaces); 136 | 137 | /* find all endpoints for this interface, and save them */ 138 | create_usb_interface_endpoints(interface, usb_intf); 139 | 140 | udev_device_unref(interface); 141 | } 142 | closedir(dir); 143 | } 144 | 145 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copied from the Linux kernel source tree, version 2.6.25. 3 | * 4 | * Licensed under the GPLv2 only, as part of the whole Linux kernel source. 5 | */ 6 | 7 | #ifndef _LIST_H 8 | #define _LIST_H 9 | 10 | #define prefetch(x) __builtin_prefetch(x) 11 | 12 | /** 13 | * container_of - cast a member of a structure out to the containing structure 14 | * 15 | * @ptr: the pointer to the member. 16 | * @type: the type of the container struct this is embedded in. 17 | * @member: the name of the member within the struct. 18 | * 19 | */ 20 | #define container_of(ptr, type, member) ({ \ 21 | const typeof(((type *)0)->member) *__mptr = (ptr); \ 22 | (type *)((char *)__mptr - offsetof(type, member)); }) 23 | 24 | 25 | /* 26 | * These are non-NULL pointers that will result in page faults 27 | * under normal circumstances, used to verify that nobody uses 28 | * non-initialized list entries. 29 | */ 30 | #define LIST_POISON1 ((void *) 0x00100100) 31 | #define LIST_POISON2 ((void *) 0x00200200) 32 | 33 | 34 | /* 35 | * Simple doubly linked list implementation. 36 | * 37 | * Some of the internal functions ("__xxx") are useful when 38 | * manipulating whole lists rather than single entries, as 39 | * sometimes we already know the next/prev entries and we can 40 | * generate better code by using them directly rather than 41 | * using the generic single-entry routines. 42 | */ 43 | 44 | struct list_head { 45 | struct list_head *next, *prev; 46 | }; 47 | 48 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 49 | 50 | #define LIST_HEAD(name) \ 51 | struct list_head name = LIST_HEAD_INIT(name) 52 | 53 | static inline void INIT_LIST_HEAD(struct list_head *list) 54 | { 55 | list->next = list; 56 | list->prev = list; 57 | } 58 | 59 | /* 60 | * Insert a new entry between two known consecutive entries. 61 | * 62 | * This is only for internal list manipulation where we know 63 | * the prev/next entries already! 64 | */ 65 | #ifndef CONFIG_DEBUG_LIST 66 | static inline void __list_add(struct list_head *new, 67 | struct list_head *prev, 68 | struct list_head *next) 69 | { 70 | next->prev = new; 71 | new->next = next; 72 | new->prev = prev; 73 | prev->next = new; 74 | } 75 | #else 76 | extern void __list_add(struct list_head *new, 77 | struct list_head *prev, 78 | struct list_head *next); 79 | #endif 80 | 81 | /** 82 | * list_add - add a new entry 83 | * @new: new entry to be added 84 | * @head: list head to add it after 85 | * 86 | * Insert a new entry after the specified head. 87 | * This is good for implementing stacks. 88 | */ 89 | #ifndef CONFIG_DEBUG_LIST 90 | static inline void list_add(struct list_head *new, struct list_head *head) 91 | { 92 | __list_add(new, head, head->next); 93 | } 94 | #else 95 | extern void list_add(struct list_head *new, struct list_head *head); 96 | #endif 97 | 98 | 99 | /** 100 | * list_add_tail - add a new entry 101 | * @new: new entry to be added 102 | * @head: list head to add it before 103 | * 104 | * Insert a new entry before the specified head. 105 | * This is useful for implementing queues. 106 | */ 107 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 108 | { 109 | __list_add(new, head->prev, head); 110 | } 111 | 112 | /* 113 | * Delete a list entry by making the prev/next entries 114 | * point to each other. 115 | * 116 | * This is only for internal list manipulation where we know 117 | * the prev/next entries already! 118 | */ 119 | static inline void __list_del(struct list_head *prev, struct list_head *next) 120 | { 121 | next->prev = prev; 122 | prev->next = next; 123 | } 124 | 125 | /** 126 | * list_del - deletes entry from list. 127 | * @entry: the element to delete from the list. 128 | * Note: list_empty() on entry does not return true after this, the entry is 129 | * in an undefined state. 130 | */ 131 | #ifndef CONFIG_DEBUG_LIST 132 | static inline void list_del(struct list_head *entry) 133 | { 134 | __list_del(entry->prev, entry->next); 135 | entry->next = LIST_POISON1; 136 | entry->prev = LIST_POISON2; 137 | } 138 | #else 139 | extern void list_del(struct list_head *entry); 140 | #endif 141 | 142 | /** 143 | * list_replace - replace old entry by new one 144 | * @old : the element to be replaced 145 | * @new : the new element to insert 146 | * 147 | * If @old was empty, it will be overwritten. 148 | */ 149 | static inline void list_replace(struct list_head *old, 150 | struct list_head *new) 151 | { 152 | new->next = old->next; 153 | new->next->prev = new; 154 | new->prev = old->prev; 155 | new->prev->next = new; 156 | } 157 | 158 | static inline void list_replace_init(struct list_head *old, 159 | struct list_head *new) 160 | { 161 | list_replace(old, new); 162 | INIT_LIST_HEAD(old); 163 | } 164 | 165 | /** 166 | * list_del_init - deletes entry from list and reinitialize it. 167 | * @entry: the element to delete from the list. 168 | */ 169 | static inline void list_del_init(struct list_head *entry) 170 | { 171 | __list_del(entry->prev, entry->next); 172 | INIT_LIST_HEAD(entry); 173 | } 174 | 175 | /** 176 | * list_move - delete from one list and add as another's head 177 | * @list: the entry to move 178 | * @head: the head that will precede our entry 179 | */ 180 | static inline void list_move(struct list_head *list, struct list_head *head) 181 | { 182 | __list_del(list->prev, list->next); 183 | list_add(list, head); 184 | } 185 | 186 | /** 187 | * list_move_tail - delete from one list and add as another's tail 188 | * @list: the entry to move 189 | * @head: the head that will follow our entry 190 | */ 191 | static inline void list_move_tail(struct list_head *list, 192 | struct list_head *head) 193 | { 194 | __list_del(list->prev, list->next); 195 | list_add_tail(list, head); 196 | } 197 | 198 | /** 199 | * list_is_last - tests whether @list is the last entry in list @head 200 | * @list: the entry to test 201 | * @head: the head of the list 202 | */ 203 | static inline int list_is_last(const struct list_head *list, 204 | const struct list_head *head) 205 | { 206 | return list->next == head; 207 | } 208 | 209 | /** 210 | * list_empty - tests whether a list is empty 211 | * @head: the list to test. 212 | */ 213 | static inline int list_empty(const struct list_head *head) 214 | { 215 | return head->next == head; 216 | } 217 | 218 | /** 219 | * list_empty_careful - tests whether a list is empty and not being modified 220 | * @head: the list to test 221 | * 222 | * Description: 223 | * tests whether a list is empty _and_ checks that no other CPU might be 224 | * in the process of modifying either member (next or prev) 225 | * 226 | * NOTE: using list_empty_careful() without synchronization 227 | * can only be safe if the only activity that can happen 228 | * to the list entry is list_del_init(). Eg. it cannot be used 229 | * if another CPU could re-list_add() it. 230 | */ 231 | static inline int list_empty_careful(const struct list_head *head) 232 | { 233 | struct list_head *next = head->next; 234 | return (next == head) && (next == head->prev); 235 | } 236 | 237 | static inline void __list_splice(struct list_head *list, 238 | struct list_head *head) 239 | { 240 | struct list_head *first = list->next; 241 | struct list_head *last = list->prev; 242 | struct list_head *at = head->next; 243 | 244 | first->prev = head; 245 | head->next = first; 246 | 247 | last->next = at; 248 | at->prev = last; 249 | } 250 | 251 | /** 252 | * list_splice - join two lists 253 | * @list: the new list to add. 254 | * @head: the place to add it in the first list. 255 | */ 256 | static inline void list_splice(struct list_head *list, struct list_head *head) 257 | { 258 | if (!list_empty(list)) 259 | __list_splice(list, head); 260 | } 261 | 262 | /** 263 | * list_splice_init - join two lists and reinitialise the emptied list. 264 | * @list: the new list to add. 265 | * @head: the place to add it in the first list. 266 | * 267 | * The list at @list is reinitialised 268 | */ 269 | static inline void list_splice_init(struct list_head *list, 270 | struct list_head *head) 271 | { 272 | if (!list_empty(list)) { 273 | __list_splice(list, head); 274 | INIT_LIST_HEAD(list); 275 | } 276 | } 277 | 278 | /** 279 | * list_entry - get the struct for this entry 280 | * @ptr: the &struct list_head pointer. 281 | * @type: the type of the struct this is embedded in. 282 | * @member: the name of the list_struct within the struct. 283 | */ 284 | #define list_entry(ptr, type, member) \ 285 | container_of(ptr, type, member) 286 | 287 | /** 288 | * list_first_entry - get the first element from a list 289 | * @ptr: the list head to take the element from. 290 | * @type: the type of the struct this is embedded in. 291 | * @member: the name of the list_struct within the struct. 292 | * 293 | * Note, that list is expected to be not empty. 294 | */ 295 | #define list_first_entry(ptr, type, member) \ 296 | list_entry((ptr)->next, type, member) 297 | 298 | /** 299 | * list_for_each - iterate over a list 300 | * @pos: the &struct list_head to use as a loop cursor. 301 | * @head: the head for your list. 302 | */ 303 | #define list_for_each(pos, head) \ 304 | for (pos = (head)->next; prefetch(pos->next), pos != (head); \ 305 | pos = pos->next) 306 | 307 | /** 308 | * __list_for_each - iterate over a list 309 | * @pos: the &struct list_head to use as a loop cursor. 310 | * @head: the head for your list. 311 | * 312 | * This variant differs from list_for_each() in that it's the 313 | * simplest possible list iteration code, no prefetching is done. 314 | * Use this for code that knows the list to be very short (empty 315 | * or 1 entry) most of the time. 316 | */ 317 | #define __list_for_each(pos, head) \ 318 | for (pos = (head)->next; pos != (head); pos = pos->next) 319 | 320 | /** 321 | * list_for_each_prev - iterate over a list backwards 322 | * @pos: the &struct list_head to use as a loop cursor. 323 | * @head: the head for your list. 324 | */ 325 | #define list_for_each_prev(pos, head) \ 326 | for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ 327 | pos = pos->prev) 328 | 329 | /** 330 | * list_for_each_safe - iterate over a list safe against removal of list entry 331 | * @pos: the &struct list_head to use as a loop cursor. 332 | * @n: another &struct list_head to use as temporary storage 333 | * @head: the head for your list. 334 | */ 335 | #define list_for_each_safe(pos, n, head) \ 336 | for (pos = (head)->next, n = pos->next; pos != (head); \ 337 | pos = n, n = pos->next) 338 | 339 | /** 340 | * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry 341 | * @pos: the &struct list_head to use as a loop cursor. 342 | * @n: another &struct list_head to use as temporary storage 343 | * @head: the head for your list. 344 | */ 345 | #define list_for_each_prev_safe(pos, n, head) \ 346 | for (pos = (head)->prev, n = pos->prev; \ 347 | prefetch(pos->prev), pos != (head); \ 348 | pos = n, n = pos->prev) 349 | 350 | /** 351 | * list_for_each_entry - iterate over list of given type 352 | * @pos: the type * to use as a loop cursor. 353 | * @head: the head for your list. 354 | * @member: the name of the list_struct within the struct. 355 | */ 356 | #define list_for_each_entry(pos, head, member) \ 357 | for (pos = list_entry((head)->next, typeof(*pos), member); \ 358 | prefetch(pos->member.next), &pos->member != (head); \ 359 | pos = list_entry(pos->member.next, typeof(*pos), member)) 360 | 361 | /** 362 | * list_for_each_entry_reverse - iterate backwards over list of given type. 363 | * @pos: the type * to use as a loop cursor. 364 | * @head: the head for your list. 365 | * @member: the name of the list_struct within the struct. 366 | */ 367 | #define list_for_each_entry_reverse(pos, head, member) \ 368 | for (pos = list_entry((head)->prev, typeof(*pos), member); \ 369 | prefetch(pos->member.prev), &pos->member != (head); \ 370 | pos = list_entry(pos->member.prev, typeof(*pos), member)) 371 | 372 | /** 373 | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() 374 | * @pos: the type * to use as a start point 375 | * @head: the head of the list 376 | * @member: the name of the list_struct within the struct. 377 | * 378 | * Prepares a pos entry for use as a start point in 379 | * list_for_each_entry_continue(). 380 | */ 381 | #define list_prepare_entry(pos, head, member) \ 382 | ((pos) ? : list_entry(head, typeof(*pos), member)) 383 | 384 | /** 385 | * list_for_each_entry_continue - continue iteration over list of given type 386 | * @pos: the type * to use as a loop cursor. 387 | * @head: the head for your list. 388 | * @member: the name of the list_struct within the struct. 389 | * 390 | * Continue to iterate over list of given type, continuing after 391 | * the current position. 392 | */ 393 | #define list_for_each_entry_continue(pos, head, member) \ 394 | for (pos = list_entry(pos->member.next, typeof(*pos), member); \ 395 | prefetch(pos->member.next), &pos->member != (head); \ 396 | pos = list_entry(pos->member.next, typeof(*pos), member)) 397 | 398 | /** 399 | * list_for_each_entry_continue_reverse - iterate backwards from the given point 400 | * @pos: the type * to use as a loop cursor. 401 | * @head: the head for your list. 402 | * @member: the name of the list_struct within the struct. 403 | * 404 | * Start to iterate over list of given type backwards, continuing after 405 | * the current position. 406 | */ 407 | #define list_for_each_entry_continue_reverse(pos, head, member) \ 408 | for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ 409 | prefetch(pos->member.prev), &pos->member != (head); \ 410 | pos = list_entry(pos->member.prev, typeof(*pos), member)) 411 | 412 | /** 413 | * list_for_each_entry_from - iterate over list of given type from the current point 414 | * @pos: the type * to use as a loop cursor. 415 | * @head: the head for your list. 416 | * @member: the name of the list_struct within the struct. 417 | * 418 | * Iterate over list of given type, continuing from current position. 419 | */ 420 | #define list_for_each_entry_from(pos, head, member) \ 421 | for (; prefetch(pos->member.next), &pos->member != (head); \ 422 | pos = list_entry(pos->member.next, typeof(*pos), member)) 423 | 424 | /** 425 | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry 426 | * @pos: the type * to use as a loop cursor. 427 | * @n: another type * to use as temporary storage 428 | * @head: the head for your list. 429 | * @member: the name of the list_struct within the struct. 430 | */ 431 | #define list_for_each_entry_safe(pos, n, head, member) \ 432 | for (pos = list_entry((head)->next, typeof(*pos), member), \ 433 | n = list_entry(pos->member.next, typeof(*pos), member); \ 434 | &pos->member != (head); \ 435 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) 436 | 437 | /** 438 | * list_for_each_entry_safe_continue 439 | * @pos: the type * to use as a loop cursor. 440 | * @n: another type * to use as temporary storage 441 | * @head: the head for your list. 442 | * @member: the name of the list_struct within the struct. 443 | * 444 | * Iterate over list of given type, continuing after current point, 445 | * safe against removal of list entry. 446 | */ 447 | #define list_for_each_entry_safe_continue(pos, n, head, member) \ 448 | for (pos = list_entry(pos->member.next, typeof(*pos), member), \ 449 | n = list_entry(pos->member.next, typeof(*pos), member); \ 450 | &pos->member != (head); \ 451 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) 452 | 453 | /** 454 | * list_for_each_entry_safe_from 455 | * @pos: the type * to use as a loop cursor. 456 | * @n: another type * to use as temporary storage 457 | * @head: the head for your list. 458 | * @member: the name of the list_struct within the struct. 459 | * 460 | * Iterate over list of given type from current point, safe against 461 | * removal of list entry. 462 | */ 463 | #define list_for_each_entry_safe_from(pos, n, head, member) \ 464 | for (n = list_entry(pos->member.next, typeof(*pos), member); \ 465 | &pos->member != (head); \ 466 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) 467 | 468 | /** 469 | * list_for_each_entry_safe_reverse 470 | * @pos: the type * to use as a loop cursor. 471 | * @n: another type * to use as temporary storage 472 | * @head: the head for your list. 473 | * @member: the name of the list_struct within the struct. 474 | * 475 | * Iterate backwards over list of given type, safe against removal 476 | * of list entry. 477 | */ 478 | #define list_for_each_entry_safe_reverse(pos, n, head, member) \ 479 | for (pos = list_entry((head)->prev, typeof(*pos), member), \ 480 | n = list_entry(pos->member.prev, typeof(*pos), member); \ 481 | &pos->member != (head); \ 482 | pos = n, n = list_entry(n->member.prev, typeof(*n), member)) 483 | 484 | #endif 485 | -------------------------------------------------------------------------------- /lsusb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * lsusb 3 | * 4 | * Copyright (C) 2009 Kay Sievers 5 | * Copyright (C) 2009 Greg Kroah-Hartman 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License, 9 | * version 2, as published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 30 | 31 | #include 32 | #include "list.h" 33 | #include "usb.h" 34 | #include "lsusb.h" 35 | 36 | 37 | 38 | static LIST_HEAD(usb_devices); 39 | struct udev *udev; 40 | 41 | void *robust_malloc(size_t size) 42 | { 43 | void *data; 44 | 45 | data = malloc(size); 46 | if (data == NULL) 47 | exit(1); 48 | memset(data, 0, size); 49 | return data; 50 | } 51 | 52 | char *get_dev_string(struct udev_device *device, const char *name) 53 | { 54 | const char *value; 55 | 56 | value = udev_device_get_sysattr_value(device, name); 57 | if (value != NULL) 58 | return strdup(value); 59 | return NULL; 60 | } 61 | 62 | 63 | //int main(int argc, char *argv[]) 64 | int main(void) 65 | { 66 | struct udev_enumerate *enumerate; 67 | struct udev_list_entry *list_entry; 68 | 69 | /* libudev context */ 70 | udev = udev_new(); 71 | 72 | /* prepare a device scan */ 73 | enumerate = udev_enumerate_new(udev); 74 | /* filter for usb devices */ 75 | udev_enumerate_add_match_subsystem(enumerate, "usb"); 76 | /* retrieve the list */ 77 | udev_enumerate_scan_devices(enumerate); 78 | /* print devices */ 79 | udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { 80 | struct udev_device *device; 81 | 82 | device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), 83 | udev_list_entry_get_name(list_entry)); 84 | if (device == NULL) 85 | continue; 86 | if (strcmp("usb_device", udev_device_get_devtype(device)) == 0) 87 | // if (strstr(udev_device_get_sysname(device), "usb") != NULL) 88 | create_usb_device(device); 89 | #if 0 90 | printf("%s: ", udev_list_entry_get_name(list_entry)); 91 | printf("\tdevtype: %s\n", udev_device_get_devtype(device)); 92 | printf("\tsubsystem: %s\n", udev_device_get_subsystem(device)); 93 | printf("\tsyspath: %s\n", udev_device_get_syspath(device)); 94 | printf("\tsysnum: %s\n", udev_device_get_sysnum(device)); 95 | printf("\tsysname: %s\n", udev_device_get_sysname(device)); 96 | printf("\tdevpath: %s\n", udev_device_get_devpath(device)); 97 | printf("\tdevnode: %s\n", udev_device_get_devnode(device)); 98 | printf("\tdriver: %s\n", udev_device_get_driver(device)); 99 | 100 | if (strcmp("usb_device", udev_device_get_devtype(device)) == 0) 101 | create_usb_device(device); 102 | 103 | if (strcmp("usb_interface", udev_device_get_devtype(device)) == 0) 104 | create_usb_interface(device); 105 | #endif 106 | 107 | udev_device_unref(device); 108 | } 109 | udev_enumerate_unref(enumerate); 110 | 111 | udev_unref(udev); 112 | sort_usb_devices(); 113 | print_usb_devices(); 114 | free_usb_devices(); 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /lsusb.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _LSUSB_H 3 | #define _LSUSB_H 4 | 5 | /* From the kernel file, include/linux/stringify.h */ 6 | #define __stringify_1(x...) #x 7 | #define __stringify(x...) __stringify_1(x) 8 | 9 | /* Functions in the core */ 10 | void *robust_malloc(size_t size); 11 | char *get_dev_string(struct udev_device *device, const char *name); 12 | extern struct udev *udev; 13 | 14 | /* device.c */ 15 | void create_usb_device(struct udev_device *device); 16 | void free_usb_devices(void); 17 | void sort_usb_devices(void); 18 | void print_usb_devices(void); 19 | 20 | /* interface.c */ 21 | void create_usb_interface(struct udev_device *device, struct usb_device *usb_device); 22 | void free_usb_interface(struct usb_interface *usb_intf); 23 | 24 | /* endpoint.c */ 25 | struct usb_endpoint *create_usb_endpoint(struct udev_device *device, 26 | const char *endpoint_name); 27 | void free_usb_endpoint(struct usb_endpoint *usb_endpoint); 28 | 29 | /* raw.c */ 30 | void read_raw_usb_descriptor(struct udev_device *device, struct usb_device *usb_device); 31 | 32 | #endif /* define _LSUSB_H */ 33 | -------------------------------------------------------------------------------- /raw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * raw.c 3 | * 4 | * Handle "raw" USB config descriptors and the logic to create stuff out 5 | * of them. 6 | * 7 | * Copyright (C) 2009 Greg Kroah-Hartman 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License, 11 | * version 2, as published by the Free Software Foundation. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 32 | 33 | #include 34 | #include "list.h" 35 | #include "usb.h" 36 | #include "lsusb.h" 37 | 38 | 39 | static void parse_config_descriptor(const unsigned char *descriptor) 40 | { 41 | struct usb_config config; 42 | 43 | config.bLength = descriptor[0]; 44 | config.bDescriptorType = descriptor[1]; 45 | config.wTotalLength = (descriptor[3] << 8) | descriptor[2]; 46 | config.bNumInterfaces = descriptor[4]; 47 | config.bConfigurationValue = descriptor[5]; 48 | config.iConfiguration = descriptor[6]; 49 | config.bmAttributes = descriptor[7]; 50 | config.bMaxPower = descriptor[8]; 51 | #if 0 52 | printf("Config descriptor\n"); 53 | printf("\tbLength\t\t\t%d\n", config.bLength); 54 | printf("\tbDescriptorType\t\t%d\n", config.bDescriptorType); 55 | printf("\twTotalLength\t\t%d\n", config.wTotalLength); 56 | printf("\tbNumInterfaces\t\t%d\n", config.bNumInterfaces); 57 | printf("\tbConfigurationValue\t%d\n", config.bConfigurationValue); 58 | printf("\tiConfiguration\t\t%d\n", config.iConfiguration); 59 | printf("\tbmAttributes\t\t0x%02x\n", config.bmAttributes); 60 | printf("\tbMaxPower\t\t%d\n", config.bMaxPower); 61 | #endif 62 | } 63 | 64 | static void parse_interface_descriptor(const unsigned char *descriptor) 65 | { 66 | unsigned char bLength = descriptor[0]; 67 | unsigned char bDescriptorType = descriptor[1]; 68 | unsigned char bInterfaceNumber = descriptor[2]; 69 | unsigned char bAlternateSetting = descriptor[3]; 70 | unsigned char bNumEndpoints = descriptor[4]; 71 | unsigned char bInterfaceClass = descriptor[5]; 72 | unsigned char bInterfaceSubClass = descriptor[6]; 73 | unsigned char bInterfaceProtocol = descriptor[7]; 74 | unsigned char iInterface = descriptor[8]; 75 | #if 0 76 | printf("Interface descriptor\n"); 77 | printf("\tbLength\t\t\t%d\n", bLength); 78 | printf("\tbDescriptorType\t\t%d\n", bDescriptorType); 79 | printf("\tbInterfaceNumber\t%d\n", bInterfaceNumber); 80 | printf("\tbAlternateSetting\t%d\n", bAlternateSetting); 81 | printf("\tbNumEndpoints\t\t%d\n", bNumEndpoints); 82 | printf("\tbInterfaceClass\t\t%d\n", bInterfaceClass); 83 | printf("\tbInterfaceSubClass\t%d\n", bInterfaceSubClass); 84 | printf("\tbInterfaceProtocol\t%d\n", bInterfaceProtocol); 85 | printf("\tiInterface\t\t%d\n", iInterface); 86 | #endif 87 | } 88 | 89 | static void parse_endpoint_descriptor(const unsigned char *descriptor) 90 | { 91 | unsigned char bLength = descriptor[0]; 92 | unsigned char bDescriptorType = descriptor[1]; 93 | unsigned char bEndpointAddress = descriptor[2]; 94 | unsigned char bmAttributes = descriptor[3]; 95 | unsigned short wMaxPacketSize = (descriptor[5] << 8) | descriptor[4]; 96 | unsigned char bInterval = descriptor[6]; 97 | #if 0 98 | printf("Endpoint descriptor\n"); 99 | printf("\tbLength\t\t\t%d\n", bLength); 100 | printf("\tbDescriptorType\t\t%d\n", bDescriptorType); 101 | printf("\tbEndpointAddress\t%0x\n", bEndpointAddress); 102 | printf("\tbmAtributes\t\t%0x\n", bmAttributes); 103 | printf("\twMaxPacketSize\t\t%d\n", wMaxPacketSize); 104 | printf("\tbInterval\t\t%d\n", bInterval); 105 | #endif 106 | } 107 | 108 | static void parse_device_qualifier(struct usb_device *usb_device, const unsigned char *descriptor) 109 | { 110 | struct usb_device_qualifier *dq; 111 | char string[255]; 112 | unsigned char bLength = descriptor[0]; 113 | unsigned char bDescriptorType = descriptor[1]; 114 | unsigned char bcdUSB0 = descriptor[3]; 115 | unsigned char bcdUSB1 = descriptor[2]; 116 | unsigned char bDeviceClass = descriptor[4]; 117 | unsigned char bDeviceSubClass = descriptor[5]; 118 | unsigned char bDeviceProtocol = descriptor[6]; 119 | unsigned char bMaxPacketSize0 = descriptor[7]; 120 | unsigned char bNumConfigurations = descriptor[8]; 121 | 122 | dq = robust_malloc(sizeof(struct usb_device_qualifier)); 123 | 124 | #define build_string(name) \ 125 | sprintf(string, "%d", name); \ 126 | dq->name = strdup(string); 127 | 128 | build_string(bLength); 129 | build_string(bDescriptorType); 130 | build_string(bDeviceClass); 131 | build_string(bDeviceSubClass); 132 | build_string(bDeviceProtocol); 133 | build_string(bMaxPacketSize0); 134 | build_string(bNumConfigurations); 135 | sprintf(string, "%2x.%2x", bcdUSB0, bcdUSB1); 136 | dq->bcdUSB = strdup(string); 137 | 138 | usb_device->qualifier = dq; 139 | 140 | printf("Device Qualifier\n"); 141 | printf("\tbLength\t\t\t%s\n", dq->bLength); 142 | printf("\tbDescriptorType\t\t%s\n", dq->bDescriptorType); 143 | printf("\tbcdUSB\t\t%s", dq->bcdUSB); 144 | } 145 | 146 | void read_raw_usb_descriptor(struct udev_device *device, struct usb_device *usb_device) 147 | { 148 | char filename[PATH_MAX]; 149 | int file; 150 | unsigned char *data; 151 | unsigned char size; 152 | ssize_t read_retval; 153 | 154 | sprintf(filename, "%s/descriptors", udev_device_get_syspath(device)); 155 | 156 | file = open(filename, O_RDONLY); 157 | if (file == -1) 158 | exit(1); 159 | while (1) { 160 | read_retval = read(file, &size, 1); 161 | if (read_retval != 1) 162 | break; 163 | data = malloc(size); 164 | data[0] = size; 165 | read_retval = read(file, &data[1], size-1); 166 | switch (data[1]) { 167 | case 0x01: 168 | /* device descriptor */ 169 | /* 170 | * We get all of this information from sysfs, so no 171 | * need to do any parsing here of the raw data. 172 | */ 173 | break; 174 | case 0x02: 175 | /* config descriptor */ 176 | parse_config_descriptor(data); 177 | break; 178 | case 0x03: 179 | /* string descriptor */ 180 | // parse_string_descriptor(data); 181 | break; 182 | case 0x04: 183 | /* interface descriptor */ 184 | parse_interface_descriptor(data); 185 | break; 186 | case 0x05: 187 | /* endpoint descriptor */ 188 | parse_endpoint_descriptor(data); 189 | break; 190 | case 0x06: 191 | /* device qualifier */ 192 | parse_device_qualifier(usb_device, data); 193 | break; 194 | case 0x07: 195 | /* other speed config */ 196 | break; 197 | case 0x08: 198 | /* interface power */ 199 | break; 200 | default: 201 | break; 202 | } 203 | free(data); 204 | } 205 | close(file); 206 | } 207 | 208 | -------------------------------------------------------------------------------- /short_types.h: -------------------------------------------------------------------------------- 1 | #ifndef CCAN_SHORT_TYPES_H 2 | #define CCAN_SHORT_TYPES_H 3 | #include 4 | 5 | /** 6 | * u64/s64/u32/s32/u16/s16/u8/s8 - short names for explicitly-sized types. 7 | */ 8 | typedef uint64_t u64; 9 | typedef int64_t s64; 10 | typedef uint32_t u32; 11 | typedef int32_t s32; 12 | typedef uint16_t u16; 13 | typedef int16_t s16; 14 | typedef uint8_t u8; 15 | typedef int8_t s8; 16 | 17 | /** 18 | * be64/be32/be16 - 64/32/16 bit big-endian representation. 19 | */ 20 | typedef uint64_t be64; 21 | typedef uint32_t be32; 22 | typedef uint16_t be16; 23 | 24 | /** 25 | * le64/le32/le16 - 64/32/16 bit little-endian representation. 26 | */ 27 | typedef uint64_t le64; 28 | typedef uint32_t le32; 29 | typedef uint16_t le16; 30 | 31 | #endif /* CCAN_SHORT_TYPES_H */ 32 | -------------------------------------------------------------------------------- /usb.h: -------------------------------------------------------------------------------- 1 | #ifndef _USB_H 2 | #define _USB_H 3 | 4 | #include "short_types.h" 5 | 6 | struct usb_endpoint { 7 | struct list_head list; 8 | char *bEndpointAddress; 9 | char *bInterval; 10 | char *bLength; 11 | char *bmAttributes; 12 | char *direction; 13 | char *type; 14 | char *wMaxPacketSize; 15 | }; 16 | 17 | struct usb_config { 18 | struct list_head list; 19 | u8 bLength; 20 | u8 bDescriptorType; 21 | u16 wTotalLength; 22 | u8 bNumInterfaces; 23 | u8 bConfigurationValue; 24 | u8 iConfiguration; 25 | u8 bmAttributes; 26 | u8 bMaxPower; 27 | }; 28 | 29 | struct usb_interface { 30 | struct list_head list; 31 | struct list_head endpoints; 32 | unsigned int configuration; 33 | unsigned int ifnum; 34 | 35 | char *sysname; 36 | char *bAlternateSetting; 37 | char *bInterfaceClass; 38 | char *bInterfaceNumber; 39 | char *bInterfaceProtocol; 40 | char *bInterfaceSubClass; 41 | char *bNumEndpoints; 42 | 43 | char *name; 44 | char *driver; 45 | }; 46 | 47 | struct usb_device_qualifier { 48 | char *bLength; 49 | char *bDescriptorType; 50 | char *bcdUSB; 51 | char *bDeviceClass; 52 | char *bDeviceSubClass; 53 | char *bDeviceProtocol; 54 | char *bMaxPacketSize0; 55 | char *bNumConfigurations; 56 | }; 57 | 58 | struct usb_device { 59 | struct list_head list; /* connect devices independant of the bus */ 60 | struct list_head interfaces; 61 | 62 | char *idProduct; 63 | char *idVendor; 64 | char *busnum; 65 | char *devnum; 66 | char *maxchild; 67 | char *quirks; 68 | char *speed; 69 | char *version; 70 | 71 | char *bConfigurationValue; 72 | char *bDeviceClass; 73 | char *bDeviceProtocol; 74 | char *bDeviceSubClass; 75 | char *bNumConfigurations; 76 | char *bNumInterfaces; 77 | char *bmAttributes; 78 | char *bMaxPacketSize0; 79 | char *bMaxPower; 80 | char *manufacturer; 81 | char *bcdDevice; 82 | char *product; 83 | char *serial; 84 | 85 | struct usb_endpoint *ep0; 86 | struct usb_device_qualifier *qualifier; 87 | char *name; 88 | char *driver; /* always "usb" but hey, it's nice to be complete */ 89 | }; 90 | 91 | #endif /* #define _USB_H */ 92 | --------------------------------------------------------------------------------