From db5a94788a783a716de6c79e23f2e45093aca398 Mon Sep 17 00:00:00 2001 From: Dexter Morgan Date: Thu, 2 Jun 2011 20:49:50 +0000 Subject: Branch for updates --- AUTHORS | 4 + ChangeLog | 1290 ++++++++++++++++++++++++++++++++++++++++++++++++++ MDV/Lspciusb.pm | 63 +++ Makefile | 89 ++++ NEWS | 65 +++ common.c | 110 +++++ common.h | 47 ++ dmi.c | 285 +++++++++++ generate_pciclass.pl | 28 ++ generate_usbclass.pl | 81 ++++ hid.c | 154 ++++++ libldetect.h | 95 ++++ libsysfs.h | 90 ++++ lspcidrake.c | 120 +++++ lspcidrake.pl | 35 ++ modalias.c | 148 ++++++ names.c | 813 +++++++++++++++++++++++++++++++ names.h | 52 ++ pci.c | 112 +++++ pciusb.c | 192 ++++++++ sysfs.h | 64 +++ sysfs_attr.c | 241 ++++++++++ sysfs_utils.c | 59 +++ usb.c | 145 ++++++ 24 files changed, 4382 insertions(+) create mode 100644 AUTHORS create mode 100644 ChangeLog create mode 100755 MDV/Lspciusb.pm create mode 100644 Makefile create mode 100644 NEWS create mode 100644 common.c create mode 100644 common.h create mode 100644 dmi.c create mode 100644 generate_pciclass.pl create mode 100755 generate_usbclass.pl create mode 100644 hid.c create mode 100644 libldetect.h create mode 100644 libsysfs.h create mode 100644 lspcidrake.c create mode 100755 lspcidrake.pl create mode 100644 modalias.c create mode 100644 names.c create mode 100644 names.h create mode 100644 pci.c create mode 100644 pciusb.c create mode 100644 sysfs.h create mode 100644 sysfs_attr.c create mode 100644 sysfs_utils.c create mode 100644 usb.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e9857cb --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Chmouel (cannot open fix) +Guillaume Cottenceau (bug fixes, -v -f options) +Pixel (core developer) +Thierry Vignaud (core developer) diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..62119c9 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1290 @@ +2008-03-20 15:24 Pixel + + * lspcidrake.c: when faking probe (ie -p, -u, --dmidecode), do not + do real probe on other bus + (eg: do not probe pci and usb if using --dmidecode) + +2008-02-29 15:01 Olivier Blin + + * Makefile: 0.7.23 + +2008-02-29 15:00 Olivier Blin + + * pciusb.c: fix bus type (and segfault on x86_64) + +2008-02-28 18:29 Olivier Blin + + * Makefile: 0.7.22 + +2008-02-28 16:53 Olivier Blin + + * pciusb.c: do not free aliasfilename that early (really use + modules.alias file from kernel or ldetect-lst) + +2008-02-27 18:59 Olivier Blin + + * Makefile: 0.7.21 + +2008-02-27 18:51 Olivier Blin + + * pciusb.c: check opendir return code + +2008-02-27 18:34 Olivier Blin + + * pciusb.c: find modules from USB modaliases as well (useful when + module is a + dkms one, or during install where modules are not autoloaded, + this could allow to remove most modules from usbtable) + +2008-02-27 17:57 Olivier Blin + + * pciusb.c: cosmetics + +2008-02-27 17:57 Olivier Blin + + * pciusb.c: extract pci-specific function + +2008-02-27 17:55 Olivier Blin + + * pciusb.c: extract set_modules_from_modalias_file + (bus-independant) + +2008-02-27 17:43 Olivier Blin + + * pciusb.c: move libmodprobe variables declaration + +2008-02-27 17:40 Olivier Blin + + * pciusb.c: make some functions static + +2008-02-27 17:39 Olivier Blin + + * pciusb.c: free modalias + +2008-02-27 17:39 Olivier Blin + + * pciusb.c: free modalias path earlier + +2008-02-27 17:38 Olivier Blin + + * pciusb.c: set module in find_modules_through_aliases_one + +2008-02-27 17:31 Olivier Blin + + * pciusb.c: fix indentation + +2008-02-27 17:31 Olivier Blin + + * pciusb.c: find default alias file once only + +2008-02-27 17:24 Olivier Blin + + * pciusb.c: extract set_modules_from_modalias() + +2008-02-27 17:20 Olivier Blin + + * pciusb.c: remove unused symfilename + +2008-02-27 17:18 Olivier Blin + + * pciusb.c: pass bus to find_modalias + +2008-02-27 16:56 Olivier Blin + + * pciusb.c: extract find_modalias function + +2008-02-27 16:52 Olivier Blin + + * pciusb.c: fix indentation + +2008-02-27 16:51 Olivier Blin + + * pciusb.c: do not ignore subsequent modaliases if resolving one + fails + +2008-02-27 16:25 Olivier Blin + + * common.c, common.h: add back /bin/gzip support, and prefer it if + available (6 hundredths of second faster on my test system, this + should please Titi) + +2008-02-27 16:11 Olivier Blin + + * common.c, common.h, dmi.c, pciusb.c: allow to modify the fh type + more easily by adding more wrappers + +2008-02-27 16:02 Olivier Blin + + * common.c: remove doble zlib.h include + +2008-02-27 16:01 Olivier Blin + + * Makefile: rebuild common.o if common.h has been modified + +2007-09-28 20:00 Olivier Blin + + * Makefile: 0.7.20 + +2007-09-28 20:00 Olivier Blin + + * pciusb.c: fix modalias fd leak (thanks to Anssi for the report) + +2007-08-27 14:24 Thierry Vignaud + + * ChangeLog, Makefile: bump minor (14) + +2007-08-27 13:53 Thierry Vignaud + + * Makefile: ld doesn't like -g, so use gcc back again + +2007-08-27 13:28 Thierry Vignaud + + * Makefile: bump minor (13) + +2007-08-27 13:28 Thierry Vignaud + + * common.h: fix build on x86_64 + +2007-08-27 13:16 Thierry Vignaud + + * pciusb.c: (find_modules_through_aliases) fix test, thus fixing + overwriting Card: in chroot + +2007-08-27 12:43 Thierry Vignaud + + * ChangeLog: kill doble entrie + +2007-08-27 09:47 Thierry Vignaud + + * Makefile, dmi.c, pci.c, pciusb.c: try harder to reduce number of + relocations (most remaining ones are due to + arrays of pointers) + +2007-08-27 09:47 Thierry Vignaud + + * Makefile, common.h, generate_pciclass.pl, generate_usbclass.pl, + libldetect.h: use visibility in order to enforce exported ABI and + to reduce code size + +2007-08-27 09:46 Thierry Vignaud + + * ChangeLog: update + +2007-08-22 17:27 Olivier Blin + + * Makefile: 0.7.12 + +2007-08-22 10:35 Olivier Blin + + * pciusb.c: prefer ldetect-lst's modules.alias if more recent (to + detect modular IDE controllers when run from old kernels) + +2007-08-22 10:24 Olivier Blin + + * pciusb.c: remove spurious argument + +2007-08-20 11:46 Olivier Blin + + * Makefile: bump minor to 11 + +2007-08-20 11:46 Olivier Blin + + * pciusb.c: revert '_' characters substitution + +2007-08-16 15:47 Thierry Vignaud + + * Makefile: bump minor + +2007-08-16 15:40 Thierry Vignaud + + * pciusb.c: (find_modules_through_aliases) plug some memory leak + +2007-08-16 15:34 Thierry Vignaud + + * pciusb.c: (find_modules_through_aliases) fallback to + ldetect-lst's modules.alias + if kernel's modules.alias cannot be found (eg: installer) + +2007-08-16 14:07 Thierry Vignaud + + * Makefile: bump minor (9) + +2007-08-16 14:07 Thierry Vignaud + + * dmi.c: (entries_matching_criteria) fix zlib conversion (#32590) + +2007-08-15 00:23 Olivier Blin + + * Makefile: 0.7.8 + +2007-08-15 00:22 Olivier Blin + + * common.c, common.h, dmi.c, pciusb.c: use zlib to read gzipped + files instead of piping gzip command + +2007-08-14 13:37 Olivier Blin + + * Makefile: 0.7.7 + +2007-08-14 13:35 Thierry Vignaud + + * Makefile: use -rBASE for svn export in order to please blino by + making sure local changes do not got exported + +2007-08-14 12:42 Olivier Blin + + * pciusb.c: replace '_' characters with '-' to be compliant with + pcitable and list_modules.pm + +2007-08-14 12:25 Olivier Blin + + * Makefile: build static library + +2007-08-14 12:24 Olivier Blin + + * Makefile: move objects list in lib_objs variable + +2007-08-14 11:55 Olivier Blin + + * pci.c: remove old 8139too/gdth hardcoded rules (already in + modules.alias) + +2007-08-07 13:29 Thierry Vignaud + + * Makefile: bump minor (6) + +2007-08-07 13:28 Thierry Vignaud + + * pciusb.c: (find_modules_through_aliases) exit() is not nice error + managment in a library + +2007-08-07 10:46 Pixel + + * pciusb.c: - don't free before printing + - print fatal error on stderr + +2007-08-07 13:28 Thierry Vignaud + + * pciusb.c: (find_modules_through_aliases) exit() is not nice error + managment in a library + +2007-08-07 10:46 Pixel + + * pciusb.c: - don't free before printing + - print fatal error on stderr + +2007-08-06 15:34 Thierry Vignaud + + * Makefile: bump minor (5) + +2007-08-06 15:33 Thierry Vignaud + + * pciusb.c: (pciusb_find_modules) handle pcitable without + description field + +2007-08-06 12:45 Thierry Vignaud + + * Makefile: bump minor (4) + +2007-08-06 11:22 Thierry Vignaud + + * ChangeLog: update + +2007-08-06 11:21 Thierry Vignaud + + * ChangeLog: update + +2007-08-04 09:11 Thierry Vignaud + + * pci.c: (pci_probe) simplify + +2007-08-04 09:11 Thierry Vignaud + + * pci.c: (pci_probe) kill some quirks that are either obsolete now + that we + resolve modalias (which bring wildcard support) or were removed + from + the kernel (eg: sata_nv do not more probe on class) + +2007-08-04 08:10 Thierry Vignaud + + * Makefile: bump minor (3) + +2007-08-04 08:10 Thierry Vignaud + + * Makefile, common.h, pci.c, pciusb.c, usb.c: reuse modprobe code + in order to resolve modalias (need to be optimized) + +2007-07-04 16:04 Thierry Vignaud + + * Makefile: (changelog) typo fix + +2007-07-03 17:48 Thierry Vignaud + + * Makefile: (changelog) --strip-prefix is now uneeded with + svn2cl-0.9 + +2007-05-07 07:59 Pixel + + * : new release, 0.7.1 (build with zlib which is needed by libpci) + +2007-02-26 16:56 Thierry Vignaud + + * MDV/Lspciusb.pm: use libldetect for parsing pci.ids & getting PCI + description (thus shrinking execution time by 13%) + +2007-02-26 15:01 Thierry Vignaud + + * pci.c: (pci_probe) typo fix :-( + +2007-02-26 13:55 Thierry Vignaud + + * Makefile: bump major after ABI changes + +2007-02-26 13:55 Thierry Vignaud + + * libldetect.h, pci.c: export PCI domain + +2007-02-26 13:55 Thierry Vignaud + + * pci.c: (pci_probe) get PCI class as reported by pciutils (might + be used by harddrake + in order to display something nicer than ->{media_type}) + +2007-02-26 13:54 Thierry Vignaud + + * libldetect.h, pciusb.c: (struct pciusb_entry) add a class field + +2007-02-26 13:53 Thierry Vignaud + + * generate_pciclass.pl, generate_usbclass.pl, libldetect.h, + lspcidrake.c, pci.c, pciusb.c, usb.c: (struct pciusb_entry) + rename class_ as class_id + +2007-02-26 13:53 Thierry Vignaud + + * pci.c: (pci_probe) remove an extra space wronly added in r125837 + +2007-02-26 13:51 Thierry Vignaud + + * pci.c: (pci_probe) replace a couple magic valyes by constants + from pciutils + +2007-02-26 13:51 Thierry Vignaud + + * pci.c, usb.c: stop performing descriptions lookup from pcitable + for PCI + +2007-02-26 13:49 Thierry Vignaud + + * common.h, pciusb.c: (pciusb_find_modules) add "descr_lookup" + parameter to enable/disable description lookup + +2007-02-26 13:48 Thierry Vignaud + + * pci.c: (pci_probe) use pciutils in order to get device + description from /usr/share/pci.ids + +2007-02-26 13:48 Thierry Vignaud + + * Makefile, pci.c: switch to pciutils as PCI listing backend + +2007-02-22 20:58 Thierry Vignaud + + * Makefile: get rid of rpm packaging rules + +2007-02-22 20:54 Thierry Vignaud + + * Makefile: use svn export instead of tar for preparing the tarball + +2007-02-12 17:31 Thierry Vignaud + + * MDV/Lspciusb.pm: (list) enable to scan only pci or usb bus + +2007-02-12 14:41 Pixel + + * MDV/.perl_checker: unneeded + +2007-02-12 14:23 Thierry Vignaud + + * MDV/Lspciusb.pm, lspcidrake.pl: perl_checker cleanups + +2007-02-12 14:22 Thierry Vignaud + + * .perl_checker, MDV/.perl_checker: blacklist enough modules in + order to let perl_checker run + +2007-02-12 14:20 Thierry Vignaud + + * MDV, MDV/Lspciusb.pm, lspcidrake.pl: move detection code from + lspcidrake.pl into MDV::Lspciusb + +2007-02-12 14:13 Thierry Vignaud + + * lspcidrake.pl: add copyright header + +2007-02-12 14:11 Thierry Vignaud + + * lspcidrake.pl: (read_pciids) rename "class" as "vendor" since it + really is + +2007-01-10 15:40 Thierry Vignaud + + * .cvsignore, .svnignore: rename b/c of CVS -> SVN switch + +2007-01-10 15:39 Thierry Vignaud + + * Makefile: bump release + +2007-01-10 15:14 Thierry Vignaud + + * usb.c: (usb_probe) fix parsing /proc/bus/usb/devices with + kernel-2.6.20 + (eg: "I:* If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 + Driver=usb-storage") + +2006-11-06 14:38 Thierry Vignaud + + * Makefile: bump minor + +2006-11-06 14:36 Thierry Vignaud + + * ldetect.spec: 0.6.6-1mdv2007.1 + +2006-11-06 14:36 Thierry Vignaud + + * Makefile: (log) switch from CVS to SVN + +2006-11-06 14:27 Thierry Vignaud + + * usb.c: (usb_probe) fix parsing /proc/bus/usb/devices with large + "parent + device" field (eg when some special usb keys are plugged on a non + root + USB hub) + +2006-07-12 18:27 Olivier Blin + + * ldetect.spec: add missing changelog entry + +2006-07-12 18:26 Olivier Blin + + * ldetect.spec: ldetect-0.6.5-1mdv2007.0 + +2006-07-12 18:21 Olivier Blin + + * Makefile: update minor + +2006-07-12 18:21 Olivier Blin + + * Makefile: use dis target + +2006-07-12 17:40 Olivier Blin + + * Makefile: use spec file from current directory + +2006-07-12 17:39 Olivier Blin + + * Makefile: drop duplicated warning (already in the spec) + +2006-07-12 16:13 Olivier Blin + + * dmi.c: dmidecode >= 2.7 support + +2006-06-27 20:35 Olivier Blin + + * lspcidrake.pl: initial lspcidrake immplementation using modalias + +2006-06-07 16:17 Thierry Vignaud + + * ldetect.spec: add standard cvs warning + +2006-02-22 13:11 Thierry Vignaud + + * usb.c: fix freeing a reference to a constant string (fredl) + +2006-01-05 15:58 Gwenole Beauchesne + + * ldetect.spec: fix url (mandriva) + +2006-01-05 15:42 Gwenole Beauchesne + + * pci.c: always initialize n_pci_domains, stick to 0 on opendir() + error and no match + +2006-01-05 15:38 Gwenole Beauchesne + + * ldetect.spec: 0.6.4-1mdk + +2006-01-05 15:38 Gwenole Beauchesne + + * pci.c: add support for pci domains + +2005-10-17 08:32 Pixel + + * ldetect.spec: fix rpm Group + +2005-08-05 13:22 Thierry Vignaud + + * ChangeLog: *** empty log message *** + +2005-08-05 13:21 Thierry Vignaud + + * ldetect.spec: 0.6.3-1mdk + +2005-08-05 13:20 Thierry Vignaud + + * usb.c: (usb_probe) prevent spurious warnings for strange USB + interfaces + +2005-08-03 09:03 Pixel + + * lspcidrake.c: when given a dmidecode_file, we don't need to be + root + +2005-05-16 04:11 Thierry Vignaud + + * ChangeLog: *** empty log message *** + +2005-05-16 04:11 Thierry Vignaud + + * ldetect.spec: 0.6.2-1mdk + +2005-05-16 03:19 Thierry Vignaud + + * lspcidrake.c: do not try to run dmidecode when not root + +2005-03-30 15:08 Thierry Vignaud + + * ChangeLog: *** empty log message *** + +2005-03-30 15:06 Thierry Vignaud + + * ldetect.spec: 0.6.1-1mdk + +2005-03-30 15:03 Thierry Vignaud + + * pci.c: oops: sata_via doesn't support for CLASS probing whereas + sata_nv does + +2005-03-14 17:20 Pixel + + * Makefile, common.c, common.h, dmi.c, ldetect.spec, + libldetect-private.h, libldetect.h, lspcidrake.c, pci.c, + pciusb.c, usb.c: libify and simplify + +2005-03-14 13:10 Pixel + + * pciusb.c: fix running on a empty pci/usb devices source + +2005-03-14 12:34 Pixel + + * lspcidrake.c: fix typo + +2005-03-14 12:33 Pixel + + * pciusb.c: fix a memory leak + +2005-03-14 12:32 Pixel + + * Makefile, common.c, common.h, dmi.c, ldetect.spec, + libldetect-private.h, libldetect.h, lspcidrake.c, pciusb.c: add + dmitable use + +2005-03-11 09:43 Pixel + + * pci.c: setting .nb to 0 seems a better idea than setting .entries + +2005-02-23 17:48 Pablo Saratxaga + + * ChangeLog: converted to UTF-8 + +2005-02-17 14:16 Thierry Vignaud + + * ChangeLog: *** empty log message *** + +2005-02-17 14:16 Thierry Vignaud + + * ldetect.spec: fill in 0.5.5-1mdk's changelog + +2005-02-17 14:15 Thierry Vignaud + + * ldetect.spec: 0.5.5-1mdk + +2005-02-17 14:15 Thierry Vignaud + + * pci.c: handle a few more special cases (gdth, snd-vx222, 8139too, + and agp bridges) + +2005-02-17 12:26 Thierry Vignaud + + * pci.c: detect VIA SATA controllers since new sata_via.c driver + probes them + this way... (we should really add a class/... matching table like + kernel's pcimap is) + +2004-12-07 16:06 Pixel + + * ldetect.spec, pci.c: all PCI_CLASS_BRIDGE_CARDBUS cards are + yenta_socket (says kudzu) + +2004-10-28 08:08 Thierry Vignaud + + * ChangeLog: *** empty log message *** + +2004-10-28 08:07 Thierry Vignaud + + * ldetect.spec: 0.5.3-1mdk + +2004-10-27 13:35 Thierry Vignaud + + * Makefile: make ldetect-devel usable on amd64 + +2004-10-27 13:21 Thierry Vignaud + + * pciusb.c: keep existing description string if already reported by + the device + +2004-06-17 08:35 Thierry Vignaud + + * ldetect.spec: 0.5.2-1mdk + +2004-06-17 08:33 Thierry Vignaud + + * usb.c: (usb_probe) ask the kernel for module to use with usb + devices + +2003-11-20 15:20 Pixel + + * generate_usbclass.pl, ldetect.spec: don't display "Vendor + Specific Class" usb class + +2003-11-20 15:03 Pixel + + * generate_usbclass.pl, ldetect.spec, libldetect.h, lspcidrake.c: + new usb_class code (breaks compatibility!) + +2003-08-20 09:11 Thierry Vignaud + + * lspcidrake.c: remove dummy reference to silently ignored -f + option + +2003-08-20 00:23 Pixel + + * lspcidrake.c: fix argument testing + +2003-08-20 00:21 Pixel + + * generate_pciclass.pl, generate_usbclass.pl, usb.c: a little + cleanup + +2003-08-19 21:28 Thierry Vignaud + + * ChangeLog, ldetect.spec, libldetect-private.h, libldetect.h, + lspcidrake.c, pci.c, pciusb.c, usb.c: do full-probe by default; + remove support for no full-probe + +2003-07-31 13:36 Pixel + + * ldetect.spec, pci.c: - detect ohci1394 & ehci-hcd based on the + pci class + (as done in RedHat's kudzu) + + This should fix freezes when doing a full probe + +2003-04-22 09:04 Pixel + + * pci.c: Use read() instead of fread() to read from + "/proc/bus/pci/%02x/%02x.%d". + Thanks a lot to Tom Cox for finding this bug: + + The proc.c module in the kernel source clearly states that + reading more than 64 bytes can cause problems. The pci.c + module in the ldetect library uses the buffered fread() + function. This function always reads in blocks, so when + run as root, the read always tried to read more than the + user requested amount. + +2003-01-28 15:44 Thierry Vignaud + + * Makefile: only check for latest logs + +2003-01-28 14:39 Thierry Vignaud + + * ChangeLog, Makefile: - sanitize ChangeLog + - add log rule + +2003-01-06 14:34 Thierry Vignaud + + * ChangeLog: *** empty log message *** + +2003-01-06 14:34 Thierry Vignaud + + * ldetect.spec: add pixel changes + +2003-01-06 14:32 Thierry Vignaud + + * ldetect.spec: 0.4.8-1mdk + +2003-01-06 14:24 Thierry Vignaud + + * pciusb.c: special case for buggy 0x0 usb entry so that we + eventually got a + class, thus normalizing lspcidrake & harddrake output + +2002-11-05 15:12 Pixel + + * pci.c, usb.c: no error message when -p is not used and there is + neither pci nor usb bus + +2002-11-05 14:27 Thierry Vignaud + + * usb.c: fix access check + +2002-10-15 14:40 Thierry Vignaud + + * ldetect.spec: 0.4.7-1mdk + +2002-10-07 09:32 Thierry Vignaud + + * pciusb.c: enforce gc coding rules + +2002-10-07 09:21 Thierry Vignaud + + * pciusb.c: - remove gc hack that tried to fix my bug + (which i fixed in last commit) + + - simplify subids match; explay why we can only test for nb==4 + +2002-10-07 07:47 Thierry Vignaud + + * pciusb.c: fix "skipping already handled device" (aka kill stupid + remaining test) + +2002-10-04 15:30 Guillaume Cottenceau + + * pciusb.c: try to detect correctly the module when subv/subd + differ with non-subv/subd + +2002-09-12 10:20 Thierry Vignaud + + * AUTHORS: fix gc + +2002-09-05 11:25 Pixel + + * ldetect.spec, pciusb.c: fix ugly case for snd-usb-audio which + should have made titi think that + something was broken. Really fixing the right way (this fixes + automatic + detection of unknown usb controllers) + +2002-08-29 12:18 Pixel + + * ldetect.spec: fix getting the Product name in usb (occurs when + there is no entry in usbtable) + +2002-08-29 12:17 Pixel + + * usb.c: fix getting the Product name + +2002-08-29 12:17 Thierry Vignaud + + * pci.c: fix PCI_CLASS_PROG offset + +2002-08-26 02:50 Thierry Vignaud + + * ChangeLog, ldetect.spec: 0.4.6-4mdk + +2002-08-25 22:47 Thierry Vignaud + + * pci.c: - kill last fseek + - change if(cdt) cascade into if(!cdt) continue + - move loop invariant out of loop + +2002-08-22 10:31 Thierry Vignaud + + * ChangeLog, ldetect.spec: 0.4.6-3mdk + +2002-08-22 10:27 Thierry Vignaud + + * pci.c: try to not freeze on buggy motherboard by preventing: + - seeking in /proc/bus/pci//. + - not reading the whole /proc/bus/pci//. + + we now read 48 linear bytes the same way lspci read 64 linear + bytes. + +2002-08-17 14:18 Thierry Vignaud + + * ldetect.spec: - rpmlint fixes (url, doc) + - simplification + +2002-08-17 14:12 Thierry Vignaud + + * Makefile: split rpm target in srpm and rpm + +2002-08-17 14:08 Thierry Vignaud + + * ChangeLog, ldetect.spec: 4.6mdk + +2002-08-17 14:06 Thierry Vignaud + + * Makefile: default RPM to ~/rpm + +2002-08-16 16:07 Thierry Vignaud + + * ChangeLog: *** empty log message *** + +2002-08-16 16:03 Thierry Vignaud + + * Makefile, pci.c, usb.c: - usb.c: allocate mem as pci.c does + - usb.c: kill dead code + - usb.c: give url to get info on /proc/bus/usb/devices format + - usb.c: the /proc/bus/usb/devices really is a state machine; + use switch to make it clearer + - {usb,pci}.c: r.nb is zeroed in all path, let's do it only time + +2002-08-15 21:23 Thierry Vignaud + + * pciusb.c, usb.c: usb audio devices can use new alsa modules + snd-usb-audio + +2002-08-08 15:25 Thierry Vignaud + + * ChangeLog, ldetect.spec: 0.4.5-1mdk: don't depend of the table + order + +2002-08-08 15:20 Thierry Vignaud + + * libldetect.h, pciusb.c: - struct pciusb_entrie : add + already_found flag + - pciusb::pciusb_initialize() : zero the above flag: + - pciusb::pciusb_find_modules() : use the above flag: + o if device subids matches the table ones, + swtich the already_found flag + o skip already handled device (if already_found==1) + +2002-07-31 11:42 Pixel + + * ldetect.spec: use -fPIC on every arch + +2002-07-30 19:03 Pixel + + * ldetect.spec, usb.c: fill in pci_bus and pci_device for USB + +2002-07-25 12:07 Thierry Vignaud + + * ldetect.spec: 0.4.4-1mdk + +2002-07-25 12:05 Thierry Vignaud + + * ChangeLog: *** empty log message *** + +2002-07-25 12:04 Thierry Vignaud + + * pciusb.c: fix "(null) description" bug: don't skip entries where + module has + already be set by pci.c workaround + +2002-07-24 15:22 Thierry Vignaud + + * ldetect.spec: 0.4.3-1mdk + +2002-07-23 08:10 Thierry Vignaud + + * lspcidrake.c: enhanced help + +2002-07-22 21:37 Pixel + + * ldetect.spec, pci.c, usb.c: - don't die when missing + /proc/bus/pci/devices (resp. /proc/bus/usb/devices), + since on some boxes, this is *normal*! + - free error messages obtained via asprintf + - remove debugging message "TOTO" + +2002-07-16 20:36 Pixel + + * ldetect.spec, pciusb.c: teach titi that !(a && !b) is not (!a && + !b) but (!a || b) + (the other solution is to teach him to *test*) + (oh, remind me to teach him not to re-indent the whole code until + he + doesn't make stupid bugs) + +2002-07-16 15:34 Thierry Vignaud + + * ChangeLog, ldetect.spec: next release is ok + +2002-07-16 15:33 Thierry Vignaud + + * lspcidrake.c: explain what does -f + +2002-07-16 15:30 Thierry Vignaud + + * pci.c: no need for unistd.h + +2002-07-16 15:29 Thierry Vignaud + + * ChangeLog, pci.c, usb.c: - print error message if unable to open + the arguement passed to -u,-p + + - print error message if usb service isn't started (commented for + now + to follow previous behaviour) + +2002-07-16 15:28 Thierry Vignaud + + * lspcidrake.c: - fix usb "url" + + - prevent potential segfault if no argument to -u in next test + +2002-07-16 15:07 Thierry Vignaud + + * ChangeLog, ldetect.spec, libldetect-private.h, lspcidrake.c, + pci.c: - pci.c: add the ability to read pci devices list from a + file instead + of /proc/bus/pci/devices + + - spec: prepare for next release + + - add ChangeLog + +2002-07-16 14:54 Thierry Vignaud + + * libldetect-private.h, lspcidrake.c, usb.c: - move usb devices + proc entry path into + libldetect-private.h::proc_usb_path + + - add -u option so that lspcidrake can read usb devices from a + file in + order to understand what happened to remote testers + + - make if (test) action clearer by rejecting action singleton in + next + line + + - lspcidrake: describe all options + +2002-07-16 14:51 Thierry Vignaud + + * pci.c: - change memory pattern : MAX*sizeof(entry) on stack + + REAL_NB*sizeof() in heap + to MAX*sizeof(entry) on heap then downsized to real size + + - make if (test) action clearer by rejecting action singleton in + next line + +2002-07-16 14:39 Thierry Vignaud + + * pci.c: don't do useless stuff when full probe isn't requires: + - allocatestuff on stack + - call snprintf + +2002-07-15 16:26 Thierry Vignaud + + * lspcidrake.c: compacificazion + +2002-07-09 21:28 Thierry Vignaud + + * lspcidrake.c: fix for "gcc-2.95.3 don't compile" (reported by Ian + White) + +2002-07-05 09:02 Thierry Vignaud + + * Makefile: add explicit depandancies so that make rebuild files if + needed when header're altered + +2002-07-05 08:56 Thierry Vignaud + + * Makefile: compile with -Os (which results in saving 12% of text + size) + +2002-07-04 15:15 Thierry Vignaud + + * pci.c: factorize common constants in private header + +2002-07-04 15:14 Thierry Vignaud + + * usb.c: typo fix + +2002-07-04 15:14 Thierry Vignaud + + * usb.c: - factorize common constants in private header + + - factorize strlen() call + +2002-07-04 15:04 Thierry Vignaud + + * libldetect-private.h, pci.c, usb.c: factorize common constants in + private header + +2002-07-04 14:59 Thierry Vignaud + + * lspcidrake.c: we don't really need stdlib.h + +2002-07-04 14:58 Thierry Vignaud + + * lspcidrake.c: move full_probe definition nearer its usage, aka in + main() + + - kill print_name() and print_id() [used only once] + +2002-07-04 14:53 Thierry Vignaud + + * lspcidrake.c: - merge {pci,usb}_printit into printit + + - kill usage() + +2002-07-04 11:44 Thierry Vignaud + + * ldetect.spec: 0.4.1-1mdk + +2002-07-04 11:29 Thierry Vignaud + + * usb.c: make an if clearer + +2002-07-03 12:03 Thierry Vignaud + + * pciusb.c: s/zcat/gzip -cd/ back for lord pixou + +2002-07-03 10:20 Thierry Vignaud + + * pciusb.c: ifree(e->text) to prevent mem leak with usb + +2002-07-03 10:09 Thierry Vignaud + + * pciusb.c: - fix pipe() error path + + - make pciusb_find_modules() normal path clearer: rewrite tests + cascade into a single path were exceptions're just "go away" + +2002-07-03 10:01 Thierry Vignaud + + * pciusb.c: - make gzip path in fh_open() be clearer + + - pciusb_find_modules() optimization / cleanups : + + - only calc module and description once so that if there're + multiples identical cards, we just gives the same result + + - do less copies : + - only copy when setting e->{text,module} + + - it's useless to do copies on the stack, just play with + strndup() instead of strdup() + + - skip comments in {usb,pci}table + + - remove if (q) test which is uneeded since we've already parsed + the buffer with sscanf() and we've skipped comments + + - remove uneeded ifree (it's impossible to get valid pointer a + this point) + +2002-07-03 09:14 Thierry Vignaud + + * pciusb.c: - no need to allocate fname_gz in fast path + + - reduce cmd size + + - use zcat rather than gzip + +2002-07-03 09:06 Thierry Vignaud + + * libldetect-private.h, pci.c, pciusb.c, usb.c: get rid of more + uneeded copies + +2002-07-03 09:05 Thierry Vignaud + + * AUTHORS: list all contributors + +2002-07-03 08:54 Thierry Vignaud + + * pci.c, usb.c: get rid of {pci,usb}_find_modules() + +2002-07-03 08:53 Thierry Vignaud + + * libldetect.h, lspcidrake.c: prevent signed vs unsigned comp + warnings + +2002-07-03 08:49 Thierry Vignaud + + * lspcidrake.c, pci.c, pciusb.c, usb.c: indent-region + +2002-07-03 08:42 Thierry Vignaud + + * libldetect.h, lspcidrake.c, pciusb.c: don't do uneeded copies + (saves 2% of text size) + +2002-07-03 08:41 Thierry Vignaud + + * Makefile: be more strict + +2002-07-03 08:27 Thierry Vignaud + + * lspcidrake.c: simplify (source is clearer, binary isn't really + altered) + +2002-06-26 14:10 Gwenole Beauchesne + + * ldetect.spec: sanitize specfile + +2002-06-10 18:39 Pixel + + * generate_pciclass.pl, generate_usbclass.pl, ldetect.spec, + libldetect.h, lspcidrake.c, pci.c, pciusb.c, usb.c: ensure the + header file are C++ compliant (do not use "class" for struct + field name) + +2002-05-06 18:48 Pixel + + * AUTHORS: *** empty log message *** + +2001-12-28 12:04 Pixel + + * ldetect.spec, pci.c: in probe_type=1, recognize usb controllers + (is either usb-uhci or usb-ohci) + +2001-11-22 23:16 Guillaume Cottenceau + + * generate_usbclass.pl: - don't limitate to CLASS ID's with a + Protocol number + - fix bug that made ID's with a-f not appear (\d not very + good to parse hexadecimal) + +2001-10-11 15:44 Pixel + + * ldetect.spec: s/Copyright/License/ + +2001-09-13 13:41 Pixel + + * generate_pciclass.pl, generate_usbclass.pl, ldetect.spec, + libldetect.h, usb.c: use the sub-category for usb probing + +2001-09-10 22:11 Guillaume Cottenceau + + * ldetect.spec, lspcidrake.c: add "-v" and "-f" options to + lspcidrake for (v)erbose mode and (f)ull probe + +2001-08-29 16:33 Pixel + + * ldetect.spec: fix when 2 similar devices are there + +2001-07-03 20:28 Pixel + + * pciusb.c: fix pb when 2 similar cards are there + +2001-04-12 15:15 Pixel + + * ldetect.spec, pciusb.c: close fdno's of the pipe which are unused + or dup2'ed + +2001-04-12 15:15 Pixel + + * generate_usbclass.pl: add the line in comment + +2001-04-11 16:53 Fançois Pons + + * ldetect.spec, pciusb.c: *** empty log message *** + +2001-04-05 00:12 Chmouel Boudjnah + + * usb.c: Don't print ugly can't open. + +2001-03-29 10:38 Pixel + + * ldetect.spec: fix some memory leak and a few segfaults + +2001-03-29 10:36 Pixel + + * pciusb.c: fix some memory leak a few segfaults + +2001-03-24 10:48 Pixel + + * ldetect.spec, pciusb.c: nasty C, fclose on popen'ed gets a + segfault, in /some/ cases :-( + +2001-03-23 15:17 Pixel + + * ldetect.spec, pciusb.c: handle gzip'ed pcitable/usbtable + +2001-03-21 18:05 Pixel + + * ldetect.spec: use subids if they are needed + +2001-03-21 18:03 Pixel + + * libldetect-private.h, lspcidrake.c, pci.c, pciusb.c, usb.c: if + subid can be useful, use them. use probe_type==-1 to ensure no + subid is used + +2001-03-15 14:11 Fançois Pons + + * ldetect.spec: *** empty log message *** + +2001-03-15 14:00 Fançois Pons + + * ldetect.spec, libldetect.h, pci.c, pciusb.c: added + pci(bus,device,function) for DrakX. + +2001-03-06 16:17 Fançois Pons + + * ldetect.spec, pci.c, usb.c: *** empty log message *** + +2001-03-06 16:05 Pixel + + * ldetect.spec: *** empty log message *** + +2001-02-13 12:25 uid553 + + * common.h: ifree must be a macro, so let it be + +2001-02-10 11:53 Pixel + + * pci.c: fix the fclose + +2001-02-06 16:56 Pixel + + * ldetect.spec: add missing fclose's + +2001-02-06 16:55 Pixel + + * pci.c, pciusb.c: add some fclose where it should + +2000-12-22 14:53 Guillaume Cottenceau + + * ldetect.spec, lspcidrake.c: see changelog + +2000-12-16 18:22 Pixel + + * ., .cvsignore, Makefile, common.h, generate_usbclass.pl, + ldetect.spec, libldetect-private.h, libldetect.h, lspcidrake.c, + pci.c, pciusb.c, usb.c: now detect usb + +2000-12-15 18:19 Pixel + + * Makefile: *** empty log message *** + +2000-12-15 15:32 Pixel + + * ldetect.spec: - add requires ldetect-lst + +2000-12-15 15:30 Pixel + + * ldetect.spec: fix description tag + +2000-12-15 15:25 Pixel + + * Makefile, ldetect.spec: put the version in .spec too, otherwise + can't use rpm C-c e :) + +2000-12-15 15:19 Pixel + + * Makefile, generate_pciclass.pl, ldetect.spec, libldetect.h, + lspcidrake.c, pci.c: creation + +2000-12-15 15:19 + + * soft/ldetect/branches, soft/ldetect/tags, .: New repository + initialized by cvs2svn. + diff --git a/MDV/Lspciusb.pm b/MDV/Lspciusb.pm new file mode 100755 index 0000000..f3a3227 --- /dev/null +++ b/MDV/Lspciusb.pm @@ -0,0 +1,63 @@ +package MDV::Lspciusb; +#***************************************************************************** +# +# Copyright (c) 2006-2007 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: Lspciusb.pm 44676 2007-02-26 16:56:43Z tv $ + +use lib qw(/usr/lib/libDrakX); +use modalias; +use MDK::Common; +use detect_devices; + +my %bus_get_description = ( + usb => sub { + my ($dev_path, $_values) = @_; + my $full_path = dirname($dev_path) . "/" . readlink($dev_path); + my $parent_path = dirname($full_path); + chomp_(cat_("$parent_path/product")); + }, +); + +sub list { + my (@bus) = @_; + @bus = qw(usb) if !@bus; + map { + my ($modalias_path, $desc); + if (ref $_) { + my $device = $_; + $modalias_path = sprintf('/sys/bus/pci/devices/%04x:%02x:%02x.%x/modalias', $device->{pci_domain}, $device->{pci_bus}, $device->{pci_device}, $device->{pci_function}); + $desc = $device->{description}; + } else { + $modalias_path = $_; + } + my $modalias = chomp_(cat_($modalias_path)); + my $dev_path = dirname($modalias_path); + my ($bus, $values) = $modalias =~ /^([^:]+):(\S+)$/; # modalias::get_bus + my @modules = modalias::get_modules($modalias); + my $module = first(@modules) || "unknown"; + my $modules = @modules > 1 ? " (" . join(",", @modules) . ")" : ""; + if (my $get_desc = $bus_get_description{$bus} and !$desc) { + $desc = $get_desc->($dev_path, $values); + } + $desc ||= "unknown"; + { module => $module, descr => $desc, modules => $modules }; + } detect_devices::pci_probe(), map { glob("/sys/bus/$_/devices/*/modalias") } @bus; +} + +1; diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..79aee5b --- /dev/null +++ b/Makefile @@ -0,0 +1,89 @@ +NAME = ldetect +LIB_MAJOR = 0.11 +LIB_MINOR = 1 +VERSION=$(LIB_MAJOR).$(LIB_MINOR) + +prefix = /usr +bindir = $(prefix)/bin +libdir = $(prefix)/lib +includedir = $(prefix)/include + +binaries = lspcidrake +lib_objs = common.o hid.o modalias.o pciusb.o pci.o usb.o pciclass.o usbclass.o dmi.o sysfs_attr.o sysfs_utils.o names.o +lib_major = libldetect.so.$(LIB_MAJOR) +libraries = libldetect.so $(lib_major) $(lib_major).$(LIB_MINOR) libldetect.a +CFLAGS = -Wall -W -Wstrict-prototypes -Os -fPIC -fvisibility=hidden -g + +RPM ?= $(HOME)/rpm + +build: $(binaries) $(libraries) + +lspcidrake: lspcidrake.c libldetect.so + +$(lib_major).$(LIB_MINOR): $(lib_objs) + $(CC) -shared -Wl,-z,relro -Wl,-O1,-soname,$(lib_major) -o $@ $^ -lpci -lmodprobe -lz +$(lib_major): $(lib_major).$(LIB_MINOR) + ln -sf $< $@ +libldetect.so: $(lib_major) + ln -sf $< $@ + +libldetect.a: $(lib_objs) + ar -cru $@ $^ + ranlib $@ + +pciclass.c: /usr/include/linux/pci.h /usr/include/linux/pci_ids.h + rm -f $@ + perl generate_pciclass.pl $^ > $@ + chmod a-w $@ + +usbclass.c: /usr/share/usb.ids + rm -f $@ + perl generate_usbclass.pl $^ > $@ + chmod a-w $@ + +common.o: common.c common.h +pciusb.o: pciusb.c libldetect.h common.h +pci.o: pci.c libldetect.h common.h +usb.o: usb.c libldetect.h common.h names.h +dmi.o: dmi.c libldetect.h common.h +names.o: names.c names.h +sysfs_attr.o: sysfs_attr.c sysfs.h libsysfs.h +sysfs_utils.o: sysfs_utils.c sysfs.h libsysfs.h + +clean: + rm -f *~ *.o pciclass.c usbclass.c $(binaries) $(libraries) + +install: build + install -d $(bindir) $(libdir) $(includedir) + install $(binaries) $(bindir) + cp -a $(libraries) $(libdir) + install libldetect.h $(includedir) + +dist: dis +dis ../$(NAME)-$(VERSION).tar.bz2: tar + +tar: + @if [ -e ".svn" ]; then \ + $(MAKE) dist-svn; \ + elif [ -e ".git" ]; then \ + $(MAKE) dist-git; \ + else \ + echo "Unknown SCM (not SVN nor GIT)";\ + exit 1; \ + fi; + $(info $(NAME)-$(VERSION).tar.bz2 is ready) + +dist-svn: + svn export -q -rBASE . $(NAME)-$(VERSION) + tar cfj ../$(NAME)-$(VERSION).tar.bz2 $(NAME)-$(VERSION) + rm -rf $(NAME)-$(VERSION) + +dist-git: + @git archive --prefix=$(NAME)-$(VERSION)/ HEAD | bzip2 >../$(NAME)-$(VERSION).tar.bz2; + + +log: + svn2cl --authors ../common/username.xml --accum + +run: lspcidrake + LD_LIBRARY_PATH=$(PWD) ./lspcidrake diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..83f77e2 --- /dev/null +++ b/NEWS @@ -0,0 +1,65 @@ +Version 0.11.1 - 1 December 2009, Thierry Vignaud + +- do not crash if there're more than 100 PCI devices +- further use libpci in order to check for PCIe capability + +Version 0.11.0 - 1 October 2009, Thierry Vignaud + +- reduce memory footprint + +Version 0.10.0 - 30 September 2009, Thierry Vignaud + +- do not display random revisions for USB devices +- retrieve PCI capabilities in order to better identify PCI Express devices + +Version 0.9.1 - 28 September 2009, Thierry Vignaud + +- fix inverted test for choosing between '8139cp' & '8139too' drivers (#53349) + +Version 0.9.0 - 23 September 2009, Thierry Vignaud + +- display PCI revision (#42576) +- try harder to fetch the right driver between '8139cp' & '8139too' + according to PCI revision (#53349) + +Version 0.8.6 - 23 September 2009, Pascal Terjan + +- parse only once usb.ids (avoids displaying Duplicate errors) + +Version 0.8.5 - 14 September 2009, Pascal Terjan + +- do not display any warning when driver field is empty in + /proc/bus/usb/devices (#53412) +- fix freed memory usage in criteria_from_dmidecode and entries_matching_criteria +- fix const warnings in dmi.c + +Version 0.8.4 - 25 June 2009, Pascal Terjan + +- fix freed memory usage in usb_probe and pci_probe +- use usb.ids + +Version 0.8.3 - 20 April 2009, Pascal Terjan + +- fix parsing of /proc/bus/usb/device I: lines and use the class + of the first interface used by a driver instead of the first + interface (or first one like before when none is used). + That fixed presenting something as usb_storage even if the + device is ignored by usb_storage driver and handled on another + interface by option driver +- ignore usb interfaces not active + +Version 0.8.1 - 3 April 2009, Christophe Fergeau + +- enumerate hid bus +- fixes some memory leaks + +Version 0.8.0 - 27 March 2009, Olivier Blin + +- do not use random string as device description +- use /sys/bus/usb/devices instead of /sys/class/usb_device + (disabled in recent kernel) to find modalias + (this breaks ABI because we now need to keep port number) + +Version 0.7.26 - 14 May 2008, Thierry Vignaud + +- adapt to pciutils-3.x API diff --git a/common.c b/common.c new file mode 100644 index 0000000..58d45ee --- /dev/null +++ b/common.c @@ -0,0 +1,110 @@ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "common.h" + +char *table_name_to_file(const char *name) { + + char *share_path = getenv("SHARE_PATH"); + char *fname; + if (!share_path || !*share_path) share_path = "/usr/share"; + + asprintf(&fname, "%s/ldetect-lst/%s", share_path, name); + + return fname; +} + +fh fh_open(const char *name) { + fh ret; + char *fname = table_name_to_file(name); + + if (access(fname, R_OK) == 0) { + /* prefer gzip type when not compressed, more direct than zlib access */ + ret.gztype = GZIP; + ret.u.gzip_fh.f = fopen(fname, "r"); + ret.u.gzip_fh.pid = 0; + } else { + char *fname_gz; + asprintf(&fname_gz, "%s.gz", fname); + if (access(GZIP_BIN, R_OK) == 0) { + int fdno[2]; + ret.gztype = GZIP; + if (access(fname_gz, R_OK) != 0) { + fprintf(stderr, "Missing %s (should be %s)\n", name, fname); + exit(1); + } + if (pipe(fdno)) { + perror("pciusb"); + exit(1); + } + + if ((ret.u.gzip_fh.pid = fork()) != 0) { + ret.u.gzip_fh.f = fdopen(fdno[0], "r"); + close(fdno[1]); + } else { + char* cmd[5]; + int ip = 0; + char *ld_loader = getenv("LD_LOADER"); + + if (ld_loader && *ld_loader) + cmd[ip++] = ld_loader; + + cmd[ip++] = GZIP_BIN; + cmd[ip++] = "-cd"; + cmd[ip++] = fname_gz; + cmd[ip++] = NULL; + + dup2(fdno[1], STDOUT_FILENO); + close(fdno[0]); + close(fdno[1]); + execvp(cmd[0], cmd); + perror("pciusb"); + exit(2); + } + } else { + ret.gztype = ZLIB; + ret.u.zlib_fh = gzopen(fname_gz, "r"); + if (!ret.u.zlib_fh) { + perror("pciusb"); + exit(3); + } + } + free(fname_gz); + } + + free(fname); + return ret; +} + +char* fh_gets(char *line, int size, fh *f) { + char *ret = NULL; + switch (f->gztype) { + case ZLIB: + ret = gzgets(f->u.zlib_fh, line, size); + break; + case GZIP: + ret = fgets(line, size, f->u.gzip_fh.f); + break; + } + return ret; +} + +int fh_close(fh *f) { + int ret = EOF; + switch (f->gztype) { + case ZLIB: + ret = gzclose(f->u.zlib_fh); + break; + case GZIP: + ret = fclose(f->u.gzip_fh.f); + if (f->u.gzip_fh.pid > 0) + waitpid(f->u.gzip_fh.pid, NULL, 0); + break; + } + return ret; +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..e6f927d --- /dev/null +++ b/common.h @@ -0,0 +1,47 @@ +#ifndef LIBLDETECT_COMMON +#define LIBLDETECT_COMMON + +#include "libldetect.h" +#include + +#define NON_EXPORTED __attribute__((visibility("hidden"))) + +#pragma GCC visibility push(hidden) + +#define GZIP_BIN "/bin/gzip" + +extern char *table_name_to_file(const char *name); + +typedef enum { + LOAD, + DO_NOT_LOAD, +} descr_lookup; + +extern int pciusb_find_modules(struct pciusb_entries *entries, const char *fpciusbtable, const descr_lookup, int is_pci) NON_EXPORTED; +extern void pciusb_initialize(struct pciusb_entry *e) NON_EXPORTED; +extern char *modalias_resolve_module(const char *modalias) NON_EXPORTED; +extern void modalias_cleanup(void) NON_EXPORTED; + +#define MAX_DEVICES 100 +#define BUF_SIZE 512 + +typedef struct { + enum { ZLIB, GZIP } gztype; + union { + struct { + FILE *f; + pid_t pid; + } gzip_fh; + gzFile zlib_fh; + } u; +} fh; + +#define psizeof(a) (sizeof(a) / sizeof(*(a))) +#define ifree(p) do { if (p) { free(p); p = NULL; } } while (0) + +extern fh fh_open(const char *name) NON_EXPORTED; +extern char* fh_gets(char *line, int size, fh *f) NON_EXPORTED; +extern int fh_close(fh *f) NON_EXPORTED; +#pragma GCC visibility pop + +#endif diff --git a/dmi.c b/dmi.c new file mode 100644 index 0000000..b927994 --- /dev/null +++ b/dmi.c @@ -0,0 +1,285 @@ +/* DMI (Desktop Management Interface) + also called + SMBIOS (System Management BIOS) +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include "common.h" + +char *dmidecode_file = NULL; + + +static const char *cat_BIOS[] = { "Vendor", "Version" }; +static const char *cat_System[] = { "Manufacturer", "Product Name", "Version" }; +static const char *cat_Base_Board[] = { "Manufacturer", "Product Name", "Version" }; + +struct category { + const char *cat_name; + unsigned int nb_fields; + const char **fields; +}; + +static const struct category categories[] = { + { "BIOS", psizeof(cat_BIOS), cat_BIOS }, + { "System", psizeof(cat_System), cat_System }, + { "Base Board", psizeof(cat_Base_Board), cat_Base_Board }, + +}; +static int nb_categories = psizeof(categories); + +struct criterion { + char *name; + char *val; +}; +struct criteria { + unsigned int nb; + struct criterion *criteria; +}; + +/*********************************************************************************/ +static int streq(const char *s1, const char *s2) { + return strcmp(s1, s2) == 0; +} +static int str_begins_with(const char *s, const char *prefix) { + return strncmp(s, prefix, strlen(prefix)) == 0; +} +static int remove_suffix_in_place(char *s, const char *suffix) { + unsigned int l = strlen(s); + unsigned int l_suffix = strlen(suffix); + if (l >= l_suffix && streq(s + l - l_suffix, suffix)) { + s[l - l_suffix] = '\0'; + return 1; + } else + return 0; +} +static void remove_ending_spaces(char *s) { + char *p; + for (p = s + strlen(s) - 1; p >= s; p--) { + if (*p != '\n' && *p != '\r' && *p != ' ' && *p != '\t') + break; + *p = '\0'; + } +} +static char *skip_leading_spaces(char *s) { + for (; *s; s++) + if (*s != '\n' && *s != '\r' && *s != ' ' && *s != '\t') + break; + return s; +} + +/*********************************************************************************/ +static char *get_after_colon(char *s) { + char *p = strchr(s, ':'); + if (p) { + *p = '\0'; + return p + (p[1] == ' ' ? 2 : 1); + } else return NULL; +} + +static const struct category *lookup_category(const char *cat_name) { + int i; + for (i = 0; i < nb_categories; i++) + if (streq(categories[i].cat_name, cat_name)) + return &categories[i]; + return NULL; +} + +static int lookup_field(const struct category *category, const char *field_name) { + unsigned int i; + for (i = 0; i < category->nb_fields; i++) + if (streq(category->fields[i], field_name)) + return 1; + return 0; +} + +static char *lookup_criteria(struct criteria criteria, const char *field) { + unsigned int i; + for (i = 0; i < criteria.nb; i++) + if (streq(criteria.criteria[i].name, field)) + return criteria.criteria[i].val; + return NULL; +} + +/*********************************************************************************/ +static struct criteria criteria_from_dmidecode(void) { + FILE *f; + char buf[BUF_SIZE]; + + struct criteria r = {0, NULL}; + + if (!(f = dmidecode_file ? fopen(dmidecode_file, "r") : popen("dmidecode", "r"))) { + perror("dmidecode"); + return r; + } + + r.criteria = malloc(sizeof(*r.criteria) * MAX_DEVICES); + + const struct category *category = NULL; + + /* dmidecode output is less indented as of 2.7 */ + int tab_level = 1; + if (fgets(buf, sizeof(buf) - 1, f)) { + int major, minor; + if (sscanf(buf, "# dmidecode %d.%d", &major, &minor) == 2 && major >= 2 && minor >= 7) + tab_level = 0; + } + + while (fgets(buf, sizeof(buf) - 1, f)) { + if (!buf[0] || !buf[1] || (tab_level && buf[0] != '\t')) + ; /* don't care */ + else if (buf[tab_level] != '\t') { + char *s = buf + tab_level; + if (!str_begins_with(s, "DMI type ")) { + remove_ending_spaces(s); + remove_suffix_in_place(s, " Information"); + category = lookup_category(s); + } + } else if (category) { + /* don't even look if we don't have an interesting category */ + char *s = buf + tab_level + 1; + char *val = get_after_colon(s); + if (val && lookup_field(category, s)) { + struct criterion *criterion = &r.criteria[r.nb++]; + asprintf(&criterion->name, "%s/%s", category->cat_name, s); + remove_ending_spaces(val); + criterion->val = strdup(skip_leading_spaces(val)); + } + } + } + if (dmidecode_file ? fclose(f) != 0 : pclose(f) == -1) { + r.nb = 0; + return r; + } + r.criteria = realloc(r.criteria, sizeof(*r.criteria) * r.nb); + + return r; +} + +static void free_criteria(struct criteria criteria) { + unsigned int i; + for (i = 0; i < criteria.nb; i++) { + free(criteria.criteria[i].name); + free(criteria.criteria[i].val); + } + if (criteria.nb) free(criteria.criteria); + criteria.nb = 0; +} + +static struct dmi_entries entries_matching_criteria(struct criteria criteria) { + fh f; + char buf[2048]; + int line; + struct dmi_entries r; + #define MAX_INDENT 20 + int valid[MAX_INDENT]; + char *constraints[MAX_INDENT]; + + enum state { in_constraints, in_implies } state = in_implies; + int was_a_blank_line = 1; + + r.nb = 0; + f = fh_open("dmitable"); + +#define die(err) do { fprintf(stderr, "%s %d: " err "\n", "dmitable", line); exit(1); } while (0) + + r.entries = malloc(sizeof(*r.entries) * MAX_DEVICES); + +#define foreach_indent(min, action) do { int i; for (i = min; i < MAX_INDENT; i++) { action; } } while (0) + + foreach_indent(0, valid[i] = 1; constraints[i] = NULL); + + int previous_refine = 0; + + for (line = 1; fh_gets(buf, sizeof(buf) - 1, &f); line++) { + char *s = skip_leading_spaces(buf); + if (*s == '#') continue; // skip comments + + if (!*s) { + was_a_blank_line = 1; + } else { + int refine = s - buf; + if (refine > MAX_INDENT) die("too indented constraints"); + + remove_ending_spaces(s); + if (str_begins_with(s, "=> ")) { + if (refine != previous_refine) die("\"=>\" must not be indented"); + state = in_implies; + was_a_blank_line = 0; + + if (valid[refine]) { + struct dmi_entry *entry = &r.entries[r.nb++]; + + s += strlen("=> "); + char *val = get_after_colon(s); + if (!val) die("invalid value"); + asprintf(&entry->module, "%s:%s", s, val); + + char tmp[BUF_SIZE]; + tmp[0] = '\0'; + + int i; + for (i = 0; i <= refine; i++) + if (constraints[i]) { + if (i) strncat(tmp, "|", BUF_SIZE); + strncat(tmp, constraints[i], BUF_SIZE); + } + entry->constraints = strdup(tmp); + } + } else { + if (state == in_constraints && refine == previous_refine) die("to refine, indent"); + if (!was_a_blank_line) die("missing empty line"); + state = in_constraints; + previous_refine = refine; + was_a_blank_line = 0; + + if (refine == 0 || valid[refine - 1]) { + + char *wanted_val = get_after_colon(s); + if (!wanted_val) die("bad format"); + + char *wanted_val_orig = strdup(wanted_val); + char *val = lookup_criteria(criteria, s); + + int ok = wanted_val && val && ( + remove_suffix_in_place(wanted_val, ".*") ? + str_begins_with(val, wanted_val) : + streq(val, wanted_val)); + + foreach_indent(refine, valid[i] = ok; ifree(constraints[i])); + if (ok) + constraints[refine] = wanted_val_orig; + else + free(wanted_val_orig); + + } /* otherwise no need checking */ + } + } + } + foreach_indent(0, ifree(constraints[i])); + fh_close(&f); + + r.entries = realloc(r.entries, sizeof(*r.entries) * r.nb); + return r; +} + +extern void dmi_entries_free(struct dmi_entries entries) { + unsigned int i; + for (i = 0; i < entries.nb; i++) { + free(entries.entries[i].constraints); + free(entries.entries[i].module); + } + if (entries.nb) free(entries.entries); + entries.nb = 0; +} + +extern struct dmi_entries dmi_probe(void) { + struct criteria criteria = criteria_from_dmidecode(); + struct dmi_entries entries = entries_matching_criteria(criteria); + free_criteria(criteria); + + return entries; +} + diff --git a/generate_pciclass.pl b/generate_pciclass.pl new file mode 100644 index 0000000..948431d --- /dev/null +++ b/generate_pciclass.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl + +print q(/* This auto-generated from , don't modify! */ + +static struct { + unsigned short id; + const char *name; +} classes[] = { +); + +/^#define PCI_CLASS_(\w+)\s+(0x\w{4})/ and print qq( { $2, "$1" },\n) while <>; + +print ' +}; + +static int nb_classes = sizeof(classes) / sizeof(*classes); + +#pragma GCC visibility push(default) +extern const char *pci_class2text(unsigned long class_id) { + int i; + for (i = 0; i < nb_classes; i++) + if (classes[i].id == class_id) return classes[i].name; + + return pci_class2text(0); +} +#pragma GCC visibility pop + +'; diff --git a/generate_usbclass.pl b/generate_usbclass.pl new file mode 100755 index 0000000..de533ed --- /dev/null +++ b/generate_usbclass.pl @@ -0,0 +1,81 @@ +#!/usr/bin/perl + +print q(/* This is auto-generated from , don't modify! */ + +#define NULL 0 + +struct node { + int id; + const char *name; + int nb_subnodes; + struct node *subnodes; +}; + +); + +my (@l, $sub, $subsub); +while (<>) { + chomp; + if (/^C\s+([\da-f]+)\s+(.*)/) { #- I want alphanumeric but I can't get this [:alnum:] to work :-( + push @l, [ $1, $2, $sub = [] ]; + undef $subsub; + } elsif (/^\t([\da-f]+)\s+(.*)/ && defined $sub) { + my ($sub_id, $sub_descr) = ($1, $2); + $sub_id =~ /^[\da-f]{2}$/ or die "bad line $.: sub category number badly formatted ($_)\n"; + push @$sub, [ $sub_id, $sub_descr, $subsub = [] ]; + } elsif (/^\t\t([\da-f]+)\s+(.*)/ && defined $subsub) { + push @$subsub, [ $1, $2, [] ]; + } elsif (/^\S/) { + undef $sub; + undef $subsub; + } +} + +sub dump_it { + my ($l, $name, $prefix) = @_; + + my @l = sort { $a->[0] cmp $b->[0] } @$l or return; + + dump_it($_->[2], $name . '_' . $_->[0], "$prefix ") foreach @l; + + print "${prefix}static struct node $name\[] = {\n"; + foreach (@l) { + my $nb = @{$_->[2]}; + my $sub = $nb ? $name . '_' . $_->[0] : 'NULL'; + printf qq($prefix { 0x%x, "%s", $nb, $sub },\n), hex($_->[0]), $_->[1]; + } + print "$prefix};\n"; +} + +dump_it(\@l, "classes", ''); + +print ' + +static int nb_classes = sizeof(classes) / sizeof(*classes); + +static void lookup(const char **p, int *a_class, int kind, int nb_nodes, struct node *nodes) { + int i; + for (i = 0; i < nb_nodes; i++) + if (nodes[i].id == a_class[kind]) { + p[kind] = nodes[i].name; + return lookup(p, a_class, kind + 1, nodes[i].nb_subnodes, nodes[i].subnodes); + } +} + +struct class_text { + const char *class_text; + const char *sub_text; + const char *prot_text; +}; + +extern struct class_text __attribute__ ((visibility("default"))) usb_class2text(unsigned long class_id) { + const char *p[3] = { NULL, NULL, NULL }; + int a_class[3] = { (class_id >> 16) & 0xff, (class_id >> 8) & 0xff, class_id & 0xff }; + if (a_class[0] != 0xff) lookup(p, a_class, 0, nb_classes, classes); + { + struct class_text r = { p[0], p[1], p[2] }; + return r; + } +} + +'; diff --git a/hid.c b/hid.c new file mode 100644 index 0000000..2103c00 --- /dev/null +++ b/hid.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include + +#include "libsysfs.h" +#include "libldetect.h" +#include "common.h" + + +#define HID_BUS_NAME "hid" +const char *sysfs_hid_path = "/sys/bus/"HID_BUS_NAME"/devices"; +#if 0 +#define DEBUG(args...) printf(args) +#else +#define DEBUG(args...) +#endif + +#if 0 +struct module_alias { + const char *modalias; + const char *module; +}; + +static struct module_alias aliasdb[] = { {NULL, NULL} }; +static const char *resolve_modalias(const struct module_alias *aliasdb, + const char *alias_name) +{ + const struct module_alias *alias = aliasdb; + + while (alias->modalias != NULL) { + if (fnmatch(alias->modalias, alias_name, 0) == 0) + return alias->module; + + alias++; + } + return NULL; +} +#endif + +static char *get_field_value(const char *fields, const char *field_name) +{ + char *modalias; + char *end; + + modalias = strstr(fields, field_name); + if (modalias == NULL) + return NULL; + end = strchr(modalias, '\n'); + if (end == NULL) + end = modalias + strlen(modalias); + + return strndup(modalias+strlen(field_name), end - (modalias+strlen(field_name))); +} + +static char *parse_modalias(char *fields) +{ + return get_field_value(fields, "MODALIAS="); +} + +static char *parse_name(char *fields) +{ + return get_field_value(fields, "HID_NAME="); +} + +static void add_entry(struct hid_entries *entry_list, char *name, char *module) +{ + + struct hid_entry *new_entries; + + new_entries = realloc(entry_list->entries, (entry_list->nb+1)*sizeof(*(entry_list->entries))); + if (new_entries != NULL) { + new_entries[entry_list->nb].module = module; + new_entries[entry_list->nb].text = name; + entry_list->entries = new_entries; + entry_list->nb++; + } +} + +static void parse_device(struct hid_entries *entries, const char *dev) +{ + char keyfile[SYSFS_PATH_MAX]; + char *modalias; + char *modname; + char *device_name; + struct sysfs_attribute *sysfs_attr; + + snprintf(keyfile, sizeof(keyfile)-1, "%s/%s/uevent", + sysfs_hid_path, dev); + sysfs_attr = sysfs_open_attribute(keyfile); + if (!sysfs_attr) + return; + if (sysfs_read_attribute(sysfs_attr) != 0 || !sysfs_attr->value) { + sysfs_close_attribute(sysfs_attr); + return; + } + + DEBUG("%s: read %s\n", HID_BUS_NAME, sysfs_attr->value); + + modalias = parse_modalias(sysfs_attr->value); + if (modalias == NULL) + return; + DEBUG("%s: modalias is [%s]\n", HID_BUS_NAME, modalias); + + device_name = parse_name(sysfs_attr->value); + sysfs_close_attribute(sysfs_attr); + if (device_name != NULL) + DEBUG("%s: device name is [%s]\n", HID_BUS_NAME, device_name); + else + device_name = strdup("HID Device"); + + modname = modalias_resolve_module(modalias); + free(modalias); + DEBUG("%s: module name is [%s]\n", HID_BUS_NAME, modname); + if (modname != NULL) + add_entry(entries, device_name, modname); +} + + +struct hid_entries hid_probe(void) +{ + DIR *dir; + struct dirent *dent; + struct hid_entries entry_list = {NULL, 0}; + + dir = opendir(sysfs_hid_path); + if (dir == NULL) + goto end_probe; + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + if (dent->d_name[0] == '.') + continue; + DEBUG("%s: device found %s\n", HID_BUS_NAME, dent->d_name); + parse_device(&entry_list, dent->d_name); + } + +end_probe: + if (dir) + closedir(dir); + + return entry_list; +} + +void hid_entries_free(struct hid_entries *entries) +{ + unsigned int i; + for (i = 0; i < entries->nb; i++) { + free(entries->entries[i].module); + free(entries->entries[i].text); + } + free(entries->entries); +} diff --git a/libldetect.h b/libldetect.h new file mode 100644 index 0000000..7c02ae2 --- /dev/null +++ b/libldetect.h @@ -0,0 +1,95 @@ +#pragma GCC visibility push(default) +#ifndef LIBLDETECT +#define LIBLDETECT + +#include + +/******************************************************************************/ +/* pciusb *********************************************************************/ +/******************************************************************************/ +struct pciusb_entry { + uint16_t vendor; /* PCI vendor id */ + uint16_t device; /* PCI device id */ + + uint16_t subvendor; /* 0xffff if not probe_type'd or no subid */ + uint16_t subdevice; /* 0xffff if not probe_type'd or no subid */ + unsigned long class_id; /* 0 if not probe_type'd ; big because of USB backend */ + + uint16_t pci_domain; /* PCI domain id (16 bits wide in libpci) */ + uint8_t pci_bus; /* PCI bus id 8 bits wide */ + uint8_t pci_device; /* PCI device id 5 bits wide */ + uint8_t pci_function; /* PCI function id 3 bits wide */ + uint8_t pci_revision; /* PCI revision 8 bits wide */ + + unsigned short usb_port; /* USB port */ + uint8_t is_pciexpress:1; /* is it PCI express */ + uint8_t already_found:1; + + char *module; + char *text; + char* class; +}; +struct pciusb_entries { + struct pciusb_entry *entries; + unsigned int nb; +}; + +extern void pciusb_free(struct pciusb_entries *entries); + + +/******************************************************************************/ +/* pci ************************************************************************/ +/******************************************************************************/ +extern struct pciusb_entries pci_probe(void); +extern const char *pci_class2text(unsigned long class_id); +extern char *proc_pci_path; + +/******************************************************************************/ +/* usb ************************************************************************/ +/******************************************************************************/ +extern struct pciusb_entries usb_probe(void); + +struct usb_class_text { + const char *usb_class_text; + const char *usb_sub_text; + const char *usb_prot_text; +}; + +extern struct usb_class_text usb_class2text(unsigned long class_id); + +extern char *proc_usb_path; + +/******************************************************************************/ +/* dmi ************************************************************************/ +/******************************************************************************/ +struct dmi_entry { + char *constraints; + char *module; +}; +struct dmi_entries { + struct dmi_entry *entries; + unsigned int nb; +}; + +extern struct dmi_entries dmi_probe(void); +extern void dmi_entries_free(struct dmi_entries entries); +extern char *dmidecode_file; + +/******************************************************************************/ +/* hid ************************************************************************/ +/******************************************************************************/ +struct hid_entry { + char *module; + char *text; +}; +struct hid_entries { + struct hid_entry *entries; + unsigned int nb; +}; + +extern struct hid_entries hid_probe(void); +extern void hid_entries_free(struct hid_entries *entries); +extern const char *sysfs_hid_path; + +#endif +#pragma GCC visibility pop diff --git a/libsysfs.h b/libsysfs.h new file mode 100644 index 0000000..7bdf54f --- /dev/null +++ b/libsysfs.h @@ -0,0 +1,90 @@ +/* + * libsysfs.h + * + * Header Definitions for libsysfs + * + * Copyright (C) IBM Corp. 2004-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef _LIBSYSFS_H_ +#define _LIBSYSFS_H_ + +#include +#include + +#define SYSFS_FSTYPE_NAME "sysfs" +#define SYSFS_PROC_MNTS "/proc/mounts" +#define SYSFS_BUS_NAME "bus" +#define SYSFS_CLASS_NAME "class" +#define SYSFS_BLOCK_NAME "block" +#define SYSFS_DEVICES_NAME "devices" +#define SYSFS_DRIVERS_NAME "drivers" +#define SYSFS_MODULE_NAME "module" +#define SYSFS_NAME_ATTRIBUTE "name" +#define SYSFS_MOD_PARM_NAME "parameters" +#define SYSFS_MOD_SECT_NAME "sections" +#define SYSFS_UNKNOWN "unknown" +#define SYSFS_PATH_ENV "SYSFS_PATH" + +#define SYSFS_PATH_MAX 256 +#define SYSFS_NAME_LEN 64 +#define SYSFS_BUS_ID_SIZE 32 + +/* mount path for sysfs, can be overridden by exporting SYSFS_PATH */ +#define SYSFS_MNT_PATH "/sys" + +enum sysfs_attribute_method { + SYSFS_METHOD_SHOW = 0x01, /* attr can be read by user */ + SYSFS_METHOD_STORE = 0x02, /* attr can be changed by user */ +}; + +/* + * NOTE: + * 1. We have the statically allocated "name" as the first element of all + * the structures. This feature is used in the "sorter" function for dlists + * 2. As is the case with attrlist + * 3. As is the case with path + */ +struct sysfs_attribute { + char name[SYSFS_NAME_LEN]; + char path[SYSFS_PATH_MAX]; + char *value; + unsigned short len; /* value length */ + enum sysfs_attribute_method method; /* show and store */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Function Prototypes + */ +extern int sysfs_get_name_from_path(const char *path, char *name, size_t len); + +/* sysfs directory and file access */ +extern void sysfs_close_attribute(struct sysfs_attribute *sysattr); +extern struct sysfs_attribute *sysfs_open_attribute(const char *path); +extern int sysfs_read_attribute(struct sysfs_attribute *sysattr); +extern int sysfs_write_attribute(struct sysfs_attribute *sysattr, + const char *new_value, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSYSFS_H_ */ diff --git a/lspcidrake.c b/lspcidrake.c new file mode 100644 index 0000000..9637671 --- /dev/null +++ b/lspcidrake.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include "libldetect.h" + +static int verboze = 0; + +static void printit(struct pciusb_entries entries, void print_class(unsigned long )) { + unsigned int i; + for (i = 0; i < entries.nb; i++) { + struct pciusb_entry *e = &entries.entries[i]; + printf("%-16s: ", e->module ? e->module : "unknown"); + if (e->text) + printf(e->text); + else printf("unknown (%04x/%04x/%04x/%04x)", e->vendor, e->device, e->subvendor, e->subdevice); + if (e->class_id) { + print_class(e->class_id); + } + if (verboze && e->text) { + printf(" (vendor:%04x device:%04x", e->vendor, e->device); + if (e->subvendor != 0xffff || e->subdevice != 0xffff) + printf(" subv:%04x subd:%04x", e->subvendor, e->subdevice); + printf(")"); + } + if (e->pci_revision) + printf(" (rev: %02x)", e->pci_revision); + printf("\n"); + } + pciusb_free(&entries); +} + +static void print_pci_class(unsigned long class_id) { + const char *s = pci_class2text(class_id); + if (strcmp(s, "NOT_DEFINED") != 0) + printf(" [%s]", s); +} + +static void print_usb_class(unsigned long class_id) { + struct usb_class_text s = usb_class2text(class_id); + if (s.usb_class_text) { + printf(" ["); + printf("%s", s.usb_class_text); + if (s.usb_sub_text) printf("|%s", s.usb_sub_text); + if (s.usb_prot_text) printf("|%s", s.usb_prot_text); + printf("]"); + } +} + +static void print_dmi_entries(struct dmi_entries entries) { + unsigned int i; + for (i = 0; i < entries.nb; i++) + printf("%-16s: %s\n", entries.entries[i].module, entries.entries[i].constraints); +} + +static void print_hid_entries(struct hid_entries entries) { + unsigned int i; + for (i = 0; i < entries.nb; i++) + printf("%-16s: %s\n", entries.entries[i].module, + entries.entries[i].text); +} + +static void usage(void) +{ + printf( + "usage: lspcidrake [options]\n" + "\t-p, --pci-file \tPCI devices source [/proc/bus/pci/devices by default]\n" + "\t-u, --usb-file \tUSB devices source [/proc/bus/usb/devices by default]\n" + "\t-v, --verbose\t\tVerbose mode [print ids and sub-ids], implies full probe\n" + "\t-d, --dmidecode \tTo use this dmidecode output instead of calling demicode\n"); +} + +int main(int argc, char **argv) { + int opt, fake = 0; + struct option options[] = { { "verbose", 0, NULL, 'v' }, + { "pci-file", 1, NULL, 'p' }, + { "usb-file", 1, NULL, 'u' }, + { "dmidecode", 0, NULL, 'd' }, + { NULL, 0, NULL, 0 } }; + + while ((opt = getopt_long(argc, argv, "vp:u:d", options, NULL)) != -1) { + switch (opt) { + case 'v': + verboze = 1; + break; + case 'p': + proc_pci_path = optarg; + fake = 1; + break; + case 'u': + proc_usb_path = optarg; + fake = 1; + break; + case 'd': + dmidecode_file = optarg; + fake = 1; + break; + default: + usage(); + return 1; + } + } + + if (!fake || proc_pci_path) printit(pci_probe(), print_pci_class); + if (!fake || proc_usb_path) printit(usb_probe(), print_usb_class); + + if (!fake && geteuid() == 0 || dmidecode_file) { + struct dmi_entries dmi_entries = dmi_probe(); + print_dmi_entries(dmi_entries); + dmi_entries_free(dmi_entries); + } + + if (!fake || sysfs_hid_path) { + struct hid_entries hid_entries = hid_probe(); + print_hid_entries(hid_entries); + hid_entries_free(&hid_entries); + } + + return 0; +} diff --git a/lspcidrake.pl b/lspcidrake.pl new file mode 100755 index 0000000..864b441 --- /dev/null +++ b/lspcidrake.pl @@ -0,0 +1,35 @@ +#!/usr/bin/perl +#***************************************************************************** +# +# Copyright (c) 2006-2007 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: lspcidrake.pl 44475 2007-02-12 14:23:36Z tv $ + +use lib qw(/usr/lib/libDrakX); +use modalias; +use MDK::Common; +use MDV::Lspciusb; + +if (@ARGV) { + print "$_: " . join(",", modalias::get_modules($_)) . "\n" foreach @ARGV; + exit(); +} + +foreach my $device (MDV::Lspciusb::list()) { + print "$device->{module}\t: $device->{descr}$device->{modules}\n"; +} diff --git a/modalias.c b/modalias.c new file mode 100644 index 0000000..86494c6 --- /dev/null +++ b/modalias.c @@ -0,0 +1,148 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +static char *aliasdefault = NULL; + +static void free_aliases(struct module_alias *aliases) { + if (aliases == NULL) + return; + while (aliases->next) { + struct module_alias *next; + next = aliases->next; + free(aliases->module); + free(aliases); + aliases = next; + } + free(aliases); +} + +static void free_options(struct module_options *modoptions) { + if (modoptions == NULL) + return; + while (modoptions->next) { + struct module_options *next; + next = modoptions->next; + free(modoptions->modulename); + free(modoptions->options); + free(modoptions); + modoptions = next; + } + free(modoptions); +} + +static void free_commands(struct module_command *commands) { + if (commands == NULL) + return; + while (commands->next) { + struct module_command *next; + next = commands->next; + free(commands->modulename); + free(commands->command); + free(commands); + commands = next; + } + free(commands); +} + +static void free_blacklist(struct module_blacklist *blacklist) { + if (blacklist == NULL) + return; + while (blacklist->next) { + struct module_blacklist *next; + next = blacklist->next; + free(blacklist->modulename); + free(blacklist); + blacklist = next; + } + free(blacklist); +} + +static void set_default_alias_file(void) { + struct utsname rel_buf; + if (!aliasdefault) { + char *dirname; + char *fallback_aliases = table_name_to_file("fallback-modules.alias"); + char *aliasfilename; + struct stat st_alias, st_fallback; + + uname(&rel_buf); + asprintf(&dirname, "%s/%s", MODULE_DIR, rel_buf.release); + asprintf(&aliasfilename, "%s/modules.alias", dirname); + free(dirname); + + /* fallback on ldetect-lst's modules.alias and prefer it if more recent */ + if (stat(aliasfilename, &st_alias) || + (!stat(fallback_aliases, &st_fallback) && st_fallback.st_mtime > st_alias.st_mtime)) { + free(aliasfilename); + aliasdefault = fallback_aliases; + } else { + aliasdefault = aliasfilename; + } + } +} + +char *modalias_resolve_module(const char *modalias) { + struct module_command *commands = NULL; + struct module_options *modoptions = NULL; + struct module_alias *aliases = NULL; + struct module_blacklist *blacklist = NULL; + const char *config = NULL; + + if (!aliasdefault) + set_default_alias_file(); + + /* Returns the resolved alias, options */ + read_toplevel_config(config, modalias, 0, + 0, &modoptions, &commands, &aliases, &blacklist); + + if (!aliases) { + /* We only use canned aliases as last resort. */ + char *dkms_file = table_name_to_file("dkms-modules.alias"); + char *alias_filelist[] = { + "/lib/module-init-tools/ldetect-lst-modules.alias", + aliasdefault, + dkms_file, + NULL, + }; + char **alias_file = alias_filelist; + while (!aliases && *alias_file) { + read_config(*alias_file, modalias, 0, + 0, &modoptions, &commands, + &aliases, &blacklist); + aliases = apply_blacklist(aliases, blacklist); + alias_file++; + } + free(dkms_file); + } + free_blacklist(blacklist); + free_commands(commands); + free_options(modoptions); + if (aliases) { + char *result; + // take the last one because we find eg: generic/ata_generic/sata_sil + struct module_alias *it = aliases; + while (it->next) + it = it->next; + + result = strdup(it->module); + free_aliases(aliases); + return result; + } + + return NULL; +} + +void modalias_cleanup(void) { + ifree(aliasdefault); +} diff --git a/names.c b/names.c new file mode 100644 index 0000000..a39425d --- /dev/null +++ b/names.c @@ -0,0 +1,813 @@ +/*****************************************************************************/ +/* + * names.c -- USB name database manipulation routines + * + * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_LIBZ +#include +#define usb_file gzFile +#define usb_fopen(path, mode) gzopen(path, mode) +#define usb_fgets(s, size, stream) gzgets(stream, s, size) +#define usb_close(f) gzclose(f) +#else +#define usb_file FILE* +#define usb_fopen(path, mode) fopen(path, mode) +#define usb_fgets(s, size, stream) fgets(s, size, stream) +#define usb_close(f) fclose(f) +#endif + +#include "names.h" + + +/* ---------------------------------------------------------------------- */ + +struct vendor { + struct vendor *next; + uint16_t vendorid; + char name[1]; +}; + +struct product { + struct product *next; + uint16_t vendorid, productid; + char name[1]; +}; + +struct class { + struct class *next; + uint8_t classid; + char name[1]; +}; + +struct subclass { + struct subclass *next; + uint8_t classid, subclassid; + char name[1]; +}; + +struct protocol { + struct protocol *next; + uint8_t classid, subclassid, protocolid; + char name[1]; +}; + +struct audioterminal { + struct audioterminal *next; + uint16_t termt; + char name[1]; +}; + +struct videoterminal { + struct videoterminal *next; + uint16_t termt; + char name[1]; +}; + +struct genericstrtable { + struct genericstrtable *next; + unsigned int num; + char name[1]; +}; + +/* ---------------------------------------------------------------------- */ + +#define HASH1 0x10 +#define HASH2 0x02 +#define HASHSZ 16 + +static unsigned int hashnum(unsigned int num) +{ + unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27; + + for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1) + if (num & mask1) + num ^= mask2; + return num & (HASHSZ-1); +} + +/* ---------------------------------------------------------------------- */ + +static struct vendor *vendors[HASHSZ] = { NULL, }; +static struct product *products[HASHSZ] = { NULL, }; +static struct class *classes[HASHSZ] = { NULL, }; +static struct subclass *subclasses[HASHSZ] = { NULL, }; +static struct protocol *protocols[HASHSZ] = { NULL, }; +static struct audioterminal *audioterminals[HASHSZ] = { NULL, }; +static struct videoterminal *videoterminals[HASHSZ] = { NULL, }; +static struct genericstrtable *hiddescriptors[HASHSZ] = { NULL, }; +static struct genericstrtable *reports[HASHSZ] = { NULL, }; +static struct genericstrtable *huts[HASHSZ] = { NULL, }; +static struct genericstrtable *biass[HASHSZ] = { NULL, }; +static struct genericstrtable *physdess[HASHSZ] = { NULL, }; +static struct genericstrtable *hutus[HASHSZ] = { NULL, }; +static struct genericstrtable *langids[HASHSZ] = { NULL, }; +static struct genericstrtable *countrycodes[HASHSZ] = { NULL, }; + +static int init_done = 0; + +/* ---------------------------------------------------------------------- */ + +static const char *names_genericstrtable(struct genericstrtable *t[HASHSZ], unsigned int index) +{ + struct genericstrtable *h; + + for (h = t[hashnum(index)]; h; h = h->next) + if (h->num == index) + return h->name; + return NULL; +} + +const char *names_hid(uint8_t hidd) +{ + return names_genericstrtable(hiddescriptors, hidd); +} + +const char *names_reporttag(uint8_t rt) +{ + return names_genericstrtable(reports, rt); +} + +const char *names_huts(unsigned int data) +{ + return names_genericstrtable(huts, data); +} + +const char *names_hutus(unsigned int data) +{ + return names_genericstrtable(hutus, data); +} + +const char *names_langid(uint16_t langid) +{ + return names_genericstrtable(langids, langid); +} + +const char *names_physdes(uint8_t ph) +{ + return names_genericstrtable(physdess, ph); +} + +const char *names_bias(uint8_t b) +{ + return names_genericstrtable(biass, b); +} + +const char *names_countrycode(unsigned int countrycode) +{ + return names_genericstrtable(countrycodes, countrycode); +} + +const char *names_vendor(uint16_t vendorid) +{ + struct vendor *v; + + v = vendors[hashnum(vendorid)]; + for (; v; v = v->next) + if (v->vendorid == vendorid) + return v->name; + return NULL; +} + +const char *names_product(uint16_t vendorid, uint16_t productid) +{ + struct product *p; + + p = products[hashnum((vendorid << 16) | productid)]; + for (; p; p = p->next) + if (p->vendorid == vendorid && p->productid == productid) + return p->name; + return NULL; +} + +const char *names_class(uint8_t classid) +{ + struct class *c; + + c = classes[hashnum(classid)]; + for (; c; c = c->next) + if (c->classid == classid) + return c->name; + return NULL; +} + +const char *names_subclass(uint8_t classid, uint8_t subclassid) +{ + struct subclass *s; + + s = subclasses[hashnum((classid << 8) | subclassid)]; + for (; s; s = s->next) + if (s->classid == classid && s->subclassid == subclassid) + return s->name; + return NULL; +} + +const char *names_protocol(uint8_t classid, uint8_t subclassid, uint8_t protocolid) +{ + struct protocol *p; + + p = protocols[hashnum((classid << 16) | (subclassid << 8) | protocolid)]; + for (; p; p = p->next) + if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid) + return p->name; + return NULL; +} + +const char *names_audioterminal(uint16_t termt) +{ + struct audioterminal *at; + + at = audioterminals[hashnum(termt)]; + for (; at; at = at->next) + if (at->termt == termt) + return at->name; + return NULL; +} + +const char *names_videoterminal(uint16_t termt) +{ + struct videoterminal *vt; + + vt = videoterminals[hashnum(termt)]; + for (; vt; vt = vt->next) + if (vt->termt == termt) + return vt->name; + return NULL; +} + +/* ---------------------------------------------------------------------- */ + +static int new_vendor(const char *name, uint16_t vendorid) +{ + struct vendor *v; + unsigned int h = hashnum(vendorid); + + v = vendors[h]; + for (; v; v = v->next) + if (v->vendorid == vendorid) + return -1; + v = malloc(sizeof(struct vendor) + strlen(name)); + if (!v) + return -1; + strcpy(v->name, name); + v->vendorid = vendorid; + v->next = vendors[h]; + vendors[h] = v; + return 0; +} + +static int new_product(const char *name, uint16_t vendorid, uint16_t productid) +{ + struct product *p; + unsigned int h = hashnum((vendorid << 16) | productid); + + p = products[h]; + for (; p; p = p->next) + if (p->vendorid == vendorid && p->productid == productid) + return -1; + p = malloc(sizeof(struct product) + strlen(name)); + if (!p) + return -1; + strcpy(p->name, name); + p->vendorid = vendorid; + p->productid = productid; + p->next = products[h]; + products[h] = p; + return 0; +} + +static int new_class(const char *name, uint8_t classid) +{ + struct class *c; + unsigned int h = hashnum(classid); + + c = classes[h]; + for (; c; c = c->next) + if (c->classid == classid) + return -1; + c = malloc(sizeof(struct class) + strlen(name)); + if (!c) + return -1; + strcpy(c->name, name); + c->classid = classid; + c->next = classes[h]; + classes[h] = c; + return 0; +} + +static int new_subclass(const char *name, uint8_t classid, uint8_t subclassid) +{ + struct subclass *s; + unsigned int h = hashnum((classid << 8) | subclassid); + + s = subclasses[h]; + for (; s; s = s->next) + if (s->classid == classid && s->subclassid == subclassid) + return -1; + s = malloc(sizeof(struct subclass) + strlen(name)); + if (!s) + return -1; + strcpy(s->name, name); + s->classid = classid; + s->subclassid = subclassid; + s->next = subclasses[h]; + subclasses[h] = s; + return 0; +} + +static int new_protocol(const char *name, uint8_t classid, uint8_t subclassid, uint8_t protocolid) +{ + struct protocol *p; + unsigned int h = hashnum((classid << 16) | (subclassid << 8) | protocolid); + + p = protocols[h]; + for (; p; p = p->next) + if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid) + return -1; + p = malloc(sizeof(struct protocol) + strlen(name)); + if (!p) + return -1; + strcpy(p->name, name); + p->classid = classid; + p->subclassid = subclassid; + p->protocolid = protocolid; + p->next = protocols[h]; + protocols[h] = p; + return 0; +} + +static int new_audioterminal(const char *name, uint16_t termt) +{ + struct audioterminal *at; + unsigned int h = hashnum(termt); + + at = audioterminals[h]; + for (; at; at = at->next) + if (at->termt == termt) + return -1; + at = malloc(sizeof(struct audioterminal) + strlen(name)); + if (!at) + return -1; + strcpy(at->name, name); + at->termt = termt; + at->next = audioterminals[h]; + audioterminals[h] = at; + return 0; +} + +static int new_videoterminal(const char *name, uint16_t termt) +{ + struct videoterminal *vt; + unsigned int h = hashnum(termt); + + vt = videoterminals[h]; + for (; vt; vt = vt->next) + if (vt->termt == termt) + return -1; + vt = malloc(sizeof(struct videoterminal) + strlen(name)); + if (!vt) + return -1; + strcpy(vt->name, name); + vt->termt = termt; + vt->next = videoterminals[h]; + videoterminals[h] = vt; + return 0; +} + +static int new_genericstrtable(struct genericstrtable *t[HASHSZ], const char *name, unsigned int index) +{ + struct genericstrtable *g; + unsigned int h = hashnum(index); + + for (g = t[h]; g; g = g->next) + if (g->num == index) + return -1; + g = malloc(sizeof(struct genericstrtable) + strlen(name)); + if (!g) + return -1; + strcpy(g->name, name); + g->num = index; + g->next = t[h]; + t[h] = g; + return 0; +} + +static int new_hid(const char *name, uint8_t hidd) +{ + return new_genericstrtable(hiddescriptors, name, hidd); +} + +static int new_reporttag(const char *name, uint8_t rt) +{ + return new_genericstrtable(reports, name, rt); +} + +static int new_huts(const char *name, unsigned int data) +{ + return new_genericstrtable(huts, name, data); +} + +static int new_hutus(const char *name, unsigned int data) +{ + return new_genericstrtable(hutus, name, data); +} + +static int new_langid(const char *name, uint16_t langid) +{ + return new_genericstrtable(langids, name, langid); +} + +static int new_physdes(const char *name, uint8_t ph) +{ + return new_genericstrtable(physdess, name, ph); +} +static int new_bias(const char *name, uint8_t b) +{ + return new_genericstrtable(biass, name, b); +} + +static int new_countrycode(const char *name, unsigned int countrycode) +{ + return new_genericstrtable(countrycodes, name, countrycode); +} + +/* ---------------------------------------------------------------------- */ + +#define DBG(x) + +static void parse(usb_file f) +{ + char buf[512], *cp; + unsigned int linectr = 0; + int lastvendor = -1, lastclass = -1, lastsubclass = -1, lasthut=-1, lastlang=-1; + unsigned int u; + + while (usb_fgets(buf, sizeof(buf), f)) { + linectr++; + /* remove line ends */ + if ((cp = strchr(buf, 13))) + *cp = 0; + if ((cp = strchr(buf, 10))) + *cp = 0; + if (buf[0] == '#' || !buf[0]) + continue; + cp = buf; + if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && buf[3] == 'S' && buf[4] == 'D' && + buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ buf[7] == ' ') { + cp = buf + 8; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid Physdes type at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid Physdes type at line %u\n", linectr); + continue; + } + if (new_physdes(cp, u)) + fprintf(stderr, "Duplicate Physdes type spec at line %u terminal type %04x %s\n", linectr, u, cp); + DBG(printf("line %5u physdes type %02x %s\n", linectr, u, cp)); + continue; + + } + if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { + cp = buf + 4; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid PHY type at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid PHY type at line %u\n", linectr); + continue; + } + if (new_physdes(cp, u)) + fprintf(stderr, "Duplicate PHY type spec at line %u terminal type %04x %s\n", linectr, u, cp); + DBG(printf("line %5u PHY type %02x %s\n", linectr, u, cp)); + continue; + + } + if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { + cp = buf + 5; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid BIAS type at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid BIAS type at line %u\n", linectr); + continue; + } + if (new_bias(cp, u)) + fprintf(stderr, "Duplicate BIAS type spec at line %u terminal type %04x %s\n", linectr, u, cp); + DBG(printf("line %5u BIAS type %02x %s\n", linectr, u, cp)); + continue; + + } + if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { + cp = buf+2; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr); + continue; + } + if (new_langid(cp, u)) + fprintf(stderr, "Duplicate LANGID spec at line %u language-id %04x %s\n", linectr, u, cp); + DBG(printf("line %5u LANGID %02x %s\n", linectr, u, cp)); + lasthut = lastclass = lastvendor = lastsubclass = -1; + lastlang = u; + continue; + } + if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') { + /* class spec */ + cp = buf+2; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid class spec at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid class spec at line %u\n", linectr); + continue; + } + if (new_class(cp, u)) + fprintf(stderr, "Duplicate class spec at line %u class %04x %s\n", linectr, u, cp); + DBG(printf("line %5u class %02x %s\n", linectr, u, cp)); + lasthut = lastlang = lastvendor = lastsubclass = -1; + lastclass = u; + continue; + } + if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) { + /* audio terminal type spec */ + cp = buf+3; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr); + continue; + } + if (new_audioterminal(cp, u)) + fprintf(stderr, "Duplicate audio terminal type spec at line %u terminal type %04x %s\n", linectr, u, cp); + DBG(printf("line %5u audio terminal type %02x %s\n", linectr, u, cp)); + continue; + } + if (buf[0] == 'V' && buf[1] == 'T' && isspace(buf[2])) { + /* video terminal type spec */ + cp = buf+3; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid video terminal type at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid video terminal type at line %u\n", linectr); + continue; + } + if (new_videoterminal(cp, u)) + fprintf(stderr, "Duplicate video terminal type spec at line %u terminal type %04x %s\n", linectr, u, cp); + DBG(printf("line %5u video terminal type %02x %s\n", linectr, u, cp)); + continue; + } + if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' && isspace(buf[3])) { + /* HID Descriptor bCountryCode */ + cp = buf+3; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid HID country code at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 10); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid HID country code at line %u\n", linectr); + continue; + } + if (new_countrycode(cp, u)) + fprintf(stderr, "Duplicate HID country code at line %u country %02u %s\n", linectr, u, cp); + DBG(printf("line %5u keyboard country code %02u %s\n", linectr, u, cp)); + continue; + } + if (isxdigit(*cp)) { + /* vendor */ + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid vendor spec at line %u\n", linectr); + continue; + } + if (new_vendor(cp, u)) + fprintf(stderr, "Duplicate vendor spec at line %u vendor %04x %s\n", linectr, u, cp); + DBG(printf("line %5u vendor %04x %s\n", linectr, u, cp)); + lastvendor = u; + lasthut = lastlang = lastclass = lastsubclass = -1; + continue; + } + if (buf[0] == '\t' && isxdigit(buf[1])) { + /* product or subclass spec */ + u = strtoul(buf+1, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid product/subclass spec at line %u\n", linectr); + continue; + } + if (lastvendor != -1) { + if (new_product(cp, lastvendor, u)) + fprintf(stderr, "Duplicate product spec at line %u product %04x:%04x %s\n", linectr, lastvendor, u, cp); + DBG(printf("line %5u product %04x:%04x %s\n", linectr, lastvendor, u, cp)); + continue; + } + if (lastclass != -1) { + if (new_subclass(cp, lastclass, u)) + fprintf(stderr, "Duplicate subclass spec at line %u class %02x:%02x %s\n", linectr, lastclass, u, cp); + DBG(printf("line %5u subclass %02x:%02x %s\n", linectr, lastclass, u, cp)); + lastsubclass = u; + continue; + } + if (lasthut != -1) { + if (new_hutus(cp, (lasthut << 16)+u)) + fprintf(stderr, "Duplicate HUT Usage Spec at line %u\n", linectr); + continue; + } + if (lastlang != -1) { + if (new_langid(cp, lastlang+(u<<10))) + fprintf(stderr, "Duplicate LANGID Usage Spec at line %u\n", linectr); + continue; + } + fprintf(stderr, "Product/Subclass spec without prior Vendor/Class spec at line %u\n", linectr); + continue; + } + if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) { + /* protocol spec */ + u = strtoul(buf+2, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid protocol spec at line %u\n", linectr); + continue; + } + if (lastclass != -1 && lastsubclass != -1) { + if (new_protocol(cp, lastclass, lastsubclass, u)) + fprintf(stderr, "Duplicate protocol spec at line %u class %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp); + DBG(printf("line %5u protocol %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp)); + continue; + } + fprintf(stderr, "Protocol spec without prior Class and Subclass spec at line %u\n", linectr); + continue; + } + if (buf[0] == 'H' && buf[1] == 'I' && buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { + cp = buf + 4; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid HID type at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid HID type at line %u\n", linectr); + continue; + } + if (new_hid(cp, u)) + fprintf(stderr, "Duplicate HID type spec at line %u terminal type %04x %s\n", linectr, u, cp); + DBG(printf("line %5u HID type %02x %s\n", linectr, u, cp)); + continue; + + } + if (buf[0] == 'H' && buf[1] == 'U' && buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { + cp = buf + 4; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid HUT type at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid HUT type at line %u\n", linectr); + continue; + } + if (new_huts(cp, u)) + fprintf(stderr, "Duplicate HUT type spec at line %u terminal type %04x %s\n", linectr, u, cp); + lastlang = lastclass = lastvendor = lastsubclass = -1; + lasthut = u; + DBG(printf("line %5u HUT type %02x %s\n", linectr, u, cp)); + continue; + + } + if (buf[0] == 'R' && buf[1] == ' ') { + cp = buf + 2; + while (isspace(*cp)) + cp++; + if (!isxdigit(*cp)) { + fprintf(stderr, "Invalid Report type at line %u\n", linectr); + continue; + } + u = strtoul(cp, &cp, 16); + while (isspace(*cp)) + cp++; + if (!*cp) { + fprintf(stderr, "Invalid Report type at line %u\n", linectr); + continue; + } + if (new_reporttag(cp, u)) + fprintf(stderr, "Duplicate Report type spec at line %u terminal type %04x %s\n", linectr, u, cp); + DBG(printf("line %5u Report type %02x %s\n", linectr, u, cp)); + continue; + + } + fprintf(stderr, "Unknown line at line %u\n", linectr); + } +} + +/* ---------------------------------------------------------------------- */ + +int names_init(char *n) +{ + usb_file f; + if(init_done) + return 0; + init_done = 1; + if (!(f = usb_fopen(n, "r"))) { + return errno; + } + parse(f); + usb_close(f); + return 0; +} diff --git a/names.h b/names.h new file mode 100644 index 0000000..71c27d4 --- /dev/null +++ b/names.h @@ -0,0 +1,52 @@ +/*****************************************************************************/ + +/* + * names.h -- USB name database manipulation routines + * + * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +/*****************************************************************************/ + +#ifndef _NAMES_H +#define _NAMES_H + +#include + +/* ---------------------------------------------------------------------- */ + +extern const char *names_vendor(uint16_t vendorid); +extern const char *names_product(uint16_t vendorid, uint16_t productid); +extern const char *names_class(uint8_t classid); +extern const char *names_subclass(uint8_t classid, uint8_t subclassid); +extern const char *names_protocol(uint8_t classid, uint8_t subclassid, uint8_t protocolid); +extern const char *names_audioterminal(uint16_t termt); +extern const char *names_videoterminal(uint16_t termt); +extern const char *names_hid(uint8_t hidd); +extern const char *names_reporttag(uint8_t rt); +extern const char *names_huts(unsigned int data); +extern const char *names_hutus(unsigned int data); +extern const char *names_langid(uint16_t langid); +extern const char *names_physdes(uint8_t ph); +extern const char *names_bias(uint8_t b); +extern const char *names_countrycode(unsigned int countrycode); +extern int names_init(char *n); + +/* ---------------------------------------------------------------------- */ +#endif /* _NAMES_H */ diff --git a/pci.c b/pci.c new file mode 100644 index 0000000..5bd344f --- /dev/null +++ b/pci.c @@ -0,0 +1,112 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +/* /proc files're 256 bytes but we only need first 64 bytes*/ +#define CONFIG_SPACE_SIZE 64 + +static char *proc_pci_path_default = "/proc/bus/pci/devices"; +char* proc_pci_path = NULL; + +static void __attribute__((noreturn)) error_and_die(char *msg, ...) +{ + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s: ", "lspcidrake"); + vfprintf(stderr, msg, args); + fputc('\n', stderr); + exit(1); +} + +extern struct pciusb_entries pci_probe(void) { + u8 buf[CONFIG_SPACE_SIZE]; + struct pciusb_entries r; + + static struct pci_access *pacc; + struct pci_dev *dev; + char classbuf[128], vendorbuf[128], devbuf[128]; + + pacc = pci_alloc(); + + if (proc_pci_path) { + pci_set_param(pacc, "proc.path", proc_pci_path); + } + + + pci_init(pacc); + pacc->error = error_and_die; + pci_scan_bus(pacc); + + r.nb = 0; + r.entries = malloc(sizeof(struct pciusb_entry) * MAX_DEVICES); + + for (dev = pacc->devices; dev && r.nb < MAX_DEVICES; dev = dev->next, r.nb++) { + + struct pciusb_entry *e = &r.entries[r.nb]; + memset(buf, 0, CONFIG_SPACE_SIZE); // make sure not to retrieve values from previous devices + pci_setup_cache(dev, (u8*)buf, CONFIG_SPACE_SIZE); + pci_read_block(dev, 0, buf, CONFIG_SPACE_SIZE); + pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_CAPS); + + pciusb_initialize(e); + + asprintf(&e->text, "%s|%s", + pci_lookup_name(pacc, vendorbuf, sizeof(vendorbuf), PCI_LOOKUP_VENDOR, dev->vendor_id, dev->device_id), + pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id) + ); + pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, dev->device_class), + e->class=strdup(classbuf); + + e->vendor = dev->vendor_id; + e->device = dev->device_id; + e->pci_domain = dev->domain; + e->pci_bus = dev->bus; + e->pci_device = dev->dev; + e->pci_function = dev->func; + + e->class_id = dev->device_class; + e->subvendor = pci_read_word(dev, PCI_SUBSYSTEM_VENDOR_ID); + e->subdevice = pci_read_word(dev, PCI_SUBSYSTEM_ID); + e->pci_revision = pci_read_byte(dev, PCI_REVISION_ID); + + if ((e->subvendor == 0 && e->subdevice == 0) || + (e->subvendor == e->vendor && e->subdevice == e->device)) { + e->subvendor = 0xffff; + e->subdevice = 0xffff; + } + + if (pci_find_cap(dev,PCI_CAP_ID_EXP, PCI_CAP_NORMAL)) + e->is_pciexpress = 1; + + /* special case for realtek 8139 that has two drivers */ + if (e->vendor == 0x10ec && e->device == 0x8139) { + if (e->pci_revision < 0x20) + e->module = strdup("8139too"); + else + e->module = strdup("8139cp"); + } + + } + + /* shrink to real size */ + r.entries = realloc(r.entries, sizeof(struct pciusb_entry) * r.nb); + + pci_cleanup(pacc); + + if (pciusb_find_modules(&r, "pcitable", DO_NOT_LOAD, 1)) + return r; + + /* should not happen */ + exit(1); +} diff --git a/pciusb.c b/pciusb.c new file mode 100644 index 0000000..bcd901f --- /dev/null +++ b/pciusb.c @@ -0,0 +1,192 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +static void set_modules_from_modalias_file(struct pciusb_entry *e, char *modalias_path) { + FILE *file; + file = fopen(modalias_path, "r"); + if (file) { + char *modalias = NULL; + size_t n, size; + if (-1 == getline(&modalias, &n, file)) { + fprintf(stderr, "Unable to read modalias from %s\n", modalias_path); + fclose(file); + return; + } + fclose(file); + size = strlen(modalias); + if (size) + modalias[size-1] = 0; + + ifree(e->module); + e->module = modalias_resolve_module(modalias); + free(modalias); + } else { + fprintf(stderr, "Unable to read modalias from %s\n", modalias_path); + return; + } +} + +static void find_pci_modules_through_aliases(struct pciusb_entry *e) { + char *modalias_path; + asprintf(&modalias_path, + "/sys/bus/pci/devices/%04x:%02x:%02x.%x/modalias", + e->pci_domain, e->pci_bus, e->pci_device, e->pci_function); + set_modules_from_modalias_file(e, modalias_path); + free(modalias_path); +} + +static void find_usb_modules_through_aliases(struct pciusb_entry *e) { + char *usb_prefix, *sysfs_path; + DIR *dir; + struct dirent *dent; + + asprintf(&usb_prefix, "%d-", e->pci_bus); + /* USB port is indexed from 0 in procfs, from 1 in sysfs */ + asprintf(&sysfs_path, "/sys/bus/usb/devices/%d-%d", e->pci_bus, e->usb_port + 1); + + dir = opendir(sysfs_path); + if (!dir) { + goto end; + } + while ((dent = readdir(dir)) != NULL) { + if ((dent->d_type == DT_DIR) && + !strncmp(usb_prefix, dent->d_name, strlen(usb_prefix))) { + char *modalias_path; + asprintf(&modalias_path, "%s/%s/modalias", sysfs_path, dent->d_name); + set_modules_from_modalias_file(e, modalias_path); + free(modalias_path); + /* maybe we would need a "other_modules" field in pciusb_entry + to list modules from all USB interfaces */ + if (e->module) + break; + } + } + closedir(dir); +end: + free(sysfs_path); + free(usb_prefix); +} + +static void find_modules_through_aliases_one(const char *bus, struct pciusb_entry *e) { + if (!strcmp("pci", bus)) { + find_pci_modules_through_aliases(e); + } else if (!strcmp("usb", bus)) { + find_usb_modules_through_aliases(e); + } +} + +static void find_modules_through_aliases(const char *bus, struct pciusb_entries *entries) { + unsigned int i; + for (i = 0; i < entries->nb; i++) { + struct pciusb_entry *e = &entries->entries[i]; + + // No special case found in pcitable ? Then lookup modalias for PCI devices + if (e->module && strcmp(e->module, "unknown")) + continue; + find_modules_through_aliases_one(bus, e); + } + + modalias_cleanup(); +} + +extern int pciusb_find_modules(struct pciusb_entries *entries, const char *fpciusbtable, const descr_lookup descr_lookup, int is_pci) { + fh f; + char buf[2048]; + int line; + + f = fh_open(fpciusbtable); + + for (line = 1; fh_gets(buf, sizeof(buf) - 1, &f); line++) { + unsigned short vendor, device, subvendor, subdevice; + char *p = NULL, *q = NULL; + int offset; unsigned int i; + int nb; + if (buf[0]=='#') + continue; // skip comments + + nb = sscanf(buf, "0x%hx\t0x%hx\t0x%hx\t0x%hx\t%n", &vendor, &device, &subvendor, &subdevice, &offset); + if (nb != 4) { + nb = sscanf(buf, "0x%hx\t0x%hx\t%n", &vendor, &device, &offset); + if (nb != 2) { + fprintf(stderr, "%s %d: bad line\n", fpciusbtable, line); + continue; // skip bad line + } + } + for (i = 0; i < entries->nb; i++) { + struct pciusb_entry *e = &entries->entries[i]; + if (e->already_found) + continue; // skip since already found with sub ids + if (vendor != e->vendor || device != e->device) + continue; // main ids differ + + if (nb == 4 && !(subvendor == e->subvendor && subdevice == e->subdevice)) + continue; // subids differ + + if (!p) { // only calc text & module if not already done + p = buf + offset + 1; + q = strchr(p, '\t'); + if (!q) // no description field? + q = strchr(p, '\0') - 1; + } + if (strncmp(p, "unknown", q-p-1)) { + ifree(e->module); + e->module = strndup(p,q-p-1); + } + /* special case for buggy 0x0 usb entry */ + if (descr_lookup == LOAD && strlen(q) > 1 && 2 < strlen(q+2) && vendor != 0 && device != 0 && e->class_id != 0x90000d) { /* Hub class */ + ifree(e->text); /* usb.c set it so that we display something when usbtable doesn't refer that hw*/ + e->text = strndup(q+2, strlen(q)-4); + } + /* if subids read on pcitable line, we know that subids matches : + (see "subids differ" test above) */ + if (nb == 4) + e->already_found = 1; + } + } + fh_close(&f); + + /* If no special case in pcitable, then lookup modalias for devices */ + const char *bus = is_pci ? "pci" : "usb"; + find_modules_through_aliases(bus, entries); + + return 1; +} + +extern void pciusb_initialize(struct pciusb_entry *e) { + e->vendor = 0xffff; + e->device = 0xffff; + e->subvendor = 0xffff; + e->subdevice = 0xffff; + e->class_id = 0; + e->pci_bus = 0xff; + e->pci_device = 0xff; + e->pci_function = 0xff; + e->pci_revision = 0; + e->usb_port = 0xffff; + e->module = NULL; + e->text = NULL; + e->class = NULL; + e->already_found = 0; + e->is_pciexpress = 0; +} + +extern void pciusb_free(struct pciusb_entries *entries) { + unsigned int i; + for (i = 0; i < entries->nb; i++) { + struct pciusb_entry *e = &entries->entries[i]; + ifree(e->module); + ifree(e->text); + } + if (entries->nb) ifree(entries->entries); +} diff --git a/sysfs.h b/sysfs.h new file mode 100644 index 0000000..76754a4 --- /dev/null +++ b/sysfs.h @@ -0,0 +1,64 @@ +/* + * sysfs.h + * + * Internal Header Definitions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef _SYSFS_H_ +#define _SYSFS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1) +#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1) + +#define safestrcpymax(to, from, max) \ +do { \ + to[max-1] = '\0'; \ + strncpy(to, from, max-1); \ +} while (0) + +#define safestrcatmax(to, from, max) \ +do { \ + to[max-1] = '\0'; \ + strncat(to, from, max - strlen(to)-1); \ +} while (0) + +extern struct sysfs_attribute *get_attribute(void *dev, const char *name); +extern struct dlist *read_dir_subdirs(const char *path); +extern struct dlist *read_dir_links(const char *path); +extern struct dlist *get_dev_attributes_list(void *dev); +extern struct dlist *get_attributes_list(struct dlist *alist, const char *path); + +/* Debugging */ +#ifdef DEBUG +#define dprintf(format, arg...) fprintf(stderr, format, ## arg) +#else +#define dprintf(format, arg...) do { } while (0) +#endif + +#endif /* _SYSFS_H_ */ diff --git a/sysfs_attr.c b/sysfs_attr.c new file mode 100644 index 0000000..6d67711 --- /dev/null +++ b/sysfs_attr.c @@ -0,0 +1,241 @@ +/* + * sysfs_dir.c + * + * Directory utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "libsysfs.h" +#include "sysfs.h" + +/** + * sysfs_close_attribute: closes and cleans up attribute + * @sysattr: attribute to close. + */ +void sysfs_close_attribute(struct sysfs_attribute *sysattr) +{ + if (sysattr) { + if (sysattr->value) + free(sysattr->value); + free(sysattr); + } +} + +/** + * alloc_attribute: allocates and initializes attribute structure + * returns struct sysfs_attribute with success and NULL with error. + */ +static struct sysfs_attribute *alloc_attribute(void) +{ + return (struct sysfs_attribute *) + calloc(1, sizeof(struct sysfs_attribute)); +} + +/** + * sysfs_open_attribute: creates sysfs_attribute structure + * @path: path to attribute. + * returns sysfs_attribute struct with success and NULL with error. + */ +struct sysfs_attribute *sysfs_open_attribute(const char *path) +{ + struct sysfs_attribute *sysattr = NULL; + struct stat fileinfo; + + if (!path) { + errno = EINVAL; + return NULL; + } + sysattr = alloc_attribute(); + if (!sysattr) { + dprintf("Error allocating attribute at %s\n", path); + return NULL; + } + if (sysfs_get_name_from_path(path, sysattr->name, + SYSFS_NAME_LEN) != 0) { + dprintf("Error retrieving attrib name from path: %s\n", path); + sysfs_close_attribute(sysattr); + return NULL; + } + safestrcpy(sysattr->path, path); + if ((stat(sysattr->path, &fileinfo)) != 0) { + dprintf("Stat failed: No such attribute?\n"); + sysattr->method = 0; + free(sysattr); + sysattr = NULL; + } else { + if (fileinfo.st_mode & S_IRUSR) + sysattr->method |= SYSFS_METHOD_SHOW; + if (fileinfo.st_mode & S_IWUSR) + sysattr->method |= SYSFS_METHOD_STORE; + } + + return sysattr; +} + +/** + * sysfs_read_attribute: reads value from attribute + * @sysattr: attribute to read + * returns 0 with success and -1 with error. + */ +int sysfs_read_attribute(struct sysfs_attribute *sysattr) +{ + char *fbuf = NULL; + char *vbuf = NULL; + ssize_t length = 0; + long pgsize = 0; + int fd; + + if (!sysattr) { + errno = EINVAL; + return -1; + } + if (!(sysattr->method & SYSFS_METHOD_SHOW)) { + dprintf("Show method not supported for attribute %s\n", + sysattr->path); + errno = EACCES; + return -1; + } + pgsize = getpagesize(); + fbuf = (char *)calloc(1, pgsize+1); + if (!fbuf) { + dprintf("calloc failed\n"); + return -1; + } + if ((fd = open(sysattr->path, O_RDONLY)) < 0) { + dprintf("Error reading attribute %s\n", sysattr->path); + free(fbuf); + return -1; + } + length = read(fd, fbuf, pgsize); + if (length < 0) { + dprintf("Error reading from attribute %s\n", sysattr->path); + close(fd); + free(fbuf); + return -1; + } + if (sysattr->len > 0) { + if ((sysattr->len == length) && + (!(strncmp(sysattr->value, fbuf, length)))) { + close(fd); + free(fbuf); + return 0; + } + free(sysattr->value); + } + sysattr->len = length; + close(fd); + vbuf = (char *)realloc(fbuf, length+1); + if (!vbuf) { + dprintf("realloc failed\n"); + free(fbuf); + return -1; + } + sysattr->value = vbuf; + + return 0; +} + +/** + * sysfs_write_attribute: write value to the attribute + * @sysattr: attribute to write + * @new_value: value to write + * @len: length of "new_value" + * returns 0 with success and -1 with error. + */ +int sysfs_write_attribute(struct sysfs_attribute *sysattr, + const char *new_value, size_t len) +{ + int fd; + int length; + + if (!sysattr || !new_value || len == 0) { + errno = EINVAL; + return -1; + } + + if (!(sysattr->method & SYSFS_METHOD_STORE)) { + dprintf ("Store method not supported for attribute %s\n", + sysattr->path); + errno = EACCES; + return -1; + } + if (sysattr->method & SYSFS_METHOD_SHOW) { + /* + * read attribute again to see if we can get an updated value + */ + if ((sysfs_read_attribute(sysattr))) { + dprintf("Error reading attribute\n"); + return -1; + } + if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0 && + (len == sysattr->len)) { + dprintf("Attr %s already has the requested value %s\n", + sysattr->name, new_value); + return 0; + } + } + /* + * open O_WRONLY since some attributes have no "read" but only + * "write" permission + */ + if ((fd = open(sysattr->path, O_WRONLY)) < 0) { + dprintf("Error reading attribute %s\n", sysattr->path); + return -1; + } + + length = write(fd, new_value, len); + if (length < 0) { + dprintf("Error writing to the attribute %s - invalid value?\n", + sysattr->name); + close(fd); + return -1; + } else if ((unsigned int)length != len) { + dprintf("Could not write %zd bytes to attribute %s\n", + len, sysattr->name); + /* + * since we could not write user supplied number of bytes, + * restore the old value if one available + */ + if (sysattr->method & SYSFS_METHOD_SHOW) { + length = write(fd, sysattr->value, sysattr->len); + close(fd); + return -1; + } + } + + /* + * Validate length that has been copied. Alloc appropriate area + * in sysfs_attribute. Verify first if the attribute supports reading + * (show method). If it does not, do not bother + */ + if (sysattr->method & SYSFS_METHOD_SHOW) { + if (length != sysattr->len) { + sysattr->value = (char *)realloc + (sysattr->value, length); + sysattr->len = length; + safestrcpymax(sysattr->value, new_value, length); + } else { + /*"length" of the new value is same as old one */ + safestrcpymax(sysattr->value, new_value, length); + } + } + + close(fd); + return 0; +} + diff --git a/sysfs_utils.c b/sysfs_utils.c new file mode 100644 index 0000000..a0354a8 --- /dev/null +++ b/sysfs_utils.c @@ -0,0 +1,59 @@ +/* + * sysfs_utils.c + * + * System utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "libsysfs.h" +#include "sysfs.h" + +/** + * sysfs_get_name_from_path: returns last name from a "/" delimited path + * @path: path to get name from + * @name: where to put name + * @len: size of name + */ +int sysfs_get_name_from_path(const char *path, char *name, size_t len) +{ + char tmp[SYSFS_PATH_MAX]; + char *n = NULL; + + if (!path || !name || len == 0) { + errno = EINVAL; + return -1; + } + memset(tmp, 0, SYSFS_PATH_MAX); + safestrcpy(tmp, path); + n = strrchr(tmp, '/'); + if (n == NULL) { + errno = EINVAL; + return -1; + } + if (*(n+1) == '\0') { + *n = '\0'; + n = strrchr(tmp, '/'); + if (n == NULL) { + errno = EINVAL; + return -1; + } + } + n++; + safestrcpymax(name, n, len); + return 0; +} diff --git a/usb.c b/usb.c new file mode 100644 index 0000000..2d5b77f --- /dev/null +++ b/usb.c @@ -0,0 +1,145 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include "libldetect.h" +#include "common.h" +#include "names.h" + +static char *proc_usb_path_default = "/proc/bus/usb/devices"; +char *proc_usb_path = NULL; + +static void build_text(struct pciusb_entry *e, char *vendor_text, char *product_text) { + if(e) { + if(!vendor_text) { + char const* vendorname; + vendorname = names_vendor(e->vendor); + if(vendorname) { + vendor_text = malloc(strlen(vendorname)+2); + sprintf(vendor_text, "%s|", vendorname); + } else + vendor_text = strdup("Unknown|"); + } + if(!product_text) { + char const* productname; + productname = names_product(e->vendor, e->device); + if(productname) { + product_text = strdup(productname); + } else + product_text = strdup("Unknown"); + } + vendor_text = realloc(vendor_text, strlen(vendor_text)+strlen(product_text)+1); + e->text = vendor_text; + strcat(e->text, product_text); + free(product_text); + } +} + + +extern struct pciusb_entries usb_probe(void) { + FILE *f; + char buf[BUF_SIZE]; + int line; + struct pciusb_entries r; + struct pciusb_entry *e = NULL; + char *vendor_text = NULL, *product_text = NULL; + r.nb = 0; + + names_init("/usr/share/usb.ids"); + if (!(f = fopen(proc_usb_path ? proc_usb_path : proc_usb_path_default, "r"))) { + if (proc_usb_path) { + char *err_msg; + asprintf(&err_msg, "unable to open \"%s\"\n" + "You may have passed a wrong argument to the \"-u\" option.\n" + "fopen() sets errno to", proc_usb_path); + perror(err_msg); + free(err_msg); + } + r.entries = NULL; + return r; + } + + r.entries = malloc(sizeof(struct pciusb_entry) * MAX_DEVICES); + /* for further information on the format parsed by this state machine, + * read /usr/share/doc/kernel-doc-X.Y.Z/usb/proc_usb_info.txt */ + for(line = 1; fgets(buf, sizeof(buf) - 1, f) && r.nb < MAX_DEVICES; line++) { + + switch (buf[0]) { + case 'T': { + unsigned short pci_bus, pci_device, usb_port; + build_text(e, vendor_text, product_text); + vendor_text = NULL; + product_text = NULL; + e = &r.entries[r.nb++]; + pciusb_initialize(e); + + if (sscanf(buf, "T: Bus=%02hd Lev=%*02d Prnt=%*04d Port=%02hd Cnt=%*02d Dev#=%3hd Spd=%*3s MxCh=%*2d", &pci_bus, &usb_port, &pci_device) == 3) { + e->pci_bus = pci_bus; + e->pci_device = pci_device; + e->usb_port = usb_port; + } else fprintf(stderr, "%s %d: unknown ``T'' line\n", proc_usb_path, line); + break; + } + case 'P': { + unsigned short vendor, device; + if (sscanf(buf, "P: Vendor=%hx ProdID=%hx", &vendor, &device) == 2) { + e->vendor = vendor; + e->device = device; + } else fprintf(stderr, "%s %d: unknown ``P'' line\n", proc_usb_path, line); + break; + } + case 'I': if (e->class_id == 0 || e->module == NULL) { + char driver[50]; + int class_id, sub, prot = 0; + if (sscanf(buf, "I:* If#=%*2d Alt=%*2d #EPs=%*2d Cls=%02x(%*5c) Sub=%02x Prot=%02x Driver=%s", &class_id, &sub, &prot, driver) >= 3) { + unsigned long cid = (class_id * 0x100 + sub) * 0x100 + prot; + if (e->class_id == 0) + e->class_id = cid; + if (strncmp(driver, "(none)", 6)) { + char *p; + /* Get current class if we are on the first one having used by a driver */ + e->class_id = cid; + e->module = strdup(driver); + /* replace '-' characters with '_' to be compliant with modnames from modaliases */ + p = e->module; + while (p && *p) { + if (*p == '-') *p = '_'; + p++; + } + } + /* see linux/sound/usb/usbaudio.c::usb_audio_ids */ + if (e->class_id == (0x1*0x100+ 0x01)) /* USB_AUDIO_CLASS*0x100 + USB_SUBCLASS_AUDIO_CONTROL*/ + e->module = strdup("snd_usb_audio"); + + } else if (sscanf(buf, "I: If#=%*2d Alt=%*2d #EPs=%*2d Cls=%02x(%*5c) Sub=%02x Prot=%02x Driver=%s", &class_id, &sub, &prot, driver) >= 3) { + /* Ignore interfaces not active */ + } else fprintf(stderr, "%s %d: unknown ``I'' line\n", proc_usb_path, line); + break; + } + case 'S': { + int offset; + char dummy; + size_t length = strlen(buf) -1; + if (sscanf(buf, "S: Manufacturer=%n%c", &offset, &dummy) == 1) { + buf[length] = '|'; /* replacing '\n' by '|' */ + vendor_text = strdup(buf + offset); + } else if (sscanf(buf, "S: Product=%n%c", &offset, &dummy) == 1) { + buf[length] = 0; /* removing '\n' */ + product_text = strdup(buf + offset); + } + } + } + } + + build_text(e, vendor_text, product_text); + + fclose(f); + + /* shrink to real size */ + r.entries = realloc(r.entries, sizeof(struct pciusb_entry) * r.nb); + + pciusb_find_modules(&r, "usbtable", DO_NOT_LOAD, 0); + return r; +} + -- cgit v1.2.1