diff options
author | Dexter Morgan <dmorgan@mageia.org> | 2011-06-02 20:49:50 +0000 |
---|---|---|
committer | Dexter Morgan <dmorgan@mageia.org> | 2011-06-02 20:49:50 +0000 |
commit | db5a94788a783a716de6c79e23f2e45093aca398 (patch) | |
tree | f0448c53425509d4272a355f120cb7249d4d58e8 | |
download | ldetect-distro/mga1.tar ldetect-distro/mga1.tar.gz ldetect-distro/mga1.tar.bz2 ldetect-distro/mga1.tar.xz ldetect-distro/mga1.zip |
Branch for updatesdistro/mga1
-rw-r--r-- | AUTHORS | 4 | ||||
-rw-r--r-- | ChangeLog | 1290 | ||||
-rwxr-xr-x | MDV/Lspciusb.pm | 63 | ||||
-rw-r--r-- | Makefile | 89 | ||||
-rw-r--r-- | NEWS | 65 | ||||
-rw-r--r-- | common.c | 110 | ||||
-rw-r--r-- | common.h | 47 | ||||
-rw-r--r-- | dmi.c | 285 | ||||
-rw-r--r-- | generate_pciclass.pl | 28 | ||||
-rwxr-xr-x | generate_usbclass.pl | 81 | ||||
-rw-r--r-- | hid.c | 154 | ||||
-rw-r--r-- | libldetect.h | 95 | ||||
-rw-r--r-- | libsysfs.h | 90 | ||||
-rw-r--r-- | lspcidrake.c | 120 | ||||
-rwxr-xr-x | lspcidrake.pl | 35 | ||||
-rw-r--r-- | modalias.c | 148 | ||||
-rw-r--r-- | names.c | 813 | ||||
-rw-r--r-- | names.h | 52 | ||||
-rw-r--r-- | pci.c | 112 | ||||
-rw-r--r-- | pciusb.c | 192 | ||||
-rw-r--r-- | sysfs.h | 64 | ||||
-rw-r--r-- | sysfs_attr.c | 241 | ||||
-rw-r--r-- | sysfs_utils.c | 59 | ||||
-rw-r--r-- | usb.c | 145 |
24 files changed, 4382 insertions, 0 deletions
@@ -0,0 +1,4 @@ +Chmouel (cannot open fix) +Guillaume Cottenceau (bug fixes, -v -f options) +Pixel (core developer) +Thierry Vignaud <tvignaud@mandriva.com> (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 <pixel at mandriva.com> + + * 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 <oblin at mandriva.com> + + * Makefile: 0.7.23 + +2008-02-29 15:00 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: fix bus type (and segfault on x86_64) + +2008-02-28 18:29 Olivier Blin <oblin at mandriva.com> + + * Makefile: 0.7.22 + +2008-02-28 16:53 Olivier Blin <oblin at mandriva.com> + + * 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 <oblin at mandriva.com> + + * Makefile: 0.7.21 + +2008-02-27 18:51 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: check opendir return code + +2008-02-27 18:34 Olivier Blin <oblin at mandriva.com> + + * 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 <oblin at mandriva.com> + + * pciusb.c: cosmetics + +2008-02-27 17:57 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: extract pci-specific function + +2008-02-27 17:55 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: extract set_modules_from_modalias_file + (bus-independant) + +2008-02-27 17:43 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: move libmodprobe variables declaration + +2008-02-27 17:40 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: make some functions static + +2008-02-27 17:39 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: free modalias + +2008-02-27 17:39 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: free modalias path earlier + +2008-02-27 17:38 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: set module in find_modules_through_aliases_one + +2008-02-27 17:31 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: fix indentation + +2008-02-27 17:31 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: find default alias file once only + +2008-02-27 17:24 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: extract set_modules_from_modalias() + +2008-02-27 17:20 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: remove unused symfilename + +2008-02-27 17:18 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: pass bus to find_modalias + +2008-02-27 16:56 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: extract find_modalias function + +2008-02-27 16:52 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: fix indentation + +2008-02-27 16:51 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: do not ignore subsequent modaliases if resolving one + fails + +2008-02-27 16:25 Olivier Blin <oblin at mandriva.com> + + * 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 <oblin at mandriva.com> + + * 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 <oblin at mandriva.com> + + * common.c: remove doble zlib.h include + +2008-02-27 16:01 Olivier Blin <oblin at mandriva.com> + + * Makefile: rebuild common.o if common.h has been modified + +2007-09-28 20:00 Olivier Blin <oblin at mandriva.com> + + * Makefile: 0.7.20 + +2007-09-28 20:00 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: fix modalias fd leak (thanks to Anssi for the report) + +2007-08-27 14:24 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog, Makefile: bump minor (14) + +2007-08-27 13:53 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: ld doesn't like -g, so use gcc back again + +2007-08-27 13:28 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: bump minor (13) + +2007-08-27 13:28 Thierry Vignaud <tvignaud at mandriva.com> + + * common.h: fix build on x86_64 + +2007-08-27 13:16 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: (find_modules_through_aliases) fix test, thus fixing + overwriting Card: in chroot + +2007-08-27 12:43 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: kill doble entrie + +2007-08-27 09:47 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * ChangeLog: update + +2007-08-22 17:27 Olivier Blin <oblin at mandriva.com> + + * Makefile: 0.7.12 + +2007-08-22 10:35 Olivier Blin <oblin at mandriva.com> + + * 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 <oblin at mandriva.com> + + * pciusb.c: remove spurious argument + +2007-08-20 11:46 Olivier Blin <oblin at mandriva.com> + + * Makefile: bump minor to 11 + +2007-08-20 11:46 Olivier Blin <oblin at mandriva.com> + + * pciusb.c: revert '_' characters substitution + +2007-08-16 15:47 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: bump minor + +2007-08-16 15:40 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: (find_modules_through_aliases) plug some memory leak + +2007-08-16 15:34 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * Makefile: bump minor (9) + +2007-08-16 14:07 Thierry Vignaud <tvignaud at mandriva.com> + + * dmi.c: (entries_matching_criteria) fix zlib conversion (#32590) + +2007-08-15 00:23 Olivier Blin <oblin at mandriva.com> + + * Makefile: 0.7.8 + +2007-08-15 00:22 Olivier Blin <oblin at mandriva.com> + + * 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 <oblin at mandriva.com> + + * Makefile: 0.7.7 + +2007-08-14 13:35 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <oblin at mandriva.com> + + * pciusb.c: replace '_' characters with '-' to be compliant with + pcitable and list_modules.pm + +2007-08-14 12:25 Olivier Blin <oblin at mandriva.com> + + * Makefile: build static library + +2007-08-14 12:24 Olivier Blin <oblin at mandriva.com> + + * Makefile: move objects list in lib_objs variable + +2007-08-14 11:55 Olivier Blin <oblin at mandriva.com> + + * pci.c: remove old 8139too/gdth hardcoded rules (already in + modules.alias) + +2007-08-07 13:29 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: bump minor (6) + +2007-08-07 13:28 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: (find_modules_through_aliases) exit() is not nice error + managment in a library + +2007-08-07 10:46 Pixel <pixel at mandriva.com> + + * pciusb.c: - don't free before printing + - print fatal error on stderr + +2007-08-07 13:28 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: (find_modules_through_aliases) exit() is not nice error + managment in a library + +2007-08-07 10:46 Pixel <pixel at mandriva.com> + + * pciusb.c: - don't free before printing + - print fatal error on stderr + +2007-08-06 15:34 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: bump minor (5) + +2007-08-06 15:33 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: (pciusb_find_modules) handle pcitable without + description field + +2007-08-06 12:45 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: bump minor (4) + +2007-08-06 11:22 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: update + +2007-08-06 11:21 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: update + +2007-08-04 09:11 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: (pci_probe) simplify + +2007-08-04 09:11 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * Makefile: bump minor (3) + +2007-08-04 08:10 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * Makefile: (changelog) typo fix + +2007-07-03 17:48 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: (changelog) --strip-prefix is now uneeded with + svn2cl-0.9 + +2007-05-07 07:59 Pixel <pixel at mandriva.com> + + * : new release, 0.7.1 (build with zlib which is needed by libpci) + +2007-02-26 16:56 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * pci.c: (pci_probe) typo fix :-( + +2007-02-26 13:55 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: bump major after ABI changes + +2007-02-26 13:55 Thierry Vignaud <tvignaud at mandriva.com> + + * libldetect.h, pci.c: export PCI domain + +2007-02-26 13:55 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * libldetect.h, pciusb.c: (struct pciusb_entry) add a class field + +2007-02-26 13:53 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * pci.c: (pci_probe) remove an extra space wronly added in r125837 + +2007-02-26 13:51 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: (pci_probe) replace a couple magic valyes by constants + from pciutils + +2007-02-26 13:51 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c, usb.c: stop performing descriptions lookup from pcitable + for PCI + +2007-02-26 13:49 Thierry Vignaud <tvignaud at mandriva.com> + + * common.h, pciusb.c: (pciusb_find_modules) add "descr_lookup" + parameter to enable/disable description lookup + +2007-02-26 13:48 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: (pci_probe) use pciutils in order to get device + description from /usr/share/pci.ids + +2007-02-26 13:48 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile, pci.c: switch to pciutils as PCI listing backend + +2007-02-22 20:58 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: get rid of rpm packaging rules + +2007-02-22 20:54 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: use svn export instead of tar for preparing the tarball + +2007-02-12 17:31 Thierry Vignaud <tvignaud at mandriva.com> + + * MDV/Lspciusb.pm: (list) enable to scan only pci or usb bus + +2007-02-12 14:41 Pixel <pixel at mandriva.com> + + * MDV/.perl_checker: unneeded + +2007-02-12 14:23 Thierry Vignaud <tvignaud at mandriva.com> + + * MDV/Lspciusb.pm, lspcidrake.pl: perl_checker cleanups + +2007-02-12 14:22 Thierry Vignaud <tvignaud at mandriva.com> + + * .perl_checker, MDV/.perl_checker: blacklist enough modules in + order to let perl_checker run + +2007-02-12 14:20 Thierry Vignaud <tvignaud at mandriva.com> + + * MDV, MDV/Lspciusb.pm, lspcidrake.pl: move detection code from + lspcidrake.pl into MDV::Lspciusb + +2007-02-12 14:13 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.pl: add copyright header + +2007-02-12 14:11 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.pl: (read_pciids) rename "class" as "vendor" since it + really is + +2007-01-10 15:40 Thierry Vignaud <tvignaud at mandriva.com> + + * .cvsignore, .svnignore: rename b/c of CVS -> SVN switch + +2007-01-10 15:39 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: bump release + +2007-01-10 15:14 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * Makefile: bump minor + +2006-11-06 14:36 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.6.6-1mdv2007.1 + +2006-11-06 14:36 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: (log) switch from CVS to SVN + +2006-11-06 14:27 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <oblin at mandriva.com> + + * ldetect.spec: add missing changelog entry + +2006-07-12 18:26 Olivier Blin <oblin at mandriva.com> + + * ldetect.spec: ldetect-0.6.5-1mdv2007.0 + +2006-07-12 18:21 Olivier Blin <oblin at mandriva.com> + + * Makefile: update minor + +2006-07-12 18:21 Olivier Blin <oblin at mandriva.com> + + * Makefile: use dis target + +2006-07-12 17:40 Olivier Blin <oblin at mandriva.com> + + * Makefile: use spec file from current directory + +2006-07-12 17:39 Olivier Blin <oblin at mandriva.com> + + * Makefile: drop duplicated warning (already in the spec) + +2006-07-12 16:13 Olivier Blin <oblin at mandriva.com> + + * dmi.c: dmidecode >= 2.7 support + +2006-06-27 20:35 Olivier Blin <oblin at mandriva.com> + + * lspcidrake.pl: initial lspcidrake immplementation using modalias + +2006-06-07 16:17 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: add standard cvs warning + +2006-02-22 13:11 Thierry Vignaud <tvignaud at mandriva.com> + + * usb.c: fix freeing a reference to a constant string (fredl) + +2006-01-05 15:58 Gwenole Beauchesne <gbeauchesne at mandriva.com> + + * ldetect.spec: fix url (mandriva) + +2006-01-05 15:42 Gwenole Beauchesne <gbeauchesne at mandriva.com> + + * pci.c: always initialize n_pci_domains, stick to 0 on opendir() + error and no match + +2006-01-05 15:38 Gwenole Beauchesne <gbeauchesne at mandriva.com> + + * ldetect.spec: 0.6.4-1mdk + +2006-01-05 15:38 Gwenole Beauchesne <gbeauchesne at mandriva.com> + + * pci.c: add support for pci domains + +2005-10-17 08:32 Pixel <pixel at mandriva.com> + + * ldetect.spec: fix rpm Group + +2005-08-05 13:22 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: *** empty log message *** + +2005-08-05 13:21 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.6.3-1mdk + +2005-08-05 13:20 Thierry Vignaud <tvignaud at mandriva.com> + + * usb.c: (usb_probe) prevent spurious warnings for strange USB + interfaces + +2005-08-03 09:03 Pixel <pixel at mandriva.com> + + * lspcidrake.c: when given a dmidecode_file, we don't need to be + root + +2005-05-16 04:11 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: *** empty log message *** + +2005-05-16 04:11 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.6.2-1mdk + +2005-05-16 03:19 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.c: do not try to run dmidecode when not root + +2005-03-30 15:08 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: *** empty log message *** + +2005-03-30 15:06 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.6.1-1mdk + +2005-03-30 15:03 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: oops: sata_via doesn't support for CLASS probing whereas + sata_nv does + +2005-03-14 17:20 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * pciusb.c: fix running on a empty pci/usb devices source + +2005-03-14 12:34 Pixel <pixel at mandriva.com> + + * lspcidrake.c: fix typo + +2005-03-14 12:33 Pixel <pixel at mandriva.com> + + * pciusb.c: fix a memory leak + +2005-03-14 12:32 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * pci.c: setting .nb to 0 seems a better idea than setting .entries + +2005-02-23 17:48 Pablo Saratxaga <pablo at mandriva.com> + + * ChangeLog: converted to UTF-8 + +2005-02-17 14:16 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: *** empty log message *** + +2005-02-17 14:16 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: fill in 0.5.5-1mdk's changelog + +2005-02-17 14:15 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.5.5-1mdk + +2005-02-17 14:15 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: handle a few more special cases (gdth, snd-vx222, 8139too, + and agp bridges) + +2005-02-17 12:26 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <pixel at mandriva.com> + + * ldetect.spec, pci.c: all PCI_CLASS_BRIDGE_CARDBUS cards are + yenta_socket (says kudzu) + +2004-10-28 08:08 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: *** empty log message *** + +2004-10-28 08:07 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.5.3-1mdk + +2004-10-27 13:35 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: make ldetect-devel usable on amd64 + +2004-10-27 13:21 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: keep existing description string if already reported by + the device + +2004-06-17 08:35 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.5.2-1mdk + +2004-06-17 08:33 Thierry Vignaud <tvignaud at mandriva.com> + + * usb.c: (usb_probe) ask the kernel for module to use with usb + devices + +2003-11-20 15:20 Pixel <pixel at mandriva.com> + + * generate_usbclass.pl, ldetect.spec: don't display "Vendor + Specific Class" usb class + +2003-11-20 15:03 Pixel <pixel at mandriva.com> + + * generate_usbclass.pl, ldetect.spec, libldetect.h, lspcidrake.c: + new usb_class code (breaks compatibility!) + +2003-08-20 09:11 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.c: remove dummy reference to silently ignored -f + option + +2003-08-20 00:23 Pixel <pixel at mandriva.com> + + * lspcidrake.c: fix argument testing + +2003-08-20 00:21 Pixel <pixel at mandriva.com> + + * generate_pciclass.pl, generate_usbclass.pl, usb.c: a little + cleanup + +2003-08-19 21:28 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * Makefile: only check for latest logs + +2003-01-28 14:39 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog, Makefile: - sanitize ChangeLog + - add log rule + +2003-01-06 14:34 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: *** empty log message *** + +2003-01-06 14:34 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: add pixel changes + +2003-01-06 14:32 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.4.8-1mdk + +2003-01-06 14:24 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <pixel at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * usb.c: fix access check + +2002-10-15 14:40 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.4.7-1mdk + +2002-10-07 09:32 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: enforce gc coding rules + +2002-10-07 09:21 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * AUTHORS: fix gc + +2002-09-05 11:25 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * ldetect.spec: fix getting the Product name in usb (occurs when + there is no entry in usbtable) + +2002-08-29 12:17 Pixel <pixel at mandriva.com> + + * usb.c: fix getting the Product name + +2002-08-29 12:17 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: fix PCI_CLASS_PROG offset + +2002-08-26 02:50 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog, ldetect.spec: 0.4.6-4mdk + +2002-08-25 22:47 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * ChangeLog, ldetect.spec: 0.4.6-3mdk + +2002-08-22 10:27 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: try to not freeze on buggy motherboard by preventing: + - seeking in /proc/bus/pci/<bus>/<device>.<function> + - not reading the whole /proc/bus/pci/<bus>/<device>.<function> + + we now read 48 linear bytes the same way lspci read 64 linear + bytes. + +2002-08-17 14:18 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: - rpmlint fixes (url, doc) + - simplification + +2002-08-17 14:12 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: split rpm target in srpm and rpm + +2002-08-17 14:08 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog, ldetect.spec: 4.6mdk + +2002-08-17 14:06 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: default RPM to ~/rpm + +2002-08-16 16:07 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: *** empty log message *** + +2002-08-16 16:03 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * pciusb.c, usb.c: usb audio devices can use new alsa modules + snd-usb-audio + +2002-08-08 15:25 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog, ldetect.spec: 0.4.5-1mdk: don't depend of the table + order + +2002-08-08 15:20 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <pixel at mandriva.com> + + * ldetect.spec: use -fPIC on every arch + +2002-07-30 19:03 Pixel <pixel at mandriva.com> + + * ldetect.spec, usb.c: fill in pci_bus and pci_device for USB + +2002-07-25 12:07 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.4.4-1mdk + +2002-07-25 12:05 Thierry Vignaud <tvignaud at mandriva.com> + + * ChangeLog: *** empty log message *** + +2002-07-25 12:04 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * ldetect.spec: 0.4.3-1mdk + +2002-07-23 08:10 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.c: enhanced help + +2002-07-22 21:37 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * ChangeLog, ldetect.spec: next release is ok + +2002-07-16 15:33 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.c: explain what does -f + +2002-07-16 15:30 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: no need for unistd.h + +2002-07-16 15:29 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * lspcidrake.c: - fix usb "url" + + - prevent potential segfault if no argument to -u in next test + +2002-07-16 15:07 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * lspcidrake.c: compacificazion + +2002-07-09 21:28 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.c: fix for "gcc-2.95.3 don't compile" (reported by Ian + White) + +2002-07-05 09:02 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: add explicit depandancies so that make rebuild files if + needed when header're altered + +2002-07-05 08:56 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: compile with -Os (which results in saving 12% of text + size) + +2002-07-04 15:15 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c: factorize common constants in private header + +2002-07-04 15:14 Thierry Vignaud <tvignaud at mandriva.com> + + * usb.c: typo fix + +2002-07-04 15:14 Thierry Vignaud <tvignaud at mandriva.com> + + * usb.c: - factorize common constants in private header + + - factorize strlen() call + +2002-07-04 15:04 Thierry Vignaud <tvignaud at mandriva.com> + + * libldetect-private.h, pci.c, usb.c: factorize common constants in + private header + +2002-07-04 14:59 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.c: we don't really need stdlib.h + +2002-07-04 14:58 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * lspcidrake.c: - merge {pci,usb}_printit into printit + + - kill usage() + +2002-07-04 11:44 Thierry Vignaud <tvignaud at mandriva.com> + + * ldetect.spec: 0.4.1-1mdk + +2002-07-04 11:29 Thierry Vignaud <tvignaud at mandriva.com> + + * usb.c: make an if clearer + +2002-07-03 12:03 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: s/zcat/gzip -cd/ back for lord pixou + +2002-07-03 10:20 Thierry Vignaud <tvignaud at mandriva.com> + + * pciusb.c: ifree(e->text) to prevent mem leak with usb + +2002-07-03 10:09 Thierry Vignaud <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * 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 <tvignaud at mandriva.com> + + * libldetect-private.h, pci.c, pciusb.c, usb.c: get rid of more + uneeded copies + +2002-07-03 09:05 Thierry Vignaud <tvignaud at mandriva.com> + + * AUTHORS: list all contributors + +2002-07-03 08:54 Thierry Vignaud <tvignaud at mandriva.com> + + * pci.c, usb.c: get rid of {pci,usb}_find_modules() + +2002-07-03 08:53 Thierry Vignaud <tvignaud at mandriva.com> + + * libldetect.h, lspcidrake.c: prevent signed vs unsigned comp + warnings + +2002-07-03 08:49 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.c, pci.c, pciusb.c, usb.c: indent-region + +2002-07-03 08:42 Thierry Vignaud <tvignaud at mandriva.com> + + * libldetect.h, lspcidrake.c, pciusb.c: don't do uneeded copies + (saves 2% of text size) + +2002-07-03 08:41 Thierry Vignaud <tvignaud at mandriva.com> + + * Makefile: be more strict + +2002-07-03 08:27 Thierry Vignaud <tvignaud at mandriva.com> + + * lspcidrake.c: simplify (source is clearer, binary isn't really + altered) + +2002-06-26 14:10 Gwenole Beauchesne <gbeauchesne at mandriva.com> + + * ldetect.spec: sanitize specfile + +2002-06-10 18:39 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * AUTHORS: *** empty log message *** + +2001-12-28 12:04 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * ldetect.spec: s/Copyright/License/ + +2001-09-13 13:41 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * ldetect.spec: fix when 2 similar devices are there + +2001-07-03 20:28 Pixel <pixel at mandriva.com> + + * pciusb.c: fix pb when 2 similar cards are there + +2001-04-12 15:15 Pixel <pixel at mandriva.com> + + * ldetect.spec, pciusb.c: close fdno's of the pipe which are unused + or dup2'ed + +2001-04-12 15:15 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * ldetect.spec: fix some memory leak and a few segfaults + +2001-03-29 10:36 Pixel <pixel at mandriva.com> + + * pciusb.c: fix some memory leak a few segfaults + +2001-03-24 10:48 Pixel <pixel at mandriva.com> + + * ldetect.spec, pciusb.c: nasty C, fclose on popen'ed gets a + segfault, in /some/ cases :-( + +2001-03-23 15:17 Pixel <pixel at mandriva.com> + + * ldetect.spec, pciusb.c: handle gzip'ed pcitable/usbtable + +2001-03-21 18:05 Pixel <pixel at mandriva.com> + + * ldetect.spec: use subids if they are needed + +2001-03-21 18:03 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * pci.c: fix the fclose + +2001-02-06 16:56 Pixel <pixel at mandriva.com> + + * ldetect.spec: add missing fclose's + +2001-02-06 16:55 Pixel <pixel at mandriva.com> + + * 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 <pixel at mandriva.com> + + * ., .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 <pixel at mandriva.com> + + * Makefile: *** empty log message *** + +2000-12-15 15:32 Pixel <pixel at mandriva.com> + + * ldetect.spec: - add requires ldetect-lst + +2000-12-15 15:30 Pixel <pixel at mandriva.com> + + * ldetect.spec: fix description tag + +2000-12-15 15:25 Pixel <pixel at mandriva.com> + + * Makefile, ldetect.spec: put the version in .spec too, otherwise + can't use rpm C-c e :) + +2000-12-15 15:19 Pixel <pixel at mandriva.com> + + * 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 @@ -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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#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 <zlib.h> + +#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 @@ -0,0 +1,285 @@ +/* DMI (Desktop Management Interface) + also called + SMBIOS (System Management BIOS) +*/ + +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#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 <pci.h>, 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 </usr/share/usb.ids>, 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; + } +} + +'; @@ -0,0 +1,154 @@ +#include <sys/types.h> +#include <dirent.h> +#include <fnmatch.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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 <stdint.h> + +/******************************************************************************/ +/* 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 <sys/types.h> +#include <string.h> + +#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 <stdio.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#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 <file>\tPCI devices source [/proc/bus/pci/devices by default]\n" + "\t-u, --usb-file <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 <file>\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 <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/utsname.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <modprobe.h> +#include <dirent.h> +#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); +} @@ -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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <ctype.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_LIBZ +#include <zlib.h> +#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; +} @@ -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 <stdint.h> + +/* ---------------------------------------------------------------------- */ + +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 */ @@ -0,0 +1,112 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <pci/pci.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <dirent.h> +#include <pci/header.h> +#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 <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/utsname.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <modprobe.h> +#include <dirent.h> +#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); +} @@ -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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <dirent.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#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; +} @@ -0,0 +1,145 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#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; +} + |