summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDexter Morgan <dmorgan@mageia.org>2011-06-02 20:49:50 +0000
committerDexter Morgan <dmorgan@mageia.org>2011-06-02 20:49:50 +0000
commitdb5a94788a783a716de6c79e23f2e45093aca398 (patch)
treef0448c53425509d4272a355f120cb7249d4d58e8
downloadldetect-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--AUTHORS4
-rw-r--r--ChangeLog1290
-rwxr-xr-xMDV/Lspciusb.pm63
-rw-r--r--Makefile89
-rw-r--r--NEWS65
-rw-r--r--common.c110
-rw-r--r--common.h47
-rw-r--r--dmi.c285
-rw-r--r--generate_pciclass.pl28
-rwxr-xr-xgenerate_usbclass.pl81
-rw-r--r--hid.c154
-rw-r--r--libldetect.h95
-rw-r--r--libsysfs.h90
-rw-r--r--lspcidrake.c120
-rwxr-xr-xlspcidrake.pl35
-rw-r--r--modalias.c148
-rw-r--r--names.c813
-rw-r--r--names.h52
-rw-r--r--pci.c112
-rw-r--r--pciusb.c192
-rw-r--r--sysfs.h64
-rw-r--r--sysfs_attr.c241
-rw-r--r--sysfs_utils.c59
-rw-r--r--usb.c145
24 files changed, 4382 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e9857cb
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Chmouel (cannot open fix)
+Guillaume Cottenceau (bug fixes, -v -f options)
+Pixel (core developer)
+Thierry Vignaud <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
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..83f77e2
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,65 @@
+Version 0.11.1 - 1 December 2009, Thierry Vignaud
+
+- do not crash if there're more than 100 PCI devices
+- further use libpci in order to check for PCIe capability
+
+Version 0.11.0 - 1 October 2009, Thierry Vignaud
+
+- reduce memory footprint
+
+Version 0.10.0 - 30 September 2009, Thierry Vignaud
+
+- do not display random revisions for USB devices
+- retrieve PCI capabilities in order to better identify PCI Express devices
+
+Version 0.9.1 - 28 September 2009, Thierry Vignaud
+
+- fix inverted test for choosing between '8139cp' & '8139too' drivers (#53349)
+
+Version 0.9.0 - 23 September 2009, Thierry Vignaud
+
+- display PCI revision (#42576)
+- try harder to fetch the right driver between '8139cp' & '8139too'
+ according to PCI revision (#53349)
+
+Version 0.8.6 - 23 September 2009, Pascal Terjan
+
+- parse only once usb.ids (avoids displaying Duplicate errors)
+
+Version 0.8.5 - 14 September 2009, Pascal Terjan
+
+- do not display any warning when driver field is empty in
+ /proc/bus/usb/devices (#53412)
+- fix freed memory usage in criteria_from_dmidecode and entries_matching_criteria
+- fix const warnings in dmi.c
+
+Version 0.8.4 - 25 June 2009, Pascal Terjan
+
+- fix freed memory usage in usb_probe and pci_probe
+- use usb.ids
+
+Version 0.8.3 - 20 April 2009, Pascal Terjan
+
+- fix parsing of /proc/bus/usb/device I: lines and use the class
+ of the first interface used by a driver instead of the first
+ interface (or first one like before when none is used).
+ That fixed presenting something as usb_storage even if the
+ device is ignored by usb_storage driver and handled on another
+ interface by option driver
+- ignore usb interfaces not active
+
+Version 0.8.1 - 3 April 2009, Christophe Fergeau
+
+- enumerate hid bus
+- fixes some memory leaks
+
+Version 0.8.0 - 27 March 2009, Olivier Blin
+
+- do not use random string as device description
+- use /sys/bus/usb/devices instead of /sys/class/usb_device
+ (disabled in recent kernel) to find modalias
+ (this breaks ABI because we now need to keep port number)
+
+Version 0.7.26 - 14 May 2008, Thierry Vignaud
+
+- adapt to pciutils-3.x API
diff --git a/common.c b/common.c
new file mode 100644
index 0000000..58d45ee
--- /dev/null
+++ b/common.c
@@ -0,0 +1,110 @@
+
+#define _GNU_SOURCE
+#include <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
diff --git a/dmi.c b/dmi.c
new file mode 100644
index 0000000..b927994
--- /dev/null
+++ b/dmi.c
@@ -0,0 +1,285 @@
+/* DMI (Desktop Management Interface)
+ also called
+ SMBIOS (System Management BIOS)
+*/
+
+#define _GNU_SOURCE
+#include <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;
+ }
+}
+
+';
diff --git a/hid.c b/hid.c
new file mode 100644
index 0000000..2103c00
--- /dev/null
+++ b/hid.c
@@ -0,0 +1,154 @@
+#include <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);
+}
diff --git a/names.c b/names.c
new file mode 100644
index 0000000..a39425d
--- /dev/null
+++ b/names.c
@@ -0,0 +1,813 @@
+/*****************************************************************************/
+/*
+ * names.c -- USB name database manipulation routines
+ *
+ * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+/*****************************************************************************/
+
+#include <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;
+}
diff --git a/names.h b/names.h
new file mode 100644
index 0000000..71c27d4
--- /dev/null
+++ b/names.h
@@ -0,0 +1,52 @@
+/*****************************************************************************/
+
+/*
+ * names.h -- USB name database manipulation routines
+ *
+ * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+/*****************************************************************************/
+
+#ifndef _NAMES_H
+#define _NAMES_H
+
+#include <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 */
diff --git a/pci.c b/pci.c
new file mode 100644
index 0000000..5bd344f
--- /dev/null
+++ b/pci.c
@@ -0,0 +1,112 @@
+#define _GNU_SOURCE
+#include <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);
+}
diff --git a/sysfs.h b/sysfs.h
new file mode 100644
index 0000000..76754a4
--- /dev/null
+++ b/sysfs.h
@@ -0,0 +1,64 @@
+/*
+ * sysfs.h
+ *
+ * Internal Header Definitions for libsysfs
+ *
+ * Copyright (C) IBM Corp. 2003-2005
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef _SYSFS_H_
+#define _SYSFS_H_
+
+#include <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;
+}
diff --git a/usb.c b/usb.c
new file mode 100644
index 0000000..2d5b77f
--- /dev/null
+++ b/usb.c
@@ -0,0 +1,145 @@
+#define _GNU_SOURCE
+#include <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;
+}
+