Import Upstream version 02.18.85

This commit is contained in:
Lu zhiping 2022-06-27 14:59:23 +08:00
commit 30f903d069
186 changed files with 268963 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.o
*.a
src/lshw
lshw.spec

339
COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

20
Makefile Normal file
View File

@ -0,0 +1,20 @@
PACKAGENAME = lshw
VERSION?= $(shell git describe --tags | cut -d - -f 1,2 | tr - .)
export PACKAGENAME
all clean install snapshot gui install-gui:
+$(MAKE) -C src $@
version.cpe: .version
echo -n cpe:/a:ezix:$(PACKAGENAME): > $@
cat $^ >> $@
.PHONY: $(PACKAGENAME).spec
$(PACKAGENAME).spec: $(PACKAGENAME).spec.in
cat $^ | sed -e s/\@VERSION\@/$(VERSION)/g > $@
release: $(PACKAGENAME).spec
git archive --prefix=$(PACKAGENAME)-$(VERSION)/ -o $(PACKAGENAME)-$(VERSION).tar HEAD
tar --transform s!^!$(PACKAGENAME)-$(VERSION)/! -rf $(PACKAGENAME)-$(VERSION).tar $^
gzip -f $(PACKAGENAME)-$(VERSION).tar

72
README.md Normal file
View File

@ -0,0 +1,72 @@
lshw: HardWare LiSter for Linux
===============================
lshw is a small tool to provide detailed information on the hardware configuration of the machine. It can report exact memory configuration, firmware version, mainboard configuration, CPU version and speed, cache configuration, bus speed, etc. on DMI-capable x86 or EFI (IA-64) systems and on some ARM and PowerPC machines (PowerMac G4 is known to work).
Information can be output in plain text, XML or HTML.
It currently supports DMI (x86 and EFI only), OpenFirmware device tree
(PowerPC only), PCI/AGP, ISA PnP (x86), CPUID (x86), IDE/ATA/ATAPI, PCMCIA
(only tested on x86), USB and SCSI.
Installation
------------
1. Requirements
- Linux 2.4.x, 2.6.x, 3.x or 4.x (2.2.x might work, though)
- a PA-RISC-, Alpha-, IA-64- (Itanium-), PowerPC-, ARM- or x86- based machine
- an ANSI (or close enough to ANSI compliance) C++ compiler (tested with g++ 2.95.4 and 3.x)
- for the (optional) GTK+ graphical user interface, you will need a
complete GTK+ development environment (gtk2-devel on RedHat/Fedora derivatives)
2. To compile it, just use:
$ make
To complile with zlib support (see below), use:
$ make ZLIB=1
3. If you want to build the optional GUI, do:
$ make
$ make gui
4. If you want to install the result, do:
$ make install
$ make install-gui
Getting help
------------
1. the lshw home page is http://lshw.ezix.org/
2. bug reports and feature requests: http://ezix.org/project/newticket?component=lshw
Please make sure you include enough information in your bug report: XML output from lshw is preferred over text or HTML, indicate the affected version of lshw, your platform (i386, x86-64, PA-RISC, PowerPC, etc.) and your distribution.
NOTE TO DISTRIBUTIONS
---------------------
By default, lshw includes its own lists of PCI IDs, USB IDs, etc. but will also look for this information in
/usr/share/lshw/,
/usr/local/share/,
/usr/share/,
/etc/,
/usr/share/hwdata/,
/usr/share/misc/
If compiled with zlib support, lshw will look for `file`.gz first, then for `file`.
Statically-linked and/or compressed binaries can be built by using
$ make static
or
$ make compressed
in the `src/` directory
Building compressed binaries requires `upx` (cf. https://upx.github.io/).

214
docs/Changelog Normal file
View File

@ -0,0 +1,214 @@
* lshw B.02.18
migrated to git
bug fixes
code cleanup
updated data files
* lshw B.02.17
bug fixes
code cleanup
improved support for FAT-formatted disks
updated data files
* lshw B.02.16
bug fixes
code cleanup
improved support for GPT-partitioned disks
report physical sector size of hard disks
rewrote GTK2 GUI for increased flexibility (use external UI file)
updated data files
* lshw B.02.15
experimental SQLite support
bug fixes
updated data files
* lshw B.02.14
bug fixes
support for EXT4 partitions
* lshw B.02.13
fix bug #402: properly detect 64 bit systems (even when compiled for i386)
fix bug #401: SMP-related crash on IA-64
fix bug #399: portability problem on Arch Linux
fix bug #386: portability problem (crash) on Sparc
fix bug #340: hang on certain PCI devices
fix bug #105: Debian bug 456896
code cleanup
updated data files
* lshw B.02.12.01
fix problem with log lines in `usb.ids` (#321)
* lshw B.02.12
be more careful about invalid UTF-8 strings (some DMI implementations return garbage) (#142)
added detection of LUKS volumes (#132)
implemented automatic check for updates
implemented SMP detection (#7)
report volume/filesystem detailed information (FAT, ext2/ext3, reiserfs, NTFS, HFS/HFS+, swap)
report MBR disk signatures (#21)
GUI: added `nologo` make target to remove copyrighted icons
GUI: added `icon` make target to embed SVG icon into executable
GUI: display a warning when running as non-root user
updated data files
* lshw B.02.11.01
fixed `make install` (#128)
GUI: only activate ''Save'' function (toolbar button and menu entry) when needed
GUI: better handling of older GTK+ versions that can't read SVG files (#130)
updated data files
* lshw B.02.11
implemented "export" function in GUI (#13)
RPM package cleanups, GUI now built by default (#111)
fixed XML output (#115)
fixed handling of command-line options (#121)
added -sanitize option (#122)
support 15000rpm SCSI discs (#124)
fixed IDE detection (#126)
* lshw B.02.10
minor bugfixes (#95, ...)
added -quiet option (#107)
added preliminary support for IDE RAID arrays (#25)
* lshw B.02.09
minor bugfixes (#26, #27)
added support for PCI domains (#28)
use of /sys (sysfs) when possible for PCI devices
* B.02.08.01
bugfix release for non-x86 platforms (#24)
* B.02.08
added reporting of GUID-based partitions tables (#4)
added reporting of basic LVM2 information (#2)
"nicer" (and more customisable) HTML output
* B.02.07
added reporting of extended partitions (#1)
minor cosmetic fixes
some new SVG icons [1235] [1236] [1237]
* B.02.06
fixed reporting of SCSI disks serial numbers [1159] [1158]
added support for reporting of disk partitions (MS-DOS [1107], Apple [1112] & HP-UX LIF [1113])
some new SVG icons [1163] [1160] [1155]
* B.02.05.01
fixed a portability problem with GTK+ [1099]
* B.02.05
added support for DVD writers
improved GUI usability (thanks to OpenUsability volonteers: Tina Trillitzsch and Florian Graessle)
many new SVG icons
added a logo for LSHW (used as icon for gtk-lshw's windows)
build system updates
bug fixes
* B.02.04
added support for CPUFreq (Speedstep & similar technologies)
the GUI now uses a GtkTextView instead of a GtkLabel
SVG icons are now displayed for USB, Firewire, SCSI, etc.
added support for reporting VMX (Vanderpool) capabilities (untested)
fixed a compilation problem with GCC 4
* B.02.03
added support for PA-RISC devices (IODC-controlled) on 2.6 kernels
the GUI can now be launched by invoking lshw with the '-X' option
network devices clean-up (removed last bits of MII-diag, replaced by ethtool); gigabit-ethernet is now reported
cosmetic fixes
simplified reporting of SCSI devices
added an XML Schema Definition (XSD)
fixes for Apple machines (serial # reporting, more models identified)
added reporting of "width" (32 or 64 bits) for various components (PCI devices, memory banks, CPUs)
documentation updates
allow parallel builds
* B.02.02
added reporting of battery-related information using DMI
added reporting of hardware security (DMI): admin/user/power-on passwords
FIX: worked around the disparition of /proc/ide/ide*/config on 2.6.10
new "businfo" output style
first try to define an XML schema (cf. XSD file in docs/)
renamed lm capability to x86-64 (easier to understand)
portability fixes for RedHat 7.3
updated USB IDs
documentation updates
added support for /proc/cpuinfo on x86-64
code cleanup
* B.02.01
better support for emulated SCSI devices: USB mass storage devices are now properly handled
added a "go-up" button to the GUI
lshw now reports x86-64 capability
minor fixes to give better descriptions of capabilities
automatically create ghost (removed after use) /dev/sgxx entries when needed (affects Fedora Core 3 and other distributions that don't include these entries)
USB code clean-up
portability fixes for Gentoo Linux
* B.02.00
various fixes
added a GTK+ GUI
* A.01.09
code cleanup
added support for USB devices
various fixes
updated list of recognised PCI devices
added list of recognised USB devices
source code reorganisation
preparation for the development of a GTK+-based GUI
* A.01.08
code cleanup
added support for static and compressed (UPX) static builds
added support for HT (hyper-threading); lshw now reports "virtual" CPUs
DMI fixes (thanks to Erwan Velu from MandrakeSoft)
XML output filtering
packaging system fixes (thanks to Oron Peled)
updated list of recognised PCI devices
* A.01.07
fixed annoying IDE-related bug that caused un-necessary kernel error messages
portability fixes
migrated lshw's source code to Subversion
build system updates
more work on sysfs
report WLAN capabilities
report speed of network links
bugfixes
* A.01.06
code cleanup
support for EFI-based (IA-64) systems, thanks to Bruno Cornec from HP
the output of lshw can now be restricted to certain classes of hardware (disks, memory, etc.)
preliminary support for 2.6 kernel using sysfs
very preliminary support for USB devices (disabled by default)
fixed typos
* A.01.05
code cleanup
PCI and PCMCIA now correctly report resources (ports, memory and IRQs)
support for framebuffer devices
report detailed DIMM info on PowerPC machines
fixed compilation problem for older distributions
* A.01.04
beginning of resources reporting
bug fixes for multi-host bridge machines (servers, PowerMacs)
fixes for OpenFirmware machines (PowerMacs)
SCSI-over-IDE fixes (now connected to the right IDE device)
new ability to disable some tests
ISA PnP is now disabled by default (was too long)
* A.01.03
new ioscan (HP-UX) -like output format
added detection of ISA Plug & Play cards on x86 machines
lshw now reports more detailed information on network interfaces
* A.01.02
cosmetic changes
added detection of Apple model names for Macs
1st try of SPD memory DIMM support
lshw now reports information on network interfaces
* A.01.01
fixed memory reporting for systems with more than 2GB of memory
* A.01.00
minor bug fixes
support for more platforms (PA-RISC, IA-64 and Alpha)
lshw can now generate XML
* T.00.07
minor bug fixes
lshw now generates correct HTML (thanks to Ola Lundqvist)
SCSI support
added a manpage (thanks to Helge Kreutzmann)
* T.00.06
minor bug fixes
PCMCIA support
support for device claiming
preliminary support for non-PCI IDE controllers/devices
* T.00.05
code clean-up
probing of IDE devices
* T.00.04
activated HTML mode
reporting of video memory
bug fixes
* T.00.03
fixes for GCC 3.2
* T.00.02
second public test release
PCI busses listing
* T.00.01
first public test release

68
docs/IODC.txt Normal file
View File

@ -0,0 +1,68 @@
Some notes on IODC, its general brokenness, and how to work around it.
Short Version
IODC is HP's pre-PCI standard for device identification (a la PCI vendor,
device IDs), detection, configuration, initialization and so on.
It also can provide firmware function to do the actual IO, which are slow,
not really defined for runtime usage and generally not desirable. (There
are other firmware standards, such as STI, to do real IO).
Usually, there are two parts to IODC. The actual ROMs, which are laid out,
detected aso in a bus-specific manner (IO_DC_ADDRESS / IO_DC_DATA on
GSC/Runway, PCI spec - compliant ROMs for PCI, God-only-knows how on EISA),
and the slightly cooked data read by PDC_IODC.
The ROM layout is generally icky (only one byte out of every 4-byte-word
might be valid, and many devices don't implement required options), so
using PDC_IODC is highly recommended. (In fact, you should use the device
lists set up by the kernel proper instead of calling PDC_IODC yourself).
Now, let's have a look at what the cooked ROM looks like (see iodc.pdf for
the details, this is the simplified version).
Basically, the first 8 bytes of IODC contain two 32-bit ids called HVERSION
and SVERSION. Those are further split up into bit fields, and
unfortunately just ignoring this split up isn't an option.
SVERSION consists of a 4-bit revision field, a 20-bit model field and a
8-bit opt field. Now, forget the revision and opt fields exist. Basically,
the model field is equivalent to a PCI device id (there is no vendor id.
this is proprietary hardware we're talking about). That is, all your
driver cares for, in 90 % of the cases, is to find all devices that match
the model field.
The rev field is - you guessed it - roughly equivalent to the revision
byte for PCI, with the exception that higher revisions should be strict
supersets of lower revisions.
The last byte of HVERSION, "type", and the last byte of SVERSION, "opt",
belong together; type gives a very rough indication of what the device
is supposed to do, and opt contains some type-specific information. (For
example, the "bus converter" (ie bus bridge) type encodes the kind of
bus behind the bridge in the opt field.
The rest of HVERSION contains, in most cases, a number identifying the
machine the chip was used in, or a revision indicator that just fixed
bugs and didn't add any features (or was done in a shrinked process or
whatever).
So, here's the interface you actually should use to find your devices:
/* Find a device, matching the model field of sversion only (from=NULL
* for the first call */
struct iodc_dev *iodc_find_device(u32 sversion, struct iodc_dev *from);
Here's a function you should use if you have special requirements, such
as finding devices by type rather than by model. Generally, if you're
using this, you should be me).
/* Find a device, masking out bits as specified */
struct iodc_dev *iodc_find_device_mask(u32 hversion, u32 sversion,
u32 hversion_mask, u32 sversion_mask, struct iodc_dev *from);
Philipp Rumpf <prumpf@tux.org>

9
docs/TODO Normal file
View File

@ -0,0 +1,9 @@
=IMPROVEMENTS:=
* use sysfs instead of trying to "guess" a device's parent
* report wireless-related information (SSID, channel, AP, mode, etc.) - cf. iwconfig
* SCSI clean-up (cf. newest versions of sg_utils)
* on 2.6 kernels, use SG_IO directly on devices, not their sg counterpart
* for emulated SCSI devices, don't report fake host/channel, just target
* use businfo to find CPUs instead of hardcoding cpu:n form
* use sysfs for PCMCIA access
* use MPTABLE for reporting of CPUs

90
docs/lshw.xsd Normal file
View File

@ -0,0 +1,90 @@
<?xml version="1.0"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.ezix.org"
xmlns="http://www.ezix.org"
elementFormDefault="qualified">
<xs:element name="node" type="nodeinfo" />
<xs:complexType name="nodeinfo">
<xs:sequence>
<xs:element name="description" type="xs:string" minOccurs="0" />
<xs:element name="product" type="xs:string" minOccurs="0" />
<xs:element name="vendor" type="xs:string" minOccurs="0" />
<xs:element name="physid" type="xs:string" minOccurs="0" />
<xs:element name="version" type="xs:string" minOccurs="0" />
<xs:element name="date" type="xs:string" minOccurs="0" />
<xs:element name="serial" type="xs:string" minOccurs="0" />
<xs:element name="businfo" type="xs:string" minOccurs="0" />
<xs:element name="slot" type="xs:string" minOccurs="0" />
<xs:element name="size" type="measured" minOccurs="0" />
<xs:element name="capacity" type="measured" minOccurs="0" />
<xs:element name="clock" type="measured" minOccurs="0" />
<xs:element name="width" type="measured" minOccurs="0" />
<xs:element name="configuration" type="configinfo" minOccurs="0" />
<xs:element name="capabilities" type="capinfo" minOccurs="0" />
<xs:element name="resources" type="resinfo" minOccurs="0" />
<xs:element name="node" type="nodeinfo" maxOccurs="unbounded" minOccurs="0" />
</xs:sequence>
<xs:attribute name="id" type="xs:string" minOccurs="0" />
<xs:attribute name="handle" type="xs:string" minOccurs="0" />
<xs:attribute name="class" type="xs:string" minOccurs="0" />
<xs:attribute name="claimed" type="xs:boolean" minOccurs="0" />
<xs:attribute name="disabled" type="xs:boolean" minOccurs="0" />
<xs:attribute name="modalias" type="xs:string" minOccurs="0" />
</xs:complexType>
<xs:complexType name="measured">
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="units" type="xs:string" minOccurs="0" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="configinfo">
<xs:sequence>
<xs:element name="setting" type="configentry" maxOccurs="unbounded" minOccurs="0" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="configentry">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="id" type="xs:string" />
<xs:attribute name="value" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="capinfo">
<xs:sequence>
<xs:element name="capability" type="capentry" maxOccurs="unbounded" minOccurs="0" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="capentry">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="id" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="resinfo">
<xs:sequence>
<xs:element name="resource" type="resentry" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="resentry">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="type" type="xs:string" />
<xs:attribute name="value" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>

274
docs/proc_usb_info.txt Normal file
View File

@ -0,0 +1,274 @@
[from http://www.charmed.com/txt/proc_usb_info.txt]
/proc/bus/usb filesystem output
===============================
(version 2000.08.15)
The /proc filesystem for USB devices generates
/proc/bus/usb/drivers and /proc/bus/usb/devices.
/proc/bus/usb/drivers lists the registered drivers,
one per line, with each driver's USB minor dev node
number range if applicable.
**NOTE**: If /proc/bus/usb appears empty, you need
to mount the filesystem, issue the command (as root):
mount -t usbdevfs none /proc/bus/usb
An alternative and more permanent method would be to add
none /proc/bus/usb usbdevfs defaults 0 0
to /etc/fstab. This will mount usbdevfs at each reboot.
You can then issue `cat /proc/bus/usb/devices` to extract
USB device information.
For more information on mounting the usbdevfs file system, see the
"USB Device Filesystem" section of the USB Guide. The latest copy
of the USB Guide can be found at http://www.linux-usb.org/
In /proc/bus/usb/devices, each device's output has multiple
lines of ASCII output.
I made it ASCII instead of binary on purpose, so that someone
can obtain some useful data from it without the use of an
auxiliary program. However, with an auxiliary program, the numbers
in the first 4 columns of each "T:" line (topology info:
Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
(I think. I haven't proved this, but I have tested it with 3
different topo/connections and it looked possible.)
Each line is tagged with a one-character ID for that line:
T = Topology (etc.)
B = Bandwidth (applies only to USB host controllers, which are
virtualized as root hubs)
D = Device descriptor info.
P = Product ID info. (from Device descriptor, but they won't fit
together on one line)
S = String descriptors.
C = Configuration descriptor info. (* = active configuration)
I = Interface descriptor info.
E = Endpoint descriptor info.
=======================================================================
/proc/bus/usb/devices output format:
Legend:
d = decimal number (may have leading spaces or 0's)
x = hexadecimal number (may have leading spaces or 0's)
s = string
Topology info:
T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
| | | | | | | | |__MaxChildren
| | | | | | | |__Device Speed in Mbps
| | | | | | |__DeviceNumber
| | | | | |__Count of devices at this level
| | | | |__Connector/Port on Parent for this device
| | | |__Parent DeviceNumber
| | |__Level in topology for this bus
| |__Bus number
|__Topology info tag
Bandwidth info:
B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
| | | |__Number if isochronous requests
| | |__Number of interrupt requests
| |__Total Bandwidth allocated to this bus
|__Bandwidth info tag
Device descriptor info & Product ID info:
D: Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
where
D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
| | | | | | |__NumberConfigurations
| | | | | |__MaxPacketSize of Default Endpoint
| | | | |__DeviceProtocol
| | | |__DeviceSubClass
| | |__DeviceClass
| |__Device USB version
|__Device info tag #1
where
P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
| | | |__Product revision number
| | |__Product ID code
| |__Vendor ID code
|__Device info tag #2
String descriptor info:
S: Manufacturer=ssss
| |__Manufacturer of this device as read from the device.
|__String info tag
S: Product=ssss
| |__Product description of this device as read from the device,
| except that it is a generated string for USB host controllers
| (virtual root hubs), in the form "USB *HCI Root Hub".
|__String info tag
S: SerialNumber=ssss
| |__Serial Number of this device as read from the device,
| except that it is a generated string for USB host controllers
| (virtual root hubs), and represents the host controller's
| unique identification in the system (currently I/O or
| memory-mapped base address).
|__String info tag
Configuration descriptor info:
C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
| | | | |__MaxPower in mA
| | | |__Attributes
| | |__ConfiguratioNumber
| |__NumberOfInterfaces
|__Config info tag
Interface descriptor info (can be multiple per Config):
I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
| | | | | | | |__Driver name
| | | | | | |__InterfaceProtocol
| | | | | |__InterfaceSubClass
| | | | |__InterfaceClass
| | | |__NumberOfEndpoints
| | |__AlternateSettingNumber
| |__InterfaceNumber
|__Interface info tag
Endpoint descriptor info (can be multiple per Interface):
E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
| | | | |__Interval
| | | |__EndpointMaxPacketSize
| | |__Attributes(EndpointType)
| |__EndpointAddress(I=In,O=Out)
|__Endpoint info tag
=======================================================================
If a user or script is interested only in Topology info, for
example, use something like "grep ^T: /proc/bus/usb/devices"
for only the Topology lines. A command like
"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list
only the lines that begin with the characters in square brackets,
where the valid characters are TDPCIE. With a slightly more able
script, it can display any selected lines (for example, only T, D,
and P lines) and change their output format. (The "procusb"
Perl script is the beginning of this idea. It will list only
selected lines [selected from TBDPSCIE] or "All" lines from
/proc/bus/usb/devices.)
The Topology lines can be used to generate a graphic/pictorial
of the USB devices on a system's root hub. (See more below
on how to do this.)
The Interface lines can be used to determine what driver is
being used for each device.
The Configuration lines could be used to list maximum power
(in milliamps) that a system's USB devices are using.
For example, "grep ^C: /proc/bus/usb/devices".
Here's an example, from a system which has a UHCI root hub,
an external hub connected to the root hub, and a mouse and
a serial converter connected to the external hub.
T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
B: Alloc= 28/900 us ( 3%), #Int= 2, #Iso= 0
D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0000 ProdID=0000 Rev= 0.00
S: Product=USB UHCI Root Hub
S: SerialNumber=dce0
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms
T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0451 ProdID=1446 Rev= 1.00
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=04b4 ProdID=0001 Rev= 0.00
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms
T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0565 ProdID=0001 Rev= 1.08
S: Manufacturer=Peracom Networks, Inc.
S: Product=Peracom USB to Serial Converter
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl= 16ms
E: Ad=01(O) Atr=02(Bulk) MxPS= 16 Ivl= 16ms
E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl= 8ms
Selecting only the "T:" and "I:" lines from this (for example, by using
"procusb ti"), we have:
T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
Physically this looks like (or could be converted to):
+------------------+
| PC/root_hub (12)| Dev# = 1
+------------------+ (nn) is Mbps.
Level 0 | CN.0 | CN.1 | [CN = connector/port #]
+------------------+
/
/
+-----------------------+
Level 1 | Dev#2: 4-port hub (12)|
+-----------------------+
|CN.0 |CN.1 |CN.2 |CN.3 |
+-----------------------+
\ \____________________
\_____ \
\ \
+--------------------+ +--------------------+
Level 2 | Dev# 3: mouse (1.5)| | Dev# 4: serial (12)|
+--------------------+ +--------------------+
Or, in a more tree-like structure (ports [Connectors] without
connections could be omitted):
PC: Dev# 1, root hub, 2 ports, 12 Mbps
|_ CN.0: Dev# 2, hub, 4 ports, 12 Mbps
|_ CN.0: Dev #3, mouse, 1.5 Mbps
|_ CN.1:
|_ CN.2: Dev #4, serial, 12 Mbps
|_ CN.3:
|_ CN.1:
### END ###

115
lshw.spec.in Normal file
View File

@ -0,0 +1,115 @@
# Conditional build (--with/--without option)
# --without gui
Summary: HardWare LiSter
Name: lshw
Version: @VERSION@
Release: 2
Source: http://www.ezix.org/software/files/%{name}-%{version}.tar.gz
URL: http://lshw.ezix.org/
License: GPL
Group: Applications/System
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
%description
lshw (Hardware Lister) is a small tool to provide detailed information on
the hardware configuration of the machine. It can report exact memory
configuration, firmware version, mainboard configuration, CPU version
and speed, cache configuration, bus speed, etc. on DMI-capable x86s
systems and on some PowerPC machines (PowerMac G4 is known to work).
Information can be output in plain text, XML or HTML.
For detailed information on lshw features and usage, please see the
included documentation or go to the lshw Web page,
http://lshw.ezix.org/
%if %{!?_without_gui:1}0
%package gui
Summary: HardWare LiSter (GUI version)
Group: Applications/System
Requires: %{name} >= %{version}
Requires: gtk2 >= 2.4
BuildRequires: gtk2-devel >= 2.4
%description gui
lshw (Hardware Lister) is a small tool to provide detailed informaton on
the hardware configuration of the machine. It can report exact memory
configuration, firmware version, mainboard configuration, CPU version
and speed, cache configuration, bus speed, etc. on DMI-capable x86s
systems and on some PowerPC machines (PowerMac G4 is known to work).
This package provides a graphical user interface to display hardware
information.
For detailed information on lshw features and usage, please see the
included documentation or go to the lshw Web page,
http://lshw.ezix.org/
%endif
%prep
%setup -q
%build
%{__make} %{?_smp_mflags} \
PREFIX="%{_prefix}" \
SBINDIR="%{_sbindir}" \
MANDIR="%{_mandir}" \
DATADIR="%{_datadir}" \
all
%if %{!?_without_gui:1}0
%{__make} %{?_smp_mflags} \
PREFIX="%{_prefix}" \
SBINDIR="%{_sbindir}" \
MANDIR="%{_mandir}" \
DATADIR="%{_datadir}" \
gui
%endif
%install
%{__rm} -rf "%{buildroot}"
%{__make} \
DESTDIR="%{buildroot}" \
PREFIX="%{_prefix}" \
SBINDIR="%{_sbindir}" \
MANDIR="%{_mandir}" \
DATADIR="%{_datadir}" \
INSTALL="%{__install} -p" \
install
%if %{!?_without_gui:1}0
%{__make} \
DESTDIR="%{buildroot}" \
PREFIX="%{_prefix}" \
SBINDIR="%{_sbindir}" \
MANDIR="%{_mandir}" \
DATADIR="%{_datadir}" \
INSTALL="%{__install} -p" \
install-gui
%endif
%clean
%{__rm} -rf %{buildroot}
%files
%defattr(-,root,root, 0555)
%doc README.md COPYING docs/TODO docs/Changelog docs/lshw.xsd
%{_sbindir}/lshw
%doc %{_mandir}/man?/*
%{_datadir}/lshw/
%{_datadir}/locale/*/*/*
%if %{!?_without_gui:1}0
%files gui
%defattr(-,root,root, 0555)
%doc COPYING
%{_sbindir}/gtk-lshw
%endif
%changelog
* Tue May 1 2007 Lyonel Vincent <lyonel@ezix.org> B.02.10-2
- spec file cleanup
* Thu Apr 10 2003 Lyonel Vincent <lyonel@ezix.org> A.01.00-1
- RPM packaging

144
src/Makefile Normal file
View File

@ -0,0 +1,144 @@
PACKAGENAME:=lshw
export PACKAGENAME
VERSION?= $(shell git describe --tags --long | cut -d - -f 1,2 | tr - .)
SQLITE?=0
ZLIB?=0
DESTDIR?=/
PREFIX?=/usr
SBINDIR=$(PREFIX)/sbin
MANDIR=$(PREFIX)/share/man
DATADIR=$(PREFIX)/share
INSTALL?=install -p
STRIP?=strip
export DESTDIR
export PREFIX
export SBINDIR
export MANDIR
export DATADIR
export SQLITE
export ZLIB
CXX?=$(CROSS_COMPILE)c++
INCLUDES=-I./core/
DEFINES=-DPREFIX=\"$(PREFIX)\" -DSBINDIR=\"$(SBINDIR)\" -DMANDIR=\"$(MANDIR)\" -DDATADIR=\"$(DATADIR)\" -DVERSION=\"$(VERSION)\"
CXXFLAGS=-g -Wall -g $(INCLUDES) $(DEFINES) $(RPM_OPT_FLAGS)
ifeq ($(SQLITE), 1)
CXXFLAGS+= -DSQLITE $(shell pkg-config --cflags sqlite3)
endif
ifeq ($(ZLIB), 1)
CXXFLAGS+= -DZLIB $(shell pkg-config --cflags zlib)
endif
LDFLAGS+=-L./core/ -g
ifneq ($(shell $(LD) --help 2| grep -- --as-needed), )
LDFLAGS+= -Wl,--as-needed
endif
LDSTATIC=-static
LIBS+=-llshw -lresolv
ifeq ($(SQLITE), 1)
LIBS+= $(shell pkg-config --libs sqlite3)
endif
ifeq ($(ZLIB), 1)
LIBS+= $(shell pkg-config --libs zlib)
endif
export CXXFLAGS
export LIBS
export LDFLAGS
ifeq ($(ZLIB), 1)
DATAFILES = pci.ids.gz usb.ids.gz oui.txt.gz manuf.txt.gz pnp.ids.gz pnpid.txt.gz
else
DATAFILES = pci.ids usb.ids oui.txt manuf.txt pnp.ids pnpid.txt
endif
all: $(PACKAGENAME) $(PACKAGENAME).1 $(DATAFILES)
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $@
%.gz: %
gzip -c $< > $@
.PHONY: core
core:
+make -C core all
$(PACKAGENAME): core $(PACKAGENAME).o
$(CXX) $(LDFLAGS) -o $@ $(PACKAGENAME).o $(LIBS)
.PHONY: po
po:
+make -C po all
.PHONY: gui
gui: core
+make -C gui all
.PHONY: nologo
nologo:
cp -f gui/artwork/nologo/* gui/artwork/
.PHONY: static
static: $(PACKAGENAME)-static
$(PACKAGENAME)-static: core core/lib$(PACKAGENAME).a $(PACKAGENAME).o
$(CXX) $(LDSTATIC) $(LDFLAGS) -o $@ $(PACKAGENAME).o $(LIBS)
$(STRIP) $@
.PHONY: compressed
compressed: $(PACKAGENAME)-compressed
$(PACKAGENAME)-compressed: $(PACKAGENAME)-static
upx -9 -o $@ $<
$(PACKAGENAME).1: $(PACKAGENAME).sgml
docbook2man $<
pci.ids:
wget http://pciids.sourceforge.net/pci.ids
usb.ids:
wget http://www.linux-usb.org/usb.ids
oui.txt:
wget http://standards.ieee.org/regauth/oui/oui.txt
manuf.txt:
wget -O $@ http://anonsvn.wireshark.org/wireshark/trunk/manuf
pnp.ids:
wget https://git.fedorahosted.org/cgit/hwdata.git/plain/pnp.ids
pnpid.txt:
wget http://www-pc.uni-regensburg.de/hardware/TECHNIK/PCI_PNP/pnpid.txt
install: all
$(INSTALL) -d -m 0755 $(DESTDIR)/$(SBINDIR)
$(INSTALL) -m 0755 $(PACKAGENAME) $(DESTDIR)/$(SBINDIR)
$(INSTALL) -d -m 0755 $(DESTDIR)/$(MANDIR)/man1
$(INSTALL) -m 0644 $(PACKAGENAME).1 $(DESTDIR)/$(MANDIR)/man1
$(INSTALL) -d -m 0755 $(DESTDIR)/$(DATADIR)/$(PACKAGENAME)
$(INSTALL) -m 0644 $(DATAFILES) $(DESTDIR)/$(DATADIR)/$(PACKAGENAME)
make -C po install
install-gui: gui
$(INSTALL) -d -m 0755 $(DESTDIR)/$(SBINDIR)
$(INSTALL) -m 0755 gui/gtk-$(PACKAGENAME) $(DESTDIR)/$(SBINDIR)
$(INSTALL) -d -m 0755 $(DESTDIR)/$(DATADIR)/$(PACKAGENAME)/artwork
$(INSTALL) -d -m 0755 $(DESTDIR)/$(DATADIR)/$(PACKAGENAME)/ui
$(INSTALL) -m 0644 gui/*.ui $(DESTDIR)/$(DATADIR)/$(PACKAGENAME)/ui
$(INSTALL) -m 0644 gui/artwork/*.svg $(DESTDIR)/$(DATADIR)/$(PACKAGENAME)/artwork
clean:
rm -f $(PACKAGENAME).o $(PACKAGENAME) $(PACKAGENAME)-static $(PACKAGENAME)-compressed
rm -f $(addsuffix .gz,$(DATAFILES))
make -C core clean
make -C gui clean
depend:
@makedepend -Y $(SRCS) 2> /dev/null > /dev/null
# DO NOT DELETE

80
src/core/Makefile Normal file
View File

@ -0,0 +1,80 @@
PACKAGENAME?=lshw
CXX?=$(CROSS_COMPILE)c++
INCLUDES=
DEFINES=-DPREFIX=\"$(PREFIX)\" -DSBINDIR=\"$(SBINDIR)\" -DMANDIR=\"$(MANDIR)\" -DDATADIR=\"$(DATADIR)\"
CXXFLAGS?=-g -Wall $(INCLUDES) $(DEFINES) $(RPM_OPT_FLAGS)
LDFLAGS=
LDSTATIC=
LIBS=
OBJS = hw.o main.o print.o mem.o dmi.o device-tree.o cpuinfo.o osutils.o pci.o version.o cpuid.o ide.o cdrom.o pcmcia-legacy.o scsi.o s390.o disk.o spd.o network.o isapnp.o pnp.o fb.o options.o usb.o sysfs.o display.o heuristics.o parisc.o cpufreq.o partitions.o blockio.o lvm.o ideraid.o pcmcia.o volumes.o mounts.o smp.o abi.o jedec.o dump.o fat.o virtio.o vio.o
ifeq ($(SQLITE), 1)
OBJS+= db.o
endif
SRCS = $(OBJS:.o=.cc)
all: lib$(PACKAGENAME).a
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $@
lib$(PACKAGENAME).a: $(OBJS)
$(AR) rs $@ $^
install: all
clean:
rm -f $(OBJS) lib$(PACKAGENAME).a
depend:
@makedepend -Y $(SRCS) 2> /dev/null > /dev/null
# DO NOT DELETE
hw.o: hw.h osutils.h version.h config.h options.h heuristics.h
main.o: hw.h print.h version.h options.h mem.h dmi.h cpuinfo.h cpuid.h
main.o: device-tree.h pci.h pcmcia.h pcmcia-legacy.h ide.h scsi.h spd.h
main.o: network.h isapnp.h fb.h usb.h sysfs.h display.h parisc.h cpufreq.h
main.o: ideraid.h mounts.h smp.h abi.h s390.h virtio.h pnp.h vio.h
print.o: print.h hw.h options.h version.h osutils.h config.h
mem.o: version.h config.h mem.h hw.h sysfs.h
dmi.o: version.h config.h dmi.h hw.h osutils.h
device-tree.o: version.h device-tree.h hw.h osutils.h
cpuinfo.o: version.h cpuinfo.h hw.h osutils.h
osutils.o: version.h osutils.h
pci.o: version.h config.h pci.h hw.h osutils.h options.h
version.o: version.h config.h
cpuid.o: version.h cpuid.h hw.h
ide.o: version.h cpuinfo.h hw.h osutils.h cdrom.h disk.h heuristics.h
cdrom.o: version.h cdrom.h hw.h partitions.h
pcmcia-legacy.o: version.h pcmcia-legacy.h hw.h osutils.h
scsi.o: version.h mem.h hw.h cdrom.h disk.h osutils.h heuristics.h sysfs.h
disk.o: version.h disk.h hw.h osutils.h heuristics.h partitions.h
spd.o: version.h spd.h hw.h osutils.h
network.o: version.h config.h network.h hw.h osutils.h sysfs.h options.h
network.o: heuristics.h
isapnp.o: version.h isapnp.h hw.h pnp.h
pnp.o: version.h pnp.h hw.h sysfs.h osutils.h
fb.o: version.h fb.h hw.h
options.o: version.h options.h osutils.h
usb.o: version.h usb.h hw.h osutils.h heuristics.h options.h
sysfs.o: version.h sysfs.h hw.h osutils.h
display.o: display.h hw.h
heuristics.o: version.h sysfs.h hw.h osutils.h
parisc.o: version.h device-tree.h hw.h osutils.h heuristics.h
cpufreq.o: version.h hw.h osutils.h
partitions.o: version.h partitions.h hw.h blockio.h lvm.h volumes.h osutils.h
blockio.o: version.h blockio.h osutils.h
lvm.o: version.h lvm.h hw.h blockio.h osutils.h
ideraid.o: version.h cpuinfo.h hw.h osutils.h cdrom.h disk.h heuristics.h
pcmcia.o: version.h pcmcia.h hw.h osutils.h sysfs.h
volumes.o: version.h volumes.h hw.h blockio.h lvm.h osutils.h
mounts.o: version.h mounts.h hw.h osutils.h
smp.o: version.h smp.h hw.h osutils.h
abi.o: version.h abi.h hw.h osutils.h
jedec.o: jedec.h
s390.o: hw.h sysfs.h disk.h s390.h
virtio.o: version.h hw.h sysfs.h disk.h virtio.h
vio.o: version.h hw.h sysfs.h vio.h

55
src/core/abi.cc Normal file
View File

@ -0,0 +1,55 @@
/*
* abi.cc
*
*
*/
#include "version.h"
#include "config.h"
#include "abi.h"
#include "osutils.h"
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <limits.h>
__ID("@(#) $Id: mem.cc 1352 2006-05-27 23:54:13Z ezix $");
#define PROC_SYS "/proc/sys"
bool scan_abi(hwNode & system)
{
// are we compiled as 32- or 64-bit process ?
long sc = sysconf(LONG_BIT);
if(sc==-1) sc = sysconf(_SC_LONG_BIT);
if(sc!=-1) system.setWidth(sc);
pushd(PROC_SYS);
if(exists("kernel/vsyscall64"))
{
system.addCapability("vsyscall64");
system.setWidth(64);
}
if(chdir("abi") == 0)
{
int i,n;
struct dirent **namelist;
n = scandir(".", &namelist, selectfile, alphasort);
for(i=0; i<n; i++)
{
system.addCapability(namelist[i]->d_name);
free(namelist[i]);
}
if(namelist)
free(namelist);
}
popd();
system.describeCapability("vsyscall32", _("32-bit processes"));
system.describeCapability("vsyscall64", _("64-bit processes"));
return true;
}

7
src/core/abi.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _ABI_H_
#define _ABI_H_
#include "hw.h"
bool scan_abi(hwNode & n);
#endif

44
src/core/blockio.cc Normal file
View File

@ -0,0 +1,44 @@
/*
* blockio.cc
*
*
*/
#define _LARGEFILE_SOURCE
#define _FILE_OFFSET_BITS 64
#include "version.h"
#include "blockio.h"
#include "osutils.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
__ID("@(#) $Id$");
ssize_t readlogicalblocks(source & s,
void * buffer,
long long pos, long long count)
{
long long result = 0;
memset(buffer, 0, count*s.blocksize);
/* attempt to read past the end of the section */
if((s.size>0) && ((pos+count)*s.blocksize>s.size)) return 0;
result = lseek(s.fd, s.offset + pos*s.blocksize, SEEK_SET);
if(result == -1) return 0;
result = read(s.fd, buffer, count*s.blocksize);
if(result!=count*s.blocksize)
return 0;
else
return count;
}

22
src/core/blockio.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _BLOCKIO_H_
#define _BLOCKIO_H_
#include <stdint.h>
#include <unistd.h>
#include <string>
#define BLOCKSIZE 512
struct source
{
std::string diskname;
int fd;
ssize_t blocksize;
long long offset;
long long size;
};
ssize_t readlogicalblocks(source & s,
void * buffer,
long long pos, long long count);
#endif

469
src/core/burner.cc Normal file
View File

@ -0,0 +1,469 @@
/*
* burner.cc
*
* This file was originally part of dvd+rw-tools by Andy Polyakov but it went
* through severe modifications. Don't blame Andy for any bug.
*
* Original notice below.
*
* This is part of dvd+rw-tools by Andy Polyakov <appro@fy.chalmers.se>
*
* Use-it-on-your-own-risk, GPL bless...
*
* For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/
*/
#define CREAM_ON_ERRNO(s) do { \
switch ((s)[2]&0x0F) \
{ \
case 2: if ((s)[12]==4) errno=EAGAIN; break; \
case 5: errno=EINVAL; \
if ((s)[13]==0) \
{ \
if ((s)[12]==0x21) errno=ENOSPC; \
else if ((s)[12]==0x20) errno=ENODEV; \
} \
break; \
} \
} while(0)
#define ERRCODE(s) ((((s)[2]&0x0F)<<16)|((s)[12]<<8)|((s)[13]))
#define SK(errcode) (((errcode)>>16)&0xF)
#define ASC(errcode) (((errcode)>>8)&0xFF)
#define ASCQ(errcode) ((errcode)&0xFF)
#ifndef _LARGEFILE_SOURCE
#define _LARGEFILE_SOURCE
#endif
#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>
#include <errno.h>
#include <string.h>
#include <mntent.h>
#include <sys/wait.h>
#include <sys/utsname.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#include <poll.h>
#include <sys/time.h>
#include "version.h"
#include "burner.h"
typedef enum
{
NONE = CGC_DATA_NONE, // 3
READ = CGC_DATA_READ, // 2
WRITE = CGC_DATA_WRITE // 1
} Direction;
typedef struct ScsiCommand ScsiCommand;
struct ScsiCommand
{
int fd;
int autoclose;
char *filename;
struct cdrom_generic_command cgc;
union
{
struct request_sense s;
unsigned char u[18];
} _sense;
struct sg_io_hdr sg_io;
};
#define DIRECTION(i) (Dir_xlate[i]);
/* 1,CGC_DATA_WRITE
* 2,CGC_DATA_READ
* 3,CGC_DATA_NONE
*/
const int Dir_xlate[4] =
{
0, // implementation-dependent...
SG_DXFER_TO_DEV, // 1,CGC_DATA_WRITE
SG_DXFER_FROM_DEV, // 2,CGC_DATA_READ
SG_DXFER_NONE // 3,CGC_DATA_NONE
};
static ScsiCommand * scsi_command_new (void)
{
ScsiCommand *cmd;
cmd = (ScsiCommand *) malloc (sizeof (ScsiCommand));
memset (cmd, 0, sizeof (ScsiCommand));
cmd->fd = -1;
cmd->filename = NULL;
cmd->autoclose = 1;
return cmd;
}
static ScsiCommand * scsi_command_new_from_fd (int f)
{
ScsiCommand *cmd;
cmd = scsi_command_new ();
cmd->fd = f;
cmd->autoclose = 0;
return cmd;
}
static void scsi_command_free (ScsiCommand * cmd)
{
if (cmd->fd >= 0 && cmd->autoclose)
{
close (cmd->fd);
cmd->fd = -1;
}
if (cmd->filename)
{
free (cmd->filename);
cmd->filename = NULL;
}
free (cmd);
}
static int scsi_command_transport (ScsiCommand * cmd, Direction dir, void *buf,
size_t sz)
{
int ret = 0;
cmd->sg_io.dxferp = buf;
cmd->sg_io.dxfer_len = sz;
cmd->sg_io.dxfer_direction = DIRECTION (dir);
if (ioctl (cmd->fd, SG_IO, &cmd->sg_io))
return -1;
if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK)
{
errno = EIO;
ret = -1;
if (cmd->sg_io.masked_status & CHECK_CONDITION)
{
CREAM_ON_ERRNO (cmd->sg_io.sbp);
ret = ERRCODE (cmd->sg_io.sbp);
if (ret == 0)
ret = -1;
}
}
return ret;
}
static void scsi_command_init (ScsiCommand * cmd, size_t i, int arg)
{
if (i == 0)
{
memset (&cmd->cgc, 0, sizeof (cmd->cgc));
memset (&cmd->_sense, 0, sizeof (cmd->_sense));
cmd->cgc.quiet = 1;
cmd->cgc.sense = &cmd->_sense.s;
memset (&cmd->sg_io, 0, sizeof (cmd->sg_io));
cmd->sg_io.interface_id = 'S';
cmd->sg_io.mx_sb_len = sizeof (cmd->_sense);
cmd->sg_io.cmdp = cmd->cgc.cmd;
cmd->sg_io.sbp = cmd->_sense.u;
cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO;
}
cmd->sg_io.cmd_len = i + 1;
cmd->cgc.cmd[i] = arg;
}
int get_dvd_r_rw_profile (int fd)
{
ScsiCommand *cmd;
int retval = -1;
unsigned char page[20];
unsigned char *list;
int i, len;
cmd = scsi_command_new_from_fd (fd);
scsi_command_init (cmd, 0, 0x46);
scsi_command_init (cmd, 1, 2);
scsi_command_init (cmd, 8, 8);
scsi_command_init (cmd, 9, 0);
if (scsi_command_transport (cmd, READ, page, 8))
{
/* GET CONFIGURATION failed */
scsi_command_free (cmd);
return -1;
}
/* See if it's 2 gen drive by checking if DVD+R profile is an option */
len = 4 + (page[0] << 24 | page[1] << 16 | page[2] << 8 | page[3]);
if (len > 264)
{
scsi_command_free (cmd);
/* insane profile list length */
return -1;
}
list = (unsigned char *) malloc (len);
scsi_command_init (cmd, 0, 0x46);
scsi_command_init (cmd, 1, 2);
scsi_command_init (cmd, 7, len >> 8);
scsi_command_init (cmd, 8, len);
scsi_command_init (cmd, 9, 0);
if (scsi_command_transport (cmd, READ, list, len))
{
/* GET CONFIGURATION failed */
scsi_command_free (cmd);
free (list);
return -1;
}
for (i = 12; i < list[11]; i += 4)
{
int profile = (list[i] << 8 | list[i + 1]);
/* 0x1B: DVD+R
* 0x1A: DVD+RW */
if (profile == 0x1B)
{
if (retval == 1)
retval = 2;
else
retval = 0;
}
else if (profile == 0x1A)
{
if (retval == 0)
retval = 2;
else
retval = 1;
}
}
scsi_command_free (cmd);
free (list);
return retval;
}
static unsigned char * pull_page2a_from_fd (int fd)
{
ScsiCommand *cmd;
unsigned char header[12], *page2A;
unsigned int len, bdlen;
cmd = scsi_command_new_from_fd (fd);
scsi_command_init (cmd, 0, 0x5A); /* MODE SENSE */
scsi_command_init (cmd, 1, 0x08); /* Disable Block Descriptors */
scsi_command_init (cmd, 2, 0x2A); /* Capabilities and Mechanical Status */
scsi_command_init (cmd, 8, sizeof (header)); /* header only to start with */
scsi_command_init (cmd, 9, 0);
if (scsi_command_transport (cmd, READ, header, sizeof (header)))
{
/* MODE SENSE failed */
scsi_command_free (cmd);
return NULL;
}
len = (header[0] << 8 | header[1]) + 2;
bdlen = header[6] << 8 | header[7];
/* should never happen as we set "DBD" above */
if (bdlen)
{
if (len < (8 + bdlen + 30))
{
/* LUN impossible to bear with */
scsi_command_free (cmd);
return NULL;
}
}
else if (len < (8 + 2 + (unsigned int) header[9]))
{
/* SANYO does this. */
len = 8 + 2 + header[9];
}
page2A = (unsigned char *) malloc (len);
if (page2A == NULL)
{
/* ENOMEM */
scsi_command_free (cmd);
return NULL;
}
scsi_command_init (cmd, 0, 0x5A); /* MODE SENSE */
scsi_command_init (cmd, 1, 0x08); /* Disable Block Descriptors */
scsi_command_init (cmd, 2, 0x2A); /* Capabilities and Mechanical Status */
scsi_command_init (cmd, 7, len >> 8);
scsi_command_init (cmd, 8, len); /* Real length */
scsi_command_init (cmd, 9, 0);
if (scsi_command_transport (cmd, READ, page2A, len))
{
/* MODE SENSE failed */
scsi_command_free (cmd);
free (page2A);
return NULL;
}
scsi_command_free (cmd);
len -= 2;
/* paranoia */
if (len < ((unsigned int) page2A[0] << 8 | page2A[1]))
{
page2A[0] = len >> 8;
page2A[1] = len;
}
return page2A;
}
static int get_read_write_speed (int fd, int *read_speed, int *write_speed)
{
unsigned char *page2A;
int len, hlen;
unsigned char *p;
*read_speed = 0;
*write_speed = 0;
page2A = pull_page2a_from_fd (fd);
if (page2A == NULL)
{
printf ("Failed to get Page 2A\n");
/* Failed to get Page 2A */
return -1;
}
len = (page2A[0] << 8 | page2A[1]) + 2;
hlen = 8 + (page2A[6] << 8 | page2A[7]);
p = page2A + hlen;
/* Values guessed from the cd_mode_page_2A struct
* in cdrecord's libscg/scg/scsireg.h */
if (len < (hlen + 30) || p[1] < (30 - 2))
{
/* no MMC-3 "Current Write Speed" present,
* try to use the MMC-2 one */
if (len < (hlen + 20) || p[1] < (20 - 2))
*write_speed = 0;
else
*write_speed = p[18] << 8 | p[19];
}
else
{
*write_speed = p[28] << 8 | p[29];
}
if (len >= hlen+9)
*read_speed = p[8] << 8 | p[9];
else
*read_speed = 0;
free (page2A);
return 0;
}
static int get_disc_type (int fd)
{
ScsiCommand *cmd;
int retval = -1;
unsigned char header[8];
cmd = scsi_command_new_from_fd (fd);
scsi_command_init (cmd, 0, 0x46);
scsi_command_init (cmd, 1, 1);
scsi_command_init (cmd, 8, 8);
scsi_command_init (cmd, 9, 0);
if (scsi_command_transport (cmd, READ, header, 8))
{
/* GET CONFIGURATION failed */
scsi_command_free (cmd);
return -1;
}
retval = (header[6]<<8)|(header[7]);
scsi_command_free (cmd);
return retval;
}
static int disc_is_appendable (int fd)
{
ScsiCommand *cmd;
int retval = -1;
unsigned char header[32];
cmd = scsi_command_new_from_fd (fd);
/* see section 5.19 of MMC-3 from http://www.t10.org/drafts.htm#mmc3 */
scsi_command_init (cmd, 0, 0x51); /* READ_DISC_INFORMATION */
scsi_command_init (cmd, 8, 32);
scsi_command_init (cmd, 9, 0);
if (scsi_command_transport (cmd, READ, header, 32))
{
/* READ_DISC_INFORMATION failed */
scsi_command_free (cmd);
return 0;
}
retval = ((header[2]&0x03) == 0x01);
scsi_command_free (cmd);
return retval;
}
static int disc_is_rewritable (int fd)
{
ScsiCommand *cmd;
int retval = -1;
unsigned char header[32];
cmd = scsi_command_new_from_fd (fd);
/* see section 5.19 of MMC-3 from http://www.t10.org/drafts.htm#mmc3 */
scsi_command_init (cmd, 0, 0x51); /* READ_DISC_INFORMATION */
scsi_command_init (cmd, 8, 32);
scsi_command_init (cmd, 9, 0);
if (scsi_command_transport (cmd, READ, header, 32))
{
/* READ_DISC_INFORMATION failed */
scsi_command_free (cmd);
return 0;
}
retval = ((header[2]&0x10) != 0);
scsi_command_free (cmd);
return retval;
}

7
src/core/burner.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _BURNER_H_
#define _BURNER_H_
#include "hw.h"
bool scan_burner(hwNode & n);
#endif

122
src/core/cdrom.cc Normal file
View File

@ -0,0 +1,122 @@
/*
* cdrom.cc
*
* This scan reports optical media-specific capabilities:
* - audio CD playback
* - CD-R burning
* - CD-RW burning
* - DVD reading
* - DVD-R burning
* - DVD-RAM burning
*
* NOTE: DVD+R/RW are not covered by the ioctls used in this code and, therefore,
* not reported.
*
*
*/
#include "version.h"
#include "cdrom.h"
#include "partitions.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <linux/cdrom.h>
__ID("@(#) $Id$");
#ifndef CDC_CD_R
#define CDC_CD_R 0x2000
#endif
#ifndef CDC_CD_RW
#define CDC_CD_RW 0x4000
#endif
#ifndef CDC_DVD
#define CDC_DVD 0x8000
#endif
#ifndef CDC_DVD_R
#define CDC_DVD_R 0x10000
#endif
#ifndef CDC_DVD_RAM
#define CDC_DVD_RAM 0x20000
#endif
bool scan_cdrom(hwNode & n)
{
if (n.getLogicalName() == "")
return false;
n.addHint("icon", string("cd"));
int fd = open(n.getLogicalName().c_str(), O_RDONLY | O_NONBLOCK);
if (fd < 0)
return false;
int status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
if (status < 0)
{
close(fd);
return false;
}
int capabilities = ioctl(fd, CDROM_GET_CAPABILITY);
if (capabilities < 0)
{
close(fd);
return false;
}
if (capabilities & CDC_PLAY_AUDIO)
n.addCapability("audio", "Audio CD playback");
if (capabilities & CDC_CD_R)
{
n.addCapability("cd-r", "CD-R burning");
n.setDescription("CD-R writer");
}
if (capabilities & CDC_CD_RW)
{
n.addCapability("cd-rw", "CD-RW burning");
n.setDescription("CD-R/CD-RW writer");
}
if (capabilities & CDC_DVD)
{
n.addCapability("dvd", "DVD playback");
n.setDescription("DVD reader");
}
if (capabilities & CDC_DVD_R)
{
n.addCapability("dvd-r", "DVD-R burning");
n.setDescription("DVD writer");
}
if (capabilities & CDC_DVD_RAM)
{
n.addCapability("dvd-ram", "DVD-RAM burning");
n.setDescription("DVD-RAM writer");
}
switch(ioctl(fd, CDROM_DRIVE_STATUS, 0))
{
case CDS_NO_INFO:
case CDS_NO_DISC:
n.setConfig("status", "nodisc");
break;
case CDS_TRAY_OPEN:
n.setConfig("status", "open");
break;
case CDS_DRIVE_NOT_READY:
n.setConfig("status", "busy");
break;
case CDS_DISC_OK:
n.setConfig("status", "ready");
scan_partitions(n);
break;
}
close(fd);
return true;
}

7
src/core/cdrom.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _CDROM_H_
#define _CDROM_H_
#include "hw.h"
bool scan_cdrom(hwNode & n);
#endif

39
src/core/config.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#ifdef NONLS
#define _(String) (String)
#define N_(String) String
#define textdomain(Domain)
#define bindtextdomain(Package, Directory)
#else
#include <libintl.h>
#define _(String) gettext (String)
#define gettext_noop(String) String
#define N_(String) gettext_noop (String)
#endif
#ifndef PACKAGE
#define PACKAGE "lshw"
#endif
#ifndef PREFIX
#define PREFIX "/usr"
#endif
#ifndef SBINDIR
#define SBINDIR PREFIX"/sbin"
#endif
#ifndef DATADIR
#define DATADIR PREFIX"/share/lshw"
#endif
#ifndef MANDIR
#define MANDIR PREFIX"/share/man"
#endif
#ifndef LOCALEDIR
#define LOCALEDIR PREFIX"/share/locale"
#endif
#endif

78
src/core/cpufreq.cc Normal file
View File

@ -0,0 +1,78 @@
/*
* cpufreq.cc
*
* This module scans /sys for CPUfreq info
*
*
*
*/
#include "version.h"
#include "hw.h"
#include "osutils.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
__ID("@(#) $Id$");
#define DEVICESCPUFREQ "/sys/devices/system/cpu/cpu%d/cpufreq/"
static long get_long(const string & path)
{
long result = 0;
FILE * in = fopen(path.c_str(), "r");
if (in)
{
if(fscanf(in, "%ld", &result) != 1)
result = 0;
fclose(in);
}
return result;
}
static string cpubusinfo(int cpu)
{
char buffer[10];
snprintf(buffer, sizeof(buffer), "cpu@%d", cpu);
return string(buffer);
}
bool scan_cpufreq(hwNode & node)
{
char buffer[PATH_MAX];
unsigned i =0;
while(hwNode * cpu = node.findChildByBusInfo(cpubusinfo(i)))
{
snprintf(buffer, sizeof(buffer), DEVICESCPUFREQ, i);
if(exists(buffer))
{
unsigned long long max, cur;
pushd(buffer);
// in Hz
max = 1000*(unsigned long long)get_long("cpuinfo_max_freq");
// in Hz
cur = 1000*(unsigned long long)get_long("scaling_cur_freq");
cpu->addCapability("cpufreq", "CPU Frequency scaling");
if(cur) cpu->setSize(cur);
if(max>cpu->getCapacity()) cpu->setCapacity(max);
popd();
}
i++;
}
return true;
}

7
src/core/cpufreq.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _CPUFREQ_H_
#define _CPUFREQ_H_
#include "hw.h"
bool scan_cpufreq(hwNode & n);
#endif

761
src/core/cpuid.cc Normal file
View File

@ -0,0 +1,761 @@
#include "version.h"
#include "config.h"
#include "cpuid.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
__ID("@(#) $Id$");
#if defined(__i386__) || defined(__alpha__)
static hwNode *getcache(hwNode & node,
int n = 0)
{
char cachename[10];
hwNode *cache = NULL;
if (n < 0)
n = 0;
snprintf(cachename, sizeof(cachename), "cache:%d", n);
cache = node.getChild(string(cachename));
if (cache)
return cache;
// "cache:0" is equivalent to "cache" if we only have L1 cache
if ((n == 0) && (node.countChildren(hw::memory) <= 1))
cache = node.getChild(string("cache"));
if (cache)
return cache;
else
return NULL;
}
static hwNode *getcpu(hwNode & node,
int n = 0)
{
char cpubusinfo[10];
hwNode *cpu = NULL;
if (n < 0)
n = 0;
snprintf(cpubusinfo, sizeof(cpubusinfo), "cpu@%d", n);
cpu = node.findChildByBusInfo(cpubusinfo);
if (cpu)
return cpu;
if (n > 0)
return NULL;
hwNode *core = node.getChild("core");
if (core)
{
hwNode cpu("cpu", hw::processor);
cpu.setBusInfo(cpubusinfo);
cpu.addHint("icon", string("cpu"));
cpu.claim();
return core->addChild(cpu);
}
else
return NULL;
}
#endif // __i386__ || __alpha__
#ifdef __i386__
/* %ebx may be the PIC register. */
#define cpuid_up(in,a,b,c,d)\
__asm__ ("xchgl\t%%ebx, %1\n\t" \
"cpuid\n\t" \
"xchgl\t%%ebx, %1\n\t" \
: "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
: "0" (in))
static void cpuid(int cpunumber,
unsigned long idx,
unsigned long &eax,
unsigned long &ebx,
unsigned long &ecx,
unsigned long &edx)
{
char cpuname[50];
int fd = -1;
unsigned char buffer[16];
snprintf(cpuname, sizeof(cpuname), "/dev/cpu/%d/cpuid", cpunumber);
fd = open(cpuname, O_RDONLY);
if (fd >= 0)
{
lseek(fd, idx, SEEK_CUR);
memset(buffer, 0, sizeof(buffer));
if(read(fd, buffer, sizeof(buffer)) == sizeof(buffer))
{
eax = (*(unsigned long *) buffer);
ebx = (*(unsigned long *) (buffer + 4));
ecx = (*(unsigned long *) (buffer + 8));
edx = (*(unsigned long *) (buffer + 12));
}
close(fd);
}
else
cpuid_up(idx, eax, ebx, ecx, edx);
}
/* Decode Intel TLB and cache info descriptors */
static void decode_intel_tlb(int x,
long long &l1cache,
long long &l2cache)
{
x &= 0xff;
switch (x)
{
case 0:
break;
case 0x1:
// Instruction TLB: 4KB pages, 4-way set assoc, 32 entries
break;
case 0x2:
// Instruction TLB: 4MB pages, 4-way set assoc, 2 entries
break;
case 0x3:
// Data TLB: 4KB pages, 4-way set assoc, 64 entries
break;
case 0x4:
// Data TLB: 4MB pages, 4-way set assoc, 8 entries
break;
case 0x6:
// 1st-level instruction cache: 8KB, 4-way set assoc, 32 byte line size
l1cache += 8 * 1024;
break;
case 0x8:
// 1st-level instruction cache: 16KB, 4-way set assoc, 32 byte line size
l1cache += 16 * 1024;
break;
case 0xa:
// 1st-level data cache: 8KB, 2-way set assoc, 32 byte line size
l1cache += 8 * 1024;
break;
case 0xc:
// 1st-level data cache: 16KB, 4-way set assoc, 32 byte line size
l1cache += 16 * 1024;
break;
case 0x40:
// No 2nd-level cache, or if 2nd-level cache exists, no 3rd-level cache
break;
case 0x41:
// 2nd-level cache: 128KB, 4-way set assoc, 32 byte line size
l2cache = 128 * 1024;
break;
case 0x42:
// 2nd-level cache: 256KB, 4-way set assoc, 32 byte line size
l2cache = 256 * 1024;
break;
case 0x43:
// 2nd-level cache: 512KB, 4-way set assoc, 32 byte line size
l2cache = 512 * 1024;
break;
case 0x44:
// 2nd-level cache: 1MB, 4-way set assoc, 32 byte line size
l2cache = 1024 * 1024;
break;
case 0x45:
// 2nd-level cache: 2MB, 4-way set assoc, 32 byte line size
l2cache = 2 * 1024 * 1024;
break;
case 0x50:
// Instruction TLB: 4KB and 2MB or 4MB pages, 64 entries
break;
case 0x51:
// Instruction TLB: 4KB and 2MB or 4MB pages, 128 entries
break;
case 0x52:
// Instruction TLB: 4KB and 2MB or 4MB pages, 256 entries
break;
case 0x5b:
// Data TLB: 4KB and 4MB pages, 64 entries
break;
case 0x5c:
// Data TLB: 4KB and 4MB pages, 128 entries
break;
case 0x5d:
// Data TLB: 4KB and 4MB pages, 256 entries
break;
case 0x66:
// 1st-level data cache: 8KB, 4-way set assoc, 64 byte line size
l1cache += 8 * 1024;
break;
case 0x67:
// 1st-level data cache: 16KB, 4-way set assoc, 64 byte line size
l1cache += 16 * 1024;
break;
case 0x68:
// 1st-level data cache: 32KB, 4-way set assoc, 64 byte line size
l1cache += 32 * 1024;
break;
case 0x70:
// Trace cache: 12K-micro-op, 4-way set assoc
break;
case 0x71:
// Trace cache: 16K-micro-op, 4-way set assoc
break;
case 0x72:
// Trace cache: 32K-micro-op, 4-way set assoc
break;
case 0x79:
// 2nd-level cache: 128KB, 8-way set assoc, sectored, 64 byte line size
l2cache += 128 * 1024;
break;
case 0x7a:
// 2nd-level cache: 256KB, 8-way set assoc, sectored, 64 byte line size
l2cache += 256 * 1024;
break;
case 0x7b:
// 2nd-level cache: 512KB, 8-way set assoc, sectored, 64 byte line size
l2cache += 512 * 1024;
break;
case 0x7c:
// 2nd-level cache: 1MB, 8-way set assoc, sectored, 64 byte line size
l2cache += 1024 * 1024;
break;
case 0x82:
// 2nd-level cache: 256KB, 8-way set assoc, 32 byte line size
l2cache += 256 * 1024;
break;
case 0x83:
// 2nd-level cache: 512KB, 8-way set assoc 32 byte line size
l2cache += 512 * 1024;
break;
case 0x84:
// 2nd-level cache: 1MB, 8-way set assoc, 32 byte line size
l2cache += 1024 * 1024;
break;
case 0x85:
// 2nd-level cache: 2MB, 8-way set assoc, 32 byte line size
l2cache += 2 * 1024 * 1024;
break;
default:
// unknown TLB/cache descriptor
break;
}
}
static bool dointel(unsigned long maxi,
hwNode * cpu,
int cpunumber = 0)
{
char buffer[1024];
unsigned long signature = 0, flags = 0, bflags = 0, eax = 0, ebx = 0, ecx = 0, edx = 0, unused = 0;
int stepping, model, family;
if (!cpu)
return false;
cpu->addHint("logo", string("intel"));
if (maxi >= 1)
{
cpuid(cpunumber, 1, eax, ebx, ecx, edx);
signature = eax;
stepping = eax & 0xf;
model = (eax >> 4) & 0xf;
family = (eax >> 8) & 0xf;
flags = edx;
bflags = ebx;
snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping);
cpu->setVersion(buffer);
if(ecx & (1 << 5))
cpu->addCapability("vmx", _("CPU virtualization (Vanderpool)"));
/* Hyper-Threading Technology */
if (flags & (1 << 28))
{
char buff[20];
unsigned int nr_ht = (bflags >> 16) & 0xFF;
unsigned int phys_id = (bflags >> 24) & 0xFF;
snprintf(buff, sizeof(buff), "%d", phys_id);
cpu->setConfig("id", buff);
hwNode logicalcpu("logicalcpu", hw::processor);
logicalcpu.setDescription(_("Logical CPU"));
logicalcpu.addCapability("logical", _("Logical CPU"));
logicalcpu.setWidth(cpu->getWidth());
logicalcpu.claim();
cpu->addCapability("ht", _("HyperThreading"));
if(nr_ht>1)
for(unsigned int i=0; i< nr_ht; i++)
{
snprintf(buff, sizeof(buff), "CPU:%d.%d", phys_id, i);
logicalcpu.setHandle(buff);
logicalcpu.setPhysId(phys_id, i+1);
cpu->addChild(logicalcpu);
cpu->claim();
}
}
}
if (maxi >= 2)
{
/*
* Decode TLB and cache info
*/
int ntlb, i;
long long l1cache = 0, l2cache = 0;
ntlb = 255;
for (i = 0; i < ntlb; i++)
{
cpuid(cpunumber, 2, eax, ebx, ecx, edx);
ntlb = eax & 0xff;
decode_intel_tlb(eax >> 8, l1cache, l2cache);
decode_intel_tlb(eax >> 16, l1cache, l2cache);
decode_intel_tlb(eax >> 24, l1cache, l2cache);
if ((ebx & 0x80000000) == 0)
{
decode_intel_tlb(ebx, l1cache, l2cache);
decode_intel_tlb(ebx >> 8, l1cache, l2cache);
decode_intel_tlb(ebx >> 16, l1cache, l2cache);
decode_intel_tlb(ebx >> 24, l1cache, l2cache);
}
if ((ecx & 0x80000000) == 0)
{
decode_intel_tlb(ecx, l1cache, l2cache);
decode_intel_tlb(ecx >> 8, l1cache, l2cache);
decode_intel_tlb(ecx >> 16, l1cache, l2cache);
decode_intel_tlb(ecx >> 24, l1cache, l2cache);
}
if ((edx & 0x80000000) == 0)
{
decode_intel_tlb(edx, l1cache, l2cache);
decode_intel_tlb(edx >> 8, l1cache, l2cache);
decode_intel_tlb(edx >> 16, l1cache, l2cache);
decode_intel_tlb(edx >> 24, l1cache, l2cache);
}
}
if (l1cache != 0)
{
hwNode *l1 = getcache(*cpu, 0);
hwNode *l2 = getcache(*cpu, 1);
if (l1)
{
l1->setSize(l1cache);
if (l1->getDescription() == "")
l1->setDescription(_("L1 cache"));
}
else
{
hwNode cache("cache",
hw::memory);
cache.setSize(l1cache);
cache.setDescription(_("L1 cache"));
cpu->addChild(cache);
}
if (l2cache != 0)
{
if (l2 && (l2cache != 0))
{
l2->setSize(l2cache);
if (l2->getDescription() == "")
l2->setDescription(_("L2 cache"));
}
else
{
hwNode cache("cache",
hw::memory);
cache.setSize(l2cache);
cache.setDescription(_("L2 cache"));
cpu->addChild(cache);
}
}
}
}
if (maxi >= 3)
{
cpuid(cpunumber, 3, unused, unused, ecx, edx);
snprintf(buffer, sizeof(buffer),
"%04lX-%04lX-%04lX-%04lX-%04lX-%04lX",
signature >> 16,
signature & 0xffff,
edx >> 16, edx & 0xffff, ecx >> 16, ecx & 0xffff);
cpu->setSerial(buffer);
}
else
cpu->setSerial("");
return true;
}
static bool doamd(unsigned long maxi,
hwNode * cpu,
int cpunumber = 0)
{
unsigned long maxei = 0, eax, ebx, ecx, edx;
long long l1cache = 0, l2cache = 0;
unsigned int family = 0, model = 0, stepping = 0;
char buffer[1024];
if (maxi < 1)
return false;
cpu->addHint("logo", string("amd"));
cpuid(cpunumber, 1, eax, ebx, ecx, edx);
stepping = eax & 0xf;
model = (eax >> 4) & 0xf;
family = (eax >> 8) & 0xf;
snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping);
cpu->setVersion(buffer);
cpuid(cpunumber, 0x80000000, maxei, ebx, ecx, edx);
if (maxei >= 0x80000005)
{
cpuid(cpunumber, 0x80000005, eax, ebx, ecx, edx);
l1cache = (ecx >> 24) * 1024; // data cache
l1cache += (edx >> 24) * 1024; // instruction cache
}
if (maxei >= 0x80000006)
{
cpuid(cpunumber, 0x80000006, eax, ebx, ecx, edx);
l2cache = (ecx >> 16) * 1024;
}
if (l1cache != 0)
{
hwNode *l1 = cpu->getChild("cache:0");
hwNode *l2 = cpu->getChild("cache:1");
if (l1)
l1->setSize(l1cache);
else
{
hwNode newl1("cache",
hw::memory);
newl1.setDescription(_("L1 cache"));
newl1.setSize(l1cache);
cpu->addChild(newl1);
}
if (l2 && l2cache)
l2->setSize(l2cache);
else
{
hwNode newl2("cache",
hw::memory);
newl2.setDescription(_("L2 cache"));
newl2.setSize(l2cache);
if (l2cache)
cpu->addChild(newl2);
}
}
return true;
}
static bool docyrix(unsigned long maxi,
hwNode * cpu,
int cpunumber = 0)
{
unsigned long eax, ebx, ecx, edx;
unsigned int family = 0, model = 0, stepping = 0;
char buffer[1024];
if (maxi < 1)
return false;
cpuid(cpunumber, 1, eax, ebx, ecx, edx);
stepping = eax & 0xf;
model = (eax >> 4) & 0xf;
family = (eax >> 8) & 0xf;
snprintf(buffer, sizeof(buffer), "%d.%d.%d", family, model, stepping);
cpu->setVersion(buffer);
return true;
}
static __inline__ bool flag_is_changeable_p(unsigned int flag)
{
unsigned int f1, f2;
__asm__ volatile ("pushfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"movl %0,%1\n\t"
"xorl %2,%0\n\t"
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t" "popl %0\n\t" "popfl\n\t":"=&r" (f1),
"=&r"(f2):"ir"(flag));
return ((f1 ^ f2) & flag) != 0;
}
static bool haveCPUID()
{
return flag_is_changeable_p(0x200000);
}
/*
* Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de>
* Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz>
*
*/
static __inline__ unsigned long long int rdtsc()
{
unsigned long long int x;
__asm__ volatile (".byte 0x0f, 0x31":"=A" (x));
return x;
}
static float estimate_MHz(int cpunum,
long sleeptime = 250000)
{
struct timezone tz;
struct timeval tvstart, tvstop;
unsigned long long int cycles[2]; /* gotta be 64 bit */
float microseconds; /* total time taken */
unsigned long eax, ebx, ecx, edx;
double freq = 1.0f;
/*
* Make sure we have a TSC (and hence RDTSC)
*/
cpuid(cpunum, 1, eax, ebx, ecx, edx);
if ((edx & (1 << 4)) == 0)
{
return 0; // can't estimate frequency
}
memset(&tz, 0, sizeof(tz));
/*
* get this function in cached memory
*/
gettimeofday(&tvstart, &tz);
cycles[0] = rdtsc();
gettimeofday(&tvstart, &tz);
/*
* we don't trust that this is any specific length of time
*/
usleep(sleeptime);
gettimeofday(&tvstop, &tz);
cycles[1] = rdtsc();
gettimeofday(&tvstop, &tz);
microseconds = (tvstop.tv_sec - tvstart.tv_sec) * 1000000 +
(tvstop.tv_usec - tvstart.tv_usec);
return (float) (cycles[1] - cycles[0]) / (microseconds / freq);
}
static float average_MHz(int cpunum,
int tries = 2)
{
float frequency = 0;
for (int i = 1; i <= tries; i++)
frequency += estimate_MHz(cpunum, i * 150000);
if (tries > 0)
return frequency / (float) tries;
else
return 0;
}
static long round_MHz(float fMHz)
{
long MHz = (long)fMHz;
if ((MHz % 50) > 15)
return ((MHz / 50) * 50) + 50;
else
return ((MHz / 50) * 50);
}
bool scan_cpuid(hwNode & n)
{
unsigned long maxi, ebx, ecx, edx;
hwNode *cpu = NULL;
int currentcpu = 0;
if (!haveCPUID())
return false;
while ((cpu = getcpu(n, currentcpu)))
{
cpu->claim(true); // claim the cpu and all its children
cpuid(currentcpu, 0, maxi, ebx, ecx, edx);
maxi &= 0xffff;
switch (ebx)
{
case 0x756e6547: /* Intel */
dointel(maxi, cpu, currentcpu);
break;
case 0x68747541: /* AMD */
doamd(maxi, cpu, currentcpu);
break;
case 0x69727943: /* Cyrix */
docyrix(maxi, cpu, currentcpu);
break;
default:
return false;
}
cpu->claim(true); // claim the cpu and all its children
if (cpu->getSize() == 0)
cpu->setSize((unsigned long long) (1000000uL * round_MHz(average_MHz(currentcpu))));
currentcpu++;
}
return true;
}
#else
#ifdef __alpha__
#define BWX (1 << 0)
#define FIX (1 << 1)
#define CIX (1 << 2)
#define MVI (1 << 8)
#define PAT (1 << 9)
#define PMI (1 << 12)
bool scan_cpuid(hwNode & n)
{
hwNode *cpu = NULL;
int currentcpu = 0;
unsigned long ver = 0, mask = 0;
while (cpu = getcpu(n, currentcpu))
{
asm("implver %0":"=r"(ver));
asm("amask %1, %0": "=r"(mask):"r"(-1));
cpu->setVendor("Digital Equipment Corporation");
cpu->setProduct("Alpha");
cpu->setWidth(64);
if ((~mask) & BWX)
cpu->addCapability("BWX");
if ((~mask) & FIX)
cpu->addCapability("FIX");
if ((~mask) & CIX)
cpu->addCapability("CIX");
if ((~mask) & MVI)
cpu->addCapability("MVI");
if ((~mask) & PAT)
cpu->addCapability("PAT");
if ((~mask) & PMI)
cpu->addCapability("PMI");
switch (ver)
{
case 0:
cpu->setVersion("EV4");
break;
case 1:
switch (~mask)
{
case 0:
cpu->setVersion("EV5");
break;
case BWX:
cpu->setVersion("EV56");
break;
case BWX | MVI:
cpu->setVersion("PCA56");
break;
default:
cpu->setVersion("EV5 unknown");
}
break;
case 2:
switch (~mask)
{
case BWX | FIX | MVI | PAT:
cpu->setVersion("EV6");
break;
case BWX | FIX | MVI | PAT | CIX:
cpu->setVersion("EV67");
break;
case BWX | FIX | MVI | PAT | CIX | PMI:
cpu->setVersion("EV68");
break;
default:
cpu->setVersion("EV6 unknown");
}
break;
case 3:
switch (~mask)
{
case BWX | FIX | MVI | PAT | CIX | PMI:
cpu->setVersion("EV7x");
break;
default:
cpu->setVersion("EV7 unknown");
}
break;
}
currentcpu++;
}
return true;
}
#else
bool scan_cpuid(hwNode & n)
{
return true;
}
#endif /* __alpha__ */
#endif /* __i386__ */

7
src/core/cpuid.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _CPUID_H_
#define _CPUID_H_
#include "hw.h"
bool scan_cpuid(hwNode & n);
#endif

672
src/core/cpuinfo.cc Normal file
View File

@ -0,0 +1,672 @@
#include "version.h"
#include "cpuinfo.h"
#include "osutils.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
__ID("@(#) $Id$");
static int currentcpu = 0;
static inline bool is_system_ppc_ibm(hwNode & node)
{
string desc = node.getDescription();
return (desc == "PowerNV" || desc == "pSeries Guest" || desc == "pSeries LPAR");
}
static hwNode *getcpu(hwNode & node,
int n = 0)
{
char cpubusinfo[10];
hwNode *cpu = NULL;
if (n < 0)
n = 0;
snprintf(cpubusinfo, sizeof(cpubusinfo), "cpu@%d", n);
cpu = node.findChildByBusInfo(cpubusinfo);
if (cpu)
{
cpu->addHint("icon", string("cpu"));
cpu->claim(true); // claim the cpu and all its children
if (!is_system_ppc_ibm(node))
cpu->enable(); // enable it
return cpu;
}
/*
* device-tree.cc creates all CPU nodes on Power Systems.
* Hence do not create new CPU nodes here.
*/
if (is_system_ppc_ibm(node))
return NULL;
hwNode *core = node.getChild("core");
if (core)
{
hwNode newcpu("cpu", hw::processor);
newcpu.setBusInfo(cpubusinfo);
newcpu.claim();
return core->addChild(newcpu);
}
else
return NULL;
}
static void cpuinfo_ppc_ibm(hwNode & node,
const string & description, const string & version)
{
hwNode *cpu = getcpu(node, currentcpu);
while (cpu)
{
cpu->setDescription(description);
cpu->setVersion(version);
cpu = getcpu(node, ++currentcpu);
}
}
static void cpuinfo_ppc(hwNode & node,
string id,
string value)
{
if (id == "processor")
currentcpu++;
hwNode *cpu = getcpu(node, currentcpu);
if (cpu)
{
cpu->addHint("logo", string("powerpc"));
cpu->claim(true);
if (id == "revision")
cpu->setVersion(value);
if (id == "cpu")
cpu->setProduct(value);
if (id == "clock")
{
double frequency = 0.0;
frequency = atof(value.c_str());
cpu->setSize((unsigned long long) (frequency * 1E6));
}
}
}
static vector <string> s390x_features;
static string s390x_vendor;
static void cpuinfo_s390x(hwNode & node,
string id,
string value)
{
if (id == "features")
{
while (value.length() > 0)
{
size_t pos = value.find(' ');
string capability = (pos==string::npos)?value:value.substr(0, pos);
s390x_features.push_back(capability);
if (pos == string::npos)
value = "";
else
value = hw::strip(value.substr(pos));
}
}
if (id == "vendor_id")
s390x_vendor = value;
if (matches(id, "^processor"))
currentcpu++;
hwNode *cpu = getcpu(node, currentcpu);
if (cpu)
{
cpu->addHint("logo", string("s390x"));
cpu->claim(true);
cpu->setVendor(s390x_vendor);
for(size_t i=0; i < s390x_features.size(); i++)
cpu->addCapability(s390x_features[i]);
/* many thanks to Martin Schwidefsky for communicating the descriptions
of the feature flags
*/
cpu->describeCapability("esan3", "ESA new instructions 3 (N3)");
cpu->describeCapability("zarch", "x/Architecture (64-bit) mode)");
cpu->describeCapability("stfle", "store facility list extended instruction");
cpu->describeCapability("msa", "message security assist facility");
cpu->describeCapability("ldisp", "long displacement facility");
cpu->describeCapability("eimm", "extended immediate facility");
cpu->describeCapability("dfp", "decimal floating point facility");
cpu->describeCapability("edat", "enhanced DAT facility");
cpu->describeCapability("etf3eh", "ETF3 enhancement facility");
cpu->describeCapability("highgprs", "support for 64-bit registers for 31-bit programs");
cpu->describeCapability("te", "transactional/constraint transactional execution facilities");
}
}
static void cpuinfo_arm(hwNode & node,
string id,
string value)
{
if (id.substr(0, string("processor").size())=="processor")
currentcpu++;
hwNode *cpu = getcpu(node, currentcpu);
if (cpu)
{
cpu->addHint("logo", string("arm"));
if (id == "model name" && node.getDescription() == "")
node.setDescription(value);
cpu->claim(true);
if (id == "Features")
{
while (value.length() > 0)
{
size_t pos = value.find(' ');
string capability = (pos==string::npos)?value:value.substr(0, pos);
cpu->addCapability(capability);
if (pos == string::npos)
value = "";
else
value = hw::strip(value.substr(pos));
}
}
/* With help from:
http://infocenter.arm.com/help/index.jsp
http://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean
http://en.wikipedia.org/wiki/ARM_architecture
*/
cpu->describeCapability("swp", "Swap instruction");
cpu->describeCapability("swpb", "Swap Byte instruction");
cpu->describeCapability("half", "Unknown");
cpu->describeCapability("thumb", "Thumb instruction set");
cpu->describeCapability("26bit", "26-bit Model");
cpu->describeCapability("fastmult", "Fast Multiplication");
cpu->describeCapability("fpa", "Floating point accelerator");
cpu->describeCapability("vfp", "VFP (vector floating point instructions)");
cpu->describeCapability("vfpv3", "VFP version 3");
cpu->describeCapability("vfpv3d16", "VFP version 3 with 16 64-bit FPU registers");
cpu->describeCapability("vfpv4", "VFP version 4");
cpu->describeCapability("vfpd32", "Unknown");
cpu->describeCapability("edsp", "DSP extensions");
cpu->describeCapability("java", "Jazelle (Java bytecode accelerator)");
cpu->describeCapability("thumbee", "Thumb Execution Environment");
cpu->describeCapability("neon", "NEON aka MPE - Media Processing Engine");
cpu->describeCapability("tls", "TLS register");
cpu->describeCapability("iwmmxt", "SIMD instructions");
cpu->describeCapability("crunch", "MaverickCrunch coprocessor");
cpu->describeCapability("idiva", "SDIV and UDIV hardware division in ARM mode");
cpu->describeCapability("idivt", "SDIV and UDIV hardware division in Thumb mode");
cpu->describeCapability("lpae", "Large Physical Address Extension architecture");
cpu->describeCapability("evtstrm", "Unknown");
}
}
static vector <string> aarch64_features;
static string aarch64_processor_name;
static void cpuinfo_aarch64(hwNode & node,
string id,
string value)
{
/*
* If we already have CPU info extracted from SMBIOS, ignore /proc/cpuinfo
* entirely. This is because the kernel's /proc/cpuinfo output on aarch64
* does not distinguish between cores and physical processors (every core is
* treated as a separate processor) so we may end up creating too many CPU
* nodes.
*/
if (getcpu(node)->getHandle().compare(0, 4, "DMI:") == 0)
return;
if (id.substr(0, string("processor").size())=="processor")
currentcpu++;
if (id.substr(0, string("Processor").size())=="Processor")
aarch64_processor_name = value;
if (id == "Features")
{
hwNode *cpu = getcpu(node, currentcpu);
if (cpu)
{
cpu->addHint("logo", string("aarch64"));
if (node.getDescription() == "")
node.setDescription(aarch64_processor_name);
cpu->claim(true);
while (value.length() > 0)
{
size_t pos = value.find(' ');
string capability = (pos==string::npos)?value:value.substr(0, pos);
aarch64_features.push_back(capability);
if (pos == string::npos)
value = "";
else
value = hw::strip(value.substr(pos));
}
for(size_t i=0; i < aarch64_features.size(); i++)
{
cpu->addCapability(aarch64_features[i]);
cpu->describeCapability("fp", "Floating point instructions");
cpu->describeCapability("asimd", "Advanced SIMD");
cpu->describeCapability("evtstrm", "Event stream");
cpu->describeCapability("aes", "AES instructions");
cpu->describeCapability("pmull", "PMULL instruction");
cpu->describeCapability("sha1", "SHA1 instructions");
cpu->describeCapability("sha2", "SHA2 instructions");
cpu->describeCapability("crc32", "CRC extension");
}
}
}
}
static void cpuinfo_ia64(hwNode & node,
string id,
string value)
{
if (id == "processor")
currentcpu++;
hwNode *cpu = getcpu(node, currentcpu);
if (cpu)
{
cpu->claim(true);
if (id == "cpu number")
{
int physicalcpu = 0;
physicalcpu = atoi(value.c_str());
if (physicalcpu != currentcpu)
{
cpu->addCapability("emulated");
cpu->addCapability("hyperthreading");
}
}
if (id == "vendor")
{
if (value == "GenuineIntel")
value = "Intel Corp.";
cpu->setVendor(value);
}
if (id == "revision")
cpu->setVersion(value);
if (id == "family")
cpu->setProduct(value);
if (id == "cpu MHz" && cpu->getSize() == 0)
{
double frequency = 0.0;
frequency = atof(value.c_str());
cpu->setSize((unsigned long long) (frequency * 1E6));
}
}
}
static void cpuinfo_hppa(hwNode & node,
string id,
string value)
{
if (id == "processor")
currentcpu++;
hwNode *cpu = getcpu(node, currentcpu);
if (id == "model" && node.getProduct() == "")
node.setProduct(value);
if (id == "model name" && node.getDescription() == "")
node.setDescription(value);
if (id == "software id" && node.getSerial() == "")
node.setSerial(value);
if (cpu)
{
cpu->claim(true);
if (id == "cpu family" && cpu->getVersion() == "")
cpu->setVersion(value);
if (id == "cpu" && cpu->getProduct() == "")
cpu->setProduct(value);
if (id == "cpu MHz" && cpu->getSize() == 0)
{
double frequency = 0.0;
frequency = atof(value.c_str());
cpu->setSize((unsigned long long) (frequency * 1E6));
}
}
}
static void cpuinfo_alpha(hwNode & node,
string id,
string value)
{
static int cpusdetected = 0;
static int cpusactive = 0;
unsigned long long frequency = 0;
int i;
hwNode *cpu = getcpu(node, 0);
if (id == "platform string" && node.getProduct() == "")
node.setProduct(value);
if (id == "system serial number" && node.getSerial() == "")
node.setSerial(value);
if (id == "system type")
node.setVersion(node.getVersion() + " " + value);
if (id == "system variation")
node.setVersion(node.getVersion() + " " + value);
if (id == "system revision")
node.setVersion(node.getVersion() + " " + value);
if (id == "cpus detected")
cpusdetected = atoi(value.c_str());
if (id == "cpus active")
cpusactive = atoi(value.c_str());
if (id == "cycle frequency [Hz]")
frequency = atoll(value.c_str());
if (cpu)
{
cpu->claim(true);
if (frequency)
cpu->setSize(frequency);
}
for (i = 1; i < cpusdetected; i++)
{
hwNode *mycpu = getcpu(node, i);
if (mycpu)
{
mycpu->disable();
if (cpu)
mycpu->setSize(cpu->getSize());
}
}
for (i = 1; i < cpusactive; i++)
{
hwNode *mycpu = getcpu(node, i);
if (mycpu)
mycpu->enable();
}
}
static void cpuinfo_x86(hwNode & node,
string id,
string value)
{
static int siblings = -1;
if(currentcpu < 0) siblings = -1;
if ((siblings<0) && (id == "siblings"))
{
siblings = atoi(value.c_str());
siblings--;
}
if (id == "processor")
{
siblings--;
if(siblings >= 0)
return;
else
currentcpu++;
}
hwNode *cpu = getcpu(node, currentcpu);
if (cpu)
{
// x86 CPUs are assumed to be 32 bits per default
if(cpu->getWidth()==0) cpu->setWidth(32);
cpu->claim(true);
if (id == "vendor_id")
{
if (value == "AuthenticAMD")
value = "Advanced Micro Devices [AMD]";
if (value == "GenuineIntel")
value = "Intel Corp.";
cpu->setVendor(value);
}
if (id == "model name")
cpu->setProduct(value);
//if ((id == "cpu MHz") && (cpu->getSize() == 0))
//{
//cpu->setSize((long long) (1000000L * atof(value.c_str())));
//}
if (id == "Physical processor ID")
cpu->setSerial(value);
if ((id == "fdiv_bug") && (value == "yes"))
cpu->addCapability("fdiv_bug");
if ((id == "hlt_bug") && (value == "yes"))
cpu->addCapability("hlt_bug");
if ((id == "f00f_bug") && (value == "yes"))
cpu->addCapability("f00f_bug");
if ((id == "coma_bug") && (value == "yes"))
cpu->addCapability("coma_bug");
if ((id == "fpu") && (value == "yes"))
cpu->addCapability("fpu");
if ((id == "wp") && (value == "yes"))
cpu->addCapability("wp");
if ((id == "fpu_exception") && (value == "yes"))
cpu->addCapability("fpu_exception", "FPU exceptions reporting");
if (id == "flags")
while (value.length() > 0)
{
size_t pos = value.find(' ');
string capability = (pos==string::npos)?value:value.substr(0, pos);
if(capability == "lm") capability = "x86-64";
cpu->addCapability(capability);
if (pos == string::npos)
value = "";
else
value = hw::strip(value.substr(pos));
}
cpu->describeCapability("fpu", "mathematical co-processor");
cpu->describeCapability("vme", "virtual mode extensions");
cpu->describeCapability("de", "debugging extensions");
cpu->describeCapability("pse", "page size extensions");
cpu->describeCapability("tsc", "time stamp counter");
cpu->describeCapability("msr", "model-specific registers");
cpu->describeCapability("mce", "machine check exceptions");
cpu->describeCapability("cx8", "compare and exchange 8-byte");
cpu->describeCapability("apic", "on-chip advanced programmable interrupt controller (APIC)");
cpu->describeCapability("sep", "fast system calls");
cpu->describeCapability("mtrr", "memory type range registers");
cpu->describeCapability("pge", "page global enable");
cpu->describeCapability("mca", "machine check architecture");
cpu->describeCapability("cmov", "conditional move instruction");
cpu->describeCapability("pat", "page attribute table");
cpu->describeCapability("pse36", "36-bit page size extensions");
cpu->describeCapability("pn", "processor serial number");
cpu->describeCapability("psn", "processor serial number");
//cpu->describeCapability("clflush", "");
cpu->describeCapability("dts", "debug trace and EMON store MSRs");
cpu->describeCapability("acpi", "thermal control (ACPI)");
cpu->describeCapability("fxsr", "fast floating point save/restore");
cpu->describeCapability("sse", "streaming SIMD extensions (SSE)");
cpu->describeCapability("sse2", "streaming SIMD extensions (SSE2)");
cpu->describeCapability("ss", "self-snoop");
cpu->describeCapability("tm", "thermal interrupt and status");
cpu->describeCapability("ia64", "IA-64 (64-bit Intel CPU)");
cpu->describeCapability("pbe", "pending break event");
cpu->describeCapability("syscall", "fast system calls");
cpu->describeCapability("mp", "multi-processor capable");
cpu->describeCapability("nx", "no-execute bit (NX)");
cpu->describeCapability("mmxext", "multimedia extensions (MMXExt)");
cpu->describeCapability("3dnowext", "multimedia extensions (3DNow!Ext)");
cpu->describeCapability("3dnow", "multimedia extensions (3DNow!)");
//cpu->describeCapability("recovery", "");
cpu->describeCapability("longrun", "LongRun Dynamic Power/Thermal Management");
cpu->describeCapability("lrti", "LongRun Table Interface");
cpu->describeCapability("cxmmx", "multimedia extensions (Cyrix MMX)");
cpu->describeCapability("k6_mtrr", "AMD K6 MTRRs");
//cpu->describeCapability("cyrix_arr", "");
//cpu->describeCapability("centaur_mcr", "");
//cpu->describeCapability("pni", "");
//cpu->describeCapability("monitor", "");
//cpu->describeCapability("ds_cpl", "");
//cpu->describeCapability("est", "");
//cpu->describeCapability("tm2", "");
//cpu->describeCapability("cid", "");
//cpu->describeCapability("xtpr", "");
cpu->describeCapability("rng", "random number generator");
cpu->describeCapability("rng_en", "random number generator (enhanced)");
cpu->describeCapability("ace", "advanced cryptography engine");
cpu->describeCapability("ace_en", "advanced cryptography engine (enhanced)");
cpu->describeCapability("ht", "HyperThreading");
cpu->describeCapability("lm", "64bits extensions (x86-64)");
cpu->describeCapability("x86-64", "64bits extensions (x86-64)");
cpu->describeCapability("mmx", "multimedia extensions (MMX)");
cpu->describeCapability("pae", "4GB+ memory addressing (Physical Address Extension)");
if(cpu->isCapable("ia64") || cpu->isCapable("lm") || cpu->isCapable("x86-64"))
cpu->setWidth(64);
if(node.getWidth()==0) node.setWidth(cpu->getWidth());
}
}
bool scan_cpuinfo(hwNode & n)
{
hwNode *core = n.getChild("core");
int cpuinfo = open("/proc/cpuinfo", O_RDONLY);
if (cpuinfo < 0)
return false;
if (!core)
{
n.addChild(hwNode("core", hw::bus));
core = n.getChild("core");
}
if (core)
{
char buffer[1024];
size_t count;
string cpuinfo_str = "";
string description = "", version = "";
string plat = platform();
while ((count = read(cpuinfo, buffer, sizeof(buffer))) > 0)
{
cpuinfo_str += string(buffer, count);
}
close(cpuinfo);
vector < string > cpuinfo_lines;
splitlines(cpuinfo_str, cpuinfo_lines);
cpuinfo_str = ""; // free memory
currentcpu = -1;
for (unsigned int i = 0; i < cpuinfo_lines.size(); i++)
{
string id = "";
string value = "";
size_t pos = 0;
pos = cpuinfo_lines[i].find(':');
if (pos != string::npos)
{
id = hw::strip(cpuinfo_lines[i].substr(0, pos));
value = hw::strip(cpuinfo_lines[i].substr(pos + 1));
if (plat == "ppc" || plat == "ppc64" || plat == "ppc64le")
{
// All cores have same product name and version on power systems
if (is_system_ppc_ibm(n))
{
if (id == "cpu")
description = value;
if (id == "revision")
version = value;
if (description != "" && version != "")
{
cpuinfo_ppc_ibm(n, description, version);
break;
}
}
else
cpuinfo_ppc(n, id, value);
}
else if (plat == "hppa")
{
cpuinfo_hppa(n, id, value);
}
else if (plat == "alpha")
{
cpuinfo_alpha(n, id, value);
}
else if (plat == "ia64")
{
cpuinfo_ia64(n, id, value);
}
else if (plat == "s390" || plat == "s390x")
{
cpuinfo_s390x(n, id, value);
}
else if (plat.compare(0, 3, "arm") == 0)
{
cpuinfo_arm(n, id, value);
}
else if (plat == "aarch64")
{
cpuinfo_aarch64(n, id, value);
}
else
{
cpuinfo_x86(n, id, value);
}
}
}
}
else
{
close(cpuinfo);
return false;
}
hwNode *cpu = getcpu(n, 0);
if(cpu && (n.getWidth()==0))
n.setWidth(cpu->getWidth());
return true;
}

7
src/core/cpuinfo.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _CPUINFO_H_
#define _CPUINFO_H_
#include "hw.h"
bool scan_cpuinfo(hwNode & n);
#endif

421
src/core/db.cc Normal file
View File

@ -0,0 +1,421 @@
#include <string.h>
#include <string>
#include <stdexcept>
#include <sqlite3.h>
#include "db.h"
using namespace sqlite;
using namespace std;
namespace sqlite {
class exception : public std::runtime_error
{
public:
exception(sqlite3 *db):
runtime_error("SQLite error: " + string(sqlite3_errmsg(db)))
{
}
exception(const char * msg):
runtime_error(msg)
{
}
};
}; // namespace sqlite
struct sqlite::database_i
{
sqlite3* connection;
database_i()
{
connection = NULL;
}
};
database::database(const std::string & filename):
implementation(NULL)
{
implementation = new database_i;
if(implementation)
if(sqlite3_open(filename.c_str(), &implementation->connection) != SQLITE_OK)
throw exception(implementation->connection);
}
database::database(const database & db)
{
implementation = new database_i;
if(implementation && db.implementation)
*implementation = *(db.implementation);
}
database::~database()
{
if(implementation)
{
sqlite3_close(implementation->connection);
delete implementation;
}
}
void database::execute(const string & sql)
{
if(implementation)
{
statement s(*this, sql);
s.execute();
}
}
struct sqlite::value_i
{
unsigned int ref;
type value_type;
union
{
long long integer_value;
double real_value;
string *text_value;
};
value_i()
{
value_type = null;
ref = 1;
}
~value_i()
{
if((value_type == text) && text_value)
delete text_value;
}
};
value::value(const std::string & s)
{
implementation = new value_i;
if(implementation)
{
implementation->value_type = text;
implementation->text_value = new string(s);
}
}
value::value(const char * s)
{
implementation = new value_i;
if(implementation)
{
implementation->value_type = text;
implementation->text_value = new string(s);
}
}
value::value(long long l)
{
implementation = new value_i;
if(implementation)
{
implementation->value_type = integer;
implementation->integer_value = l;
}
}
value::value(double d)
{
implementation = new value_i;
if(implementation)
{
implementation->value_type = real;
implementation->real_value = d;
}
}
value::value()
{
implementation = new value_i;
}
value::value(const value & v)
{
implementation = v.implementation;
if(implementation) implementation->ref++;
}
value::~value()
{
if(implementation)
{
implementation->ref--;
if(implementation->ref<=0) delete implementation;
}
}
value & value::operator =(const value & v)
{
if(&v == this) return *this; // self-affectation
if(implementation)
{
implementation->ref--;
if(implementation->ref<=0) delete implementation;
}
implementation = v.implementation;
if(implementation) implementation->ref++;
return *this;
}
type value::getType() const
{
if(implementation)
return implementation->value_type;
else
return null;
}
string value::asText() const
{
if(!implementation || (implementation->value_type == null))
throw exception("Can't convert NULL value to text");
switch(implementation->value_type)
{
case text:
case blob:
return *(implementation->text_value);
default:
throw exception("Can't convert value to text");
}
throw exception("Can't convert value to text");
}
long long value::asInteger() const
{
if(!implementation || (implementation->value_type == null))
throw exception("Can't convert NULL value to integer");
switch(implementation->value_type)
{
case integer:
return implementation->integer_value;
default:
throw exception("Can't convert value to integer");
}
}
double value::asReal() const
{
if(!implementation || (implementation->value_type == null))
throw exception("Can't convert NULL value to real");
switch(implementation->value_type)
{
case real:
return implementation->real_value;
default:
throw exception("Can't convert value to real");
}
}
ostream & value::print(std::ostream & out) const
{
if(!implementation)
out << "NULL";
else
switch(implementation->value_type)
{
case integer:
out << implementation->integer_value;
break;
case real:
out << implementation->real_value;
break;
case text:
out << *(implementation->text_value);
break;
case blob:
out << "BLOB";
break;
case null:
out << "NULL";
break;
}
return out;
}
struct sqlite::statement_i
{
database *db;
sqlite3_stmt *stmt;
};
statement::statement(database & db, const std::string & s)
{
implementation = new statement_i;
if(!implementation)
throw exception("memory exhausted");
implementation->db = &db;
if(!db.implementation)
throw exception("invalid database");
if(sqlite3_prepare(db.implementation->connection, s.c_str(), -1, &implementation->stmt, NULL) != SQLITE_OK)
throw exception(db.implementation->connection);
}
statement::~statement()
{
if(implementation)
{
if(implementation->stmt)
sqlite3_finalize(implementation->stmt);
delete implementation;
}
}
void statement::prepare(const std::string & s)
{
if(implementation)
{
if(implementation->stmt)
sqlite3_finalize(implementation->stmt);
}
else
implementation = new statement_i;
if(!implementation)
throw exception("memory exhausted");
if(sqlite3_prepare(implementation->db->implementation->connection, s.c_str(), -1, &implementation->stmt, NULL) != SQLITE_OK)
throw exception(implementation->db->implementation->connection);
}
void statement::bind(int index, const value & v)
{
if(!implementation)
throw exception("undefined statement");
switch(v.getType())
{
case null:
if(sqlite3_bind_null(implementation->stmt, index) != SQLITE_OK)
throw exception(implementation->db->implementation->connection);
break;
case text:
if(sqlite3_bind_text(implementation->stmt, index, v.asText().c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
throw exception(implementation->db->implementation->connection);
break;
case blob:
{
string blob = v.asText();
if(sqlite3_bind_text(implementation->stmt, index, blob.data(), blob.size(), SQLITE_TRANSIENT) != SQLITE_OK)
throw exception(implementation->db->implementation->connection);
break;
}
case integer:
if(sqlite3_bind_int64(implementation->stmt, index, v.asInteger()) != SQLITE_OK)
throw exception(implementation->db->implementation->connection);
break;
case real:
if(sqlite3_bind_double(implementation->stmt, index, v.asReal()) != SQLITE_OK)
throw exception(implementation->db->implementation->connection);
break;
default:
throw exception("unknown type");
}
}
bool statement::step()
{
if(!implementation)
throw exception("undefined statement");
int result = sqlite3_step(implementation->stmt);
if(result == SQLITE_DONE) return false;
if(result == SQLITE_ROW) return true;
throw exception(implementation->db->implementation->connection);
}
void statement::execute()
{
while(step());
}
void statement::reset()
{
if(!implementation)
throw exception("undefined statement");
sqlite3_reset(implementation->stmt); // ignore return value
}
int statement::columns() const
{
if(!implementation)
throw exception("undefined statement");
return sqlite3_column_count(implementation->stmt);
}
value statement::column(unsigned int i) const
{
if(!implementation)
throw exception("undefined statement");
switch(sqlite3_column_type(implementation->stmt, i))
{
case SQLITE_INTEGER:
return value(sqlite3_column_int64(implementation->stmt, i));
case SQLITE_FLOAT:
return value(sqlite3_column_double(implementation->stmt, i));
case SQLITE_TEXT:
return value((const char*)sqlite3_column_text(implementation->stmt, i));
case SQLITE_BLOB:
case SQLITE_NULL:
default:
return value();
}
}
value statement::column(const string & name) const
{
if(!implementation)
throw exception("undefined statement");
for(int i=0; i<columns(); i++)
if(strcasecmp(sqlite3_column_name(implementation->stmt, i), name.c_str())==0)
return column(i);
return value();
}
value statement::operator[](unsigned int i) const
{
return column(i);
}
value statement::operator[](const string & i) const
{
return column(i);
}

93
src/core/db.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef _DB_H_
#define _DB_H_
#include <string>
#include <iostream>
namespace sqlite {
class database
{
public:
database(const std::string & filename);
database(const database & db);
~database();
database operator =(const database &);
void execute(const std::string & sql);
friend class statement;
private:
database();
struct database_i *implementation;
};
typedef enum {
null,
text,
integer,
real,
blob} type;
class value
{
public:
value();
value(const char *);
value(const std::string &);
value(long long);
value(double);
value(const value &);
~value();
value & operator =(const value &);
type getType() const;
std::string asText() const;
long long asInteger() const;
double asReal() const;
std::ostream & print(std::ostream &) const;
private:
struct value_i *implementation;
};
class statement
{
public:
statement(database &, const std::string &);
~statement();
void prepare(const std::string &);
void bind(int index, const value & v);
bool step();
void execute();
void reset();
int columns() const;
value column(unsigned int) const;
value column(const std::string &) const;
value operator[](unsigned int) const;
value operator[](const std::string &) const;
private:
statement();
statement(const statement &);
statement & operator =(const statement &);
struct statement_i *implementation;
};
}; // namespace sqlite
#endif

1480
src/core/device-tree.cc Normal file

File diff suppressed because it is too large Load Diff

9
src/core/device-tree.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _DEVICETREE_H_
#define _DEVICETREE_H_
#include "hw.h"
bool scan_device_tree(hwNode & n);
void add_device_tree_info(hwNode & n, string sysfs_path);
#endif

83
src/core/disk.cc Normal file
View File

@ -0,0 +1,83 @@
#include "version.h"
#include "disk.h"
#include "osutils.h"
#include "heuristics.h"
#include "partitions.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
//#include <linux/fs.h>
__ID("@(#) $Id$");
#ifndef BLKROGET
#define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
#endif
#ifndef BLKGETSIZE
#define BLKGETSIZE _IO(0x12,96) /* return device size */
#endif
#ifndef BLKGETSIZE64
#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* size in bytes */
#endif
#ifndef BLKSSZGET
#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
#endif
#ifndef BLKPBSZGET
#define BLKPBSZGET _IO(0x12,123)
#endif
bool scan_disk(hwNode & n)
{
long size = 0;
unsigned long long bytes = 0;
int sectsize = 0;
int physsectsize = 0;
if (n.getLogicalName() == "")
return false;
int fd = open(n.getLogicalName().c_str(), O_RDONLY | O_NONBLOCK);
if (fd < 0)
return false;
if (ioctl(fd, BLKPBSZGET, &physsectsize) != 0)
physsectsize = 0;
if(physsectsize)
n.setConfig("sectorsize", physsectsize);
if (ioctl(fd, BLKSSZGET, &sectsize) < 0)
sectsize = 0;
if (sectsize)
n.setConfig("logicalsectorsize", sectsize);
if (n.getSize() == 0)
{
if(ioctl(fd, BLKGETSIZE64, &bytes) == 0)
{
n.setSize(bytes);
}
else
{
if (ioctl(fd, BLKGETSIZE, &size) != 0)
size = 0;
if ((size > 0) && (sectsize > 0)){
n.setSize((unsigned long long) size * (unsigned long long) sectsize);
}
}
}
close(fd);
if(n.getSize()>=0)
{
n.addHint("icon", string("disc"));
scan_partitions(n);
}
return true;
}

7
src/core/disk.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _DISK_H_
#define _DISK_H_
#include "hw.h"
bool scan_disk(hwNode & n);
#endif

22
src/core/display.cc Normal file
View File

@ -0,0 +1,22 @@
/*
* display.cc
*
*
*/
#include "display.h"
static const char rcsid[] = "@(#) $Id: fb.cc 576 2004-05-07 07:13:31Z ezix $";
bool scan_display(hwNode & n)
{
if((n.getClass() == hw::display) && n.isCapable("vga"))
{
n.claim(true);
}
for(unsigned int i=0; i<n.countChildren(); i++)
scan_display(*n.getChild(i));
return true;
}

7
src/core/display.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _DISPLAY_H_
#define _DISPLAY_H_
#include "hw.h"
bool scan_display(hwNode & n);
#endif

2046
src/core/dmi.cc Normal file

File diff suppressed because it is too large Load Diff

7
src/core/dmi.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _DMI_H_
#define _DMI_H_
#include "hw.h"
bool scan_dmi(hwNode & n);
#endif

177
src/core/dump.cc Normal file
View File

@ -0,0 +1,177 @@
#include "dump.h"
#include "version.h"
#include "osutils.h"
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#ifdef SQLITE
using namespace std;
using namespace sqlite;
static bool createtables(database & db)
{
try {
db.execute("CREATE TABLE IF NOT EXISTS META(key TEXT PRIMARY KEY COLLATE NOCASE, value BLOB)");
statement stm(db, "INSERT OR IGNORE INTO META (key,value) VALUES(?,?)");
stm.bind(1, "schema");
stm.bind(2, 1.0);
stm.execute();
stm.reset();
stm.bind(1, "application");
stm.bind(2, "org.ezix.lshw");
stm.execute();
stm.reset();
stm.bind(1, "creator");
stm.bind(2, "lshw/" + string(getpackageversion()));
stm.execute();
stm.reset();
stm.bind(1, "OS");
stm.bind(2, operating_system());
stm.execute();
stm.reset();
stm.bind(1, "platform");
stm.bind(2, platform());
stm.execute();
db.execute("CREATE TABLE IF NOT EXISTS nodes(path TEXT PRIMARY KEY, id TEXT NOT NULL COLLATE NOCASE, parent TEXT COLLATE NOCASE, class TEXT NOT NULL COLLATE NOCASE, enabled BOOL, claimed BOOL, description TEXT, vendor TEXT, product TEXT, version TEXT, serial TEXT, businfo TEXT, physid TEXT, slot TEXT, size INTEGER, capacity INTEGER, clock INTEGER, width INTEGER, dev TEXT)");
db.execute("CREATE TABLE IF NOT EXISTS logicalnames(logicalname TEXT NOT NULL, node TEXT NOT NULL COLLATE NOCASE)");
db.execute("CREATE TABLE IF NOT EXISTS capabilities(capability TEXT NOT NULL COLLATE NOCASE, node TEXT NOT NULL COLLATE NOCASE, description TEXT, UNIQUE (capability,node))");
db.execute("CREATE TABLE IF NOT EXISTS configuration(config TEXT NOT NULL COLLATE NOCASE, node TEXT NOT NULL COLLATE NOCASE, value TEXT, UNIQUE (config,node))");
db.execute("CREATE TABLE IF NOT EXISTS hints(hint TEXT NOT NULL COLLATE NOCASE, node TEXT NOT NULL COLLATE NOCASE, value TEXT, UNIQUE (hint,node))");
db.execute("CREATE TABLE IF NOT EXISTS resources(node TEXT NOT NULL COLLATE NOCASE, type TEXT NOT NULL COLLATE NOCASE, resource TEXT NOT NULL, UNIQUE(node,type,resource))");
db.execute("CREATE VIEW IF NOT EXISTS unclaimed AS SELECT * FROM nodes WHERE NOT claimed");
db.execute("CREATE VIEW IF NOT EXISTS disabled AS SELECT * FROM nodes WHERE NOT enabled");
}
catch(exception & e)
{
return false;
}
return true;
}
bool dump(hwNode & n, database & db, const string & path, bool recurse)
{
if(!createtables(db))
return false;
try {
unsigned i = 0;
statement stm(db, "INSERT OR REPLACE INTO nodes (id,class,product,vendor,description,size,capacity,width,version,serial,enabled,claimed,slot,clock,businfo,physid,path,parent,dev) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
string mypath = path+(path=="/"?"":"/")+n.getPhysId();
stm.bind(1, n.getId());
stm.bind(2, n.getClassName());
if(n.getProduct() != "") stm.bind(3, n.getProduct());
if(n.getVendor() != "") stm.bind(4, n.getVendor());
if(n.getDescription() != "") stm.bind(5, n.getDescription());
if(n.getSize()) stm.bind(6, (long long int)n.getSize());
if(n.getCapacity()) stm.bind(7, (long long int)n.getCapacity());
if(n.getWidth()) stm.bind(8, (long long int)n.getWidth());
if(n.getVersion() != "") stm.bind(9, n.getVersion());
if(n.getSerial() != "") stm.bind(10, n.getSerial());
stm.bind(11, (long long int)n.enabled());
stm.bind(12, (long long int)n.claimed());
if(n.getSlot() != "") stm.bind(13, n.getSlot());
if(n.getClock()) stm.bind(14, (long long int)n.getClock());
if(n.getBusInfo() != "") stm.bind(15, n.getBusInfo());
if(n.getPhysId() != "") stm.bind(16, n.getPhysId());
stm.bind(17, mypath);
if(path != "") stm.bind(18, path);
if(n.getDev() != "") stm.bind(19, n.getDev());
stm.execute();
stm.prepare("INSERT OR REPLACE INTO logicalnames (node,logicalname) VALUES(?,?)");
vector<string> keys = n.getLogicalNames();
for(i=0; i<keys.size(); i++)
{
stm.reset();
stm.bind(1, mypath);
stm.bind(2, keys[i]);
stm.execute();
}
stm.prepare("INSERT OR REPLACE INTO capabilities (capability,node,description) VALUES(?,?,?)");
keys = n.getCapabilitiesList();
for(i=0; i<keys.size(); i++)
{
stm.reset();
stm.bind(1, keys[i]);
stm.bind(2, mypath);
stm.bind(3, n.getCapabilityDescription(keys[i]));
stm.execute();
}
stm.prepare("INSERT OR REPLACE INTO configuration (config,node,value) VALUES(?,?,?)");
keys = n.getConfigKeys();
for(i=0; i<keys.size(); i++)
{
stm.reset();
stm.bind(1, keys[i]);
stm.bind(2, mypath);
stm.bind(3, n.getConfig(keys[i]));
stm.execute();
}
stm.prepare("INSERT OR IGNORE INTO resources (type,node,resource) VALUES(?,?,?)");
keys = n.getResources(":");
for(i=0; i<keys.size(); i++)
{
string type = keys[i].substr(0, keys[i].find_first_of(':'));
string resource = keys[i].substr(keys[i].find_first_of(':')+1);
stm.reset();
stm.bind(1, type);
stm.bind(2, mypath);
stm.bind(3, resource);
stm.execute();
}
stm.prepare("INSERT OR REPLACE INTO hints (hint,node,value) VALUES(?,?,?)");
keys = n.getHints();
for(i=0; i<keys.size(); i++)
{
stm.reset();
stm.bind(1, keys[i]);
stm.bind(2, mypath);
stm.bind(3, n.getHint(keys[i]).asString());
stm.execute();
}
stm.reset();
stm.bind(1,"run.root");
stm.bind(2,"");
stm.bind(3,(long long int)(geteuid() == 0));
stm.execute();
stm.reset();
stm.bind(1,"run.time");
stm.bind(2,"");
stm.bind(3,(long long int)time(NULL));
stm.execute();
stm.reset();
stm.bind(1,"run.language");
stm.bind(2,"");
stm.bind(3,getenv("LANG"));
stm.execute();
if(recurse)
for(i=0; i<n.countChildren(); i++)
dump(*(n.getChild(i)), db, mypath, recurse);
}
catch(exception & e)
{
return false;
}
return true;
}
#endif

10
src/core/dump.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _DUMP_H_
#ifdef SQLITE
#include "db.h"
#include "hw.h"
bool dump(hwNode &, sqlite::database &, const std::string & path = "", bool recurse = true);
#endif
#endif

297
src/core/fat.cc Normal file
View File

@ -0,0 +1,297 @@
/*
* based on Kay Sievers' volume_id - reads filesystem label and uuid
*
* CAUTION: this version is severely brain-damaged, don't blame Kay
*
* for instance, it will only detect the volume label on FAT32 if it
* is declared within the first cluster of the root directory
* (i.e. usually within the first 128 files)
*
* original copyright follows:
*
* Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
*
* 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 "fat.h"
#include "osutils.h"
#include <stdlib.h>
#include <string.h>
/* linux/msdos_fs.h says: */
#define FAT12_MAX 0xff4
#define FAT16_MAX 0xfff4
#define FAT32_MAX 0x0ffffff6
#define FAT_ATTR_VOLUME_ID 0x08
#define FAT_ATTR_DIR 0x10
#define FAT_ATTR_LONG_NAME 0x0f
#define FAT_ATTR_MASK 0x3f
#define FAT_ENTRY_FREE 0xe5
struct vfat_super_block {
uint8_t boot_jump[3];
uint8_t sysid[8];
uint16_t sector_size_bytes;
uint8_t sectors_per_cluster;
uint16_t reserved_sct;
uint8_t fats;
uint16_t dir_entries;
uint16_t sectors;
uint8_t media;
uint16_t fat_length;
uint16_t secs_track;
uint16_t heads;
uint32_t hidden;
uint32_t total_sect;
union {
struct fat_super_block {
uint8_t unknown[3];
uint8_t serno[4];
uint8_t label[11];
uint8_t magic[8];
uint8_t dummy2[192];
uint8_t pmagic[2];
} __attribute__((__packed__)) fat;
struct fat32_super_block {
uint32_t fat32_length;
uint16_t flags;
uint8_t version[2];
uint32_t root_cluster;
uint16_t insfo_sector;
uint16_t backup_boot;
uint16_t reserved2[6];
uint8_t unknown[3];
uint8_t serno[4];
uint8_t label[11];
uint8_t magic[8];
uint8_t dummy2[164];
uint8_t pmagic[2];
} __attribute__((__packed__)) fat32;
char sector[512]; // to make sure the whole struct is at least 512 bytes long
} __attribute__((__packed__)) type;
} __attribute__((__packed__));
struct vfat_dir_entry {
uint8_t name[11];
uint8_t attr;
uint16_t time_creat;
uint16_t date_creat;
uint16_t time_acc;
uint16_t date_acc;
uint16_t cluster_high;
uint16_t time_write;
uint16_t date_write;
uint16_t cluster_low;
uint32_t size;
} __attribute__((__packed__));
static uint8_t *get_attr_volume_id(struct vfat_dir_entry *dir, int count)
{
for (; --count >= 0; dir++) {
/* end marker */
if (dir->name[0] == 0x00) {
break;
}
/* empty entry */
if (dir->name[0] == FAT_ENTRY_FREE)
continue;
/* long name */
if ((dir->attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)
continue;
if ((dir->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
/* labels do not have file data */
if (dir->cluster_high != 0 || dir->cluster_low != 0)
continue;
return dir->name;
}
}
return NULL;
}
bool scan_fat(hwNode & n, source & id)
{
struct vfat_super_block vs;
struct vfat_dir_entry *dir;
uint16_t sector_size_bytes;
uint16_t dir_entries;
uint32_t sect_count;
uint16_t reserved_sct;
uint32_t fat_size_sct;
uint32_t root_cluster;
uint32_t dir_size_sct;
uint32_t cluster_count;
uint64_t root_start_sect;
uint32_t start_data_sct;
uint8_t *buf = NULL;
uint32_t buf_size;
uint8_t *label = NULL;
uint32_t next_cluster;
if(!readlogicalblocks(id, &vs, 0, 1))
return false;
/* believe only that's fat, don't trust the version
* the cluster_count will tell us
*/
if (memcmp(vs.sysid, "NTFS", 4) == 0)
return -1;
if (memcmp(vs.type.fat32.magic, "MSWIN", 5) == 0)
goto valid;
if (memcmp(vs.type.fat32.magic, "FAT32 ", 8) == 0)
goto valid;
if (memcmp(vs.type.fat.magic, "FAT16 ", 8) == 0)
goto valid;
if (memcmp(vs.type.fat.magic, "MSDOS", 5) == 0)
goto valid;
if (memcmp(vs.type.fat.magic, "FAT12 ", 8) == 0)
goto valid;
/*
* There are old floppies out there without a magic, so we check
* for well known values and guess if it's a fat volume
*/
/* boot jump address check */
if ((vs.boot_jump[0] != 0xeb || vs.boot_jump[2] != 0x90) &&
vs.boot_jump[0] != 0xe9)
return false;
/* heads check */
if (vs.heads == 0)
return false;
/* cluster size check */
if (vs.sectors_per_cluster == 0 ||
(vs.sectors_per_cluster & (vs.sectors_per_cluster-1)))
return false;
/* media check */
if (vs.media < 0xf8 && vs.media != 0xf0)
return false;
/* fat count*/
if (vs.fats != 2)
return false;
valid:
/* sector size check */
sector_size_bytes = le_short(&vs.sector_size_bytes);
if (sector_size_bytes != 0x200 && sector_size_bytes != 0x400 &&
sector_size_bytes != 0x800 && sector_size_bytes != 0x1000)
return false;
id.blocksize = sector_size_bytes;
reserved_sct = le_short(&vs.reserved_sct);
sect_count = le_short(&vs.sectors);
if (sect_count == 0)
sect_count = le_long(&vs.total_sect);
fat_size_sct = le_short(&vs.fat_length);
if (fat_size_sct == 0)
fat_size_sct = le_long(&vs.type.fat32.fat32_length);
fat_size_sct *= vs.fats;
dir_entries = le_short(&vs.dir_entries);
dir_size_sct = ((dir_entries * sizeof(struct vfat_dir_entry)) +
(sector_size_bytes-1)) / sector_size_bytes;
cluster_count = sect_count - (reserved_sct + fat_size_sct + dir_size_sct);
cluster_count /= vs.sectors_per_cluster;
// if (cluster_count < FAT12_MAX) {
// strcpy(id->type_version, "FAT12");
// } else if (cluster_count < FAT16_MAX) {
// strcpy(id->type_version, "FAT16");
// } else {
// strcpy(id->type_version, "FAT32");
// goto fat32;
// }
if (cluster_count < FAT16_MAX)
{
/* the label may be an attribute in the root directory */
root_start_sect = reserved_sct + fat_size_sct;
buf_size = dir_entries * sizeof(struct vfat_dir_entry);
buf = (uint8_t*)malloc(buf_size);
if(!readlogicalblocks(id, buf, root_start_sect, buf_size / sector_size_bytes))
goto end;
label = get_attr_volume_id((struct vfat_dir_entry*) buf, dir_entries);
if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) {
n.setConfig("label", hw::strip(string((char*)label, 11)));
} else if (memcmp(vs.type.fat.label, "NO NAME ", 11) != 0) {
n.setConfig("label", hw::strip(string((char*)vs.type.fat.label, 11)));
}
}
else {
/* FAT32 root dir is a cluster chain like any other directory */
/* FIXME: we actually don't bother checking the whole chain */
/* --> the volume label is assumed to be within the first cluster (usually 128 entries)*/
buf_size = vs.sectors_per_cluster * sector_size_bytes;
buf = (uint8_t*)malloc(buf_size);
root_cluster = le_long(&vs.type.fat32.root_cluster);
start_data_sct = reserved_sct + fat_size_sct;
id.blocksize = sector_size_bytes;
next_cluster = root_cluster;
{
uint32_t next_off_sct;
uint64_t next_off;
int count;
next_off_sct = (next_cluster - 2) * vs.sectors_per_cluster;
next_off = start_data_sct + next_off_sct;
/* get cluster */
if(!readlogicalblocks(id, buf, next_off, vs.sectors_per_cluster))
goto end;
dir = (struct vfat_dir_entry*) buf;
count = buf_size / sizeof(struct vfat_dir_entry);
label = get_attr_volume_id(dir, count);
}
if (label != NULL && memcmp(label, "NO NAME ", 11) != 0) {
n.setConfig("label", hw::strip(string((char*)label, 11)));
} else if (memcmp(vs.type.fat32.label, "NO NAME ", 11) != 0) {
n.setConfig("label", hw::strip(string((char*)vs.type.fat.label, 11)));
}
}
end:
if(buf) free(buf);
return true;
}

9
src/core/fat.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _FAT_H_
#define _FAT_H_
#include "hw.h"
#include "blockio.h"
bool scan_fat(hwNode & n, source & s);
#endif

341
src/core/fb.cc Normal file
View File

@ -0,0 +1,341 @@
/*
* fb.cc
*
*
*/
#include "version.h"
#include "fb.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
__ID("@(#) $Id$");
#define FB_MODES_SHIFT 5 /* 32 modes per framebuffer */
#define FB_NUM_MINORS 256 /* 256 Minors */
#define MAX_FB (FB_NUM_MINORS / (1 << FB_MODES_SHIFT))
/* ioctls
0x46 is 'F' */
#define FBIOGET_VSCREENINFO 0x4600
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602
#define FBIOGETCMAP 0x4604
#define FBIOPUTCMAP 0x4605
#define FBIOPAN_DISPLAY 0x4606
/* 0x4607-0x460B are defined below */
/* #define FBIOGET_MONITORSPEC 0x460C */
/* #define FBIOPUT_MONITORSPEC 0x460D */
/* #define FBIOSWITCH_MONIBIT 0x460E */
#define FBIOGET_CON2FBMAP 0x460F
#define FBIOPUT_CON2FBMAP 0x4610
#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
#define FB_TYPE_PLANES 1 /* Non interleaved planes */
#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */
#define FB_TYPE_TEXT 3 /* Text/attributes */
#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */
#define FB_AUX_TEXT_MDA 0 /* Monochrome text */
#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */
#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */
#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */
#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */
#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */
#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */
#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */
#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */
#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */
#define FB_VISUAL_TRUECOLOR 2 /* True color */
#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */
#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */
#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */
#define FB_ACCEL_NONE 0 /* no hardware accelerator */
#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */
#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */
#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */
#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */
#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */
#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */
#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */
#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */
#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */
#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */
#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */
#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */
#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */
#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */
#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */
#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */
#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */
#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */
#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */
#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */
#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */
#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */
#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */
#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */
#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */
#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */
#define FB_VMODE_NONINTERLACED 0 /* non interlaced */
#define FB_VMODE_INTERLACED 1 /* interlaced */
#define FB_VMODE_DOUBLE 2 /* double scan */
#define FB_VMODE_MASK 255
struct fb_fix_screeninfo
{
char id[16]; /* identification string eg "TT Builtin" */
char *smem_start; /* Start of frame buffer mem */
/*
* (physical address)
*/
u_int32_t smem_len; /* Length of frame buffer mem */
u_int32_t type; /* see FB_TYPE_* */
u_int32_t type_aux; /* Interleave for interleaved Planes */
u_int32_t visual; /* see FB_VISUAL_* */
u_int16_t xpanstep; /* zero if no hardware panning */
u_int16_t ypanstep; /* zero if no hardware panning */
u_int16_t ywrapstep; /* zero if no hardware ywrap */
u_int32_t line_length; /* length of a line in bytes */
char *mmio_start; /* Start of Memory Mapped I/O */
/*
* (physical address)
*/
u_int32_t mmio_len; /* Length of Memory Mapped I/O */
u_int32_t accel; /* Type of acceleration available */
u_int16_t reserved[3]; /* Reserved for future compatibility */
};
struct fb_bitfield
{
u_int32_t offset; /* beginning of bitfield */
u_int32_t length; /* length of bitfield */
u_int32_t msb_right; /* != 0 : Most significant bit is */
/*
* right
*/
};
struct fb_var_screeninfo
{
u_int32_t xres; /* visible resolution */
u_int32_t yres;
u_int32_t xres_virtual; /* virtual resolution */
u_int32_t yres_virtual;
u_int32_t xoffset; /* offset from virtual to visible */
u_int32_t yoffset; /* resolution */
u_int32_t bits_per_pixel; /* guess what */
u_int32_t grayscale; /* != 0 Graylevels instead of colors */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
u_int32_t nonstd; /* != 0 Non standard pixel format */
u_int32_t activate; /* see FB_ACTIVATE_* */
u_int32_t height; /* height of picture in mm */
u_int32_t width; /* width of picture in mm */
u_int32_t accel_flags; /* acceleration flags (hints) */
/*
* Timing: All values in pixclocks, except pixclock (of course)
*/
u_int32_t pixclock; /* pixel clock in ps (pico seconds) */
u_int32_t left_margin; /* time from sync to picture */
u_int32_t right_margin; /* time from picture to sync */
u_int32_t upper_margin; /* time from sync to picture */
u_int32_t lower_margin;
u_int32_t hsync_len; /* length of horizontal sync */
u_int32_t vsync_len; /* length of vertical sync */
u_int32_t sync; /* see FB_SYNC_* */
u_int32_t vmode; /* see FB_VMODE_* */
u_int32_t reserved[6]; /* Reserved for future compatibility */
};
static int lookup_dev(const char *name)
{
FILE *f;
int n;
char s[32], t[32];
f = fopen("/proc/devices", "r");
if (f == NULL)
return -errno;
while (fgets(s, 32, f) != NULL)
{
if (sscanf(s, "%d %s", &n, t) == 2)
if (strcmp(name, t) == 0)
break;
}
fclose(f);
if (strcmp(name, t) == 0)
return n;
else
return -ENODEV;
}
static int open_dev(dev_t dev)
{
static const char *paths[] =
{
"/var/run", "/dev", "/tmp", NULL
};
char const **p;
char fn[64];
int fd;
for (p = paths; *p; p++)
{
sprintf(fn, "%s/fb-%d", *p, getpid());
if (mknod(fn, (S_IFCHR | S_IREAD), dev) == 0)
{
fd = open(fn, O_RDONLY);
unlink(fn);
if (fd >= 0)
return fd;
}
}
return -1;
}
bool scan_fb(hwNode & n)
{
int fd[MAX_FB];
unsigned int fbdevs = 0;
unsigned int i;
int major = lookup_dev("fb");
if (major < 0) // framebuffer support not loaded, there isn't
return false; // much we can do
memset(fd, 0, sizeof(fd));
for (i = 0; i < MAX_FB; i++)
{
fd[i] = open_dev((dev_t) ((major << 8) + i));
if (fd[i] >= 0)
{
hwNode *fbdev = NULL;
struct fb_fix_screeninfo fbi;
if (ioctl(fd[i], FBIOGET_FSCREENINFO, &fbi) == 0)
{
fbdev =
n.
findChildByResource(hw::resource::
iomem((unsigned long) fbi.smem_start,
fbi.smem_len));
if (fbdev)
{
char devname[20];
struct fb_var_screeninfo fbconfig;
snprintf(devname, sizeof(devname), "/dev/fb%d", i);
fbdev->setLogicalName(devname);
fbdev->claim();
if (fbdev->getDescription() == "")
fbdev->setDescription(hw::strip(fbi.id));
fbdev->addCapability("fb");
switch (fbi.visual)
{
case FB_VISUAL_MONO01:
fbdev->setConfig("visual", "mono01");
break;
case FB_VISUAL_MONO10:
fbdev->setConfig("visual", "mono10");
break;
case FB_VISUAL_TRUECOLOR:
fbdev->setConfig("visual", "truecolor");
break;
case FB_VISUAL_PSEUDOCOLOR:
fbdev->setConfig("visual", "pseudocolor");
break;
case FB_VISUAL_DIRECTCOLOR:
fbdev->setConfig("visual", "directcolor");
break;
case FB_VISUAL_STATIC_PSEUDOCOLOR:
fbdev->setConfig("visual", "static_pseudocolor");
break;
}
if (fbi.accel != FB_ACCEL_NONE)
fbdev->addCapability("accelerated");
if (ioctl(fd[i], FBIOGET_VSCREENINFO, &fbconfig) == 0)
{
char vidmode[20];
unsigned int htotal = 0;
unsigned int vtotal = 0;
snprintf(vidmode, sizeof(vidmode), "%dx%d", fbconfig.xres,
fbconfig.yres);
fbdev->setConfig("mode", vidmode);
snprintf(vidmode, sizeof(vidmode), "%d", fbconfig.xres);
fbdev->setConfig("xres", vidmode);
snprintf(vidmode, sizeof(vidmode), "%d", fbconfig.yres);
fbdev->setConfig("yres", vidmode);
snprintf(vidmode, sizeof(vidmode), "%d", fbconfig.bits_per_pixel);
fbdev->setConfig("depth", vidmode);
vtotal =
fbconfig.upper_margin + fbconfig.yres + fbconfig.lower_margin +
fbconfig.vsync_len;
htotal =
fbconfig.left_margin + fbconfig.xres + fbconfig.right_margin +
fbconfig.hsync_len;
switch (fbconfig.vmode & FB_VMODE_MASK)
{
case FB_VMODE_INTERLACED:
vtotal >>= 1;
break;
case FB_VMODE_DOUBLE:
vtotal <<= 1;
break;
}
if (fbconfig.pixclock)
{
char freq[20];
double drate = 1E12 / fbconfig.pixclock;
double hrate = drate / htotal;
double vrate = hrate / vtotal;
snprintf(freq, sizeof(freq), "%5.2fHz", vrate);
fbdev->setConfig("frequency", freq);
}
}
}
}
}
else
break;
}
for (unsigned int j = 0; j < fbdevs; j++)
{
close(fd[j]);
}
return false;
}

7
src/core/fb.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _FB_H_
#define _FB_H_
#include "hw.h"
bool scan_fb(hwNode & n);
#endif

180
src/core/heuristics.cc Normal file
View File

@ -0,0 +1,180 @@
/*
* heuristics.cc
*
*
*/
#include "version.h"
#include "sysfs.h"
#include "jedec.h"
#include "osutils.h"
#include <stdlib.h>
#include <regex.h>
__ID("@(#) $Id$");
string guessBusInfo(const string & info)
{
// 2.6-style PCI
if(matches(info,"^[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]\\.[[:xdigit:]]$"))
{
return "pci@" + info;
}
// 2.4-style PCI
if(matches(info,"^[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]\\.[[:xdigit:]]$"))
{
return "pci@0000:" + info;
}
// USB: host-port[.port]:config.interface
if(matches(info, "^[0-9]+-[0-9]+(\\.[0-9]+)*:[0-9]+\\.[0-9]+$"))
{
size_t colon = info.rfind(":");
size_t dash = info.find("-");
return "usb@" + info.substr(0, dash) + ":" + info.substr(dash+1, colon-dash-1);
}
if(matches(info, "^[[:xdigit:]]+-[0-9]+$")) // Firewire: guid-function
{
size_t dash = info.find("-");
return "firewire@" + info.substr(0, dash);
}
#if 1
//#ifdef __hppa__
if(matches(info, "^[0-9]+(:[0-9]+)*$")) // PA-RISC: x:y:z:t corresponds to /x/y/z/t
{
string result = "parisc@";
for(unsigned i=0; i<info.length(); i++)
if(info[i] == ':')
result += '/';
else
result += info[i];
return result;
}
#endif
return "";
}
static string guessParentBusInfo(const hwNode & child)
{
string sysfs_path = sysfs_finddevice(child.getLogicalName());
vector < string > path;
string result = "";
if(sysfs_path == "") return "";
splitlines(sysfs_path, path, '/');
if(path.size()>1)
path.pop_back();
else
return "";
while((result=="") && (path.size()>1))
{
result = guessBusInfo(path[path.size()-1]);
path.pop_back();
}
return result;
}
hwNode * guessParent(const hwNode & child, hwNode & base)
{
return base.findChildByBusInfo(guessParentBusInfo(child));
}
static const char *disk_manufacturers[] =
{
"^ST(?!I\\ ).+", "Seagate",
"^STI\\ .+", "SimpleTech",
"^D...-.+", "IBM",
"^IBM.+", "IBM",
"^HITACHI.+", "Hitachi",
"^IC.+", "Hitachi",
"^HTS.+", "Hitachi",
"^FUJITSU.+", "Fujitsu",
"^MP.+", "Fujitsu",
"^TOSHIBA.+", "Toshiba",
"^MK.+", "Toshiba",
"^MAXTOR.+", "Maxtor",
"^Pioneer.+", "Pioneer",
"^PHILIPS.+", "Philips",
"^QUANTUM.+", "Quantum",
"FIREBALL.+", "Quantum",
"^WDC.+", "Western Digital",
"WD.+", "Western Digital",
"^VBOX.+", "VirtualBox",
NULL, NULL
};
bool guessVendor(hwNode & device)
{
int i = 0;
bool result = false;
device.setVendor(jedec_resolve(device.getVendor()));
if(device.getVendor() != "")
return false;
if(device.getClass() == hw::disk)
while (disk_manufacturers[i])
{
if (matches(device.getProduct().c_str(), disk_manufacturers[i], REG_ICASE))
{
device.setVendor(disk_manufacturers[i + 1]);
result = true;
}
i += 2;
}
return result;
}
static string parsehex(const string & s)
{
unsigned int i = 0;
string result = "";
if(matches(s,"^0x[[:xdigit:]][[:xdigit:]]+$"))
{
for(i=2; i<s.length(); i+=2)
{
string c = s.substr(i,2);
static char code[2];
code[0] = strtol(c.c_str(), NULL, 16);
code[1] = '\0';
if(code[0] < ' ') return s;
result += string(code);
}
}
else
return s;
return result;
}
bool guessProduct(hwNode & device)
{
string product = device.getProduct();
if(product == "")
return false;
device.setProduct(parsehex(product));
return true;
}

13
src/core/heuristics.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef _HEURISTICS_H_
#define _HEURISTICS_H_
#include "hw.h"
hwNode * guessParent(const hwNode & child, hwNode & base);
string guessBusInfo(const string &);
string guessParentBusInfo(const string &);
bool guessVendor(hwNode & device);
bool guessProduct(hwNode & device);
#endif

2462
src/core/hw.cc Normal file

File diff suppressed because it is too large Load Diff

240
src/core/hw.h Normal file
View File

@ -0,0 +1,240 @@
#ifndef _HW_H_
#define _HW_H_
#include <string>
#include <vector>
using namespace std;
namespace hw
{
typedef enum
{
system,
bridge,
memory,
processor,
address,
storage,
disk,
tape,
bus,
network,
display,
input,
printer,
multimedia,
communication,
power,
volume,
generic
} hwClass;
typedef enum { none, iomem, ioport, mem, irq, dma }
hwResourceType;
typedef enum { nil, boolean, integer, text }
hwValueType;
string strip(const string &);
string asString(long);
string reportSize(unsigned long long);
class resource
{
public:
resource();
~resource();
resource(const resource &);
resource & operator =(const resource &);
static resource iomem(unsigned long long, unsigned long long);
static resource ioport(unsigned long, unsigned long);
static resource mem(unsigned long long, unsigned long long, bool prefetchable = false);
static resource irq(unsigned int);
static resource dma(unsigned int);
bool operator ==(const resource &) const;
string asString(const string & separator = ":") const;
private:
struct resource_i * This;
};
class value
{
public:
value();
~value();
value(const value &);
value(long long);
value(const string &);
value & operator =(const value &);
bool operator ==(const value &) const;
string asString() const;
bool defined() const;
private:
struct value_i * This;
};
} // namespace hw
class hwNode
{
public:
hwNode(const string & id,
hw::hwClass c = hw::generic,
const string & vendor = "",
const string & product = "",
const string & version = "");
hwNode(const hwNode & o);
~hwNode();
hwNode & operator =(const hwNode & o);
string getId() const;
void setHandle(const string & handle);
string getHandle() const;
bool enabled() const;
bool disabled() const;
void enable();
void disable();
bool claimed() const;
void claim(bool claimchildren=false);
void unclaim();
hw::hwClass getClass() const;
const char * getClassName() const;
void setClass(hw::hwClass c);
string getDescription() const;
void setDescription(const string & description);
string getVendor() const;
void setVendor(const string & vendor);
string getSubVendor() const;
void setSubVendor(const string & subvendor);
string getProduct() const;
void setProduct(const string & product);
string getSubProduct() const;
void setSubProduct(const string & subproduct);
string getVersion() const;
void setVersion(const string & version);
string getDate() const;
void setDate(const string &);
string getSerial() const;
void setSerial(const string & serial);
unsigned long long getStart() const;
void setStart(unsigned long long start);
unsigned long long getSize() const;
void setSize(unsigned long long size);
unsigned long long getCapacity() const;
void setCapacity(unsigned long long capacity);
unsigned long long getClock() const;
void setClock(unsigned long long clock);
unsigned int getWidth() const;
void setWidth(unsigned int width);
string getSlot() const;
void setSlot(const string & slot);
string getModalias() const;
void setModalias(const string & modalias);
unsigned int countChildren(hw::hwClass c = hw::generic) const;
hwNode * getChild(unsigned int);
hwNode * getChildByPhysId(long);
hwNode * getChildByPhysId(const string &);
hwNode * getChild(const string & id);
hwNode * findChildByHandle(const string & handle);
hwNode * findChildByLogicalName(const string & handle);
hwNode * findChildByBusInfo(const string & businfo);
hwNode * findChildByResource(const hw::resource &);
hwNode * findChild(bool(*matchfunction)(const hwNode &));
hwNode * addChild(const hwNode & node);
bool isBus() const
{
return countChildren()>0;
}
bool isCapable(const string & feature) const;
void addCapability(const string & feature, const string & description = "");
void describeCapability(const string & feature, const string & description);
string getCapabilities() const;
vector<string> getCapabilitiesList() const;
string getCapabilityDescription(const string & feature) const;
void attractHandle(const string & handle);
void setConfig(const string & key, const string & value);
void setConfig(const string & key, unsigned long long value);
string getConfig(const string & key) const;
vector<string> getConfigKeys() const;
vector<string> getConfigValues(const string & separator = "") const;
vector<string> getLogicalNames() const;
string getLogicalName() const;
void setLogicalName(const string &);
string getDev() const;
void setDev(const string &);
string getBusInfo() const;
void setBusInfo(const string &);
string getPhysId() const;
void setPhysId(long);
void setPhysId(unsigned, unsigned);
void setPhysId(unsigned, unsigned, unsigned);
void setPhysId(const string &);
void assignPhysIds();
void addResource(const hw::resource &);
bool usesResource(const hw::resource &) const;
vector<string> getResources(const string & separator = "") const;
void addHint(const string &, const hw::value &);
hw::value getHint(const string &) const;
vector<string> getHints() const;
void merge(const hwNode & node);
void fixInconsistencies();
string asXML(unsigned level = 0);
string asJSON(unsigned level = 0);
string asString();
bool dump(const string & filename, bool recurse = true);
private:
void setId(const string & id);
bool attractsHandle(const string & handle) const;
bool attractsNode(const hwNode & node) const;
struct hwNode_i * This;
};
#endif

486
src/core/ide.cc Normal file
View File

@ -0,0 +1,486 @@
/*
* ide.cc
*
* This scan tries to detect all IDE interfaces in the system by scanning
* /proc/ide and looking for /proc/ide/xxx/channel
* It then tries to find the parent device for this interface (on 2.4 kernels,
* /proc/ide/xxx/identify contains useful information for PCI devices), other-
* wise, guessParent() is used.
* Each IDE-connected device is scanned and more information is gathered
* by calling scan_disk() and scan_cdrom(), as appropriate.
*/
#include "version.h"
#include "cpuinfo.h"
#include "osutils.h"
#include "cdrom.h"
#include "disk.h"
#include "heuristics.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <endian.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <ctype.h>
#include <vector>
#include <linux/hdreg.h>
__ID("@(#) $Id$");
#define PROC_IDE "/proc/ide"
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
#define IORDY_OFF 0x0400 /* 1=may be disabled */
#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
#define GEN_CONFIG 0 /* general configuration */
#define CD_ROM 5
#define NOT_ATA 0x8000
#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
#define EQPT_TYPE 0x1f00
static const char *description[] =
{
"Direct-access device", /* word 0, bits 12-8 = 00 */
"Sequential-access device", /* word 0, bits 12-8 = 01 */
"Printer", /* word 0, bits 12-8 = 02 */
"Processor", /* word 0, bits 12-8 = 03 */
"Write-once device", /* word 0, bits 12-8 = 04 */
"CD-ROM", /* word 0, bits 12-8 = 05 */
"Scanner", /* word 0, bits 12-8 = 06 */
"Optical memory", /* word 0, bits 12-8 = 07 */
"Medium changer", /* word 0, bits 12-8 = 08 */
"Communications device", /* word 0, bits 12-8 = 09 */
"ACS-IT8 device", /* word 0, bits 12-8 = 0a */
"ACS-IT8 device", /* word 0, bits 12-8 = 0b */
"Array controller", /* word 0, bits 12-8 = 0c */
"Enclosure services", /* word 0, bits 12-8 = 0d */
"Reduced block command device", /* word 0, bits 12-8 = 0e */
"Optical card reader/writer", /* word 0, bits 12-8 = 0f */
"", /* word 0, bits 12-8 = 10 */
"", /* word 0, bits 12-8 = 11 */
"", /* word 0, bits 12-8 = 12 */
"", /* word 0, bits 12-8 = 13 */
"", /* word 0, bits 12-8 = 14 */
"", /* word 0, bits 12-8 = 15 */
"", /* word 0, bits 12-8 = 16 */
"", /* word 0, bits 12-8 = 17 */
"", /* word 0, bits 12-8 = 18 */
"", /* word 0, bits 12-8 = 19 */
"", /* word 0, bits 12-8 = 1a */
"", /* word 0, bits 12-8 = 1b */
"", /* word 0, bits 12-8 = 1c */
"", /* word 0, bits 12-8 = 1d */
"", /* word 0, bits 12-8 = 1e */
"Unknown", /* word 0, bits 12-8 = 1f */
};
/* older kernels (2.2.x) have incomplete id structure for IDE devices */
#ifndef __NEW_HD_DRIVE_ID
#define command_set_1 command_sets
#define command_set_2 word83
#define hw_config word93
#endif
static unsigned long long get_longlong(const string & path)
{
FILE *in = fopen(path.c_str(), "r");
unsigned long long l = 0;
if (in)
{
if(fscanf(in, "%lld", &l) < 1)
l = 0;
fclose(in);
}
return l;
}
static string get_pciid(const string & bus,
const string & device)
{
char buffer[20];
int pcibus, pcidevfunc;
sscanf(bus.c_str(), "%x", &pcibus);
sscanf(device.c_str(), "%x", &pcidevfunc);
snprintf(buffer, sizeof(buffer), "%02x:%02x.%x", pcibus,
PCI_SLOT(pcidevfunc), PCI_FUNC(pcidevfunc));
return string(buffer);
}
static bool probe_ide(const string & name,
hwNode & device)
{
struct hd_driveid id;
const u_int8_t *id_regs = (const u_int8_t *) &id;
int fd = open(device.getLogicalName().c_str(), O_RDONLY | O_NONBLOCK);
if (fd < 0)
return false;
memset(&id, 0, sizeof(id));
if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0)
{
close(fd);
return false;
}
u_int8_t args[4 + 512] = { WIN_IDENTIFY, 0, 0, 1, };
if(id.config & 0x8000) // we have a packet device
{
args[0] = WIN_PIDENTIFY; // so use the right command to avoid kernel messages (Aborted Command)
device.addCapability("packet", "ATAPI packet device");
}
if (ioctl(fd, HDIO_DRIVE_CMD, &args) != 0)
{
close(fd);
return false;
}
close(fd);
u_int16_t pidentity[256];
for (int i = 0; i < 256; i++)
pidentity[i] = args[4 + 2 * i] + (args[4 + 2 * i + 1] << 8);
if (id.model[0])
device.setProduct(hw::strip(string((char *) id.model, sizeof(id.model))));
if (id.fw_rev[0])
device.
setVersion(hw::strip(string((char *) id.fw_rev, sizeof(id.fw_rev))));
if (id.serial_no[0])
device.
setSerial(hw::
strip(string((char *) id.serial_no, sizeof(id.serial_no))));
if (!(pidentity[GEN_CONFIG] & NOT_ATA))
{
device.addCapability("ata", "ATA");
device.setDescription("ATA Disk");
}
else if (!(pidentity[GEN_CONFIG] & NOT_ATAPI))
{
u_int8_t eqpt = (pidentity[GEN_CONFIG] & EQPT_TYPE) >> 8;
device.addCapability("atapi", "ATAPI");
if (eqpt == CD_ROM)
device.addCapability("cdrom", "can read CD-ROMs");
if (eqpt < 0x20)
device.setDescription("IDE " + string(description[eqpt]));
}
if (id.config & (1 << 7))
device.addCapability("removable", "support is removable");
if (id.config & (1 << 15))
device.addCapability("nonmagnetic", "support is non-magnetic (optical)");
if (id.capability & 1)
device.addCapability("dma", "Direct Memory Access");
if (id.capability & 2)
device.addCapability("lba", "Large Block Addressing");
if (id.capability & 8)
device.addCapability("iordy", "I/O ready reporting");
if (id.command_set_1 & 1)
device.addCapability("smart",
"S.M.A.R.T. (Self-Monitoring And Reporting Technology)");
if (id.command_set_1 & 2)
device.addCapability("security", "ATA security extensions");
if (id.command_set_1 & 4)
device.addCapability("removable", "support is removable");
if (id.command_set_1 & 8)
device.addCapability("pm", "Power Management");
if (id.command_set_2 & 8)
device.addCapability("apm", "Advanced Power Management");
if ((id.capability & 8) || (id.field_valid & 2))
{
if (id.field_valid & 4)
{
if (id.dma_ultra & 0x100)
device.setConfig("mode", "udma0");
if (id.dma_ultra & 0x200)
device.setConfig("mode", "udma1");
if (id.dma_ultra & 0x400)
device.setConfig("mode", "udma2");
if (id.hw_config & 0x2000)
{
if (id.dma_ultra & 0x800)
device.setConfig("mode", "udma3");
if (id.dma_ultra & 0x1000)
device.setConfig("mode", "udma4");
if (id.dma_ultra & 0x2000)
device.setConfig("mode", "udma5");
if (id.dma_ultra & 0x4000)
device.setConfig("mode", "udma6");
if (id.dma_ultra & 0x8000)
device.setConfig("mode", "udma7");
}
}
}
if (id_regs[83] & 8)
device.addCapability("apm", "Advanced Power Management");
//if (device.isCapable("iordy") && (id.capability & 4))
//device.setConfig("iordy", "yes");
if (device.isCapable("smart"))
{
if (id.command_set_2 & (1 << 14))
device.setConfig("smart", "on");
else
device.setConfig("smart", "off");
}
if (device.isCapable("apm"))
{
if (!(id_regs[86] & 8))
device.setConfig("apm", "off");
else
device.setConfig("apm", "on");
}
if (device.isCapable("lba"))
device.setCapacity((unsigned long long) id.lba_capacity * 512);
if (device.isCapable("removable"))
device.setCapacity(0); // we'll first have to make sure we have a disk
//if(pidentity[168] && (pidentity[168] & 0xfff8) == 0) {
switch(pidentity[168]) {
case 1:
device.setConfig("size", "5.25 inch");
break;
case 2:
device.setConfig("size", "3.5 inch");
break;
case 3:
device.setConfig("size", "2.5 inch");
break;
case 4:
device.setConfig("size", "1.8 inch");
break;
case 5:
device.setConfig("size", "less than 1.8 inch");
break;
}
//}
if (device.isCapable("cdrom"))
scan_cdrom(device);
else
scan_disk(device);
#if 0
if (!(iddata[GEN_CONFIG] & NOT_ATA))
device.addCapability("ata");
else if (iddata[GEN_CONFIG] == CFA_SUPPORT_VAL)
{
device.addCapability("ata");
device.addCapability("compactflash");
}
else if (!(iddata[GEN_CONFIG] & NOT_ATAPI))
{
device.addCapability("atapi");
device.setDescription(description[(iddata[GEN_CONFIG] & EQPT_TYPE) >> 8]);
}
if (iddata[START_MODEL])
device.setProduct(print_ascii((char *) &iddata[START_MODEL],
LENGTH_MODEL));
if (iddata[START_SERIAL])
device.
setSerial(print_ascii((char *) &iddata[START_SERIAL], LENGTH_SERIAL));
if (iddata[START_FW_REV])
device.
setVersion(print_ascii((char *) &iddata[START_FW_REV], LENGTH_FW_REV));
if (iddata[CAPAB_0] & LBA_SUP)
device.addCapability("lba");
if (iddata[CAPAB_0] & IORDY_SUP)
device.addCapability("iordy");
if (iddata[CAPAB_0] & IORDY_OFF)
{
device.addCapability("iordy");
device.addCapability("iordyoff");
}
if (iddata[CAPAB_0] & DMA_SUP)
device.addCapability("dma");
if (iddata[CAPAB_0] & DMA_IL_SUP)
{
device.addCapability("interleaved_dma");
device.addCapability("dma");
}
if (iddata[CAPAB_0] & CMD_Q_SUP)
device.addCapability("command_queuing");
if (iddata[CAPAB_0] & OVLP_SUP)
device.addCapability("overlap_operation");
#endif
return true;
}
static bool is_master(const string & device)
{
if (device == "")
return false;
switch ((device[device.length() - 1] - 'a') % 2)
{
case 0:
return true;
case 1:
return false;
default:
return false;
}
}
bool scan_ide(hwNode & n)
{
struct dirent **namelist;
int nentries;
pushd(PROC_IDE);
nentries = scandir(".", &namelist, selectdir, alphasort);
popd();
if (nentries < 0)
return false;
for (int i = 0; i < nentries; i++)
{
vector < string > config;
hwNode ide("ide",
hw::bus);
ide.setLogicalName(namelist[i]->d_name);
ide.setHandle("IDE:" + string(namelist[i]->d_name));
if (exists(string(PROC_IDE"/") + namelist[i]->d_name + "/channel"))
{
vector < string > identify;
string channel = "";
char *id = namelist[i]->d_name;
while ((*id != 0) && (!isdigit(*id)))
id++;
if (*id != 0)
{
ide.setBusInfo("ide@" + string(id));
ide.setPhysId(string(id));
}
loadfile(string(PROC_IDE"/") + namelist[i]->d_name + "/config", config);
if (config.size() > 0)
splitlines(config[0], identify, ' ');
config.clear();
loadfile(string(PROC_IDE"/") + namelist[i]->d_name + "/channel", config);
if (config.size() > 0)
channel = config[0];
config.clear();
//if (identify.size() >= 1)
{
struct dirent **devicelist;
int ndevices;
pushd(string(PROC_IDE) + "/" + namelist[i]->d_name);
ndevices = scandir(".", &devicelist, selectdir, alphasort);
popd();
for (int j = 0; j < ndevices; j++)
{
string basepath =
string(PROC_IDE) + "/" + namelist[i]->d_name + "/" +
devicelist[j]->d_name;
hwNode idedevice("device",
hw::storage);
idedevice =
hwNode(get_string(basepath + "/media", "disk"), hw::disk);
idedevice.setCapacity(512 * get_longlong(basepath + "/capacity"));
idedevice.setLogicalName(string("/dev/") + devicelist[j]->d_name);
idedevice.setProduct(get_string(basepath + "/model"));
idedevice.claim();
idedevice.setHandle(ide.getHandle() + ":" +
string(devicelist[j]->d_name));
if (is_master(devicelist[j]->d_name))
idedevice.setPhysId(0);
else
idedevice.setPhysId(1);
idedevice.setBusInfo(ide.getBusInfo() + "." +
idedevice.getPhysId());
probe_ide(devicelist[j]->d_name, idedevice);
ide.addChild(idedevice);
free(devicelist[j]);
}
free(devicelist);
ide.setDescription(hw::strip("IDE Channel " + hw::strip(channel)));
if ( identify.size() == 11 && identify[0] == "pci")
{
string businfo = guessBusInfo(get_pciid(identify[2], identify[4]));
hwNode *parent = n.findChildByBusInfo(businfo);
if (parent)
{
parent->claim();
ide.setClock(parent->getClock());
parent->addChild(ide);
}
}
else // we have to guess the parent device
{
hwNode * parent = guessParent(ide, n);
if(parent)
{
parent->claim();
ide.setClock(parent->getClock());
parent->addChild(ide);
}
else
for (unsigned int k = 0; k < ide.countChildren(); k++)
{
hwNode *candidate =
n.findChildByLogicalName(ide.getChild(k)->getLogicalName());
if (candidate)
{
parent = candidate;
candidate->merge(*ide.getChild(k));
break;
}
}
if(!parent) n.addChild(ide);
}
}
}
free(namelist[i]);
}
free(namelist);
return false;
}

7
src/core/ide.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _IDE_H_
#define _IDE_H_
#include "hw.h"
bool scan_ide(hwNode & n);
#endif

511
src/core/ideraid.cc Normal file
View File

@ -0,0 +1,511 @@
/*
* ideraid.cc
*
*/
#include "version.h"
#include "cpuinfo.h"
#include "osutils.h"
#include "cdrom.h"
#include "disk.h"
#include "heuristics.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <endian.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
#include <vector>
#include <linux/hdreg.h>
#include <regex.h>
__ID("@(#) $Id$");
#define DEV_TWE "/dev/twe"
#define IORDY_SUP 0x0800 /* 1=support; 0=may be supported */
#define IORDY_OFF 0x0400 /* 1=may be disabled */
#define LBA_SUP 0x0200 /* 1=Logical Block Address support */
#define DMA_SUP 0x0100 /* 1=Direct Memory Access support */
#define DMA_IL_SUP 0x8000 /* 1=interleaved DMA support (ATAPI) */
#define CMD_Q_SUP 0x4000 /* 1=command queuing support (ATAPI) */
#define OVLP_SUP 0x2000 /* 1=overlap operation support (ATAPI) */
#define GEN_CONFIG 0 /* general configuration */
#define CD_ROM 5
#define NOT_ATA 0x8000
#define NOT_ATAPI 0x4000 /* (check only if bit 15 == 1) */
#define EQPT_TYPE 0x1f00
static const char *description[] =
{
"Direct-access device", /* word 0, bits 12-8 = 00 */
"Sequential-access device", /* word 0, bits 12-8 = 01 */
"Printer", /* word 0, bits 12-8 = 02 */
"Processor", /* word 0, bits 12-8 = 03 */
"Write-once device", /* word 0, bits 12-8 = 04 */
"CD-ROM", /* word 0, bits 12-8 = 05 */
"Scanner", /* word 0, bits 12-8 = 06 */
"Optical memory", /* word 0, bits 12-8 = 07 */
"Medium changer", /* word 0, bits 12-8 = 08 */
"Communications device", /* word 0, bits 12-8 = 09 */
"ACS-IT8 device", /* word 0, bits 12-8 = 0a */
"ACS-IT8 device", /* word 0, bits 12-8 = 0b */
"Array controller", /* word 0, bits 12-8 = 0c */
"Enclosure services", /* word 0, bits 12-8 = 0d */
"Reduced block command device", /* word 0, bits 12-8 = 0e */
"Optical card reader/writer", /* word 0, bits 12-8 = 0f */
"", /* word 0, bits 12-8 = 10 */
"", /* word 0, bits 12-8 = 11 */
"", /* word 0, bits 12-8 = 12 */
"", /* word 0, bits 12-8 = 13 */
"", /* word 0, bits 12-8 = 14 */
"", /* word 0, bits 12-8 = 15 */
"", /* word 0, bits 12-8 = 16 */
"", /* word 0, bits 12-8 = 17 */
"", /* word 0, bits 12-8 = 18 */
"", /* word 0, bits 12-8 = 19 */
"", /* word 0, bits 12-8 = 1a */
"", /* word 0, bits 12-8 = 1b */
"", /* word 0, bits 12-8 = 1c */
"", /* word 0, bits 12-8 = 1d */
"", /* word 0, bits 12-8 = 1e */
"Unknown", /* word 0, bits 12-8 = 1f */
};
/* older kernels (2.2.x) have incomplete id structure for IDE devices */
#ifndef __NEW_HD_DRIVE_ID
#define command_set_1 command_sets
#define command_set_2 word83
#define hw_config word93
#endif
#define ATA_SMART_CMD 0xb0
#define ATA_IDENTIFY_DEVICE 0xec
#define TW_OP_ATA_PASSTHRU 0x11
#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108
#define TW_CMD_PACKET_WITH_DATA 0x1f
#define TW_MAX_SGL_LENGTH 62
typedef struct TAG_TW_Ioctl {
int input_length;
int output_length;
unsigned char cdb[16];
unsigned char opcode;
// This one byte of padding is missing from the typedefs in the
// kernel code, but it is indeed present. We put it explicitly
// here, so that the structure can be packed. Adam agrees with
// this.
unsigned char packing;
unsigned short table_id;
unsigned char parameter_id;
unsigned char parameter_size_bytes;
unsigned char unit_index;
// Size up to here is 30 bytes + 1 padding!
unsigned char input_data[499];
// Reserve lots of extra space for commands that set Sector Count
// register to large values
unsigned char output_data[512]; // starts 530 bytes in!
// two more padding bytes here if structure NOT packed.
} TW_Ioctl;
/* 512 is the max payload size: increase if needed */
#define TW_IOCTL_BUFFER_SIZE sizeof(TW_Ioctl)
#pragma pack(1)
/* Scatter gather list entry */
typedef struct TAG_TW_SG_Entry {
unsigned int address;
unsigned int length;
} TW_SG_Entry;
/* Command header for ATA pass-thru. Note that for different
drivers/interfaces the length of sg_list (here TW_ATA_PASS_SGL_MAX)
is different. But it can be taken as same for all three cases
because it's never used to define any other structures, and we
never use anything in the sg_list or beyond! */
#define TW_ATA_PASS_SGL_MAX 60
typedef struct TAG_TW_Passthru {
struct {
unsigned char opcode:5;
unsigned char sgloff:3;
} byte0;
unsigned char size;
unsigned char request_id;
struct {
unsigned char aport:4;
unsigned char host_id:4;
} byte3;
unsigned char status; // On return, contains 3ware STATUS register
unsigned char flags;
unsigned short param;
unsigned short features; // On return, contains ATA ERROR register
unsigned short sector_count;
unsigned short sector_num;
unsigned short cylinder_lo;
unsigned short cylinder_hi;
unsigned char drive_head;
unsigned char command; // On return, contains ATA STATUS register
TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX];
unsigned char padding[12];
} TW_Passthru;
/* Command Packet */
typedef struct TW_Command {
/* First DWORD */
struct {
unsigned char opcode:5;
unsigned char sgl_offset:3;
} byte0;
unsigned char size;
unsigned char request_id;
struct {
unsigned char unit:4;
unsigned char host_id:4;
} byte3;
/* Second DWORD */
unsigned char status;
unsigned char flags;
union {
unsigned short block_count;
unsigned short parameter_count;
unsigned short message_credits;
} byte6;
union {
struct {
uint32_t lba;
TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
uint32_t padding; /* pad to 512 bytes */
} io;
struct {
TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
uint32_t padding[2];
} param;
struct {
uint32_t response_queue_pointer;
uint32_t padding[125];
} init_connection;
struct {
char version[504];
} ioctl_miniport_version;
} byte8;
} TW_Command;
typedef struct TAG_TW_New_Ioctl {
unsigned int data_buffer_length;
unsigned char padding [508];
TW_Command firmware_command;
unsigned char data_buffer[1];
// three bytes of padding here
} TW_New_Ioctl;
static void fix_string(unsigned char * s, unsigned len)
{
unsigned char c;
while(len>1)
{
c = s[0];
s[0] = s[1];
s[1] = c;
s += 2;
len -= 2;
}
}
static bool guess_manufacturer(hwNode & device);
static bool probe_port(unsigned controller, unsigned disknum, hwNode & parent)
{
hwNode device("member:"+tostring(disknum), hw::disk);
struct hd_driveid id;
const u_int8_t *id_regs = (const u_int8_t *) &id;
string devname = string(DEV_TWE) + tostring(controller);
int fd = open(devname.c_str(), O_RDONLY | O_NONBLOCK);
unsigned char ioctl_buffer[2*TW_IOCTL_BUFFER_SIZE];
// only used for 6000/7000/8000 char device interface
TW_New_Ioctl *tw_ioctl_char=NULL;
TW_Passthru *passthru=NULL;
memset(ioctl_buffer, 0, sizeof(ioctl_buffer));
tw_ioctl_char = (TW_New_Ioctl *)ioctl_buffer;
tw_ioctl_char->data_buffer_length = 512;
passthru = (TW_Passthru *)&(tw_ioctl_char->firmware_command);
passthru->byte0.opcode = TW_OP_ATA_PASSTHRU;
passthru->request_id = 0xFF;
passthru->byte3.aport = disknum;
passthru->byte3.host_id = 0;
passthru->status = 0;
passthru->flags = 0x1;
passthru->drive_head = 0x0;
passthru->sector_num = 0;
passthru->byte0.sgloff = 0x5;
passthru->size = 0x7;
passthru->param = 0xD;
passthru->sector_count = 0x1;
passthru->command = ATA_IDENTIFY_DEVICE;
passthru->features = 0;
passthru->cylinder_lo = 0;
passthru->cylinder_hi = 0;
if (fd < 0)
return false;
memset(&id, 0, sizeof(id));
if (ioctl(fd, TW_CMD_PACKET_WITH_DATA, tw_ioctl_char) != 0)
{
close(fd);
return false;
}
close(fd);
device.setPhysId(disknum);
device.setBusInfo("raid@c" + tostring(controller) + "/p" + tostring(disknum));
device.setLogicalName("c" + tostring(controller) + "/p" + tostring(disknum));
device.claim();
u_int16_t pidentity[256];
for (int i = 0; i < 256; i++)
pidentity[i] = tw_ioctl_char->data_buffer[2 * i] + (tw_ioctl_char->data_buffer[2 * i + 1] << 8);
memcpy(&id, pidentity, sizeof(id));
fix_string(id.model, sizeof(id.model));
fix_string(id.fw_rev, sizeof(id.fw_rev));
fix_string(id.serial_no, sizeof(id.serial_no));
if (id.model[0])
device.setProduct(hw::strip(string((char *) id.model, sizeof(id.model))));
else
return false;
if (id.fw_rev[0])
device.
setVersion(hw::strip(string((char *) id.fw_rev, sizeof(id.fw_rev))));
else
return false;
if (id.serial_no[0])
device.
setSerial(hw::
strip(string((char *) id.serial_no, sizeof(id.serial_no))));
else
return false;
if (!(pidentity[GEN_CONFIG] & NOT_ATA))
{
device.addCapability("ata", "ATA");
device.setDescription("ATA Disk");
}
else if (!(pidentity[GEN_CONFIG] & NOT_ATAPI))
{
u_int8_t eqpt = (pidentity[GEN_CONFIG] & EQPT_TYPE) >> 8;
device.addCapability("atapi", "ATAPI");
if (eqpt == CD_ROM)
device.addCapability("cdrom", "can read CD-ROMs");
if (eqpt < 0x20)
device.setDescription("IDE " + string(description[eqpt]));
}
if (id.config & (1 << 7))
device.addCapability("removable", "support is removable");
if (id.config & (1 << 15))
device.addCapability("nonmagnetic", "support is non-magnetic (optical)");
if (id.capability & 1)
device.addCapability("dma", "Direct Memory Access");
if (id.capability & 2)
device.addCapability("lba", "Large Block Addressing");
if (id.capability & 8)
device.addCapability("iordy", "I/O ready reporting");
if (id.command_set_1 & 1)
device.addCapability("smart",
"S.M.A.R.T. (Self-Monitoring And Reporting Technology)");
if (id.command_set_1 & 2)
device.addCapability("security", "ATA security extensions");
if (id.command_set_1 & 4)
device.addCapability("removable", "support is removable");
if (id.command_set_1 & 8)
device.addCapability("pm", "Power Management");
if (id.command_set_2 & 8)
device.addCapability("apm", "Advanced Power Management");
if ((id.capability & 8) || (id.field_valid & 2))
{
if (id.field_valid & 4)
{
if (id.dma_ultra & 0x100)
device.setConfig("mode", "udma0");
if (id.dma_ultra & 0x200)
device.setConfig("mode", "udma1");
if (id.dma_ultra & 0x400)
device.setConfig("mode", "udma2");
if (id.hw_config & 0x2000)
{
if (id.dma_ultra & 0x800)
device.setConfig("mode", "udma3");
if (id.dma_ultra & 0x1000)
device.setConfig("mode", "udma4");
if (id.dma_ultra & 0x2000)
device.setConfig("mode", "udma5");
if (id.dma_ultra & 0x4000)
device.setConfig("mode", "udma6");
if (id.dma_ultra & 0x8000)
device.setConfig("mode", "udma7");
}
}
}
if (id_regs[83] & 8)
device.addCapability("apm", "Advanced Power Management");
//if (device.isCapable("iordy") && (id.capability & 4))
//device.setConfig("iordy", "yes");
if (device.isCapable("smart"))
{
if (id.command_set_2 & (1 << 14))
device.setConfig("smart", "on");
else
device.setConfig("smart", "off");
}
if (device.isCapable("apm"))
{
if (!(id_regs[86] & 8))
device.setConfig("apm", "off");
else
device.setConfig("apm", "on");
}
if (device.isCapable("lba"))
device.setCapacity((unsigned long long) id.lba_capacity * 512);
if (device.isCapable("removable"))
device.setCapacity(0); // we'll first have to make sure we have a disk
if (device.isCapable("cdrom"))
scan_cdrom(device);
else
scan_disk(device);
#if 0
if (!(iddata[GEN_CONFIG] & NOT_ATA))
device.addCapability("ata");
else if (iddata[GEN_CONFIG] == CFA_SUPPORT_VAL)
{
device.addCapability("ata");
device.addCapability("compactflash");
}
else if (!(iddata[GEN_CONFIG] & NOT_ATAPI))
{
device.addCapability("atapi");
device.setDescription(description[(iddata[GEN_CONFIG] & EQPT_TYPE) >> 8]);
}
if (iddata[START_MODEL])
device.setProduct(print_ascii((char *) &iddata[START_MODEL],
LENGTH_MODEL));
if (iddata[START_SERIAL])
device.
setSerial(print_ascii((char *) &iddata[START_SERIAL], LENGTH_SERIAL));
if (iddata[START_FW_REV])
device.
setVersion(print_ascii((char *) &iddata[START_FW_REV], LENGTH_FW_REV));
if (iddata[CAPAB_0] & LBA_SUP)
device.addCapability("lba");
if (iddata[CAPAB_0] & IORDY_SUP)
device.addCapability("iordy");
if (iddata[CAPAB_0] & IORDY_OFF)
{
device.addCapability("iordy");
device.addCapability("iordyoff");
}
if (iddata[CAPAB_0] & DMA_SUP)
device.addCapability("dma");
if (iddata[CAPAB_0] & DMA_IL_SUP)
{
device.addCapability("interleaved_dma");
device.addCapability("dma");
}
if (iddata[CAPAB_0] & CMD_Q_SUP)
device.addCapability("command_queuing");
if (iddata[CAPAB_0] & OVLP_SUP)
device.addCapability("overlap_operation");
#endif
guess_manufacturer(device);
parent.addChild(device);
return true;
}
static const char *manufacturers[] =
{
"^ST(?!I\\ ).+", "Seagate",
"^STI\\ .+", "SimpleTech",
"^D...-.+", "IBM",
"^IBM.+", "IBM",
"^HITACHI.+", "Hitachi",
"^IC.+", "Hitachi",
"^HTS.+", "Hitachi",
"^FUJITSU.+", "Fujitsu",
"^MP.+", "Fujitsu",
"^TOSHIBA.+", "Toshiba",
"^MK.+", "Toshiba",
"^MAXTOR.+", "Maxtor",
"^Pioneer.+", "Pioneer",
"^PHILIPS.+", "Philips",
"^QUANTUM.+", "Quantum",
"FIREBALL.+", "Quantum",
"^WDC.+", "Western Digital",
"WD.+", "Western Digital",
NULL, NULL
};
static bool guess_manufacturer(hwNode & device)
{
int i = 0;
bool result = false;
while (manufacturers[i])
{
if (matches(device.getProduct().c_str(), manufacturers[i], REG_ICASE))
{
device.setVendor(manufacturers[i + 1]);
result = true;
}
i += 2;
}
return result;
}
bool scan_ideraid(hwNode & n)
{
unsigned c = 0;
unsigned u = 0;
for(c=0; c<16; c++)
{
for(u=0; u<8; u++)
if(!probe_port(c,u,n))
break;
}
return true;
}

7
src/core/ideraid.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _IDERAID_H_
#define _IDERAID_H_
#include "hw.h"
bool scan_ideraid(hwNode & n);
#endif

1082
src/core/isapnp.cc Normal file

File diff suppressed because it is too large Load Diff

7
src/core/isapnp.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _ISAPNP_H_
#define _ISAPNP_H_
#include "hw.h"
bool scan_isapnp(hwNode & n);
#endif

90
src/core/jedec.cc Normal file
View File

@ -0,0 +1,90 @@
#include "jedec.h"
#include "hw.h"
#include "osutils.h"
#include <regex.h>
#include <string>
#include <iostream>
using namespace std;
static const char * jedec_id[] = {
"01", "AMD",
"8001", "AMD",
"02", "AMI",
"8002", "AMI",
"04", "Fujitsu",
"8004", "Fujitsu",
"0500", "Elpida",
"07", "Hitachi",
"8007", "Hitachi",
"08", "Inmos",
"8008", "Inmos",
"0B", "Intersil",
"800B", "Intersil",
"0D", "Mostek",
"800D", "Mostek",
"0E", "Freescale (Motorola)",
"800E", "Freescale (Motorola)",
"10", "NEC",
"8010", "NEC",
"13", "Conexant (Rockwell)",
"8013", "Conexant (Rockwell)",
"15", "NXP (Philips Semi, Signetics)",
"8015", "NXP (Philips Semi, Signetics)",
"16", "Synertek",
"8016", "Synertek",
"19", "Xicor",
"8019", "Xicor",
"1A", "Zilog",
"801A", "Zilog",
"1C", "Mitsubishi",
"801C", "Mitsubishi",
"2C", "Micron Technology",
"802C", "Micron Technology",
"40", "ProMOS/Mosel Vitelic",
"8040", "ProMOS/Mosel Vitelic",
"6A", "Goldenram",
"806A", "Goldenram",
"7F7F7F0B", "Nanya Technology",
"830B", "Nanya Technology",
"83", "Fairchild",
"8083", "Fairchild",
"89", "Numonyx (Intel)",
"8089", "Numonyx (Intel)",
"91", "DATARAM",
"8091", "DATARAM",
"98", "Toshiba",
"8098", "Toshiba",
"A4", "IBM",
"80A4", "IBM",
"AD", "Hynix Semiconductor (Hyundai Electronics)",
"80AD", "Hynix Semiconductor (Hyundai Electronics)",
"C1", "Infineon (Siemens)",
"80C1", "Infineon (Siemens)",
"7F7F7F7F7F51", "Infineon (Siemens)",
"CE", "Samsung",
"80CE", "Samsung",
"DE", "Winbond Electronics",
"80DE", "Winbond Electronics",
"E0", "LG Semiconductor (Goldstar)",
"80E0", "LG Semiconductor (Goldstar)",
"7F45", "Micron CMS",
"7F98", "Kingston",
"7F7F7F7F43", "Ramaxel Technology",
NULL, NULL
};
string jedec_resolve(const string & s)
{
string result = hw::strip(s);
if(matches(result, "^0x"))
result.erase(0, 2);
if(!matches(result, "^[0-9a-fA-F]+$")) return s;
for(int i=0; jedec_id[i]; i+=2) {
if(matches(result, "^" + string(jedec_id[i]), REG_ICASE)) return string(jedec_id[i+1]);
}
return s;
}

8
src/core/jedec.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _JEDEC_H_
#define _JEDEC_H_
#include <string>
std::string jedec_resolve(const std::string &);
#endif

145
src/core/lvm.cc Normal file
View File

@ -0,0 +1,145 @@
/*
* lvm.cc
*
* This scan reports LVM-related information by looking for LVM2 structures
* So far, the following information is reported:
* - presence of LVM2 on-disk structures
* - size of LVM2 physical volume
* - UUID of LVM2 physical volume
*
*/
#include "version.h"
#include "config.h"
#include "lvm.h"
#include "osutils.h"
#include <string.h>
__ID("@(#) $Id$");
#define LABEL_ID "LABELONE"
#define LABEL_SIZE BLOCKSIZE /* Think very carefully before changing this */
#define LABEL_SCAN_SECTORS 4L
#define INITIAL_CRC 0xf597a6cf
/* On disk - 32 bytes */
struct label_header
{
uint8_t id[8]; /* LABELONE */
uint64_t sector_xl; /* Sector number of this label */
uint32_t crc_xl; /* From next field to end of sector */
uint32_t offset_xl; /* Offset from start of struct to contents */
uint8_t type[8]; /* LVM2 001 */
} __attribute__ ((packed));
/* On disk */
struct disk_locn
{
uint64_t offset; /* Offset in bytes to start sector */
uint64_t size; /* Bytes */
} __attribute__ ((packed));
#define ID_LEN 32
/* Fields with the suffix _xl should be xlate'd wherever they appear */
/* On disk */
struct pv_header
{
uint8_t pv_uuid[ID_LEN];
/* This size can be overridden if PV belongs to a VG */
uint64_t device_size_xl; /* Bytes */
/* NULL-terminated list of data areas followed by */
/* NULL-terminated list of metadata area headers */
struct disk_locn disk_areas_xl[0]; /* Two lists */
} __attribute__ ((packed));
/* In core */
struct label
{
char type[8];
uint64_t sector;
struct labeller *labeller;
void *info;
};
/* Calculate an endian-independent CRC of supplied buffer */
uint32_t calc_crc(uint32_t initial, void *buf, uint32_t size)
{
static const uint32_t crctab[] =
{
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
uint32_t i, crc = initial;
uint8_t *data = (uint8_t *) buf;
for(i = 0; i < size; i++)
{
crc ^= *data++;
crc = (crc >> 4) ^ crctab[crc & 0xf];
crc = (crc >> 4) ^ crctab[crc & 0xf];
}
return crc;
}
static const char *id = "@(#) $Id$";
static string uuid(void * s)
{
char * id = (char*)s;
return string(id ,6)+"-"+
string(id+ 6,4)+"-"+
string(id+10,4)+"-"+
string(id+14,4)+"-"+
string(id+18,4)+"-"+
string(id+22,4)+"-"+
string(id+26,6);
}
bool scan_lvm(hwNode & n, source & s)
{
uint8_t sector[BLOCKSIZE];
label_header lh;
if(s.blocksize != BLOCKSIZE)
return false;
for(uint32_t i=0; i<4; i++)
{
if(readlogicalblocks(s, sector, i, 1) != 1)
return false;
memcpy(&lh, sector, sizeof(lh));
lh.sector_xl = le_longlong(sector+8);
lh.crc_xl = le_long(sector+0x10);
lh.offset_xl = le_long(sector+0x14);
if((strncmp((char*)lh.id, LABEL_ID, sizeof(lh.id))==0) &&
(lh.sector_xl==i) &&
(lh.offset_xl < BLOCKSIZE) &&
(calc_crc(INITIAL_CRC, sector+0x14, LABEL_SIZE-0x14)==lh.crc_xl))
{
pv_header pvh;
memcpy(&pvh, sector+lh.offset_xl, sizeof(pvh));
if(n.getDescription()=="")
n.setDescription(_("Linux LVM Physical Volume"));
n.addCapability("lvm2");
n.setSerial(uuid(pvh.pv_uuid));
if(n.getCapacity()==0)
n.setCapacity(n.getSize());
n.setSize(le_longlong(&pvh.device_size_xl));
return true;
}
}
(void) &id; // avoid warning "id defined but not used"
return false;
}

8
src/core/lvm.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _LVM_H_
#define _LVM_H_
#include "hw.h"
#include "blockio.h"
bool scan_lvm(hwNode & n, source & s);
#endif

168
src/core/main.cc Normal file
View File

@ -0,0 +1,168 @@
/*
* main.cc
*
* this module is shared between the command-line and graphical interfaces of
* lshw (currently, only the text interface is available).
*
* It calls all the defined scans in a certain order that tries to ensure
* that devices are only reported once and that information coming from
* different sources about a given device is kept consistent.
*
* Individual tests can be disabled on the command-line by using the -disable
* option.
* Status is reported during the execution of tests.
*
*/
#include "hw.h"
#include "print.h"
#include "version.h"
#include "options.h"
#include "mem.h"
#include "dmi.h"
#include "cpuinfo.h"
#include "cpuid.h"
#include "device-tree.h"
#include "pci.h"
#include "pcmcia.h"
#include "pcmcia-legacy.h"
#include "ide.h"
#include "scsi.h"
#include "spd.h"
#include "network.h"
#include "isapnp.h"
#include "pnp.h"
#include "fb.h"
#include "usb.h"
#include "sysfs.h"
#include "display.h"
#include "parisc.h"
#include "cpufreq.h"
#include "ideraid.h"
#include "mounts.h"
#include "virtio.h"
#include "vio.h"
#include "smp.h"
#include "abi.h"
#include "s390.h"
#include <unistd.h>
#include <stdio.h>
__ID("@(#) $Id$");
bool scan_system(hwNode & system)
{
char hostname[80];
if (gethostname(hostname, sizeof(hostname)) == 0)
{
hwNode computer(::enabled("output:sanitize")?"computer":hostname,
hw::system);
status("DMI");
if (enabled("dmi"))
scan_dmi(computer);
status("SMP");
if (enabled("smp"))
scan_smp(computer);
status("PA-RISC");
if (enabled("parisc"))
scan_parisc(computer);
status("device-tree");
if (enabled("device-tree"))
scan_device_tree(computer);
status("SPD");
if (enabled("spd"))
scan_spd(computer);
status("memory");
if (enabled("memory"))
scan_memory(computer);
status("/proc/cpuinfo");
if (enabled("cpuinfo"))
scan_cpuinfo(computer);
status("CPUID");
if (enabled("cpuid"))
scan_cpuid(computer);
status("PCI (sysfs)");
if (enabled("pci"))
{
if(!scan_pci(computer))
{
if (enabled("pcilegacy"))
scan_pci_legacy(computer);
}
}
else
{
status("PCI (legacy)");
if (enabled("pcilegacy"))
scan_pci_legacy(computer);
}
status("ISA PnP");
if (enabled("isapnp"))
scan_isapnp(computer);
status("PnP (sysfs)");
if (enabled("pnp"))
scan_pnp(computer);
status("PCMCIA");
if (enabled("pcmcia"))
scan_pcmcia(computer);
status("PCMCIA");
if (enabled("pcmcia-legacy"))
scan_pcmcialegacy(computer);
status("Virtual I/O (VIRTIO) devices");
if (enabled("virtio"))
scan_virtio(computer);
status("IBM Virtual I/O (VIO)");
if (enabled("vio"))
scan_vio(computer);
status("kernel device tree (sysfs)");
if (enabled("sysfs"))
scan_sysfs(computer);
status("USB");
if (enabled("usb"))
scan_usb(computer);
status("IDE");
if (enabled("ide"))
scan_ide(computer);
if (enabled("ideraid"))
scan_ideraid(computer);
status("SCSI");
if (enabled("scsi"))
scan_scsi(computer);
status("S/390 devices");
if (enabled("s390"))
scan_s390_devices(computer);
if (enabled("mounts"))
scan_mounts(computer);
status("Network interfaces");
if (enabled("network"))
scan_network(computer);
status("Framebuffer devices");
if (enabled("fb"))
scan_fb(computer);
status("Display");
if (enabled("display"))
scan_display(computer);
status("CPUFreq");
if (enabled("cpufreq"))
scan_cpufreq(computer);
status("ABI");
if (enabled("abi"))
scan_abi(computer);
status("");
if (computer.getDescription() == "")
computer.setDescription("Computer");
computer.assignPhysIds();
computer.fixInconsistencies();
system = computer;
}
else
return false;
return true;
}

7
src/core/main.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _MAIN_H_
#define _MAIN_H_
#include "hw.h"
bool scan_system(hwNode & system);
#endif

171
src/core/mem.cc Normal file
View File

@ -0,0 +1,171 @@
/*
* mem.cc
*
* This scan tries to guess the size of system memory by looking at several
* sources:
* - the size of /proc/kcore
* - the value returned by the sysconf libc function
* - the sum of sizes of kernel hotplug memory blocks
* - the sum of sizes of individual memory banks
*
* NOTE: In the first two cases this guess can be widely inaccurate, as the
* kernel itself limits the memory addressable by userspace processes.
* Because of that, this module reports the biggest value found if it can't
* access the size of individual memory banks (information filled in by other
* scans like DMI (on PCs) or OpenFirmare device-tree (on Macs).
*
*/
#include "version.h"
#include "config.h"
#include "sysfs.h"
#include "mem.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
__ID("@(#) $Id$");
static unsigned long long get_kcore_size()
{
struct stat buf;
if (stat("/proc/kcore", &buf) != 0)
return 0;
else
return buf.st_size;
}
static unsigned long long get_sysconf_size()
{
long pagesize = 0;
long physpages = 0;
unsigned long long logicalmem = 0;
pagesize = sysconf(_SC_PAGESIZE);
physpages = sysconf(_SC_PHYS_PAGES);
if ((pagesize > 0) && (physpages > 0))
logicalmem =
(unsigned long long) pagesize *(unsigned long long) physpages;
return logicalmem;
}
static unsigned long long get_hotplug_size()
{
vector < sysfs::entry > entries = sysfs::entries_by_bus("memory");
if (entries.empty())
return 0;
unsigned long long memblocksize =
sysfs::entry::byPath("/system/memory").hex_attr("block_size_bytes");
if (memblocksize == 0)
return 0;
unsigned long long totalsize = 0;
for (vector < sysfs::entry >::iterator it = entries.begin();
it != entries.end(); ++it)
{
const sysfs::entry & e = *it;
if (e.string_attr("online") != "1")
continue;
totalsize += memblocksize;
}
return totalsize;
}
static unsigned long long count_memorybanks_size(hwNode & n)
{
hwNode *memory = n.getChild("core/memory");
if (memory)
{
unsigned long long size = 0;
memory->claim(true); // claim memory and all its children
for (unsigned int i = 0; i < memory->countChildren(); i++)
if (memory->getChild(i)->getClass() == hw::memory)
size += memory->getChild(i)->getSize();
memory->setSize(size);
return size;
}
else
return 0;
}
static void claim_memory(hwNode & n)
{
hwNode *core = n.getChild("core");
if (core)
{
for (unsigned int i = 0; i < core->countChildren(); i++)
if (core->getChild(i)->getClass() == hw::memory)
if(core->getChild(i)->claimed())
core->getChild(i)->claim(true); // claim memory and all its children
}
}
bool scan_memory(hwNode & n)
{
hwNode *memory = n.getChild("core/memory");
unsigned long long logicalmem = 0;
unsigned long long kcore = 0;
unsigned long long hotplug_size = 0;
logicalmem = get_sysconf_size();
kcore = get_kcore_size();
hotplug_size = get_hotplug_size();
count_memorybanks_size(n);
claim_memory(n);
if (!memory)
{
hwNode *core = n.getChild("core");
if (!core)
{
n.addChild(hwNode("core", hw::bus));
core = n.getChild("core");
}
if (core)
{
core->addChild(hwNode("memory", hw::memory));
memory = core->getChild("memory");
}
}
if (memory)
{
memory->claim();
memory->addHint("icon", string("memory"));
if (memory->getDescription() == "")
memory->setDescription(_("System memory"));
if (memory->getSize() > logicalmem) // we already have a value
return true;
if (hotplug_size > logicalmem)
memory->setSize(hotplug_size);
else if ((logicalmem == 0)
|| ((kcore > logicalmem) && (kcore < 2 * logicalmem)))
memory->setSize(kcore);
else
memory->setSize(logicalmem);
return true;
}
return false;
}

7
src/core/mem.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _MEM_H_
#define _MEM_H_
#include "hw.h"
bool scan_memory(hwNode & n);
#endif

125
src/core/mounts.cc Normal file
View File

@ -0,0 +1,125 @@
/*
* mounts.cc
*
*
*/
#include "version.h"
#include "mounts.h"
#include "osutils.h"
#include <vector>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
__ID("@(#) $Id$");
#define MOUNTS "/proc/mounts"
static bool has_device(const string & dev, hwNode & n)
{
string devid = get_devid(dev);
vector <string> lnames;
size_t i;
if(devid == "")
return false;
if(get_devid(dev) == n.getDev())
return true;
lnames = n.getLogicalNames();
for(i=0; i<lnames.size(); i++)
{
if(get_devid(lnames[i]) == devid)
return true;
}
return false;
}
// unescape octal-encoded "special" characters:
// "/this\040is\040a\040test" --> "/this is a test"
static string unescape(string s)
{
size_t backslash = 0;
string result = s;
while((backslash=result.find('\\', backslash)) != string::npos)
{
string code = result.substr(backslash+1,3);
if(matches(code, "^[0-9][0-9][0-9]$"))
{
result[backslash] = (char)strtol(code.c_str(), NULL, 8); // value is octal
result.erase(backslash+1,3);
}
backslash++;
}
return result;
}
static void update_mount_status(hwNode & n, const vector <string> & mount)
{
unsigned i;
if(has_device(mount[0], n))
{
n.setConfig("state", "mounted");
n.setLogicalName(mount[1]); // mountpoint
n.setConfig("mount.fstype", mount[2]);
n.setConfig("mount.options", mount[3]);
}
for(i=0; i<n.countChildren(); i++)
update_mount_status(*n.getChild(i), mount);
}
static bool process_mount(const string & s, hwNode & n)
{
vector <string> mount;
struct stat buf;
// entries' format is
// devicenode mountpoint fstype mountoptions dumpfrequency pass
if(splitlines(s, mount, ' ') != 6)
{
mount.clear();
if(splitlines(s, mount, '\t') != 6)
return false;
}
mount[0] = unescape(mount[0]);
mount[1] = unescape(mount[1]);
if(mount[0][0] != '/') // devicenode isn't a full path
return false;
if(stat(mount[0].c_str(), &buf) != 0)
return false;
if(!S_ISBLK(buf.st_mode)) // we're only interested in block devices
return false;
update_mount_status(n, mount);
return true;
}
bool scan_mounts(hwNode & n)
{
vector <string> mounts;
size_t i;
if(!loadfile(MOUNTS, mounts))
return false;
for(i=0; i<mounts.size(); i++)
process_mount(mounts[i], n);
return true;
}

7
src/core/mounts.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _MOUNTS_H_
#define _MOUNTS_H_
#include "hw.h"
bool scan_mounts(hwNode & n);
#endif

570
src/core/network.cc Normal file
View File

@ -0,0 +1,570 @@
/*
* network.cc
*
* This scan uses the same IOCTLs as ethtool, ifconfig or mii-diag to report
* information about network interfaces like:
* - medium type (ethernet, token ring, PPP, etc.)
* - hardware address (MAC address)
* - link status (link detected, in error, etc.)
* - speed (10Mbits, 100Mbits, etc.)
* - IP addressing
*
* As network interfaces can be plugged on PCI, PCMCIA, ISA, USB, etc. this
* scan should be executed after all bus-related scans.
*
*/
#include "version.h"
#include "config.h"
#include "network.h"
#include "osutils.h"
#include "sysfs.h"
#include "options.h"
#include "heuristics.h"
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if_arp.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <string>
#include <sys/types.h>
using namespace std;
__ID("@(#) $Id$");
#ifndef ARPHRD_IEEE1394
#define ARPHRD_IEEE1394 24
#endif
#ifndef ARPHRD_SIT
#define ARPHRD_SIT 776
#endif
#ifndef SIOCETHTOOL
#define SIOCETHTOOL 0x8946
#endif
typedef unsigned long long u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
struct ethtool_cmd
{
u32 cmd;
u32 supported; /* Features this interface supports */
u32 advertising; /* Features this interface advertises */
u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */
u8 duplex; /* Duplex, half or full */
u8 port; /* Which connector port */
u8 phy_address;
u8 transceiver; /* Which tranceiver to use */
u8 autoneg; /* Enable or disable autonegotiation */
u32 maxtxpkt; /* Tx pkts before generating tx int */
u32 maxrxpkt; /* Rx pkts before generating rx int */
u32 reserved[4];
};
#ifndef IFNAMSIZ
#define IFNAMSIZ 32
#endif
#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
* Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... */
#define ETHTOOL_BUSINFO_LEN 32
/* these strings are set to whatever the driver author decides... */
struct ethtool_drvinfo
{
u32 cmd;
char driver[32]; /* driver short name, "tulip", "eepro100" */
char version[32]; /* driver version string */
char fw_version[32]; /* firmware version string, if applicable */
char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
/*
* For PCI devices, use pci_dev->slot_name.
*/
char reserved1[32];
char reserved2[16];
u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */
u32 testinfo_len;
u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
};
/* for passing single values */
struct ethtool_value
{
u32 cmd;
u32 data;
};
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* Get settings. */
#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
/* Indicates what features are supported by the interface. */
#define SUPPORTED_10baseT_Half (1 << 0)
#define SUPPORTED_10baseT_Full (1 << 1)
#define SUPPORTED_100baseT_Half (1 << 2)
#define SUPPORTED_100baseT_Full (1 << 3)
#define SUPPORTED_1000baseT_Half (1 << 4)
#define SUPPORTED_1000baseT_Full (1 << 5)
#define SUPPORTED_Autoneg (1 << 6)
#define SUPPORTED_TP (1 << 7)
#define SUPPORTED_AUI (1 << 8)
#define SUPPORTED_MII (1 << 9)
#define SUPPORTED_FIBRE (1 << 10)
#define SUPPORTED_BNC (1 << 11)
#define SUPPORTED_10000baseT_Full (1 << 12)
/* The forced speed, 10Mb, 100Mb, gigabit, 10GbE. */
#define SPEED_10 10
#define SPEED_100 100
#define SPEED_1000 1000
#define SPEED_10000 10000
/* Duplex, half or full. */
#define DUPLEX_HALF 0x00
#define DUPLEX_FULL 0x01
/* Which connector port. */
#define PORT_TP 0x00
#define PORT_AUI 0x01
#define PORT_MII 0x02
#define PORT_FIBRE 0x03
#define PORT_BNC 0x04
/* Which tranceiver to use. */
#define XCVR_INTERNAL 0x00
#define XCVR_EXTERNAL 0x01
#define XCVR_DUMMY1 0x02
#define XCVR_DUMMY2 0x03
#define XCVR_DUMMY3 0x04
#define AUTONEG_DISABLE 0x00
#define AUTONEG_ENABLE 0x01
bool load_interfaces(vector < string > &interfaces)
{
vector < string > procnetdev;
interfaces.clear();
if (!loadfile("/proc/net/dev", procnetdev))
return false;
if (procnetdev.size() <= 2)
return false;
// get rid of header (2 lines)
procnetdev.erase(procnetdev.begin());
procnetdev.erase(procnetdev.begin());
for (unsigned int i = 0; i < procnetdev.size(); i++)
{
// extract interfaces names
size_t pos = procnetdev[i].find(':');
if (pos != string::npos)
interfaces.push_back(hw::strip(procnetdev[i].substr(0, pos)));
}
return true;
}
static int maclen(unsigned family = ARPHRD_ETHER)
{
switch(family)
{
case ARPHRD_INFINIBAND:
return 20;
case ARPHRD_ETHER:
return 6;
default:
return 14;
}
}
static string getmac(const unsigned char *mac, unsigned family = ARPHRD_ETHER)
{
char buff[5];
string result = "";
bool valid = false;
for (int i = 0; i < maclen(family); i++)
{
snprintf(buff, sizeof(buff), "%02x", mac[i]);
valid |= (mac[i] != 0);
if (i == 0)
result = string(buff);
else
result += ":" + string(buff);
}
if (valid)
return result;
else
return "";
}
static const char *hwname(int t)
{
switch (t)
{
case ARPHRD_ETHER:
return _("Ethernet");
case ARPHRD_SLIP:
return _("SLIP");
case ARPHRD_LOOPBACK:
return _("loopback");
case ARPHRD_FDDI:
return _("FDDI");
case ARPHRD_IEEE1394:
return _("IEEE1394");
case ARPHRD_IRDA:
return _("IRDA");
case ARPHRD_PPP:
return _("PPP");
case ARPHRD_X25:
return _("X25");
case ARPHRD_TUNNEL:
return _("IPtunnel");
case ARPHRD_DLCI:
return _("Framerelay.DLCI");
case ARPHRD_FRAD:
return _("Framerelay.AD");
case ARPHRD_TUNNEL6:
return _("IP6tunnel");
case ARPHRD_SIT:
return _("IP6inIP4");
default:
return "";
}
}
static string print_ip(struct sockaddr_in *in)
{
return string(inet_ntoa(in->sin_addr));
}
static void scan_ip(hwNode & interface)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd > 0)
{
struct ifreq ifr;
// get IP address
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
{
// IP address is in ifr.ifr_addr
interface.setConfig("ip", ::enabled("output:sanitize")?REMOVED:print_ip((sockaddr_in *) (&ifr.ifr_addr)));
strcpy(ifr.ifr_name, interface.getLogicalName().c_str());
if ((interface.getConfig("point-to-point") == "yes")
&& (ioctl(fd, SIOCGIFDSTADDR, &ifr) == 0))
{
// remote PPP address is in ifr.ifr_dstaddr
interface.setConfig("remoteip",
print_ip((sockaddr_in *) & ifr.ifr_dstaddr));
}
}
close(fd);
}
}
static bool isVirtual(const string & MAC)
{
if (MAC.length() < 8)
return false;
string manufacturer = uppercase(MAC.substr(0, 8));
if ((manufacturer == "00:05:69") ||
(manufacturer == "00:0C:29") || (manufacturer == "00:50:56"))
return true; // VMware
if (manufacturer == "00:1C:42")
return true; // Parallels
if (manufacturer == "0A:00:27")
return true; // VirtualBox
return false;
}
bool scan_network(hwNode & n)
{
vector < string > interfaces;
char buffer[2 * IFNAMSIZ + 1];
if (!load_interfaces(interfaces))
return false;
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd >= 0)
{
struct ifreq ifr;
struct ethtool_drvinfo drvinfo;
struct ethtool_cmd ecmd;
struct ethtool_value edata;
for (unsigned int i = 0; i < interfaces.size(); i++)
{
hwNode *existing;
hwNode interface("network",
hw::network);
interface.setLogicalName(interfaces[i]);
interface.claim();
interface.addHint("icon", string("network"));
string businfo = sysfs::entry::byClass("net", interface.getLogicalName()).businfo();
if (businfo!="")
interface.setBusInfo(businfo);
interface.setModalias(sysfs::entry::byClass("net", interface.getLogicalName()).modalias());
//scan_mii(fd, interface);
scan_ip(interface);
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, interfaces[i].c_str());
if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
{
#ifdef IFF_PORTSEL
if (ifr.ifr_flags & IFF_PORTSEL)
{
if (ifr.ifr_flags & IFF_AUTOMEDIA)
interface.setConfig("automedia", "yes");
}
#endif
if (ifr.ifr_flags & IFF_UP)
interface.enable();
else
interface.disable();
if (ifr.ifr_flags & IFF_BROADCAST)
interface.setConfig("broadcast", "yes");
if (ifr.ifr_flags & IFF_DEBUG)
interface.setConfig("debug", "yes");
if (ifr.ifr_flags & IFF_LOOPBACK)
interface.setConfig("loopback", "yes");
if (ifr.ifr_flags & IFF_POINTOPOINT)
interface.setConfig("point-to-point", "yes");
if (ifr.ifr_flags & IFF_PROMISC)
interface.setConfig("promiscuous", "yes");
if (ifr.ifr_flags & IFF_SLAVE)
interface.setConfig("slave", "yes");
if (ifr.ifr_flags & IFF_MASTER)
interface.setConfig("master", "yes");
if (ifr.ifr_flags & IFF_MULTICAST)
interface.setConfig("multicast", "yes");
}
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, interfaces[i].c_str());
// get MAC address
if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0)
{
string hwaddr = getmac((unsigned char *) ifr.ifr_hwaddr.sa_data, ifr.ifr_hwaddr.sa_family);
interface.addCapability(hwname(ifr.ifr_hwaddr.sa_family));
if (ifr.ifr_hwaddr.sa_family >= 256)
interface.addCapability("logical", _("Logical interface"));
else
interface.addCapability("physical", _("Physical interface"));
interface.setDescription(string(hwname(ifr.ifr_hwaddr.sa_family)) +
" interface");
interface.setSerial(hwaddr);
if (isVirtual(interface.getSerial()))
interface.addCapability("logical", _("Logical interface"));
}
// check for wireless extensions
memset(buffer, 0, sizeof(buffer));
strncpy(buffer, interfaces[i].c_str(), sizeof(buffer));
if (ioctl(fd, SIOCGIWNAME, &buffer) == 0)
{
interface.addCapability("wireless", _("Wireless-LAN"));
interface.setConfig("wireless", hw::strip(buffer + IFNAMSIZ));
interface.setDescription(_("Wireless interface"));
interface.addHint("icon", string("wifi"));
interface.addHint("bus.icon", string("radio"));
}
edata.cmd = ETHTOOL_GLINK;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, interfaces[i].c_str());
ifr.ifr_data = (caddr_t) &edata;
if (ioctl(fd, SIOCETHTOOL, &ifr) == 0)
{
interface.setConfig("link", edata.data ? "yes":"no");
}
ecmd.cmd = ETHTOOL_GSET;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, interfaces[i].c_str());
ifr.ifr_data = (caddr_t) &ecmd;
if (ioctl(fd, SIOCETHTOOL, &ifr) == 0)
{
if(ecmd.supported & SUPPORTED_TP)
interface.addCapability("tp", _("twisted pair"));
if(ecmd.supported & SUPPORTED_AUI)
interface.addCapability("aui", _("AUI"));
if(ecmd.supported & SUPPORTED_BNC)
interface.addCapability("bnc", _("BNC"));
if(ecmd.supported & SUPPORTED_MII)
interface.addCapability("mii", _("Media Independant Interface"));
if(ecmd.supported & SUPPORTED_FIBRE)
interface.addCapability("fibre",_( "optical fibre"));
if(ecmd.supported & SUPPORTED_10baseT_Half)
{
interface.addCapability("10bt", _("10Mbit/s"));
interface.setCapacity(10000000ULL);
}
if(ecmd.supported & SUPPORTED_10baseT_Full)
{
interface.addCapability("10bt-fd", _("10Mbit/s (full duplex)"));
interface.setCapacity(10000000ULL);
}
if(ecmd.supported & SUPPORTED_100baseT_Half)
{
interface.addCapability("100bt", _("100Mbit/s"));
interface.setCapacity(100000000ULL);
}
if(ecmd.supported & SUPPORTED_100baseT_Full)
{
interface.addCapability("100bt-fd", _("100Mbit/s (full duplex)"));
interface.setCapacity(100000000ULL);
}
if(ecmd.supported & SUPPORTED_1000baseT_Half)
{
interface.addCapability("1000bt", "1Gbit/s");
interface.setCapacity(1000000000ULL);
}
if(ecmd.supported & SUPPORTED_1000baseT_Full)
{
interface.addCapability("1000bt-fd", _("1Gbit/s (full duplex)"));
interface.setCapacity(1000000000ULL);
}
if(ecmd.supported & SUPPORTED_10000baseT_Full)
{
interface.addCapability("10000bt-fd", _("10Gbit/s (full duplex)"));
interface.setCapacity(10000000000ULL);
}
if(ecmd.supported & SUPPORTED_Autoneg)
interface.addCapability("autonegotiation", _("Auto-negotiation"));
switch(ecmd.speed)
{
case SPEED_10:
interface.setConfig("speed", "10Mbit/s");
interface.setSize(10000000ULL);
break;
case SPEED_100:
interface.setConfig("speed", "100Mbit/s");
interface.setSize(100000000ULL);
break;
case SPEED_1000:
interface.setConfig("speed", "1Gbit/s");
interface.setSize(1000000000ULL);
break;
case SPEED_10000:
interface.setConfig("speed", "10Gbit/s");
interface.setSize(10000000000ULL);
break;
}
switch(ecmd.duplex)
{
case DUPLEX_HALF:
interface.setConfig("duplex", "half");
break;
case DUPLEX_FULL:
interface.setConfig("duplex", "full");
break;
}
switch(ecmd.port)
{
case PORT_TP:
interface.setConfig("port", "twisted pair");
break;
case PORT_AUI:
interface.setConfig("port", "AUI");
break;
case PORT_BNC:
interface.setConfig("port", "BNC");
break;
case PORT_MII:
interface.setConfig("port", "MII");
break;
case PORT_FIBRE:
interface.setConfig("port", "fibre");
break;
}
interface.setConfig("autonegotiation", (ecmd.autoneg == AUTONEG_DISABLE) ? "off" : "on");
}
drvinfo.cmd = ETHTOOL_GDRVINFO;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, interfaces[i].c_str());
ifr.ifr_data = (caddr_t) & drvinfo;
if (ioctl(fd, SIOCETHTOOL, &ifr) == 0)
{
interface.setConfig("driver", drvinfo.driver);
interface.setConfig("driverversion", drvinfo.version);
interface.setConfig("firmware", drvinfo.fw_version);
if (interface.getBusInfo() == "")
interface.setBusInfo(guessBusInfo(drvinfo.bus_info));
}
if(sysfs::entry::byClass("net", interface.getLogicalName()).hassubdir("bridge"))
interface.addCapability("logical", _("Logical interface"));
existing = n.findChildByBusInfo(interface.getBusInfo());
// Multiple NICs can exist on one PCI function.
// Only merge if MACs also match.
if (existing && (existing->getSerial() == "" || interface.getSerial() == existing->getSerial()))
{
existing->merge(interface);
if(interface.getDescription()!="")
existing->setDescription(interface.getDescription());
}
else
{
existing = n.findChildByLogicalName(interface.getLogicalName());
if (existing)
{
existing->merge(interface);
}
else
{
// we don't care about loopback and "logical" interfaces
if (!interface.isCapable("loopback") &&
!interface.isCapable("logical"))
n.addChild(interface);
}
}
}
close(fd);
return true;
}
else
return false;
}

7
src/core/network.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _NETWORK_H_
#define _NETWORK_H_
#include "hw.h"
bool scan_network(hwNode & n);
#endif

149
src/core/options.cc Normal file
View File

@ -0,0 +1,149 @@
/*
* options.cc
*
* This module handles global options passed on the command-line.
*
*/
#include "version.h"
#include "options.h"
#include "osutils.h"
#include <set>
#include <vector>
#include <string>
#include <map>
#include <stdlib.h>
using namespace std;
__ID("@(#) $Id$");
static set < string > disabled_tests;
static set < string > visible_classes;
static map < string, string > aliases;
void alias(const char * aname, const char * cname)
{
aliases[lowercase(aname)] = lowercase(cname);
}
static string getcname(const char * aname)
{
if(aliases.find(lowercase(aname)) != aliases.end())
return lowercase(aliases[lowercase(aname)]);
else
return lowercase(aname);
}
static void remove_option_argument(int i,
int &argc,
char *argv[])
{
for (int j = i; j + 2 < argc; j++)
argv[j] = argv[j + 2];
argc -= 2;
}
bool parse_options(int &argc,
char *argv[])
{
int i = 1;
string option = "";
while (i < argc)
{
option = string(argv[i]);
if (option == "-disable")
{
if (i + 1 >= argc)
return false; // -disable requires an argument
disable(argv[i + 1]);
remove_option_argument(i, argc, argv);
}
else if (option == "-enable")
{
if (i + 1 >= argc)
return false; // -enable requires an argument
enable(argv[i + 1]);
remove_option_argument(i, argc, argv);
}
#ifdef SQLITE
else if (option == "-dump")
{
if (i + 1 >= argc)
return false; // -dump requires an argument
setenv("OUTFILE", argv[i + 1], 1);
enable("output:db");
remove_option_argument(i, argc, argv);
}
#endif
else if ( (option == "-class") || (option == "-C") || (option == "-c"))
{
vector < string > classes;
enable("output:list");
if (i + 1 >= argc)
return false; // -class requires an argument
splitlines(argv[i + 1], classes, ',');
for (unsigned int j = 0; j < classes.size(); j++)
visible_classes.insert(getcname(classes[j].c_str()));
remove_option_argument(i, argc, argv);
}
else
i++;
}
return true;
}
bool enabled(const char *option)
{
return !(disabled(lowercase(option).c_str()));
}
bool disabled(const char *option)
{
return disabled_tests.find(lowercase(option)) != disabled_tests.end();
}
void enable(const char *option)
{
if (!disabled(option))
return;
disabled_tests.erase(lowercase(option));
}
void disable(const char *option)
{
disabled_tests.insert(lowercase(option));
}
bool visible(const char *c)
{
if (visible_classes.size() == 0)
return true;
return visible_classes.find(getcname(c)) != visible_classes.end();
}

16
src/core/options.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _OPTIONS_H_
#define _OPTIONS_H_
#define REMOVED "[REMOVED]"
bool parse_options(int & argc, char * argv[]);
void alias(const char * a, const char * cname);
bool enabled(const char * option);
bool disabled(const char * option);
void enable(const char * option);
void disable(const char * option);
bool visible(const char * c);
#endif

870
src/core/osutils.cc Normal file
View File

@ -0,0 +1,870 @@
#include "version.h"
#include "osutils.h"
#include <sstream>
#include <iomanip>
#include <stack>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <libgen.h>
#include <regex.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <wchar.h>
#include <sys/utsname.h>
#ifndef MINOR
#include <linux/kdev_t.h>
#endif
#ifdef ZLIB
#include <zlib.h>
#endif
__ID("@(#) $Id$");
using namespace std;
static stack < string > dirs;
bool pushd(const string & dir)
{
string curdir = pwd();
if (dir == "")
{
if (dirs.size() == 0)
return true;
if (chdir(dirs.top().c_str()) == 0)
{
dirs.pop();
dirs.push(curdir);
return true;
}
else
return false;
}
if (chdir(dir.c_str()) == 0)
{
dirs.push(curdir);
return true;
}
else
return false;
}
string popd()
{
string curdir = pwd();
if (dirs.size() == 0)
return curdir;
if (chdir(dirs.top().c_str()) == 0)
dirs.pop();
return curdir;
}
string pwd()
{
char curdir[PATH_MAX + 1];
if (getcwd(curdir, sizeof(curdir)))
return string(curdir);
else
return "";
}
size_t splitlines(const string & s,
vector < string > &lines,
char separator)
{
size_t i = 0, j = 0;
size_t count = 0;
lines.clear();
while ((j < s.length()) && ((i = s.find(separator, j)) != string::npos))
{
lines.push_back(s.substr(j, i - j));
count++;
i++;
j = i;
}
if (j < s.length())
{
lines.push_back(s.substr(j));
count++;
}
return count;
}
bool exists(const string & path)
{
return access(path.c_str(), F_OK) == 0;
}
#ifdef ZLIB
typedef gzFile data_file;
static data_file file_open(const string & file)
{
data_file result = gzopen((file + ".gz").c_str(), "rb");
if (!result)
{
result = gzopen(file.c_str(), "rb");
}
return result;
}
#define file_open_error(f) ((f) == NULL)
#define file_read(f, b, l) gzread((f), (b), (l))
#define file_close(f) gzclose(f)
#else
typedef int data_file;
#define file_open(f) open((f).c_str(), O_RDONLY);
#define file_open_error(f) ((f) < 0)
#define file_read(f, b, l) read((f), (b), (l))
#define file_close(f) close(f)
#endif
bool loadfile(const string & file,
vector < string > &list)
{
char buffer[1024];
string buffer_str = "";
size_t count = 0;
data_file fd = file_open(file);
if (file_open_error(fd))
return false;
while ((count = file_read(fd, buffer, sizeof(buffer))) > 0)
buffer_str += string(buffer, count);
splitlines(buffer_str, list);
file_close(fd);
return true;
}
string get_string(const string & path,
const string & def)
{
int fd = open(path.c_str(), O_RDONLY);
string result = def;
if (fd >= 0)
{
char buffer[1024];
size_t count = 0;
memset(buffer, 0, sizeof(buffer));
result = "";
while ((count = read(fd, buffer, sizeof(buffer))) > 0)
result += string(buffer, count);
close(fd);
}
return result;
}
long get_number(const string & path, long def)
{
string s = get_string(path, "");
if(s=="") return def;
return strtol(s.c_str(), NULL, 10);
}
int selectdir(const struct dirent *d)
{
struct stat buf;
if (d->d_name[0] == '.')
return 0;
if (lstat(d->d_name, &buf) != 0)
return 0;
return S_ISDIR(buf.st_mode);
}
int selectlink(const struct dirent *d)
{
struct stat buf;
if (d->d_name[0] == '.')
return 0;
if (lstat(d->d_name, &buf) != 0)
return 0;
return S_ISLNK(buf.st_mode);
}
int selectfile(const struct dirent *d)
{
struct stat buf;
if (d->d_name[0] == '.')
return 0;
if (lstat(d->d_name, &buf) != 0)
return 0;
return S_ISREG(buf.st_mode);
}
static int selectdevice(const struct dirent *d)
{
struct stat buf;
if (d->d_name[0] == '.')
return 0;
if (lstat(d->d_name, &buf) != 0)
return 0;
return S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode);
}
static bool matches(string name,
mode_t mode,
dev_t device)
{
struct stat buf;
if (lstat(name.c_str(), &buf) != 0)
return false;
return ((S_ISCHR(buf.st_mode) && S_ISCHR(mode)) ||
(S_ISBLK(buf.st_mode) && S_ISBLK(mode))) && (buf.st_dev == device);
}
static string find_deventry(string basepath,
mode_t mode,
dev_t device)
{
struct dirent **namelist;
int n, i;
string result = "";
pushd(basepath);
n = scandir(".", &namelist, selectdevice, alphasort);
if (n < 0)
{
popd();
return "";
}
for (i = 0; i < n; i++)
{
if (result == "" && matches(namelist[i]->d_name, mode, device))
result = string(namelist[i]->d_name);
free(namelist[i]);
}
free(namelist);
popd();
if (result != "")
return basepath + "/" + result;
pushd(basepath);
n = scandir(".", &namelist, selectdir, alphasort);
popd();
if (n < 0)
return "";
for (i = 0; i < n; i++)
{
if (result == "")
result =
find_deventry(basepath + "/" + string(namelist[i]->d_name), mode,
device);
free(namelist[i]);
}
free(namelist);
return result;
}
string find_deventry(mode_t mode,
dev_t device)
{
return find_deventry("/dev", mode, device);
}
string get_devid(const string & name)
{
struct stat buf;
if((stat(name.c_str(), &buf)==0) && (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)))
{
char devid[80];
snprintf(devid, sizeof(devid), "%u:%u", (unsigned int)MAJOR(buf.st_rdev), (unsigned int)MINOR(buf.st_rdev));
return string(devid);
}
else
return "";
}
bool samefile(const string & path1, const string & path2)
{
struct stat stat1;
struct stat stat2;
if (stat(path1.c_str(), &stat1) != 0)
return false;
if (stat(path2.c_str(), &stat2) != 0)
return false;
return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
}
string uppercase(const string & s)
{
string result;
for (unsigned int i = 0; i < s.length(); i++)
result += toupper(s[i]);
return result;
}
string lowercase(const string & s)
{
string result;
for (unsigned int i = 0; i < s.length(); i++)
result += tolower(s[i]);
return result;
}
string tostring(unsigned long long n)
{
char buffer[80];
snprintf(buffer, sizeof(buffer), "%lld", n);
return string(buffer);
}
string tohex(unsigned long long n)
{
char buffer[80];
snprintf(buffer, sizeof(buffer), "%llX", n);
return string(buffer);
}
string join(const string & j, const string & s1, const string & s2)
{
if(s1 == "") return s2;
if(s2 == "") return s1;
return s1 + j + s2;
}
bool matches(const string & s, const string & pattern, int cflags)
{
regex_t r;
bool result = false;
if(regcomp(&r, pattern.c_str(), REG_EXTENDED | REG_NOSUB | cflags) != 0)
return false;
result = (regexec(&r, s.c_str(), 0, NULL, 0) == 0);
regfree(&r);
return result;
}
string readlink(const string & path)
{
char buffer[PATH_MAX+1];
memset(buffer, 0, sizeof(buffer));
if(readlink(path.c_str(), buffer, sizeof(buffer)-1)>0)
return string(buffer);
else
return path;
}
string realpath(const string & path)
{
char buffer[PATH_MAX+1];
memset(buffer, 0, sizeof(buffer));
if(realpath(path.c_str(), buffer))
return string(buffer);
else
return path;
}
string dirname(const string & path)
{
size_t len = path.length();
char *buffer = new char[len + 1];
path.copy(buffer, len);
buffer[len] = '\0';
string result = dirname(buffer);
delete[] buffer;
return result;
}
string spaces(unsigned int count, const string & space)
{
string result = "";
while (count-- > 0)
result += space;
return result;
}
string escape(const string & s)
{
string result = "";
for (unsigned int i = 0; i < s.length(); i++)
// #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
if (s[i] == 0x9
|| s[i] == 0xA
|| s[i] == 0xD
|| s[i] >= 0x20)
switch (s[i])
{
case '<':
result += "&lt;";
break;
case '>':
result += "&gt;";
break;
case '&':
result += "&amp;";
break;
case '"':
result += "&quot;";
break;
default:
result += s[i];
}
return result;
}
string escapeJSON(const string & s)
{
string result = "";
for (unsigned int i = 0; i < s.length(); i++)
switch (s[i])
{
case '\r':
result += "\\r";
break;
case '\n':
result += "\\n";
break;
case '\t':
result += "\\t";
break;
case '"':
result += "\\\"";
break;
default:
result += s[i];
}
return result;
}
string escapecomment(const string & s)
{
string result = "";
char previous = 0;
for (unsigned int i = 0; i < s.length(); i++)
if(!(previous == '-' && s[i] == '-'))
{
result += s[i];
previous = s[i];
}
return result;
}
unsigned short be_short(const void * from)
{
uint8_t *p = (uint8_t*)from;
return ((uint16_t)(p[0]) << 8) +
(uint16_t)p[1];
}
unsigned short le_short(const void * from)
{
uint8_t *p = (uint8_t*)from;
return ((uint16_t)(p[1]) << 8) +
(uint16_t)p[0];
}
unsigned long be_long(const void * from)
{
uint8_t *p = (uint8_t*)from;
return ((uint32_t)(p[0]) << 24) +
((uint32_t)(p[1]) << 16) +
((uint32_t)(p[2]) << 8) +
(uint32_t)p[3];
}
unsigned long le_long(const void * from)
{
uint8_t *p = (uint8_t*)from;
return ((uint32_t)(p[3]) << 24) +
((uint32_t)(p[2]) << 16) +
((uint32_t)(p[1]) << 8) +
(uint32_t)p[0];
}
unsigned long long be_longlong(const void * from)
{
uint8_t *p = (uint8_t*)from;
return ((unsigned long long)(p[0]) << 56) +
((unsigned long long)(p[1]) << 48) +
((unsigned long long)(p[2]) << 40) +
((unsigned long long)(p[3]) << 32) +
((unsigned long long)(p[4]) << 24) +
((unsigned long long)(p[5]) << 16) +
((unsigned long long)(p[6]) << 8) +
(unsigned long long)p[7];
}
unsigned long long le_longlong(const void * from)
{
uint8_t *p = (uint8_t*)from;
return ((unsigned long long)(p[7]) << 56) +
((unsigned long long)(p[6]) << 48) +
((unsigned long long)(p[5]) << 40) +
((unsigned long long)(p[4]) << 32) +
((unsigned long long)(p[3]) << 24) +
((unsigned long long)(p[2]) << 16) +
((unsigned long long)(p[1]) << 8) +
(unsigned long long)p[0];
}
int open_dev(dev_t dev, int dev_type, const string & name)
{
static const char *paths[] =
{
"/usr/tmp", "/var/tmp", "/var/run", "/dev", "/tmp", NULL
};
char const **p;
char fn[64];
int fd;
for (p = paths; *p; p++)
{
if(name=="")
snprintf(fn, sizeof(fn), "%s/lshw-%d", *p, getpid());
else
snprintf(fn, sizeof(fn), "%s", name.c_str());
if ((mknod(fn, (dev_type | S_IREAD), dev) == 0) || (errno == EEXIST))
{
fd = open(fn, O_RDONLY);
if(name=="") unlink(fn);
if (fd >= 0)
return fd;
}
}
return -1;
} /* open_dev */
#define putchar(c) ((char)((c) & 0xff))
string utf8(wchar_t c)
{
string result = "";
if (c < 0x80)
{
result += putchar (c);
}
else if (c < 0x800)
{
result += putchar (0xC0 | c>>6);
result += putchar (0x80 | (c & 0x3F));
}
else if (c < 0x10000)
{
result += putchar (0xE0 | c>>12);
result += putchar (0x80 | (c>>6 & 0x3F));
result += putchar (0x80 | (c & 0x3F));
}
else if (c < 0x200000)
{
result += putchar (0xF0 | c>>18);
result += putchar (0x80 | (c>>12 & 0x3F));
result += putchar (0x80 | (c>>6 & 0x3F));
result += putchar (0x80 | (c & 0x3F));
}
return result;
}
string utf8(uint16_t * s, ssize_t length, bool forcelittleendian)
{
string result = "";
ssize_t i;
for(i=0; (length<0) || (i<length); i++)
if(s[i])
result += utf8(forcelittleendian?le_short(s+i):s[i]);
else
break; // NUL found
return result;
}
// U+FFFD replacement character
#define REPLACEMENT "\357\277\275"
string utf8_sanitize(const string & s, bool autotruncate)
{
unsigned int i = 0;
unsigned int remaining = 0;
string result = "";
string emit = "";
unsigned char c = 0;
while(i<s.length())
{
c = s[i];
switch(remaining)
{
case 3:
case 2:
case 1:
if((0x80<=c) && (c<=0xbf))
{
emit += s[i];
remaining--;
}
else // invalid sequence (truncated)
{
if(autotruncate) return result;
emit = REPLACEMENT;
emit += s[i];
remaining = 0;
}
break;
case 0:
result += emit;
emit = "";
if(c<=0x7f)
emit = s[i];
else
if((0xc2<=c) && (c<=0xdf)) // start 2-byte sequence
{
remaining = 1;
emit = s[i];
}
else
if((0xe0<=c) && (c<=0xef)) // start 3-byte sequence
{
remaining = 2;
emit = s[i];
}
else
if((0xf0<=c) && (c<=0xf4)) // start 4-byte sequence
{
remaining = 3;
emit = s[i];
}
else
{
if(autotruncate) return result;
emit = REPLACEMENT; // invalid character
}
break;
}
i++;
}
if(remaining == 0)
result += emit;
return result;
}
string decimalkilos(unsigned long long value)
{
const char *prefixes = "KMGTPEZY";
unsigned int i = 0;
ostringstream out;
while ((i <= strlen(prefixes)) && ((value > 10000) || (value % 1000 == 0)))
{
value = value / 1000;
i++;
}
out << value;
if ((i > 0) && (i <= strlen(prefixes)))
out << prefixes[i - 1];
return out.str();
}
string kilobytes(unsigned long long value)
{
const char *prefixes = "KMGTPEZY";
unsigned int i = 0;
ostringstream out;
while ((i <= strlen(prefixes)) && ((value > 10240) || (value % 1024 == 0)))
{
value = value >> 10;
i++;
}
out << value;
if ((i > 0) && (i <= strlen(prefixes)))
out << prefixes[i - 1];
out << "iB";
return out.str();
}
string operating_system()
{
vector<string> osinfo;
struct utsname u;
string os = "";
if(loadfile("/etc/lsb-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/lsb_release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/system-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/arch-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/arklinux-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/aurox-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/conectiva-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/debian_version", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/fedora-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/gentoo-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/linuxppc-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/mandrake-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/mandriva-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/novell-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/pld-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/redhat-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/slackware-version", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/sun-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/SuSE-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
else if(loadfile("/etc/yellowdog-release", osinfo) && (osinfo.size() > 0))
os = osinfo[0];
if(uname(&u) != 0) return "";
os += (os == ""?"":" ; ") + string(u.sysname)+" "+string(u.release);
#if defined(__GLIBC__) && defined(_CS_GNU_LIBC_VERSION)
char version[PATH_MAX];
if(confstr(_CS_GNU_LIBC_VERSION, version, sizeof(version))>0)
os += " ; "+string(version);
#endif
return os;
}
string platform()
{
struct utsname u;
if(uname(&u) != 0)
return string("i386");
else
return string(u.machine);
}

65
src/core/osutils.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef _OSUTILS_H_
#define _OSUTILS_H_
#include <string>
#include <vector>
#include <sys/types.h>
#include <stdint.h>
bool pushd(const std::string & dir = "");
std::string popd();
std::string pwd();
bool exists(const std::string & path);
bool samefile(const std::string & path1, const std::string & path2);
std::string readlink(const std::string & path);
std::string realpath(const std::string & path);
std::string dirname(const std::string & path);
bool loadfile(const std::string & file, std::vector < std::string > &lines);
size_t splitlines(const std::string & s,
std::vector < std::string > &lines,
char separator = '\n');
std::string get_string(const std::string & path, const std::string & def = "");
long get_number(const std::string & path, long def = 0);
std::string find_deventry(mode_t mode, dev_t device);
std::string get_devid(const std::string &);
std::string uppercase(const std::string &);
std::string lowercase(const std::string &);
std::string tostring(unsigned long long);
std::string tohex(unsigned long long);
std::string utf8(wchar_t);
std::string utf8_sanitize(const std::string &, bool autotruncate = true);
std::string utf8(uint16_t *s, ssize_t length = -1, bool forcelittleendian = false);
std::string spaces(unsigned int count, const std::string & space = " ");
std::string escape(const std::string &);
std::string escapeJSON(const std::string &);
std::string escapecomment(const std::string &);
std::string join(const std::string &, const std::string &, const std::string &);
std::string decimalkilos(unsigned long long value);
std::string kilobytes(unsigned long long value);
bool matches(const std::string & s, const std::string & pattern, int cflags=0);
int selectdir(const struct dirent *d);
int selectlink(const struct dirent *d);
int selectfile(const struct dirent *d);
unsigned short be_short(const void *);
unsigned short le_short(const void *);
unsigned long be_long(const void *);
unsigned long le_long(const void *);
unsigned long long be_longlong(const void *);
unsigned long long le_longlong(const void *);
int open_dev(dev_t dev, int dev_type, const std::string & name="");
std::string platform();
std::string operating_system();
#endif

599
src/core/parisc.cc Normal file
View File

@ -0,0 +1,599 @@
/*
* parisc.cc
*
* This module parses the PA-RISC device tree (published under /sys
* by the kernel).
*
*
*
*
*/
#include "version.h"
#include "device-tree.h"
#include "osutils.h"
#include "heuristics.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
__ID("@(#) $Id$");
#define DEVICESPARISC "/sys/devices/parisc"
#define TP_NPROC 0x00
#define TP_MEMORY 0x01
#define TP_B_DMA 0x02
#define TP_OBSOLETE 0x03
#define TP_A_DMA 0x04
#define TP_A_DIRECT 0x05
#define TP_OTHER 0x06
#define TP_BCPORT 0x07
#define TP_CIO 0x08
#define TP_CONSOLE 0x09
#define TP_FIO 0x0a
#define TP_BA 0x0b
#define TP_IOA 0x0c
#define TP_BRIDGE 0x0d
#define TP_FABRIC 0x0e
#define TP_MC 0x0f
#define TP_FAULTY 0x1f
struct parisc_device
{
long sversion;
const char * id;
hw::hwClass device_class;
const char * description;
};
static struct parisc_device parisc_device_list[] =
{
{0x00004, "cpu", hw::processor, "Processor"},
{0x0000d, "mux", hw::communication, "MUX"},
{0x0000e, "serial", hw::communication, "RS-232 Serial Interface"},
{0x0000f, "display", hw::display, "Graphics Display"},
{0x00014, "input", hw::input, "HIL"},
{0x00015, "display", hw::display, "Graphics Display"},
{0x0003a, "printer", hw::printer, "Centronics Parallel interface"},
{0x000a8, "input", hw::input, "Keyboard"},
{0x00039, "scsi", hw::storage, "Core SCSI controller"},
{0x0003b, "scsi", hw::storage, "FW-SCSI controller"},
{0x0005e, "network", hw::network, "Token Ring Interface"},
{0x00089, "scsi", hw::storage, "FW-SCSI controller"},
{0x00091, "fc", hw::storage, "Fibre Channel controller"},
{0x0009a, "network", hw::network, "ATM Interface"},
{0x000a7, "fc", hw::storage, "Fibre Channel controller"},
{0x00070, "core", hw::bus, "Core Bus"},
{0x00076, "eisa", hw::bus, "EISA Bus"},
{0x00078, "vme", hw::bus, "VME Bus"},
{0x00081, "core", hw::bus, "Core Bus"},
{0x0008e, "wax", hw::bus, "Wax Bus"},
{0x00090, "eisa", hw::bus, "Wax EISA Bus"},
{0x00093, "bus", hw::bus, "TIMI Bus"},
{0x0000c, "bridge", hw::bridge, "Bus Converter"},
{0x0000a, "pci", hw::bridge, "PCI Bridge"},
{0x000a5, "pci", hw::bridge, "PCI Bridge"},
{0x00052, "lanconsole", hw::network, "LAN/Console"},
{0x00060, "lanconsole", hw::network, "LAN/Console"},
{0x00071, "scsi", hw::storage, "Core SCSI controller"},
{0x00072, "network", hw::network, "Core Ethernet Interface"},
{0x00072, "input", hw::input, "Core HIL"},
{0x00074, "printer", hw::printer, "Core Centronics Parallel interface"},
{0x00075, "serial", hw::communication, "Core RS-232 Serial Interface"},
{0x00077, "display", hw::display, "Graphics Display"},
{0x0007a, "audio", hw::multimedia, "Audio"},
{0x0007b, "audio", hw::multimedia, "Audio"},
{0x0007c, "scsi", hw::storage, "FW-SCSI controller"},
{0x0007d, "network", hw::network, "FDDI Interface"},
{0x0007e, "audio", hw::multimedia, "Audio"},
{0x0007f, "audio", hw::multimedia, "Audio"},
{0x00082, "scsi", hw::storage, "SCSI controller"},
{0x00083, "floppy", hw::storage, "Floppy"},
{0x00084, "input", hw::input, "PS/2 port"},
{0x00085, "display", hw::display, "Graphics Display"},
{0x00086, "network", hw::network, "Token Ring Interface"},
{0x00087, "communication", hw::communication, "ISDN"},
{0x00088, "network", hw::network, "VME Networking Interface"},
{0x0008a, "network", hw::network, "Core Ethernet Interface"},
{0x0008c, "serial", hw::communication, "RS-232 Serial Interface"},
{0x0008d, "unknown", hw::communication, "RJ-16"},
{0x0008f, "firmware", hw::memory, "Boot ROM"},
{0x00096, "input", hw::input, "PS/2 port"},
{0x00097, "network", hw::network, "100VG LAN Interface"},
{0x000a2, "network", hw::network, "10/100BT LAN Interface"},
{0x000a3, "scsi", hw::storage, "Ultra2 SCSI controller"},
{0x00000, "generic", hw::generic, NULL},
};
enum cpu_type
{
pcx = 0, /* pa7000 pa 1.0 */
pcxs = 1, /* pa7000 pa 1.1a */
pcxt = 2, /* pa7100 pa 1.1b */
pcxt_ = 3, /* pa7200 (t') pa 1.1c */
pcxl = 4, /* pa7100lc pa 1.1d */
pcxl2 = 5, /* pa7300lc pa 1.1e */
pcxu = 6, /* pa8000 pa 2.0 */
pcxu_ = 7, /* pa8200 (u+) pa 2.0 */
pcxw = 8, /* pa8500 pa 2.0 */
pcxw_ = 9, /* pa8600 (w+) pa 2.0 */
pcxw2 = 10, /* pa8700 pa 2.0 */
mako = 11 /* pa8800 pa 2.0 */
};
static struct hp_cpu_type_mask
{
unsigned short model;
unsigned short mask;
enum cpu_type cpu;
}
hp_cpu_type_mask_list[] =
{
{ /* 0x0000 - 0x000f */
0x0000, 0x0ff0, pcx
},
{ /* 0x0040 - 0x004f */
0x0048, 0x0ff0, pcxl
},
{ /* 0x0080 - 0x008f */
0x0080, 0x0ff0, pcx
},
{ /* 0x0100 - 0x010f */
0x0100, 0x0ff0, pcx
},
{ /* 0x0182 - 0x0183 */
0x0182, 0x0ffe, pcx
},
{ /* 0x0182 - 0x0183 */
0x0182, 0x0ffe, pcxt
},
{ /* 0x0184 - 0x0184 */
0x0184, 0x0fff, pcxu
},
{ /* 0x0200 - 0x0201 */
0x0200, 0x0ffe, pcxs
},
{ /* 0x0202 - 0x0202 */
0x0202, 0x0fff, pcxs
},
{ /* 0x0203 - 0x0203 */
0x0203, 0x0fff, pcxt
},
{ /* 0x0204 - 0x0207 */
0x0204, 0x0ffc, pcxt
},
{ /* 0x0280 - 0x0283 */
0x0280, 0x0ffc, pcxs
},
{ /* 0x0284 - 0x0287 */
0x0284, 0x0ffc, pcxt
},
{ /* 0x0288 - 0x0288 */
0x0288, 0x0fff, pcxt
},
{ /* 0x0300 - 0x0303 */
0x0300, 0x0ffc, pcxs
},
{ /* 0x0310 - 0x031f */
0x0310, 0x0ff0, pcxt
},
{ /* 0x0320 - 0x032f */
0x0320, 0x0ff0, pcxt
},
{ /* 0x0400 - 0x040f */
0x0400, 0x0ff0, pcxt
},
{ /* 0x0480 - 0x048f */
0x0480, 0x0ff0, pcxl
},
{ /* 0x0500 - 0x050f */
0x0500, 0x0ff0, pcxl2
},
{ /* 0x0510 - 0x051f */
0x0510, 0x0ff0, pcxl2
},
{ /* 0x0580 - 0x0587 */
0x0580, 0x0ff8, pcxt_
},
{ /* 0x0588 - 0x058b */
0x0588, 0x0ffc, pcxt_
},
{ /* 0x058c - 0x058d */
0x058c, 0x0ffe, pcxt_
},
{ /* 0x058e - 0x058e */
0x058e, 0x0fff, pcxt_
},
{ /* 0x058f - 0x058f */
0x058f, 0x0fff, pcxu
},
{ /* 0x0590 - 0x0591 */
0x0590, 0x0ffe, pcxu
},
{ /* 0x0592 - 0x0592 */
0x0592, 0x0fff, pcxt_
},
{ /* 0x0593 - 0x0593 */
0x0593, 0x0fff, pcxu
},
{ /* 0x0594 - 0x0597 */
0x0594, 0x0ffc, pcxu
},
{ /* 0x0598 - 0x0599 */
0x0598, 0x0ffe, pcxu_
},
{ /* 0x059a - 0x059b */
0x059a, 0x0ffe, pcxu
},
{ /* 0x059c - 0x059c */
0x059c, 0x0fff, pcxu
},
{ /* 0x059d - 0x059d */
0x059d, 0x0fff, pcxu_
},
{ /* 0x059e - 0x059e */
0x059e, 0x0fff, pcxt_
},
{ /* 0x059f - 0x059f */
0x059f, 0x0fff, pcxu
},
{ /* 0x05a0 - 0x05a1 */
0x05a0, 0x0ffe, pcxt_
},
{ /* 0x05a2 - 0x05a3 */
0x05a2, 0x0ffe, pcxu
},
{ /* 0x05a4 - 0x05a7 */
0x05a4, 0x0ffc, pcxu
},
{ /* 0x05a8 - 0x05ab */
0x05a8, 0x0ffc, pcxu
},
{ /* 0x05ad - 0x05ad */
0x05ad, 0x0fff, pcxu_
},
{ /* 0x05ae - 0x05af */
0x05ae, 0x0ffe, pcxu_
},
{ /* 0x05b0 - 0x05b1 */
0x05b0, 0x0ffe, pcxu_
},
{ /* 0x05b2 - 0x05b2 */
0x05b2, 0x0fff, pcxu_
},
{ /* 0x05b3 - 0x05b3 */
0x05b3, 0x0fff, pcxu
},
{ /* 0x05b4 - 0x05b4 */
0x05b4, 0x0fff, pcxw
},
{ /* 0x05b5 - 0x05b5 */
0x05b5, 0x0fff, pcxu_
},
{ /* 0x05b6 - 0x05b7 */
0x05b6, 0x0ffe, pcxu_
},
{ /* 0x05b8 - 0x05b9 */
0x05b8, 0x0ffe, pcxu_
},
{ /* 0x05ba - 0x05ba */
0x05ba, 0x0fff, pcxu_
},
{ /* 0x05bb - 0x05bb */
0x05bb, 0x0fff, pcxw
},
{ /* 0x05bc - 0x05bf */
0x05bc, 0x0ffc, pcxw
},
{ /* 0x05c0 - 0x05c3 */
0x05c0, 0x0ffc, pcxw
},
{ /* 0x05c4 - 0x05c5 */
0x05c4, 0x0ffe, pcxw
},
{ /* 0x05c6 - 0x05c6 */
0x05c6, 0x0fff, pcxw
},
{ /* 0x05c7 - 0x05c7 */
0x05c7, 0x0fff, pcxw_
},
{ /* 0x05c8 - 0x05cb */
0x05c8, 0x0ffc, pcxw
},
{ /* 0x05cc - 0x05cd */
0x05cc, 0x0ffe, pcxw
},
{ /* 0x05ce - 0x05cf */
0x05ce, 0x0ffe, pcxw_
},
{ /* 0x05d0 - 0x05d3 */
0x05d0, 0x0ffc, pcxw_
},
{ /* 0x05d4 - 0x05d5 */
0x05d4, 0x0ffe, pcxw_
},
{ /* 0x05d6 - 0x05d6 */
0x05d6, 0x0fff, pcxw
},
{ /* 0x05d7 - 0x05d7 */
0x05d7, 0x0fff, pcxw_
},
{ /* 0x05d8 - 0x05db */
0x05d8, 0x0ffc, pcxw_
},
{ /* 0x05dc - 0x05dd */
0x05dc, 0x0ffe, pcxw2
},
{ /* 0x05de - 0x05de */
0x05de, 0x0fff, pcxw_
},
{ /* 0x05df - 0x05df */
0x05df, 0x0fff, pcxw2
},
{ /* 0x05e0 - 0x05e3 */
0x05e0, 0x0ffc, pcxw2
},
{ /* 0x05e4 - 0x05e4 */
0x05e4, 0x0fff, pcxw2
},
{ /* 0x05e5 - 0x05e5 */
0x05e5, 0x0fff, pcxw_
},
{ /* 0x05e6 - 0x05e7 */
0x05e6, 0x0ffe, pcxw2
},
{ /* 0x05e8 - 0x05ef */
0x05e8, 0x0ff8, pcxw2
},
{ /* 0x05f0 - 0x05ff */
0x05f0, 0x0ff0, pcxw2
},
{ /* 0x0600 - 0x061f */
0x0600, 0x0fe0, pcxl
},
{ /* 0x0880 - 0x088f */
0x0880, 0x0ff0, mako
},
{ /* terminate table */
0x0000, 0x0000, pcx
}
};
static const char *cpu_name_version[][2] =
{
{ "PA7000 (PCX)", "1.0" },
{ "PA7000 (PCX-S)", "1.1a" },
{ "PA7100 (PCX-T)", "1.1b" },
{ "PA7200 (PCX-T')", "1.1c" },
{ "PA7100LC (PCX-L)", "1.1d" },
{ "PA7300LC (PCX-L2)", "1.1e" },
{ "PA8000 (PCX-U)", "2.0" },
{ "PA8200 (PCX-U+)", "2.0" },
{ "PA8500 (PCX-W)", "2.0" },
{ "PA8600 (PCX-W+)", "2.0" },
{ "PA8700 (PCX-W2)", "2.0" },
{ "PA8800 (Mako)", "2.0" }
};
static long get_long(const string & path)
{
long result = -1;
FILE * in = fopen(path.c_str(), "r");
if (in)
{
if(fscanf(in, "%lx", &result) != 1)
result = -1;
fclose(in);
}
return result;
}
static string cpubusinfo(int cpu)
{
char buffer[10];
snprintf(buffer, sizeof(buffer), "cpu@%d", cpu);
return string(buffer);
}
enum cpu_type parisc_get_cpu_type(long hversion)
{
struct hp_cpu_type_mask *ptr;
for (ptr = hp_cpu_type_mask_list; 0 != ptr->mask; ptr++)
{
if (ptr->model == (hversion & ptr->mask))
return ptr->cpu;
}
return pcx; /* not reached: */
}
static int currentcpu = 0;
static hwNode get_device(long hw_type, long sversion, long hversion)
{
hwNode newnode("generic");
for(unsigned i=0; parisc_device_list[i].description!=NULL; i++)
{
if(sversion == parisc_device_list[i].sversion)
{
newnode = hwNode(parisc_device_list[i].id, parisc_device_list[i].device_class);
newnode.setDescription(parisc_device_list[i].description);
if(hw_type == TP_NPROC)
{
enum cpu_type cpu = parisc_get_cpu_type(hversion);
newnode.setBusInfo(cpubusinfo(currentcpu++));
newnode.setProduct(cpu_name_version[cpu][0]);
newnode.setVersion(cpu_name_version[cpu][1]);
}
return newnode;
}
}
switch(hw_type)
{
case TP_NPROC:
newnode = hwNode("cpu", hw::processor);
newnode.setDescription("Processor");
newnode.setBusInfo(cpubusinfo(currentcpu++));
break;
case TP_MEMORY:
newnode = hwNode("memory", hw::memory);
newnode.setDescription("Memory");
break;
case TP_B_DMA:
newnode.addCapability("b-dma", "Type B DMA I/O");
break;
case TP_A_DMA:
newnode.addCapability("a-dma", "Type A DMA I/O");
break;
case TP_A_DIRECT:
switch (sversion)
{
case 0x0D:
newnode = hwNode("serial", hw::communication);
newnode.setDescription("MUX port");
break;
case 0x0E:
newnode = hwNode("serial", hw::communication);
newnode.setDescription("RS-232 port");
break;
}
newnode.addCapability("a-direct", "Type A Direct I/O");
break;
case TP_BCPORT:
newnode = hwNode("busconverter", hw::bridge);
newnode.setDescription("Bus converter port");
break;
case TP_CIO:
newnode.setDescription("HP-CIO adapter");
break;
case TP_CONSOLE:
newnode = hwNode("console", hw::input);
newnode.setDescription("Console");
break;
case TP_FIO:
newnode.setDescription("Foreign I/O module");
break;
case TP_BA:
newnode = hwNode("bus", hw::bus);
newnode.setDescription("Bus adapter");
break;
case TP_IOA:
newnode.setDescription("I/O adapter");
break;
case TP_BRIDGE:
newnode = hwNode("bridge", hw::bridge);
newnode.setDescription("Bus bridge to foreign bus");
break;
case TP_FABRIC:
newnode.setDescription("Fabric ASIC");
break;
case TP_FAULTY:
newnode.disable();
newnode.setDescription("Faulty module");
break;
}
return newnode;
}
static bool scan_device(hwNode & node, string name = "")
{
struct dirent **namelist;
int n;
hwNode * curnode = NULL;
if(name != "")
{
size_t colon = name.rfind(":");
long hw_type = get_long("hw_type");
long sversion = get_long("sversion");
long hversion = get_long("hversion");
long rev = get_long("rev");
hwNode newnode = get_device(hw_type, sversion, hversion);
if((rev>0) && (newnode.getVersion() == ""))
{
char buffer[20];
snprintf(buffer, sizeof(buffer), "%ld", rev);
newnode.setVersion(buffer);
}
if(newnode.getBusInfo()=="")
newnode.setBusInfo(guessBusInfo(name));
if(exists("driver"))
{
string driver = readlink("driver");
size_t slash = driver.rfind("/");
newnode.setConfig("driver", driver.substr(slash==driver.npos?0:slash+1));
newnode.claim();
}
if(colon!=name.npos)
newnode.setPhysId(name.substr(colon+1));
else
newnode.setPhysId(name);
curnode = node.addChild(newnode);
}
n = scandir(".", &namelist, selectdir, alphasort);
if (n < 0)
return false;
else
{
for (int i = 0; i < n; i++)
if(matches(namelist[i]->d_name, "^[0-9]+(:[0-9]+)*$"))
{
pushd(namelist[i]->d_name);
scan_device(curnode?*curnode:node, namelist[i]->d_name);
popd();
free(namelist[i]);
}
free(namelist);
}
return true;
}
bool scan_parisc(hwNode & node)
{
hwNode *core = node.getChild("core");
currentcpu = 0;
if (!core)
{
core = node.addChild(hwNode("core", hw::bus));
}
if (!core)
return false;
if(core->getDescription()=="")
core->setDescription("Motherboard");
pushd(DEVICESPARISC);
scan_device(*core);
popd();
return true;
}

7
src/core/parisc.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _PARISC_H_
#define _PARISC_H_
#include "hw.h"
bool scan_parisc(hwNode & n);
#endif

1404
src/core/partitions.cc Normal file

File diff suppressed because it is too large Load Diff

7
src/core/partitions.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _PARTITIONS_H_
#define _PARTITIONS_H_
#include "hw.h"
bool scan_partitions(hwNode & n);
#endif

1231
src/core/pci.cc Normal file

File diff suppressed because it is too large Load Diff

8
src/core/pci.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _PCI_H_
#define _PCI_H_
#include "hw.h"
bool scan_pci(hwNode & n);
bool scan_pci_legacy(hwNode & n);
#endif

1191
src/core/pcmcia-legacy.cc Normal file

File diff suppressed because it is too large Load Diff

7
src/core/pcmcia-legacy.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _PCMCIALEGACY_H_
#define _PCMCIALEGACY_H_
#include "hw.h"
bool scan_pcmcialegacy(hwNode & n);
#endif

55
src/core/pcmcia.cc Normal file
View File

@ -0,0 +1,55 @@
#include "version.h"
#include "pcmcia.h"
#include "osutils.h"
#include "sysfs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
__ID("@(#) $Id$");
#define SYS_CLASS_PCMCIASOCKET "/sys/class/pcmcia_socket"
#define CLASS_PCMCIASOCKET "pcmcia_socket"
bool scan_pcmcia(hwNode & n)
{
bool result = false;
hwNode *core = n.getChild("core");
int count = 0;
dirent **sockets = NULL;
return result;
if (!core)
{
n.addChild(hwNode("core", hw::bus));
core = n.getChild("core");
}
if(!pushd(SYS_CLASS_PCMCIASOCKET))
return false;
count = scandir(".", &sockets, NULL, alphasort);
if(count>=0)
{
for(int i=0; i<count; i++)
{
if(matches(sockets[i]->d_name, "^pcmcia_socket[[:digit:]]+$"))
{
sysfs::entry socket = sysfs::entry::byClass(CLASS_PCMCIASOCKET, sockets[i]->d_name);
printf("found PCMCIA socket: %s\n", sockets[i]->d_name);
}
free(sockets[i]);
}
free(sockets);
}
popd();
return result;
}

7
src/core/pcmcia.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _PCMCIA_H_
#define _PCMCIA_H_
#include "hw.h"
bool scan_pcmcia(hwNode & n);
#endif

214
src/core/pnp.cc Normal file
View File

@ -0,0 +1,214 @@
/*
* pnp.cc
*
*
*
*
*
*/
#include "version.h"
#include "pnp.h"
#include "sysfs.h"
#include "osutils.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <map>
#include <iostream>
__ID("@(#) $Id$");
using namespace std;
#define PNPVENDORS_PATH DATADIR"/pnp.ids:/usr/share/lshw/pnp.ids:/usr/share/hwdata/pnp.ids"
#define PNPID_PATH DATADIR"/pnpid.txt:/usr/share/lshw/pnpid.txt:/usr/share/hwdata/pnpid.txt"
static bool pnpdb_loaded = false;
static map < string, string > pnp_vendors;
static map < string, string > pnp_ids;
static void parse_pnp_vendors(const vector < string > & lines)
{
for (vector < string >::const_iterator it = lines.begin();
it != lines.end(); ++it)
{
const string & line = *it;
if (line.length() < 5 || line.at(3) != '\t')
continue;
string id = line.substr(0, 3);
id[0] = toupper(id[0]);
id[1] = toupper(id[1]);
id[2] = toupper(id[2]);
string name = line.substr(4);
// Microsoft is not really the manufacturer of all PNP devices
if (id == "PNP")
continue;
pnp_vendors[id] = name;
}
}
static void parse_pnp_ids(const vector < string > & lines)
{
for (vector < string >::const_iterator it = lines.begin();
it != lines.end(); ++it)
{
const string & line = *it;
if (line.length() < 1 || line.at(0) == ';')
continue;
if (line.length() < 9 || line.at(7) != '\t')
continue;
string id = line.substr(0, 7);
id[0] = toupper(id[0]);
id[1] = toupper(id[1]);
id[2] = toupper(id[2]);
id[3] = tolower(id[3]);
id[4] = tolower(id[4]);
id[5] = tolower(id[5]);
id[6] = tolower(id[6]);
string desc = line.substr(8);
pnp_ids[id] = desc;
}
}
static void load_pnpdb()
{
vector < string > lines;
vector < string > filenames;
splitlines(PNPVENDORS_PATH, filenames, ':');
for (int i = filenames.size() - 1; i >= 0; i--)
{
lines.clear();
if (loadfile(filenames[i], lines))
parse_pnp_vendors(lines);
}
filenames.clear();
splitlines(PNPID_PATH, filenames, ':');
for (int i = filenames.size() - 1; i >= 0; i--)
{
lines.clear();
if (loadfile(filenames[i], lines))
parse_pnp_ids(lines);
}
pnpdb_loaded = true;
}
string pnp_vendorname(const string & id)
{
if (!pnpdb_loaded)
load_pnpdb();
string vendorid = id.substr(0, 3);
map < string, string >::const_iterator lookup = pnp_vendors.find(vendorid);
if (lookup != pnp_vendors.end())
return lookup->second;
return "";
}
string pnp_description(const string & id)
{
if (!pnpdb_loaded)
load_pnpdb();
map < string, string >::const_iterator lookup = pnp_ids.find(id);
if (lookup != pnp_ids.end())
return lookup->second;
return "";
}
hw::hwClass pnp_class(const string & pnpid)
{
long numericid = 0;
if (pnpid.substr(0, 3) != "PNP")
return hw::generic;
numericid = strtol(pnpid.substr(3).c_str(), NULL, 16);
if (numericid < 0x0300)
return hw::system;
if (numericid >= 0x300 && numericid < 0x0400)
return hw::input; // keyboards
if (numericid >= 0x400 && numericid < 0x0500)
return hw::printer; // parallel
if (numericid >= 0x500 && numericid < 0x0600)
return hw::communication; // serial
if (numericid >= 0x600 && numericid < 0x0800)
return hw::storage; // ide
if (numericid >= 0x900 && numericid < 0x0A00)
return hw::display; // vga
if (numericid == 0x802)
return hw::multimedia; // Microsoft Sound System compatible device
if (numericid >= 0xA00 && numericid < 0x0B00)
return hw::bridge; // isa,pci...
if (numericid >= 0xE00 && numericid < 0x0F00)
return hw::bridge; // pcmcia
if (numericid >= 0xF00 && numericid < 0x1000)
return hw::input; // mice
if (numericid < 0x8000)
return hw::system;
if (numericid >= 0x8000 && numericid < 0x9000)
return hw::network; // network
if (numericid >= 0xA000 && numericid < 0xB000)
return hw::storage; // scsi&cd
if (numericid >= 0xB000 && numericid < 0xC000)
return hw::multimedia; // multimedia
if (numericid >= 0xC000 && numericid < 0xD000)
return hw::communication; // modems
return hw::generic;
}
bool scan_pnp(hwNode & n)
{
vector < sysfs::entry > entries = sysfs::entries_by_bus("pnp");
if (entries.empty())
return false;
hwNode *core = n.getChild("core");
if (!core)
{
n.addChild(hwNode("core", hw::bus));
core = n.getChild("core");
}
for (vector < sysfs::entry >::iterator it = entries.begin();
it != entries.end(); ++it)
{
const sysfs::entry & e = *it;
vector < string > pnpids = e.multiline_attr("id");
if (pnpids.empty())
continue;
// devices can report multiple PnP IDs, just pick the first
string pnpid = pnpids[0];
hwNode device("pnp" + e.name(), pnp_class(pnpid));
device.addCapability("pnp");
string driver = e.driver();
if (!driver.empty())
device.setConfig("driver", driver);
string vendor = pnp_vendorname(pnpid);
if (!vendor.empty())
device.setVendor(vendor);
string name = e.string_attr("name");
string description = pnp_description(pnpid);
if (!name.empty())
device.setProduct(name);
else if (!description.empty())
device.setProduct(description);
else
device.setProduct("PnP device " + pnpid);
device.claim();
core->addChild(device);
}
return true;
}

12
src/core/pnp.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _PNP_H_
#define _PNP_H_
#include "hw.h"
#include <string>
string pnp_vendorname(const string & id);
hw::hwClass pnp_class(const string & pnpid);
bool scan_pnp(hwNode &);
#endif

735
src/core/print.cc Normal file
View File

@ -0,0 +1,735 @@
/*
* print.cc
*
* This module prints out the hardware tree depending on options passed
* Output can be plain text (good for human beings), HTML (good for web brow-
* sers), XML (good for programs) or "hardware path" (ioscan-like).
*
*/
#include "print.h"
#include "options.h"
#include "version.h"
#include "osutils.h"
#include "config.h"
#include <cstring>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <termios.h>
__ID("@(#) $Id$");
static unsigned int columns = 0, rows = 0;
static void init_wsize()
{
struct winsize ws;
char *env;
if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws))
{
rows = ws.ws_row;
columns = ws.ws_col;
}
if (!rows)
{
env = getenv("LINES");
if (env)
rows = atoi(env);
if (!rows)
rows = 24;
}
if (!columns)
{
env = getenv("COLUMNS");
if (env)
columns = atoi(env);
if (!columns)
columns = 80;
}
}
static void tab(int level,
bool connect = true)
{
if (level <= 0)
return;
for (int i = 0; i < level - 1; i++)
cout << " ";
cout << " ";
if (connect)
cout << "*-";
else
cout << " ";
}
void print(hwNode & node,
bool html,
int level)
{
vector < string > config;
vector < string > resources;
if (html)
config = node.getConfigValues("</td><td>=</td><td>");
else
config = node.getConfigValues("=");
if (html)
resources = node.getResources("</td><td>:</td><td>");
else
resources = node.getResources(":");
if (html && (level == 0))
{
cout <<
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" <<
endl;
cout << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
cout << "<head>" << endl;
cout << "<meta name=\"generator\" " <<
" content=\"lshw-" << getpackageversion() << "\" />" << endl;
cout << "<style type=\"text/css\">" << endl;
cout << " .first {font-weight: bold; margin-left: none; padding-right: 1em;vertical-align: top; }" << endl;
cout << " .second {padding-left: 1em; width: 100%; vertical-align: center; }" << endl;
cout << " .id {font-family: monospace;}" << endl;
cout << " .indented {margin-left: 2em; border-left: dotted thin #dde; padding-bottom: 1em; }" << endl;
cout << " .node {border: solid thin #ffcc66; padding: 1em; background: #ffffcc; }" << endl;
cout << " .node-unclaimed {border: dotted thin #c3c3c3; padding: 1em; background: #fafafa; color: red; }" << endl;
cout << " .node-disabled {border: solid thin #f55; padding: 1em; background: #fee; color: gray; }" << endl;
cout << "</style>" << endl;
cout << "<title>";
cout << node.getId();
cout << "</title>" << endl;
cout << "</head>" << endl;
cout << "<body>" << endl;
}
if (visible(node.getClassName()))
{
tab(level, !html);
if (html)
{
tab(level, false);
cout << "<div class=\"indented\">" << endl;
tab(level, false);
cout << "<table width=\"100%\" class=\"node";
if(!node.claimed())
cout << "-unclaimed";
else
{
if(node.disabled())
cout << "-disabled";
}
cout << "\" summary=\"attributes of " << node.getId() << "\">" << endl;
}
if (html)
cout << " <thead><tr><td class=\"first\">id:</td><td class=\"second\"><div class=\"id\">";
cout << node.getId();
if (html)
cout << "</div>";
else
{
if (node.disabled())
cout << _(" DISABLED");
if (!node.claimed())
cout << _(" UNCLAIMED");
}
if (html)
cout << "</td></tr></thead>";
cout << endl;
#if 0
if (node.getHandle() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << "handle: ";
if (html)
{
cout << "</td><td class=\"second\">";
cout << escape(node.getHandle());
cout << "</td></tr>";
}
else
cout << node.getHandle()
cout << endl;
}
#endif
if (html)
cout << " <tbody>" << endl;
if (node.getDescription() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("description") << ": ";
if (html)
{
cout << "</td><td class=\"second\">";
cout << escape(node.getDescription());
cout << "</td></tr>";
}
else
cout << node.getDescription();
cout << endl;
}
if (node.getProduct() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("product") << ": ";
if (html)
{
cout << "</td><td class=\"second\">";
cout << escape(node.getProduct());
cout << "</td></tr>";
}
else
cout << node.getProduct();
cout << endl;
}
if (node.getVendor() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("vendor") << ": ";
if (html)
{
cout << "</td><td class=\"second\">";
cout << escape(node.getVendor());
cout << "</td></tr>";
}
else
cout << node.getVendor();
cout << endl;
}
if (node.getPhysId() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("physical id") << ": ";
if (html)
{
cout << "</td><td class=\"second\"><div class=\"id\">";
cout << escape(node.getPhysId());
cout << "</div></td></tr>";
}
else
cout << node.getPhysId();
cout << endl;
}
if (node.getBusInfo() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("bus info") << ": ";
if (html)
{
cout << "</td><td class=\"second\"><div class=\"id\">";
cout << escape(node.getBusInfo());
cout << "</div></td></tr>";
}
else
cout << node.getBusInfo();
cout << endl;
}
if (node.getLogicalName() != "")
{
vector<string> logicalnames = node.getLogicalNames();
for(unsigned int i = 0; i<logicalnames.size(); i++)
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("logical name") << ": ";
if (html)
{
cout << "</td><td class=\"second\"><div class=\"id\">";
cout << escape(logicalnames[i]);
cout << "</div></td></tr>";
}
else
cout << logicalnames[i];
cout << endl;
}
}
if (node.getVersion() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("version") << ": ";
if (html)
{
cout << "</td><td class=\"second\">";
cout << escape(node.getVersion());
cout << "</td></tr>";
}
else
cout << node.getVersion();
cout << endl;
}
if (node.getDate() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("date") << ": ";
if (html)
{
cout << "</td><td class=\"second\">";
cout << escape(node.getDate());
cout << "</td></tr>";
}
else
cout << node.getDate();
cout << endl;
}
if (node.getSerial() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("serial") << ": ";
if (html)
{
cout << "</td><td class=\"second\">";
cout << escape(enabled("output:sanitize")?REMOVED:node.getSerial());
cout << "</td></tr>";
}
else
cout << (enabled("output:sanitize")?REMOVED:node.getSerial());
cout << endl;
}
if (node.getSlot() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("slot") << ": ";
if (html)
{
cout << "</td><td class=\"second\">";
cout << escape(node.getSlot());
cout << "</td></tr>";
}
else
cout << node.getSlot();
cout << endl;
}
if (node.getSize() > 0)
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("size") << ": ";
if (html)
cout << "</td><td class=\"second\">";
switch (node.getClass())
{
case hw::disk:
cout << kilobytes(node.getSize()) << " (" << decimalkilos(node.getSize()) << "B)";
if (html)
cout << "</td></tr>";
break;
case hw::display:
case hw::memory:
case hw::address:
case hw::storage:
case hw::volume:
cout << kilobytes(node.getSize());
if (html)
cout << "</td></tr>";
break;
case hw::processor:
case hw::bus:
case hw::system:
cout << decimalkilos(node.getSize()) << "Hz";
if (html)
cout << "</td></tr>";
break;
case hw::network:
cout << decimalkilos(node.getSize()) << "bit/s";
if (html)
cout << "</td></tr>";
break;
case hw::power:
cout << node.getSize();
cout << "mWh";
if (html)
cout << "</td></tr>";
break;
default:
cout << node.getSize();
if (html)
cout << "</td></tr>";
}
cout << endl;
}
if (node.getCapacity() > 0)
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("capacity") << ": ";
if (html)
cout << "</td><td class=\"second\">";
switch (node.getClass())
{
case hw::disk:
cout << kilobytes(node.getCapacity()) << " (" << decimalkilos(node.getCapacity()) << "B)";
if (html)
cout << "</td></tr>";
break;
case hw::memory:
case hw::address:
case hw::storage:
case hw::volume:
cout << kilobytes(node.getCapacity());
if (html)
cout << "</td></tr>";
break;
case hw::processor:
case hw::bus:
case hw::system:
cout << decimalkilos(node.getCapacity());
cout << "Hz";
if (html)
cout << "</td></tr>";
break;
case hw::network:
cout << decimalkilos(node.getCapacity());
cout << "bit/s";
if (html)
cout << "</td></tr>";
break;
case hw::power:
cout << node.getCapacity();
cout << "mWh";
if (html)
cout << "</td></tr>";
break;
default:
cout << node.getCapacity();
if (html)
cout << "</td></tr>";
}
cout << endl;
}
if (node.getClass() == hw::address)
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
if (node.getSize() == 0)
cout << _("address") << ": " << hex << setfill('0') << setw(8) << node.
getStart() << dec;
else
cout << _("range") << ": " << hex << setfill('0') << setw(8) << node.
getStart() << " - " << hex << setfill('0') << setw(8) << node.
getStart() + node.getSize() - 1 << dec;
cout << endl;
}
if (node.getWidth() > 0)
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("width") << ": ";
if (html)
cout << "</td><td class=\"second\">";
cout << node.getWidth() << " bits";
if (html)
cout << "</td></tr>";
cout << endl;
}
if (node.getClock() > 0)
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("clock") << ": ";
if (html)
cout << "</td><td class=\"second\">";
cout << decimalkilos(node.getClock());
cout << "Hz";
if (node.getClass() == hw::memory)
cout << " (" << setiosflags(ios::fixed) << setprecision(1) << 1.0e9 / node.getClock() << "ns)";
if (html)
cout << "</td></tr>";
cout << endl;
}
if (node.getCapabilities() != "")
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("capabilities") << ": ";
if (html)
{
vector < string > capabilities = node.getCapabilitiesList();
cout << "</td><td class=\"second\">";
for(unsigned i=0; i<capabilities.size(); i++)
{
cout << "<dfn title=\"" << escape(node.getCapabilityDescription(capabilities[i])) << "\">" << capabilities[i] << "</dfn> ";
}
cout << "</td></tr>";
}
else
cout << node.getCapabilities();
cout << endl;
}
if (config.size() > 0)
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("configuration:");
if (html)
cout << "</td><td class=\"second\"><table summary=\"" << _("configuration of ") << node.
getId() << "\">";
for (unsigned int i = 0; i < config.size(); i++)
{
if (html)
cout << "<tr><td class=\"sub-first\">";
cout << " " << config[i];
if (html)
cout << "</td></tr>";
}
if (html)
cout << "</table></td></tr>";
cout << endl;
}
if (resources.size() > 0)
{
tab(level + 1, false);
if (html)
cout << "<tr><td class=\"first\">";
cout << _("resources:");
if (html)
cout << "</td><td class=\"second\"><table summary=\"" << _("resources of ") << node.
getId() << "\">";
for (unsigned int i = 0; i < resources.size(); i++)
{
if (html)
cout << "<tr><td class=\"sub-first\">";
cout << " " << resources[i];
if (html)
cout << "</td></tr>";
}
if (html)
cout << "</table></td></tr>";
cout << endl;
}
if (html)
cout << " </tbody>";
if (html)
{
tab(level, false);
cout << "</table></div>" << endl;
}
} // if visible
for (unsigned int i = 0; i < node.countChildren(); i++)
{
if(html)
cout << "<div class=\"indented\">" << endl;
print(*node.getChild(i), html, visible(node.getClassName()) ? level + 1 : 1);
if(html)
cout << "</div>" << endl;
}
if (html)
{
if (visible(node.getClassName()))
{
tab(level, false);
}
if (level == 0)
{
cout << "</body>" << endl;
cout << "</html>" << endl;
}
}
}
struct hwpath
{
string path;
string description;
string devname;
string classname;
};
static void printhwnode(hwNode & node, vector < hwpath > &l, string prefix = "")
{
hwpath entry;
entry.path = "";
if (node.getPhysId() != "")
entry.path = prefix + "/" + node.getPhysId();
entry.description = node.asString();
entry.devname = node.getLogicalName();
entry.classname = node.getClassName();
l.push_back(entry);
for (unsigned int i = 0; i < node.countChildren(); i++)
{
printhwnode(*node.getChild(i), l, entry.path);
}
}
static void printbusinfo(hwNode & node, vector < hwpath > &l)
{
hwpath entry;
entry.path = "";
if (node.getBusInfo() != "")
entry.path = node.getBusInfo();
entry.description = node.asString();
entry.devname = node.getLogicalName();
entry.classname = node.getClassName();
l.push_back(entry);
for (unsigned int i = 0; i < node.countChildren(); i++)
{
printbusinfo(*node.getChild(i), l);
}
}
static void printline(ostringstream & out)
{
string s = out.str();
if(isatty(STDOUT_FILENO) && (s.length()>columns))
s.erase(columns);
cout << s << endl;
out.str("");
}
static void printincolumns( vector < hwpath > &l, const char *cols[])
{
unsigned int l1 = strlen(_(cols[0])),
l2 = strlen(_(cols[1])),
l3 = strlen(_(cols[2]));
unsigned int i = 0;
ostringstream out;
for (i = 0; i < l.size(); i++)
{
if (l1 < l[i].path.length())
l1 = l[i].path.length();
if (l2 < l[i].devname.length())
l2 = l[i].devname.length();
if (l3 < l[i].classname.length())
l3 = l[i].classname.length();
}
out << _(cols[0]);
out << spaces(2 + l1 - strlen(_(cols[0])));
out << _(cols[1]);
out << spaces(2 + l2 - strlen(_(cols[1])));
out << _(cols[2]);
out << spaces(2 + l3 - strlen(_(cols[2])));
out << _(cols[3]);
printline(out);
out << spaces(l1 + l2 + l3 + strlen(_(cols[3])) + 6, "=");
printline(out);
for (i = 0; i < l.size(); i++)
if (visible(l[i].classname.c_str()))
{
out << l[i].path;
out << spaces(2 + l1 - l[i].path.length());
out << l[i].devname;
out << spaces(2 + l2 - l[i].devname.length());
out << l[i].classname;
out << spaces(2 + l3 - l[i].classname.length());
out << l[i].description;
printline(out);
}
}
static const char *hwpathcols[] =
{
N_("H/W path"),
N_("Device"),
N_("Class"),
N_("Description")
};
void printhwpath(hwNode & node)
{
vector < hwpath > l;
printhwnode(node, l);
init_wsize();
printincolumns(l, hwpathcols);
}
static const char *businfocols[] =
{
N_("Bus info"),
N_("Device"),
N_("Class"),
N_("Description")
};
void printbusinfo(hwNode & node)
{
vector < hwpath > l;
printbusinfo(node, l);
init_wsize();
printincolumns(l, businfocols);
}

11
src/core/print.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _PRINT_H_
#define _PRINT_H_
#include "hw.h"
void print(hwNode & node, bool html=true, int level = 0);
void printhwpath(hwNode & node);
void printbusinfo(hwNode & node);
void status(const char *);
#endif

156
src/core/s390.cc Normal file
View File

@ -0,0 +1,156 @@
#include "hw.h"
#include "sysfs.h"
#include "disk.h"
#include "s390.h"
#include <string.h>
using namespace std;
struct ccw_device_def {
const char *cutype;
const char *devtype;
const char *description;
hw::hwClass hwClass;
};
struct ccw_device_def ccw_device_defs[] =
{
{"1403", "", "Line printer", hw::printer},
{"1731/01", "1732/01", "OSA-Express QDIO channel", hw::network},
{"1731/02", "1732/02", "OSA-Express intraensemble data network (IEDN) channel", hw::network},
{"1731/02", "1732/03", "OSA-Express intranode management network (NMN) channel", hw::network},
{"1731/05", "1732/05", "HiperSockets network", hw::network},
{"1731/06", "1732/06", "OSA-Express Network Control Program channel", hw::network},
{"1731", "1732", "Network adapter", hw::network},
{"1750", "3380", "Direct attached storage device (ECKD mode)", hw::disk},
{"1750", "3390", "Direct attached storage device (ECKD mode)", hw::disk},
{"2105", "3380", "Direct attached storage device (ECKD mode)", hw::disk},
{"2105", "3390", "Direct attached storage device (ECKD mode)", hw::disk},
{"2107", "3380", "Direct attached storage device (ECKD mode)", hw::disk},
{"2107", "3390", "Direct attached storage device (ECKD mode)", hw::disk},
{"2540", "", "Card reader/punch", hw::generic},
{"3088/01", "", "P/390 LAN channel station card", hw::communication},
{"3088/08", "", "Channel-to-Channel device", hw::network},
{"3088/1e", "", "Channel-to-Channel FICON adapter", hw::network},
{"3088/1f", "", "Channel-to-Channel ESCON adapter", hw::network},
{"3088/60", "", "LAN channel station OSA-2 card", hw::network},
{"3174", "", "3174 Establishment Controller", hw::generic},
{"3215", "", "3215 terminal", hw::communication},
{"3270", "", "3270 terminal", hw::communication},
{"3271", "", "3270 terminal", hw::communication},
{"3272", "", "3270 terminal", hw::communication},
{"3273", "", "3270 terminal", hw::communication},
{"3274", "", "3270 terminal", hw::communication},
{"3275", "", "3270 terminal", hw::communication},
{"3276", "", "3270 terminal", hw::communication},
{"3277", "", "3270 terminal", hw::communication},
{"3278", "", "3270 terminal", hw::communication},
{"3279", "", "3270 terminal", hw::communication},
{"3480", "3480", "3480 tape drive", hw::storage},
{"3490", "3490", "3490 tape drive", hw::storage},
{"3590", "3590", "3590 tape drive", hw::storage},
{"3592", "3592", "3592 tape drive", hw::storage},
{"3832", "", "Virtual network device", hw::network},
{"3880", "3370", "Direct attached storage device (FBA mode)", hw::disk},
{"3880", "3380", "Direct attached storage device (ECKD mode)", hw::disk},
{"3990", "3380", "Direct attached storage device (ECKD mode)", hw::disk},
{"3990", "3390", "Direct attached storage device (ECKD mode)", hw::disk},
{"6310", "9336", "Direct attached storage device (FBA mode)", hw::disk},
{"9343", "9345", "Direct attached storage device (ECKD mode)", hw::disk},
};
static void ccw_devtype(hwNode & device, string cutype, string devtype)
{
for (size_t i = 0; i < sizeof(ccw_device_defs) / sizeof(ccw_device_def); i ++)
{
ccw_device_def d = ccw_device_defs[i];
if (cutype.compare(0, strlen(d.cutype), d.cutype) == 0 &&
devtype.compare(0, strlen(d.devtype), d.devtype) == 0)
{
device.setClass(d.hwClass);
device.setDescription(d.description);
break;
}
}
if (!devtype.empty() && devtype != "n/a")
device.setProduct(devtype);
}
static bool scan_ccw(hwNode & n)
{
vector < sysfs::entry > entries = sysfs::entries_by_bus("ccw");
if (entries.empty())
return false;
for (vector < sysfs::entry >::iterator it = entries.begin();
it != entries.end(); ++it)
{
const sysfs::entry & e = *it;
hwNode device("device");
ccw_devtype(device, e.string_attr("cutype"), e.string_attr("devtype"));
string vendor = hw::strip(e.string_attr("vendor"));
if (!vendor.empty())
device.setVendor(vendor);
string businfo = e.businfo();
if (!businfo.empty())
device.setBusInfo(businfo);
if (e.string_attr("online") != "1")
device.disable();
string driver = e.driver();
if (!driver.empty())
device.setConfig("driver", driver);
string devname = e.name_in_class("block");
if (!devname.empty())
{
device.setLogicalName(devname);
scan_disk(device);
}
device.claim();
n.addChild(device);
}
return true;
}
static bool scan_iucv(hwNode & n)
{
vector < sysfs::entry > entries = sysfs::entries_by_bus("iucv");
if (entries.empty())
return false;
for (vector < sysfs::entry >::iterator it = entries.begin();
it != entries.end(); ++it)
{
const sysfs::entry & e = *it;
hwNode device(e.name());
string driver = e.driver();
if (!driver.empty())
device.setConfig("driver", driver);
if (driver == "hvc_iucv")
device.setDescription("z/VM IUCV hypervisor console");
else
device.setDescription("z/VM IUCV device");
device.claim();
n.addChild(device);
}
return true;
}
bool scan_s390_devices(hwNode & n)
{
scan_ccw(n);
scan_iucv(n);
return true;
}

7
src/core/s390.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _S390_H_
#define _S390_H_
#include "hw.h"
bool scan_s390_devices(hwNode & n);
#endif

914
src/core/scsi.cc Normal file
View File

@ -0,0 +1,914 @@
#include "version.h"
#include "mem.h"
#include "cdrom.h"
#include "disk.h"
#include "osutils.h"
#include "heuristics.h"
#include "sysfs.h"
#include <glob.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <scsi/sg.h>
#include <scsi/scsi.h>
#ifndef MKDEV
#include <linux/kdev_t.h>
#endif
#ifndef MINOR
#include <linux/kdev_t.h>
#endif
#include <string>
#include <map>
__ID("@(#) $Id$");
#define SG_X "/dev/sg[0-9]*"
#define SG_MAJOR 21
#ifndef SCSI_IOCTL_GET_PCI
#define SCSI_IOCTL_GET_PCI 0x5387
#endif
#define OPEN_FLAG O_RDWR
#define SENSE_BUFF_LEN 32
#define INQ_REPLY_LEN 96
#define INQ_CMD_CODE 0x12
#define INQ_CMD_LEN 6
#define INQ_PAGE_SERIAL 0x80
#define SENSE_REPLY_LEN 96
#define SENSE_CMD_CODE 0x1a
#define SENSE_CMD_LEN 6
#define SENSE_PAGE_SERIAL 0x80
#define MX_ALLOC_LEN 255
#define EBUFF_SZ 256
/* Some of the following error/status codes are exchanged between the
various layers of the SCSI sub-system in Linux and should never
reach the user. They are placed here for completeness. What appears
here is copied from drivers/scsi/scsi.h which is not visible in
the user space. */
#ifndef SCSI_CHECK_CONDITION
/* Following are the "true" SCSI status codes. Linux has traditionally
used a 1 bit right and masked version of these. So now CHECK_CONDITION
and friends (in <scsi/scsi.h>) are deprecated. */
#define SCSI_CHECK_CONDITION 0x2
#define SCSI_CONDITION_MET 0x4
#define SCSI_BUSY 0x8
#define SCSI_IMMEDIATE 0x10
#define SCSI_IMMEDIATE_CONDITION_MET 0x14
#define SCSI_RESERVATION_CONFLICT 0x18
#define SCSI_COMMAND_TERMINATED 0x22
#define SCSI_TASK_SET_FULL 0x28
#define SCSI_ACA_ACTIVE 0x30
#define SCSI_TASK_ABORTED 0x40
#endif
/* The following are 'host_status' codes */
#ifndef DID_OK
#define DID_OK 0x00
#endif
#ifndef DID_NO_CONNECT
#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */
#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */
#define DID_TIME_OUT 0x03 /* Timed out for some other reason */
#define DID_BAD_TARGET 0x04 /* Bad target (id?) */
#define DID_ABORT 0x05 /* Told to abort for some other reason */
#define DID_PARITY 0x06 /* Parity error (on SCSI bus) */
#define DID_ERROR 0x07 /* Internal error */
#define DID_RESET 0x08 /* Reset by somebody */
#define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */
#define DID_PASSTHROUGH 0x0a /* Force command past mid-level */
#define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */
#endif
/* These defines are to isolate applictaions from kernel define changes */
#define SG_ERR_DID_OK DID_OK
#define SG_ERR_DID_NO_CONNECT DID_NO_CONNECT
#define SG_ERR_DID_BUS_BUSY DID_BUS_BUSY
#define SG_ERR_DID_TIME_OUT DID_TIME_OUT
#define SG_ERR_DID_BAD_TARGET DID_BAD_TARGET
#define SG_ERR_DID_ABORT DID_ABORT
#define SG_ERR_DID_PARITY DID_PARITY
#define SG_ERR_DID_ERROR DID_ERROR
#define SG_ERR_DID_RESET DID_RESET
#define SG_ERR_DID_BAD_INTR DID_BAD_INTR
#define SG_ERR_DID_PASSTHROUGH DID_PASSTHROUGH
#define SG_ERR_DID_SOFT_ERROR DID_SOFT_ERROR
/* The following are 'driver_status' codes */
#ifndef DRIVER_OK
#define DRIVER_OK 0x00
#endif
#ifndef DRIVER_BUSY
#define DRIVER_BUSY 0x01
#define DRIVER_SOFT 0x02
#define DRIVER_MEDIA 0x03
#define DRIVER_ERROR 0x04
#define DRIVER_INVALID 0x05
#define DRIVER_TIMEOUT 0x06
#define DRIVER_HARD 0x07
#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */
/* Following "suggests" are "or-ed" with one of previous 8 entries */
#define SUGGEST_RETRY 0x10
#define SUGGEST_ABORT 0x20
#define SUGGEST_REMAP 0x30
#define SUGGEST_DIE 0x40
#define SUGGEST_SENSE 0x80
#define SUGGEST_IS_OK 0xff
#endif
#ifndef DRIVER_MASK
#define DRIVER_MASK 0x0f
#endif
#ifndef SUGGEST_MASK
#define SUGGEST_MASK 0xf0
#endif
/* These defines are to isolate applictaions from kernel define changes */
#define SG_ERR_DRIVER_OK DRIVER_OK
#define SG_ERR_DRIVER_BUSY DRIVER_BUSY
#define SG_ERR_DRIVER_SOFT DRIVER_SOFT
#define SG_ERR_DRIVER_MEDIA DRIVER_MEDIA
#define SG_ERR_DRIVER_ERROR DRIVER_ERROR
#define SG_ERR_DRIVER_INVALID DRIVER_INVALID
#define SG_ERR_DRIVER_TIMEOUT DRIVER_TIMEOUT
#define SG_ERR_DRIVER_HARD DRIVER_HARD
#define SG_ERR_DRIVER_SENSE DRIVER_SENSE
#define SG_ERR_SUGGEST_RETRY SUGGEST_RETRY
#define SG_ERR_SUGGEST_ABORT SUGGEST_ABORT
#define SG_ERR_SUGGEST_REMAP SUGGEST_REMAP
#define SG_ERR_SUGGEST_DIE SUGGEST_DIE
#define SG_ERR_SUGGEST_SENSE SUGGEST_SENSE
#define SG_ERR_SUGGEST_IS_OK SUGGEST_IS_OK
#define SG_ERR_DRIVER_MASK DRIVER_MASK
#define SG_ERR_SUGGEST_MASK SUGGEST_MASK
/* The following "category" function returns one of the following */
#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */
#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */
#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */
#define SG_ERR_CAT_TIMEOUT 3
#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */
#define SG_ERR_CAT_SENSE 98 /* Something else is in the sense buffer */
#define SG_ERR_CAT_OTHER 99 /* Some other error/warning has occurred */
typedef struct my_sg_scsi_id
{
int host_no; /* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */
int channel;
int scsi_id; /* scsi id of target device */
int lun;
int scsi_type; /* TYPE_... defined in scsi/scsi.h */
short h_cmd_per_lun; /* host (adapter) maximum commands per lun */
short d_queue_depth; /* device (or adapter) maximum queue length */
int unused1; /* probably find a good use, set 0 for now */
int unused2; /* ditto */
}
My_sg_scsi_id;
typedef struct my_scsi_idlun
{
int mux4;
int host_unique_id;
}
My_scsi_idlun;
static const char *devices[] =
{
"/dev/sd*[!0-9]", /* don't look at partitions */
"/dev/scd*",
"/dev/sr*",
"/dev/cd*",
"/dev/dvd*",
"/dev/nst*",
"/dev/nosst*",
"/dev/ntape*",
"/dev/nrtape*",
NULL
};
static map < string, string > sg_map;
static string scsi_handle(unsigned int host,
int channel = -1,
int id = -1,
int lun = -1)
{
char buffer[10];
string result = "SCSI:";
snprintf(buffer, sizeof(buffer), "%02d", host);
result += string(buffer);
if (channel < 0)
return result;
snprintf(buffer, sizeof(buffer), "%02d", channel);
result += string(":") + string(buffer);
if (id < 0)
return result;
snprintf(buffer, sizeof(buffer), "%02d", id);
result += string(":") + string(buffer);
if (lun < 0)
return result;
snprintf(buffer, sizeof(buffer), "%02d", lun);
result += string(":") + string(buffer);
return result;
}
static const char *scsi_type(int type)
{
switch (type)
{
case 0:
return "Disk";
case 1:
return "Tape";
case 3:
return "Processor";
case 4:
return "Write-Once Read-Only Memory";
case 5:
return "CD-ROM";
case 6:
return "Scanner";
case 7:
return "Magneto-optical Disk";
case 8:
return "Medium Changer";
case 0xd:
return "Enclosure";
case 0xe:
return "Simplified direct-access device";
case 0x14:
return "Host managed zoned block device";
default:
return "";
}
}
static int sg_err_category(int scsi_status,
int host_status,
int driver_status,
const unsigned char *sense_buffer,
int sb_len)
{
scsi_status &= 0x7e;
if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status))
return SG_ERR_CAT_CLEAN;
if ((SCSI_CHECK_CONDITION == scsi_status) ||
(SCSI_COMMAND_TERMINATED == scsi_status) ||
(SG_ERR_DRIVER_SENSE == (0xf & driver_status)))
{
if (sense_buffer && (sb_len > 2))
{
int sense_key;
unsigned char asc;
if (sense_buffer[0] & 0x2)
{
sense_key = sense_buffer[1] & 0xf;
asc = sense_buffer[2];
}
else
{
sense_key = sense_buffer[2] & 0xf;
asc = (sb_len > 12) ? sense_buffer[12] : 0;
}
if (RECOVERED_ERROR == sense_key)
return SG_ERR_CAT_RECOVERED;
else if (UNIT_ATTENTION == sense_key)
{
if (0x28 == asc)
return SG_ERR_CAT_MEDIA_CHANGED;
if (0x29 == asc)
return SG_ERR_CAT_RESET;
}
}
return SG_ERR_CAT_SENSE;
}
if (0 != host_status)
{
if ((SG_ERR_DID_NO_CONNECT == host_status) ||
(SG_ERR_DID_BUS_BUSY == host_status) ||
(SG_ERR_DID_TIME_OUT == host_status))
return SG_ERR_CAT_TIMEOUT;
}
if (0 != driver_status)
{
if (SG_ERR_DRIVER_TIMEOUT == driver_status)
return SG_ERR_CAT_TIMEOUT;
}
return SG_ERR_CAT_OTHER;
}
static bool do_modesense(int sg_fd,
int page,
int page_code,
void *resp,
int mx_resp_len)
{
int res;
unsigned char senseCmdBlk[SENSE_CMD_LEN] =
{ SENSE_CMD_CODE, 0, 0, 0, 0, 0 };
unsigned char sense_b[SENSE_BUFF_LEN];
sg_io_hdr_t io_hdr;
page &= 0x3f;
page_code &= 3;
senseCmdBlk[2] = (unsigned char) ((page_code << 6) | page);
senseCmdBlk[4] = (unsigned char) 0xff;
memset(&io_hdr, 0, sizeof(io_hdr));
memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(senseCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_b);
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.dxfer_len = mx_resp_len;
io_hdr.dxferp = resp;
io_hdr.cmdp = senseCmdBlk;
io_hdr.sbp = sense_b;
io_hdr.timeout = 20000; /* 20 seconds */
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
return false;
res =
sg_err_category(io_hdr.status, io_hdr.host_status, io_hdr.driver_status,
(unsigned char*)io_hdr.sbp, io_hdr.sb_len_wr);
switch (res)
{
case SG_ERR_CAT_CLEAN:
case SG_ERR_CAT_RECOVERED:
return true;
default:
return false;
}
return true;
}
static bool do_inq(int sg_fd,
int cmddt,
int evpd,
unsigned int pg_op,
void *resp,
int mx_resp_len,
int noisy)
{
int res;
unsigned char inqCmdBlk[INQ_CMD_LEN] = { INQ_CMD_CODE, 0, 0, 0, 0, 0 };
unsigned char sense_b[SENSE_BUFF_LEN];
sg_io_hdr_t io_hdr;
if (cmddt)
inqCmdBlk[1] |= 2;
if (evpd)
inqCmdBlk[1] |= 1;
inqCmdBlk[2] = (unsigned char) pg_op;
inqCmdBlk[4] = (unsigned char) mx_resp_len;
memset(&io_hdr, 0, sizeof(io_hdr));
memset(sense_b, 0, sizeof(sense_b));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(inqCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_b);
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.dxfer_len = mx_resp_len;
io_hdr.dxferp = resp;
io_hdr.cmdp = inqCmdBlk;
io_hdr.sbp = sense_b;
io_hdr.timeout = 20000; /* 20 seconds */
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
return false;
res =
sg_err_category(io_hdr.status, io_hdr.host_status, io_hdr.driver_status,
(unsigned char*)io_hdr.sbp, io_hdr.sb_len_wr);
switch (res)
{
case SG_ERR_CAT_CLEAN:
case SG_ERR_CAT_RECOVERED:
return true;
default:
return false;
}
return true;
}
static unsigned long decode_3_bytes(void *ptr)
{
unsigned char *p = (unsigned char *) ptr;
return (p[0] << 16) + (p[1] << 8) + p[2];
}
static u_int16_t decode_word(void *ptr)
{
unsigned char *p = (unsigned char *) ptr;
return (p[0] << 8) + p[1];
}
static bool do_inquiry(int sg_fd,
hwNode & node)
{
uint8_t rsp_buff[MX_ALLOC_LEN + 1];
int k;
unsigned int len;
if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000))
return false;
memset(rsp_buff, 0, sizeof(rsp_buff));
if (!do_inq(sg_fd, 0, 0, 0, rsp_buff, 36, 1))
return false;
len = (unsigned int) rsp_buff[4] + 5;
if ((len >= 36) && (len < 256))
{
memset(rsp_buff, 0, sizeof(rsp_buff));
if (!do_inq(sg_fd, 0, 0, 0, rsp_buff, len, 1))
return false;
}
else
return false;
if (len != ((unsigned int) rsp_buff[4] + 5))
return false; // twin INQUIRYs yield different lengths
unsigned ansiversion = rsp_buff[2] & 0x7;
if (rsp_buff[1] & 0x80)
node.addCapability("removable", "support is removable");
node.setVendor(string((char *)rsp_buff + 8, 8));
if (len > 16)
node.setProduct(string((char *)rsp_buff + 16, 16));
if (len > 32)
node.setVersion(string((char *)rsp_buff + 32, 4));
if (ansiversion)
node.setConfig("ansiversion", tostring(ansiversion));
memset(rsp_buff, 0, sizeof(rsp_buff));
if (do_inq(sg_fd, 0, 1, 0x80, rsp_buff, MX_ALLOC_LEN, 0))
{
uint8_t _len = rsp_buff[3];
if (_len > 0)
node.setSerial(hw::strip(string((char *)rsp_buff + 4, _len)));
}
memset(rsp_buff, 0, sizeof(rsp_buff));
if (do_modesense(sg_fd, 0x3F, 0, rsp_buff, sizeof(rsp_buff)))
{
unsigned long long sectsize = 0;
unsigned long long heads = 0;
unsigned long long cyl = 0;
unsigned long long sectors = 0;
unsigned long rpm = 0;
uint8_t *end = rsp_buff + rsp_buff[0];
uint8_t *p = NULL;
if (rsp_buff[3] == 8)
sectsize = decode_3_bytes(rsp_buff + 9);
p = & rsp_buff[4];
p += rsp_buff[3];
while (p < end)
{
u_int8_t page = *p & 0x3F;
if (page == 3)
{
sectors = decode_word(p + 10);
sectsize = decode_word(p + 12);
}
if (page == 4)
{
cyl = decode_3_bytes(p + 2);
rpm = decode_word(p + 20);
heads = p[5];
}
p += p[1] + 2;
}
node.setCapacity(heads * cyl * sectors * sectsize);
if (rpm / 15000 == 1)
node.addCapability("15000rpm", "15000 rotations per minute");
else
{
if (rpm / 10000 == 1)
node.addCapability("10000rpm", "10000 rotations per minute");
else
{
if (rpm / 7200 == 1)
node.addCapability("7200rpm", "7200 rotations per minute");
else
{
if (rpm / 5400 == 1)
node.addCapability("5400rpm", "5400 rotations per minute");
}
}
}
}
return true;
}
static void scan_devices()
{
int fd = -1;
int i = 0;
size_t j = 0;
My_scsi_idlun m_idlun;
for (i = 0; devices[i] != NULL; i++)
{
glob_t entries;
if(glob(devices[i], 0, NULL, &entries) == 0)
{
for(j=0; j < entries.gl_pathc; j++)
{
fd = open(entries.gl_pathv[j], O_RDONLY | O_NONBLOCK);
if (fd >= 0)
{
int bus = -1;
union
{
char host[50];
int length;
} tmp;
tmp.length = sizeof(tmp.host);
memset(tmp.host, 0, sizeof(tmp.host));
if(ioctl(fd, SCSI_IOCTL_PROBE_HOST, &tmp.length) >= 0)
{
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus) >= 0)
{
memset(&m_idlun, 0, sizeof(m_idlun));
if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun) >= 0)
{
sg_map[string(entries.gl_pathv[j])] = scsi_handle(bus, (m_idlun.mux4 >> 16) & 0xff,
m_idlun.mux4 & 0xff,
(m_idlun.mux4 >> 8) & 0xff);
}
}
}
close(fd);
}
}
globfree(&entries);
}
}
}
static void find_logicalname(hwNode & n)
{
map < string, string >::iterator i = sg_map.begin();
for (i = sg_map.begin(); i != sg_map.end(); i++)
{
if (i->second == n.getHandle())
{
n.setLogicalName(i->first);
n.claim();
}
}
}
static string scsi_businfo(int host,
int channel = -1,
int target = -1,
int lun = -1)
{
string result;
result = "scsi@" + tostring(host);
if (channel >= 0)
{
result += ":" + tostring(channel);
if (target >= 0)
{
result += "." + tostring(target);
if (lun >= 0)
result += "." + tostring(lun);
}
}
return result;
}
static string host_logicalname(int i)
{
return "scsi"+tostring(i);
}
static string host_kname(int i) // for sysfs
{
return "host"+tostring(i);
}
static bool atapi(const hwNode & n)
{
return n.isCapable("atapi") && (n.countChildren() == 0);
}
static void scan_sg(hwNode & n)
{
int sg;
int fd = -1;
My_sg_scsi_id m_id;
string host = "";
string businfo = "";
string adapter_businfo = "";
int emulated = 0;
bool ghostdeventry = false;
size_t j;
glob_t entries;
if(glob(SG_X, 0, NULL, &entries) == 0)
{
for(j=0; j < entries.gl_pathc; j++)
{
sg = strtol(strpbrk(entries.gl_pathv[j], "0123456789"), NULL, 10);
ghostdeventry = !exists(entries.gl_pathv[j]);
if(ghostdeventry)
mknod(entries.gl_pathv[j], (S_IFCHR | S_IREAD), MKDEV(SG_MAJOR, sg));
fd = open(entries.gl_pathv[j], OPEN_FLAG | O_NONBLOCK);
if(ghostdeventry)
unlink(entries.gl_pathv[j]);
if (fd < 0)
continue;
memset(&m_id, 0, sizeof(m_id));
if (ioctl(fd, SG_GET_SCSI_ID, &m_id) < 0)
{
close(fd);
continue; // we failed to get info but still hope we can continue
}
emulated = 0;
ioctl(fd, SG_EMULATED_HOST, &emulated);
host = host_logicalname(m_id.host_no);
businfo = scsi_businfo(m_id.host_no);
adapter_businfo =
sysfs::entry::byClass("scsi_host", host_kname(m_id.host_no))
.parent().businfo();
hwNode device = hwNode("generic");
hwNode *parent = NULL;
switch (m_id.scsi_type)
{
case 0:
case 14:
case 20:
device = hwNode("disk", hw::disk);
break;
case 1:
device = hwNode("tape", hw::tape);
break;
case 3:
device = hwNode("processor", hw::processor);
break;
case 4:
case 5:
device = hwNode("cdrom", hw::disk);
break;
case 6:
device = hwNode("scanner", hw::generic);
break;
case 7:
device = hwNode("magnetooptical", hw::disk);
break;
case 8:
device = hwNode("changer", hw::generic);
break;
case 0xd:
device = hwNode("enclosure", hw::generic);
break;
}
device.setDescription(string(scsi_type(m_id.scsi_type)));
device.setHandle(scsi_handle(m_id.host_no,
m_id.channel, m_id.scsi_id, m_id.lun));
device.setBusInfo(scsi_businfo(m_id.host_no,
m_id.channel, m_id.scsi_id, m_id.lun));
device.setPhysId(m_id.channel, m_id.scsi_id, m_id.lun);
find_logicalname(device);
do_inquiry(fd, device);
if(device.getVendor() == "ATA")
{
device.setDescription("ATA " + device.getDescription());
device.setVendor("");
}
else
{
device.setDescription("SCSI " + device.getDescription());
device.addHint("bus.icon", string("scsi"));
}
if ((m_id.scsi_type == 4) || (m_id.scsi_type == 5))
scan_cdrom(device);
if ((m_id.scsi_type == 0) || (m_id.scsi_type == 7) ||
(m_id.scsi_type == 14) || (m_id.scsi_type == 20))
scan_disk(device);
if (!adapter_businfo.empty())
{
parent = n.findChildByBusInfo(adapter_businfo);
}
if (!parent)
parent = n.findChildByLogicalName(host);
// IDE-SCSI pseudo host controller
if (emulated && device.getConfig("driver")=="ide-scsi")
{
hwNode *ideatapi = n.findChild(atapi);
if (ideatapi)
parent = ideatapi->addChild(hwNode("scsi", hw::storage));
}
if (!parent)
{
hwNode *core = n.getChild("core");
if (core)
parent = core->addChild(hwNode("scsi", hw::storage));
}
if (!parent)
parent = n.addChild(hwNode("scsi", hw::storage));
if (parent)
{
if(parent->getBusInfo() == "")
parent->setBusInfo(adapter_businfo);
parent->setLogicalName(host);
parent->claim();
if (emulated)
{
parent->addCapability("emulated", "Emulated device");
}
parent->addChild(device);
}
close(fd);
}
globfree(&entries);
}
}
static bool scan_hosts(hwNode & node)
{
struct dirent **namelist = NULL;
int n;
vector < string > host_strs;
if (!pushd("/proc/scsi"))
return false;
n = scandir(".", &namelist, selectdir, alphasort);
popd();
if ((n < 0) || !namelist)
return false;
pushd("/proc/scsi");
for (int i = 0; i < n; i++)
{
struct dirent **filelist = NULL;
int m = 0;
pushd(namelist[i]->d_name);
m = scandir(".", &filelist, NULL, alphasort);
popd();
if (m >= 0)
{
for (int j = 0; j < m; j++)
{
char *end = NULL;
int number = -1;
number = strtol(filelist[j]->d_name, &end, 0);
if ((number >= 0) && (end != filelist[j]->d_name))
{
hwNode *controller =
node.findChildByLogicalName(host_logicalname(number));
if (!controller)
{
string parentbusinfo = sysfs::entry::byClass("scsi_host", host_kname(number)).businfo();
controller = node.findChildByBusInfo(parentbusinfo);
}
if (!controller)
{
controller = node.addChild(hwNode("scsi", hw::storage));
if (controller)
{
controller->setLogicalName(host_logicalname(number));
controller->setBusInfo(scsi_businfo(number));
}
}
if (controller)
{
controller->setLogicalName(host_logicalname(number));
controller->setConfig(string("driver"),
string(namelist[i]->d_name));
controller->setHandle(scsi_handle(number));
controller->addCapability("scsi-host", "SCSI host adapter");
controller->claim();
}
}
free(filelist[j]);
}
free(filelist);
}
free(namelist[i]);
}
free(namelist);
popd();
if (!loadfile("/proc/scsi/sg/host_strs", host_strs))
return false;
for (unsigned int i = 0; i < host_strs.size(); i++)
{
hwNode *host = node.findChildByLogicalName(host_logicalname(i));
if (host)
{
if ((host->getProduct() == "") && (host->getDescription() == ""))
host->setDescription("SCSI storage controller");
}
}
return true;
}
bool scan_scsi(hwNode & n)
{
scan_devices();
scan_sg(n);
scan_hosts(n);
return false;
}

7
src/core/scsi.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _SCSI_H_
#define _SCSI_H_
#include "hw.h"
bool scan_scsi(hwNode & n);
#endif

417
src/core/smp.cc Normal file
View File

@ -0,0 +1,417 @@
/*
* smp.cc
*
*
*/
#include "version.h"
#include "smp.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "osutils.h"
__ID("@(#) $Id: smp.cc 1897 2007-10-02 13:29:47Z lyonel $");
#if defined(__i386__)
typedef unsigned long vm_offset_t;
/* MP Floating Pointer Structure */
typedef struct MPFPS {
char signature[4];
uint32_t pap;
uint8_t length;
uint8_t spec_rev;
uint8_t checksum;
uint8_t mpfb1;
uint8_t mpfb2;
uint8_t mpfb3;
uint8_t mpfb4;
uint8_t mpfb5;
} mpfps_t;
/* MP Configuration Table Header */
typedef struct MPCTH {
char signature[ 4 ];
u_short base_table_length;
uint8_t spec_rev;
uint8_t checksum;
char oem_id[ 8 ];
char product_id[ 12 ];
void* oem_table_pointer;
u_short oem_table_size;
u_short entry_count;
void* apic_address;
u_short extended_table_length;
uint8_t extended_table_checksum;
uint8_t reserved;
} mpcth_t;
typedef struct PROCENTRY {
uint8_t type;
uint8_t apicID;
uint8_t apicVersion;
uint8_t cpuFlags;
uint32_t cpuSignature;
uint32_t featureFlags;
uint32_t reserved1;
uint32_t reserved2;
} ProcEntry;
/* EBDA is @ 40:0e in real-mode terms */
#define EBDA_POINTER 0x040e /* location of EBDA pointer */
/* CMOS 'top of mem' is @ 40:13 in real-mode terms */
#define TOPOFMEM_POINTER 0x0413 /* BIOS: base memory size */
#define DEFAULT_TOPOFMEM 0xa0000
#define BIOS_BASE 0xf0000
#define BIOS_BASE2 0xe0000
#define BIOS_SIZE 0x10000
#define ONE_KBYTE 1024
#define GROPE_AREA1 0x80000
#define GROPE_AREA2 0x90000
#define GROPE_SIZE 0x10000
#define PROCENTRY_FLAG_EN 0x01
#define PROCENTRY_FLAG_BP 0x02
#define IOAPICENTRY_FLAG_EN 0x01
#define MAXPNSTR 132
static int pfd = -1;
static bool seekEntry(vm_offset_t addr)
{
return(lseek(pfd, (off_t)addr, SEEK_SET) >= 0);
}
static bool readEntry(void* entry, int size)
{
return (read(pfd, entry, size) == size);
}
static int readType( void )
{
uint8_t type;
if ( read( pfd, &type, sizeof( type ) ) == sizeof( type ) )
lseek( pfd, -sizeof( type ), SEEK_CUR );
return (int)type;
}
/*
* set PHYSICAL address of MP floating pointer structure
*/
#define NEXT(X) ((X) += 4)
static int apic_probe(vm_offset_t* paddr)
{
unsigned int x;
uint16_t segment;
vm_offset_t target;
unsigned int buffer[BIOS_SIZE];
const char MP_SIG[]="_MP_";
/* search Extended Bios Data Area, if present */
seekEntry((vm_offset_t)EBDA_POINTER);
readEntry(&segment, 2);
if (segment) { /* search EBDA */
target = (vm_offset_t)segment << 4;
seekEntry(target);
readEntry(buffer, ONE_KBYTE);
for (x = 0; x < ONE_KBYTE / 4; NEXT(x)) {
if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
*paddr = (x*4) + target;
return 1;
}
}
}
/* read CMOS for real top of mem */
seekEntry((vm_offset_t)TOPOFMEM_POINTER);
readEntry(&segment, 2);
--segment; /* less ONE_KBYTE */
target = segment * 1024;
seekEntry(target);
readEntry(buffer, ONE_KBYTE);
for (x = 0; x < ONE_KBYTE/4; NEXT(x)) {
if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
*paddr = (x*4) + target;
return 2;
}
}
/* we don't necessarily believe CMOS, check base of the last 1K of 640K */
if (target != (DEFAULT_TOPOFMEM - 1024)) {
target = (DEFAULT_TOPOFMEM - 1024);
seekEntry(target);
readEntry(buffer, ONE_KBYTE);
for (x = 0; x < ONE_KBYTE/4; NEXT(x)) {
if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
*paddr = (x*4) + target;
return 3;
}
}
}
/* search the BIOS */
seekEntry(BIOS_BASE);
readEntry(buffer, BIOS_SIZE);
for (x = 0; x < BIOS_SIZE/4; NEXT(x)) {
if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
*paddr = (x*4) + BIOS_BASE;
return 4;
}
}
/* search the extended BIOS */
seekEntry(BIOS_BASE2);
readEntry(buffer, BIOS_SIZE);
for (x = 0; x < BIOS_SIZE/4; NEXT(x)) {
if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
*paddr = (x*4) + BIOS_BASE2;
return 4;
}
}
/* search additional memory */
target = GROPE_AREA1;
seekEntry(target);
readEntry(buffer, GROPE_SIZE);
for (x = 0; x < GROPE_SIZE/4; NEXT(x)) {
if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
*paddr = (x*4) + GROPE_AREA1;
return 5;
}
}
target = GROPE_AREA2;
seekEntry(target);
readEntry(buffer, GROPE_SIZE);
for (x = 0; x < GROPE_SIZE/4; NEXT(x)) {
if (!strncmp((char *)&buffer[x], MP_SIG, 4)) {
*paddr = (x*4) + GROPE_AREA2;
return 6;
}
}
*paddr = (vm_offset_t)0;
return 0;
}
static hwNode *addCPU(hwNode & n, int i, ProcEntry entry)
{
hwNode *cpu = NULL;
if(!(entry.cpuFlags & PROCENTRY_FLAG_EN))
return NULL;
cpu = n.findChildByBusInfo("cpu@"+tostring(i));
if(!cpu)
{
hwNode *core = n.getChild("core");
if (!core)
{
n.addChild(hwNode("core", hw::bus));
core = n.getChild("core");
}
if(!core)
cpu = n.addChild(hwNode("cpu", hw::processor));
else
cpu = core->addChild(hwNode("cpu", hw::processor));
if(cpu)
cpu->setBusInfo("cpu@"+tostring(i));
}
if(cpu)
{
cpu->setVersion(tostring((entry.cpuSignature >> 8) & 0x0f) + "." + tostring((entry.cpuSignature >> 4) & 0x0f) + "." + tostring(entry.cpuSignature & 0x0f));
if(entry.cpuFlags & PROCENTRY_FLAG_EN)
cpu->enable();
if(entry.cpuFlags & PROCENTRY_FLAG_BP)
cpu->addCapability("boot", "boot processor");
}
return cpu;
}
static void MPConfigDefault( hwNode & n, int featureByte )
{
switch ( featureByte ) {
case 1:
n.addCapability("ISA");
n.addCapability("APIC:82489DX");
break;
case 2:
case 3:
n.addCapability("EISA");
n.addCapability("APIC:82489DX");
break;
case 4:
n.addCapability("MCA");
n.addCapability("APIC:82489DX");
break;
case 5:
n.addCapability("ISA");
n.addCapability("PCI");
n.addCapability("APIC:integrated");
break;
case 6:
n.addCapability("EISA");
n.addCapability("PCI");
n.addCapability("APIC:integrated");
break;
case 7:
n.addCapability("MCA");
n.addCapability("PCI");
n.addCapability("APIC:integrated");
break;
}
switch ( featureByte ) {
case 1:
case 2:
case 3:
case 4:
n.setConfig("bus", 1);
break;
case 5:
case 6:
case 7:
n.setConfig("bus", 2);
break;
}
n.setConfig("cpus", 2);
}
static void MPConfigTableHeader( hwNode & n, uint32_t pap )
{
mpcth_t cth;
int c;
int entrytype;
int ncpu = 0;
int nbus = 0;
int napic = 0;
int nintr = 0;
ProcEntry entry;
if ( !pap )
return;
/* read in cth structure */
seekEntry( pap );
readEntry( &cth, sizeof( cth ) );
if(string(cth.signature, 4) != "PCMP")
return;
if(n.getVendor() == "")
n.setVendor(hw::strip(string(cth.oem_id, 8)));
if(n.getProduct() == "")
n.setProduct(hw::strip(string(cth.product_id, 12)));
n.addCapability("smp-1." + tostring(cth.spec_rev), "SMP specification v1."+tostring(cth.spec_rev));
for (c = cth.entry_count; c; c--) {
entrytype = readType();
switch (entrytype) {
case 0:
readEntry( &entry, sizeof( entry ) );
if(addCPU(n, ncpu, entry))
ncpu++;
break;
case 1:
//busEntry();
nbus++;
break;
case 2:
//ioApicEntry();
napic++;
break;
case 3:
//intEntry();
nintr++;
break;
case 4:
//intEntry();
nintr++;
break;
}
}
n.setConfig("cpus", ncpu);
}
bool issmp(hwNode & n)
{
vm_offset_t paddr;
mpfps_t mpfps;
if((pfd = open("/dev/mem", O_RDONLY)) < 0)
return false;
if (apic_probe(&paddr) <= 0)
return false;
/* read in mpfps structure*/
seekEntry(paddr);
readEntry(&mpfps, sizeof(mpfps_t));
if(string(mpfps.signature, 4) != "_MP_")
return false;
/* check whether a pre-defined MP config table exists */
if (mpfps.mpfb1)
MPConfigDefault(n, mpfps.mpfb1);
else
if(mpfps.pap)
MPConfigTableHeader(n, mpfps.pap);
close(pfd);
return true;
}
#else
bool issmp(hwNode & n)
{
string onlinecpus = get_string("/sys/devices/system/cpu/online", "0");
return matches(onlinecpus, "^[0-9]+-[0-9]+") || matches(onlinecpus, "^[0-9]+,[0-9]+");
}
#endif
bool scan_smp(hwNode & n)
{
if(issmp(n))
{
n.addCapability("smp", "Symmetric Multi-Processing");
return true;
}
else
return false;
}

7
src/core/smp.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _SMP_H_
#define _SMP_H_
#include "hw.h"
bool scan_smp(hwNode & n);
#endif

233
src/core/spd.cc Normal file
View File

@ -0,0 +1,233 @@
#include "version.h"
#include "spd.h"
#include "osutils.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <dirent.h>
#include <stdio.h>
__ID("@(#) $Id$");
/* SPD is 2048-bit long */
#define SPD_MAXSIZE (2048/8)
#define SPD_BLKSIZE 0x10
#define TYPE_EDO 0x02
#define TYPE_SDRAM 0x04
#define PROCSENSORS "/proc/sys/dev/sensors"
#define EEPROMPREFIX "eeprom-"
static unsigned char spd[SPD_MAXSIZE];
static bool spd_page_loaded[SPD_MAXSIZE / SPD_BLKSIZE];
static string current_eeprom = "";
static unsigned int current_bank = 0;
static unsigned char get_spd_byte(unsigned int offset)
{
if ((offset < 0) || (offset >= SPD_MAXSIZE))
return 0;
if (!spd_page_loaded[offset / SPD_BLKSIZE])
{
char chunkname[10];
string name = "";
FILE *in = NULL;
snprintf(chunkname, sizeof(chunkname), "%02x",
(offset / SPD_BLKSIZE) * SPD_BLKSIZE);
name = current_eeprom + "/" + string(chunkname);
in = fopen(name.c_str(), "r");
if (in)
{
for (int i = 0; i < SPD_BLKSIZE; i++)
if(fscanf(in, "%d",
(int *) &spd[i + (offset / SPD_BLKSIZE) * SPD_BLKSIZE]) < 1)
break;
fclose(in);
spd_page_loaded[offset / SPD_BLKSIZE] = true;
}
else
spd_page_loaded[offset / SPD_BLKSIZE] = false;
}
return spd[offset];
}
static int selecteeprom(const struct dirent *d)
{
struct stat buf;
if (d->d_name[0] == '.')
return 0;
if (lstat(d->d_name, &buf) != 0)
return 0;
if (!S_ISDIR(buf.st_mode))
return 0;
return (strncmp(d->d_name, EEPROMPREFIX, strlen(EEPROMPREFIX)) == 0);
}
static hwNode *get_current_bank(hwNode & memory)
{
char id[20];
hwNode *result = NULL;
if ((current_bank == 0) && (result = memory.getChild("bank")))
return result;
snprintf(id, sizeof(id), "bank:%d", current_bank);
result = memory.getChild(id);
if (!result)
return memory.addChild(hwNode(id, hw::memory));
else
return result;
}
static bool scan_eeprom(hwNode & memory,
string name)
{
int memory_type = -1;
char buff[20];
unsigned char checksum = 0;
unsigned char rows = 0;
unsigned char density = 0;
unsigned long long size = 0;
current_eeprom = string(PROCSENSORS) + "/" + name;
memset(spd, 0, sizeof(spd));
memset(spd_page_loaded, 0, sizeof(spd_page_loaded));
for (int i = 0; i < 63; i++)
checksum += get_spd_byte(i);
if (checksum != get_spd_byte(63))
return false;
memory_type = get_spd_byte(0x02);
hwNode *bank = get_current_bank(memory);
if (!bank)
return false;
switch (memory_type)
{
case TYPE_SDRAM:
bank->setDescription("SDRAM");
break;
case TYPE_EDO:
bank->setDescription("EDO");
break;
}
rows = get_spd_byte(5);
snprintf(buff, sizeof(buff), "%d", rows);
bank->setConfig("rows", buff);
if (bank->getSize() == 0)
{
density = get_spd_byte(31);
for (int j = 0; (j < 8) && (rows > 0); j++)
if (density & (1 << j))
{
rows--;
size += (4 << j) * 1024 * 1024; // MB
density ^= (1 << j);
if (density == 0)
size += rows * (4 << j) * 1024 * 1024;
}
bank->setSize(size);
}
switch (get_spd_byte(11)) // error detection and correction scheme
{
case 0x00:
bank->setConfig("errordetection", "none");
break;
case 0x01:
bank->addCapability("parity");
bank->setConfig("errordetection", "parity");
break;
case 0x02:
bank->addCapability("ecc");
bank->setConfig("errordetection", "ecc");
break;
}
int version = get_spd_byte(62);
snprintf(buff, sizeof(buff), "spd-%d.%d", (version & 0xF0) >> 4,
version & 0x0F);
bank->addCapability(buff);
return true;
}
static bool scan_eeproms(hwNode & memory)
{
struct dirent **namelist;
int n;
current_bank = 0;
pushd(PROCSENSORS);
n = scandir(".", &namelist, selecteeprom, alphasort);
popd();
if (n < 0)
return false;
for (int i = 0; i < n; i++)
if (scan_eeprom(memory, namelist[i]->d_name))
current_bank++;
return true;
}
bool scan_spd(hwNode & n)
{
hwNode *memory = n.getChild("core/memory");
current_bank = 0;
if (!memory)
{
hwNode *core = n.getChild("core");
if (!core)
{
n.addChild(hwNode("core", hw::bus));
core = n.getChild("core");
}
if (core)
{
core->addChild(hwNode("memory", hw::memory));
memory = core->getChild("memory");
}
}
if (memory)
{
memory->claim();
return scan_eeproms(*memory);
}
return false;
}

7
src/core/spd.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _SPD_H_
#define _SPD_H_
#include "hw.h"
bool scan_spd(hwNode & n);
#endif

393
src/core/sysfs.cc Normal file
View File

@ -0,0 +1,393 @@
/*
* sysfs.cc
*
*
*/
#include "version.h"
#include "sysfs.h"
#include "osutils.h"
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
__ID("@(#) $Id$");
using namespace sysfs;
struct sysfs::entry_i
{
string devpath;
};
struct sysfs_t
{
sysfs_t():path("/sys"),
temporary(false),
has_sysfs(false)
{
has_sysfs = exists(path + "/class/.");
if (!has_sysfs) // sysfs doesn't seem to be mounted
// try to mount it in a temporary directory
{
char buffer[50];
char *tmpdir = NULL;
strncpy(buffer,
"/var/tmp/sys-XXXXXX",
sizeof(buffer));
tmpdir = mkdtemp(buffer);
if (tmpdir)
{
temporary = true;
path = string(tmpdir);
chmod(tmpdir,
0000); // to make clear it is a mount point
mount("none",
path.c_str(),
"sysfs",
0,
NULL);
}
has_sysfs = exists(path + "/class/.");
}
}
~sysfs_t()
{
if (temporary)
{
umount(path.c_str());
rmdir(path.c_str());
}
}
string path;
bool temporary;
bool has_sysfs;
};
static sysfs_t fs;
static string sysfs_getbustype(const string & path)
{
struct dirent **namelist;
int i, n;
string devname;
/*
to determine to which kind of bus a device is connected:
- for each subdirectory of /sys/bus,
- look in ./devices/ for a link with the same basename as 'path'
- check if this link and 'path' point to the same inode
- if they do, the bus type is the name of the current directory
*/
pushd(fs.path + "/bus");
n = scandir(".", &namelist, selectdir, alphasort);
popd();
for (i = 0; i < n; i++)
{
devname =
string(fs.path + "/bus/") + string(namelist[i]->d_name) +
"/devices/" + basename(path.c_str());
if (samefile(devname, path))
return string(namelist[i]->d_name);
}
return "";
}
static string sysfstopci(const string & path)
{
if (path.length() > strlen("XXXX:XX:XX.X"))
return "pci@" + path.substr(path.length() - strlen("XXXX:XX:XX.X"));
else
return "";
}
static string sysfstoide(const string & path)
{
if (path.substr(0, 3) == "ide")
return "ide@" + path.substr(path.length() - 3);
else
return "ide@" + path;
}
static string sysfstobusinfo(const string & path)
{
string bustype = sysfs_getbustype(path);
if (bustype == "pci")
return sysfstopci(path);
if (bustype == "ide")
return sysfstoide(path);
if (bustype == "usb")
{
string name = basename(path.c_str());
if (matches(name, "^[0-9]+-[0-9]+(\\.[0-9]+)*:[0-9]+\\.[0-9]+$"))
{
size_t colon = name.rfind(":");
size_t dash = name.find("-");
return "usb@" + name.substr(0, dash) + ":" + name.substr(dash+1, colon-dash-1);
}
}
if (bustype == "virtio")
{
string name = basename(path.c_str());
if (name.compare(0, 6, "virtio") == 0)
return "virtio@" + name.substr(6);
else
return "virtio@" + name;
}
if (bustype == "vio")
return string("vio@") + basename(path.c_str());
if (bustype == "ccw")
return string("ccw@") + basename(path.c_str());
if (bustype == "ccwgroup")
{
// just report businfo for the first device in the group
// because the group doesn't really fit into lshw's tree model
string firstdev = realpath(path + "/cdev0");
return sysfstobusinfo(firstdev);
}
return "";
}
string entry::businfo() const
{
string result = sysfstobusinfo(This->devpath);
if (result.empty())
result = sysfstobusinfo(dirname(This->devpath));
return result;
}
static string finddevice(const string & name, const string & root = "")
{
struct dirent **namelist;
int n;
string result = "";
if(exists(name))
return root + "/" + name;
n = scandir(".", &namelist, selectdir, alphasort);
for (int i = 0; i < n; i++)
{
pushd(namelist[i]->d_name);
string findinchild = finddevice(name, root + "/" + string(namelist[i]->d_name));
popd();
free(namelist[i]);
if(findinchild != "")
{
result = findinchild;
}
}
free(namelist);
return result;
}
string sysfs_finddevice(const string & name)
{
string devices = fs.path + string("/devices/");
string result = "";
if(!pushd(devices))
return "";
result = finddevice(name);
popd();
return result;
}
string entry::driver() const
{
string driverlink = This->devpath + "/driver";
if (!exists(driverlink))
return "";
return basename(readlink(driverlink).c_str());
}
entry entry::byBus(string devbus, string devname)
{
entry e(fs.path + "/bus/" + devbus + "/devices/" + devname);
return e;
}
entry entry::byClass(string devclass, string devname)
{
entry e(fs.path + "/class/" + devclass + "/" + devname + "/device");
return e;
}
entry entry::byPath(string path)
{
entry e(fs.path + "/devices" + path);
return e;
}
entry::entry(const string & devpath)
{
This = new entry_i;
This->devpath = realpath(devpath);
}
entry & entry::operator =(const entry & e)
{
*This = *(e.This);
return *this;
}
entry::entry(const entry & e)
{
This = new entry_i;
*This = *(e.This);
}
entry::~entry()
{
delete This;
}
bool entry::hassubdir(const string & s)
{
return exists(This->devpath + "/" + s);
}
string entry::name_in_class(const string & classname) const
{
string result = "";
string classdir = This->devpath + "/" + classname;
if (!pushd(classdir))
return result;
struct dirent **namelist = NULL;
int count = scandir(".", &namelist, selectdir, alphasort);
popd();
if (count < 0)
return result;
// there should be at most one
for (int i = 0; i < count; i++)
{
result = namelist[i]->d_name;
free(namelist[i]);
}
free(namelist);
return result;
}
string entry::name() const
{
return basename(This->devpath.c_str());
}
entry entry::parent() const
{
entry e(dirname(This->devpath));
return e;
}
string entry::string_attr(const string & name, const string & def) const
{
return hw::strip(get_string(This->devpath + "/" + name, def));
}
unsigned long long entry::hex_attr(const string & name, unsigned long long def) const
{
string val = string_attr(name, "");
if (val.empty())
return def;
return strtoull(val.c_str(), NULL, 16);
}
vector < string > entry::multiline_attr(const string & name) const
{
vector < string > lines;
loadfile(This->devpath + "/" + name, lines);
return lines;
}
string entry::modalias() const
{
return get_string(This->devpath+"/modalias");
}
string entry::device() const
{
return get_string(This->devpath+"/device");
}
string entry::vendor() const
{
return get_string(This->devpath+"/vendor");
}
vector < entry > sysfs::entries_by_bus(const string & busname)
{
vector < entry > result;
if (!pushd(fs.path + "/bus/" + busname + "/devices"))
return result;
struct dirent **namelist;
int count;
count = scandir(".", &namelist, selectlink, alphasort);
for (int i = 0; i < count; i ++)
{
entry e = sysfs::entry::byBus(busname, namelist[i]->d_name);
result.push_back(e);
}
return result;
}
bool scan_sysfs(hwNode & n)
{
return false;
}

52
src/core/sysfs.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef _SYSFS_H_
#define _SYSFS_H_
#include <string>
#include "hw.h"
using namespace std;
namespace sysfs
{
class entry
{
public:
static entry byBus(string devbus, string devname);
static entry byClass(string devclass, string devname);
static entry byPath(string path);
entry & operator =(const entry &);
entry(const entry &);
~entry();
bool hassubdir(const string &);
string name() const;
string businfo() const;
string driver() const;
string modalias() const;
string device() const;
string vendor() const;
entry parent() const;
string name_in_class(const string &) const;
string string_attr(const string & name, const string & def = "") const;
unsigned long long hex_attr(const string & name, unsigned long long def = 0) const;
vector < string > multiline_attr(const string & name) const;
struct entry_i * This;
private:
entry(const string &);
};
vector < entry > entries_by_bus(const string & busname);
} // namespace sysfs
bool scan_sysfs(hwNode & n);
std::string sysfs_finddevice(const string &name);
#endif

507
src/core/usb.cc Normal file
View File

@ -0,0 +1,507 @@
/*
* usb.cc
*
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "version.h"
#include "config.h"
#include "usb.h"
#include "osutils.h"
#include "heuristics.h"
#include "options.h"
#include <stdio.h>
#include <map>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#define PROCBUSUSBDEVICES "/proc/bus/usb/devices"
#define SYSKERNELDEBUGUSBDEVICES "/sys/kernel/debug/usb/devices"
#define USBID_PATH DATADIR"/usb.ids:/usr/share/lshw/usb.ids:/usr/local/share/usb.ids:/usr/share/usb.ids:/etc/usb.ids:/usr/share/hwdata/usb.ids:/usr/share/misc/usb.ids"
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_IMAGING 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_DATA 0xa
#define USB_CLASS_SMARTCARD 0xb
#define USB_CLASS_VIDEO 0xe
#define USB_CLASS_WIRELESS 0xe0
#define USB_CLASS_VENDOR_SPEC 0xff
#define USB_SC_AUDIOCONTROL 1
#define USB_SC_AUDIOSTREAMING 2
#define USB_SC_AUDIOMIDISTREAMING 3
#define USB_SC_COMMMODEM 2
#define USB_SC_COMMETHERNET 6
#define USB_SC_COMMOBEX 0xb
#define USB_SC_HIDNONE 0
#define USB_SC_HIDBOOT 1
#define USB_PROT_HIDKBD 1
#define USB_PROT_HIDMOUSE 2
#define USB_SC_PRINTER 1
#define USB_PROT_PRINTERUNIDIR 1
#define USB_PROT_PRINTERBIDIR 2
#define USB_PROT_PRINTER1284 3
#define USB_SC_STORAGERBC 1
#define USB_SC_STORAGEATAPI 2
#define USB_SC_STORAGEFLOPPY 4
#define USB_SC_STORAGESCSI 6
#define USB_SC_WIRELESSRADIO 1
#define USB_PROT_BLUETOOTH 1
static map<u_int16_t,string> usbvendors;
static map<u_int32_t,string> usbproducts;
#define PRODID(x, y) ((x << 16) + y)
__ID("@(#) $Id$");
static string usbhost(unsigned bus)
{
char buffer[10];
snprintf(buffer, sizeof(buffer), "usb%u", bus);
return string(buffer);
}
static string usbhandle(unsigned bus, unsigned level, unsigned dev)
{
char buffer[10];
snprintf(buffer, sizeof(buffer), "USB:%u:%u", bus, dev);
return string(buffer);
}
static string usbbusinfo(unsigned bus, unsigned level, unsigned port)
{
char buffer[10];
if(level>0)
snprintf(buffer, sizeof(buffer), "usb@%u:%u", bus, port);
else
snprintf(buffer, sizeof(buffer), "usb@%u", bus);
return string(buffer);
}
static string usbspeed(float speed)
{
char buffer[15];
snprintf(buffer, sizeof(buffer), "%.fMbit/s", speed);
return string(buffer);
}
static bool addUSBChild(hwNode & n, hwNode & device, unsigned bus, unsigned lev, unsigned prnt)
{
hwNode * parent = NULL;
device.addHint("bus.icon", string("usb"));
if(prnt>0) parent = n.findChildByHandle(usbhandle(bus, lev-1, prnt));
if(parent)
{
if(parent->getBusInfo().find(":")==string::npos)
device.setBusInfo(parent->getBusInfo()+":"+device.getPhysId());
else
device.setBusInfo(parent->getBusInfo()+"."+device.getPhysId());
parent->addChild(device);
return true;
}
else
{
// USB host
{
string businfo = guessBusInfo(device.getSerial());
parent = n.findChildByBusInfo(businfo);
if(!parent) // still no luck
{
unsigned long long ioport = strtoll(device.getSerial().c_str(), NULL, 16);
parent = n.findChildByResource(hw::resource::ioport(ioport, ioport));
}
device.setSerial(""); // serial# has no meaning for USB hosts
}
if(parent)
{
parent->addChild(device);
return true;
}
else
n.addChild(device);
return false;
}
}
static bool setUSBClass(hwNode & device, unsigned cls, unsigned sub, unsigned prot)
{
if(device.getClass()!=hw::generic) return false;
switch(cls)
{
case USB_CLASS_AUDIO:
device.setClass(hw::multimedia);
device.setDescription(_("Audio device"));
switch(sub)
{
case USB_SC_AUDIOCONTROL:
device.addCapability("audio-control", _("Control device"));
break;
case USB_SC_AUDIOMIDISTREAMING:
device.addCapability("midi", _("MIDI"));
case USB_SC_AUDIOSTREAMING:
device.addCapability("audio-streaming", _("Audio streaming"));
break;
}
break;
case USB_CLASS_COMM:
device.setClass(hw::communication);
device.setDescription(_("Communication device"));
if(sub == USB_SC_COMMMODEM)
{
device.setDescription(_("Modem"));
if((prot>=1) && (prot<=6)) device.addCapability("atcommands", _("AT (Hayes) compatible"));
}
if(sub==USB_SC_COMMETHERNET) device.addCapability("ethernet", _("Ethernet networking"));
if(sub==USB_SC_COMMOBEX) device.addCapability("obex", _("OBEX networking"));
break;
case USB_CLASS_HID:
device.setClass(hw::input);
device.setDescription(_("Human interface device"));
if((sub==USB_SC_HIDNONE)||(sub==USB_SC_HIDBOOT))
{
switch(prot)
{
case USB_PROT_HIDKBD:
device.setDescription(_("Keyboard"));
break;
case USB_PROT_HIDMOUSE:
device.setDescription(_("Mouse"));
break;
}
}
break;
case USB_CLASS_PRINTER:
device.setClass(hw::printer);
device.setDescription(_("Printer"));
device.addHint("icon", string("printer"));
if(sub==USB_SC_PRINTER)
{
switch(prot)
{
case USB_PROT_PRINTERUNIDIR:
device.addCapability("unidirectional", _("Unidirectional"));
break;
case USB_PROT_PRINTERBIDIR:
device.addCapability("bidirectional", _("Bidirectional"));
break;
case USB_PROT_PRINTER1284:
device.addCapability("ieee1284.4", _("IEEE 1284.4 compatible bidirectional"));
break;
}
}
break;
case USB_CLASS_MASS_STORAGE:
device.setClass(hw::storage);
device.setDescription(_("Mass storage device"));
switch(sub)
{
case USB_SC_STORAGERBC:
device.addCapability("flash", _("RBC (typically Flash) mass storage"));
break;
case USB_SC_STORAGEATAPI:
device.addCapability("atapi", _("SFF-8020i, MMC-2 (ATAPI)"));
break;
case USB_SC_STORAGEFLOPPY:
device.addCapability("floppy", _("Floppy (UFI)"));
break;
case USB_SC_STORAGESCSI:
device.addCapability("scsi", _("SCSI"));
break;
}
break;
case USB_CLASS_HUB:
device.setClass(hw::bus);
device.setDescription(_("USB hub"));
break;
case USB_CLASS_DATA:
device.setClass(hw::generic);
break;
case USB_CLASS_SMARTCARD:
device.setClass(hw::generic);
device.setDescription(_("Smart card reader"));
break;
case USB_CLASS_VIDEO:
device.setClass(hw::multimedia);
device.setDescription(_("Video"));
break;
case USB_CLASS_WIRELESS:
device.setClass(hw::communication);
device.setDescription(_("Wireless interface"));
if((sub==USB_SC_WIRELESSRADIO) && (prot==USB_PROT_BLUETOOTH))
{
device.setDescription(_("Bluetooth wireless interface"));
device.addCapability("bluetooth", _("Bluetooth wireless radio"));
device.addHint("icon", string("bluetooth"));
}
break;
default:
device.setDescription(_("Generic USB device"));
return false;
}
return true;
}
static bool describeUSB(hwNode & device, unsigned vendor, unsigned prodid)
{
if(usbvendors.find(vendor)==usbvendors.end()) return false;
device.setVendor(usbvendors[vendor]+(enabled("output:numeric")?" ["+tohex(vendor)+"]":""));
device.addHint("usb.idVendor", vendor);
device.addHint("usb.idProduct", prodid);
if(usbproducts.find(PRODID(vendor, prodid))!=usbproducts.end())
device.setProduct(usbproducts[PRODID(vendor, prodid)]+(enabled("output:numeric")?" ["+tohex(vendor)+":"+tohex(prodid)+"]":""));
return true;
}
static bool load_usbids(const string & name)
{
FILE * usbids = NULL;
u_int16_t vendorid = 0;
usbids = fopen(name.c_str(), "r");
if(!usbids) return false;
while(!feof(usbids))
{
char * buffer = NULL;
size_t linelen;
unsigned t = 0;
char *description = NULL;
if(getline(&buffer, &linelen, usbids)>0)
{
if(buffer[linelen-1]<' ')
buffer[linelen-1] = '\0'; // chop \n
string line = string(buffer);
free(buffer);
description = NULL;
t = 0;
if(line.length()>0)
{
if(line[0] == '\t') // product id entry
{
line.erase(0, 1);
if(matches(line, "^[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]"))
t = strtol(line.c_str(), &description, 16);
if(description && (description != line.c_str()))
{
usbproducts[PRODID(vendorid,t)] = hw::strip(description);
}
}
else // vendor id entry
{
if(matches(line, "^[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]"))
t = strtol(line.c_str(), &description, 16);
if(description && (description != line.c_str()))
{
vendorid = t;
usbvendors[t] = hw::strip(description);
}
}
}
}
}
fclose(usbids);
return true;
}
bool scan_usb(hwNode & n)
{
hwNode device("device");
FILE * usbdevices = NULL;
bool defined = false;
unsigned int bus,lev,prnt,port,cnt,devnum,mxch;
float speed;
char ver[10+1];
unsigned int cls, sub, prot, mxps, numcfgs;
unsigned int vendor, prodid;
char rev[10+1];
unsigned numifs, cfgnum, atr;
char mxpwr[10+1];
unsigned ifnum, alt, numeps;
char driver[80+1];
if (!exists(SYSKERNELDEBUGUSBDEVICES) && !exists(PROCBUSUSBDEVICES))
return false;
vector < string > filenames;
splitlines(USBID_PATH, filenames, ':');
for (int i = filenames.size() - 1; i >= 0; i--)
{
load_usbids(filenames[i]);
}
filenames.clear();
if (exists(SYSKERNELDEBUGUSBDEVICES))
usbdevices = fopen(SYSKERNELDEBUGUSBDEVICES, "r");
if(!usbdevices && exists(PROCBUSUSBDEVICES))
usbdevices = fopen(PROCBUSUSBDEVICES, "r");
if(!usbdevices)
return false;
while(!feof(usbdevices))
{
char * buffer = NULL;
size_t linelen;
char strname[80+1];
char strval[80+1];
if(getline(&buffer, &linelen, usbdevices)>0)
{
string line = hw::strip(string(buffer));
free(buffer);
if(line.length()<=0)
{
if(defined)
addUSBChild(n, device, bus, lev, prnt);
device = hwNode("device");
defined = false;
}
else
{
if((line.length()>1) && (line[1] == ':'))
switch(line[0])
{
case 'T':
bus = lev = prnt = port = cnt = devnum = mxch = 0;
speed = 0.0;
strcpy(ver, "");
strcpy(rev, "");
cls = sub = prot = mxps = numcfgs = 0;
vendor = prodid = 0;
if(sscanf(line.c_str(), "T: Bus=%u Lev=%u Prnt=%u Port=%u Cnt=%u Dev#=%u Spd=%f MxCh=%u", &bus, &lev, &prnt, &port, &cnt, &devnum, &speed, &mxch)>0)
{
defined = true;
if(lev==0)
{
device = hwNode("usbhost", hw::bus);
device.claim();
device.setLogicalName(usbhost(bus));
}
else
device = hwNode("usb");
device.setHandle(usbhandle(bus, lev, devnum));
device.setBusInfo(usbbusinfo(bus, lev, port));
device.setPhysId(port+1);
device.setConfig("speed", usbspeed(speed));
if(mxch>0)
{
snprintf(strval, sizeof(strval), "%u", mxch);
device.setConfig("slots", strval);
}
}
break;
case 'D':
strcpy(ver, "");
cls = sub = prot = mxps = numcfgs = 0;
if(sscanf(line.c_str(), "D: Ver=%s Cls=%x(%*5c) Sub=%x Prot=%x MxPS=%u #Cfgs=%u", ver, &cls, &sub, &prot, &mxps, &numcfgs)>0)
{
setUSBClass(device, cls, sub, prot);
device.addCapability(string("usb-")+string(ver));
device.describeCapability("usb-1.00", "USB 1.0");
device.describeCapability("usb-1.10", "USB 1.1");
device.describeCapability("usb-2.00", "USB 2.0");
device.addHint("usb.bDeviceClass", cls);
device.addHint("usb.bDeviceSubClass", sub);
device.addHint("usb.bDeviceProtocol", prot);
}
break;
case 'P':
vendor = prodid = 0;
strcpy(rev, "");
if(sscanf(line.c_str(), "P: Vendor=%x ProdID=%x Rev=%10s", &vendor, &prodid, rev)>0)
{
describeUSB(device, vendor, prodid);
device.setVersion(hw::strip(rev));
}
break;
case 'S':
memset(strname, 0, sizeof(strname));
memset(strval, 0, sizeof(strval));
if(sscanf(line.c_str(), "S: %80[^=]=%80[ -z]", strname, strval)>0)
{
if(strcasecmp(strname, "Manufacturer")==0)
device.setVendor(hw::strip(strval)+(enabled("output:numeric")?" ["+tohex(vendor)+"]":""));
if(strcasecmp(strname, "Product")==0)
device.setProduct(hw::strip(strval)+(enabled("output:numeric")?" ["+tohex(vendor)+":"+tohex(prodid)+"]":""));
if(strcasecmp(strname, "SerialNumber")==0)
device.setSerial(hw::strip(strval));
}
break;
case 'C':
numifs = cfgnum = atr = 0;
strcpy(mxpwr, "");
if(sscanf(line.c_str(), "C:* #Ifs=%u Cfg#=%u Atr=%x MxPwr=%s", &numifs, &cfgnum, &atr, mxpwr)>0)
{
if(strcmp("0mA", mxpwr)!=0)
device.setConfig("maxpower", mxpwr);
}
break;
case 'I':
ifnum = alt = numeps = cls = sub = prot = 0;
memset(driver, 0, sizeof(driver));
if(((sscanf(line.c_str(), "I:* If#=%u Alt=%u #EPs=%u Cls=%x(%*5c) Sub=%x Prot=%x Driver=%80[ -z]", &ifnum, &alt, &numeps, &cls, &sub, &prot, driver)>0) && (cfgnum>0)) || ((sscanf(line.c_str(), "I: If#=%u Alt=%u #EPs=%u Cls=%x(%*5c) Sub=%x Prot=%x Driver=%80[ -z]", &ifnum, &alt, &numeps, &cls, &sub, &prot, driver)>0) && (cfgnum>0)))
{
setUSBClass(device, cls, sub, prot);
if((strlen(driver)!=0) && (strcasecmp("(none)", driver)!=0))
{
device.setConfig("driver", hw::strip(driver));
device.claim();
}
}
break;
}
}
}
}
if(defined)
addUSBChild(n, device, bus, lev, prnt);
if(usbdevices) fclose(usbdevices);
return true;
}

7
src/core/usb.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _USB_H_
#define _USB_H_
#include "hw.h"
bool scan_usb(hwNode & n);
#endif

96
src/core/version.cc Normal file
View File

@ -0,0 +1,96 @@
/*
* version.cc
*
* The sole purpose of this module is to report package version information:
* keyword expansion should be allowed for the 'URL' tag (svn ps svn:keywords URL)
* Reported version is computed using this file's location in the source archive;
* development versions return 'development' whereas released versions return
* version numbers like A.01.04
*
*/
#include "version.h"
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <sys/types.h>
#ifndef PACKETSZ
#define PACKETSZ 512
#endif
const char *getpackageversion()
{
if (VERSION)
return VERSION;
return "unknown";
}
static char *txtquery(const char *name, const char *domain, unsigned int *ttl)
{
unsigned char answer[PACKETSZ], *pt;
char host[128], *txt;
int len, exp, cttl, size, txtlen, type;
if(res_init() < 0)
return NULL;
memset(answer, 0, PACKETSZ);
if((len = res_querydomain(name, domain, C_IN, T_TXT, answer, PACKETSZ)) < 0)
return NULL;
pt = answer + sizeof(HEADER);
if((exp = dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0)
return NULL;
pt += exp;
GETSHORT(type, pt);
if(type != T_TXT)
return NULL;
pt += INT16SZ; /* class */
if((exp = dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0)
return NULL;
pt += exp;
GETSHORT(type, pt);
if(type != T_TXT)
return NULL;
pt += INT16SZ; /* class */
GETLONG(cttl, pt);
if(ttl)
*ttl = cttl;
GETSHORT(size, pt);
txtlen = *pt;
if(txtlen >= size || !txtlen)
return NULL;
if(!(txt = (char*)malloc(txtlen + 1)))
return NULL;
pt++;
strncpy(txt, (char*)pt, txtlen);
txt[txtlen] = 0;
return txt;
}
const char * checkupdates()
{
static char *latest = NULL;
if(!latest)
latest = txtquery(PACKAGE, "ezix.org", NULL);
return latest;
}

22
src/core/version.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _VERSION_H_
#define _VERSION_H_
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define __ID(string) __asm__(".ident\t\"" string "\"")
#else
#define __ID(string) static const char rcsid[] __unused = string
#endif
#ifdef __cplusplus
extern "C" {
#endif
const char * getpackageversion();
const char * checkupdates();
#ifdef __cplusplus
}
#endif
#endif

51
src/core/vio.cc Normal file
View File

@ -0,0 +1,51 @@
#include "version.h"
#include "hw.h"
#include "sysfs.h"
#include "vio.h"
#include <vector>
__ID("@(#) $Id$");
using namespace std;
bool scan_vio(hwNode & n)
{
vector < sysfs::entry > entries = sysfs::entries_by_bus("vio");
if (entries.empty())
return false;
for (vector < sysfs::entry >::iterator it = entries.begin();
it != entries.end(); ++it)
{
const sysfs::entry & e = *it;
if (e.name() == "vio")
continue; // skip root device
string name = e.string_attr("name");
if (name.empty())
name = e.name();
hwNode device(name);
device.setDescription("Virtual I/O device (" + name + ")");
string businfo = e.businfo();
if (!businfo.empty())
device.setBusInfo(businfo);
string driver = e.driver();
if (!driver.empty())
device.setConfig("driver", driver);
string devicetree_node = e.string_attr("devspec");
if (!devicetree_node.empty() && devicetree_node[0] == '/')
device.setLogicalName("/proc/device-tree" + devicetree_node);
n.addChild(device);
}
return true;
}

8
src/core/vio.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _VIO_H_
#define _VIO_H_
#include "hw.h"
bool scan_vio(hwNode &);
#endif

73
src/core/virtio.cc Normal file
View File

@ -0,0 +1,73 @@
#include "version.h"
#include "hw.h"
#include "sysfs.h"
#include "disk.h"
#include "virtio.h"
#include <vector>
__ID("@(#) $Id$");
using namespace std;
// driver seems like the only way to guess the class
static hw::hwClass virtio_class(const string & driver)
{
if (driver == "virtio_net")
return hw::network;
if (driver == "virtio_blk")
return hw::disk;
return hw::generic;
}
static void scan_virtio_block(hwNode & device, const sysfs::entry & entry)
{
string devname = entry.name_in_class("block");
if (devname.empty())
return;
device.setLogicalName(devname);
scan_disk(device);
device.claim();
}
bool scan_virtio(hwNode & n)
{
vector < sysfs::entry > entries = sysfs::entries_by_bus("virtio");
if (entries.empty())
return false;
for (vector < sysfs::entry >::iterator it = entries.begin();
it != entries.end(); ++it)
{
const sysfs::entry & e = *it;
hwNode device(e.name());
device.setDescription("Virtual I/O device");
string businfo = e.businfo();
if (!businfo.empty())
device.setBusInfo(businfo);
string driver = e.driver();
device.setClass(virtio_class(driver));
if (!driver.empty())
device.setConfig("driver", driver);
// virtio_net devices will be claimed during network interface scanning,
// but we handle virtio_blk devices here because nothing else will
scan_virtio_block(device, e);
hwNode *parent = NULL;
string parent_businfo = e.parent().businfo();
if (!parent_businfo.empty())
parent = n.findChildByBusInfo(parent_businfo);
if (!parent)
parent = n.getChild("core");
if (!parent)
parent = n.addChild(hwNode("core", hw::bus));
parent->addChild(device);
}
return true;
}

Some files were not shown because too many files have changed in this diff Show More