mirror of https://gitee.com/openkylin/lshw.git
Import Upstream version 02.18.85
This commit is contained in:
commit
30f903d069
|
@ -0,0 +1,4 @@
|
|||
*.o
|
||||
*.a
|
||||
src/lshw
|
||||
lshw.spec
|
|
@ -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.
|
|
@ -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
|
|
@ -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/).
|
|
@ -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
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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 ###
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _ABI_H_
|
||||
#define _ABI_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_abi(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _BURNER_H_
|
||||
#define _BURNER_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_burner(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _CDROM_H_
|
||||
#define _CDROM_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_cdrom(hwNode & n);
|
||||
#endif
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _CPUFREQ_H_
|
||||
#define _CPUFREQ_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_cpufreq(hwNode & n);
|
||||
#endif
|
|
@ -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__ */
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _CPUID_H_
|
||||
#define _CPUID_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_cpuid(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _CPUINFO_H_
|
||||
#define _CPUINFO_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_cpuinfo(hwNode & n);
|
||||
#endif
|
|
@ -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);
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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, §size) < 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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _DISK_H_
|
||||
#define _DISK_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_disk(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _DISPLAY_H_
|
||||
#define _DISPLAY_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_display(hwNode & n);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
#ifndef _DMI_H_
|
||||
#define _DMI_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_dmi(hwNode & n);
|
||||
#endif
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _FAT_H_
|
||||
#define _FAT_H_
|
||||
|
||||
#include "hw.h"
|
||||
#include "blockio.h"
|
||||
|
||||
bool scan_fat(hwNode & n, source & s);
|
||||
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _FB_H_
|
||||
#define _FB_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_fb(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _IDE_H_
|
||||
#define _IDE_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_ide(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _IDERAID_H_
|
||||
#define _IDERAID_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_ideraid(hwNode & n);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
#ifndef _ISAPNP_H_
|
||||
#define _ISAPNP_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_isapnp(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _JEDEC_H_
|
||||
#define _JEDEC_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string jedec_resolve(const std::string &);
|
||||
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _LVM_H_
|
||||
#define _LVM_H_
|
||||
|
||||
#include "hw.h"
|
||||
#include "blockio.h"
|
||||
|
||||
bool scan_lvm(hwNode & n, source & s);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _MAIN_H_
|
||||
#define _MAIN_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_system(hwNode & system);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _MEM_H_
|
||||
#define _MEM_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_memory(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _MOUNTS_H_
|
||||
#define _MOUNTS_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_mounts(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _NETWORK_H_
|
||||
#define _NETWORK_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_network(hwNode & n);
|
||||
#endif
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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 += "<";
|
||||
break;
|
||||
case '>':
|
||||
result += ">";
|
||||
break;
|
||||
case '&':
|
||||
result += "&";
|
||||
break;
|
||||
case '"':
|
||||
result += """;
|
||||
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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _PARISC_H_
|
||||
#define _PARISC_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_parisc(hwNode & n);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
#ifndef _PARTITIONS_H_
|
||||
#define _PARTITIONS_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_partitions(hwNode & n);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
#ifndef _PCMCIALEGACY_H_
|
||||
#define _PCMCIALEGACY_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_pcmcialegacy(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _PCMCIA_H_
|
||||
#define _PCMCIA_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_pcmcia(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _S390_H_
|
||||
#define _S390_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_s390_devices(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _SCSI_H_
|
||||
#define _SCSI_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_scsi(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _SMP_H_
|
||||
#define _SMP_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_smp(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _SPD_H_
|
||||
#define _SPD_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_spd(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _USB_H_
|
||||
#define _USB_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_usb(hwNode & n);
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _VIO_H_
|
||||
#define _VIO_H_
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
bool scan_vio(hwNode &);
|
||||
|
||||
#endif
|
|
@ -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
Loading…
Reference in New Issue