Import Upstream version 21.68
This commit is contained in:
commit
e913968499
|
@ -0,0 +1,7 @@
|
|||
hwinfo
|
||||
hw
|
||||
.depend
|
||||
hwscan
|
||||
todo
|
||||
hwscanqueue
|
||||
hwscand
|
|
@ -0,0 +1,7 @@
|
|||
changelog
|
||||
Changelog
|
||||
VERSION
|
||||
*.o
|
||||
.depend
|
||||
hwinfo
|
||||
hwinfo.pc
|
|
@ -0,0 +1,341 @@
|
|||
----------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, 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 Library 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) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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 Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1 @@
|
|||
Steffen Winterfeldt (snwint@suse.de)
|
|
@ -0,0 +1,134 @@
|
|||
TOPDIR = $(CURDIR)
|
||||
SUBDIRS = src
|
||||
TARGETS = hwinfo hwinfo.pc changelog
|
||||
CLEANFILES = hwinfo hwinfo.pc hwinfo.static hwscan hwscan.static hwscand hwscanqueue doc/libhd doc/*~
|
||||
LIBS = -lhd
|
||||
SLIBS = -lhd -luuid
|
||||
TLIBS = -lhd_tiny
|
||||
SO_LIBS = -luuid
|
||||
TSO_LIBS =
|
||||
|
||||
export SO_LIBS
|
||||
|
||||
GIT2LOG := $(shell if [ -x ./git2log ] ; then echo ./git2log --update ; else echo true ; fi)
|
||||
GITDEPS := $(shell [ -d .git ] && echo .git/HEAD .git/refs/heads .git/refs/tags)
|
||||
BRANCH := $(shell [ -d .git ] && git branch | perl -ne 'print $$_ if s/^\*\s*//')
|
||||
ifdef HWINFO_VERSION
|
||||
VERSION := $(shell echo ${HWINFO_VERSION} > VERSION; cat VERSION)
|
||||
else
|
||||
VERSION := $(shell $(GIT2LOG) --version VERSION ; cat VERSION)
|
||||
endif
|
||||
PREFIX := hwinfo-$(VERSION)
|
||||
|
||||
include Makefile.common
|
||||
|
||||
ifeq "$(ARCH)" "x86_64"
|
||||
LIBDIR ?= /usr/lib64
|
||||
else
|
||||
LIBDIR ?= /usr/lib
|
||||
endif
|
||||
ULIBDIR = $(LIBDIR)
|
||||
|
||||
# ia64
|
||||
ifneq ($(filter i386 x86_64, $(ARCH)),)
|
||||
SLIBS += -lx86emu
|
||||
TLIBS += -lx86emu
|
||||
SO_LIBS += -lx86emu
|
||||
TSO_LIBS += -lx86emu
|
||||
endif
|
||||
|
||||
SHARED_FLAGS =
|
||||
OBJS_NO_TINY = names.o parallel.o modem.o
|
||||
|
||||
.PHONY: fullstatic static shared tiny doc diet tinydiet uc tinyuc
|
||||
|
||||
ifdef HWINFO_VERSION
|
||||
changelog:
|
||||
@true
|
||||
else
|
||||
changelog: $(GITDEPS)
|
||||
$(GIT2LOG) --changelog changelog
|
||||
endif
|
||||
|
||||
hwscan: hwscan.o $(LIBHD)
|
||||
$(CC) hwscan.o $(LDFLAGS) $(CFLAGS) $(LIBS) -o $@
|
||||
|
||||
hwinfo: hwinfo.o $(LIBHD)
|
||||
$(CC) hwinfo.o $(LDFLAGS) $(CFLAGS) $(LIBS) -o $@
|
||||
|
||||
hwscand: hwscand.o
|
||||
$(CC) $< $(LDFLAGS) $(CFLAGS) -o $@
|
||||
|
||||
hwscanqueue: hwscanqueue.o
|
||||
$(CC) $< $(LDFLAGS) $(CFLAGS) -o $@
|
||||
|
||||
hwinfo.pc: hwinfo.pc.in VERSION
|
||||
VERSION=`cat VERSION`; \
|
||||
sed -e "s,@VERSION@,$${VERSION},g" -e 's,@LIBDIR@,$(ULIBDIR),g;s,@LIBS@,$(LIBS),g' $< > $@.tmp && mv $@.tmp $@
|
||||
|
||||
# kept for compatibility
|
||||
shared:
|
||||
@make
|
||||
|
||||
tiny:
|
||||
@make EXTRA_FLAGS=-DLIBHD_TINY LIBHD_BASE=libhd_tiny LIBS="$(TLIBS)" SO_LIBS="$(TSO_LIBS)"
|
||||
|
||||
tinyinstall:
|
||||
@make EXTRA_FLAGS=-DLIBHD_TINY LIBHD_BASE=libhd_tiny LIBS="$(TLIBS)" SO_LIBS="$(TSO_LIBS)" install
|
||||
|
||||
tinystatic:
|
||||
@make EXTRA_FLAGS=-DLIBHD_TINY LIBHD_BASE=libhd_tiny SHARED_FLAGS= LIBS="$(TLIBS)" SO_LIBS="$(TSO_LIBS)"
|
||||
|
||||
diet:
|
||||
@make CC="diet gcc" EXTRA_FLAGS="-fno-pic -DDIET" SHARED_FLAGS= LIBS="$(SLIBS)"
|
||||
|
||||
tinydiet:
|
||||
@make CC="diet gcc" EXTRA_FLAGS="-fno-pic -DLIBHD_TINY -DDIET" SHARED_FLAGS= LIBS="$(SLIBS)"
|
||||
|
||||
uc:
|
||||
@make CC="/opt/i386-linux-uclibc/bin/i386-uclibc-gcc" EXTRA_FLAGS="-fno-pic -DUCLIBC" SHARED_FLAGS= LIBS="$(SLIBS)"
|
||||
|
||||
tinyuc:
|
||||
@make CC="/opt/i386-linux-uclibc/usr/bin/gcc" EXTRA_FLAGS="-fno-pic -DLIBHD_TINY -DUCLIBC" SHARED_FLAGS= LIBS="$(SLIBS)"
|
||||
|
||||
static:
|
||||
make SHARED_FLAGS= LIBS="$(SLIBS)"
|
||||
|
||||
fullstatic: static
|
||||
$(CC) -static hwinfo.o $(LDFLAGS) $(SLIBS) -o hwinfo.static
|
||||
strip -R .note -R .comment hwinfo.static
|
||||
|
||||
doc:
|
||||
@cd doc ; doxygen libhd.doxy
|
||||
|
||||
install:
|
||||
install -d -m 755 $(DESTDIR)/sbin $(DESTDIR)/usr/sbin $(DESTDIR)$(ULIBDIR) \
|
||||
$(DESTDIR)$(ULIBDIR)/pkgconfig $(DESTDIR)/usr/include
|
||||
install -m 755 hwinfo $(DESTDIR)/usr/sbin
|
||||
install -m 755 src/ids/check_hd $(DESTDIR)/usr/sbin
|
||||
install -m 755 src/ids/convert_hd $(DESTDIR)/usr/sbin
|
||||
if [ -f $(LIBHD_SO) ] ; then \
|
||||
install $(LIBHD_SO) $(DESTDIR)$(ULIBDIR) ; \
|
||||
ln -snf $(LIBHD_NAME) $(DESTDIR)$(ULIBDIR)/$(LIBHD_SONAME) ; \
|
||||
ln -snf $(LIBHD_SONAME) $(DESTDIR)$(ULIBDIR)/$(LIBHD_BASE).so ; \
|
||||
else \
|
||||
install -m 644 $(LIBHD) $(DESTDIR)$(ULIBDIR) ; \
|
||||
fi
|
||||
install -m 644 hwinfo.pc $(DESTDIR)$(ULIBDIR)/pkgconfig
|
||||
install -m 644 src/hd/hd.h $(DESTDIR)/usr/include
|
||||
perl -pi -e "s/define\s+HD_VERSION\b.*/define HD_VERSION\t\t$(LIBHD_MAJOR_VERSION)/" $(DESTDIR)/usr/include/hd.h
|
||||
perl -pi -e "s/define\s+HD_MINOR_VERSION\b.*/define HD_MINOR_VERSION\t$(LIBHD_MINOR_VERSION)/" $(DESTDIR)/usr/include/hd.h
|
||||
install -m 755 getsysinfo $(DESTDIR)/usr/sbin
|
||||
install -m 755 src/isdn/cdb/mk_isdnhwdb $(DESTDIR)/usr/sbin
|
||||
install -d -m 755 $(DESTDIR)/usr/share/hwinfo
|
||||
install -d -m 755 $(DESTDIR)/var/lib/hardware/udi
|
||||
install -m 644 src/isdn/cdb/ISDN.CDB.txt $(DESTDIR)/usr/share/hwinfo
|
||||
install -m 644 src/isdn/cdb/ISDN.CDB.hwdb $(DESTDIR)/usr/share/hwinfo
|
||||
|
||||
archive: changelog
|
||||
@if [ ! -d .git ] ; then echo no git repo ; false ; fi
|
||||
mkdir -p package
|
||||
git archive --prefix=$(PREFIX)/ $(BRANCH) > package/$(PREFIX).tar
|
||||
tar -r -f package/$(PREFIX).tar --mode=0664 --owner=root --group=root --mtime="`git show -s --format=%ci`" --transform='s:^:$(PREFIX)/:' VERSION changelog src/hd/hd.h
|
||||
xz -f package/$(PREFIX).tar
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
# libhd/Makefile.common
|
||||
|
||||
ARCH := $(shell uname -m)
|
||||
ifeq "$(ARCH)" "i486"
|
||||
ARCH := i386
|
||||
endif
|
||||
ifeq "$(ARCH)" "i586"
|
||||
ARCH := i386
|
||||
endif
|
||||
ifeq "$(ARCH)" "i686"
|
||||
ARCH := i386
|
||||
endif
|
||||
ifeq "$(ARCH)" "parisc"
|
||||
EXTRA_FLAGS := -fPIC $(EXTRA_FLAGS)
|
||||
endif
|
||||
|
||||
LIBHD_VERSION := $(shell cat $(TOPDIR)/VERSION)
|
||||
LIBHD_MINOR_VERSION := $(shell cut -d . -f 2 $(TOPDIR)/VERSION)
|
||||
LIBHD_MAJOR_VERSION := $(shell cut -d . -f 1 $(TOPDIR)/VERSION)
|
||||
|
||||
RPM_OPT_FLAGS ?= -O2
|
||||
|
||||
CC ?= gcc
|
||||
LD = ld
|
||||
CFLAGS += $(RPM_OPT_FLAGS) -Wall -Wno-pointer-sign -pipe -g $(SHARED_FLAGS) $(EXTRA_FLAGS) -I$(TOPDIR)/src/hd
|
||||
SHARED_FLAGS = -fPIC
|
||||
|
||||
LDFLAGS += -Lsrc
|
||||
|
||||
CFILES = $(sort $(wildcard *.c))
|
||||
OBJS = $(CFILES:.c=.o)
|
||||
LIBHD_BASE = libhd
|
||||
LIBHD = $(TOPDIR)/src/$(LIBHD_BASE).a
|
||||
LIBHD_SONAME = $(LIBHD_BASE).so.$(LIBHD_MAJOR_VERSION)
|
||||
LIBHD_NAME = $(LIBHD_BASE).so.$(LIBHD_VERSION)
|
||||
LIBHD_SO = $(TOPDIR)/src/$(LIBHD_NAME)
|
||||
LIBHD_D = $(TOPDIR)/src/.lib
|
||||
|
||||
export CC TOPDIR CFLAGS LIBHD ARCH
|
||||
|
||||
.PHONY: all distclean clean install subdirs
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $<
|
||||
|
||||
all: subdirs $(TARGETS)
|
||||
|
||||
install: all
|
||||
|
||||
ifneq "$(SUBDIRS)" ""
|
||||
subdirs:
|
||||
@for i in $(SUBDIRS) ; do make -C $$i $(MAKECMDGOALS) || exit ; done
|
||||
endif
|
||||
|
||||
clean: subdirs
|
||||
@rm -rf $(OBJS) .depend $(CLEANFILES) *~
|
||||
@rm -rf package
|
||||
|
||||
distclean: subdirs
|
||||
@rm -rf $(OBJS) .depend $(CLEANFILES) $(DISTCLEANFILES) *~
|
||||
@rm -rf package
|
||||
|
||||
ifneq "$(CFILES)" ""
|
||||
ifeq ($(findstring $(MAKECMDGOALS), clean distclean),)
|
||||
.depend: $(CFILES)
|
||||
@$(CC) -MG -MM $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(CFILES) >$@
|
||||
|
||||
-include .depend
|
||||
endif
|
||||
endif
|
|
@ -0,0 +1,100 @@
|
|||
# hwprobe environment variable/kernel cmdline parameter
|
||||
|
||||
This document describes the `hwprobe` environment variable/kernel cmdline
|
||||
parameter.
|
||||
|
||||
You can control the hardware probing using the environment variable
|
||||
`hwprobe` and the kernel cmdline parameter `hwprobe`.
|
||||
|
||||
If `hwprobe` is set on the kernel cmdline, the environment variable
|
||||
`hwprobe` is ignored. Otherwise, the meaning of both is exactly the same.
|
||||
|
||||
## Controlling probing flags
|
||||
|
||||
`hwprobe` controls which probing flags should *always* be set/cleared (These
|
||||
settings *cannot* be overridden by command line switches). Examples:
|
||||
|
||||
* `hwprobe=-isapnp` - *never* do any isapnp probing
|
||||
* `hwprobe=-braille,-modem` - don't look for braille displays & modems
|
||||
|
||||
The list of supported flags varies from version to version. To get a list of
|
||||
the actual set of probing flags, call `hwinfo -all` (**Not** `--all`!) and look at the top of
|
||||
the log (it lists all probing flags with their respective status there).
|
||||
|
||||
## Adding/removing hardware from results
|
||||
|
||||
`hwprobe` allows you to add and remove hardware from the probing results. In
|
||||
this case the syntax is (-: remove, +: add at end of list, `<nothing>`: add at
|
||||
begin of list):
|
||||
|
||||
hwprobe=[+-]<device_class>:<vendor_id>:<device_id>[:<unix_device_file>]
|
||||
|
||||
`<device_class>`, `<vendor_id>` and `<device_id>` are device ids as used by
|
||||
libhd. See the output of `hwinfo` for examples. In connection with `-`, you can
|
||||
use `*` as a placeholder that matches every id.
|
||||
|
||||
Note: `<unix_device_file>` is optional.
|
||||
|
||||
Note2: you cannot usefully *add* hardware that needs more info than that
|
||||
given by the `hwprobe` entry. Disks & floppies are notable examples.
|
||||
(But you can *remove* them.)
|
||||
|
||||
Here is a typical `hwinfo` output for a mouse, with the relevant ids
|
||||
underlined (`<device_class>` is the combined `base_class` & `sub_class`),
|
||||
(see 1st example below):
|
||||
|
||||
14: PS/2 00.0: 10500 PS/2 Mouse
|
||||
^^^^^ --> <device_class>
|
||||
[Created at mouse.110]
|
||||
Vendor: s0200 "Unknown"
|
||||
^^^^^ --> <vendor_id>
|
||||
Model: 0002 "Generic PS/2 Mouse"
|
||||
^^^^ --> <device_id>
|
||||
Device File: /dev/psaux
|
||||
^^^^^^^^^^ --> <unix_device_file>
|
||||
Driver Info #0:
|
||||
XFree86 Protocol: ps/2
|
||||
GPM Protocol: ps2
|
||||
Attached to: #8 (PS/2 Controller)
|
||||
|
||||
Examples:
|
||||
|
||||
hwprobe=+10500:s200:2:/dev/psaux
|
||||
o add a ps/2 mouse [at the end of the hardware list]
|
||||
|
||||
hwprobe=10500:s200:2:/dev/psaux
|
||||
o add a ps/2 mouse [at the start of the hardware list, so it
|
||||
is our default mouse]
|
||||
|
||||
hwprobe=+10b00:s5001:0:/dev/ttyS0
|
||||
o add a braille display connected to /dev/ttyS0
|
||||
|
||||
hwprobe=-10500:s200:2:/dev/psaux
|
||||
o remove ps/2 mice attached to /dev/psaux
|
||||
|
||||
hwprobe=-10500:s200:2
|
||||
o remove all ps/2 mice
|
||||
|
||||
hwprobe=-10500:*:*
|
||||
o remove all ps/2 mice
|
||||
|
||||
hwprobe=-*:*:*:/dev/hdc
|
||||
o remove /dev/hdc
|
||||
|
||||
hwprobe=+401:1274:5000
|
||||
o add an ensoniq sound card
|
||||
|
||||
Graphics cards are slightly trickier:
|
||||
|
||||
hwprobe=+300:1014:b7
|
||||
o add a Fire GL1 card
|
||||
Note: this way you'll get a multihead config. You'll probably
|
||||
rather want the following example.
|
||||
|
||||
hwprobe=-300:*:*,+300:1014:b7
|
||||
o remove all graphics cards; then add a Fire GL1 card
|
||||
|
||||
hwprobe=+400:121a:1
|
||||
o add a 3fx voodoo card (Note the class "400", not "300"!)
|
||||
|
||||
For more ids, see `src/ids/names.*` and `src/ids/drivers.*`.
|
|
@ -0,0 +1,37 @@
|
|||
# Legacy
|
||||
|
||||
This document describes some legacy features.
|
||||
|
||||
__Note: please do not do this, this is only kept to assist debugging.__
|
||||
|
||||
Legacy mode is activated when no option starting with "--" is given. In this case hwinfo
|
||||
works as follows:
|
||||
|
||||
hwinfo [debug=deb_flag] [log=log_file] [list[+]=hw_item] [[+|-]probe_option1] [[+|-]probe_option2] ...
|
||||
|
||||
Examples:
|
||||
|
||||
* `hwinfo` - probes for nearly everything
|
||||
* `hwinfo +all` - probes for everything
|
||||
* `hwinfo log=hw_log` - default probing, output is written to hw_log. Please
|
||||
don't use `hwinfo >some_log 2>&1` to store the output into a log file!
|
||||
* `hwinfo -all +pci +int` - probe for pci devices
|
||||
|
||||
Note that `int` should almost always be active.
|
||||
|
||||
Some probing flags do not stand for complete modules but enable additional
|
||||
features; e.g. `bios.vesa` or `block.cdrom`.
|
||||
|
||||
Example:
|
||||
|
||||
hwinfo -all +block +int
|
||||
|
||||
gives a list of all block devs
|
||||
|
||||
hwinfo -all +block.cdrom +int
|
||||
|
||||
additionally reads the iso9660 info.
|
||||
|
||||
The list of supported flags varies from version to version. To get a list of
|
||||
the actual set of probing flags, call `hwinfo -all` and look at the top of
|
||||
the log.
|
|
@ -0,0 +1,127 @@
|
|||
# hwinfo
|
||||
|
||||
## Overview
|
||||
|
||||
hwinfo/libhd are used to probe for the hardware present in the system. It can be
|
||||
used to generate a system overview log which can be later used for support.
|
||||
|
||||
This project provides a hardware probing library `libhd.so` and a command line tool `hwinfo` using it.
|
||||
A major project using this library is [YaST](https://yast.github.io), the SUSE installation tool.
|
||||
|
||||
To give you an idea what kind of information it provides, here's the output it gives when asked about the graphcs card:
|
||||
|
||||
```sh
|
||||
# hwinfo --gfxcard
|
||||
27: PCI 200.0: 0300 VGA compatible controller (VGA)
|
||||
[Created at pci.378]
|
||||
Unique ID: B35A.G9ppNwS+xM4
|
||||
Parent ID: _Znp.nMBktMhAWbC
|
||||
SysFS ID: /devices/pci0000:00/0000:00:02.0/0000:02:00.0
|
||||
SysFS BusID: 0000:02:00.0
|
||||
Hardware Class: graphics card
|
||||
Model: "nVidia GF119 [NVS 310]"
|
||||
Vendor: pci 0x10de "nVidia Corporation"
|
||||
Device: pci 0x107d "GF119 [NVS 310]"
|
||||
SubVendor: pci 0x10de "nVidia Corporation"
|
||||
SubDevice: pci 0x094e
|
||||
Revision: 0xa1
|
||||
Driver: "nvidia"
|
||||
Driver Modules: "nvidia"
|
||||
Memory Range: 0xfa000000-0xfaffffff (rw,non-prefetchable)
|
||||
Memory Range: 0xf0000000-0xf7ffffff (ro,non-prefetchable)
|
||||
Memory Range: 0xf8000000-0xf9ffffff (ro,non-prefetchable)
|
||||
I/O Ports: 0xe000-0xefff (rw)
|
||||
Memory Range: 0xfb000000-0xfb07ffff (ro,non-prefetchable,disabled)
|
||||
IRQ: 82 (3241635 events)
|
||||
I/O Ports: 0x3c0-0x3df (rw)
|
||||
Module Alias: "pci:v000010DEd0000107Dsv000010DEsd0000094Ebc03sc00i00"
|
||||
Driver Info #0:
|
||||
Driver Status: nouveau is not active
|
||||
Driver Activation Cmd: "modprobe nouveau"
|
||||
Driver Info #1:
|
||||
Driver Status: nvidia is active
|
||||
Driver Activation Cmd: "modprobe nvidia"
|
||||
Config Status: cfg=new, avail=yes, need=no, active=unknown
|
||||
Attached to: #9 (PCI bridge)
|
||||
|
||||
Primary display adapter: #27
|
||||
```
|
||||
|
||||
If that's a bit too much information, you can ask it also for an abbreviated form. For example:
|
||||
|
||||
```sh
|
||||
# hwinfo --short --disk --cdrom
|
||||
disk:
|
||||
/dev/sda WDC WD10EARS-00Y
|
||||
/dev/sdb ST2000DM001-1CH1
|
||||
cdrom:
|
||||
/dev/sr0 PLDS DVD+-RW DS-8ABSH
|
||||
```
|
||||
|
||||
You can influence libhd via the `hwprobe` environment variable resp. the `hwprobe` boot option.
|
||||
This includes turning on or off
|
||||
probing modules and also manually adding hardware devices (to some degree).
|
||||
|
||||
For example
|
||||
|
||||
```sh
|
||||
export hwprobe=-bios
|
||||
```
|
||||
will turn off the `bios` probing module.
|
||||
|
||||
For details about `hwprobe` look [here](README-hwprobe.md).
|
||||
|
||||
For general usage instructions, see `hwinfo` manual page.
|
||||
|
||||
> ### Note
|
||||
>
|
||||
>
|
||||
> `hwinfo` has a legacy interface, accepting `hwprobe`-like options as command argument (For example
|
||||
> `hwinfo -bios` - note the single '`-`'). Please don't do this. If you are interested, you can
|
||||
> read about it [here](README-legacy.md).
|
||||
|
||||
## Technical documentation
|
||||
|
||||
The hardware detection library makes use of a number of technical specifications.
|
||||
|
||||
[Here](specifications.md) is a compilation of external links to technical standards relevant to `libhd`.
|
||||
|
||||
## openSUSE Development
|
||||
|
||||
To build the library, simply run `make`. Install with `make install`.
|
||||
|
||||
Basically every new commit into the master branch of the repository will be auto-submitted
|
||||
to all current SUSE products. No further action is needed except accepting the pull request.
|
||||
|
||||
Submissions are managed by a SUSE internal [jenkins](https://jenkins.io) node in the InstallTools tab.
|
||||
|
||||
Each time a new commit is integrated into the master branch of the repository,
|
||||
a new submit request is created to the openSUSE Build Service. The devel project
|
||||
is [system:install:head](https://build.opensuse.org/package/show/system:install:head/hwinfo).
|
||||
|
||||
For maintained branches, the package is submitted to a devel project but the final submission
|
||||
must be triggered manually.
|
||||
|
||||
`*.changes` and version numbers are auto-generated from git commits, you don't have to worry about this.
|
||||
|
||||
The spec file is maintained in the Build Service only. If you need to change it for the `master` branch,
|
||||
submit to the
|
||||
[devel project](https://build.opensuse.org/package/show/system:install:head/hwinfo)
|
||||
in the build service directly.
|
||||
|
||||
The current names of the devel projects for other branches can be seen in the jenkins logs.
|
||||
|
||||
Development happens mainly in the `master` branch. The branch is used for all current products.
|
||||
|
||||
In rare cases branching was unavoidable:
|
||||
|
||||
* branch `sl_11.1`: SLE 11 SP4
|
||||
* branch `sle12`: SLE 12 (**not** SPx)
|
||||
|
||||
You can find more information about the changes auto-generation and the
|
||||
tools used for jenkis submissions in the [linuxrc-devtools
|
||||
documentation](https://github.com/openSUSE/linuxrc-devtools#opensuse-development).
|
||||
|
||||
## Updating Database for Pci and Usb Ids
|
||||
|
||||
For details about updating pci and usb ids look [here](src/ids/README.md).
|
|
@ -0,0 +1 @@
|
|||
libhd
|
|
@ -0,0 +1,84 @@
|
|||
.TH CHECK_HD "1" "User Commands"
|
||||
.SH NAME
|
||||
manual page for check_hd
|
||||
.SH SYNOPSIS
|
||||
.B check_hd
|
||||
[\fIoptions\fR] \fIfiles\fR
|
||||
.SH DESCRIPTION
|
||||
Try to put hardware data into a consistent form.
|
||||
.TP
|
||||
\fB\-\-check\fR
|
||||
do a lot of checks and remove unnecessary data
|
||||
.TP
|
||||
\fB\-\-sort\fR
|
||||
sort data
|
||||
.TP
|
||||
\fB\-\-reverse\fR
|
||||
reverse sorting order
|
||||
.TP
|
||||
\fB\-\-split\fR
|
||||
write separate entries for each key
|
||||
.TP
|
||||
\fB\-\-with\-source\fR
|
||||
add comment to each item indicating info source
|
||||
.TP
|
||||
\fB\-\-mini\fR
|
||||
minimal data base (basically driver info only)
|
||||
.TP
|
||||
\fB\-\-join\-keys\-first\fR
|
||||
when combining similar items, join entries with
|
||||
common keys first (default is common values first)
|
||||
.TP
|
||||
\fB\-\-cfile\fR file
|
||||
create C file to be included in libhd
|
||||
.TP
|
||||
\fB\-\-no\-compact\fR
|
||||
don't try to make C version as small as possible
|
||||
.TP
|
||||
\fB\-\-out\fR file
|
||||
write results to file, default is "hd.ids"
|
||||
.TP
|
||||
\fB\-\-log\fR file
|
||||
write log info to file, default is "hd.log"
|
||||
.IP
|
||||
Note: check_hd works with libhd/hwinfo internal format only;
|
||||
to convert to other formats, use convert_hd
|
||||
.PP
|
||||
Try to put hardware data into a consistent form.
|
||||
.TP
|
||||
\fB\-\-check\fR
|
||||
do a lot of checks and remove unnecessary data
|
||||
.TP
|
||||
\fB\-\-sort\fR
|
||||
sort data
|
||||
.TP
|
||||
\fB\-\-reverse\fR
|
||||
reverse sorting order
|
||||
.TP
|
||||
\fB\-\-split\fR
|
||||
write separate entries for each key
|
||||
.TP
|
||||
\fB\-\-with\-source\fR
|
||||
add comment to each item indicating info source
|
||||
.TP
|
||||
\fB\-\-mini\fR
|
||||
minimal data base (basically driver info only)
|
||||
.TP
|
||||
\fB\-\-join\-keys\-first\fR
|
||||
when combining similar items, join entries with
|
||||
common keys first (default is common values first)
|
||||
.TP
|
||||
\fB\-\-cfile\fR file
|
||||
create C file to be included in libhd
|
||||
.TP
|
||||
\fB\-\-no\-compact\fR
|
||||
don't try to make C version as small as possible
|
||||
.TP
|
||||
\fB\-\-out\fR file
|
||||
write results to file, default is "hd.ids"
|
||||
.TP
|
||||
\fB\-\-log\fR file
|
||||
write log info to file, default is "hd.log"
|
||||
.IP
|
||||
Note: check_hd works with libhd/hwinfo internal format only;
|
||||
to convert to other formats, use convert_hd
|
|
@ -0,0 +1,29 @@
|
|||
.TH CONVERT_HD "1" "User Commands"
|
||||
.SH NAME
|
||||
convert_hd
|
||||
.SH SYNOPSIS
|
||||
.B convert_hd
|
||||
[\fIoptions\fR] \fIfiles\fR
|
||||
.SH DESCRIPTION
|
||||
Convert various hardware info to libhd/hwinfo internal format or to XML.
|
||||
.TP
|
||||
\fB\-\-ids\fR
|
||||
write internal format (default) to "hd.ids"
|
||||
.TP
|
||||
\fB\-\-no\-ids\fR
|
||||
do not write internal format
|
||||
.TP
|
||||
\fB\-\-xml\fR
|
||||
write XML to "hd.xml", DTD to "hd.dtd"
|
||||
.TP
|
||||
\fB\-\-no\-xml\fR
|
||||
do not write XML (default)
|
||||
.TP
|
||||
\fB\-\-with\-source\fR
|
||||
add comment to each item indicating info source
|
||||
.TP
|
||||
\fB\-\-internal\-dtd\fR
|
||||
generate internal dtd
|
||||
.IP
|
||||
Note: for more sophisticated operations on hardware data use check_hd.
|
||||
.IP
|
|
@ -0,0 +1,26 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <hd.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
hd_data_t *hd_data;
|
||||
hd_t *hd;
|
||||
|
||||
hd_data = calloc(1, sizeof *hd_data);
|
||||
|
||||
hd = hd_list(hd_data, hw_scsi, 1, NULL);
|
||||
|
||||
for(; hd; hd = hd->next) {
|
||||
hd_dump_entry(hd_data, hd, stdout)
|
||||
}
|
||||
|
||||
hd_free_hd_list(hd); /* free it */
|
||||
hd_free_hd_data(hd_data);
|
||||
|
||||
free(hd_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <hd.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
hd_data_t *hd_data;
|
||||
hd_t *hd;
|
||||
unsigned display_idx;
|
||||
|
||||
hd_data = calloc(1, sizeof *hd_data);
|
||||
|
||||
hd = hd_list(hd_data, hw_display, 1, NULL);
|
||||
display_idx = hd_display_adapter(hd_data);
|
||||
|
||||
hd_dump_entry(hd_data, hd_get_device_by_idx(hd_data, display_idx), stdout)
|
||||
|
||||
hd_free_hd_list(hd);
|
||||
hd_free_hd_data(hd_data);
|
||||
|
||||
free(hd_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
</body></html>
|
|
@ -0,0 +1,10 @@
|
|||
.TH GETSYSINFO "1" "getsysinfo" "User Commands"
|
||||
.SH NAME
|
||||
getsysinfo
|
||||
.SH SYNOPSIS
|
||||
.B getsysinfo
|
||||
|
||||
.SH DESCRIPTION
|
||||
Collect some system data that are useful for debugging
|
||||
hardware detection bugs.
|
||||
.PP
|
|
@ -0,0 +1,125 @@
|
|||
.TH HWINFO 8 "June 2016" "hwinfo" "System configuration"
|
||||
.\"
|
||||
.nh
|
||||
.SH NAME
|
||||
hwinfo \- probe for hardware
|
||||
.\"
|
||||
.SH SYNOPSIS
|
||||
.B hwinfo [
|
||||
.I OPTIONS
|
||||
.B ]
|
||||
.\"
|
||||
.SH DESCRIPTION
|
||||
.B hwinfo
|
||||
is used to probe for the hardware present in the system. It can be used to
|
||||
generate a system overview log which can be later used for support.
|
||||
.\"
|
||||
.SH OPTIONS
|
||||
Note that running \fBhwinfo\fR without any options is roughly equivalent
|
||||
to 'hwinfo --all --log=-'.
|
||||
.TP
|
||||
\fB--<\f[BI]HARDWARE_ITEM\fB>\fR
|
||||
This option can be given more than once.
|
||||
Probe for a particular \fIHARDWARE_ITEM\fR. Available hardware items are:
|
||||
|
||||
all, arch, bios, block, bluetooth, braille, bridge, camera, cdrom, chipcard,
|
||||
cpu, disk, dsl, dvb, fingerprint, floppy, framebuffer, gfxcard, hub, ide,
|
||||
isapnp, isdn, joystick, keyboard, memory, mmc-ctrl, modem, monitor, mouse, netcard,
|
||||
network, partition, pci, pcmcia, pcmcia-ctrl, pppoe, printer, redasd,
|
||||
reallyall, scanner, scsi, smp, sound, storage-ctrl, sys, tape, tv, uml, usb,
|
||||
usb-ctrl, vbe, wlan, xen, zip
|
||||
|
||||
Note that if this option is missing, no hardware probing will be done!
|
||||
.TP
|
||||
\fB--short\fR
|
||||
Show only a summary. Use this option in addition to a hardware probing
|
||||
option.
|
||||
.TP
|
||||
\fB--listmd\fR
|
||||
Normally hwinfo does not report RAID devices. Add this option to see them.
|
||||
.TP
|
||||
\fB--only \fIDEVNAME\fR
|
||||
This option can be given more than once. If you add this option
|
||||
only entries in the device list matching \fIDEVNAME\fR will be shown.
|
||||
Note that you also have to specify --<\fIHARDWARE_ITEM\fR> to trigger
|
||||
any device probing.
|
||||
.TP
|
||||
\fB--save-config \fISPEC\fR
|
||||
Store config for a particular device below /var/lib/hardware. \fISPEC\fR
|
||||
can be a device name, an UDI, or 'all'. This option must be given in addition to
|
||||
a hardware probing option.
|
||||
.TP
|
||||
\fB--show-config \fIUDI\fR
|
||||
Show saved config data for a particular device.
|
||||
.TP
|
||||
\fB--map\fR
|
||||
If disk names have changed (e.g. after a kernel update) this prints a list
|
||||
of disk name mappings. Note that you must have used --save-config at some
|
||||
point before for this can work.
|
||||
.TP
|
||||
\fB--debug \fIN\fR
|
||||
Set debug level to \fIN\fR. The debug info is shown only in the log file.
|
||||
If you specify a log file, the debug level is implicitly set to a reasonable value
|
||||
(N is a bitmask of individual flags).
|
||||
.TP
|
||||
\fB--verbose\fR
|
||||
Increase verbosity. Only together with --map.
|
||||
.TP
|
||||
\fB--log \fIFILE\fR
|
||||
Write log info to \fIFILE\fR.
|
||||
Don't forget to also specify --<\fIHARDWARE_ITEM\fR> to trigger any device probing.
|
||||
.TP
|
||||
\fB--dump-db \fIN\fR
|
||||
Dump hardware data base. \fIN\fR is either 0 for the external data base in
|
||||
/var/lib/hardware, or 1 for the internal data base.
|
||||
.TP
|
||||
\fB--version\fR
|
||||
Print libhd version.
|
||||
.TP
|
||||
\fB--help\fR
|
||||
Print usage.
|
||||
.\"
|
||||
.SH ENVIRONMENT
|
||||
\fBhwprobe\fR can hold a comma-separated list of probing flags preceded by '+'
|
||||
or '-' to be turned on or off. To get a complete list of supported flags,
|
||||
run 'hwinfo -all' (note: not '--all') and look at the top of the output.
|
||||
|
||||
hwinfo also looks at /proc/cmdline for a \fBhwprobe\fR option.
|
||||
.\"
|
||||
.SH EXAMPLES
|
||||
.TP
|
||||
- show all disks
|
||||
hwinfo --disk
|
||||
.TP
|
||||
- just an overview
|
||||
hwinfo --short --block
|
||||
.TP
|
||||
- show a particular disk
|
||||
hwinfo --disk --only /dev/sdb
|
||||
.TP
|
||||
- save disk config state
|
||||
hwinfo --disk --save-config=all
|
||||
.TP
|
||||
- try 4 graphics card ports for monitor data (default: 3)
|
||||
hwprobe=bios.ddc.ports=4 hwinfo --monitor
|
||||
.TP
|
||||
- monitor detection runs the Video BIOS to get the monitor data; dump a complete BIOS code execution trace to the log
|
||||
hwprobe=bios.ddc.ports=1,x86emu=trace:dump:trace.only=0:dump.only=0 \
|
||||
hwinfo --monitor --log=foo
|
||||
.\"
|
||||
.SH FILES
|
||||
.TP
|
||||
\fB/var/lib/hardware/hd.ids\fR
|
||||
External hardware data base (in readable text form). Try the --dump-db option to see the format.
|
||||
.TP
|
||||
\fB/var/lib/hardware/udi\fR
|
||||
Directory where persistent config data are stored (see --save-config option).
|
||||
.\"
|
||||
.SH BUGS
|
||||
Not all hardware can be detected.
|
||||
.\"
|
||||
.SH "SEE ALSO"
|
||||
More documentation in /usr/share/doc/packages/hwinfo.
|
||||
.br
|
||||
Source repository: git://git.opensuse.org/projects/hwinfo.git.
|
||||
.\"
|
|
@ -0,0 +1,109 @@
|
|||
/*! \mainpage libhd documentation
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
libhd is a hardware detection lib.
|
||||
|
||||
<h2>Changes</h2>
|
||||
|
||||
\ref libhd_5_12
|
||||
|
||||
<h2>Examples</h2>
|
||||
|
||||
\ref example1
|
||||
|
||||
\ref example2
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*! \page examples Examples
|
||||
|
||||
\ref example1
|
||||
|
||||
\ref example2
|
||||
|
||||
<hr>
|
||||
|
||||
\subsection example1 Get list of SCSI controllers
|
||||
|
||||
\include example1.c
|
||||
|
||||
<hr>
|
||||
|
||||
\subsection example2 Get primary display controller
|
||||
|
||||
\include example2.c
|
||||
|
||||
*/
|
||||
|
||||
/*! \page changes Changes
|
||||
|
||||
\ref libhd_5_12
|
||||
|
||||
<hr>
|
||||
|
||||
\subsection libhd_5_12 libhd-5.12
|
||||
|
||||
<ul>
|
||||
|
||||
<li>changes in \ref hd_t
|
||||
|
||||
<ul>
|
||||
|
||||
<li>\ref hd_t::bus "bus" is now a struct, use \ref hd_t::bus "bus.id" instead.
|
||||
|
||||
<li>\ref hd_t::base_class "base_class" is now a struct, use \ref hd_t::base_class "base_class.id" instead.
|
||||
|
||||
<li>\ref hd_t::sub_class "sub_class" is now a struct, use \ref hd_t::sub_class "sub_class.id" instead.
|
||||
|
||||
<li>\ref hd_t::prog_if "prog_if" is now a struct, use \ref hd_t::prog_if "prog_if.id" instead.
|
||||
|
||||
<li>\ref hd_t::vendor "vendor" is a struct replacing vend and vend_name.
|
||||
Use \ref hd_t::vendor "vendor.id" and \ref hd_t::vendor "vendor.name" now.
|
||||
|
||||
<li>\ref hd_t::device "device" is a struct replacing dev and dev_name.
|
||||
Use \ref hd_t::device "device.id" and \ref hd_t::device "device.name" now.
|
||||
|
||||
<li>\ref hd_t::sub_vendor "sub_vendor" is a struct replacing sub_vend and sub_vend_name.
|
||||
Use \ref hd_t::sub_vendor "sub_vendor.id" and \ref hd_t::sub_vendor "sub_vendor.name" now.
|
||||
|
||||
<li>\ref hd_t::sub_device "sub_device" is a struct replacing sub_dev and sub_dev_name.
|
||||
Use \ref hd_t::sub_device "sub_device.id" and \ref hd_t::sub_device "sub_device.name" now.
|
||||
|
||||
<li>\ref hd_t::revision "revision" is a struct replacing rev and rev_name.
|
||||
Use \ref hd_t::revision "revision.id" and \ref hd_t::revision "revision.name" now.
|
||||
|
||||
<li>\ref hd_t::compat_vendor "compat_vendor" is a struct replacing compat_vend.
|
||||
Use \ref hd_t::compat_vendor "compat_vendor.id" now.
|
||||
|
||||
<li>\ref hd_t::compat_device "compat_device" is a struct replacing compat_dev.
|
||||
Use \ref hd_t::compat_device "compat_device.id" now.
|
||||
|
||||
</ul>
|
||||
|
||||
<li>interface functions removed
|
||||
|
||||
<ul>
|
||||
|
||||
<li>hd_bus_name is gone. Use \ref hd_t::bus "bus.name" instead.
|
||||
|
||||
<li>hd_class_name is gone. Use \ref hd_t::base_class "base_class.name",
|
||||
\ref hd_t::sub_class "sub_class.name" or \ref hd_t::prog_if "prog_if.name" instead.
|
||||
|
||||
<li>hd_vendor_name is gone. Use \ref hd_t::vendor "vendor.name" instead.
|
||||
|
||||
<li>hd_device_name is gone. Use \ref hd_t::device "device.name" instead.
|
||||
|
||||
<li>hd_sub_device_name is gone. Use \ref hd_t::sub_device "sub_device.name" instead.
|
||||
|
||||
<li>hd_find_device_by_name is gone.
|
||||
|
||||
</ul>
|
||||
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,898 @@
|
|||
# Doxyfile 1.2.13.1
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project
|
||||
#
|
||||
# All text after a hash (#) is considered a comment and will be ignored
|
||||
# The format is:
|
||||
# TAG = value [value, ...]
|
||||
# For lists items can also be appended using:
|
||||
# TAG += value [value, ...]
|
||||
# Values that contain spaces should be placed between quotes (" ")
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# General configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
|
||||
# by quotes) that should identify the project.
|
||||
|
||||
PROJECT_NAME = libhd
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER = 5.0
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = libhd
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
# The default language is English, other supported languages are:
|
||||
# Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French,
|
||||
# German, Greek, Hungarian, Italian, Japanese, Korean, Norwegian, Polish,
|
||||
# Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
|
||||
# documentation are documented, even if no documentation was available.
|
||||
# Private class members and static file members will be hidden unless
|
||||
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
|
||||
|
||||
EXTRACT_ALL = YES
|
||||
|
||||
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_PRIVATE = NO
|
||||
|
||||
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_STATIC = YES
|
||||
|
||||
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
||||
# defined locally in source files will be included in the documentation.
|
||||
# If set to NO only classes defined in header files are included.
|
||||
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
|
||||
# undocumented members of documented classes, files or namespaces.
|
||||
# If set to NO (the default) these members will be included in the
|
||||
# various overviews, but no documentation section is generated.
|
||||
# This option has no effect if EXTRACT_ALL is enabled.
|
||||
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
|
||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
|
||||
# undocumented classes that are normally visible in the class hierarchy.
|
||||
# If set to NO (the default) these class will be included in the various
|
||||
# overviews. This option has no effect if EXTRACT_ALL is enabled.
|
||||
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
||||
# include brief member descriptions after the members that are listed in
|
||||
# the file and class documentation (similar to JavaDoc).
|
||||
# Set to NO to disable this.
|
||||
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
|
||||
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
|
||||
# the brief description of a member or function before the detailed description.
|
||||
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
|
||||
# brief descriptions will be completely suppressed.
|
||||
|
||||
REPEAT_BRIEF = YES
|
||||
|
||||
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
|
||||
# Doxygen will generate a detailed section even if there is only a brief
|
||||
# description.
|
||||
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
|
||||
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
|
||||
# members of a class in the documentation of that class as if those members were
|
||||
# ordinary class members. Constructors, destructors and assignment operators of
|
||||
# the base classes will not be shown.
|
||||
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
|
||||
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
|
||||
# path before files name in the file list and in the header files. If set
|
||||
# to NO the shortest path that makes the file name unique will be used.
|
||||
|
||||
FULL_PATH_NAMES = NO
|
||||
|
||||
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
|
||||
# can be used to strip a user defined part of the path. Stripping is
|
||||
# only done if one of the specified strings matches the left-hand part of
|
||||
# the path. It is allowed to use relative paths in the argument list.
|
||||
|
||||
STRIP_FROM_PATH =
|
||||
|
||||
# The INTERNAL_DOCS tag determines if documentation
|
||||
# that is typed after a \internal command is included. If the tag is set
|
||||
# to NO (the default) then the documentation will be excluded.
|
||||
# Set it to YES to include the internal documentation.
|
||||
|
||||
INTERNAL_DOCS = NO
|
||||
|
||||
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
|
||||
# doxygen to hide any special comment blocks from generated source code
|
||||
# fragments. Normal C and C++ comments will always remain visible.
|
||||
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
|
||||
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
|
||||
# file names in lower case letters. If set to YES upper case letters are also
|
||||
# allowed. This is useful if you have classes or files whose names only differ
|
||||
# in case and if your file system supports case sensitive file names. Windows
|
||||
# users are adviced to set this option to NO.
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
|
||||
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
|
||||
# (but less readable) file names. This can be useful is your file systems
|
||||
# doesn't support long names like on DOS, Mac, or CD-ROM.
|
||||
|
||||
SHORT_NAMES = NO
|
||||
|
||||
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
|
||||
# will show members with their full class and namespace scopes in the
|
||||
# documentation. If set to YES the scope will be hidden.
|
||||
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
|
||||
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
|
||||
# will generate a verbatim copy of the header file for each class for
|
||||
# which an include is specified. Set to NO to disable this.
|
||||
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
|
||||
# will put list of the files that are included by a file in the documentation
|
||||
# of that file.
|
||||
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
|
||||
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
|
||||
# will interpret the first line (until the first dot) of a JavaDoc-style
|
||||
# comment as the brief description. If set to NO, the JavaDoc
|
||||
# comments will behave just like the Qt-style comments (thus requiring an
|
||||
# explict @brief command for a brief description.
|
||||
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
||||
# member inherits the documentation from any documented member that it
|
||||
# reimplements.
|
||||
|
||||
INHERIT_DOCS = YES
|
||||
|
||||
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
|
||||
# is inserted in the documentation for inline members.
|
||||
|
||||
INLINE_INFO = YES
|
||||
|
||||
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
|
||||
# will sort the (detailed) documentation of file and class members
|
||||
# alphabetically by member name. If set to NO the members will appear in
|
||||
# declaration order.
|
||||
|
||||
SORT_MEMBER_DOCS = YES
|
||||
|
||||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
||||
# tag is set to YES, then doxygen will reuse the documentation of the first
|
||||
# member in the group (if any) for the other members of the group. By default
|
||||
# all members of a group must be documented explicitly.
|
||||
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
|
||||
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
||||
# Doxygen uses this value to replace tabs by spaces in code fragments.
|
||||
|
||||
TAB_SIZE = 8
|
||||
|
||||
# The GENERATE_TODOLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the todo list. This list is created by putting \todo
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_TODOLIST = YES
|
||||
|
||||
# The GENERATE_TESTLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the test list. This list is created by putting \test
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_TESTLIST = YES
|
||||
|
||||
# The GENERATE_BUGLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the bug list. This list is created by putting \bug
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_BUGLIST = YES
|
||||
|
||||
# This tag can be used to specify a number of aliases that acts
|
||||
# as commands in the documentation. An alias has the form "name=value".
|
||||
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
|
||||
# put the command \sideeffect (or @sideeffect) in the documentation, which
|
||||
# will result in a user defined paragraph with heading "Side Effects:".
|
||||
# You can put \n's in the value part of an alias to insert newlines.
|
||||
|
||||
ALIASES =
|
||||
|
||||
# The ENABLED_SECTIONS tag can be used to enable conditional
|
||||
# documentation sections, marked by \if sectionname ... \endif.
|
||||
|
||||
ENABLED_SECTIONS =
|
||||
|
||||
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
|
||||
# the initial value of a variable or define consist of for it to appear in
|
||||
# the documentation. If the initializer consists of more lines than specified
|
||||
# here it will be hidden. Use a value of 0 to hide initializers completely.
|
||||
# The appearance of the initializer of individual variables and defines in the
|
||||
# documentation can be controlled using \showinitializer or \hideinitializer
|
||||
# command in the documentation regardless of this setting.
|
||||
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
|
||||
# only. Doxygen will then generate output that is more tailored for C.
|
||||
# For instance some of the names that are used will be different. The list
|
||||
# of all members will be omitted, etc.
|
||||
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
|
||||
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
|
||||
# at the bottom of the documentation of classes and structs. If set to YES the
|
||||
# list will mention the files that were used to generate the documentation.
|
||||
|
||||
SHOW_USED_FILES = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The QUIET tag can be used to turn on/off the messages that are generated
|
||||
# by doxygen. Possible values are YES and NO. If left blank NO is used.
|
||||
|
||||
QUIET = NO
|
||||
|
||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||
# generated by doxygen. Possible values are YES and NO. If left blank
|
||||
# NO is used.
|
||||
|
||||
WARNINGS = YES
|
||||
|
||||
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
|
||||
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
|
||||
# automatically be disabled.
|
||||
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
|
||||
# The WARN_FORMAT tag determines the format of the warning messages that
|
||||
# doxygen can produce. The string should contain the $file, $line, and $text
|
||||
# tags, which will be replaced by the file and line number from which the
|
||||
# warning originated and the warning text.
|
||||
|
||||
WARN_FORMAT =
|
||||
|
||||
# The WARN_LOGFILE tag can be used to specify a file to which warning
|
||||
# and error messages should be written. If left blank the output is written
|
||||
# to stderr.
|
||||
|
||||
WARN_LOGFILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The INPUT tag can be used to specify the files and/or directories that contain
|
||||
# documented source files. You may enter file names like "myfile.cpp" or
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = libhd.doc ../src
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank the following patterns are tested:
|
||||
# *.c *.cc *.cxx *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
|
||||
# *.h++ *.idl
|
||||
|
||||
FILE_PATTERNS = *.c *.h
|
||||
|
||||
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
|
||||
# should be searched for input files as well. Possible values are YES and NO.
|
||||
# If left blank NO is used.
|
||||
|
||||
RECURSIVE = YES
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
||||
|
||||
EXCLUDE = ../src/ids
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
||||
# certain files from those directories.
|
||||
|
||||
EXCLUDE_PATTERNS =
|
||||
|
||||
# The EXAMPLE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH = .
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank all files are included.
|
||||
|
||||
EXAMPLE_PATTERNS = *.c
|
||||
|
||||
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
|
||||
# searched for input files to be used with the \include or \dontinclude
|
||||
# commands irrespective of the value of the RECURSIVE tag.
|
||||
# Possible values are YES and NO. If left blank NO is used.
|
||||
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
|
||||
# The IMAGE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain image that are included in the documentation (see
|
||||
# the \image command).
|
||||
|
||||
IMAGE_PATH =
|
||||
|
||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
||||
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
||||
# input file. Doxygen will then use the output that the filter program writes
|
||||
# to standard output.
|
||||
|
||||
INPUT_FILTER =
|
||||
|
||||
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
|
||||
# INPUT_FILTER) will be used to filter the input files when producing source
|
||||
# files to browse.
|
||||
|
||||
FILTER_SOURCE_FILES = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
|
||||
# be generated. Documented entities will be cross-referenced with these sources.
|
||||
|
||||
SOURCE_BROWSER = NO
|
||||
|
||||
# Setting the INLINE_SOURCES tag to YES will include the body
|
||||
# of functions and classes directly in the documentation.
|
||||
|
||||
INLINE_SOURCES = NO
|
||||
|
||||
# If the REFERENCED_BY_RELATION tag is set to YES (the default)
|
||||
# then for each documented function all documented
|
||||
# functions referencing it will be listed.
|
||||
|
||||
REFERENCED_BY_RELATION = YES
|
||||
|
||||
# If the REFERENCES_RELATION tag is set to YES (the default)
|
||||
# then for each documented function all documented entities
|
||||
# called/used by that function will be listed.
|
||||
|
||||
REFERENCES_RELATION = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
|
||||
# of all compounds will be generated. Enable this if the project
|
||||
# contains a lot of classes, structs, unions or interfaces.
|
||||
|
||||
ALPHABETICAL_INDEX = NO
|
||||
|
||||
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
|
||||
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
|
||||
# in which this list will be split (can be a number in the range [1..20])
|
||||
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
|
||||
# In case all classes in a project start with a common prefix, all
|
||||
# classes will be put under the same header in the alphabetical index.
|
||||
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
|
||||
# should be ignored while generating the index headers.
|
||||
|
||||
IGNORE_PREFIX =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
|
||||
# generate HTML output.
|
||||
|
||||
GENERATE_HTML = YES
|
||||
|
||||
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `html' will be used as the default path.
|
||||
|
||||
HTML_OUTPUT =
|
||||
|
||||
# The HTML_HEADER tag can be used to specify a personal HTML header for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard header.
|
||||
|
||||
HTML_HEADER =
|
||||
|
||||
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard footer.
|
||||
|
||||
HTML_FOOTER = footer.html
|
||||
|
||||
# The HTML_STYLESHEET tag can be used to specify a user defined cascading
|
||||
# style sheet that is used by each HTML page. It can be used to
|
||||
# fine-tune the look of the HTML output. If the tag is left blank doxygen
|
||||
# will generate a default style sheet
|
||||
|
||||
HTML_STYLESHEET =
|
||||
|
||||
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
||||
# files or namespaces will be aligned in HTML using tables. If set to
|
||||
# NO a bullet list will be used.
|
||||
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for tools like the
|
||||
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
|
||||
# of the generated HTML documentation.
|
||||
|
||||
GENERATE_HTMLHELP = NO
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
|
||||
# controls if a separate .chi index file is generated (YES) or that
|
||||
# it should be included in the master .chm file (NO).
|
||||
|
||||
GENERATE_CHI = NO
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
|
||||
# controls whether a binary table of contents is generated (YES) or a
|
||||
# normal table of contents (NO) in the .chm file.
|
||||
|
||||
BINARY_TOC = NO
|
||||
|
||||
# The TOC_EXPAND flag can be set to YES to add extra items for group members
|
||||
# to the contents of the Html help documentation and to the tree view.
|
||||
|
||||
TOC_EXPAND = NO
|
||||
|
||||
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
||||
# top of each HTML page. The value NO (the default) enables the index and
|
||||
# the value YES disables it.
|
||||
|
||||
DISABLE_INDEX = NO
|
||||
|
||||
# This tag can be used to set the number of enum values (range [1..20])
|
||||
# that doxygen will group on one line in the generated HTML documentation.
|
||||
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
|
||||
# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
|
||||
# generated containing a tree-like index structure (just like the one that
|
||||
# is generated for HTML Help). For this to work a browser that supports
|
||||
# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
|
||||
# or Internet explorer 4.0+). Note that for large projects the tree generation
|
||||
# can take a very long time. In such cases it is better to disable this feature.
|
||||
# Windows users are probably better off using the HTML help feature.
|
||||
|
||||
GENERATE_TREEVIEW = NO
|
||||
|
||||
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
|
||||
# used to set the initial width (in pixels) of the frame in which the tree
|
||||
# is shown.
|
||||
|
||||
TREEVIEW_WIDTH = 250
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||
# generate Latex output.
|
||||
|
||||
GENERATE_LATEX = YES
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `latex' will be used as the default path.
|
||||
|
||||
LATEX_OUTPUT =
|
||||
|
||||
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
|
||||
# LaTeX documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_LATEX = NO
|
||||
|
||||
# The PAPER_TYPE tag can be used to set the paper type that is used
|
||||
# by the printer. Possible values are: a4, a4wide, letter, legal and
|
||||
# executive. If left blank a4wide will be used.
|
||||
|
||||
PAPER_TYPE = a4wide
|
||||
|
||||
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
|
||||
# packages that should be included in the LaTeX output.
|
||||
|
||||
EXTRA_PACKAGES =
|
||||
|
||||
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
|
||||
# the generated latex document. The header should contain everything until
|
||||
# the first chapter. If it is left blank doxygen will generate a
|
||||
# standard header. Notice: only use this tag if you know what you are doing!
|
||||
|
||||
LATEX_HEADER =
|
||||
|
||||
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
|
||||
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
|
||||
# contain links (just like the HTML output) instead of page references
|
||||
# This makes the output suitable for online browsing using a pdf viewer.
|
||||
|
||||
PDF_HYPERLINKS = NO
|
||||
|
||||
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
|
||||
# plain latex in the generated Makefile. Set this option to YES to get a
|
||||
# higher quality PDF documentation.
|
||||
|
||||
USE_PDFLATEX = NO
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep
|
||||
# running if errors occur, instead of asking the user for help.
|
||||
# This option is also used when generating formulas in HTML.
|
||||
|
||||
LATEX_BATCHMODE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
|
||||
# The RTF output is optimised for Word 97 and may not look very pretty with
|
||||
# other RTF readers or editors.
|
||||
|
||||
GENERATE_RTF = NO
|
||||
|
||||
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `rtf' will be used as the default path.
|
||||
|
||||
RTF_OUTPUT =
|
||||
|
||||
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
|
||||
# RTF documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_RTF = NO
|
||||
|
||||
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
|
||||
# will contain hyperlink fields. The RTF file will
|
||||
# contain links (just like the HTML output) instead of page references.
|
||||
# This makes the output suitable for online browsing using WORD or other
|
||||
# programs which support those fields.
|
||||
# Note: wordpad (write) and others do not support links.
|
||||
|
||||
RTF_HYPERLINKS = NO
|
||||
|
||||
# Load stylesheet definitions from file. Syntax is similar to doxygen's
|
||||
# config file, i.e. a series of assigments. You only have to provide
|
||||
# replacements, missing definitions are set to their default value.
|
||||
|
||||
RTF_STYLESHEET_FILE =
|
||||
|
||||
# Set optional variables used in the generation of an rtf document.
|
||||
# Syntax is similar to doxygen's config file.
|
||||
|
||||
RTF_EXTENSIONS_FILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
||||
# generate man pages
|
||||
|
||||
GENERATE_MAN = NO
|
||||
|
||||
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `man' will be used as the default path.
|
||||
|
||||
MAN_OUTPUT =
|
||||
|
||||
# The MAN_EXTENSION tag determines the extension that is added to
|
||||
# the generated man pages (default is the subroutine's section .3)
|
||||
|
||||
MAN_EXTENSION =
|
||||
|
||||
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
|
||||
# then it will generate one additional man file for each entity
|
||||
# documented in the real man page(s). These additional files
|
||||
# only source the real man page, but without them the man command
|
||||
# would be unable to find the correct page. The default is NO.
|
||||
|
||||
MAN_LINKS = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_XML tag is set to YES Doxygen will
|
||||
# generate an XML file that captures the structure of
|
||||
# the code including all documentation. Note that this
|
||||
# feature is still experimental and incomplete at the
|
||||
# moment.
|
||||
|
||||
GENERATE_XML = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
|
||||
# generate an AutoGen Definitions (see autogen.sf.net) file
|
||||
# that captures the structure of the code including all
|
||||
# documentation. Note that this feature is still experimental
|
||||
# and incomplete at the moment.
|
||||
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
|
||||
# evaluate all C-preprocessor directives found in the sources and include
|
||||
# files.
|
||||
|
||||
ENABLE_PREPROCESSING = YES
|
||||
|
||||
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
|
||||
# names in the source code. If set to NO (the default) only conditional
|
||||
# compilation will be performed. Macro expansion can be done in a controlled
|
||||
# way by setting EXPAND_ONLY_PREDEF to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
|
||||
# then the macro expansion is limited to the macros specified with the
|
||||
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
|
||||
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
|
||||
# in the INCLUDE_PATH (see below) will be search if a #include is found.
|
||||
|
||||
SEARCH_INCLUDES = YES
|
||||
|
||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||
# contain include files that are not input files but should be processed by
|
||||
# the preprocessor.
|
||||
|
||||
INCLUDE_PATH =
|
||||
|
||||
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
||||
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
||||
# directories. If left blank, the patterns specified with FILE_PATTERNS will
|
||||
# be used.
|
||||
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
|
||||
# The PREDEFINED tag can be used to specify one or more macro names that
|
||||
# are defined before the preprocessor is started (similar to the -D option of
|
||||
# gcc). The argument of the tag is a list of macros of the form: name
|
||||
# or name=definition (no spaces). If the definition and the = are
|
||||
# omitted =1 is assumed.
|
||||
|
||||
PREDEFINED =
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
|
||||
# this tag can be used to specify a list of macro names that should be expanded.
|
||||
# The macro definition that is found in the sources will be used.
|
||||
# Use the PREDEFINED tag if you want to use a different macro definition.
|
||||
|
||||
EXPAND_AS_DEFINED =
|
||||
|
||||
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
|
||||
# doxygen's preprocessor will remove all function-like macros that are alone
|
||||
# on a line and do not end with a semicolon. Such function macros are typically
|
||||
# used for boiler-plate code, and will confuse the parser if not removed.
|
||||
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The TAGFILES tag can be used to specify one or more tagfiles.
|
||||
|
||||
TAGFILES =
|
||||
|
||||
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
||||
# a tag file that is based on the input files it reads.
|
||||
|
||||
GENERATE_TAGFILE =
|
||||
|
||||
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
||||
# in the class index. If set to NO only the inherited external classes
|
||||
# will be listed.
|
||||
|
||||
ALLEXTERNALS = NO
|
||||
|
||||
# The PERL_PATH should be the absolute path and name of the perl script
|
||||
# interpreter (i.e. the result of `which perl').
|
||||
|
||||
PERL_PATH =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
|
||||
# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
|
||||
# super classes. Setting the tag to NO turns the diagrams off. Note that this
|
||||
# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
|
||||
# recommended to install and use dot, since it yield more powerful graphs.
|
||||
|
||||
CLASS_DIAGRAMS = YES
|
||||
|
||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||
# available from the path. This tool is part of Graphviz, a graph visualization
|
||||
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
||||
# have no effect if this option is set to NO (the default)
|
||||
|
||||
HAVE_DOT = NO
|
||||
|
||||
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
# indirect inheritance relations. Setting this tag to YES will force the
|
||||
# the CLASS_DIAGRAMS tag to NO.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
|
||||
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
# indirect implementation dependencies (inheritance, containment, and
|
||||
# class references variables) of the class with other documented classes.
|
||||
|
||||
COLLABORATION_GRAPH = YES
|
||||
|
||||
# If set to YES, the inheritance and collaboration graphs will show the
|
||||
# relations between templates and their instances.
|
||||
|
||||
TEMPLATE_RELATIONS = YES
|
||||
|
||||
# If set to YES, the inheritance and collaboration graphs will hide
|
||||
# inheritance and usage relations if the target is undocumented
|
||||
# or is not a class.
|
||||
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
|
||||
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
|
||||
# tags are set to YES then doxygen will generate a graph for each documented
|
||||
# file showing the direct and indirect include dependencies of the file with
|
||||
# other documented files.
|
||||
|
||||
INCLUDE_GRAPH = YES
|
||||
|
||||
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
|
||||
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
|
||||
# documented header file showing the documented files that directly or
|
||||
# indirectly include this file.
|
||||
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
|
||||
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
||||
# will graphical hierarchy of all classes instead of a textual one.
|
||||
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
|
||||
# The tag DOT_PATH can be used to specify the path where the dot tool can be
|
||||
# found. If left blank, it is assumed the dot tool can be found on the path.
|
||||
|
||||
DOT_PATH =
|
||||
|
||||
# The DOTFILE_DIRS tag can be used to specify one or more directories that
|
||||
# contain dot files that are included in the documentation (see the
|
||||
# \dotfile command).
|
||||
|
||||
DOTFILE_DIRS =
|
||||
|
||||
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
|
||||
# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
|
||||
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
|
||||
# generate a legend page explaining the meaning of the various boxes and
|
||||
# arrows in the dot generated graphs.
|
||||
|
||||
GENERATE_LEGEND = YES
|
||||
|
||||
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
|
||||
# remove the intermedate dot files that are used to generate
|
||||
# the various graphs.
|
||||
|
||||
DOT_CLEANUP = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
||||
# used. If set to NO the values of all tags below this one will be ignored.
|
||||
|
||||
SEARCHENGINE = NO
|
||||
|
||||
# The CGI_NAME tag should be the name of the CGI script that
|
||||
# starts the search engine (doxysearch) with the correct parameters.
|
||||
# A script with this name will be generated by doxygen.
|
||||
|
||||
CGI_NAME =
|
||||
|
||||
# The CGI_URL tag should be the absolute URL to the directory where the
|
||||
# cgi binaries are located. See the documentation of your http daemon for
|
||||
# details.
|
||||
|
||||
CGI_URL =
|
||||
|
||||
# The DOC_URL tag should be the absolute URL to the directory where the
|
||||
# documentation is located. If left blank the absolute path to the
|
||||
# documentation, with file:// prepended to it, will be used.
|
||||
|
||||
DOC_URL =
|
||||
|
||||
# The DOC_ABSPATH tag should be the absolute path to the directory where the
|
||||
# documentation is located. If left blank the directory on the local machine
|
||||
# will be used.
|
||||
|
||||
DOC_ABSPATH =
|
||||
|
||||
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
|
||||
# is installed.
|
||||
|
||||
BIN_ABSPATH =
|
||||
|
||||
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
|
||||
# documentation generated for other projects. This allows doxysearch to search
|
||||
# the documentation for these projects as well.
|
||||
|
||||
EXT_DOC_PATHS =
|
|
@ -0,0 +1,8 @@
|
|||
.TH mk_isdnhwdb "1" "mk_isdnhwdb" "User Commands"
|
||||
.SH NAME
|
||||
mk_isdnhwdb
|
||||
.SH SYNOPSIS
|
||||
.B mk_isdnhwdb
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
|
@ -0,0 +1,50 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# gen-hwcfg-disk.sh
|
||||
#
|
||||
# Generates hwcfg file for all configured disks
|
||||
#
|
||||
|
||||
if [ -x /sbin/ata_identify ]; then
|
||||
ATA_ID=/sbin/ata_identify
|
||||
elif [ -x /lib/klibc/bin/ata_identify ]; then
|
||||
ATA_ID=/lib/klibc/bin/ata_identify
|
||||
else
|
||||
echo "ata_identify not found, please install udev"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
hwcfg=/etc/sysconfig/hardware
|
||||
|
||||
if [ ! -d "$hwcfg" ]; then
|
||||
echo "No hardware configuration directory found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# IDE disks first
|
||||
for ifname in /sys/block/hd*; do
|
||||
id=$($ATA_ID /dev/${ifname##*/} 2> /dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
filename="SATA_$id"
|
||||
echo "Generate hwcfg file for $filename"
|
||||
echo "DEVICE=${ifname##*/}" > ${hwcfg}/hwcfg-disk-id-${filename}
|
||||
fi
|
||||
done
|
||||
|
||||
# SCSI disks next
|
||||
for ifname in /sys/block/sd*; do
|
||||
if [ -d $ifname/device ]; then
|
||||
read vendor < $ifname/device/vendor
|
||||
if [ "$vendor" = "ATA" ]; then
|
||||
# We need page 0x80 to get the serial number
|
||||
page="-p 0x80"
|
||||
else
|
||||
page=
|
||||
fi
|
||||
scsi_id -g $page -s ${ifname#/sys} 2> /dev/null | while read vendor model serial; do
|
||||
filename="${vendor}_${model}_${serial}"
|
||||
echo "Generate hwcfg file for $filename"
|
||||
echo "DEVICE=${ifname##*/}" > ${hwcfg}/hwcfg-disk-id-${filename}
|
||||
done
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,91 @@
|
|||
#! /bin/sh
|
||||
|
||||
if [ "$1" ] ; then
|
||||
cat <<EOF
|
||||
Usage: getsysinfo
|
||||
Collect some system data that are useful for debugging
|
||||
hardware detection bugs.
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# collect some system data
|
||||
|
||||
dir=`mktemp -d /tmp/getsysinfo.XXXXXXXXXX`
|
||||
|
||||
[ -d "$dir" ] || exit 1
|
||||
|
||||
host=`hostname`
|
||||
[ "$host" ] || host=xxx
|
||||
|
||||
mkdir -p "$dir/$host"
|
||||
|
||||
for i in \
|
||||
/proc/asound \
|
||||
/proc/bus/input \
|
||||
/proc/cpuinfo \
|
||||
/proc/device-tree \
|
||||
/proc/devices \
|
||||
/proc/dma \
|
||||
/proc/driver/nvram \
|
||||
/proc/fb \
|
||||
/proc/filesystems \
|
||||
/proc/iSeries \
|
||||
/proc/ide \
|
||||
/proc/interrupts \
|
||||
/proc/iomem \
|
||||
/proc/ioports \
|
||||
/proc/meminfo \
|
||||
/proc/modules \
|
||||
/proc/net/dev \
|
||||
/proc/partitions \
|
||||
/proc/scsi \
|
||||
/proc/sys/dev/cdrom/info \
|
||||
/proc/sys/dev/parport \
|
||||
/proc/tty \
|
||||
/proc/version \
|
||||
/sys \
|
||||
/var/log/boot.msg \
|
||||
/var/lib/hardware/udi
|
||||
do
|
||||
if [ -e "$i" ] ; then
|
||||
echo "$i"
|
||||
cp -x -a --parents "$i" "$dir/$host" 2>/dev/null
|
||||
chmod -R u+w,a+r,a+X "$dir/$host"
|
||||
for i in `( cd "$dir/$host" ; find proc -type f -size 0 )` ; do
|
||||
cat "/$i" >"$dir/$host/$i"
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
echo /proc/mounts
|
||||
perl -nl -e 'print unless (split)[0] =~ /none|automount|:/' /proc/mounts >"$dir/$host/proc/mounts"
|
||||
|
||||
mkdir -p "$dir/$host/var/log"
|
||||
echo "
|
||||
------ dmesg start ------
|
||||
" >>"$dir/$host/var/log/boot.msg"
|
||||
dmesg >>"$dir/$host/var/log/boot.msg"
|
||||
|
||||
if [ -x /usr/bin/lshal ] ; then
|
||||
echo lshal
|
||||
lshal >$dir/$host/lshal.txt 2>/dev/null
|
||||
fi
|
||||
|
||||
file="$host.tar.gz"
|
||||
tar -C "$dir" -zcf "$dir/$file" "$host"
|
||||
|
||||
rm -f "/tmp/$file"
|
||||
|
||||
if [ -e "/tmp/$file" ] ; then
|
||||
echo "Warning: /tmp/$file exists, no info written"\!
|
||||
rm -rf "$dir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ln -nf "$dir/$file" "/tmp/$file"
|
||||
|
||||
rm -rf "$dir"
|
||||
|
||||
echo "
|
||||
System data written to: /tmp/$file"
|
|
@ -0,0 +1,984 @@
|
|||
#! /usr/bin/perl
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
#
|
||||
# This script is maintained at https://github.com/openSUSE/linuxrc-devtools
|
||||
#
|
||||
# If you're in another project, this is just a copy.
|
||||
# You may update it to the latest version from time to time...
|
||||
#
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
use strict;
|
||||
|
||||
use Getopt::Long;
|
||||
|
||||
use Data::Dumper;
|
||||
$Data::Dumper::Sortkeys = 1;
|
||||
$Data::Dumper::Terse = 1;
|
||||
$Data::Dumper::Indent = 1;
|
||||
|
||||
sub usage;
|
||||
sub changelog_outdated;
|
||||
sub get_github_project;
|
||||
sub get_version;
|
||||
sub get_tags;
|
||||
sub get_log;
|
||||
sub is_formatted_tag;
|
||||
sub get_branch;
|
||||
sub choose_tags;
|
||||
sub add_head_tag;
|
||||
sub tags_to_str;
|
||||
sub format_log;
|
||||
sub format_all_logs;
|
||||
sub fix_dates;
|
||||
sub add_line_breaks;
|
||||
sub format_date_obs;
|
||||
sub format_date_iso;
|
||||
sub raw_date_to_s;
|
||||
|
||||
usage 0 if !@ARGV;
|
||||
|
||||
my @changelog_deps = qw ( .git/HEAD .git/refs/heads .git/refs/tags );
|
||||
|
||||
my $branch;
|
||||
my $current_version;
|
||||
my @tags;
|
||||
my @all_tags;
|
||||
my $config;
|
||||
|
||||
my $opt_log;
|
||||
my $opt_version;
|
||||
my $opt_branch;
|
||||
my $opt_update;
|
||||
my $opt_file;
|
||||
my $opt_start;
|
||||
my $opt_max;
|
||||
my $opt_width = 66;
|
||||
my $opt_width_fuzz = 8;
|
||||
my $opt_sep_width = 68;
|
||||
my $opt_format = 'internal'; # obs, internal
|
||||
my $opt_merge_msg_before = 1; # log auto generated pr merge message before the commit messages (vs. after)
|
||||
my $opt_join_author = 1; # join consecutive commit messages as long as they are by the same author
|
||||
my $opt_keep_date = 1; # don't join consecutive commit messages if they have different time stamps
|
||||
my $opt_default_email = 'opensuse-packaging@opensuse.org'; # default email to use in changelog
|
||||
|
||||
GetOptions(
|
||||
'help' => sub { usage 0 },
|
||||
'version' => \$opt_version,
|
||||
'branch' => \$opt_branch,
|
||||
'update' => \$opt_update,
|
||||
'start=s' => \$opt_start,
|
||||
'format=s' => \$opt_format,
|
||||
'max=i' => \$opt_max,
|
||||
'width=i' => \$opt_width,
|
||||
'fuzz=i' => \$opt_width_fuzz,
|
||||
'merge-msg=s' => sub { $opt_merge_msg_before = ($_[1] eq 'after' ? 0 : 1) },
|
||||
'join-author!' => \$opt_join_author,
|
||||
'keep-date!' => \$opt_keep_date,
|
||||
'log|changelog' => \$opt_log,
|
||||
'default-email=s' => \$opt_default_email,
|
||||
) || usage 1;
|
||||
|
||||
# ensure we are used correctly
|
||||
usage 1 if @ARGV > 1 || !($opt_log || $opt_version || $opt_branch);
|
||||
$opt_file = @ARGV ? shift : '-';
|
||||
|
||||
die "no git repo\n" unless -d ".git";
|
||||
|
||||
# if update option has been give write changelog only if git refs are newer
|
||||
exit 0 if $opt_update && $opt_file ne '-' && -f($opt_file) && !changelog_outdated($opt_file);
|
||||
|
||||
$opt_max = 2 if $opt_version || $opt_branch;
|
||||
|
||||
# gather some data
|
||||
get_github_project;
|
||||
get_branch;
|
||||
get_log;
|
||||
fix_dates;
|
||||
get_tags;
|
||||
choose_tags;
|
||||
add_head_tag;
|
||||
get_version;
|
||||
|
||||
# just print current branch
|
||||
if($opt_branch) {
|
||||
open my $f, ">$opt_file";
|
||||
print $f $config->{branch} ? $config->{branch} : "master", "\n";
|
||||
close $f;
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# just print current version
|
||||
if($opt_version) {
|
||||
my $old_version;
|
||||
|
||||
if($opt_file ne '-' && open(my $f, $opt_file)) {
|
||||
chomp($old_version = <$f>);
|
||||
close $f;
|
||||
}
|
||||
|
||||
if($config->{version} ne $old_version) {
|
||||
open my $f, ">$opt_file";
|
||||
print $f "$config->{version}\n";
|
||||
close $f;
|
||||
}
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# set start tag
|
||||
if($opt_start) {
|
||||
my $x = is_formatted_tag $opt_start;
|
||||
die "$opt_start: not a valid start tag\n" if !$x;
|
||||
$x->{branch} = $config->{branch} if !$x->{branch};
|
||||
$config->{start} = $x;
|
||||
}
|
||||
|
||||
format_all_logs;
|
||||
|
||||
open my $f, ">$opt_file";
|
||||
|
||||
print $f $_->{formatted} for @{$config->{log}};
|
||||
|
||||
close $f;
|
||||
|
||||
exit 0;
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# usage(exit_code)
|
||||
#
|
||||
# Print help message and exit.
|
||||
# - exit_code: exit code
|
||||
#
|
||||
# Function does not return.
|
||||
#
|
||||
sub usage
|
||||
{
|
||||
my $err = shift;
|
||||
|
||||
print <<" usage";
|
||||
Usage: git2log [OPTIONS] [FILE]
|
||||
Create changelog and project version from git repo.
|
||||
--changelog Write changelog to FILE.
|
||||
--version Write version number to FILE.
|
||||
--branch Write current branch to FILE.
|
||||
--start START_TAG Start with tag START_TAG.
|
||||
--max N Write at most MAX long entries.
|
||||
--update Write changelog or version only if FILE is outdated.
|
||||
--format FORMAT Write log using FORMAT. Supported FORMATs are 'internal' (default) and 'obs'.
|
||||
--width WIDTH Reformat log entries to be max WIDTH chars wide.
|
||||
--fuzz FUZZ Allow log lines to be up to FUZZ chars longer as WIDTH to avoid
|
||||
line breaks leaving tiny bits on the last line.
|
||||
--merge-msg WHERE Log message about merges before or after the actual merge commit messages.
|
||||
Valid values for WHERE are 'after' and 'before' (default).
|
||||
--join-author Join consecutive commits as long as they are by the same author. (default)
|
||||
--no-join-author Keep consecutive commits by the same author separate.
|
||||
--keep-date Join consecutive commits only if they have the same date. (default)
|
||||
--no-keep-date Join consecutive commits even if dates differ.
|
||||
--default-email Use this email in changelog entries if no other suitable email could be
|
||||
determined (default: opensuse-packaging\@opensuse.org).
|
||||
--help Print this help text.
|
||||
usage
|
||||
|
||||
exit $err;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# res = changelog_outdated(file)
|
||||
#
|
||||
# Return status of changelog file.
|
||||
# - file: changelog file name
|
||||
# - res: status
|
||||
# 1: file is newer than the last git repo change and should be updated
|
||||
# 0: file is still recent enough
|
||||
#
|
||||
# Relies on global var @changelog_deps.
|
||||
#
|
||||
sub changelog_outdated
|
||||
{
|
||||
my $file = $_[0];
|
||||
|
||||
my $changelog_time = (stat $file)[9];
|
||||
|
||||
return 1 if !defined $changelog_time;
|
||||
|
||||
for (@changelog_deps) {
|
||||
return 1 if (stat)[9] > $changelog_time;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# get_github_project()
|
||||
#
|
||||
# Set $config->{github_project} to the github project name.
|
||||
#
|
||||
sub get_github_project
|
||||
{
|
||||
if(`git config remote.origin.url` =~ m#github.com[:/]+(\S+/\S+)#) {
|
||||
$config->{github_project} = $1;
|
||||
$config->{github_project} =~ s/\.git$//;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# get_version()
|
||||
#
|
||||
# Set $config->{branch} and $config->{version} to the current branch and
|
||||
# version info.
|
||||
#
|
||||
# This might be taken directly from HEAD if HEAD is tagged or otherwise be
|
||||
# exprapolated from the most recent tag (cf. add_head_tag()).
|
||||
#
|
||||
sub get_version
|
||||
{
|
||||
$config->{version} = "0.0";
|
||||
|
||||
my $tag = $config->{log}[0]{tags}[0];
|
||||
|
||||
if($tag->{version}) {
|
||||
$config->{version} = $tag->{version};
|
||||
$config->{branch} = $tag->{branch};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# get_tags()
|
||||
#
|
||||
# Parse $config->{raw_log}, extract tag names, and split into per-tag
|
||||
# sections.
|
||||
#
|
||||
# Only tags recognized by is_formatted_tag() are considered.
|
||||
#
|
||||
# Tags inside merge commits are ignored.
|
||||
#
|
||||
# The parsed logs is stored in $config->{log}, an array of log sections.
|
||||
# Each section is a hash with these keys:
|
||||
# - 'tags': array of tags for this section
|
||||
# - 'commit': git commit id associated with these tags
|
||||
# - 'lines': git log lines
|
||||
#
|
||||
sub get_tags
|
||||
{
|
||||
my $log_entry;
|
||||
|
||||
# the end of the merge commit if in a merge
|
||||
my $merge;
|
||||
|
||||
for (@{$config->{raw_log}}) {
|
||||
if(/^commit (\S+)( \((.*)\))?/) {
|
||||
my $commit = $1;
|
||||
my $tag_list = $3;
|
||||
my $xtag;
|
||||
|
||||
# we have reached the end of the merge commit
|
||||
undef $merge if $merge && $commit =~ /^$merge/;
|
||||
|
||||
# ignore tag info inside a merge commit
|
||||
$tag_list = "" if $merge;
|
||||
|
||||
for my $t (split /, /, $tag_list) {
|
||||
if($t =~ /tag: (\S+)/) {
|
||||
my $tag = $1;
|
||||
my $x = is_formatted_tag $tag;
|
||||
push @$xtag, $x if $x;
|
||||
}
|
||||
}
|
||||
|
||||
if($xtag) {
|
||||
if($log_entry) {
|
||||
push @{$config->{log}}, $log_entry;
|
||||
last if $opt_max && @{$config->{log}} >= $opt_max;
|
||||
}
|
||||
$log_entry = { commit => $commit, tags => $xtag };
|
||||
}
|
||||
else {
|
||||
$log_entry = { commit => $commit } if !$log_entry;
|
||||
}
|
||||
}
|
||||
elsif(!$merge && /^Merge: (\S+)/) {
|
||||
# remember end of merge
|
||||
$merge = $1;
|
||||
}
|
||||
|
||||
push @{$log_entry->{lines}}, $_ if $log_entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# get_log()
|
||||
#
|
||||
# Read git log and store lines as array in $config->{raw_log} (trailing
|
||||
# newlines removed).
|
||||
#
|
||||
sub get_log
|
||||
{
|
||||
chomp(@{$config->{raw_log}} = `git log --pretty=medium --date=raw --topo-order --decorate`);
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# hash_ref = is_formatted_tag(tag_name)
|
||||
#
|
||||
# Parse tag and return hash ref with branch and version number parts or
|
||||
# undef if it doesn't match.
|
||||
# - tag_name: tag as string
|
||||
# - hash_ref: hash ref with internal tag representation (with keys 'branch' and 'version').
|
||||
#
|
||||
# This expects tags of the form "VERSION" or "BRANCH-VERSION" where VERSION
|
||||
# consists of decimal numbers separated by dots '.' and BRANCH can be any
|
||||
# string.
|
||||
# (Note: it doesn't really have to be the name of an existing branch.)
|
||||
#
|
||||
# Tags not conforming to this convention are ignored.
|
||||
#
|
||||
sub is_formatted_tag
|
||||
{
|
||||
if($_[0] =~ /^((.+)-)?((\d+\.)*\d+)$/) {
|
||||
return { branch => $2, version => $3 }
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# get_branch()
|
||||
#
|
||||
# Get currently active git branch and store in $config->{branch}.
|
||||
#
|
||||
# 'master' branch is represented by empty 'branch' key.
|
||||
#
|
||||
sub get_branch
|
||||
{
|
||||
chomp(my $branch = `git rev-parse --abbrev-ref HEAD`);
|
||||
|
||||
$branch = "" if $branch eq 'master';
|
||||
|
||||
$config->{branch} = $branch;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# res = tag_sort(a, b)
|
||||
#
|
||||
# Compare 2 tags.
|
||||
# - a, b: refs to tag hash
|
||||
# - res: -1, 0, 1
|
||||
#
|
||||
# This is used when we have to decide between alternative tags.
|
||||
# (Prefer 'lesser' variant.)
|
||||
#
|
||||
sub tag_sort
|
||||
{
|
||||
my ($x, $y);
|
||||
|
||||
$x = length $a->{version};
|
||||
$y = length $b->{version};
|
||||
|
||||
# longer version number first
|
||||
return $y <=> $x if $y <=> $x;
|
||||
|
||||
return $a->{branch} cmp $b->{branch};
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# str = tag_to_str(tag_ref)
|
||||
#
|
||||
# Convert tag into string.
|
||||
# - tag_ref: ref to hash with 'branch' and 'version' keys
|
||||
# - str: string (e.g. "foo-1.44")
|
||||
#
|
||||
# 'master' branch is represented by missing/empty 'branch' key.
|
||||
#
|
||||
sub tag_to_str
|
||||
{
|
||||
my $tag = $_[0];
|
||||
my $str;
|
||||
|
||||
$str = "$tag->{branch}-" if $tag->{branch} ne "";
|
||||
$str .= $tag->{version};
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# str = tags_to_str(tag_array_ref)
|
||||
#
|
||||
# Convert array of tags into string.
|
||||
# - tag_array_ref: ref to array of tags
|
||||
# - str: string (e.g. "(tag1, tag2)"
|
||||
#
|
||||
# This function is used only internally for debugging.
|
||||
#
|
||||
sub tags_to_str
|
||||
{
|
||||
my $tags = $_[0];
|
||||
my $str;
|
||||
|
||||
for my $t (@$tags) {
|
||||
$str .= ", " if $str;
|
||||
$str .= tag_to_str $t;
|
||||
}
|
||||
|
||||
return "($str)";
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# choose_tags()
|
||||
#
|
||||
# Scan commit messages and extract tag & branch information.
|
||||
#
|
||||
# This stores the tag/branch info in $config->{log}[]{tags}.
|
||||
#
|
||||
sub choose_tags
|
||||
{
|
||||
my $branch = $config->{branch};
|
||||
|
||||
for my $x (@{$config->{log}}) {
|
||||
# printf "# %s\n", tags_to_str($x->{tags});
|
||||
|
||||
# no tag info? -> ignore
|
||||
next if !$x->{tags};
|
||||
|
||||
# single tag? -> remember branch info
|
||||
if(@{$x->{tags}} == 1) {
|
||||
$branch = $x->{tags}[0]{branch};
|
||||
next;
|
||||
}
|
||||
|
||||
# several tags? -> choose one
|
||||
|
||||
# any with current branch name?
|
||||
my @t = grep { $_->{branch} eq $branch } @{$x->{tags}};
|
||||
|
||||
# no? -> choose among all
|
||||
@t = @{$x->{tags}} if @t == 0;
|
||||
|
||||
# prefer longest version number, then alphanumerically smallest branch name
|
||||
@t = sort tag_sort @t;
|
||||
|
||||
$branch = $t[0]{branch};
|
||||
$x->{tags} = [ $t[0] ];
|
||||
|
||||
# printf "X %s\n", tags_to_str($x->{tags});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# add_head_tag()
|
||||
#
|
||||
# Suggest tag for HEAD if there isn't one.
|
||||
#
|
||||
# Basically, use branch + version from most recent tag and increment version.
|
||||
#
|
||||
sub add_head_tag
|
||||
{
|
||||
return if @{$config->{log}} < 2;
|
||||
|
||||
# HEAD tagged already?
|
||||
return if $config->{log}[0]{tags};
|
||||
|
||||
# the first tagged commit if HEAD isn't tagged
|
||||
my $tag = { %{$config->{log}[1]{tags}[0]} };
|
||||
|
||||
# increment version
|
||||
$tag->{version} =~ s/(\d+)$/$1 + 1/e;
|
||||
|
||||
$config->{log}[0]{tags}[0] = $tag;
|
||||
|
||||
# remember that the tag was generated
|
||||
$config->{log}[0]{was_untagged} = 1;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# fix_dates()
|
||||
#
|
||||
# Adjust time stamps in entire git log.
|
||||
#
|
||||
# The time stamps of the git commits are not necessarily ordered by date.
|
||||
# But the generated changelog is required to have a strictly monotonic time.
|
||||
#
|
||||
# We do this by going through the log in reverse and rewriting any dates we
|
||||
# find whenever the date decreases.
|
||||
#
|
||||
# A minimum time difference of 1 second beween entries is maintained.
|
||||
#
|
||||
# Not very subtle but it works.
|
||||
#
|
||||
sub fix_dates
|
||||
{
|
||||
my $last_date;
|
||||
|
||||
for (reverse @{$config->{raw_log}}) {
|
||||
# e.g. "Date: 1443184889 +0200"
|
||||
if(/^(Date:\s+)(\S+)(\s+\S+)/) {
|
||||
if(defined $last_date && $2 < $last_date) {
|
||||
$_ = "$1$last_date$3\n";
|
||||
}
|
||||
else {
|
||||
$last_date = $2;
|
||||
}
|
||||
|
||||
# ensure a minimal time gap of 1 second
|
||||
$last_date += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# format_all_logs()
|
||||
#
|
||||
# Format the entire git log.
|
||||
#
|
||||
# This is done for every code version individually (the log has already been
|
||||
# split accordingly).
|
||||
#
|
||||
# If $config->{start} is set, use this as starting point. Else format the
|
||||
# entire git log.
|
||||
#
|
||||
sub format_all_logs
|
||||
{
|
||||
# check if start tag actually exists - if not, print nothing
|
||||
if($config->{start}) {
|
||||
my $tag_found;
|
||||
for (@{$config->{log}}) {
|
||||
$tag_found = 1, last if grep { tag_to_str($config->{start}) eq tag_to_str($_) } @{$_->{tags}};
|
||||
}
|
||||
return if !$tag_found;
|
||||
}
|
||||
|
||||
for (@{$config->{log}}) {
|
||||
if($config->{start}) {
|
||||
# stop if we meet the start tag
|
||||
last if grep { tag_to_str($config->{start}) eq tag_to_str($_) } @{$_->{tags}};
|
||||
}
|
||||
format_log $_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# format_log(log)
|
||||
#
|
||||
# Format log messages.
|
||||
# - log: is an array ref with individual commits
|
||||
#
|
||||
# All commits belong to a specific code version (stored in $log->{tag}).
|
||||
# $log->{formatted} holds the result.
|
||||
#
|
||||
# The process is done in several individual steps, documented below in the code.
|
||||
#
|
||||
sub format_log
|
||||
{
|
||||
my $log = $_[0];
|
||||
|
||||
my $merge;
|
||||
my $commit;
|
||||
my $commits;
|
||||
|
||||
for (@{$log->{lines}}) {
|
||||
if(/^commit (\S+)/) {
|
||||
$commit = { ref => $1 };
|
||||
push @{$commits}, $commit;
|
||||
|
||||
if(
|
||||
$merge &&
|
||||
$merge->{merge_end} eq substr($commit->{ref}, 0, length($merge->{merge_end}))
|
||||
) {
|
||||
undef $merge;
|
||||
}
|
||||
|
||||
if($merge) {
|
||||
$commit->{merge_ref} = $merge->{ref};
|
||||
$commit->{date} = $merge->{date};
|
||||
$commit->{author} = $merge->{author};
|
||||
# add to all commits so it's not lost when we re-arrange
|
||||
$commit->{merge_msg} = $merge->{msg};
|
||||
}
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
if(/^Merge: (\S+)/ && !$merge) {
|
||||
if($commit) {
|
||||
$merge = { merge_end => $1, ref => $commit->{ref} } unless $merge;
|
||||
}
|
||||
next;
|
||||
}
|
||||
|
||||
if(/^Date:\s+(\S.*)/) {
|
||||
$commit->{date} ||= $1 if $commit;
|
||||
$merge->{date} ||= $1 if $merge;
|
||||
next;
|
||||
}
|
||||
|
||||
if(/^Author:\s+(\S.*)/) {
|
||||
$commit->{author} ||= $1 if $commit;
|
||||
$merge->{author} ||= $1 if $merge;
|
||||
next;
|
||||
}
|
||||
|
||||
if($merge) {
|
||||
if(/^ Merge pull request (#\d+) from (\S+)/) {
|
||||
if($config->{github_project}) {
|
||||
push @{$merge->{msg}}, "merge gh#$config->{github_project}$1";
|
||||
}
|
||||
else {
|
||||
push @{$merge->{msg}}, "merge pr $2";
|
||||
}
|
||||
}
|
||||
elsif(/^ Merge branch '([^']+)'( into)?/) {
|
||||
push @{$merge->{msg}}, "merge branch $1" if $2 eq "";
|
||||
}
|
||||
elsif(/^ Merge remote-tracking branch /) {
|
||||
# ignore
|
||||
}
|
||||
elsif(s/^ //) {
|
||||
push @{$commit->{lines}}, $_ unless /^# /;
|
||||
}
|
||||
}
|
||||
elsif($commit) {
|
||||
if(s/^ //) {
|
||||
push @{$commit->{lines}}, $_ unless /^# /;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Note: the individual steps below work on the array @$commits and modify
|
||||
# its content.
|
||||
|
||||
# step 1
|
||||
# - if there are paragraphs starting with '@log@' or '@+log@'
|
||||
# - delete first paragraph (short summary)
|
||||
# - else
|
||||
# - keep only first paragraph
|
||||
# - if there is a paragraph starting with '@-log', delete entire log
|
||||
# - tag commits that have a '@log@' tag so we can delete untagged commits
|
||||
# belonging to the same merge commit later
|
||||
|
||||
my $tagged_merges = {};
|
||||
|
||||
for my $commit (@$commits) {
|
||||
# skip leading empty lines
|
||||
for (@{$commit->{lines}}) {
|
||||
last if !/^\s*$/;
|
||||
shift @{$commit->{lines}};
|
||||
}
|
||||
my $para_cnt = 0;
|
||||
my $delete_all = 0;
|
||||
my $delete_first = 0;
|
||||
for (@{$commit->{lines}}) {
|
||||
$para_cnt++ if $_ eq "";
|
||||
$para_cnt = 0, $delete_first = 1 if /^\@\+log\@/;
|
||||
$delete_all = 1 if /^\@\-log\@/;
|
||||
if(/^\@log\@/) {
|
||||
$para_cnt = 0;
|
||||
$commit->{clear} = 1;
|
||||
$tagged_merges->{$commit->{merge_ref}} = 1 if $commit->{merge_ref} || $log->{was_untagged};
|
||||
}
|
||||
$_ = undef if $para_cnt;
|
||||
}
|
||||
shift @{$commit->{lines}} if $delete_first;
|
||||
$commit->{lines} = [] if $delete_all;
|
||||
}
|
||||
|
||||
# step 2
|
||||
# - clean up tagged commits or commits belonging to tagged merges
|
||||
|
||||
for my $commit (@$commits) {
|
||||
next unless $commit->{clear} || $tagged_merges->{$commit->{merge_ref}};
|
||||
for (@{$commit->{lines}}) {
|
||||
last if /^\@\+?log\@/;
|
||||
$_ = undef;
|
||||
}
|
||||
}
|
||||
|
||||
# step 3
|
||||
# - join lines
|
||||
|
||||
for my $commit (@$commits) {
|
||||
my $lines;
|
||||
my $line;
|
||||
|
||||
for (@{$commit->{lines}}) {
|
||||
next if $_ eq "";
|
||||
if(
|
||||
s/^\s*[+\-][\-\s]*// ||
|
||||
s/^\@\+?log\@// ||
|
||||
$line eq ""
|
||||
) {
|
||||
s/^\s*//;
|
||||
push @$lines, $line if $line ne "";
|
||||
$line = $_;
|
||||
}
|
||||
else {
|
||||
s/^\s*//;
|
||||
$line .= " " if $line ne "";
|
||||
$line .= $_;
|
||||
}
|
||||
}
|
||||
push @$lines, $line if $line ne "";
|
||||
|
||||
$commit->{formatted} = $lines if $lines;
|
||||
}
|
||||
|
||||
# step 4
|
||||
# - fix small glitches
|
||||
|
||||
for my $commit (@$commits) {
|
||||
next unless $commit->{formatted};
|
||||
for (@{$commit->{formatted}}) {
|
||||
s/(fate|bnc|bsc|boo)\s*(#\d+)/\L$1\E$2/ig;
|
||||
}
|
||||
}
|
||||
|
||||
# step 5
|
||||
# - add merge info at the top or bottom (depending on $opt_merge_msg_before)
|
||||
|
||||
my $merge_logged;
|
||||
|
||||
for my $commit ($opt_merge_msg_before ? reverse(@$commits) : @$commits) {
|
||||
next unless $commit->{formatted};
|
||||
|
||||
if($commit->{merge_ref} && !$merge_logged->{$commit->{merge_ref}}) {
|
||||
$merge_logged->{$commit->{merge_ref}} = 1;
|
||||
if($commit->{merge_msg}) {
|
||||
if($opt_merge_msg_before) {
|
||||
unshift @{$commit->{formatted}}, @{$commit->{merge_msg}};
|
||||
}
|
||||
else {
|
||||
push @{$commit->{formatted}}, @{$commit->{merge_msg}};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# step 6
|
||||
# - join commit messages with same author (optionally even with different dates)
|
||||
|
||||
my $commit0;
|
||||
|
||||
for my $commit (@$commits) {
|
||||
next if !$commit->{formatted};
|
||||
$commit0 = $commit, next if !$commit0;
|
||||
|
||||
if(
|
||||
# $commit->{merge_ref} eq $commit0->{merge_ref} &&
|
||||
(
|
||||
$opt_join_author && ($commit->{author} eq $commit0->{author})
|
||||
&& (!$opt_keep_date || $commit->{date} eq $commit0->{date})
|
||||
)
|
||||
|| $opt_format eq 'internal'
|
||||
) {
|
||||
unshift @{$commit0->{formatted}}, @{$commit->{formatted}};
|
||||
delete $commit->{formatted};
|
||||
}
|
||||
else {
|
||||
$commit0 = $commit;
|
||||
}
|
||||
}
|
||||
|
||||
# step 7
|
||||
# - add version tag at the end of the first log entry
|
||||
|
||||
for my $commit (@$commits) {
|
||||
next unless $commit->{formatted};
|
||||
|
||||
if($opt_format eq 'obs') {
|
||||
push @{$commit->{formatted}}, $log->{tags}[0]{version} if defined $log->{tags}[0]{version};
|
||||
}
|
||||
else {
|
||||
# push @{$commit->{formatted}}, tag_to_str($log->{tags}[0]);
|
||||
}
|
||||
|
||||
last;
|
||||
}
|
||||
|
||||
# step 8
|
||||
# - remove identical lines
|
||||
|
||||
for my $commit (@$commits) {
|
||||
next unless $commit->{formatted};
|
||||
my %k;
|
||||
$commit->{formatted} = [ grep { !$k{$_}++ } @{$commit->{formatted}} ]
|
||||
}
|
||||
|
||||
# step 9
|
||||
# - remove shortened lines (that match the beginning of other lines)
|
||||
|
||||
for my $commit (@$commits) {
|
||||
next unless $commit->{formatted};
|
||||
|
||||
# return 1 if some other commit line starts with function arg
|
||||
my $is_substr = sub {
|
||||
my $str = $_[0];
|
||||
$str =~ s/\s*…$//; # github likes to shorten lines with ' …'
|
||||
my $str_len = length $str;
|
||||
for (@{$commit->{formatted}}) {
|
||||
return 1 if $str_len < length($_) && $str eq substr($_, 0, $str_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
$commit->{formatted} = [ grep { ! $is_substr->($_) } @{$commit->{formatted}} ]
|
||||
}
|
||||
|
||||
# step 10
|
||||
# - add line breaks
|
||||
|
||||
for my $commit (@$commits) {
|
||||
next unless $commit->{formatted};
|
||||
for (@{$commit->{formatted}}) {
|
||||
$_ = add_line_breaks $_;
|
||||
}
|
||||
}
|
||||
|
||||
# step 11
|
||||
# - generate final log message
|
||||
#
|
||||
# note: non-(open)suse email addresses are replaced by $opt_default_email
|
||||
|
||||
my $formated_log;
|
||||
|
||||
for my $commit (@$commits) {
|
||||
next unless $commit->{formatted} && @{$commit->{formatted}};
|
||||
|
||||
if($opt_format eq 'obs') {
|
||||
$formated_log .= "-" x $opt_sep_width . "\n";
|
||||
$formated_log .= format_date_obs($commit->{date});
|
||||
}
|
||||
else {
|
||||
$formated_log .= format_date_iso($commit->{date});
|
||||
}
|
||||
if($opt_format eq 'obs') {
|
||||
my $auth = $commit->{author};
|
||||
$auth =~ s/^.*<//;
|
||||
$auth =~ s/>.*$//;
|
||||
# replace non-suse e-mail addresses with a generic one
|
||||
if($auth !~ /\@(suse\.(com|cz|de)|opensuse\.org)$/) {
|
||||
$auth = $opt_default_email;
|
||||
}
|
||||
$formated_log .= " - $auth\n\n";
|
||||
}
|
||||
else {
|
||||
$formated_log .= ":\t" . tag_to_str($log->{tags}[0]) . "\n";
|
||||
}
|
||||
|
||||
for (@{$commit->{formatted}}) {
|
||||
s/^/\t/mg if $opt_format eq 'internal';
|
||||
$formated_log .= "$_\n";
|
||||
}
|
||||
|
||||
$formated_log .= "\n";
|
||||
}
|
||||
|
||||
$log->{formatted} = $formated_log;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# new_text = add_line_breaks(text)
|
||||
#
|
||||
# Add line breaks to text.
|
||||
# - text: some text
|
||||
# - new_text: same text, reformatted
|
||||
#
|
||||
# Lines are formatted to have a maximal length of $opt_width. If this causes
|
||||
# the last line to be shorter than $opt_width_fuzz, it is appended to the
|
||||
# previous line.
|
||||
#
|
||||
sub add_line_breaks
|
||||
{
|
||||
my @words = split /\s+/, @_[0];
|
||||
my $remaining_len = length(join '', @words);
|
||||
|
||||
my $str = shift(@words);
|
||||
my $len = length $str;
|
||||
|
||||
my $next_len;
|
||||
my $word_len;
|
||||
|
||||
for (@words) {
|
||||
$word_len = length;
|
||||
$remaining_len -= $word_len;
|
||||
$next_len = $len + $word_len + 1;
|
||||
if(
|
||||
$next_len >= $opt_width &&
|
||||
$next_len + $remaining_len + 1 >= $opt_width + $opt_width_fuzz
|
||||
) {
|
||||
$str .= "\n $_";
|
||||
$len = $word_len;
|
||||
}
|
||||
else {
|
||||
$str .= " $_";
|
||||
$len += $word_len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return "- " . $str;
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# seconds = raw_date_to_s(git_date)
|
||||
#
|
||||
# Convert git raw date to seconds.
|
||||
# - git_date: raw git format (e.g. "1443184889 +0200")
|
||||
# - seconds: the seconds part (e.g. "1443184889")
|
||||
#
|
||||
sub raw_date_to_s
|
||||
{
|
||||
return (split / /, $_[0])[0];
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# date = format_date_obs(git_date)
|
||||
#
|
||||
# Convert git raw date to obs format.
|
||||
# - git_date: raw git format (e.g. "1443184889 +0200")
|
||||
# - date: obs format ("Fri Sep 25 12:41:29 UTC 2015")
|
||||
#
|
||||
sub format_date_obs
|
||||
{
|
||||
my @d = gmtime(raw_date_to_s($_[0]));
|
||||
|
||||
return
|
||||
qw(Sun Mon Tue Wed Thu Fri Sat)[$d[6]] . " " .
|
||||
qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)[$d[4]] . " " .
|
||||
$d[3] . " " .
|
||||
sprintf("%02d:%02d:%02d", $d[2], $d[1], $d[0]) . " UTC " .
|
||||
(1900 + $d[5]);
|
||||
}
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# date = format_date_iso(git_date)
|
||||
#
|
||||
# Convert git raw date to iso format.
|
||||
# - git_date: raw git format (e.g. "1443184889 +0200")
|
||||
# - date: obs format ("2015-09-25")
|
||||
#
|
||||
sub format_date_iso
|
||||
{
|
||||
my @d = gmtime(raw_date_to_s($_[0]));
|
||||
|
||||
return sprintf("%04d-%02d-%02d", 1900 + $d[5], $d[4] + 1, $d[3]);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
rm -f /var/lib/hardware/LOCK
|
||||
|
||||
/sbin/hwscan --silent --boot --fast --isapnp --pci --block --floppy --mouse
|
||||
|
||||
#
|
||||
# create icons for static drives
|
||||
#
|
||||
if [ -e /etc/hotplug/hotplug.subfs.functions ]; then
|
||||
. /etc/hotplug/hotplug.subfs.functions
|
||||
coldplug_create_subfs
|
||||
fi
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,101 @@
|
|||
#! /bin/sh
|
||||
# Copyright (c) 2002 SuSE GmbH Nuernberg, Germany. All rights reserved.
|
||||
#
|
||||
# Author: Marcus Meissner <meissner@suse.de>
|
||||
#
|
||||
# /etc/init.d/hwscan
|
||||
#
|
||||
# System startup script for boot hw probing and reconfiguration
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: hwscan
|
||||
# Required-Start:
|
||||
# X-UnitedLinux-Should-Start: hotplug kbd
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 5
|
||||
# Default-Stop:
|
||||
# Description: Hardware scan and reconfiguration on boot.
|
||||
### END INIT INFO
|
||||
|
||||
HWBOOTSCAN_BIN=/usr/sbin/hwbootscan
|
||||
test -x $HWBOOTSCAN_BIN || exit 5
|
||||
|
||||
# Shell functions sourced from /etc/rc.status:
|
||||
# rc_check check and set local and overall rc status
|
||||
# rc_status check and set local and overall rc status
|
||||
# rc_status -v ditto but be verbose in local rc status
|
||||
# rc_status -v -r ditto and clear the local rc status
|
||||
# rc_failed set local and overall rc status to failed
|
||||
# rc_reset clear local rc status (overall remains)
|
||||
# rc_exit exit appropriate to overall rc status
|
||||
. /etc/rc.status
|
||||
|
||||
# First reset status of this service
|
||||
rc_reset
|
||||
|
||||
# Return values acc. to LSB for all commands but status:
|
||||
# 0 - success
|
||||
# 1 - misc error
|
||||
# 2 - invalid or excess args
|
||||
# 3 - unimplemented feature (e.g. reload)
|
||||
# 4 - insufficient privilege
|
||||
# 5 - program not installed
|
||||
# 6 - program not configured
|
||||
# 7 - program is not running
|
||||
#
|
||||
# Note that starting an already running service, stopping
|
||||
# or restarting a not-running service as well as the restart
|
||||
# with force-reload (in case signalling is not supported) are
|
||||
# considered a success.
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting hardware scan on boot"
|
||||
rc_splash "YaST"
|
||||
[ -n "$REDIRECT" ] && exec 0<> $REDIRECT 1>&0 2>&0
|
||||
$HWBOOTSCAN_BIN
|
||||
rc_check
|
||||
rc_status -v
|
||||
;;
|
||||
stop)
|
||||
rc_check
|
||||
;;
|
||||
restart)
|
||||
## Stop the service and regardless of whether it was
|
||||
## running or not, start it again.
|
||||
# Remember status and be quiet
|
||||
rc_check
|
||||
;;
|
||||
force-reload)
|
||||
## Signal the daemon to reload its config. Most daemons
|
||||
## do this on signal 1 (SIGHUP).
|
||||
## If it does not support it, restart.
|
||||
# Remember status and be quiet
|
||||
rc_check
|
||||
;;
|
||||
reload)
|
||||
## Like force-reload, but if daemon does not support
|
||||
## signalling, do nothing (!)
|
||||
|
||||
# If it supports signalling:
|
||||
rc_reset
|
||||
;;
|
||||
status)
|
||||
## Check status with checkproc(8), if process is running
|
||||
## checkproc will return with exit status 0.
|
||||
|
||||
# Status has a slightly different for the status command:
|
||||
# 0 - service running
|
||||
# 1 - service dead, but /var/run/ pid file exists
|
||||
# 2 - service dead, but /var/lock/ lock file exists
|
||||
# 3 - service not running
|
||||
|
||||
rc_reset
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|force-reload|reload|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
rc_exit
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Package Information for pkg-config
|
||||
|
||||
prefix=/usr
|
||||
exec_prefix=${prefix}
|
||||
libdir=@LIBDIR@
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: hwinfo
|
||||
Description: Hardware Detection Library
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} @LIBS@
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,625 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
|
||||
struct option options[] = {
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "verbose", 0, NULL, 'v' },
|
||||
{ "version", 0, NULL, 400 },
|
||||
{ "show", 1, NULL, 500 },
|
||||
{ "list", 0, NULL, 501 },
|
||||
{ "cfg", 1, NULL, 502 },
|
||||
{ "avail", 1, NULL, 503 },
|
||||
{ "need", 1, NULL, 504 },
|
||||
{ "new", 0, NULL, 505 },
|
||||
{ "fast", 0, NULL, 506 },
|
||||
{ "silent", 0, NULL, 507 },
|
||||
{ "boot", 0, NULL, 508 },
|
||||
{ "active", 1, NULL, 509 },
|
||||
{ "only", 1, NULL, 510 },
|
||||
{ "sys", 0, NULL, 1000 + hw_sys },
|
||||
{ "cpu", 0, NULL, 1000 + hw_cpu },
|
||||
{ "keyboard", 0, NULL, 1000 + hw_keyboard },
|
||||
{ "braille", 0, NULL, 1000 + hw_braille },
|
||||
{ "mouse", 0, NULL, 1000 + hw_mouse },
|
||||
{ "joystick", 0, NULL, 1000 + hw_joystick },
|
||||
{ "printer", 0, NULL, 1000 + hw_printer },
|
||||
{ "scanner", 0, NULL, 1000 + hw_scanner },
|
||||
{ "chipcard", 0, NULL, 1000 + hw_chipcard },
|
||||
{ "monitor", 0, NULL, 1000 + hw_monitor },
|
||||
{ "tv", 0, NULL, 1000 + hw_tv },
|
||||
{ "gfxcard", 0, NULL, 1000 + hw_display },
|
||||
{ "framebuffer", 0, NULL, 1000 + hw_framebuffer },
|
||||
{ "camera", 0, NULL, 1000 + hw_camera },
|
||||
{ "sound", 0, NULL, 1000 + hw_sound },
|
||||
{ "storage-ctrl", 0, NULL, 1000 + hw_storage_ctrl },
|
||||
{ "storage_ctrl", 0, NULL, 1000 + hw_storage_ctrl },
|
||||
{ "netcard", 0, NULL, 1000 + hw_network_ctrl },
|
||||
{ "network-ctrl", 0, NULL, 1000 + hw_network_ctrl },
|
||||
{ "network_ctrl", 0, NULL, 1000 + hw_network_ctrl },
|
||||
{ "isdn", 0, NULL, 1000 + hw_isdn },
|
||||
{ "modem", 0, NULL, 1000 + hw_modem },
|
||||
{ "network", 0, NULL, 1000 + hw_network },
|
||||
{ "disk", 0, NULL, 1000 + hw_disk },
|
||||
{ "partition", 0, NULL, 1000 + hw_partition },
|
||||
{ "cdrom", 0, NULL, 1000 + hw_cdrom },
|
||||
{ "floppy", 0, NULL, 1000 + hw_floppy },
|
||||
{ "update", 0, NULL, 1000 + hw_manual },
|
||||
{ "usb-ctrl", 0, NULL, 1000 + hw_usb_ctrl },
|
||||
{ "usb_ctrl", 0, NULL, 1000 + hw_usb_ctrl },
|
||||
{ "usb", 0, NULL, 1000 + hw_usb },
|
||||
{ "bios", 0, NULL, 1000 + hw_bios },
|
||||
{ "pci", 0, NULL, 1000 + hw_pci },
|
||||
{ "isapnp", 0, NULL, 1000 + hw_isapnp },
|
||||
{ "bridge", 0, NULL, 1000 + hw_bridge },
|
||||
{ "hub", 0, NULL, 1000 + hw_hub },
|
||||
{ "scsi", 0, NULL, 1000 + hw_scsi },
|
||||
{ "ide", 0, NULL, 1000 + hw_ide },
|
||||
{ "memory", 0, NULL, 1000 + hw_memory },
|
||||
{ "dvb", 0, NULL, 1000 + hw_dvb },
|
||||
{ "pcmcia", 0, NULL, 1000 + hw_pcmcia },
|
||||
{ "pcmcia_ctrl", 0, NULL, 1000 + hw_pcmcia_ctrl },
|
||||
{ "ieee1394", 0, NULL, 1000 + hw_ieee1394 },
|
||||
{ "firewire", 0, NULL, 1000 + hw_ieee1394 },
|
||||
{ "ieee1394_ctrl", 0, NULL, 1000 + hw_ieee1394_ctrl },
|
||||
{ "firewire_ctrl", 0, NULL, 1000 + hw_ieee1394_ctrl },
|
||||
{ "hotplug", 0, NULL, 1000 + hw_hotplug },
|
||||
{ "hotplug_ctrl", 0, NULL, 1000 + hw_hotplug_ctrl },
|
||||
{ "zip", 0, NULL, 1000 + hw_zip },
|
||||
{ "pppoe", 0, NULL, 1000 + hw_pppoe },
|
||||
{ "dsl", 0, NULL, 1000 + hw_dsl },
|
||||
{ "wlan", 0, NULL, 1000 + hw_wlan },
|
||||
{ "block", 0, NULL, 1000 + hw_block },
|
||||
{ "tape", 0, NULL, 1000 + hw_tape },
|
||||
{ "vbe", 0, NULL, 1000 + hw_vbe },
|
||||
{ "bluetooth", 0, NULL, 1000 + hw_bluetooth },
|
||||
{ "all", 0, NULL, 1000 + hw_all },
|
||||
{ }
|
||||
};
|
||||
|
||||
int verbose = 0;
|
||||
hd_hw_item_t scan_item[100] = { };
|
||||
unsigned scan_items = 0;
|
||||
int found_items = 0;
|
||||
|
||||
struct {
|
||||
unsigned show:1;
|
||||
unsigned scan:1;
|
||||
unsigned list:1;
|
||||
unsigned config_cfg:1;
|
||||
unsigned config_avail:1;
|
||||
unsigned config_need:1;
|
||||
unsigned config_active:1;
|
||||
unsigned new:1;
|
||||
unsigned fast:1;
|
||||
unsigned silent:1;
|
||||
unsigned boot:1;
|
||||
str_list_t *only;
|
||||
} opt;
|
||||
|
||||
void help(void);
|
||||
int do_scan(hd_hw_item_t *items);
|
||||
int do_show(char *id);
|
||||
int do_list(hd_hw_item_t *items);
|
||||
int do_config(int type, char *val, char *id);
|
||||
int fast_ok(hd_hw_item_t *items);
|
||||
int has_item(hd_hw_item_t *items, hd_hw_item_t item);
|
||||
int has_hw_class(hd_t *hd, hd_hw_item_t *items);
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifndef LIBHD_TINY
|
||||
|
||||
char *id = NULL;
|
||||
char *config_cfg = NULL;
|
||||
char *config_avail = NULL;
|
||||
char *config_need = NULL;
|
||||
char *config_active = NULL;
|
||||
int i;
|
||||
int ok = 0;
|
||||
FILE *f;
|
||||
|
||||
opterr = 0;
|
||||
|
||||
while((i = getopt_long(argc, argv, "hv", options, NULL)) != -1) {
|
||||
switch(i) {
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 400:
|
||||
printf("%s\n", hd_version());
|
||||
ok = 1;
|
||||
break;
|
||||
|
||||
case 500:
|
||||
opt.show = 1;
|
||||
id = optarg;
|
||||
break;
|
||||
|
||||
case 501:
|
||||
opt.list = 1;
|
||||
break;
|
||||
|
||||
case 502:
|
||||
opt.config_cfg = 1;
|
||||
config_cfg = optarg;
|
||||
break;
|
||||
|
||||
case 503:
|
||||
opt.config_avail = 1;
|
||||
config_avail = optarg;
|
||||
break;
|
||||
|
||||
case 504:
|
||||
opt.config_need = 1;
|
||||
config_need = optarg;
|
||||
break;
|
||||
|
||||
case 505:
|
||||
opt.new = 1;
|
||||
break;
|
||||
|
||||
case 506:
|
||||
opt.fast = 1;
|
||||
break;
|
||||
|
||||
case 507:
|
||||
opt.silent = 1;
|
||||
break;
|
||||
|
||||
case 508:
|
||||
opt.boot = 1;
|
||||
break;
|
||||
|
||||
case 509:
|
||||
opt.config_active = 1;
|
||||
config_active = optarg;
|
||||
break;
|
||||
|
||||
case 510:
|
||||
if(*optarg) add_str_list(&opt.only, optarg);
|
||||
break;
|
||||
|
||||
case 1000 ... 1100:
|
||||
opt.scan = 1;
|
||||
if(scan_items + 1 < sizeof scan_item / sizeof *scan_item) {
|
||||
scan_item[scan_items++] = i - 1000;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
help();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
scan_item[scan_items] = 0;
|
||||
|
||||
if(opt.scan && !opt.list) {
|
||||
if(argv[optind] || !scan_items) return help(), 1;
|
||||
rc = do_scan(scan_item);
|
||||
if(found_items) {
|
||||
unlink(HARDWARE_DIR "/.update"); /* the old file */
|
||||
unlink(HARDWARE_UNIQUE_KEYS "/.update"); /* so we trigger a rescan */
|
||||
if((f = fopen(HARDWARE_UNIQUE_KEYS "/.update", "a"))) fclose(f);
|
||||
}
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
if(opt.show) {
|
||||
do_show(id);
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
if(opt.list) {
|
||||
do_list(scan_item);
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
if(opt.config_cfg) {
|
||||
if(!argv[optind]) return help(), 1;
|
||||
do_config(1, config_cfg, argv[optind]);
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
if(opt.config_avail) {
|
||||
if(!argv[optind]) return help(), 1;
|
||||
do_config(2, config_avail, argv[optind]);
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
if(opt.config_need) {
|
||||
if(!argv[optind]) return help(), 1;
|
||||
do_config(3, config_need, argv[optind]);
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
if(opt.config_active) {
|
||||
if(!argv[optind]) return help(), 1;
|
||||
do_config(4, config_active, argv[optind]);
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
if(!ok) help();
|
||||
|
||||
#endif /* !defined(LIBHD_TINY) */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void help()
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: hwscan [options]\n"
|
||||
"Show information about currently known hardware.\n"
|
||||
" --list show list of known hardware\n"
|
||||
" --version show libhd version\n"
|
||||
" --silent don't show hardware config changes\n"
|
||||
" --boot run only if we haven't been disabled via 'hwprobe=-scan'\n"
|
||||
" --cfg=state id change 'configured' status; id is one of the\n"
|
||||
" ids from 'hwscan --list'\n"
|
||||
" state is one of new, no, yes\n"
|
||||
" --avail=state id change 'available' status\n"
|
||||
" --need=state id change 'needed' status\n"
|
||||
" --active=state id change 'active' status\n"
|
||||
" --hw_item probe for hw_item and update status info\n"
|
||||
" hw_item is one of:\n"
|
||||
" all, bios, block, bluetooth, braille, bridge, camera, cdrom, chipcard, cpu,\n"
|
||||
" disk, dsl, dvb, floppy, framebuffer, gfxcard, hub, ide, isapnp, isdn,\n"
|
||||
" joystick, keyboard, memory, modem, monitor, mouse, netcard, network,\n"
|
||||
" partition, pci, pcmcia, pcmcia-ctrl, pppoe, printer, scanner, scsi, smp,\n"
|
||||
" sound, storage-ctrl, sys, tape, tv, usb, usb-ctrl, vbe, wlan, zip\n"
|
||||
);
|
||||
}
|
||||
|
||||
#ifndef LIBHD_TINY
|
||||
|
||||
int do_scan(hd_hw_item_t *items)
|
||||
{
|
||||
int run_config = 0;
|
||||
hd_status_t status = { };
|
||||
hd_data_t *hd_data;
|
||||
hd_t *hd, *hd1;
|
||||
int err = 0;
|
||||
|
||||
if(opt.fast) opt.fast = fast_ok(items);
|
||||
|
||||
hd_data = calloc(1, sizeof *hd_data);
|
||||
|
||||
if(opt.boot) {
|
||||
/* look if we have been disabled */
|
||||
hd_clear_probe_feature(hd_data, pr_all);
|
||||
hd_scan(hd_data);
|
||||
hd_set_probe_feature(hd_data, pr_scan);
|
||||
if(!hd_probe_feature(hd_data, pr_scan)) {
|
||||
hd_free_hd_data(hd_data);
|
||||
free(hd_data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
hd_data->only = opt.only;
|
||||
opt.only = NULL;
|
||||
|
||||
hd_data->flags.list_all = 1;
|
||||
hd_data->flags.fast = opt.fast;
|
||||
|
||||
hd = hd_list2(hd_data, items, 1);
|
||||
|
||||
if(hd) found_items = 1;
|
||||
|
||||
for(hd1 = hd; hd1; hd1 = hd1->next) {
|
||||
err = hd_write_config(hd_data, hd1);
|
||||
if(verbose >= 2) {
|
||||
printf(
|
||||
"write=%d %s: (cfg=%s, avail=%s, need=%s, active=%s",
|
||||
err,
|
||||
hd1->unique_id,
|
||||
hd_status_value_name(hd1->status.configured),
|
||||
hd_status_value_name(hd1->status.available),
|
||||
hd_status_value_name(hd1->status.needed),
|
||||
hd_status_value_name(hd1->status.active)
|
||||
);
|
||||
if(hd1->unix_dev_name) {
|
||||
printf(", dev=%s", hd1->unix_dev_name);
|
||||
}
|
||||
printf(
|
||||
") %s\n",
|
||||
hd1->model
|
||||
);
|
||||
|
||||
}
|
||||
if(err) break;
|
||||
}
|
||||
|
||||
if(err) {
|
||||
fprintf(stderr,
|
||||
"Error writing configuration for %s (%s)\n",
|
||||
hd1->unique_id,
|
||||
hd1->model
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hd = hd_free_hd_list(hd);
|
||||
|
||||
if(opt.new) {
|
||||
status.configured = status_new;
|
||||
}
|
||||
else {
|
||||
status.reconfig = status_yes;
|
||||
}
|
||||
|
||||
hd = hd_list_with_status2(hd_data, items, status);
|
||||
if(hd) run_config = 1;
|
||||
|
||||
if(verbose) {
|
||||
for(hd1 = hd; hd1; hd1 = hd1->next) {
|
||||
printf(
|
||||
"%s: (cfg=%s, avail=%s, need=%s, active=%s",
|
||||
hd1->unique_id,
|
||||
hd_status_value_name(hd1->status.configured),
|
||||
hd_status_value_name(hd1->status.available),
|
||||
hd_status_value_name(hd1->status.needed),
|
||||
hd_status_value_name(hd1->status.active)
|
||||
);
|
||||
if(hd1->unix_dev_name) {
|
||||
printf(", dev=%s", hd1->unix_dev_name);
|
||||
}
|
||||
printf(
|
||||
") %s\n",
|
||||
hd1->model
|
||||
);
|
||||
}
|
||||
}
|
||||
else if(!opt.silent) {
|
||||
for(hd1 = hd; hd1; hd1 = hd1->next) printf("%s\n", hd1->unique_id);
|
||||
}
|
||||
|
||||
hd = hd_free_hd_list(hd);
|
||||
|
||||
hd_free_hd_data(hd_data);
|
||||
free(hd_data);
|
||||
|
||||
return run_config ^ 1;
|
||||
}
|
||||
|
||||
|
||||
int do_show(char *id)
|
||||
{
|
||||
hd_data_t *hd_data;
|
||||
hd_t *hd;
|
||||
|
||||
hd_data = calloc(1, sizeof *hd_data);
|
||||
|
||||
if ( id[0] == '/' ){
|
||||
int nr=0;
|
||||
char *_id = 0;
|
||||
hd_t *hd_manual;
|
||||
|
||||
hd_manual = hd_list(hd_data, hw_manual, 1, NULL);
|
||||
for(hd = hd_manual; hd; hd = hd->next) {
|
||||
if(hd->status.available != status_yes) continue;
|
||||
if(!search_str_list(hd->unix_dev_names, id)) continue;
|
||||
_id = hd->unique_id;
|
||||
nr++;
|
||||
}
|
||||
|
||||
if ( nr == 1 ) /* > 1 means our database is not okay */
|
||||
hd = hd_read_config(hd_data, _id);
|
||||
}else
|
||||
hd = hd_read_config(hd_data, id);
|
||||
|
||||
if(hd) {
|
||||
hd_data->debug = -1;
|
||||
hd_dump_entry(hd_data, hd, stdout);
|
||||
hd = hd_free_hd_list(hd);
|
||||
}
|
||||
else {
|
||||
printf("no such hardware item: %s\n", id);
|
||||
}
|
||||
|
||||
hd_free_hd_data(hd_data);
|
||||
free(hd_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int do_list(hd_hw_item_t *items)
|
||||
{
|
||||
hd_data_t *hd_data;
|
||||
hd_t *hd, *hd_manual;
|
||||
char *s;
|
||||
char status[64];
|
||||
int i;
|
||||
|
||||
hd_data = calloc(1, sizeof *hd_data);
|
||||
|
||||
hd_manual = hd_list(hd_data, hw_manual, 1, NULL);
|
||||
|
||||
for(hd = hd_manual; hd; hd = hd->next) {
|
||||
if(opt.scan && ! has_hw_class(hd, items)) continue;
|
||||
|
||||
strcpy(status, "(");
|
||||
|
||||
i = 0;
|
||||
if(hd->status.configured && (s = hd_status_value_name(hd->status.configured))) {
|
||||
sprintf(status + strlen(status), "%scfg=%s", i ? ", " : "", s);
|
||||
i++;
|
||||
}
|
||||
|
||||
if(hd->status.available && (s = hd_status_value_name(hd->status.available))) {
|
||||
sprintf(status + strlen(status), "%savail=%s", i ? ", " : "", s);
|
||||
i++;
|
||||
}
|
||||
|
||||
if(hd->status.needed && (s = hd_status_value_name(hd->status.needed))) {
|
||||
sprintf(status + strlen(status), "%sneed=%s", i ? ", " : "", s);
|
||||
i++;
|
||||
}
|
||||
|
||||
if(hd->status.active && (s = hd_status_value_name(hd->status.active))) {
|
||||
sprintf(status + strlen(status), "%sactive=%s", i ? ", " : "", s);
|
||||
i++;
|
||||
}
|
||||
|
||||
strcat(status, ")");
|
||||
|
||||
s = hd_hw_item_name(hd->hw_class);
|
||||
if(!s) s = "???";
|
||||
|
||||
printf("%s: %-32s %-16s %s\n", hd->unique_id, status, s, hd->model);
|
||||
if(hd->config_string) {
|
||||
printf(" configured as: \"%s\"\n", hd->config_string);
|
||||
}
|
||||
}
|
||||
|
||||
hd_free_hd_list(hd_manual);
|
||||
|
||||
hd_free_hd_data(hd_data);
|
||||
free(hd_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int do_config(int type, char *val, char *id)
|
||||
{
|
||||
hd_data_t *hd_data;
|
||||
hd_t *hd;
|
||||
hd_status_value_t status = 0;
|
||||
int i;
|
||||
char *s;
|
||||
|
||||
hd_data = calloc(1, sizeof *hd_data);
|
||||
|
||||
if ( id[0] == '/' ){
|
||||
int nr=0;
|
||||
char *_id = 0;
|
||||
hd_t *hd_manual;
|
||||
|
||||
hd_manual = hd_list(hd_data, hw_manual, 1, NULL);
|
||||
for(hd = hd_manual; hd; hd = hd->next) {
|
||||
if(hd->status.available != status_yes) continue;
|
||||
if(!search_str_list(hd->unix_dev_names, id)) continue;
|
||||
_id = hd->unique_id;
|
||||
nr++;
|
||||
}
|
||||
if ( nr == 1 )
|
||||
hd = hd_read_config(hd_data, _id);
|
||||
}else
|
||||
hd = hd_read_config(hd_data, id);
|
||||
|
||||
if(hd) {
|
||||
for(i = 1; i < 8; i++) {
|
||||
s = hd_status_value_name(i);
|
||||
if(s && !strcmp(val, s)) {
|
||||
status = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!status) {
|
||||
printf("invalid status: %s\n", val);
|
||||
}
|
||||
else {
|
||||
switch(type) {
|
||||
case 1:
|
||||
hd->status.configured = status;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
hd->status.available = status;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
hd->status.needed = status;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
hd->status.active = status;
|
||||
break;
|
||||
}
|
||||
hd_write_config(hd_data, hd);
|
||||
}
|
||||
hd = hd_free_hd_list(hd);
|
||||
}
|
||||
else {
|
||||
printf("no such hardware item: %s\n", id);
|
||||
}
|
||||
|
||||
hd_free_hd_data(hd_data);
|
||||
free(hd_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check whether a 'fast' scan would suffice to re-check the presence
|
||||
* of all known hardware.
|
||||
*/
|
||||
int fast_ok(hd_hw_item_t *items)
|
||||
{
|
||||
hd_data_t *hd_data;
|
||||
hd_t *hd, *hd1;
|
||||
int ok = 1;
|
||||
|
||||
if(!has_item(items, hw_mouse) && !has_item(items, hw_storage_ctrl)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
hd_data = calloc(1, sizeof *hd_data);
|
||||
|
||||
hd_data->flags.list_all = 1;
|
||||
|
||||
hd = hd_list(hd_data, hw_manual, 1, NULL);
|
||||
|
||||
for(hd1 = hd; hd1; hd1 = hd1->next) {
|
||||
/* serial mice */
|
||||
if(hd1->hw_class == hw_mouse && hd1->bus.id == bus_serial) {
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
/* parallel zip */
|
||||
if(hd1->hw_class == hw_storage_ctrl && hd1->bus.id == bus_parallel) {
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hd_free_hd_data(hd_data);
|
||||
free(hd_data);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
/* check if item is in items */
|
||||
int has_item(hd_hw_item_t *items, hd_hw_item_t item)
|
||||
{
|
||||
while(*items) if(*items++ == item) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* check if one of items is in hw_class */
|
||||
int has_hw_class(hd_t *hd, hd_hw_item_t *items)
|
||||
{
|
||||
while(*items) if(hd_is_hw_class(hd, *items++)) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* !defined(LIBHD_TINY) */
|
|
@ -0,0 +1,257 @@
|
|||
|
||||
/* hwscan front end
|
||||
Copyright 2004 by SUSE (<adrian@suse.de>) */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "init_message.h"
|
||||
|
||||
#define TIMEOUT 2
|
||||
#define LONG_TIMEOUT 0
|
||||
#define BUFFERS 1024
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
int ret, i;
|
||||
key_t key = KEY;
|
||||
int msgid;
|
||||
int mode = 0;
|
||||
int dev_nr = 0;
|
||||
int lines = 0;
|
||||
int block, usb, firewire, pci;
|
||||
int dev_last_state[BUFFERS];
|
||||
int dev_counter[BUFFERS];
|
||||
char * command_device[NR_COMMANDS][BUFFERS];
|
||||
time_t command_device_last[NR_COMMANDS][BUFFERS];
|
||||
time_t last;
|
||||
char **commands;
|
||||
char **devices;
|
||||
char buffer[32];
|
||||
message m;
|
||||
|
||||
// are we running already, maybe ?
|
||||
{
|
||||
do {
|
||||
ssize_t r;
|
||||
char b[1024];
|
||||
char link[1024];
|
||||
int fd = open( PID_FILE, O_RDONLY );
|
||||
if ( fd >= 0 && (r=read(fd,b,1023)) > 0 ){
|
||||
close(fd);
|
||||
b[r]='\0';
|
||||
snprintf(link, 1023, "/proc/%s/exe", b);
|
||||
if ( (r=readlink( link, b, 1023 )) > 0 ){
|
||||
b[r]='\0';
|
||||
if ( r<8 )
|
||||
unlink(PID_FILE);
|
||||
else if ( strcmp("/hwscand", b+strlen(b)-8) )
|
||||
unlink(PID_FILE);
|
||||
else
|
||||
exit(1);
|
||||
}else
|
||||
unlink(PID_FILE);
|
||||
}else if ( fd >= 0 )
|
||||
unlink(PID_FILE);
|
||||
} while ( 0 > (ret = open( PID_FILE, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR ) ) );
|
||||
sprintf(buffer, "%d", getpid());
|
||||
if ( ret < 0 || write(ret,buffer,strlen(buffer)) <= 0 ){
|
||||
perror("hwscand: unable to write pid file "PID_FILE);
|
||||
exit(1);
|
||||
}
|
||||
close(ret);
|
||||
}
|
||||
|
||||
// initialize ...
|
||||
for ( i=0; i<NR_COMMANDS; i++ ){
|
||||
command_device[i][0] = 0;
|
||||
command_device_last[i][0] = 1;
|
||||
}
|
||||
|
||||
last=block=usb=firewire=pci=0;
|
||||
commands = (char**) malloc( BUFFERS * sizeof(char*) );
|
||||
devices = (char**) malloc( BUFFERS * sizeof(char*) );
|
||||
|
||||
msgid = msgget(key, IPC_CREAT | 0600);
|
||||
if (msgid < 0) {
|
||||
perror("msgget");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if ( last || dev_nr )
|
||||
mode = IPC_NOWAIT;
|
||||
else
|
||||
mode = 0;
|
||||
|
||||
if( msgrcv(msgid, &m, MESSAGE_BUFFER, 1, mode) >= 0 ){
|
||||
char *p = m.mtext;
|
||||
|
||||
if ( p == 0 ){
|
||||
fprintf( stderr, "hwscand: error, zero sized message\n" );
|
||||
}else{
|
||||
if ( p[0] == 'S' && strlen(p) > 1 ){
|
||||
// scan calls
|
||||
char z[2];
|
||||
int c;
|
||||
z[0] = *(p+1);
|
||||
z[1] = '\0';
|
||||
c = atoi(z);
|
||||
if ( c < NR_COMMANDS ){
|
||||
if ( ! command_with_device[c] ){
|
||||
last = time(0L);
|
||||
if ( LONG_TIMEOUT+command_device_last[c][0] < time(0L) )
|
||||
command_device_last[c][0] = 0;
|
||||
}else
|
||||
for ( i=0; i<BUFFERS; i++ ){
|
||||
if ( !command_device[c][i] ){
|
||||
last = time(0L);
|
||||
command_device[c][i] = strdup(p+2);
|
||||
command_device[c][i+1] = 0;
|
||||
command_device_last[c][i] = 0;
|
||||
break;
|
||||
}else if ( !strcmp(command_device[c][i], p+2) ){
|
||||
last = time(0L);
|
||||
if ( LONG_TIMEOUT+command_device_last[c][i] < time(0L) )
|
||||
command_device_last[c][i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( p[0] == 'C' && lines < BUFFERS ){
|
||||
last = time(0L);
|
||||
// config calls
|
||||
commands[lines] = strdup(p+1);
|
||||
lines++;
|
||||
}
|
||||
if ( p[0] == 'A' && dev_nr < BUFFERS ){
|
||||
// add scan devices
|
||||
devices[dev_nr] = strdup(p+1);
|
||||
dev_last_state[dev_nr] = 0;
|
||||
dev_counter[dev_nr] = 0;
|
||||
dev_nr++;
|
||||
}
|
||||
if ( p[0] == 'R' && dev_nr < BUFFERS ){
|
||||
for ( i=0; i<dev_nr; i++ ){
|
||||
if ( !strcmp(p+1, devices[i]) ){
|
||||
int j;
|
||||
free(devices[i]);
|
||||
for ( j=i; j+1<dev_nr; j++ ){
|
||||
devices[j] = devices[j+1];
|
||||
dev_last_state[j] = dev_last_state[j+1];
|
||||
dev_counter[j] = dev_counter[j+1];
|
||||
}
|
||||
dev_nr--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
printf("CALL RECEIVED %s\n", p);
|
||||
#endif
|
||||
}else{
|
||||
// we do this only in scanning mode ...
|
||||
|
||||
sleep(1);
|
||||
for ( i=0; i<dev_nr; i++ ){
|
||||
if (dev_counter[i]<0) continue;
|
||||
dev_counter[i]++;
|
||||
if ( dev_counter[i] > 5 ){
|
||||
int fd;
|
||||
char buf[MESSAGE_BUFFER];
|
||||
dev_counter[i] = 0;
|
||||
fd = open( devices[i], O_RDONLY );
|
||||
strcpy( buf, "/sbin/hwscan --fast --partition --only=");
|
||||
strcat( buf, devices[i] );
|
||||
if ( fd < 0 ){
|
||||
if ( dev_last_state[i] )
|
||||
system(buf);
|
||||
dev_last_state[i] = 0;
|
||||
}else{
|
||||
if ( dev_last_state[i] == 0)
|
||||
system(buf);
|
||||
dev_last_state[i] = 1;
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( last && (last+TIMEOUT <= time(0L)) ){
|
||||
char buf[MESSAGE_BUFFER * NR_COMMANDS];
|
||||
int run_really = 0;
|
||||
|
||||
last=0;
|
||||
strcpy( buf, "/sbin/hwscan --fast --boot --silent" );
|
||||
for ( i=0; i<NR_COMMANDS; i++ ){
|
||||
if ( command_with_device[i] == 0 &&
|
||||
command_device_last[i][0] == 0 ){
|
||||
command_device_last[i][0] = time(0L);
|
||||
strcat( buf, " --");
|
||||
strcat( buf, command_args[i] );
|
||||
run_really = 1;
|
||||
} else {
|
||||
int j;
|
||||
int commappended = 0;
|
||||
|
||||
for ( j=0; j<BUFFERS; j++ ){
|
||||
if ( !command_device[i][j] )
|
||||
break;
|
||||
if ( command_device_last[i][j] == 0 ){
|
||||
if (!commappended) {
|
||||
strcat( buf, " --");
|
||||
strcat( buf, command_args[i] );
|
||||
commappended = 1;
|
||||
}
|
||||
strcat( buf, " --only=" );
|
||||
strcat( buf, command_device[i][j] );
|
||||
command_device_last[i][j] = time(0L);
|
||||
run_really = 1;
|
||||
if (strlen(buf) > sizeof(buf) - MESSAGE_BUFFER)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strlen(buf) > sizeof(buf) - MESSAGE_BUFFER) {
|
||||
last = time(0L); /* call me again */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( run_really ){
|
||||
#if DEBUG
|
||||
printf("RUN %s\n", buf);
|
||||
#endif
|
||||
system(buf);
|
||||
#if DEBUG
|
||||
printf("RUN quit %s\n", buf);
|
||||
#endif
|
||||
}
|
||||
if ( lines ){
|
||||
for (i=0; i<lines; i++){
|
||||
#if DEBUG
|
||||
printf("CALL DIRECT %s\n", commands[i]);
|
||||
#endif
|
||||
system(commands[i]);
|
||||
#if DEBUG
|
||||
printf("CALL quit %s\n", commands[i]);
|
||||
#endif
|
||||
free(commands[i]);
|
||||
}
|
||||
lines=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
|
||||
/* hwscan front end
|
||||
Copyright 2004 by SUSE (<adrian@suse.de>) */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "init_message.h"
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
int ret;
|
||||
unsigned short i;
|
||||
key_t key = KEY;
|
||||
int msgid;
|
||||
message m;
|
||||
char *device = argv[2];
|
||||
|
||||
if ( argc < 2 ){
|
||||
fprintf( stderr, "help: hwscanqueue hwscan-commands\n" );
|
||||
fprintf( stderr, "help: commands:\n" );
|
||||
for ( i=0; i<NR_COMMANDS; i++ ){
|
||||
fprintf( stderr, " --%s", command_args[i] );
|
||||
if ( command_with_device[i] )
|
||||
fprintf( stderr, " device" );
|
||||
fprintf( stderr, "\n");
|
||||
}
|
||||
fprintf( stderr, " --avail=yes/no id\n" );
|
||||
fprintf( stderr, " --scan=device\n" );
|
||||
fprintf( stderr, " --stop=device\n" );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( !strncmp("--cfg=", argv[1], 6) && argc>2 )
|
||||
snprintf( m.mtext, MESSAGE_BUFFER, "C/sbin/hwscan %s %s", argv[1], argv[2] );
|
||||
else if ( !strncmp("--avail=", argv[1], 8) && argc>2 )
|
||||
snprintf( m.mtext, MESSAGE_BUFFER, "C/sbin/hwscan %s %s", argv[1], argv[2] );
|
||||
else if ( !strncmp("--scan=", argv[1], 7) )
|
||||
snprintf( m.mtext, MESSAGE_BUFFER, "A%s", argv[1]+7 );
|
||||
else if ( !strncmp("--stop=", argv[1], 7) )
|
||||
snprintf( m.mtext, MESSAGE_BUFFER, "R%s", argv[1]+7 );
|
||||
else if ( !strncmp("--", argv[1], 2) ){
|
||||
for ( i=0; i<NR_COMMANDS; i++ ){
|
||||
if ( !strcmp(argv[1]+2,command_args[i]) ){
|
||||
#if DEBUG
|
||||
printf("COMMAND %s\n", command_args[i] );
|
||||
#endif
|
||||
snprintf( m.mtext, MESSAGE_BUFFER, "S%d", i );
|
||||
if (command_with_device[i]){
|
||||
if ( !device ){
|
||||
fprintf(stderr, "need a device for this command\n");
|
||||
exit(1);
|
||||
}
|
||||
strncat( m.mtext, device, MESSAGE_BUFFER-3 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( i>=NR_COMMANDS ){
|
||||
fprintf(stderr, "unknown command\n");
|
||||
exit(1);
|
||||
}
|
||||
}else
|
||||
exit(1);
|
||||
|
||||
if ( (msgid = msgget(key, IPC_CREAT | 0600)) < 0 ){
|
||||
perror("unable to init.");
|
||||
exit(1);
|
||||
}
|
||||
m.mtype = 1;
|
||||
ret = msgsnd( msgid, &m, MESSAGE_BUFFER, IPC_NOWAIT);
|
||||
#if DEBUG
|
||||
printf("SEND %s, return %d\n", m.mtext, ret );
|
||||
#endif
|
||||
|
||||
if ( ret < 0 )
|
||||
perror("message send failed");
|
||||
else{
|
||||
// success ... start hwscand, if it is not yet running
|
||||
ssize_t r;
|
||||
char buffer[1024];
|
||||
char link[1024];
|
||||
int fd = open( PID_FILE, O_RDONLY );
|
||||
if ( fd >= 0 && (r=read(fd,buffer,1023)) > 0 ){
|
||||
close(fd);
|
||||
buffer[r]='\0';
|
||||
snprintf(link, 1023, "/proc/%s/exe", buffer);
|
||||
if ( (r=readlink( link, buffer, 1023 )) > 0 ){
|
||||
buffer[r]='\0';
|
||||
if ( r<8 )
|
||||
fd=-1;
|
||||
else if ( strcmp("/hwscand", buffer+strlen(buffer)-8) )
|
||||
fd=-1;
|
||||
}else
|
||||
fd=-1;
|
||||
}else
|
||||
fd=-1;
|
||||
|
||||
if ( fd < 0 ){
|
||||
pid_t pid;
|
||||
signal(SIGCHLD,SIG_IGN);
|
||||
pid=fork();
|
||||
if (pid==0){
|
||||
/* Change directory to allow clean shut-down */
|
||||
chdir("/");
|
||||
/* Close std fds */
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
/* Start hwscand */
|
||||
execve("/sbin/hwscand", 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#define MESSAGE_BUFFER 1024
|
||||
#define KEY 8024;
|
||||
#define PID_FILE "/var/run/hwscand.pid"
|
||||
|
||||
// WARNING NEEDS TO BE <= 9
|
||||
#define NR_COMMANDS 7
|
||||
// WARNING NEEDS TO BE <= 9
|
||||
static const char *command_args[] = { "block", "partition", "usb", "firewire", "pci", "pcmcia", "bluetooth" };
|
||||
static const int command_with_device[] = { 1, 1, 0, 0, 0, 0, 0 };
|
||||
|
||||
typedef struct msgbuf {
|
||||
long mtype;
|
||||
char mtext[MESSAGE_BUFFER+1];
|
||||
} message;
|
||||
|
||||
#define DEBUG 0
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
#! /usr/bin/perl
|
||||
|
||||
sub addr2line;
|
||||
|
||||
$list = shift;
|
||||
$bin = shift;
|
||||
$ofs = shift;
|
||||
|
||||
die "usage: mci data_file binary\n" unless -f($list);
|
||||
|
||||
open F, $list;
|
||||
|
||||
while(<F>) {
|
||||
if(/^;\s*(.+?)\s*$/) {
|
||||
@i = split ' ', $1;
|
||||
$i[0] = sprintf "%-24s", $i[0];
|
||||
$i[1] = addr2line $i[1];
|
||||
print "; ", join("\t", @i), "\n";
|
||||
next
|
||||
}
|
||||
@i = split;
|
||||
|
||||
die "oops, format error" if @i > 3;
|
||||
|
||||
if(@i == 1) {
|
||||
if($i[0] =~ /^>(\S+)/) {
|
||||
unshift @funcs, $1;
|
||||
}
|
||||
elsif($i[0] =~ /<(\S+)/) {
|
||||
if($funcs[0] eq $1) {
|
||||
shift @funcs
|
||||
}
|
||||
else {
|
||||
die "oops, strange data (line $.)\n"
|
||||
}
|
||||
}
|
||||
else {
|
||||
die "oops, format error"
|
||||
}
|
||||
}
|
||||
else {
|
||||
$func = $i[0];
|
||||
$addr = $i[1];
|
||||
$size = undef;
|
||||
$size = @i == 2 ? undef : $i[2];
|
||||
|
||||
if(defined $size) {
|
||||
if(exists $mem{$addr}) {
|
||||
$x = addr2line $func;
|
||||
$y = addr2line ${$mem{$addr}}[1];
|
||||
print "malloc oops (line $.): mem $addr; old: $y, size ${$mem{$addr}}[0]; new: $x, size $size\n";
|
||||
}
|
||||
$mem{$addr} = [ $size, $func, @funcs ];
|
||||
delete $lfree{$addr};
|
||||
}
|
||||
else {
|
||||
if(!exists $mem{$addr}) {
|
||||
$xx = "";
|
||||
$first = 1;
|
||||
for $f ($func, @funcs) {
|
||||
$xx .= "<-" unless $first;
|
||||
$first = 0;
|
||||
$xx .= addr2line $f;
|
||||
}
|
||||
print "free oops (line $.): $addr ($xx) [last free: line $lfree{$addr}]\n";
|
||||
}
|
||||
delete $mem{$addr};
|
||||
$lfree{$addr} .= " $.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (sort keys %mem) {
|
||||
$total += oct(${$mem{$_}}[0]);
|
||||
$cnt++;
|
||||
|
||||
# $x = `addr2line -s -e $bin ${$mem{$_}}[1]`;
|
||||
# chomp $x;
|
||||
# $x = $x =~ /\?{2}/ ? undef : "$x ";
|
||||
$x = addr2line ${$mem{$_}}[1];
|
||||
|
||||
print "$_\t${$mem{$_}}[0]\t";
|
||||
$first = 1;
|
||||
for $f (@{$mem{$_}}[1..$#{$mem{$_}}]) {
|
||||
print "<-" unless $first;
|
||||
$first = 0;
|
||||
print addr2line $f;
|
||||
}
|
||||
print "\n"
|
||||
}
|
||||
|
||||
printf "total: %u bytes in %u blocks\n", $total, $cnt;
|
||||
|
||||
|
||||
sub addr2line
|
||||
{
|
||||
my ($x, $y);
|
||||
|
||||
return $_[0] unless $bin;
|
||||
|
||||
$y = sprintf "0x%x", oct($_[0]) + $ofs;
|
||||
|
||||
return $addr_cache{$y} if exists $addr_cache{$y};
|
||||
|
||||
$x = `addr2line -s -e $bin $y`;
|
||||
chomp $x;
|
||||
$x = $x =~ /\?{2}/ ? $_[0] : $x;
|
||||
|
||||
$addr_cache{$y} = $x;
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# Links to external technical documentaion
|
||||
|
||||
## System Management BIOS (SMBIOS)
|
||||
|
||||
https://www.dmtf.org/standards/smbios
|
||||
|
||||
|
||||
## VESA BIOS Extensions (VBE)
|
||||
|
||||
http://www.petesqbsite.com/sections/tutorials/tuts/vbe3.pdf
|
||||
|
||||
|
||||
## PCI specification
|
||||
|
||||
https://pcisig.com/specifications
|
||||
|
||||
### device ids
|
||||
|
||||
- http://pci-ids.ucw.cz
|
||||
|
||||
|
||||
## SDIO specification
|
||||
|
||||
https://www.sdcard.org/developers/overview/sdio/
|
||||
|
||||
### device ids
|
||||
|
||||
- https://github.com/systemd/systemd/blob/master/hwdb/sdio.ids
|
||||
- https://wikidevi.com/wiki/Talk:Linux_Wi-Fi_device_entries
|
||||
|
||||
|
||||
## USB specification
|
||||
|
||||
http://www.usb.org/developers/docs/
|
||||
|
||||
### device ids
|
||||
|
||||
- http://www.linux-usb.org/usb.ids
|
||||
|
||||
|
||||
## SCSI specification
|
||||
|
||||
### SCSI commands
|
||||
|
||||
Google for 'SCSI Primary Commands 5 (SPC-5)' (or choose another version).
|
||||
The latest draft is usually freely available but not directly downloadable.
|
|
@ -0,0 +1,2 @@
|
|||
.lib
|
||||
*.so*
|
|
@ -0,0 +1,3 @@
|
|||
.lib
|
||||
libhd.a
|
||||
libhd.so*
|
|
@ -0,0 +1,32 @@
|
|||
TOPDIR = ..
|
||||
SUBDIRS = hd isdn ids
|
||||
TARGETS = touch $(LIBHD) $(LIBHD_SO)
|
||||
CLEANFILES = $(LIBHD) $(LIBHD_D) $(LIBHD_SO) *.so *.so.* *.a
|
||||
|
||||
.PHONY: touch
|
||||
|
||||
include $(TOPDIR)/Makefile.common
|
||||
|
||||
#ifeq "$(findstring $(ARCH), i386 alpha)" ""
|
||||
#SUBDIRS := $(filter-out pnpdump, $(SUBDIRS))
|
||||
#endif
|
||||
|
||||
$(LIBHD): $(OBJS)
|
||||
ar r $@ $?
|
||||
@rm -f $(LIBHD_D)
|
||||
|
||||
ifdef SHARED_FLAGS
|
||||
$(LIBHD_SO): $(LIBHD)
|
||||
$(CC) -shared $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -Wl,--whole-archive $(LIBHD) -Wl,--no-whole-archive \
|
||||
-Wl,-soname=$(LIBHD_SONAME) \
|
||||
-o $(LIBHD_SO) $(SO_LIBS)
|
||||
ln -snf $(LIBHD_NAME) $(LIBHD_SONAME)
|
||||
ln -snf $(LIBHD_SONAME) $(LIBHD_BASE).so
|
||||
else
|
||||
$(LIBHD_SO):
|
||||
endif
|
||||
|
||||
subdirs: touch
|
||||
|
||||
touch:
|
||||
@touch -r $(LIBHD) $(LIBHD_D) 2>/dev/null || true
|
|
@ -0,0 +1,2 @@
|
|||
.depend
|
||||
version.h
|
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
.depend
|
||||
version.h
|
|
@ -0,0 +1,11 @@
|
|||
TOPDIR = ../..
|
||||
TARGETS = $(LIBHD_D)
|
||||
CLEANFILES = version.h
|
||||
|
||||
include $(TOPDIR)/Makefile.common
|
||||
|
||||
version.h: $(TOPDIR)/VERSION
|
||||
@echo "#define HD_VERSION_STRING \"`cat $(TOPDIR)/VERSION`\"" >$@
|
||||
|
||||
$(LIBHD_D): $(OBJS)
|
||||
ar r $(LIBHD) $?
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
|||
#define BIOS_ROM_START 0xc0000
|
||||
#define BIOS_ROM_SIZE 0x40000
|
||||
|
||||
#define BIOS_RAM_START 0x400
|
||||
#define BIOS_RAM_SIZE 0x100
|
||||
|
||||
void hd_scan_bios(hd_data_t *hd_data);
|
||||
void get_vbe_info(hd_data_t *hd_data, vbe_info_t *vbe);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
void hd_scan_sysfs_block(hd_data_t *hd_data);
|
||||
void hd_scan_sysfs_scsi(hd_data_t *hd_data);
|
|
@ -0,0 +1,584 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "braille.h"
|
||||
|
||||
/**
|
||||
* @defgroup BRAILLEint Braille devices
|
||||
* @ingroup libhdDEVint
|
||||
* @brief Braille displays functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(LIBHD_TINY) && !defined(__sparc__)
|
||||
|
||||
static unsigned do_alva(hd_data_t *hd_data, char *dev_name, int cnt);
|
||||
static unsigned do_fhp(hd_data_t *hd_data, char *dev_name, unsigned baud, int cnt);
|
||||
static unsigned do_fhp_new(hd_data_t *hd_data, char *dev_name, int cnt);
|
||||
static unsigned do_ht(hd_data_t *hd_data, char *dev_name, int cnt);
|
||||
static unsigned do_baum(hd_data_t *hd_data, char *dev_name, int cnt);
|
||||
|
||||
void hd_scan_braille(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd_tmp;
|
||||
int cnt = 0;
|
||||
unsigned *dev, *vend;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_braille)) return;
|
||||
|
||||
hd_data->module = mod_braille;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
dev = hd_shm_add(hd_data, NULL, sizeof *dev);
|
||||
vend = hd_shm_add(hd_data, NULL, sizeof *vend);
|
||||
|
||||
if(!dev || !vend) return;
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_comm &&
|
||||
hd->sub_class.id == sc_com_ser &&
|
||||
hd->unix_dev_name &&
|
||||
!hd->tag.skip_braille &&
|
||||
!has_something_attached(hd_data, hd)
|
||||
) {
|
||||
cnt++;
|
||||
*dev = *vend = 0;
|
||||
|
||||
hd_fork(hd_data, 10, 10);
|
||||
|
||||
if(hd_data->flags.forked) {
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_braille_alva)) {
|
||||
PROGRESS(1, cnt, "alva");
|
||||
*vend = MAKE_ID(TAG_SPECIAL, 0x5001);
|
||||
*dev = do_alva(hd_data, hd->unix_dev_name, cnt);
|
||||
}
|
||||
|
||||
if(!*dev && hd_probe_feature(hd_data, pr_braille_fhp)) {
|
||||
PROGRESS(1, cnt, "fhp_old");
|
||||
*vend = MAKE_ID(TAG_SPECIAL, 0x5002);
|
||||
*dev = do_fhp(hd_data, hd->unix_dev_name, B19200, cnt);
|
||||
if(!*dev) {
|
||||
PROGRESS(1, cnt, "fhp_el");
|
||||
*dev = do_fhp(hd_data, hd->unix_dev_name, B38400, cnt);
|
||||
}
|
||||
}
|
||||
|
||||
if(!*dev && hd_probe_feature(hd_data, pr_braille_ht)) {
|
||||
PROGRESS(1, cnt, "ht");
|
||||
*vend = MAKE_ID(TAG_SPECIAL, 0x5003);
|
||||
*dev = do_ht(hd_data, hd->unix_dev_name, cnt);
|
||||
}
|
||||
|
||||
if(!*dev && hd_probe_feature(hd_data, pr_braille_baum)) {
|
||||
PROGRESS(1, cnt, "baum");
|
||||
*vend = MAKE_ID(TAG_SPECIAL, 0x5004);
|
||||
*dev = do_baum(hd_data, hd->unix_dev_name, cnt);
|
||||
}
|
||||
|
||||
if(!*dev && hd_probe_feature(hd_data, pr_braille_fhp)) {
|
||||
PROGRESS(1, cnt, "fhp new");
|
||||
*vend = MAKE_ID(TAG_SPECIAL, 0x5002);
|
||||
*dev = do_fhp_new(hd_data, hd->unix_dev_name, cnt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hd_fork_done(hd_data);
|
||||
|
||||
if(*dev && *vend) {
|
||||
hd_tmp = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd_tmp->base_class.id = bc_braille;
|
||||
hd_tmp->bus.id = bus_serial;
|
||||
hd_tmp->unix_dev_name = new_str(hd->unix_dev_name);
|
||||
hd_tmp->attached_to = hd->idx;
|
||||
hd_tmp->vendor.id = *vend;
|
||||
hd_tmp->device.id = *dev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hd_shm_clean(hd_data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* autodetect for Alva Braille-displays
|
||||
* Author: marco Skambraks <marco@suse.de>
|
||||
* Suse GmbH Nuernberg
|
||||
*
|
||||
* This is free software, placed under the terms of the
|
||||
* GNU General Public License, as published by the Free Software
|
||||
* Foundation. Please see the file COPYING for details.
|
||||
*/
|
||||
|
||||
/* Communication codes */
|
||||
#define BRL_ID "\033ID="
|
||||
|
||||
|
||||
#define WAIT_DTR 700000
|
||||
#define WAIT_FLUSH 200
|
||||
|
||||
unsigned do_alva(hd_data_t *hd_data, char *dev_name, int cnt)
|
||||
{
|
||||
int fd, i, timeout = 100;
|
||||
struct termios oldtio, newtio; /* old & new terminal settings */
|
||||
int model = -1;
|
||||
unsigned char buffer[sizeof BRL_ID];
|
||||
unsigned dev = 0;
|
||||
|
||||
PROGRESS(2, cnt, "alva open");
|
||||
|
||||
/* Open the Braille display device for random access */
|
||||
fd = open(dev_name, O_RDWR | O_NOCTTY);
|
||||
if(fd < 0) return 0;
|
||||
|
||||
tcgetattr(fd, &oldtio); /* save current settings */
|
||||
|
||||
/* Set flow control and 8n1, enable reading */
|
||||
memset(&newtio, 0, sizeof newtio);
|
||||
newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD;
|
||||
/* Ignore bytes with parity errors and make terminal raw and dumb */
|
||||
newtio.c_iflag = IGNPAR;
|
||||
newtio.c_oflag = 0; /* raw output */
|
||||
newtio.c_lflag = 0; /* don't echo or generate signals */
|
||||
newtio.c_cc[VMIN] = 0; /* set nonblocking read */
|
||||
newtio.c_cc[VTIME] = 0;
|
||||
|
||||
PROGRESS(3, cnt, "alva init ok");
|
||||
|
||||
PROGRESS(4, cnt, "alva read data");
|
||||
|
||||
/* autodetecting ABT model */
|
||||
/* to force DTR off */
|
||||
cfsetispeed(&newtio, B0);
|
||||
cfsetospeed(&newtio, B0);
|
||||
tcsetattr(fd, TCSANOW, &newtio); /* activate new settings */
|
||||
usleep(WAIT_DTR);
|
||||
|
||||
tcflush(fd, TCIOFLUSH); /* clean line */
|
||||
usleep(WAIT_FLUSH);
|
||||
|
||||
/* DTR back on */
|
||||
cfsetispeed(&newtio, B9600);
|
||||
cfsetospeed(&newtio, B9600);
|
||||
tcsetattr(fd, TCSANOW, &newtio); /* activate new settings */
|
||||
usleep(WAIT_DTR); /* give time to send ID string */
|
||||
|
||||
if((i = read(fd, buffer, sizeof buffer)) == sizeof buffer) {
|
||||
if(!strncmp(buffer, BRL_ID, sizeof BRL_ID - 1)) {
|
||||
/* Find out which model we are connected to... */
|
||||
switch(model = buffer[sizeof buffer - 1])
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 0x0b:
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
dev = MAKE_ID(TAG_SPECIAL, model);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ADD2LOG("alva.%d@%s[%d]: ", timeout, dev_name, i);
|
||||
if(i > 0) hd_log_hex(hd_data, 1, i, buffer);
|
||||
ADD2LOG("\n");
|
||||
|
||||
PROGRESS(5, cnt, "alva read done");
|
||||
|
||||
/* reset serial lines */
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
tcsetattr(fd, TCSAFLUSH, &oldtio);
|
||||
close(fd);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* autodetect for Papenmeier Braille-displays
|
||||
* Author: marco Skambraks <marco@suse.de>
|
||||
* Suse GmbH Nuernberg
|
||||
*
|
||||
* This is free software, placed under the terms of the
|
||||
* GNU General Public License, as published by the Free Software
|
||||
* Foundation. Please see the file COPYING for details.
|
||||
*/
|
||||
|
||||
unsigned do_fhp(hd_data_t *hd_data, char *dev_name, unsigned baud, int cnt)
|
||||
{
|
||||
int fd, i;
|
||||
char crash[] = { 2, 'S', 0, 0, 0, 0 };
|
||||
unsigned char buf[10];
|
||||
struct termios oldtio, newtio; /* old & new terminal settings */
|
||||
unsigned dev;
|
||||
|
||||
PROGRESS(2, cnt, "fhp open");
|
||||
|
||||
/* Now open the Braille display device for random access */
|
||||
fd = open(dev_name, O_RDWR | O_NOCTTY);
|
||||
if(fd < 0) return 0;
|
||||
|
||||
tcgetattr(fd, &oldtio); /* save current settings */
|
||||
|
||||
/* Set bps, flow control and 8n1, enable reading */
|
||||
memset(&newtio, 0, sizeof newtio);
|
||||
newtio.c_cflag = baud | CS8 | CLOCAL | CREAD;
|
||||
|
||||
/* Ignore bytes with parity errors and make terminal raw and dumb */
|
||||
newtio.c_iflag = IGNPAR;
|
||||
newtio.c_oflag = 0; /* raw output */
|
||||
newtio.c_lflag = 0; /* don't echo or generate signals */
|
||||
newtio.c_cc[VMIN] = 0; /* set nonblocking read */
|
||||
newtio.c_cc[VTIME] = 0;
|
||||
tcflush(fd, TCIFLUSH); /* clean line */
|
||||
tcsetattr(fd, TCSANOW, &newtio); /* activate new settings */
|
||||
|
||||
PROGRESS(3, cnt, "fhp init ok");
|
||||
|
||||
crash[2] = 0x200 >> 8;
|
||||
crash[3] = 0x200 & 0xff;
|
||||
crash[5] = (7+10) & 0xff;
|
||||
|
||||
write(fd, crash, sizeof crash);
|
||||
write(fd, "1111111111",10);
|
||||
write(fd, "\03", 1);
|
||||
|
||||
crash[2] = 0x0 >> 8;
|
||||
crash[3] = 0x0 & 0xff;
|
||||
crash[5] = 5 & 0xff;
|
||||
|
||||
write(fd, crash, sizeof crash);
|
||||
write(fd, "1111111111", 10);
|
||||
write(fd, "\03", 1);
|
||||
|
||||
usleep(500000); /* 100000 should be enough */
|
||||
|
||||
PROGRESS(4, cnt, "fhp write ok");
|
||||
|
||||
i = read(fd, &buf, 10);
|
||||
|
||||
PROGRESS(5, cnt, "fhp read done");
|
||||
|
||||
ADD2LOG("fhp@%s[%d]: ", dev_name, i);
|
||||
if(i > 0) hd_log_hex(hd_data, 1, i, buf);
|
||||
ADD2LOG("\n");
|
||||
|
||||
dev = 0;
|
||||
if(i == 10 && buf[0] == 0x02 && buf[1] == 0x49) {
|
||||
switch(buf[2]) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 64:
|
||||
case 65:
|
||||
case 66:
|
||||
case 67:
|
||||
case 68:
|
||||
dev = buf[2];
|
||||
dev = MAKE_ID(TAG_SPECIAL, dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!dev) ADD2LOG("no fhp display: 0x%02x\n", i >= 2 ? buf[2] : 0);
|
||||
|
||||
/* reset serial lines */
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
tcsetattr(fd, TCSAFLUSH, &oldtio);
|
||||
close(fd);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* autodetect for Handy Tech Braille-displays
|
||||
* Author: marco Skambraks <marco@suse.de>
|
||||
* Suse GmbH Nuernberg
|
||||
*
|
||||
* This is free software, placed under the terms of the
|
||||
* GNU General Public License, as published by the Free Software
|
||||
* Foundation. Please see the file COPYING for details.
|
||||
*/
|
||||
|
||||
unsigned do_ht(hd_data_t *hd_data, char *dev_name, int cnt)
|
||||
{
|
||||
int fd, i;
|
||||
unsigned char code = 0xff, buf[2] = { 0, 0 };
|
||||
struct termios oldtio, newtio;
|
||||
unsigned dev = 0;
|
||||
|
||||
PROGRESS(2, cnt, "ht open");
|
||||
|
||||
fd = open(dev_name, O_RDWR | O_NOCTTY);
|
||||
if(fd < 0) return 0;
|
||||
|
||||
tcgetattr(fd, &oldtio);
|
||||
|
||||
newtio = oldtio;
|
||||
newtio.c_cflag = CLOCAL | PARODD | PARENB | CREAD | CS8;
|
||||
newtio.c_iflag = IGNPAR;
|
||||
newtio.c_oflag = 0;
|
||||
newtio.c_lflag = 0;
|
||||
newtio.c_cc[VMIN] = 0;
|
||||
newtio.c_cc[VTIME] = 0;
|
||||
|
||||
i = 0;
|
||||
/*
|
||||
* Force down DTR, flush any pending data and then the port to what we
|
||||
* want it to be
|
||||
*/
|
||||
if(
|
||||
!(
|
||||
cfsetispeed(&newtio, B0) ||
|
||||
cfsetospeed(&newtio, B0) ||
|
||||
tcsetattr(fd, TCSANOW, &newtio) ||
|
||||
tcflush(fd, TCIOFLUSH) ||
|
||||
cfsetispeed(&newtio, B19200) ||
|
||||
cfsetospeed(&newtio, B19200) ||
|
||||
tcsetattr(fd, TCSANOW, &newtio)
|
||||
)
|
||||
) {
|
||||
/* Pause 20ms to let them take effect */
|
||||
usleep(20 * 1000);
|
||||
|
||||
PROGRESS(3, cnt, "ht init ok");
|
||||
|
||||
write(fd, &code, 1); /* reset brl */
|
||||
usleep(40 * 1000); /* wait for reset */
|
||||
|
||||
PROGRESS(4, cnt, "ht write ok");
|
||||
|
||||
read(fd, buf, 1);
|
||||
i = 1;
|
||||
|
||||
PROGRESS(5, cnt, "ht read done");
|
||||
|
||||
if(buf[0] == 0xfe) { /* resetok now read id */
|
||||
usleep(80 * 1000);
|
||||
read(fd, buf + 1, 1);
|
||||
i = 2;
|
||||
|
||||
PROGRESS(6, cnt, "ht read done");
|
||||
|
||||
switch(buf[1]) {
|
||||
case 0x05:
|
||||
case 0x09:
|
||||
case 0x36:
|
||||
case 0x38:
|
||||
case 0x44:
|
||||
case 0x72:
|
||||
case 0x74:
|
||||
case 0x78:
|
||||
case 0x80:
|
||||
case 0x84:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
dev = buf[1];
|
||||
dev = MAKE_ID(TAG_SPECIAL, dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ADD2LOG("ht@%s[%d]: ", dev_name, i);
|
||||
if(i > 0) hd_log_hex(hd_data, 1, i, buf);
|
||||
ADD2LOG("\n");
|
||||
|
||||
if(!dev) ADD2LOG("no ht display: 0x%02x\n", buf[1]);
|
||||
|
||||
/* reset serial lines */
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
tcsetattr(fd, TCSAFLUSH, &oldtio);
|
||||
close(fd);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* autodetect for Baum Braille-displays
|
||||
* Author: marco Skambraks <marco@suse.de>
|
||||
* Suse GmbH Nuernberg
|
||||
*
|
||||
* This is free software, placed under the terms of the
|
||||
* GNU General Public License, as published by the Free Software
|
||||
* Foundation. Please see the file COPYING for details.
|
||||
*/
|
||||
|
||||
#define BAUDRATE B19200 /* But both run at 19k2 */
|
||||
#define MAXREAD 18
|
||||
|
||||
unsigned do_baum(hd_data_t *hd_data, char *dev_name, int cnt)
|
||||
{
|
||||
static char device_id[] = { 0x1b, 0x84 };
|
||||
int fd;
|
||||
struct termios oldtio, curtio;
|
||||
unsigned char buf[MAXREAD + 1];
|
||||
int i;
|
||||
|
||||
PROGRESS(2, cnt, "baum open");
|
||||
|
||||
fd = open(dev_name, O_RDWR | O_NOCTTY);
|
||||
if(fd < 0) return 0;
|
||||
|
||||
tcgetattr(fd, &curtio);
|
||||
|
||||
oldtio = curtio;
|
||||
cfmakeraw(&curtio);
|
||||
|
||||
/* no SIGTTOU to backgrounded processes */
|
||||
curtio.c_lflag &= ~TOSTOP;
|
||||
curtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
|
||||
/* no input parity check, no XON/XOFF */
|
||||
curtio.c_iflag &= ~(INPCK | ~IXOFF);
|
||||
|
||||
curtio.c_cc[VTIME] = 2; /* 0.1s timeout between chars on input */
|
||||
curtio.c_cc[VMIN] = 0; /* no minimum input */
|
||||
|
||||
tcsetattr(fd, TCSAFLUSH, &curtio);
|
||||
|
||||
/* write ID-request */
|
||||
write(fd, device_id, sizeof device_id);
|
||||
|
||||
/* wait for response */
|
||||
usleep(250000);
|
||||
|
||||
PROGRESS(3, cnt, "baum write ok");
|
||||
|
||||
i = read(fd, buf, sizeof buf - 1);
|
||||
buf[sizeof buf - 1] = 0;
|
||||
|
||||
PROGRESS(4, cnt, "baum read done");
|
||||
|
||||
ADD2LOG("baum@%s[%d]: ", dev_name, i);
|
||||
if(i > 0) hd_log_hex(hd_data, 1, i, buf);
|
||||
ADD2LOG("\n");
|
||||
|
||||
/* reset serial lines */
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
tcsetattr(fd, TCSAFLUSH, &oldtio);
|
||||
close(fd);
|
||||
|
||||
if(!strcmp(buf + 2, "Baum Vario40")) return MAKE_ID(TAG_SPECIAL, 1);
|
||||
if(!strcmp(buf + 2, "Baum Vario80")) return MAKE_ID(TAG_SPECIAL, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned do_fhp_new(hd_data_t *hd_data, char *dev_name, int cnt)
|
||||
{
|
||||
int i, fd, status = 0;
|
||||
unsigned id;
|
||||
unsigned char retstr[50] = "";
|
||||
unsigned char brlauto[] = { 2, 0x42, 0x50, 0x50, 3 };
|
||||
struct termios oldtio, tiodata = { };
|
||||
|
||||
PROGRESS(2, cnt, "fhp2 open");
|
||||
|
||||
fd = open(dev_name, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
if(fd < 0) return 0;
|
||||
|
||||
fcntl(fd, F_SETFL, 0); // remove O_NONBLOCK
|
||||
|
||||
tcgetattr(fd, &oldtio);
|
||||
|
||||
/* Set bps, and 8n1, enable reading */
|
||||
tiodata.c_cflag = (CLOCAL | CREAD | CS8);
|
||||
tiodata.c_iflag = IGNPAR;
|
||||
tiodata.c_lflag = 0;
|
||||
tiodata.c_cc[VMIN] = 0;
|
||||
tiodata.c_cc[VTIME] = 0;
|
||||
|
||||
if(
|
||||
cfsetispeed(&tiodata, B0) ||
|
||||
cfsetospeed(&tiodata, B0) ||
|
||||
tcsetattr(fd, TCSANOW, &tiodata) ||
|
||||
tcflush(fd, TCIOFLUSH) ||
|
||||
cfsetispeed(&tiodata, B57600) ||
|
||||
cfsetospeed(&tiodata, B57600) ||
|
||||
tcsetattr(fd, TCSANOW, &tiodata)
|
||||
) {
|
||||
/* init error */
|
||||
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
tcsetattr(fd, TCSAFLUSH, &oldtio);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
usleep(100 * 1000);
|
||||
|
||||
/* get status of inteface */
|
||||
ioctl(fd, TIOCMGET, &status);
|
||||
|
||||
/* clear dtr-line */
|
||||
status &= ~TIOCM_DTR;
|
||||
|
||||
/* set new status */
|
||||
ioctl(fd, TIOCMSET, &status);
|
||||
|
||||
usleep(100 * 1000);
|
||||
|
||||
write(fd, brlauto, sizeof brlauto);
|
||||
|
||||
PROGRESS(3, cnt, "fhp2 write ok");
|
||||
|
||||
usleep(100 * 1000);
|
||||
|
||||
i = read(fd, retstr, 20);
|
||||
|
||||
PROGRESS(4, cnt, "fhp2 read done");
|
||||
|
||||
ADD2LOG("fhp2@%s[%d]: ", dev_name, i);
|
||||
if(i > 0) hd_log_hex(hd_data, 1, i, retstr);
|
||||
ADD2LOG("\n");
|
||||
|
||||
id = 0;
|
||||
|
||||
if(i == 10 && retstr[1] == 'J') {
|
||||
id = retstr[3];
|
||||
|
||||
/* papenmeir new serial and usb device IDs */
|
||||
switch(id) {
|
||||
case 0x55:
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
id = MAKE_ID(TAG_SPECIAL, id);
|
||||
break;
|
||||
|
||||
default:
|
||||
ADD2LOG("unknown id %d\n", id);
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset serial lines */
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
tcsetattr(fd, TCSAFLUSH, &oldtio);
|
||||
close(fd);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
#endif /* !defined(LIBHD_TINY) && !defined(__sparc__) */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_braille(hd_data_t *hd_data);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
void hd_scan_cpu(hd_data_t *hd_data);
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
|
||||
int is_kms_active(hd_data_t *hd_data) {
|
||||
int kms = open("/sys/class/drm/card0", O_RDONLY) > 0;
|
||||
ADD2LOG(" KMS detected: %d\n", kms);
|
||||
|
||||
return kms;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
#ifndef DRM_H
|
||||
#define DRM_H
|
||||
|
||||
int is_kms_active(hd_data_t *hd_data);
|
||||
|
||||
#endif /* DRM_H */
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* taken from HAL 0.5.14
|
||||
* http://www.freedesktop.org/Software/hal
|
||||
*
|
||||
* Originally part of dvd+rw-tools by Andy Polyakov <appro@fy.chalmers.se>
|
||||
* 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 <stdint.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 "dvd.h"
|
||||
|
||||
#if !defined(SG_FLAG_LUN_INHIBIT)
|
||||
# if defined(SG_FLAG_UNUSED_LUN_INHIBIT)
|
||||
# define SG_FLAG_LUN_INHIBIT SG_FLAG_UNUSED_LUN_INHIBIT
|
||||
# else
|
||||
# define SG_FLAG_LUN_INHIBIT 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
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 ((unsigned char*)cmd->sg_io.sbp);
|
||||
ret = ERRCODE ((unsigned char*)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_profile(int fd)
|
||||
{
|
||||
ScsiCommand *cmd;
|
||||
int retval = 0;
|
||||
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]);
|
||||
/* 0x13: DVD-RW Restricted Overwrite
|
||||
* 0x14: DVD-RW Sequential
|
||||
* 0x15: DVD-R Dual Layer Sequential
|
||||
* 0x16: DVD-R Dual Layer Jump
|
||||
* 0x1A: DVD+RW
|
||||
* 0x1B: DVD+R
|
||||
* 0x2A: DVD+RW DL
|
||||
* 0x2B: DVD+R DL
|
||||
* 0x40: BD-ROM
|
||||
* 0x41: BD-R SRM
|
||||
* 0x42: BR-R RRM
|
||||
* 0x43: BD-RE
|
||||
* 0x50: HD DVD-ROM
|
||||
* 0x51: HD DVD-R
|
||||
* 0x52: HD DVD-Rewritable
|
||||
*/
|
||||
|
||||
switch (profile) {
|
||||
case 0x13:
|
||||
case 0x14:
|
||||
retval |= DRIVE_CDROM_CAPS_DVDRW;
|
||||
break;
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
retval |= DRIVE_CDROM_CAPS_DVDRDL;
|
||||
break;
|
||||
case 0x1B:
|
||||
retval |= DRIVE_CDROM_CAPS_DVDPLUSR;
|
||||
break;
|
||||
case 0x1A:
|
||||
retval |= DRIVE_CDROM_CAPS_DVDPLUSRW;
|
||||
break;
|
||||
case 0x2A:
|
||||
retval |= DRIVE_CDROM_CAPS_DVDPLUSRWDL;
|
||||
break;
|
||||
case 0x2B:
|
||||
retval |= DRIVE_CDROM_CAPS_DVDPLUSRDL;
|
||||
break;
|
||||
case 0x40:
|
||||
retval |= DRIVE_CDROM_CAPS_BDROM;
|
||||
break;
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
retval |= DRIVE_CDROM_CAPS_BDR;
|
||||
break;
|
||||
case 0x43:
|
||||
retval |= DRIVE_CDROM_CAPS_BDRE;
|
||||
break;
|
||||
case 0x50:
|
||||
retval |= DRIVE_CDROM_CAPS_HDDVDROM;
|
||||
break;
|
||||
case 0x51:
|
||||
retval |= DRIVE_CDROM_CAPS_HDDVDR;
|
||||
break;
|
||||
case 0x52:
|
||||
retval |= DRIVE_CDROM_CAPS_HDDVDRW;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scsi_command_free (cmd);
|
||||
free (list);
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* taken from HAL 0.5.14
|
||||
* http://www.freedesktop.org/Software/hal
|
||||
*/
|
||||
|
||||
#define DRIVE_CDROM_CAPS_DVDRW 1
|
||||
#define DRIVE_CDROM_CAPS_DVDRDL 2
|
||||
#define DRIVE_CDROM_CAPS_DVDPLUSR 4
|
||||
#define DRIVE_CDROM_CAPS_DVDPLUSRW 8
|
||||
#define DRIVE_CDROM_CAPS_DVDPLUSRWDL 16
|
||||
#define DRIVE_CDROM_CAPS_DVDPLUSRDL 32
|
||||
#define DRIVE_CDROM_CAPS_BDROM 64
|
||||
#define DRIVE_CDROM_CAPS_BDR 128
|
||||
#define DRIVE_CDROM_CAPS_BDRE 256
|
||||
#define DRIVE_CDROM_CAPS_HDDVDROM 512
|
||||
#define DRIVE_CDROM_CAPS_HDDVDR 1024
|
||||
#define DRIVE_CDROM_CAPS_HDDVDRW 2048
|
||||
|
||||
int get_dvd_profile(int fd);
|
|
@ -0,0 +1,398 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <endian.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "hddb.h"
|
||||
#include "edd.h"
|
||||
|
||||
/**
|
||||
* @defgroup EDDint EDD partition information
|
||||
* @ingroup libhdINFOint
|
||||
* @brief EDD disks layout / partition functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
||||
static void read_edd_info(hd_data_t *hd_data);
|
||||
static int does_match(edd_info_t *ei, hd_t *hd, unsigned type);
|
||||
static int does_match0(edd_info_t *ei, edd_info_t *ei0, unsigned type);
|
||||
static int is_disk(hd_t *hd);
|
||||
static uint64_t disk_size(hd_t *hd);
|
||||
static int identical_disks(hd_t *hd1, hd_t *hd2);
|
||||
|
||||
void hd_scan_sysfs_edd(hd_data_t *hd_data)
|
||||
{
|
||||
if(!hd_probe_feature(hd_data, pr_edd)) return;
|
||||
|
||||
hd_data->module = mod_edd;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
hd_data->flags.edd_used = 0;
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_edd_mod)) {
|
||||
PROGRESS(1, 0, "edd mod");
|
||||
load_module(hd_data, "edd");
|
||||
}
|
||||
|
||||
PROGRESS(2, 0, "edd info");
|
||||
|
||||
read_edd_info(hd_data);
|
||||
}
|
||||
|
||||
|
||||
void read_edd_info(hd_data_t *hd_data)
|
||||
{
|
||||
unsigned u, u1;
|
||||
uint64_t ul0, edd_dev_path1, edd_dev_path2;
|
||||
edd_info_t *ei;
|
||||
str_list_t *sl, *sf_dir, *sf_dir_e, *sf_dir2;
|
||||
char *sf_edd = NULL, *net_link = NULL;
|
||||
unsigned char *edd_raw;
|
||||
char *edd_bus, *edd_interface, *edd_link;
|
||||
|
||||
for(u = 0; u < sizeof hd_data->edd / sizeof *hd_data->edd; u++) {
|
||||
free_mem(hd_data->edd[u].sysfs_id);
|
||||
}
|
||||
|
||||
memset(hd_data->edd, 0, sizeof hd_data->edd);
|
||||
|
||||
sf_dir = read_dir("/sys/firmware/edd", 'd');
|
||||
|
||||
for(sf_dir_e = sf_dir; sf_dir_e; sf_dir_e = sf_dir_e->next) {
|
||||
str_printf(&sf_edd, 0, "/sys/firmware/edd/%s", sf_dir_e->str);
|
||||
|
||||
if(
|
||||
sscanf(sf_dir_e->str, "int13_dev%02x", &u) == 1 &&
|
||||
u >= 0x80 &&
|
||||
u <= 0xff
|
||||
) {
|
||||
u -= 0x80;
|
||||
|
||||
ei = hd_data->edd + u;
|
||||
|
||||
ei->valid = 1;
|
||||
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_edd, "sectors"), &ul0, 0)) {
|
||||
ei->sectors = ul0;
|
||||
}
|
||||
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_edd, "default_cylinders"), &ul0, 0)) {
|
||||
ei->edd.cyls = ul0;
|
||||
}
|
||||
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_edd, "default_heads"), &ul0, 0)) {
|
||||
ei->edd.heads = ul0;
|
||||
}
|
||||
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_edd, "default_sectors_per_track"), &ul0, 0)) {
|
||||
ei->edd.sectors = ul0;
|
||||
}
|
||||
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_edd, "legacy_max_cylinder"), &ul0, 0)) {
|
||||
ei->legacy.cyls = ul0 + 1;
|
||||
}
|
||||
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_edd, "legacy_max_head"), &ul0, 0)) {
|
||||
ei->legacy.heads = ul0 + 1;
|
||||
}
|
||||
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_edd, "legacy_sectors_per_track"), &ul0, 0)) {
|
||||
ei->legacy.sectors = ul0;
|
||||
}
|
||||
|
||||
if(ei->sectors && ei->edd.heads && ei->edd.sectors) {
|
||||
ei->edd.cyls = ei->sectors / (ei->edd.heads * ei->edd.sectors);
|
||||
}
|
||||
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_edd, "mbr_signature"), &ul0, 0)) {
|
||||
ei->signature = ul0;
|
||||
}
|
||||
|
||||
sl = hd_attr_list(get_sysfs_attr_by_path(sf_edd, "extensions"));
|
||||
if(search_str_list(sl, "Fixed disk access")) hd_data->edd[u].ext_fixed_disk = 1;
|
||||
if(search_str_list(sl, "Device locking and ejecting")) hd_data->edd[u].ext_lock_eject = 1;
|
||||
if(search_str_list(sl, "Enhanced Disk Drive support")) hd_data->edd[u].ext_edd = 1;
|
||||
if(search_str_list(sl, "64-bit extensions")) hd_data->edd[u].ext_64bit = 1;
|
||||
|
||||
edd_bus = edd_interface = NULL;
|
||||
edd_dev_path1 = edd_dev_path2 = 0;
|
||||
|
||||
edd_raw = get_sysfs_attr_by_path2(sf_edd, "raw_data", &u1);
|
||||
if(u1 >= 40) edd_bus = canon_str(edd_raw + 36, 4);
|
||||
if(u1 >= 48) {
|
||||
edd_interface = canon_str(edd_raw + 40, 8);
|
||||
if(!strcmp(edd_interface, "FIBRE")) ei->ext_fibre = 1;
|
||||
}
|
||||
if(u1 >= 72) {
|
||||
memcpy(&edd_dev_path1, edd_raw + 56, 8);
|
||||
memcpy(&edd_dev_path2, edd_raw + 64, 8);
|
||||
|
||||
edd_dev_path1 = be64toh(edd_dev_path1); // wwid for fc
|
||||
}
|
||||
|
||||
edd_link = hd_read_sysfs_link(sf_edd, "pci_dev");
|
||||
if(edd_link) {
|
||||
str_printf(&net_link, 0, "%s/net", edd_link);
|
||||
sf_dir2 = read_dir("/sys/firmware/edd", 'D');
|
||||
if(sf_dir2) ei->ext_net = 1;
|
||||
free_str_list(sf_dir2);
|
||||
}
|
||||
|
||||
ADD2LOG(
|
||||
"edd: 0x%02x\n mbr sig: 0x%08x\n size: %"PRIu64"\n chs default: %u/%u/%u\n chs legacy: %u/%u/%u\n caps: %s%s%s%s%s%s\n",
|
||||
u + 0x80,
|
||||
ei->signature,
|
||||
ei->sectors,
|
||||
ei->edd.cyls,
|
||||
ei->edd.heads,
|
||||
ei->edd.sectors,
|
||||
ei->legacy.cyls,
|
||||
ei->legacy.heads,
|
||||
ei->legacy.sectors,
|
||||
ei->ext_fixed_disk ? "fixed " : "",
|
||||
ei->ext_lock_eject ? "lock " : "",
|
||||
ei->ext_edd ? "edd " : "",
|
||||
ei->ext_64bit ? "64bit " : "",
|
||||
ei->ext_fibre ? "fibre " : "",
|
||||
ei->ext_net ? "net " : ""
|
||||
);
|
||||
ADD2LOG(" bus: %s\n interface: %s\n dev path: %016"PRIx64" %016"PRIx64"\n", edd_bus, edd_interface, edd_dev_path1, edd_dev_path2);
|
||||
|
||||
free_mem(edd_bus);
|
||||
free_mem(edd_interface);
|
||||
}
|
||||
}
|
||||
|
||||
free_mem(sf_edd);
|
||||
free_mem(net_link);
|
||||
free_str_list(sf_dir);
|
||||
}
|
||||
|
||||
|
||||
void assign_edd_info(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *match_hd;
|
||||
unsigned u, u1, u2, lba, matches, real_matches, match_edd, type;
|
||||
bios_info_t *bt;
|
||||
edd_info_t *ei;
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(is_disk(hd)) hd->rom_id = free_mem(hd->rom_id);
|
||||
}
|
||||
|
||||
/* add BIOS drive ids to disks */
|
||||
for(type = 0; type < 4; type++) {
|
||||
for(u = 0; u < sizeof hd_data->edd / sizeof *hd_data->edd; u++) {
|
||||
ei = hd_data->edd + u;
|
||||
if(!ei->valid || ei->assigned) continue;
|
||||
|
||||
for(u1 = u2 = 0; u1 < sizeof hd_data->edd / sizeof *hd_data->edd; u1++) {
|
||||
if(does_match0(ei, hd_data->edd + u1, type)) u2++;
|
||||
}
|
||||
|
||||
/* not unique */
|
||||
if(u2 != 1) continue;
|
||||
|
||||
matches = real_matches = 0;
|
||||
match_hd = 0;
|
||||
match_edd = 0;
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(!is_disk(hd) || hd->rom_id) continue;
|
||||
|
||||
if(does_match(ei, hd, type)) {
|
||||
if(!matches) {
|
||||
match_edd = u;
|
||||
match_hd = hd;
|
||||
}
|
||||
else {
|
||||
if(identical_disks(hd, match_hd)) real_matches--;
|
||||
}
|
||||
matches++;
|
||||
real_matches++;
|
||||
}
|
||||
}
|
||||
|
||||
ADD2LOG(" %02x: matches %d (%d)\n", u + 0x80, real_matches, matches);
|
||||
|
||||
if(real_matches == 1) {
|
||||
hd_data->flags.edd_used = 1;
|
||||
hd_data->edd[match_edd].assigned = 1;
|
||||
|
||||
if(matches == 1) {
|
||||
str_printf(&match_hd->rom_id, 0, "0x%02x", match_edd + 0x80);
|
||||
ADD2LOG(" %s = %s (match %d)\n", match_hd->unix_dev_name, match_hd->rom_id, type);
|
||||
}
|
||||
else {
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(!is_disk(hd) || hd->rom_id) continue;
|
||||
if(does_match(ei, hd, type)) {
|
||||
str_printf(&hd->rom_id, 0, "0x%02x", match_edd + 0x80);
|
||||
ADD2LOG(" %s = %s (match %d)\n", hd->unix_dev_name, hd->rom_id, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* set lba support flag in BIOS data */
|
||||
for(lba = u = 0; u < sizeof hd_data->edd / sizeof *hd_data->edd; u++) {
|
||||
if(hd_data->edd[u].ext_fixed_disk) {
|
||||
lba = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lba) {
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_internal &&
|
||||
hd->sub_class.id == sc_int_bios &&
|
||||
hd->detail &&
|
||||
hd->detail->type == hd_detail_bios &&
|
||||
(bt = hd->detail->bios.data)
|
||||
) {
|
||||
bt->lba_support = lba;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int does_match(edd_info_t *ei, hd_t *hd, unsigned type)
|
||||
{
|
||||
int i = 0;
|
||||
uint64_t u64;
|
||||
|
||||
switch(type) {
|
||||
case 0:
|
||||
i = ei->signature == edd_disk_signature(hd) && ei->sectors == disk_size(hd);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
i = ei->signature == edd_disk_signature(hd);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
i = ei->sectors == disk_size(hd);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
u64 = ei->edd.heads * ei->edd.sectors;
|
||||
if(u64) {
|
||||
i = ei->edd.cyls == disk_size(hd) / u64;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int does_match0(edd_info_t *ei, edd_info_t *ei0, unsigned type)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
switch(type) {
|
||||
case 0:
|
||||
i = ei->signature == ei0->signature && ei->sectors == ei0->sectors;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
i = ei->signature == ei0->signature;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
i = ei->sectors == ei0->sectors;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
i = ei->edd.cyls == ei0->edd.cyls;
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int is_disk(hd_t *hd)
|
||||
{
|
||||
return
|
||||
hd->base_class.id == bc_storage_device &&
|
||||
hd->sub_class.id == sc_sdev_disk;
|
||||
}
|
||||
|
||||
|
||||
uint64_t disk_size(hd_t *hd)
|
||||
{
|
||||
hd_res_t *res;
|
||||
uint64_t ul = 0;
|
||||
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(
|
||||
res->any.type == res_size &&
|
||||
res->size.unit == size_unit_sectors
|
||||
) {
|
||||
ul = res->size.val1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ul;
|
||||
}
|
||||
|
||||
|
||||
unsigned edd_disk_signature(hd_t *hd)
|
||||
{
|
||||
unsigned char *s = hd->block0;
|
||||
|
||||
if(!s) return 0;
|
||||
|
||||
return s[0x1b8] + (s[0x1b9] << 8) + (s[0x1ba] << 16) + (s[0x1bb] << 24);
|
||||
}
|
||||
|
||||
|
||||
int identical_disks(hd_t *hd1, hd_t *hd2)
|
||||
{
|
||||
char *s1 = NULL, *s2 = NULL;
|
||||
str_list_t *sl;
|
||||
|
||||
for(sl = hd1->unix_dev_names; sl; sl = sl->next) {
|
||||
if(!strncmp(sl->str, "/dev/disk/by-id/", sizeof "/dev/disk/by-id/" - 1)) {
|
||||
s1 = sl->str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(sl = hd2->unix_dev_names; sl; sl = sl->next) {
|
||||
if(!strncmp(sl->str, "/dev/disk/by-id/", sizeof "/dev/disk/by-id/" - 1)) {
|
||||
s2 = sl->str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!s1) s1 = hd1->serial;
|
||||
if(!s2) s2 = hd1->serial;
|
||||
|
||||
if(s1 && s2 && !strcmp(s1, s2)) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* defined(__i386__) || defined(__x86_64__) */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#if defined(__i386__) || defined(__x86_64__)
|
||||
void hd_scan_sysfs_edd(hd_data_t *hd_data);
|
||||
unsigned edd_disk_signature(hd_t *hd);
|
||||
void assign_edd_info(hd_data_t *hd_data);
|
||||
#endif
|
|
@ -0,0 +1,140 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "fb.h"
|
||||
|
||||
/**
|
||||
* @defgroup Framebuffer Framebuffer devices
|
||||
* @ingroup libhdDEVint
|
||||
* @brief Scan framebuffer devices
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
double pix_clock;
|
||||
double h_freq;
|
||||
double v_freq;
|
||||
} fb_info_t;
|
||||
|
||||
static fb_info_t *fb_get_info(hd_data_t *hd_data);
|
||||
|
||||
void hd_scan_fb(hd_data_t *hd_data)
|
||||
{
|
||||
fb_info_t *fb;
|
||||
hd_t *hd;
|
||||
hd_res_t *res;
|
||||
unsigned imac_dev, imac_vend;
|
||||
unsigned imac = 0;
|
||||
monitor_info_t *mi = NULL;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_fb)) return;
|
||||
|
||||
hd_data->module = mod_fb;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "read info");
|
||||
|
||||
fb = fb_get_info(hd_data);
|
||||
|
||||
if(fb) {
|
||||
imac_dev = MAKE_ID(TAG_EISA, 0x9d03);
|
||||
imac_vend = name2eisa_id("APP");
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_monitor) break;
|
||||
}
|
||||
|
||||
if(hd && hd->device.id == imac_dev && hd->vendor.id == imac_vend) {
|
||||
hd->tag.remove = 1;
|
||||
remove_tagged_hd_entries(hd_data);
|
||||
imac = 1;
|
||||
hd = NULL;
|
||||
}
|
||||
|
||||
/* add monitor entry based on fb data if we have no other info */
|
||||
if(!hd) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_monitor;
|
||||
if(imac) {
|
||||
hd->vendor.id = imac_vend;
|
||||
hd->device.id = imac_dev;
|
||||
}
|
||||
else {
|
||||
hd->vendor.name = new_str("Generic");
|
||||
hd->device.name = new_str("Monitor");
|
||||
}
|
||||
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->monitor.type = res_monitor;
|
||||
res->monitor.width = fb->width;
|
||||
res->monitor.height = fb->height;
|
||||
res->monitor.vfreq = fb->v_freq + 0.5;
|
||||
|
||||
if(!hd->detail) {
|
||||
mi = new_mem(sizeof *mi);
|
||||
hd->detail = new_mem(sizeof *hd->detail);
|
||||
hd->detail->type = hd_detail_monitor;
|
||||
hd->detail->monitor.data = mi;
|
||||
|
||||
mi->min_vsync = 50;
|
||||
mi->min_hsync = 31;
|
||||
mi->max_vsync = fb->v_freq * 1.11 + 0.9;
|
||||
mi->max_hsync = fb->h_freq / 1000.0 + 1.9;
|
||||
if(mi->max_vsync <= mi->min_vsync) mi->max_vsync = mi->min_vsync + 10;
|
||||
if(mi->max_hsync <= mi->min_hsync) mi->max_hsync = mi->min_hsync + 5;
|
||||
/* round up */
|
||||
mi->max_vsync = ((mi->max_vsync + 9) / 10) * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fb_info_t *fb_get_info(hd_data_t *hd_data)
|
||||
{
|
||||
int fd;
|
||||
struct fb_var_screeninfo fbv_info;
|
||||
static fb_info_t fb_info;
|
||||
fb_info_t *fb = NULL;
|
||||
int h, v;
|
||||
|
||||
fd = open(DEV_FB, O_RDONLY);
|
||||
if(fd < 0) fd = open(DEV_FB0, O_RDONLY);
|
||||
if(fd < 0) return fb;
|
||||
|
||||
if(!ioctl(fd, FBIOGET_VSCREENINFO, &fbv_info)) {
|
||||
h = fbv_info.left_margin + fbv_info.xres + fbv_info.right_margin + fbv_info.hsync_len;
|
||||
v = fbv_info.upper_margin + fbv_info.yres + fbv_info.lower_margin + fbv_info.vsync_len;
|
||||
if(fbv_info.pixclock && h && v) {
|
||||
fb_info.width = fbv_info.xres;
|
||||
fb_info.height = fbv_info.yres;
|
||||
fb_info.pix_clock = 1e12 / fbv_info.pixclock;
|
||||
fb_info.h_freq = fb_info.pix_clock / h;
|
||||
fb_info.v_freq = fb_info.h_freq / v;
|
||||
fb = &fb_info;
|
||||
ADD2LOG("fb: size %d x %d\n", fb_info.width, fb_info.height);
|
||||
ADD2LOG("fb: timing %.2f MHz, %.2f kHz, %.2f Hz\n", fb_info.pix_clock * 1e-6, fb_info.h_freq * 1e-3, fb_info.v_freq);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_fb(hd_data_t *hd_data);
|
|
@ -0,0 +1,175 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "klog.h"
|
||||
#include "floppy.h"
|
||||
|
||||
/**
|
||||
* @defgroup FLOPPYint Floppy devices
|
||||
* @ingroup libhdDEVint
|
||||
*
|
||||
* This should currently be called *before* scan_misc() so we can try to get
|
||||
* the floppy controller resources in scan_misc() by actually accessing the
|
||||
* floppy drive. (Otherwise there would be a rather longish timeout.)
|
||||
*
|
||||
* This is all rather strange and should be rewritten...
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
static void dump_floppy_data(hd_data_t *hd_data);
|
||||
|
||||
void hd_scan_floppy(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
char b0[10], b1[10], c;
|
||||
unsigned u;
|
||||
int fd, i, floppy_ctrls = 0, floppy_ctrl_idx = 0;
|
||||
str_list_t *sl;
|
||||
hd_res_t *res;
|
||||
int floppy_stat[2] = { 1, 1 };
|
||||
unsigned floppy_created = 0;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_floppy)) return;
|
||||
|
||||
hd_data->module = mod_floppy;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
hd_data->floppy = free_str_list(hd_data->floppy);
|
||||
|
||||
PROGRESS(1, 0, "get nvram");
|
||||
|
||||
/*
|
||||
* Look for existing floppy controller entries (typically there will be
|
||||
* *none*).
|
||||
*/
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_storage && hd->sub_class.id == sc_sto_floppy) {
|
||||
floppy_ctrls++;
|
||||
floppy_ctrl_idx = hd->idx;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Is enough to load the nvram module.
|
||||
*
|
||||
* Note: although you must be root to access /dev/nvram, every
|
||||
* user can read /proc/nvram.
|
||||
*/
|
||||
fd = open(DEV_NVRAM, O_RDONLY | O_NONBLOCK);
|
||||
if(fd >= 0) close(fd);
|
||||
|
||||
if(
|
||||
!(hd_data->floppy = read_file(PROC_NVRAM_24, 0, 0)) &&
|
||||
!(hd_data->floppy = read_file(PROC_NVRAM_22, 0, 0))
|
||||
);
|
||||
|
||||
if(hd_data->floppy && (hd_data->debug & HD_DEB_FLOPPY)) dump_floppy_data(hd_data);
|
||||
|
||||
if(!hd_data->klog) read_klog(hd_data);
|
||||
|
||||
for(sl = hd_data->klog; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "<4>floppy%u: no floppy controllers foun%c", &u, &c) == 2) {
|
||||
if(u < sizeof floppy_stat / sizeof *floppy_stat) {
|
||||
floppy_stat[u] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(hd_data->floppy) {
|
||||
PROGRESS(2, 0, "nvram info");
|
||||
sl = hd_data->floppy;
|
||||
}
|
||||
else {
|
||||
PROGRESS(2, 0, "klog info");
|
||||
sl = hd_data->klog;
|
||||
}
|
||||
|
||||
for(; sl; sl = sl->next) {
|
||||
if(hd_data->floppy) {
|
||||
i = sscanf(sl->str, " Floppy %u type : %8[0-9.]'' %8[0-9.]%c", &u, b0, b1, &c) == 4;
|
||||
}
|
||||
else {
|
||||
i = sscanf(sl->str, "<6>Floppy drive(s): fd%u is %8[0-9.]%c", &u, b1, &c) == 3;
|
||||
*b0 = 0;
|
||||
}
|
||||
|
||||
if(i) {
|
||||
if(
|
||||
!floppy_ctrls &&
|
||||
u < sizeof floppy_stat / sizeof *floppy_stat &&
|
||||
floppy_stat[u]
|
||||
) {
|
||||
/* create one, if missing (there's no floppy without a controller...) */
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_storage;
|
||||
hd->sub_class.id = sc_sto_floppy;
|
||||
floppy_ctrl_idx = hd->idx;
|
||||
floppy_ctrls++;
|
||||
}
|
||||
|
||||
struct stat sbuf;
|
||||
unsigned floppy_exists = 0;
|
||||
char *floppy_name = NULL;
|
||||
str_printf(&floppy_name, 0, "/dev/fd%u", u);
|
||||
floppy_exists = stat(floppy_name, &sbuf) ? 0 : 1;
|
||||
free_mem(floppy_name);
|
||||
|
||||
if(floppy_ctrls && !(floppy_created & (1 << u)) && floppy_exists) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_storage_device;
|
||||
hd->sub_class.id = sc_sdev_floppy;
|
||||
hd->bus.id = bus_floppy;
|
||||
hd->slot = u;
|
||||
str_printf(&hd->unix_dev_name, 0, "/dev/fd%u", u);
|
||||
|
||||
floppy_created |= 1 << u;
|
||||
|
||||
if(*b0) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->size.type = res_size;
|
||||
res->size.val1 = str2float(b0, 2);
|
||||
res->size.unit = size_unit_cinch;
|
||||
}
|
||||
|
||||
/* 'k' or 'M' */
|
||||
i = c == 'M' ? str2float(b1, 3) : str2float(b1, 0);
|
||||
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->size.type = res_size;
|
||||
res->size.val1 = i << 1;
|
||||
res->size.val2 = 0x200;
|
||||
res->size.unit = size_unit_sectors;
|
||||
|
||||
/* the only choice... */
|
||||
if(floppy_ctrls == 1) hd->attached_to = floppy_ctrl_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add floppy data to the global log.
|
||||
*/
|
||||
void dump_floppy_data(hd_data_t *hd_data)
|
||||
{
|
||||
str_list_t *sl;
|
||||
|
||||
ADD2LOG("----- /proc/nvram -----\n");
|
||||
for(sl = hd_data->floppy; sl; sl = sl->next) {
|
||||
ADD2LOG(" %s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- /proc/nvram end -----\n");
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_floppy(hd_data_t *hd_data);
|
|
@ -0,0 +1,768 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
// #define WITH_HAL 1
|
||||
|
||||
#if WITH_HAL
|
||||
|
||||
#ifndef DBUS_API_SUBJECT_TO_CHANGE
|
||||
#define DBUS_API_SUBJECT_TO_CHANGE 1
|
||||
#endif
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <hal/libhal.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "hal.h"
|
||||
|
||||
/**
|
||||
* @defgroup HALint Hardware abstraction (HAL) information
|
||||
* @ingroup libhdInternals
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
static void read_hal(hd_data_t *hd_data);
|
||||
static void add_pci(hd_data_t *hd_data);
|
||||
static void link_hal_tree(hd_data_t *hd_data);
|
||||
|
||||
static int hal_match_str(hal_prop_t *prop, const char *key, const char *val);
|
||||
|
||||
static int check_udi(const char *udi);
|
||||
static FILE *hd_open_properties(const char *udi, const char *mode);
|
||||
static char *skip_space(char *s);
|
||||
static char *skip_non_eq_or_space(char *s);
|
||||
static char *skip_nonquote(char *s);
|
||||
static void parse_property(hal_prop_t *prop, char *str);
|
||||
|
||||
static void find_udi(hd_data_t *hd_data, hd_t *hd, int match);
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*
|
||||
* read hal data
|
||||
*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*/
|
||||
|
||||
void hd_scan_hal(hd_data_t *hd_data)
|
||||
{
|
||||
if(!hd_probe_feature(hd_data, pr_hal)) return;
|
||||
|
||||
hd_data->module = mod_hal;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
hd_data->hal = hd_free_hal_devices(hd_data->hal);
|
||||
|
||||
PROGRESS(1, 0, "read hal data");
|
||||
|
||||
read_hal(hd_data);
|
||||
|
||||
if(!hd_data->hal) return;
|
||||
|
||||
link_hal_tree(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "pci sysfs");
|
||||
|
||||
hd_pci_read_data(hd_data);
|
||||
|
||||
PROGRESS(2, 0, "pci devices");
|
||||
|
||||
add_pci(hd_data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void hd_scan_hal_basic(hd_data_t *hd_data)
|
||||
{
|
||||
hd_data->module = mod_hal;
|
||||
|
||||
/* some clean-up */
|
||||
hd_data->hal = hd_free_hal_devices(hd_data->hal);
|
||||
|
||||
PROGRESS(1, 0, "read hal data");
|
||||
|
||||
read_hal(hd_data);
|
||||
}
|
||||
|
||||
|
||||
void read_hal(hd_data_t *hd_data)
|
||||
{
|
||||
#if WITH_HAL
|
||||
DBusError error;
|
||||
DBusConnection *conn;
|
||||
LibHalContext *hal_ctx;
|
||||
LibHalPropertySet *props;
|
||||
LibHalPropertySetIterator it;
|
||||
char **device_names, **slist, *s;
|
||||
int i, num_devices, type;
|
||||
hal_device_t *dev;
|
||||
hal_prop_t *prop;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if(!(conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
|
||||
ADD2LOG(" hal: dbus_bus_get: %s: %s\n", error.name, error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
ADD2LOG(" hal: connected to: %s\n", dbus_bus_get_unique_name(conn));
|
||||
|
||||
if(!(hal_ctx = libhal_ctx_new())) return;
|
||||
|
||||
if(!libhal_ctx_set_dbus_connection(hal_ctx, conn)) return;
|
||||
|
||||
if(!libhal_ctx_init(hal_ctx, &error)) {
|
||||
ADD2LOG(" hal: libhal_ctx_init: %s: %s\n", error.name, error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if((device_names = libhal_get_all_devices(hal_ctx, &num_devices, &error))) {
|
||||
ADD2LOG("----- hal device list -----\n");
|
||||
for(i = 0; i < num_devices; i++) {
|
||||
if(!(props = libhal_device_get_all_properties(hal_ctx, device_names[i], &error))) {
|
||||
ADD2LOG(" hal: %s: %s\n", error.name, error.message);
|
||||
dbus_error_init(&error);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev = new_mem(sizeof *dev);
|
||||
dev->udi = new_str(device_names[i]);
|
||||
dev->next = hd_data->hal;
|
||||
hd_data->hal = dev;
|
||||
|
||||
ADD2LOG(" %d: udi = '%s'\n", i, dev->udi);
|
||||
|
||||
for(libhal_psi_init(&it, props); libhal_psi_has_more(&it); libhal_psi_next(&it)) {
|
||||
type = libhal_psi_get_type(&it);
|
||||
|
||||
prop = new_mem(sizeof *prop);
|
||||
prop->next = dev->prop;
|
||||
dev->prop = prop;
|
||||
|
||||
switch(type) {
|
||||
case LIBHAL_PROPERTY_TYPE_STRING:
|
||||
prop->type = p_string;
|
||||
prop->key = new_str(libhal_psi_get_key(&it));
|
||||
prop->val.str = new_str(libhal_psi_get_string(&it));
|
||||
break;
|
||||
|
||||
case LIBHAL_PROPERTY_TYPE_INT32:
|
||||
prop->type = p_int32;
|
||||
prop->key = new_str(libhal_psi_get_key(&it));
|
||||
prop->val.int32 = libhal_psi_get_int(&it);
|
||||
break;
|
||||
|
||||
case LIBHAL_PROPERTY_TYPE_UINT64:
|
||||
prop->type = p_uint64;
|
||||
prop->key = new_str(libhal_psi_get_key(&it));
|
||||
prop->val.uint64 = libhal_psi_get_uint64(&it);
|
||||
break;
|
||||
|
||||
case LIBHAL_PROPERTY_TYPE_DOUBLE:
|
||||
prop->type = p_double;
|
||||
prop->key = new_str(libhal_psi_get_key(&it));
|
||||
prop->val.d = libhal_psi_get_double(&it);
|
||||
break;
|
||||
|
||||
case LIBHAL_PROPERTY_TYPE_BOOLEAN:
|
||||
prop->type = p_bool;
|
||||
prop->key = new_str(libhal_psi_get_key(&it));
|
||||
prop->val.b = libhal_psi_get_bool(&it);
|
||||
break;
|
||||
|
||||
case LIBHAL_PROPERTY_TYPE_STRLIST:
|
||||
prop->type = p_list;
|
||||
prop->key = new_str(libhal_psi_get_key(&it));
|
||||
for(slist = libhal_psi_get_strlist(&it); *slist; slist++) {
|
||||
add_str_list(&prop->val.list, *slist);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
prop->type = p_invalid;
|
||||
}
|
||||
|
||||
if((s = hd_hal_print_prop(prop))) {
|
||||
ADD2LOG(" %s\n", s);
|
||||
}
|
||||
}
|
||||
|
||||
libhal_free_property_set(props);
|
||||
if(i != num_devices - 1) ADD2LOG("\n");
|
||||
|
||||
}
|
||||
|
||||
ADD2LOG("----- hal device list end -----\n");
|
||||
|
||||
libhal_free_string_array(device_names);
|
||||
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
else {
|
||||
ADD2LOG(" hal: empty device list\n");
|
||||
}
|
||||
|
||||
|
||||
libhal_ctx_shutdown(hal_ctx, &error);
|
||||
|
||||
libhal_ctx_free(hal_ctx);
|
||||
|
||||
dbus_connection_unref(conn);
|
||||
|
||||
dbus_error_free(&error);
|
||||
#endif /* WITH_HAL */
|
||||
}
|
||||
|
||||
|
||||
void link_hal_tree(hd_data_t *hd_data)
|
||||
{
|
||||
hal_device_t *dev;
|
||||
hal_prop_t *prop;
|
||||
|
||||
for(dev = hd_data->hal; dev; dev = dev->next) {
|
||||
prop = hal_get_str(dev->prop, "info.parent");
|
||||
if(prop) {
|
||||
dev->parent = hal_find_device(hd_data, prop->val.str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hal_device_t *hal_find_device(hd_data_t *hd_data, char *udi)
|
||||
{
|
||||
hal_device_t *dev;
|
||||
|
||||
if(udi) {
|
||||
for(dev = hd_data->hal; dev; dev = dev->next) {
|
||||
if(!strcmp(dev->udi, udi)) return dev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void hal_invalidate(hal_prop_t *prop)
|
||||
{
|
||||
if(prop->type == p_string) free_mem(prop->val.str);
|
||||
if(prop->type == p_list) free_str_list(prop->val.list);
|
||||
prop->type = p_invalid;
|
||||
memset(&prop->val, 0, sizeof prop->val);
|
||||
}
|
||||
|
||||
|
||||
void hal_invalidate_all(hal_prop_t *prop, const char *key)
|
||||
{
|
||||
for(; (prop = hal_get_any(prop, key)); prop = prop->next) {
|
||||
hal_invalidate(prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *hal_get_any(hal_prop_t *prop, const char *key)
|
||||
{
|
||||
for(; prop; prop = prop->next) {
|
||||
if(!strcmp(prop->key, key)) return prop;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *hal_get_bool(hal_prop_t *prop, const char *key)
|
||||
{
|
||||
for(; prop; prop = prop->next) {
|
||||
if(prop->type == p_bool && !strcmp(prop->key, key)) return prop;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *hal_get_int32(hal_prop_t *prop, const char *key)
|
||||
{
|
||||
for(; prop; prop = prop->next) {
|
||||
if(prop->type == p_int32 && !strcmp(prop->key, key)) return prop;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *hal_get_str(hal_prop_t *prop, const char *key)
|
||||
{
|
||||
for(; prop; prop = prop->next) {
|
||||
if(prop->type == p_string && !strcmp(prop->key, key)) return prop;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char *hal_get_useful_str(hal_prop_t *prop, const char *key)
|
||||
{
|
||||
for(; prop; prop = prop->next) {
|
||||
if(prop->type == p_string && !strcmp(prop->key, key)) {
|
||||
if(prop->val.str && strncmp(prop->val.str, "Unknown", sizeof "Unknown" - 1)) return prop->val.str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int hal_match_str(hal_prop_t *prop, const char *key, const char *val)
|
||||
{
|
||||
return val && (prop = hal_get_str(prop, key)) && !strcmp(prop->val.str, val);
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *hal_get_list(hal_prop_t *prop, const char *key)
|
||||
{
|
||||
for(; prop; prop = prop->next) {
|
||||
if(prop->type == p_list && !strcmp(prop->key, key)) return prop;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *hal_add_new(hal_prop_t **prop)
|
||||
{
|
||||
while(*prop) prop = &(*prop)->next;
|
||||
*prop = new_mem(sizeof **prop);
|
||||
hal_invalidate(*prop);
|
||||
|
||||
return *prop;
|
||||
}
|
||||
|
||||
|
||||
void add_pci(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
hal_prop_t *prop;
|
||||
int i, j;
|
||||
char *s;
|
||||
hal_device_t *dev;
|
||||
pci_t *pci;
|
||||
|
||||
for(dev = hd_data->hal ; dev; dev = dev->next) {
|
||||
if(dev->used) continue;
|
||||
if(!hal_match_str(dev->prop, "info.subsystem", "pci")) continue;
|
||||
dev->used = 1;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
|
||||
if((prop = hal_get_str(dev->prop, "linux.sysfs_path"))) hd->sysfs_id = new_str(hd_sysfs_id(prop->val.str));
|
||||
|
||||
for(pci = hd_data->pci; pci; pci = pci->next) {
|
||||
if(!strcmp(hd_sysfs_id(pci->sysfs_id), hd->sysfs_id)) {
|
||||
hd->detail = new_mem(sizeof *hd->detail);
|
||||
hd->detail->type = hd_detail_pci;
|
||||
hd->detail->pci.data = pci;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hd_pci_complete_data(hd);
|
||||
|
||||
hd->udi = new_str(dev->udi);
|
||||
if(dev->parent) hd->parent_udi = new_str(dev->parent->udi);
|
||||
|
||||
if((prop = hal_get_int32(dev->prop, "pci.device_protocol"))) hd->prog_if.id = prop->val.int32;
|
||||
if((prop = hal_get_int32(dev->prop, "pci.device_subclass"))) hd->sub_class.id = prop->val.int32;
|
||||
if((prop = hal_get_int32(dev->prop, "pci.device_class"))) hd->base_class.id = prop->val.int32;
|
||||
|
||||
i = (prop = hal_get_int32(dev->prop, "pci.vendor_id")) ? prop->val.int32 : 0;
|
||||
j = (prop = hal_get_int32(dev->prop, "pci.product_id")) ? prop->val.int32 : 0;
|
||||
|
||||
if(i || j) {
|
||||
hd->vendor.id = MAKE_ID(TAG_PCI, i);
|
||||
hd->device.id = MAKE_ID(TAG_PCI, j);
|
||||
}
|
||||
|
||||
if((s = hal_get_useful_str(dev->prop, "pci.vendor"))) hd->vendor.name = new_str(s);
|
||||
if((s = hal_get_useful_str(dev->prop, "pci.product"))) hd->device.name = new_str(s);
|
||||
|
||||
i = (prop = hal_get_int32(dev->prop, "pci.subsys_vendor_id")) ? prop->val.int32 : 0;
|
||||
j = (prop = hal_get_int32(dev->prop, "pci.subsys_product_id")) ? prop->val.int32 : 0;
|
||||
|
||||
if(i || j) {
|
||||
hd->sub_vendor.id = MAKE_ID(TAG_PCI, i);
|
||||
hd->sub_device.id = MAKE_ID(TAG_PCI, j);
|
||||
}
|
||||
|
||||
if((s = hal_get_useful_str(dev->prop, "pci.subsys_vendor"))) hd->sub_vendor.name = new_str(s);
|
||||
if((s = hal_get_useful_str(dev->prop, "pci.subsys_product"))) hd->sub_device.name = new_str(s);
|
||||
|
||||
if((prop = hal_get_str(dev->prop, "linux.sysfs_path"))) hd->sysfs_id = new_str(hd_sysfs_id(prop->val.str));
|
||||
|
||||
if((prop = hal_get_str(dev->prop, "info.linux.driver"))) add_str_list(&hd->drivers, prop->val.str);
|
||||
|
||||
hd->hal_prop = dev->prop;
|
||||
dev->prop = NULL;
|
||||
}
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
!hd->detail ||
|
||||
hd->detail->type != hd_detail_pci ||
|
||||
!(pci = hd->detail->pci.data)
|
||||
) continue;
|
||||
|
||||
pci->next = NULL;
|
||||
}
|
||||
|
||||
hd_data->pci = NULL;
|
||||
}
|
||||
|
||||
|
||||
char *hd_hal_print_prop(hal_prop_t *prop)
|
||||
{
|
||||
static char *s = NULL;
|
||||
str_list_t *sl;
|
||||
|
||||
switch(prop->type) {
|
||||
case p_string:
|
||||
str_printf(&s, 0, "%s = '%s'", prop->key, prop->val.str);
|
||||
break;
|
||||
|
||||
case p_int32:
|
||||
str_printf(&s, 0, "%s = %d (0x%x)", prop->key, prop->val.int32, prop->val.int32);
|
||||
break;
|
||||
|
||||
case p_uint64:
|
||||
str_printf(&s, 0, "%s = %"PRIu64"ull (0x%"PRIx64"ull)", prop->key, prop->val.uint64, prop->val.uint64);
|
||||
break;
|
||||
|
||||
case p_double:
|
||||
str_printf(&s, 0, "%s = %#g", prop->key, prop->val.d);
|
||||
break;
|
||||
|
||||
case p_bool:
|
||||
str_printf(&s, 0, "%s = %s", prop->key, prop->val.b ? "true" : "false");
|
||||
break;
|
||||
|
||||
case p_list:
|
||||
str_printf(&s, 0, "%s = { ", prop->key);
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
str_printf(&s, -1, "'%s'%s", sl->str, sl->next ? ", " : "");
|
||||
}
|
||||
str_printf(&s, -1, " }");
|
||||
break;
|
||||
|
||||
case p_invalid:
|
||||
str_printf(&s, 0, "%s", prop->key);
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Ensure that udi is a sane path name.
|
||||
*
|
||||
* return:
|
||||
* 0/1: fail/ok
|
||||
*/
|
||||
int check_udi(const char *udi)
|
||||
{
|
||||
if(
|
||||
!udi ||
|
||||
!strncmp(udi, "../", sizeof "../" - 1) ||
|
||||
strstr(udi, "/../") ||
|
||||
strstr(udi, "//")
|
||||
) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int hd_write_properties(const char *udi, hal_prop_t *prop)
|
||||
{
|
||||
FILE *f;
|
||||
char *s;
|
||||
|
||||
f = hd_open_properties(udi, "w");
|
||||
|
||||
if(!f) return 1;
|
||||
|
||||
for(; prop; prop = prop->next) {
|
||||
if(prop->type == p_invalid) continue;
|
||||
s = hd_hal_print_prop(prop);
|
||||
if(s) fprintf(f, "%s\n", s);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *hd_read_properties(const char *udi)
|
||||
{
|
||||
char *path = NULL;
|
||||
str_list_t *sl0, *sl;
|
||||
hal_prop_t *prop_list = NULL, *prop_list_e = NULL, prop, *p;
|
||||
|
||||
if(!udi) return NULL;
|
||||
|
||||
while(*udi == '/') udi++;
|
||||
|
||||
if(!check_udi(udi)) return NULL;
|
||||
|
||||
str_printf(&path, 0, "%s/%s", hd_get_hddb_path("udi"), udi);
|
||||
|
||||
sl0 = read_file(path, 0, 0);
|
||||
|
||||
free_mem(path);
|
||||
|
||||
for(sl = sl0; sl; sl = sl->next) {
|
||||
parse_property(&prop, sl->str);
|
||||
if(prop.type != p_invalid) {
|
||||
p = new_mem(sizeof *p);
|
||||
*p = prop;
|
||||
if(prop_list) {
|
||||
prop_list_e->next = p;
|
||||
prop_list_e = prop_list_e->next;
|
||||
}
|
||||
else {
|
||||
prop_list = prop_list_e = p;
|
||||
}
|
||||
}
|
||||
else {
|
||||
prop.key = free_mem(prop.key);
|
||||
}
|
||||
}
|
||||
|
||||
free_str_list(sl0);
|
||||
|
||||
return prop_list;
|
||||
}
|
||||
|
||||
|
||||
FILE *hd_open_properties(const char *udi, const char *mode)
|
||||
{
|
||||
str_list_t *path, *sl;
|
||||
struct stat sbuf;
|
||||
char *dir = NULL;
|
||||
int err, i;
|
||||
FILE *f = NULL;
|
||||
|
||||
if(!udi) return f;
|
||||
while(*udi == '/') udi++;
|
||||
|
||||
if(!check_udi(udi)) return f;
|
||||
|
||||
path = hd_split('/', udi);
|
||||
|
||||
if(!path) return f;
|
||||
|
||||
dir = new_str(hd_get_hddb_path("udi"));
|
||||
|
||||
for(err = 0, sl = path; sl->next; sl = sl->next) {
|
||||
str_printf(&dir, -1, "/%s", sl->str);
|
||||
i = lstat(dir, &sbuf);
|
||||
if(i == -1 && errno == ENOENT) {
|
||||
mkdir(dir, 0755);
|
||||
i = lstat(dir, &sbuf);
|
||||
}
|
||||
if(i || !S_ISDIR(sbuf.st_mode)) {
|
||||
err = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!err) {
|
||||
str_printf(&dir, -1, "/%s", sl->str);
|
||||
f = fopen(dir, mode);
|
||||
}
|
||||
|
||||
free_mem(dir);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
char *skip_space(char *s)
|
||||
{
|
||||
while(isspace(*s)) s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
char *skip_non_eq_or_space(char *s)
|
||||
{
|
||||
while(*s && *s != '=' && !isspace(*s)) s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
char *skip_nonquote(char *s)
|
||||
{
|
||||
while(*s && *s != '\'') s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void parse_property(hal_prop_t *prop, char *str)
|
||||
{
|
||||
char *s, *s1, *key, *s_val;
|
||||
int l;
|
||||
|
||||
memset(prop, 0, sizeof *prop);
|
||||
prop->type = p_invalid;
|
||||
|
||||
s = skip_space(str);
|
||||
s = skip_non_eq_or_space(key = s);
|
||||
|
||||
*s++ = 0;
|
||||
if(!*key) return;
|
||||
|
||||
s = skip_space(s);
|
||||
if(*s == '=') s++;
|
||||
s = skip_space(s);
|
||||
|
||||
prop->key = new_str(key);
|
||||
|
||||
if(!*s) return;
|
||||
|
||||
if(*s == '\'') {
|
||||
s_val = s + 1;
|
||||
s = strrchr(s_val, '\'');
|
||||
*(s ?: s_val) = 0;
|
||||
prop->type = p_string;
|
||||
prop->val.str = strdup(s_val);
|
||||
}
|
||||
else if(*s == '{') {
|
||||
s_val = skip_space(s + 1);
|
||||
s1 = strrchr(s_val, '}');
|
||||
if(s1) *s1 = 0;
|
||||
prop->type = p_list;
|
||||
while(*s_val++ == '\'') {
|
||||
s = skip_nonquote(s_val);
|
||||
if(*s) *s++ = 0;
|
||||
add_str_list(&prop->val.list, s_val);
|
||||
s_val = skip_nonquote(s);
|
||||
}
|
||||
}
|
||||
else if(!strncmp(s, "true", 4)) {
|
||||
s += 4;
|
||||
prop->type = p_bool;
|
||||
prop->val.b = 1;
|
||||
}
|
||||
else if(!strncmp(s, "false", 5)) {
|
||||
s += 5;
|
||||
prop->type = p_bool;
|
||||
prop->val.b = 0;
|
||||
}
|
||||
else if(isdigit(*s) || *s == '+' || *s == '-' || *s == '.') {
|
||||
*skip_non_eq_or_space(s) = 0;
|
||||
if(strchr(s, '.')) {
|
||||
prop->type = p_double;
|
||||
prop->val.d = strtod(s, NULL);
|
||||
}
|
||||
else {
|
||||
l = strlen(s);
|
||||
if(l >= 2 && s[l - 2] == 'l' && s[l - 1] == 'l') {
|
||||
prop->type = p_uint64;
|
||||
s[l -= 2] = 0;
|
||||
}
|
||||
else {
|
||||
prop->type = p_int32;
|
||||
}
|
||||
if(l >= 1 && s[l - 1] == 'u') s[--l] = 0;
|
||||
|
||||
if(prop->type == p_int32) {
|
||||
prop->val.int32 = strtol(s, NULL, 0);
|
||||
}
|
||||
else {
|
||||
prop->val.uint64 = strtoull(s, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hd_scan_hal_assign_udi(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
int i;
|
||||
|
||||
if(!hd_data->hal) return;
|
||||
|
||||
PROGRESS(2, 0, "assign udi");
|
||||
|
||||
for(i = 0; i < 3; i++) {
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) find_udi(hd_data, hd, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void find_udi(hd_data_t *hd_data, hd_t *hd, int match)
|
||||
{
|
||||
hal_device_t *dev;
|
||||
char *h_sysfsid, *h_devname;
|
||||
|
||||
if(hd->udi) return;
|
||||
|
||||
dev = NULL;
|
||||
|
||||
/* device file first, thanks to usb devices */
|
||||
|
||||
/* based on device file */
|
||||
if(
|
||||
!dev &&
|
||||
(
|
||||
(match == 0 && hd->unix_dev_name) ||
|
||||
(match == 1 && hd->unix_dev_name2) ||
|
||||
(match == 2 && hd->unix_dev_names)
|
||||
)
|
||||
) for(dev = hd_data->hal; dev; dev = dev->next) {
|
||||
h_devname = hal_get_useful_str(dev->prop, "linux.device_file");
|
||||
if(!h_devname) h_devname = hal_get_useful_str(dev->prop, "block.device");
|
||||
if(h_devname) {
|
||||
if(match == 0 && hd->unix_dev_name && !strcmp(hd->unix_dev_name, h_devname)) break;
|
||||
if(match == 1 && hd->unix_dev_name2 && !strcmp(hd->unix_dev_name2, h_devname)) break;
|
||||
if(match == 2 && search_str_list(hd->unix_dev_names, h_devname)) break;
|
||||
}
|
||||
}
|
||||
|
||||
/* based on sysfs id, only once for match == 0 */
|
||||
if(!dev && !match && hd->sysfs_id) for(dev = hd_data->hal; dev; dev = dev->next) {
|
||||
h_sysfsid = hd_sysfs_id(hal_get_useful_str(dev->prop, "linux.sysfs_path"));
|
||||
if(h_sysfsid && !strcmp(hd->sysfs_id, h_sysfsid)) break;
|
||||
}
|
||||
|
||||
if(dev) {
|
||||
hd->udi = new_str(dev->udi);
|
||||
hd->hal_prop = dev->prop;
|
||||
dev->prop = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
void hd_scan_hal(hd_data_t *hd_data);
|
||||
void hd_scan_hal_basic(hd_data_t *hd_data);
|
||||
void hd_scan_hal_assign_udi(hd_data_t *hd_data);
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,244 @@
|
|||
#define PROC_CMDLINE "/proc/cmdline"
|
||||
#define PROC_PCI_DEVICES "/proc/bus/pci/devices"
|
||||
#define PROC_PCI_BUS "/proc/bus/pci"
|
||||
#define PROC_CPUINFO "/proc/cpuinfo"
|
||||
#define PROC_IOPORTS "/proc/ioports"
|
||||
#define PROC_DMA "/proc/dma"
|
||||
#define PROC_INTERRUPTS "/proc/interrupts"
|
||||
#define PROC_NVRAM_22 "/proc/driver/nvram"
|
||||
#define PROC_NVRAM_24 "/proc/nvram"
|
||||
#define PROC_IDE "/proc/ide"
|
||||
#define PROC_SCSI "/proc/scsi"
|
||||
#define PROC_CDROM_INFO "/proc/sys/dev/cdrom/info"
|
||||
#define PROC_NET_IF_INFO "/proc/net/dev"
|
||||
#define PROC_MODULES "/proc/modules"
|
||||
#define PROC_DRIVER_SERIAL "/proc/tty/driver/serial"
|
||||
#define PROC_DRIVER_MACSERIAL "/proc/tty/driver/macserial"
|
||||
#define PROC_PARPORT_22 "/proc/parport/" /* Final '/' is essential! */
|
||||
#define PROC_PARPORT_24 "/proc/sys/dev/parport/parport"
|
||||
#define PROC_KCORE "/proc/kcore"
|
||||
// #define PROC_USB_DEVICES "/proc/bus/usb/devices"
|
||||
#define PROC_USB_DEVICES "/proc/bus/usb/devices_please-use-sysfs-instead"
|
||||
#define PROC_PROM "/proc/device-tree"
|
||||
#define PROC_MEMINFO "/proc/meminfo"
|
||||
#define PROC_VERSION "/proc/version"
|
||||
#define PROC_ISAPNP "/proc/isapnp"
|
||||
#define PROC_PARTITIONS "/proc/partitions"
|
||||
#define PROC_APM "/proc/apm"
|
||||
#define PROC_XEN_BALLOON "/proc/xen/balloon"
|
||||
|
||||
#define DEV_NVRAM "/dev/nvram"
|
||||
#define DEV_PSAUX "/dev/psaux"
|
||||
#define DEV_ADBMOUSE "/dev/adbmouse"
|
||||
#define DEV_MEM "/dev/mem"
|
||||
#define DEV_KBD "/dev/kbd"
|
||||
#define DEV_CONSOLE "/dev/console"
|
||||
#define DEV_OPENPROM "/dev/openprom"
|
||||
#define DEV_SUNMOUSE "/dev/sunmouse"
|
||||
#define DEV_MICE "/dev/input/mice"
|
||||
#define DEV_FB "/dev/fb"
|
||||
#define DEV_FB0 "/dev/fb0"
|
||||
|
||||
#define PROG_MODPROBE "/sbin/modprobe"
|
||||
#define PROG_RMMOD "/sbin/rmmod"
|
||||
#define PROG_CARDCTL "/sbin/cardctl"
|
||||
#define PROG_UDEVINFO "/usr/bin/udevinfo"
|
||||
#define PROG_UDEVADM "/usr/bin/udevadm"
|
||||
|
||||
#define KLOG_BOOT "/var/log/boot.msg"
|
||||
#define ISAPNP_CONF "/etc/isapnp.conf"
|
||||
|
||||
#define KERNEL_22 0x020200
|
||||
#define KERNEL_24 0x020400
|
||||
#define KERNEL_26 0x020600
|
||||
|
||||
#if defined(__s390__) || defined(__s390x__) || defined(__alpha__) || defined(LIBHD_TINY)
|
||||
#define WITH_ISDN 0
|
||||
#else
|
||||
#define WITH_ISDN 1
|
||||
#endif
|
||||
|
||||
// maximum attribute size in sysfs we expect
|
||||
// (this is to avoid accidentally reading unlimited data)
|
||||
#define MAX_ATTR_SIZE 0x10000
|
||||
|
||||
#define PROGRESS(a, b, c) progress(hd_data, a, b, c)
|
||||
#define ADD2LOG(a...) hd_log_printf(hd_data, a)
|
||||
|
||||
/*
|
||||
* define to make (hd_t).unique_id a hex string, otherwise it is a
|
||||
* base64-like string
|
||||
*/
|
||||
#undef NUMERIC_UNIQUE_ID
|
||||
|
||||
/*
|
||||
* Internal probing module numbers. Use mod_name_by_idx() outside of libhd.
|
||||
*/
|
||||
enum mod_idx {
|
||||
mod_none, mod_memory, mod_pci, mod_isapnp, mod_pnpdump, mod_net,
|
||||
mod_floppy, mod_misc, mod_bios, mod_cpu, mod_monitor, mod_mouse, mod_scsi,
|
||||
mod_serial, mod_usb, mod_adb, mod_modem, mod_parallel, mod_isa, mod_isdn,
|
||||
mod_kbd, mod_prom, mod_sbus, mod_int, mod_braille, mod_xtra, mod_sys,
|
||||
mod_manual, mod_fb, mod_veth, mod_pppoe, mod_pcmcia, mod_s390,
|
||||
mod_sysfs, mod_dsl, mod_block, mod_edd, mod_input, mod_wlan, mod_hal
|
||||
};
|
||||
|
||||
void *new_mem(size_t size);
|
||||
void *resize_mem(void *, size_t);
|
||||
void *add_mem(void *, size_t, size_t);
|
||||
char *new_str(const char *);
|
||||
void *free_mem(void *);
|
||||
int have_common_res(hd_res_t *res1, hd_res_t *res2);
|
||||
void join_res_io(hd_res_t **res1, hd_res_t *res2);
|
||||
void join_res_irq(hd_res_t **res1, hd_res_t *res2);
|
||||
void join_res_dma(hd_res_t **res1, hd_res_t *res2);
|
||||
hd_res_t *free_res_list(hd_res_t *res);
|
||||
hd_res_t *add_res_entry(hd_res_t **res, hd_res_t *new_res);
|
||||
hd_t *add_hd_entry(hd_data_t *hd_data, unsigned line, unsigned count);
|
||||
misc_t *free_misc(misc_t *m);
|
||||
scsi_t *free_scsi(scsi_t *scsi, int free_all);
|
||||
hd_detail_t *free_hd_detail(hd_detail_t *d);
|
||||
devtree_t *free_devtree(hd_data_t *hd_data);
|
||||
void hd_add_id(hd_data_t *hd_data, hd_t *hd);
|
||||
|
||||
char *isa_id2str(unsigned);
|
||||
char *eisa_vendor_str(unsigned);
|
||||
unsigned name2eisa_id(char *);
|
||||
char *canon_str(char *, int);
|
||||
|
||||
int hex(char *string, int digits);
|
||||
|
||||
void hd_log(hd_data_t *hd_data, char *buf, ssize_t len);
|
||||
void hd_log_printf(hd_data_t *hd_data, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
void hd_log_hex(hd_data_t *hd_data, int with_ascii, unsigned data_len, unsigned char *data);
|
||||
|
||||
void str_printf(char **buf, int offset, char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
void hexdump(char **buf, int with_ascii, unsigned data_len, unsigned char *data);
|
||||
str_list_t *search_str_list(str_list_t *sl, char *str);
|
||||
str_list_t *add_str_list(str_list_t **sl, char *str);
|
||||
str_list_t *free_str_list(str_list_t *list);
|
||||
str_list_t *reverse_str_list(str_list_t *list);
|
||||
str_list_t *read_file(char *file_name, unsigned start_line, unsigned lines);
|
||||
str_list_t *read_dir(char *dir_name, int type);
|
||||
char *hd_read_sysfs_link(char *base_dir, char *link_name);
|
||||
void progress(hd_data_t *hd_data, unsigned pos, unsigned count, char *msg);
|
||||
|
||||
void remove_hd_entries(hd_data_t *hd_data);
|
||||
void remove_tagged_hd_entries(hd_data_t *hd_data);
|
||||
|
||||
driver_info_t *free_driver_info(driver_info_t *di);
|
||||
|
||||
int str2float(char *s, int n);
|
||||
char *float2str(int i, int n);
|
||||
|
||||
/* return the file name of a module */
|
||||
char *mod_name_by_idx(unsigned idx);
|
||||
|
||||
int hd_timeout(void(*func)(void *), void *arg, int timeout);
|
||||
|
||||
str_list_t *read_kmods(hd_data_t *hd_data);
|
||||
char *get_cmd_param(hd_data_t *hd_data, int field);
|
||||
|
||||
#ifdef __i386__
|
||||
/* smp/smp.c */
|
||||
int detectSMP(void);
|
||||
#endif
|
||||
|
||||
void update_irq_usage(hd_data_t *hd_data);
|
||||
int run_cmd(hd_data_t *hd_data, char *cmd);
|
||||
int load_module_with_params(hd_data_t *hd_data, char *module, char *params);
|
||||
int load_module(hd_data_t *hd_data, char *module);
|
||||
int unload_module(hd_data_t *hd_data, char *module);
|
||||
int probe_module(hd_data_t *hd_data, char *module);
|
||||
|
||||
int cmp_hd(hd_t *hd1, hd_t *hd2);
|
||||
unsigned has_something_attached(hd_data_t *hd_data, hd_t *hd);
|
||||
|
||||
str_list_t *get_cmdline(hd_data_t *hd_data, char *key);
|
||||
|
||||
int detect_smp_bios(hd_data_t *hd_data);
|
||||
int detect_smp_prom(hd_data_t *hd_data);
|
||||
|
||||
unsigned char *read_block0(hd_data_t *hd_data, char *dev, int *timeout);
|
||||
|
||||
void hd_copy(hd_t *dst, hd_t *src);
|
||||
|
||||
/* parameter for gather_resources(,,, which) */
|
||||
#define W_IO (1 << 0)
|
||||
#define W_DMA (1 << 1)
|
||||
#define W_IRQ (1 << 2)
|
||||
|
||||
void gather_resources(misc_t *m, hd_res_t **r, char *name, unsigned which);
|
||||
|
||||
char *vend_id2str(unsigned vend);
|
||||
|
||||
int hd_getdisksize(hd_data_t *hd_data, char *dev, int fd, hd_res_t **geo, hd_res_t **size);
|
||||
|
||||
str_list_t *hd_split(char del, const char *str);
|
||||
char *hd_join(char *del, str_list_t *str);
|
||||
|
||||
int is_pnpinfo(ser_device_t *mi, int ofs);
|
||||
|
||||
int is_pcmcia_ctrl(hd_data_t *hd_data, hd_t *hd);
|
||||
|
||||
void hd_fork(hd_data_t *hd_data, int timeout, int total_timeout);
|
||||
void hd_fork_done(hd_data_t *hd_data);
|
||||
void hd_shm_init(hd_data_t *hd_data);
|
||||
void hd_shm_clean(hd_data_t *hd_data);
|
||||
void hd_shm_done(hd_data_t *hd_data);
|
||||
void *hd_shm_add(hd_data_t *hd_data, void *ptr, unsigned len);
|
||||
int hd_is_shm_ptr(hd_data_t *hd_data, void *ptr);
|
||||
void hd_move_to_shm(hd_data_t *hd_data);
|
||||
|
||||
void read_udevinfo(hd_data_t *hd_data);
|
||||
|
||||
hd_t *hd_find_sysfs_id(hd_data_t *hd_data, char *id);
|
||||
hd_t *hd_find_sysfs_id_devname(hd_data_t *hd_data, char *id, char *devname);
|
||||
int hd_attr_uint(char* attr, uint64_t* u, int base);
|
||||
str_list_t *hd_attr_list(char *str);
|
||||
char *hd_sysfs_id(char *path);
|
||||
char *hd_sysfs_name2_dev(char *str);
|
||||
char *hd_sysfs_dev2_name(char *str);
|
||||
void hd_sysfs_driver_list(hd_data_t *hd_data);
|
||||
char *hd_sysfs_find_driver(hd_data_t *hd_data, char *sysfs_id, int exact);
|
||||
int hd_report_this(hd_data_t *hd_data, hd_t *hd);
|
||||
str_list_t *hd_module_list(hd_data_t *hd_data, unsigned id);
|
||||
|
||||
char* get_sysfs_attr(const char* bus, const char* device, const char* attr);
|
||||
char *get_sysfs_attr_by_path(const char *path, const char *attr);
|
||||
char *get_sysfs_attr_by_path2(const char *path, const char *attr, unsigned *len);
|
||||
|
||||
void hd_pci_complete_data(hd_t *hd);
|
||||
void hd_pci_read_data(hd_data_t *hd_data);
|
||||
|
||||
hal_device_t *hd_free_hal_devices(hal_device_t *dev);
|
||||
char *hd_hal_print_prop(hal_prop_t *prop);
|
||||
|
||||
void hal_invalidate(hal_prop_t *prop);
|
||||
void hal_invalidate_all(hal_prop_t *prop, const char *key);
|
||||
hal_prop_t *hal_get_any(hal_prop_t *prop, const char *key);
|
||||
hal_prop_t *hal_get_bool(hal_prop_t *prop, const char *key);
|
||||
hal_prop_t *hal_get_int32(hal_prop_t *prop, const char *key);
|
||||
hal_prop_t *hal_get_str(hal_prop_t *prop, const char *key);
|
||||
hal_prop_t *hal_get_list(hal_prop_t *prop, const char *key);
|
||||
char *hal_get_useful_str(hal_prop_t *prop, const char *key);
|
||||
|
||||
hal_device_t *hal_find_device(hd_data_t *hd_data, char *udi);
|
||||
hal_prop_t *hal_add_new(hal_prop_t **prop);
|
||||
|
||||
char *hd_get_hddb_dir(void);
|
||||
char *hd_get_hddb_path(char *sub);
|
||||
|
||||
int hd_mod_cmp(char *str1, char *str2);
|
||||
|
||||
int get_probe_val_int(hd_data_t *hd_data, enum probe_feature feature);
|
||||
char *get_probe_val_str(hd_data_t *hd_data, enum probe_feature feature);
|
||||
str_list_t *get_probe_val_list(hd_data_t *hd_data, enum probe_feature feature);
|
||||
|
||||
str_list_t *sort_str_list(str_list_t *sl0, int (*cmp_func)(const void *, const void *));
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
void hddb_init(hd_data_t *hd_data);
|
||||
|
||||
unsigned device_class(hd_data_t *hd_data, unsigned vendor, unsigned device);
|
||||
unsigned sub_device_class(hd_data_t *hd_data, unsigned vendor, unsigned device, unsigned sub_vendor, unsigned sub_device);
|
||||
|
||||
char *hid_tag_name(int tag);
|
||||
char *hid_tag_name2(int tag);
|
|
@ -0,0 +1,56 @@
|
|||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*
|
||||
* type defs for internal data base
|
||||
*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#define DATA_VALUE(a) ((a) & ~(-1 << 28))
|
||||
#define DATA_FLAG(a) (((a) >> 28) & 0xf)
|
||||
#define MAKE_DATA(a, b) ((a << 28) | (b))
|
||||
|
||||
#define FLAG_ID 0
|
||||
#define FLAG_RANGE 1
|
||||
#define FLAG_MASK 2
|
||||
#define FLAG_STRING 3
|
||||
#define FLAG_REGEXP 4
|
||||
/* 5 - 7 reserved */
|
||||
#define FLAG_CONT 8 /* bit mask, _must_ be bit 31 */
|
||||
|
||||
|
||||
typedef enum hddb_entry_e {
|
||||
he_other, he_bus_id, he_baseclass_id, he_subclass_id, he_progif_id,
|
||||
he_vendor_id, he_device_id, he_subvendor_id, he_subdevice_id, he_rev_id,
|
||||
he_bus_name, he_baseclass_name, he_subclass_name, he_progif_name,
|
||||
he_vendor_name, he_device_name, he_subvendor_name, he_subdevice_name,
|
||||
he_rev_name, he_serial, he_driver, he_requires,
|
||||
he_detail_ccw_data_cu_model, he_hwclass /* 23 */,
|
||||
|
||||
/* add new entries _here_! */
|
||||
|
||||
he_nomask,
|
||||
|
||||
/* if he_nomask exceeds 31, adjust entry_mask_t & hddb_entry_mask_t */
|
||||
|
||||
he_class_id = he_nomask, he_driver_module_insmod, he_driver_module_modprobe,
|
||||
he_driver_module_config, he_driver_xfree, he_driver_xfree_config,
|
||||
he_driver_mouse, he_driver_display, he_driver_any
|
||||
} hddb_entry_t;
|
||||
|
||||
static hddb_entry_t hddb_is_numeric[] = {
|
||||
he_bus_id, he_baseclass_id, he_subclass_id, he_progif_id, he_vendor_id,
|
||||
he_device_id, he_subvendor_id, he_subdevice_id, he_rev_id,
|
||||
he_detail_ccw_data_cu_model, he_hwclass
|
||||
};
|
||||
|
||||
static char *hddb_entry_strings[] = {
|
||||
"other", "bus.id", "baseclass.id", "subclass.id", "progif.id",
|
||||
"vendor.id", "device.id", "subvendor.id", "subdevice.id", "rev.id",
|
||||
"bus.name", "baseclass.name", "subclass.name", "progif.name",
|
||||
"vendor.name", "device.name", "subvendor.name", "subdevice.name",
|
||||
"rev.name", "serial", "driver", "requires",
|
||||
"detail.ccw.data.cu_model", "hwclass",
|
||||
"class.id", "driver.module.insmod", "driver.module.modprobe",
|
||||
"driver.module.config", "driver.xfree", "driver.xfree.config",
|
||||
"driver.mouse", "driver.display", "driver.any"
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,96 @@
|
|||
typedef struct {
|
||||
int key;
|
||||
char *value;
|
||||
} hash_t;
|
||||
|
||||
static char *key2value(hash_t *hash, int id);
|
||||
static int value2key(hash_t *hash, char *str);
|
||||
|
||||
/* corresponds to hd_hw_item_t */
|
||||
static hash_t hw_items[] = {
|
||||
{ hw_sys, "system" },
|
||||
{ hw_cpu, "cpu" },
|
||||
{ hw_keyboard, "keyboard" },
|
||||
{ hw_braille, "braille" },
|
||||
{ hw_mouse, "mouse" },
|
||||
{ hw_joystick, "joystick" },
|
||||
{ hw_printer, "printer" },
|
||||
{ hw_scanner, "scanner" },
|
||||
{ hw_chipcard, "chipcard" },
|
||||
{ hw_monitor, "monitor" },
|
||||
{ hw_tv, "tv card" },
|
||||
{ hw_display, "graphics card" },
|
||||
{ hw_framebuffer, "framebuffer" },
|
||||
{ hw_camera, "camera" },
|
||||
{ hw_sound, "sound" },
|
||||
{ hw_storage_ctrl, "storage" },
|
||||
{ hw_network_ctrl, "network" },
|
||||
{ hw_isdn, "isdn adapter" },
|
||||
{ hw_modem, "modem" },
|
||||
{ hw_network, "network interface" },
|
||||
{ hw_disk, "disk" },
|
||||
{ hw_partition, "partition" },
|
||||
{ hw_cdrom, "cdrom" },
|
||||
{ hw_floppy, "floppy" },
|
||||
{ hw_manual, "manual" },
|
||||
{ hw_usb_ctrl, "usb controller" },
|
||||
{ hw_usb, "usb" },
|
||||
{ hw_bios, "bios" },
|
||||
{ hw_pci, "pci" },
|
||||
{ hw_isapnp, "isapnp" },
|
||||
{ hw_bridge, "bridge" },
|
||||
{ hw_hub, "hub" },
|
||||
{ hw_scsi, "scsi" },
|
||||
{ hw_ide, "ide" },
|
||||
{ hw_memory, "memory" },
|
||||
{ hw_dvb, "dvb card" },
|
||||
{ hw_pcmcia, "pcmcia" },
|
||||
{ hw_pcmcia_ctrl, "pcmcia controller" },
|
||||
{ hw_ieee1394, "firewire" },
|
||||
{ hw_ieee1394_ctrl, "firewire controller" },
|
||||
{ hw_hotplug, "hotplug" },
|
||||
{ hw_hotplug_ctrl, "hotplug controller" },
|
||||
{ hw_zip, "zip" },
|
||||
{ hw_pppoe, "pppoe" },
|
||||
{ hw_wlan, "wlan card" },
|
||||
{ hw_redasd, "redasd" },
|
||||
{ hw_dsl, "dsl adapter" },
|
||||
{ hw_block, "block device" },
|
||||
{ hw_tape, "tape" },
|
||||
{ hw_vbe, "vesa bios" },
|
||||
{ hw_bluetooth, "bluetooth" },
|
||||
{ hw_unknown, "unknown" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
int value2key(hash_t *hash, char *str)
|
||||
{
|
||||
for(; hash->value; hash++) {
|
||||
if(!strcmp(hash->value, str)) break;
|
||||
}
|
||||
|
||||
return hash->key;
|
||||
}
|
||||
|
||||
char *key2value(hash_t *hash, int id)
|
||||
{
|
||||
for(; hash->value; hash++) {
|
||||
if(hash->key == id) break;
|
||||
}
|
||||
|
||||
return hash->value;
|
||||
}
|
||||
|
||||
|
||||
char *hd_hw_item_name(hd_hw_item_t item)
|
||||
{
|
||||
return key2value(hw_items, item);
|
||||
}
|
||||
|
||||
|
||||
hd_hw_item_t hd_hw_item_type(char *name)
|
||||
{
|
||||
return name ? value2key(hw_items, name) : hw_none;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,456 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "hddb.h"
|
||||
#include "input.h"
|
||||
|
||||
/**
|
||||
* @defgroup INPUTint Input devices
|
||||
* @ingroup libhdDEVint
|
||||
* @brief Input device scan functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
static void get_input_devices(hd_data_t *hd_data);
|
||||
static char *all_bits(char *str);
|
||||
static int test_bit(const char *str, unsigned bit);
|
||||
|
||||
void hd_scan_input(hd_data_t *hd_data)
|
||||
{
|
||||
if(!hd_probe_feature(hd_data, pr_input)) return;
|
||||
|
||||
hd_data->module = mod_input;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "joydev mod");
|
||||
load_module(hd_data, "joydev");
|
||||
|
||||
PROGRESS(1, 1, "evdev mod");
|
||||
load_module(hd_data, "evdev");
|
||||
|
||||
PROGRESS(2, 0, "input");
|
||||
|
||||
get_input_devices(hd_data);
|
||||
}
|
||||
|
||||
// note: hd_data parameter is needed for ADD2LOG macro
|
||||
void add_joystick_details(hd_data_t *hd_data, hd_t *h, const char *key, const char *abso)
|
||||
{
|
||||
// replace existing details
|
||||
if (h->detail)
|
||||
{
|
||||
free_hd_detail(h->detail);
|
||||
}
|
||||
|
||||
// add buttons and axis details
|
||||
h->detail = new_mem(sizeof *h->detail);
|
||||
h->detail->type = hd_detail_joystick;
|
||||
|
||||
joystick_t *jt = new_mem(sizeof jt);
|
||||
unsigned u;
|
||||
|
||||
if(key) {
|
||||
for(u = BTN_JOYSTICK; u < BTN_JOYSTICK + 16; u++) {
|
||||
if(test_bit(key, u)) jt->buttons++;
|
||||
}
|
||||
}
|
||||
ADD2LOG(" joystick buttons = %u\n", jt->buttons);
|
||||
|
||||
if(abso) {
|
||||
for(u = ABS_X; u < ABS_VOLUME; u++) {
|
||||
if(test_bit(abso, u)) jt->axes++;
|
||||
}
|
||||
}
|
||||
ADD2LOG(" joystick axes = %u\n", jt->axes);
|
||||
|
||||
h->detail->joystick.data = jt;
|
||||
}
|
||||
|
||||
#define INP_NAME "N: Name="
|
||||
#define INP_HANDLERS "H: Handlers="
|
||||
#define INP_KEY "B: KEY="
|
||||
#define INP_REL "B: REL="
|
||||
#define INP_ABS "B: ABS="
|
||||
|
||||
void get_input_devices(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
str_list_t *input, *sl, *sl1;
|
||||
char *s;
|
||||
unsigned ok, u, is_mouse, is_joystick;
|
||||
unsigned bus, vendor, product, version;
|
||||
unsigned mouse_buttons, mouse_wheels;
|
||||
char *name = NULL, *handlers = NULL, *key = NULL, *rel = NULL, *abso = NULL;
|
||||
size_t len;
|
||||
str_list_t *handler_list;
|
||||
hd_dev_num_t dev_num = { type: 'c', range: 1 };
|
||||
|
||||
input = read_file("/proc/bus/input/devices", 0, 0);
|
||||
|
||||
ADD2LOG("----- /proc/bus/input/devices -----\n");
|
||||
for(sl = input; sl; sl = sl->next) {
|
||||
ADD2LOG(" %s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- /proc/bus/input/devices end -----\n");
|
||||
|
||||
for(ok = 0, sl = input; sl; sl = sl->next) {
|
||||
if(*sl->str == '\n') {
|
||||
ADD2LOG("bus = %u, name = %s\n", bus, name);
|
||||
if(handlers) ADD2LOG(" handlers = %s\n", handlers);
|
||||
if(key) ADD2LOG(" key = %s\n", key);
|
||||
if(rel) ADD2LOG(" rel = %s\n", rel);
|
||||
if(abso) ADD2LOG(" abs = %s\n", abso);
|
||||
|
||||
mouse_buttons = 0;
|
||||
if(key) {
|
||||
for(u = BTN_MOUSE; u < BTN_MOUSE + 8; u++) {
|
||||
if(test_bit(key, u)) mouse_buttons++;
|
||||
}
|
||||
}
|
||||
ADD2LOG(" mouse buttons = %u\n", mouse_buttons);
|
||||
|
||||
mouse_wheels = 0;
|
||||
if(rel) {
|
||||
for(u = REL_HWHEEL; u <= REL_MAX; u++) {
|
||||
if(test_bit(rel, u)) mouse_wheels++;
|
||||
}
|
||||
}
|
||||
ADD2LOG(" mouse wheels = %u\n", mouse_wheels);
|
||||
|
||||
if(ok && handlers) {
|
||||
handler_list = hd_split(' ', handlers);
|
||||
|
||||
is_mouse = strstr(handlers, "mouse") ? 1 : 0;
|
||||
is_joystick = strstr(handlers, "js") ? 1 : 0;
|
||||
|
||||
if( // HP Virtual Management Device
|
||||
vendor == 0x03f0 &&
|
||||
product == 0x1126 &&
|
||||
mouse_buttons >= 3
|
||||
) is_mouse = 1;
|
||||
|
||||
ADD2LOG(" is_mouse = %u\n", is_mouse);
|
||||
ADD2LOG(" is_joystick = %u\n", is_joystick);
|
||||
|
||||
if(bus == BUS_USB) {
|
||||
s = NULL;
|
||||
for(sl1 = handler_list; sl1; sl1 = sl1->next) {
|
||||
if(sscanf(sl1->str, "mouse%u", &u) == 1) {
|
||||
str_printf(&s, 0, "/dev/input/mouse%u", u);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!s && (is_mouse || is_joystick)) for(sl1 = handler_list; sl1; sl1 = sl1->next) {
|
||||
if(sscanf(sl1->str, "event%u", &u) == 1) {
|
||||
str_printf(&s, 0, "/dev/input/event%u", u);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(s) {
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
(hd->unix_dev_name2 && !strcmp(hd->unix_dev_name2, s)) ||
|
||||
(hd->unix_dev_name && !strcmp(hd->unix_dev_name, s))
|
||||
) {
|
||||
if(!hd->base_class.id) {
|
||||
if (is_mouse)
|
||||
{
|
||||
hd->base_class.id = bc_mouse;
|
||||
hd->sub_class.id = sc_mou_usb;
|
||||
}
|
||||
else if (is_joystick)
|
||||
{
|
||||
hd->base_class.id = bc_joystick;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_mouse)
|
||||
{
|
||||
hd_set_hw_class(hd, hw_mouse);
|
||||
hd->compat_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0210);
|
||||
hd->compat_device.id = MAKE_ID(TAG_SPECIAL, (mouse_wheels << 4) + mouse_buttons);
|
||||
}
|
||||
else if (is_joystick)
|
||||
{
|
||||
hd_set_hw_class(hd, hw_joystick);
|
||||
|
||||
/* add buttons and axis details */
|
||||
add_joystick_details(hd_data, hd, key, abso);
|
||||
}
|
||||
|
||||
if(hd->unix_dev_name) add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
|
||||
if(hd->unix_dev_name2) add_str_list(&hd->unix_dev_names, hd->unix_dev_name2);
|
||||
|
||||
for(sl1 = handler_list; sl1; sl1 = sl1->next) {
|
||||
if(sscanf(sl1->str, "event%u", &u) == 1) {
|
||||
str_printf(&s, 0, "/dev/input/event%u", u);
|
||||
if(!search_str_list(hd->unix_dev_names, s)) add_str_list(&hd->unix_dev_names, s);
|
||||
s = free_mem(s);
|
||||
}
|
||||
/* add /dev/input/jsN joystick device name */
|
||||
else if (is_joystick)
|
||||
{
|
||||
if(sscanf(sl1->str, "js%u", &u) == 1) {
|
||||
str_printf(&s, 0, "/dev/input/js%u", u);
|
||||
if(!search_str_list(hd->unix_dev_names, s)) add_str_list(&hd->unix_dev_names, s);
|
||||
if(!hd->unix_dev_name2) hd->unix_dev_name2 = new_str(s);
|
||||
s = free_mem(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s = free_mem(s);
|
||||
|
||||
}
|
||||
else {
|
||||
// keyboard
|
||||
if(search_str_list(handler_list, "kbd") && test_bit(key, KEY_1)) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_keyboard;
|
||||
hd->sub_class.id = sc_keyboard_kbd;
|
||||
hd->bus.id = bus_ps2;
|
||||
|
||||
hd->vendor.id = MAKE_ID(0, vendor);
|
||||
hd->device.id = MAKE_ID(0, product);
|
||||
hd->compat_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0211);
|
||||
hd->compat_device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
|
||||
hd->device.name = new_str(name);
|
||||
|
||||
for(sl1 = handler_list; sl1; sl1 = sl1->next) {
|
||||
if(sscanf(sl1->str, "event%u", &u) == 1) {
|
||||
str_printf(&hd->unix_dev_name, 0, "/dev/input/event%u", u);
|
||||
dev_num.major = 13;
|
||||
dev_num.minor = 64 + u;
|
||||
hd->unix_dev_num = dev_num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// mouse
|
||||
else if(is_mouse) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
|
||||
hd->vendor.id = MAKE_ID(0, vendor);
|
||||
hd->device.id = MAKE_ID(0, product);
|
||||
|
||||
hd->compat_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0210);
|
||||
hd->compat_device.id = MAKE_ID(TAG_SPECIAL, (mouse_wheels << 4) + mouse_buttons);
|
||||
|
||||
hd->base_class.id = bc_mouse;
|
||||
if(bus == BUS_ADB) {
|
||||
hd->sub_class.id = sc_mou_bus;
|
||||
hd->bus.id = bus_adb;
|
||||
}
|
||||
else {
|
||||
hd->sub_class.id = sc_mou_ps2;
|
||||
hd->bus.id = bus_ps2;
|
||||
}
|
||||
|
||||
hd->device.name = new_str(name);
|
||||
|
||||
#if 0
|
||||
/* Synaptics/Alps TouchPad */
|
||||
if(
|
||||
vendor == 2 &&
|
||||
(product == 7 || product == 8) &&
|
||||
test_bit(abso, ABS_X) &&
|
||||
test_bit(abso, ABS_Y) &&
|
||||
test_bit(abso, ABS_PRESSURE) &&
|
||||
test_bit(key, BTN_TOOL_FINGER)
|
||||
) {
|
||||
}
|
||||
#endif
|
||||
|
||||
hd->unix_dev_name = new_str(DEV_MICE);
|
||||
dev_num.major = 13;
|
||||
dev_num.minor = 63;
|
||||
hd->unix_dev_num = dev_num;
|
||||
|
||||
for(sl1 = handler_list; sl1; sl1 = sl1->next) {
|
||||
if(sscanf(sl1->str, "mouse%u", &u) == 1) {
|
||||
str_printf(&hd->unix_dev_name2, 0, "/dev/input/mouse%u", u);
|
||||
dev_num.major = 13;
|
||||
dev_num.minor = 32 + u;
|
||||
hd->unix_dev_num2 = dev_num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
|
||||
add_str_list(&hd->unix_dev_names, hd->unix_dev_name2);
|
||||
|
||||
for(sl1 = handler_list; sl1; sl1 = sl1->next) {
|
||||
if(sscanf(sl1->str, "event%u", &u) == 1) {
|
||||
s = NULL;
|
||||
str_printf(&s, 0, "/dev/input/event%u", u);
|
||||
add_str_list(&hd->unix_dev_names, s);
|
||||
s = free_mem(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// joystick
|
||||
else if(is_joystick) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
|
||||
hd->vendor.id = MAKE_ID(0, vendor);
|
||||
hd->device.id = MAKE_ID(0, product);
|
||||
|
||||
hd_set_hw_class(hd, hw_joystick);
|
||||
hd->base_class.id = bc_joystick;
|
||||
hd->device.name = new_str(name);
|
||||
|
||||
// gameport? (see <linux/input.h>)
|
||||
if (bus == BUS_GAMEPORT) hd->bus.id = bus_gameport;
|
||||
|
||||
/* add buttons and axis details */
|
||||
add_joystick_details(hd_data, hd, key, abso);
|
||||
|
||||
// add eventX device
|
||||
for(sl1 = handler_list; sl1; sl1 = sl1->next) {
|
||||
if(sscanf(sl1->str, "event%u", &u) == 1) {
|
||||
str_printf(&hd->unix_dev_name, 0, "/dev/input/event%u", u);
|
||||
dev_num.major = 13;
|
||||
dev_num.minor = 64 + u;
|
||||
hd->unix_dev_num = dev_num;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add jsX device
|
||||
for(sl1 = handler_list; sl1; sl1 = sl1->next) {
|
||||
if(sscanf(sl1->str, "js%u", &u) == 1) {
|
||||
str_printf(&hd->unix_dev_name2, 0, "/dev/input/js%u", u);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
|
||||
add_str_list(&hd->unix_dev_names, hd->unix_dev_name2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ADD2LOG("unknown non-USB input device\n");
|
||||
}
|
||||
}
|
||||
|
||||
handler_list = free_str_list(handler_list);
|
||||
}
|
||||
|
||||
ok = 0;
|
||||
|
||||
name = free_mem(name);
|
||||
handlers = free_mem(handlers);
|
||||
key = free_mem(key);
|
||||
rel = free_mem(rel);
|
||||
abso = free_mem(abso);
|
||||
}
|
||||
|
||||
if(sscanf(sl->str, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x", &bus, &vendor, &product, &version) == 4) {
|
||||
ok = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(sl->str, INP_NAME, sizeof INP_NAME - 1)) {
|
||||
s = sl->str + sizeof INP_NAME;
|
||||
len = strlen(s);
|
||||
if(len > 2) {
|
||||
name = canon_str(s, len - 2);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(sl->str, INP_HANDLERS, sizeof INP_HANDLERS - 1)) {
|
||||
s = sl->str + sizeof INP_HANDLERS - 1;
|
||||
handlers = canon_str(s, strlen(s));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(sl->str, INP_KEY, sizeof INP_KEY - 1)) {
|
||||
s = sl->str + sizeof INP_KEY - 1;
|
||||
key = canon_str(s, strlen(s));
|
||||
key = all_bits(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(sl->str, INP_REL, sizeof INP_REL - 1)) {
|
||||
s = sl->str + sizeof INP_REL - 1;
|
||||
rel = canon_str(s, strlen(s));
|
||||
rel = all_bits(rel);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(sl->str, INP_ABS, sizeof INP_ABS - 1)) {
|
||||
s = sl->str + sizeof INP_ABS - 1;
|
||||
abso = canon_str(s, strlen(s));
|
||||
abso = all_bits(abso);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
free_str_list(input);
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *all_bits(char *str)
|
||||
{
|
||||
str_list_t *sl, *sl0;
|
||||
char *s = NULL;
|
||||
unsigned long u;
|
||||
|
||||
if(!str) return NULL;
|
||||
|
||||
sl = sl0 = hd_split(' ', str);
|
||||
for(; sl; sl = sl->next) {
|
||||
u = strtoul(sl->str, NULL, 16);
|
||||
str_printf(&s, -1, "%0*lx", (int) sizeof (unsigned long) * 2, u);
|
||||
}
|
||||
free_str_list(sl0);
|
||||
free_mem(str);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int test_bit(const char *str, unsigned bit)
|
||||
{
|
||||
size_t len, ofs;
|
||||
unsigned u, mask;
|
||||
|
||||
if(!str) return 0;
|
||||
|
||||
len = strlen(str);
|
||||
|
||||
ofs = bit >> 2;
|
||||
mask = 1 << (bit & 3);
|
||||
|
||||
if(ofs >= len) return 0;
|
||||
|
||||
ofs = len - ofs - 1;
|
||||
|
||||
u = str[ofs] >= 'a' ? str[ofs] - 'a' + 10 : str[ofs] - '0';
|
||||
|
||||
return (u & mask) ? 1 : 0;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_input(hd_data_t *hd_data);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
void hd_scan_int(hd_data_t *hd_data);
|
|
@ -0,0 +1,118 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "isa.h"
|
||||
|
||||
/**
|
||||
* @defgroup ISAint ISA
|
||||
* @ingroup libhdBUSint
|
||||
* @brief ISA bus scan functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
static void scan_isa_isdn(hd_data_t *hd_data);
|
||||
static isa_isdn_t *free_isa_isdn(isa_isdn_t *ii);
|
||||
|
||||
static void dump_isa_isdn_data(hd_data_t *hd_data, isa_isdn_t *ii);
|
||||
|
||||
void hd_scan_isa(hd_data_t *hd_data)
|
||||
{
|
||||
if(!hd_probe_feature(hd_data, pr_isa)) return;
|
||||
|
||||
hd_data->module = mod_isa;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
// hd_data->isa = NULL;
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_isa_isdn)) {
|
||||
scan_isa_isdn(hd_data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void scan_isa_isdn(hd_data_t *hd_data)
|
||||
{
|
||||
isa_isdn_t *ii0, *ii;
|
||||
hd_t *hd;
|
||||
hd_res_t *res;
|
||||
|
||||
PROGRESS(1, 0, "isdn");
|
||||
|
||||
ii0 = isdn_detect();
|
||||
|
||||
dump_isa_isdn_data(hd_data, ii0);
|
||||
|
||||
PROGRESS(1, 1, "isdn");
|
||||
|
||||
for(ii = ii0; ii; ii = ii->next) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_isa;
|
||||
hd->base_class.id = bc_isdn;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x3000 + ii->type);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, ((ii->type << 8) + (ii->subtype & 0xff)) & 0xffff);
|
||||
|
||||
if(ii->has_io) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = ii->io;
|
||||
res->io.access = acc_rw;
|
||||
}
|
||||
|
||||
if(ii->has_irq) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->irq.type = res_irq;
|
||||
res->irq.enabled = 1;
|
||||
res->irq.base = ii->irq;
|
||||
}
|
||||
|
||||
// #### ask libihw? -> isdn.c
|
||||
|
||||
}
|
||||
|
||||
free_isa_isdn(ii0);
|
||||
}
|
||||
|
||||
isa_isdn_t *new_isa_isdn(isa_isdn_t **ii)
|
||||
{
|
||||
while(*ii) ii = &(*ii)->next;
|
||||
|
||||
return *ii = new_mem(sizeof **ii);
|
||||
}
|
||||
|
||||
isa_isdn_t *free_isa_isdn(isa_isdn_t *ii)
|
||||
{
|
||||
isa_isdn_t *l;
|
||||
|
||||
for(; ii; ii = (l = ii)->next, free_mem(l));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dump_isa_isdn_data(hd_data_t *hd_data, isa_isdn_t *ii)
|
||||
{
|
||||
ADD2LOG("---------- ISA ISDN raw data ----------\n");
|
||||
|
||||
for(; ii; ii = ii->next) {
|
||||
ADD2LOG(" type %d, subtype %d", ii->type, ii->subtype);
|
||||
if(ii->has_mem) ADD2LOG(", mem 0x%04x", ii->mem);
|
||||
if(ii->has_io) ADD2LOG(", io 0x%04x", ii->io);
|
||||
if(ii->has_irq) ADD2LOG(", irq %d", ii->irq);
|
||||
ADD2LOG("\n");
|
||||
}
|
||||
|
||||
ADD2LOG("---------- ISA ISDN raw data end ----------\n");
|
||||
}
|
||||
|
||||
|
||||
#endif /* defined(__i386__) */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
typedef struct isa_isdn_s {
|
||||
struct isa_isdn_s *next;
|
||||
unsigned has_mem:1, has_io:1, has_irq:1;
|
||||
unsigned type, subtype, mem, io, irq;
|
||||
} isa_isdn_t;
|
||||
|
||||
isa_isdn_t *new_isa_isdn(isa_isdn_t **ii);
|
||||
|
||||
void hd_scan_isa(hd_data_t *hd_data);
|
||||
|
||||
isa_isdn_t *isdn_detect(void);
|
|
@ -0,0 +1,427 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "hddb.h"
|
||||
#include "isapnp.h"
|
||||
|
||||
/**
|
||||
* @defgroup ISAPnPint ISA PnP
|
||||
* @ingroup libhdBUSint
|
||||
* @brief ISA PnP scan functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined(__i386__) || defined(__alpha__)
|
||||
|
||||
static void get_pnp_devs(hd_data_t *hd_data);
|
||||
|
||||
#if 0
|
||||
static void get_read_port(hd_data_t *hd_data, isapnp_t *);
|
||||
static void build_list(hd_data_t *hd_data, str_list_t *isapnp_list);
|
||||
#endif
|
||||
|
||||
void hd_scan_isapnp(hd_data_t *hd_data)
|
||||
{
|
||||
#if 0
|
||||
hd_t *hd;
|
||||
hd_res_t *res;
|
||||
int isapnp_ok;
|
||||
str_list_t *isapnp_list = NULL, *sl;
|
||||
#endif
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_isapnp)) return;
|
||||
|
||||
hd_data->module = mod_isapnp;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "pnp devices");
|
||||
|
||||
get_pnp_devs(hd_data);
|
||||
|
||||
#if 0
|
||||
PROGRESS(1, 0, "read port");
|
||||
|
||||
if(!hd_data->isapnp) {
|
||||
hd_data->isapnp = new_mem(sizeof *hd_data->isapnp);
|
||||
}
|
||||
else {
|
||||
hd_data->isapnp->cards = 0;
|
||||
/* just in case... */
|
||||
hd_data->isapnp->card = free_mem(hd_data->isapnp->card);
|
||||
/* keep the port */
|
||||
}
|
||||
|
||||
if(!hd_data->isapnp->read_port) get_read_port(hd_data, hd_data->isapnp);
|
||||
|
||||
PROGRESS(3, 0, "get pnp data");
|
||||
|
||||
isapnp_list = read_file(PROC_ISAPNP, 0, 0);
|
||||
|
||||
if((hd_data->debug & HD_DEB_ISAPNP)) {
|
||||
ADD2LOG("----- %s -----\n", PROC_ISAPNP);
|
||||
for(sl = isapnp_list; sl; sl = sl->next) {
|
||||
ADD2LOG(" %s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- %s end -----\n", PROC_ISAPNP);
|
||||
}
|
||||
|
||||
isapnp_ok = isapnp_list && hd_data->isapnp->read_port ? 1 : 1;
|
||||
|
||||
PROGRESS(4, 0, "build list");
|
||||
|
||||
if(isapnp_ok) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_isa;
|
||||
hd->base_class.id = bc_internal;
|
||||
hd->sub_class.id = sc_int_isapnp_if;
|
||||
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = ISAPNP_ADDR_PORT;
|
||||
res->io.range = 1;
|
||||
res->io.access = acc_wo;
|
||||
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = ISAPNP_DATA_PORT;
|
||||
res->io.range = 1;
|
||||
res->io.access = acc_wo;
|
||||
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = hd_data->isapnp->read_port;
|
||||
res->io.range = 1;
|
||||
res->io.access = acc_ro;
|
||||
}
|
||||
|
||||
build_list(hd_data, isapnp_list);
|
||||
|
||||
free_str_list(isapnp_list);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void get_pnp_devs(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
char *s, *t, buf[4];
|
||||
unsigned u1, u2, u3;
|
||||
str_list_t *sf_bus, *sf_bus_e;
|
||||
char *sf_dev, *sf_dev2;
|
||||
|
||||
sf_bus = read_dir("/sys/bus/pnp/devices", 'l');
|
||||
|
||||
if(!sf_bus) {
|
||||
ADD2LOG("sysfs: no such bus: pnp\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for(sf_bus_e = sf_bus; sf_bus_e; sf_bus_e = sf_bus_e->next) {
|
||||
sf_dev = new_str(hd_read_sysfs_link("/sys/bus/pnp/devices", sf_bus_e->str));
|
||||
|
||||
ADD2LOG(
|
||||
" pnp device: name = %s\n path = %s\n",
|
||||
sf_bus_e->str,
|
||||
hd_sysfs_id(sf_dev)
|
||||
);
|
||||
|
||||
if((s = get_sysfs_attr_by_path(sf_dev, "id"))) {
|
||||
if(sscanf(s, "%3s%4x", buf, &u1) == 2 && (u2 = name2eisa_id(buf))) {
|
||||
ADD2LOG(" id = %s %04x\n", eisa_vendor_str(u2), u1);
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
|
||||
hd->sysfs_id = new_str(hd_sysfs_id(sf_dev));
|
||||
hd->sysfs_bus_id = new_str(sf_bus_e->str);
|
||||
|
||||
hd->bus.id = bus_isa;
|
||||
hd->is.isapnp = 1;
|
||||
|
||||
hd->sub_vendor.id = u2;
|
||||
hd->sub_device.id = MAKE_ID(TAG_EISA, u1);
|
||||
|
||||
if(sscanf(hd->sysfs_bus_id, "%2x:%2x.%2x", &u1, &u2, &u3) == 3) {
|
||||
hd->slot = u2;
|
||||
hd->func = u3;
|
||||
}
|
||||
|
||||
sf_dev2 = new_str(sf_dev);
|
||||
if((t = strrchr(sf_dev2, '/'))) *t = 0;
|
||||
|
||||
if((t = get_sysfs_attr_by_path(sf_dev2, "card_id"))) {
|
||||
if(sscanf(t, "%3s%4x", buf, &u1) == 2 && (u2 = name2eisa_id(buf))) {
|
||||
ADD2LOG(" card id = %s %04x\n", eisa_vendor_str(u2), u1);
|
||||
|
||||
hd->vendor.id = u2;
|
||||
hd->device.id = MAKE_ID(TAG_EISA, u1);
|
||||
}
|
||||
}
|
||||
if((t = get_sysfs_attr_by_path(sf_dev2, "name"))) {
|
||||
hd->device.name = canon_str(t, strlen(t));
|
||||
if(!strcasecmp(hd->device.name, "unknown")) {
|
||||
hd->device.name = free_mem(hd->device.name);
|
||||
}
|
||||
}
|
||||
|
||||
free_mem(sf_dev2);
|
||||
|
||||
if(hd->sub_vendor.id == hd->vendor.id && hd->sub_device.id == hd->device.id) {
|
||||
hd->sub_vendor.id = hd->sub_device.id = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_mem(sf_dev);
|
||||
}
|
||||
|
||||
free_str_list(sf_bus);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
unsigned char *add_isapnp_card_res(isapnp_card_t *ic, int len, int type)
|
||||
{
|
||||
ic->res = add_mem(ic->res, sizeof *ic->res, ic->res_len);
|
||||
|
||||
ic->res[ic->res_len].len = len;
|
||||
ic->res[ic->res_len].type = type;
|
||||
ic->res[ic->res_len].data = new_mem(len);
|
||||
|
||||
if(type == RES_LOG_DEV_ID) { /* logical device id */
|
||||
ic->log_devs++;
|
||||
}
|
||||
|
||||
return ic->res[ic->res_len++].data;
|
||||
}
|
||||
|
||||
|
||||
isapnp_card_t *add_isapnp_card(isapnp_t *ip, int csn)
|
||||
{
|
||||
isapnp_card_t *c;
|
||||
|
||||
ip->card = add_mem(ip->card, sizeof *ip->card, ip->cards);
|
||||
c = ip->card + ip->cards++;
|
||||
|
||||
c->csn = csn;
|
||||
c->serial = new_mem(sizeof *c->serial * 8);
|
||||
c->card_regs = new_mem(sizeof *c->card_regs * 0x30);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void get_read_port(hd_data_t *hd_data, isapnp_t *p)
|
||||
{
|
||||
hd_res_t *res;
|
||||
|
||||
p->read_port = 0;
|
||||
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "ISAPnP", W_IO);
|
||||
if(res && res->any.type == res_io) p->read_port = res->io.base;
|
||||
free_res_list(res);
|
||||
}
|
||||
|
||||
|
||||
void build_list(hd_data_t *hd_data, str_list_t *isapnp_list)
|
||||
{
|
||||
hd_t *hd = NULL;
|
||||
str_list_t *sl;
|
||||
char s1[4], s2[100];
|
||||
int card, ldev, cdev_id, ldev_active = 0;
|
||||
char *dev_name = NULL, *ldev_name = NULL;
|
||||
unsigned dev_id = 0, vend_id = 0, base_class = 0, sub_class = 0, ldev_id;
|
||||
unsigned u, ux[5];
|
||||
int i, j;
|
||||
hd_res_t *res;
|
||||
|
||||
for(sl = isapnp_list; sl; sl = sl->next) {
|
||||
|
||||
if(sscanf(sl->str, "Card %d '%3s%4x:%99[^']", &card, s1, &dev_id, s2) == 4) {
|
||||
// ADD2LOG("\n\n** card %d >%s< %04x >%s<**\n", card, s1, dev_id, s2);
|
||||
|
||||
dev_name = free_mem(dev_name);
|
||||
if(strcmp(s2, "Unknown")) dev_name = new_str(s2);
|
||||
|
||||
dev_id = MAKE_ID(TAG_EISA, dev_id);
|
||||
vend_id = name2eisa_id(s1);
|
||||
|
||||
base_class = sub_class = 0;
|
||||
if((u = device_class(hd_data, vend_id, dev_id))) {
|
||||
base_class = u >> 8;
|
||||
sub_class = u & 0xff;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// ########## FIXME
|
||||
if(
|
||||
(ID_VALUE(vend_id) || ID_VALUE(dev_id)) &&
|
||||
!((db_name = hd_device_name(hd_data, vend_id, dev_id)) && *db_name)
|
||||
) {
|
||||
if(dev_name) {
|
||||
add_device_name(hd_data, vend_id, dev_id, dev_name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(sscanf(sl->str, " Logical device %d '%3s%4x:%99[^']", &ldev, s1, &ldev_id, s2) == 4) {
|
||||
// ADD2LOG("\n\n** ldev %d >%s< %04x >%s<**\n", ldev, s1, ldev_id, s2);
|
||||
|
||||
ldev_name = free_mem(ldev_name);
|
||||
if(strcmp(s2, "Unknown")) ldev_name = new_str(s2);
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
|
||||
hd->bus.id = bus_isa;
|
||||
hd->is.isapnp = 1;
|
||||
hd->slot = card;
|
||||
hd->func = ldev;
|
||||
|
||||
hd->vendor.id = vend_id;
|
||||
hd->device.id = dev_id;
|
||||
|
||||
hd->base_class.id = base_class;
|
||||
hd->sub_class.id = sub_class;
|
||||
|
||||
hd->sub_device.id = MAKE_ID(TAG_EISA, ldev_id);
|
||||
hd->sub_vendor.id = name2eisa_id(s1);
|
||||
|
||||
if(hd->sub_vendor.id == hd->vendor.id && hd->sub_device.id == hd->device.id) {
|
||||
hd->sub_vendor.id = hd->sub_device.id = 0;
|
||||
}
|
||||
|
||||
if((u = sub_device_class(hd_data, hd->vendor.id, hd->device.id, hd->sub_vendor.id, hd->sub_device.id))) {
|
||||
hd->base_class.id = u >> 8;
|
||||
hd->sub_class.id = u & 0xff;
|
||||
}
|
||||
|
||||
#if 0
|
||||
# ############# FIXME
|
||||
if(
|
||||
(ID_VALUE(hd->sub_vendor.id) || ID_VALUE(hd->sub_device.id)) &&
|
||||
!hd_sub_device_name(hd_data, hd->vend, hd->dev, hd->sub_vend, hd->sub_device.id)
|
||||
) {
|
||||
if(ldev_name) {
|
||||
add_sub_device_name(hd_data, hd->vend, hd->dev, hd->sub_vend, hd->sub_device.id, ldev_name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(strstr(sl->str, "Device is not active")) {
|
||||
ldev_active = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(strstr(sl->str, "Device is active")) {
|
||||
ldev_active = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(hd && sscanf(sl->str, " Compatible device %3s%4x", s1, &cdev_id) == 2) {
|
||||
// ADD2LOG("\n\n** cdev >%s< %04x **\n", s1, cdev_id);
|
||||
|
||||
hd->compat_device.id = MAKE_ID(TAG_EISA, cdev_id);
|
||||
hd->compat_vendor.id = name2eisa_id(s1);
|
||||
|
||||
if(!(hd->base_class.id || hd->sub_class.id)) {
|
||||
if((u = device_class(hd_data, hd->compat_vendor.id, hd->compat_device.id))) {
|
||||
hd->base_class.id = u >> 8;
|
||||
hd->sub_class.id = u & 0xff;
|
||||
}
|
||||
else if(hd->compat_vendor.id == MAKE_ID(TAG_EISA, 0x41d0)) {
|
||||
/* 0x41d0 is 'PNP' */
|
||||
switch((hd->compat_device.id >> 12) & 0xf) {
|
||||
case 8:
|
||||
hd->base_class.id = bc_network;
|
||||
hd->sub_class.id = 0x80;
|
||||
break;
|
||||
case 0xa:
|
||||
hd->base_class.id = bc_storage;
|
||||
hd->sub_class.id = 0x80;
|
||||
break;
|
||||
case 0xb:
|
||||
hd->base_class.id = bc_multimedia;
|
||||
hd->sub_class.id = 0x80;
|
||||
break;
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
hd->base_class.id = bc_modem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(
|
||||
hd &&
|
||||
(j = sscanf(sl->str,
|
||||
" Active port %x, %x, %x, %x, %x, %x",
|
||||
ux, ux + 1, ux + 2, ux + 3, ux + 4, ux + 5
|
||||
)) >= 1
|
||||
) {
|
||||
|
||||
for(i = 0; i < j; i++) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = ldev_active ? 1 : 0;
|
||||
res->io.base = ux[i];
|
||||
res->io.access = acc_rw;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(hd && (j = sscanf(sl->str, " Active IRQ %d [%x], %d [%x]", ux, ux + 1, ux + 2, ux + 3)) >= 1) {
|
||||
for(i = 0; i < j; i += 2) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->irq.type = res_irq;
|
||||
res->irq.enabled = ldev_active ? 1 : 0;
|
||||
res->irq.base = ux[i];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(hd && (j = sscanf(sl->str, " Active DMA %d, %d", ux, ux + 1)) >= 1) {
|
||||
for(i = 0; i < j; i++) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->dma.type = res_dma;
|
||||
res->dma.enabled = ldev_active ? 1 : 0;
|
||||
res->dma.base = ux[i];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
free_mem(dev_name);
|
||||
free_mem(ldev_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* defined(__i386__) || defined(__alpha__) */
|
||||
|
||||
/** @} **/
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* These are fixed and write only. Reads are done from a port with a
|
||||
* relocatable address...
|
||||
*/
|
||||
#define ISAPNP_ADDR_PORT 0x279
|
||||
#define ISAPNP_DATA_PORT 0xa79
|
||||
|
||||
|
||||
/*
|
||||
* ISA PnP resource types
|
||||
*/
|
||||
#define RES_PNP_VERSION 0x01
|
||||
#define RES_LOG_DEV_ID 0x02
|
||||
#define RES_COMPAT_DEV_ID 0x03
|
||||
#define RES_IRQ 0x04
|
||||
#define RES_DMA 0x05
|
||||
#define RES_START_DEP 0x06
|
||||
#define RES_END_DEP 0x07
|
||||
#define RES_IO 0x08
|
||||
#define RES_FIXED_IO 0x09
|
||||
#define RES_VENDOR_SMALL 0x0e
|
||||
#define RES_END 0x0f
|
||||
|
||||
#define RES_MEM_RANGE 0x81
|
||||
#define RES_ANSI_NAME 0x82
|
||||
#define RES_UNICODE_NAME 0x83
|
||||
#define RES_VENDOR_LARGE 0x84
|
||||
#define RES_MEM32_RANGE 0x85
|
||||
#define RES_FIXED_MEM32_RANGE 0x86
|
||||
|
||||
|
||||
/*
|
||||
* ISA PnP configuration regs
|
||||
*/
|
||||
#define CFG_MEM24 0x40
|
||||
#define CFG_MEM32_0 0x76
|
||||
#define CFG_MEM32_1 0x80
|
||||
#define CFG_MEM32_2 0x90
|
||||
#define CFG_MEM32_3 0xa0
|
||||
#define CFG_IO_HI_BASE 0x60
|
||||
#define CFG_IO_LO_BASE 0x61
|
||||
#define CFG_IRQ 0x70
|
||||
#define CFG_IRQ_TYPE 0x71
|
||||
#define CFG_DMA 0x74
|
||||
|
||||
|
||||
/* gather ISA-PnP info */
|
||||
void hd_scan_isapnp(hd_data_t *hd_data);
|
||||
|
||||
|
||||
/*
|
||||
* Interface functions to the pnpdump lib.
|
||||
*/
|
||||
int pnpdump(hd_data_t *hd_data, int read_boards);
|
||||
unsigned char *add_isapnp_card_res(isapnp_card_t *, int, int);
|
||||
isapnp_card_t *add_isapnp_card(isapnp_t *, int);
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "isdn.h"
|
||||
|
||||
#undef ISDN_TEST
|
||||
|
||||
/**
|
||||
* @defgroup ISDNint ISDN devices
|
||||
* @ingroup libhdDEVint
|
||||
* @brief ISDN identify functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef LIBHD_TINY
|
||||
|
||||
#if !defined(__s390__) && !defined(__s390x__) && !defined(__alpha__)
|
||||
|
||||
void hd_scan_isdn(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
cdb_isdn_card *cic;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_isdn)) return;
|
||||
|
||||
hd_data->module = mod_isdn;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "list");
|
||||
|
||||
#ifdef ISDN_TEST
|
||||
{
|
||||
hd_res_t *res;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_isa;
|
||||
hd->base_class.id = bc_isdn;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x3005);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0500); // type, subtype
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = 0x0300;
|
||||
res->io.access = acc_rw;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_isa;
|
||||
hd->base_class.id = bc_isdn;
|
||||
hd->vendor.id = MAKE_ID(TAG_EISA, 0x1593);
|
||||
hd->device.id = MAKE_ID(TAG_EISA, 0x0133); // type, subtype
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = 0x0240;
|
||||
res->io.access = acc_rw;
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->irq.type = res_irq;
|
||||
res->irq.enabled = 1;
|
||||
res->irq.base = 99;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_isa;
|
||||
hd->base_class.id = bc_isdn;
|
||||
hd->vendor.id = MAKE_ID(TAG_EISA, 0x0e98);
|
||||
hd->device.id = MAKE_ID(TAG_EISA, 0x0000); // type, subtype
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = 0x0180;
|
||||
res->io.access = acc_rw;
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = 0x0540;
|
||||
res->io.access = acc_rw;
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->irq.type = res_irq;
|
||||
res->irq.enabled = 1;
|
||||
res->irq.base = 77;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_pci;
|
||||
hd->base_class.id = bc_isdn;
|
||||
hd->vendor.id = MAKE_ID(TAG_PCI, 0x1244);
|
||||
hd->device.id = MAKE_ID(TAG_PCI, 0x0a00); // type, subtype
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = 0xe000;
|
||||
res->io.access = acc_rw;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_isa;
|
||||
hd->base_class.id = bc_isdn;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x3001);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0100); // type, subtype
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = 0xe80;
|
||||
res->io.access = acc_rw;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_isa;
|
||||
hd->base_class.id = bc_isdn;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x3000);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x1a00); // type, subtype
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = 0x400;
|
||||
res->io.access = acc_rw;
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if((cic = get_isdn_info(hd))) {
|
||||
hd->base_class.id = bc_isdn;
|
||||
hd->sub_class.id = 0;
|
||||
free_mem(cic);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
cdb_isdn_card *get_isdn_info(hd_t *hd)
|
||||
{
|
||||
cdb_isdn_card *cic0, *cic;
|
||||
unsigned u0, u1;
|
||||
|
||||
if(hd->bus.id == bus_pci ||
|
||||
hd->bus.id == bus_isa ||
|
||||
hd->bus.id == bus_usb ||
|
||||
hd->bus.id == bus_pcmcia ||
|
||||
hd->bus.id == bus_cardbus) {
|
||||
|
||||
cic = NULL;
|
||||
u0 = ID_VALUE(hd->vendor.id);
|
||||
if(
|
||||
hd->bus.id == bus_isa &&
|
||||
ID_TAG(hd->vendor.id) == TAG_SPECIAL &&
|
||||
u0 >= 0x3000 && u0 <= 0x3006 &&
|
||||
ID_TAG(hd->device.id) == TAG_SPECIAL
|
||||
) {
|
||||
u0 = ID_VALUE(hd->device.id);
|
||||
cic = hd_cdbisdn_get_card_from_type(u0 >> 8, u0 & 0xff);
|
||||
}
|
||||
|
||||
if(
|
||||
hd->bus.id == bus_isa &&
|
||||
ID_TAG(hd->vendor.id) == TAG_EISA &&
|
||||
ID_TAG(hd->device.id) == TAG_EISA
|
||||
) {
|
||||
u0 = ID_VALUE(hd->vendor.id);
|
||||
u1 = ID_VALUE(hd->device.id);
|
||||
cic = hd_cdbisdn_get_card_from_id(((u0 & 0xff) << 8) + ((u0 >> 8) & 0xff),
|
||||
((u1 & 0xff) << 8) + ((u1 >> 8) & 0xff),
|
||||
0xffff,0xffff);
|
||||
}
|
||||
|
||||
if(hd->bus.id == bus_pci) {
|
||||
cic = hd_cdbisdn_get_card_from_id(ID_VALUE(hd->vendor.id), ID_VALUE(hd->device.id),
|
||||
ID_VALUE(hd->sub_vendor.id), ID_VALUE(hd->sub_device.id));
|
||||
}
|
||||
|
||||
if(hd->bus.id == bus_usb &&
|
||||
ID_TAG(hd->vendor.id) == TAG_USB &&
|
||||
ID_TAG(hd->device.id) == TAG_USB) {
|
||||
|
||||
if (hd->revision.id == 0 && hd->revision.name) {
|
||||
/* the revision is usually saved as string (1.00) */
|
||||
sscanf(hd->revision.name, "%x.%x", &u1, &u0);
|
||||
u0 = u0 | u1 << 8;
|
||||
} else
|
||||
u0 = ID_VALUE(hd->revision.id);
|
||||
|
||||
cic = hd_cdbisdn_get_card_from_id(ID_VALUE(hd->vendor.id), ID_VALUE(hd->device.id),
|
||||
u0, 0xffff);
|
||||
if (!cic) /* to get cards without revision info in database */
|
||||
cic = hd_cdbisdn_get_card_from_id(ID_VALUE(hd->vendor.id), ID_VALUE(hd->device.id),
|
||||
0xffff, 0xffff);
|
||||
}
|
||||
|
||||
if((hd->bus.id == bus_pcmcia || hd->bus.id == bus_cardbus) &&
|
||||
(hd->base_class.id == bc_network || hd->base_class.id == bc_isdn)) {
|
||||
if (hd->drivers && hd->drivers->str) {
|
||||
if (0 == strcmp(hd->drivers->str, "teles_cs")) {
|
||||
cic = hd_cdbisdn_get_card_from_type(8, 0);
|
||||
} else if (0 == strcmp(hd->drivers->str, "sedlbauer_cs")) {
|
||||
cic = hd_cdbisdn_get_card_from_type(22, 2);
|
||||
} else if (0 == strcmp(hd->drivers->str, "avma1_cs")) {
|
||||
cic = hd_cdbisdn_get_card_from_type(26, 0);
|
||||
} else if (0 == strcmp(hd->drivers->str, "fcpcmcia_cs")) {
|
||||
cic = hd_cdbisdn_get_card_from_type(8002, 5);
|
||||
} else if (0 == strcmp(hd->drivers->str, "elsa_cs")) {
|
||||
cic = hd_cdbisdn_get_card_from_type(10, 11);
|
||||
} else if (0 == strcmp(hd->drivers->str, "avm_cs")) {
|
||||
cic = hd_cdbisdn_get_card_from_type(8001, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cic && cic->Class && strcmp(cic->Class, "DSL")) {
|
||||
cic0 = new_mem(sizeof *cic0);
|
||||
memcpy(cic0, cic, sizeof *cic0);
|
||||
return cic0;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hd_scan_dsl(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
cdb_isdn_card *cic;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_isdn)) return;
|
||||
|
||||
hd_data->module = mod_dsl;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "list");
|
||||
|
||||
#ifdef DSL_TEST
|
||||
{
|
||||
hd_res_t *res;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->bus.id = bus_pci;
|
||||
hd->base_class.id = bc_dsl;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x1244);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x2700); // type, subtype
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if((cic = get_dsl_info(hd))) {
|
||||
free_mem(cic);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
cdb_isdn_card *get_dsl_info(hd_t *hd)
|
||||
{
|
||||
cdb_isdn_card *cic0, *cic;
|
||||
cdb_isdn_vario *civ;
|
||||
unsigned u0, u1;
|
||||
|
||||
if(hd->bus.id == bus_pci ||
|
||||
hd->bus.id == bus_usb) {
|
||||
|
||||
cic = NULL;
|
||||
|
||||
if(hd->bus.id == bus_pci) {
|
||||
cic = hd_cdbisdn_get_card_from_id(ID_VALUE(hd->vendor.id), ID_VALUE(hd->device.id),
|
||||
ID_VALUE(hd->sub_vendor.id), ID_VALUE(hd->sub_device.id));
|
||||
}
|
||||
|
||||
if(hd->bus.id == bus_usb &&
|
||||
ID_TAG(hd->vendor.id) == TAG_USB &&
|
||||
ID_TAG(hd->device.id) == TAG_USB) {
|
||||
|
||||
if (hd->revision.id == 0 && hd->revision.name) {
|
||||
/* the revision is usually saved as string (1.00) */
|
||||
sscanf(hd->revision.name, "%x.%x", &u1, &u0);
|
||||
u0 = u0 | u1 << 8;
|
||||
} else
|
||||
u0 = ID_VALUE(hd->revision.id);
|
||||
|
||||
cic = hd_cdbisdn_get_card_from_id(ID_VALUE(hd->vendor.id), ID_VALUE(hd->device.id),
|
||||
u0, 0xffff);
|
||||
if (!cic) /* to get cards without revision info in database */
|
||||
cic = hd_cdbisdn_get_card_from_id(ID_VALUE(hd->vendor.id), ID_VALUE(hd->device.id),
|
||||
0xffff, 0xffff);
|
||||
}
|
||||
|
||||
if (cic && cic->Class && !strcmp(cic->Class, "DSL")) {
|
||||
hd->base_class.id = bc_dsl;
|
||||
hd->sub_class.id = sc_dsl_unknown;
|
||||
civ = hd_cdbisdn_get_vario(cic->vario);
|
||||
if (civ && civ->interface) {
|
||||
if (0 == strncmp(civ->interface, "CAPI20", 6)) {
|
||||
hd->sub_class.id = sc_dsl_capi;
|
||||
} else if (0 == strncmp(civ->interface, "pppoe", 5)) {
|
||||
hd->sub_class.id = sc_dsl_pppoe;
|
||||
}
|
||||
}
|
||||
cic0 = new_mem(sizeof *cic0);
|
||||
memcpy(cic0, cic, sizeof *cic0);
|
||||
return cic0;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* !defined(__s390__) && !defined(__s390x__) && !defined(__alpha__) */
|
||||
|
||||
#endif /* !defined(LIBHD_TINY) */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
void hd_scan_isdn(hd_data_t *hd_data);
|
||||
void hd_scan_dsl(hd_data_t *hd_data);
|
||||
cdb_isdn_card *get_isdn_info(hd_t *hd);
|
||||
cdb_isdn_card *get_dsl_info(hd_t *hd);
|
|
@ -0,0 +1,311 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/serial.h>
|
||||
|
||||
#ifndef TIOCGDEV
|
||||
#define TIOCGDEV _IOR('T', 0x32, unsigned int)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup KDBint Keyboard devices
|
||||
* @ingroup libhdDEVint
|
||||
* @brief Keyboard device functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __sparc__
|
||||
|
||||
#ifdef DIET
|
||||
typedef unsigned int u_int;
|
||||
#endif
|
||||
|
||||
#ifndef KIOCTYPE
|
||||
/* Return keyboard type */
|
||||
# define KIOCTYPE _IOR('k', 9, int)
|
||||
#endif
|
||||
#ifndef KIOCLAYOUT
|
||||
/* Return Keyboard layout */
|
||||
# define KIOCLAYOUT _IOR('k', 20, int)
|
||||
#endif
|
||||
|
||||
#include <asm/openpromio.h>
|
||||
#endif
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "kbd.h"
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*
|
||||
* Look for keyboards not covered by kernel input device driver, mainly
|
||||
* some sort of serial consoles.
|
||||
*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*/
|
||||
|
||||
#ifdef __sparc__
|
||||
static void add_sun_console(hd_data_t *hd_data);
|
||||
#else
|
||||
static void add_serial_console(hd_data_t *hd_data);
|
||||
#endif
|
||||
|
||||
|
||||
void hd_scan_kbd(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_kbd)) return;
|
||||
|
||||
hd_data->module = mod_kbd;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
PROGRESS(2, 0, "uml");
|
||||
|
||||
if(hd_is_uml(hd_data)) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_keyboard;
|
||||
hd->sub_class.id = sc_keyboard_kbd;
|
||||
hd->bus.id = bus_none;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0201);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 2);
|
||||
}
|
||||
|
||||
PROGRESS(3, 0, "serial console");
|
||||
|
||||
#ifdef __sparc__
|
||||
add_sun_console(hd_data);
|
||||
#else
|
||||
add_serial_console(hd_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifndef __sparc__
|
||||
|
||||
void add_serial_console(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
hd_res_t *res = NULL;
|
||||
int fd, i;
|
||||
str_list_t *cmd, *cmd0, *sl;
|
||||
unsigned u, u1;
|
||||
struct serial_struct ser_info;
|
||||
unsigned tty_major = 0, tty_minor = 0;
|
||||
char c, *dev = NULL, *s;
|
||||
|
||||
/* first, try console= option */
|
||||
cmd = cmd0 = get_cmdline(hd_data, "console");
|
||||
|
||||
/* use last console entry */
|
||||
if(cmd) while(cmd->next) cmd = cmd->next;
|
||||
|
||||
if(
|
||||
cmd &&
|
||||
(
|
||||
/* everything != "ttyN" */
|
||||
strncmp(cmd->str, "tty", 3) ||
|
||||
!(cmd->str[3] == 0 || (cmd->str[3] >= '0' && cmd->str[3] <= '9'))
|
||||
)
|
||||
) {
|
||||
sl = hd_split(',', cmd->str);
|
||||
s = sl->str;
|
||||
if(!strncmp(s, "/dev/", sizeof "/dev/" - 1)) s += sizeof "/dev/" - 1;
|
||||
dev = new_str(s);
|
||||
if(sl->next && (i = sscanf(sl->next->str, "%u%c%u", &u, &c, &u1)) >= 1) {
|
||||
res = add_res_entry(&res, new_mem(sizeof *res));
|
||||
res->baud.type = res_baud;
|
||||
res->baud.speed = u;
|
||||
if(i >= 2) res->baud.parity = c;
|
||||
if(i >= 3) res->baud.bits = u1;
|
||||
}
|
||||
free_str_list(sl);
|
||||
}
|
||||
|
||||
if(!dev && (fd = open(DEV_CONSOLE, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0) {
|
||||
if(ioctl(fd, TIOCGDEV, &u) != -1) {
|
||||
tty_major = (u >> 8) & 0xfff;
|
||||
tty_minor = (u & 0xff) | ((u >> 12) & 0xfff00);
|
||||
ADD2LOG(DEV_CONSOLE ": major %u, minor %u\n", tty_major, tty_minor);
|
||||
}
|
||||
|
||||
if (0)
|
||||
;
|
||||
#ifdef __powerpc__
|
||||
else if(tty_major == 229 /* iseries hvc */) {
|
||||
if (tty_minor >= 128) {
|
||||
str_printf(&dev, 0, "hvsi%u", tty_minor-128);
|
||||
} else {
|
||||
str_printf(&dev, 0, "hvc%u", tty_minor);
|
||||
}
|
||||
} else if (tty_major == 204 /* SERIAL_PSC_MAJOR */ && tty_minor == 148 /* SERIAL_PSC_MINOR */) {
|
||||
str_printf(&dev, 0, "ttyPSC0"); /* EFIKA5K2 */
|
||||
}
|
||||
#endif /* __powerpc__ */
|
||||
else if(!ioctl(fd, TIOCGSERIAL, &ser_info)) {
|
||||
ADD2LOG("serial console at line %d\n", ser_info.line);
|
||||
str_printf(&dev, 0, "ttyS%d", ser_info.line);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if(dev) {
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_keyboard;
|
||||
hd->sub_class.id = sc_keyboard_console;
|
||||
hd->bus.id = bus_serial;
|
||||
hd->device.name = new_str("serial console");
|
||||
|
||||
if(*dev) str_printf(&hd->unix_dev_name, 0, "/dev/%s", dev);
|
||||
|
||||
hd->res = res;
|
||||
|
||||
free_mem(dev);
|
||||
}
|
||||
|
||||
free_str_list(cmd0);
|
||||
}
|
||||
|
||||
|
||||
#else /* defined(__sparc__) */
|
||||
|
||||
|
||||
void add_sun_console(hd_data_t *hd_data)
|
||||
{
|
||||
int fd, kid, kid2, klay, ser_cons, i;
|
||||
unsigned u, u1, u2;
|
||||
char c1, c2;
|
||||
struct serial_struct ser_info;
|
||||
unsigned char buf[OPROMMAXPARAM];
|
||||
struct openpromio *opio = (struct openpromio *) buf;
|
||||
hd_t *hd;
|
||||
hd_res_t *res;
|
||||
|
||||
if((fd = open(DEV_CONSOLE, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0)
|
||||
{
|
||||
if(ioctl(fd, TIOCGSERIAL, &ser_info))
|
||||
{
|
||||
ser_cons = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ser_cons = ser_info.line;
|
||||
ADD2LOG("serial console at line %d\n", ser_cons);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if(ser_cons >= 0 && (fd = open(DEV_OPENPROM, O_RDWR | O_NONBLOCK)) >= 0)
|
||||
{
|
||||
sprintf(opio->oprom_array, "tty%c-mode", (ser_cons & 1) + 'a');
|
||||
opio->oprom_size = sizeof buf - 0x100;
|
||||
if(!ioctl(fd, OPROMGETOPT, opio))
|
||||
{
|
||||
if(opio->oprom_size < 0x100)
|
||||
{
|
||||
opio->oprom_array[opio->oprom_size] = 0;
|
||||
ADD2LOG(
|
||||
"prom(tty%c-mode) = \"%s\" (%d bytes)\n",
|
||||
(ser_cons & 1) + 'a', opio->oprom_array,
|
||||
opio->oprom_size
|
||||
);
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_keyboard;
|
||||
hd->sub_class.id = sc_keyboard_console;
|
||||
hd->bus.id = bus_serial;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0203);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0000);
|
||||
str_printf(&hd->unix_dev_name, 0, "/dev/ttyS%d", ser_cons);
|
||||
if((i = sscanf(opio->oprom_array, "%u,%u,%c,%u,%c",
|
||||
&u, &u1, &c1, &u2, &c2)) >= 1)
|
||||
{
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->baud.type = res_baud;
|
||||
res->baud.speed = u;
|
||||
if(i >= 2) res->baud.bits = u1;
|
||||
if(i >= 3) res->baud.parity = c1;
|
||||
if(i >= 4) res->baud.stopbits = u2;
|
||||
if(i >= 5) res->baud.handshake = c2;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
/* We have a serial console, so don't test for keyboard. Else
|
||||
we will always find a PS/2 keyboard */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PROGRESS(1, 0, "sun kbd");
|
||||
|
||||
if((fd = open(DEV_KBD, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0)
|
||||
{
|
||||
if(ioctl(fd, KIOCTYPE, &kid)) kid = -1;
|
||||
if(ioctl(fd, KIOCLAYOUT, &klay)) klay = -1;
|
||||
close(fd);
|
||||
|
||||
if(kid != -1)
|
||||
{
|
||||
ADD2LOG("sun keyboard: type %d, layout %d\n", kid, klay);
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_keyboard;
|
||||
hd->sub_class.id = sc_keyboard_kbd;
|
||||
hd->bus.id = bus_serial;
|
||||
if(kid == 4 && klay >= 0)
|
||||
hd->prog_if.id = klay;
|
||||
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0202);
|
||||
kid2 = kid;
|
||||
if(kid == 4 && klay > 0x20)
|
||||
kid2 = 5;
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, kid2);
|
||||
if(kid2 == 5) {
|
||||
if(klay == 0x22 || klay == 0x51)
|
||||
{
|
||||
hd->sub_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0202);
|
||||
hd->sub_device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
|
||||
}
|
||||
else if(!(
|
||||
klay == 0x21 || (klay >= 0x2f && klay <= 0x31) ||
|
||||
klay == 0x50 || (klay >= 0x5e && klay <= 0x60)
|
||||
))
|
||||
{
|
||||
hd->sub_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0202);
|
||||
hd->sub_device.id = MAKE_ID(TAG_SPECIAL, 0x0002);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_keyboard) break;
|
||||
}
|
||||
if(!hd) {
|
||||
/* We must have a PS/2 Keyboard */
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_keyboard;
|
||||
hd->sub_class.id = sc_keyboard_kbd;
|
||||
hd->bus.id = bus_ps2;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0201);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __sparc__ */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_kbd(hd_data_t *hd_data);
|
|
@ -0,0 +1,188 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/klog.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "klog.h"
|
||||
|
||||
/**
|
||||
* @defgroup KLOGint Kernel log information
|
||||
* @ingroup libhdINFOint
|
||||
* @brief Kernel log information scan functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
static int str_ok(str_list_t *sl);
|
||||
static int str_list_cmp(str_list_t *sl1, str_list_t *sl2);
|
||||
static void _read_klog(hd_data_t *hd_data);
|
||||
|
||||
|
||||
/*
|
||||
* Check if a string starts with '<[0-9]>'.
|
||||
*/
|
||||
int str_ok(str_list_t *sl)
|
||||
{
|
||||
return sl->str[0] == '<' && sl->str[2] == '>' && sl->str[1] >= '0' && sl->str[1] <= '9';
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if sl1 is idential to sl2; sl1 may be shorter as sl2.
|
||||
*
|
||||
* Returns 0/1 if they are equal/not equal. If sl1 is NULL, 0 is returned.
|
||||
*/
|
||||
int str_list_cmp(str_list_t *sl1, str_list_t *sl2)
|
||||
{
|
||||
for(; sl1; sl1 = sl1->next, sl2 = sl2->next) {
|
||||
if(!sl2 || strcmp(sl1->str, sl2->str)) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read kernel log info. Combine with /var/log/boot.msg.
|
||||
* Remove time stamps.
|
||||
*/
|
||||
void read_klog(hd_data_t *hd_data)
|
||||
{
|
||||
str_list_t *sl, **sl_new;
|
||||
char *str, *s;
|
||||
|
||||
_read_klog(hd_data);
|
||||
|
||||
free_str_list(hd_data->klog_raw);
|
||||
hd_data->klog_raw = hd_data->klog;
|
||||
hd_data->klog = NULL;
|
||||
|
||||
for(sl = hd_data->klog_raw, sl_new = &hd_data->klog; sl; sl = sl->next, sl_new = &(*sl_new)->next) {
|
||||
str = add_str_list(sl_new, sl->str)->str;
|
||||
if(str[0] == '<' && str[1] && str[2] == '>' && str[3] == '[') {
|
||||
s = str + 4;
|
||||
while(*s && *s != ']') s++;
|
||||
if(*s) s++;
|
||||
if(*s) s++; // skip space
|
||||
for(str += 3; (*str++ = *s++););
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read kernel log info. Combine with /var/log/boot.msg.
|
||||
*/
|
||||
void _read_klog(hd_data_t *hd_data)
|
||||
{
|
||||
char buf[0x2000 + 1], *s;
|
||||
int i, j, len, n;
|
||||
str_list_t *sl, *sl1, *sl2, *sl_last, **ssl, *sl_next;
|
||||
|
||||
/* some clean-up */
|
||||
hd_data->klog = free_str_list(hd_data->klog);
|
||||
|
||||
sl1 = read_file(KLOG_BOOT, 0, 0);
|
||||
sl2 = NULL;
|
||||
|
||||
/*
|
||||
* remove non-canonical lines (not starting with <[0-9]>) at the start and
|
||||
* at the end
|
||||
*/
|
||||
|
||||
/* note: the implementations assumes that at least *one* line is ok */
|
||||
for(sl_last = NULL, sl = sl1; sl; sl = (sl_last = sl)->next) {
|
||||
if(str_ok(sl)) {
|
||||
if(sl_last) {
|
||||
sl_last->next = NULL;
|
||||
free_str_list(sl1);
|
||||
sl1 = sl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(sl_last = NULL, sl = sl1; sl; sl = (sl_last = sl)->next) {
|
||||
if(!str_ok(sl)) {
|
||||
if(sl_last) {
|
||||
sl_last->next = NULL;
|
||||
free_str_list(sl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n = klogctl(3, buf, sizeof buf - 1);
|
||||
if(n <= 0) {
|
||||
hd_data->klog = sl1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(n > (int) sizeof buf - 1) n = sizeof buf - 1;
|
||||
buf[n] = 0;
|
||||
for(i = j = 0; i < n; i++) {
|
||||
if(buf[i] == '\n') {
|
||||
len = i - j + 1;
|
||||
s = new_mem(len + 1);
|
||||
memcpy(s, buf + j, len);
|
||||
add_str_list(&sl2, s);
|
||||
s = free_mem(s);
|
||||
j = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* the 1st line may be incomplete */
|
||||
if(sl2 && !str_ok(sl2)) {
|
||||
sl_next = sl2->next;
|
||||
sl2->next = NULL;
|
||||
free_str_list(sl2);
|
||||
sl2 = sl_next;
|
||||
}
|
||||
|
||||
if(!sl1) {
|
||||
hd_data->klog = sl2;
|
||||
return;
|
||||
}
|
||||
|
||||
if(sl1 && !sl2) {
|
||||
hd_data->klog = sl1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* now, try to join sl1 & sl2 */
|
||||
for(sl_last = NULL, sl = sl1; sl; sl = (sl_last = sl)->next) {
|
||||
if(!str_list_cmp(sl, sl2)) {
|
||||
free_str_list(sl);
|
||||
if(sl_last)
|
||||
sl_last->next = NULL;
|
||||
else
|
||||
sl1 = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* append sl2 to sl1 */
|
||||
for(ssl = &sl1; *ssl; ssl = &(*ssl)->next);
|
||||
*ssl = sl2;
|
||||
|
||||
hd_data->klog = sl1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add some klog data to the global log.
|
||||
*/
|
||||
void dump_klog(hd_data_t *hd_data)
|
||||
{
|
||||
str_list_t *sl;
|
||||
|
||||
ADD2LOG("----- kernel log -----\n");
|
||||
for(sl = hd_data->klog_raw; sl; sl = sl->next) {
|
||||
ADD2LOG(" %s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- kernel log end -----\n");
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
void read_klog(hd_data_t *hd_data);
|
||||
void dump_klog(hd_data_t *hd_data);
|
|
@ -0,0 +1,942 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "manual.h"
|
||||
#include "hddb.h"
|
||||
|
||||
/**
|
||||
* @defgroup Manualint UDI manual hardware
|
||||
* @ingroup libhdInternals
|
||||
* @brief Manual hardware information functions (/var/lib/hardware/udi/)
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <hwclass_names.h>
|
||||
|
||||
/* corresponds to hd_status_value_t */
|
||||
static hash_t status_names[] = {
|
||||
{ status_no, "no" },
|
||||
{ status_yes, "yes" },
|
||||
{ status_unknown, "unknown" },
|
||||
{ status_new, "new" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
#ifndef LIBHD_TINY
|
||||
|
||||
static void prop2hd(hd_data_t *hd_data, hd_t *hd, int status_only);
|
||||
static hal_prop_t *hal_get_new(hal_prop_t **list, const char *key);
|
||||
static void hd2prop_add_int32(hal_prop_t **list, const char *key, int32_t i);
|
||||
static void hd2prop_add_str(hal_prop_t **list, const char *key, const char *str);
|
||||
static void hd2prop_add_list(hal_prop_t **list, const char *key, str_list_t *sl);
|
||||
static void hd2prop_append_list(hal_prop_t **list, const char *key, char *str);
|
||||
static void hd2prop(hd_data_t *hd_data, hd_t *hd);
|
||||
|
||||
static hal_prop_t *hd_manual_read_entry_old(const char *id);
|
||||
static hal_prop_t *read_properties(hd_data_t *hd_data, const char *udi, const char *id);
|
||||
|
||||
|
||||
void hd_scan_manual(hd_data_t *hd_data)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
int i, j;
|
||||
hd_t *hd, *hd1, *next, *hdm, **next2;
|
||||
char *s;
|
||||
char *udi_dir[] = { "/org/freedesktop/Hal/devices", "", "" };
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_manual)) return;
|
||||
|
||||
hd_data->module = mod_manual;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
for(hd = hd_data->manual; hd; hd = next) {
|
||||
next = hd->next;
|
||||
hd->next = NULL;
|
||||
hd_free_hd_list(hd);
|
||||
}
|
||||
hd_data->manual = NULL;
|
||||
|
||||
next2 = &hd_data->manual;
|
||||
|
||||
s = NULL;
|
||||
for(j = 0; j < sizeof udi_dir / sizeof *udi_dir; j++) {
|
||||
str_printf(&s, 0, "%s%s", j == 2 ? "unique-keys" : "udi", udi_dir[j]);
|
||||
if((dir = opendir(hd_get_hddb_path(s)))) {
|
||||
i = 0;
|
||||
while((de = readdir(dir))) {
|
||||
if(*de->d_name == '.') continue;
|
||||
PROGRESS(1, ++i, "read");
|
||||
str_printf(&s, 0, "%s%s%s", udi_dir[j], *udi_dir[j] ? "/" : "", de->d_name);
|
||||
if((hd = hd_read_config(hd_data, s))) {
|
||||
if(hd->status.available != status_unknown) hd->status.available = status_no;
|
||||
ADD2LOG(" got %s\n", hd->unique_id);
|
||||
*next2 = hd;
|
||||
next2 = &hd->next;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
s = free_mem(s);
|
||||
|
||||
hd_data->flags.keep_kmods = 1;
|
||||
for(hdm = hd_data->manual; hdm; hdm = next) {
|
||||
next = hdm->next;
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->unique_id && hdm->unique_id && !strcmp(hd->unique_id, hdm->unique_id)) break;
|
||||
}
|
||||
|
||||
if(hd) {
|
||||
/* just update config status */
|
||||
hd->status = hdm->status;
|
||||
if(hd->status.available != status_unknown) hd->status.available = status_yes;
|
||||
|
||||
if(hdm->config_string) hd->config_string = new_str(hdm->config_string);
|
||||
|
||||
if(hdm->persistent_prop) {
|
||||
hd->persistent_prop = hdm->persistent_prop;
|
||||
hdm->persistent_prop = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* add new entry */
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
*hd = *hdm;
|
||||
hd->next = NULL;
|
||||
hd->tag.freeit = 0;
|
||||
|
||||
hdm->tag.remove = 1;
|
||||
|
||||
if(hd->status.available != status_unknown) hd->status.available = status_no;
|
||||
|
||||
// FIXME: do it really here?
|
||||
if(hd->parent_id) {
|
||||
for(hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
|
||||
if(hd1->unique_id && !strcmp(hd1->unique_id, hd->parent_id)) {
|
||||
hd->attached_to = hd1->idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hd_data->flags.keep_kmods = 0;
|
||||
|
||||
for(hd = hd_data->manual; hd; hd = next) {
|
||||
next = hd->next;
|
||||
hd->next = NULL;
|
||||
if(!hd->tag.remove) {
|
||||
hd_free_hd_list(hd);
|
||||
}
|
||||
else {
|
||||
free_mem(hd);
|
||||
}
|
||||
}
|
||||
hd_data->manual = NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void hd_scan_manual2(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd1;
|
||||
|
||||
/* add persistent properties */
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->persistent_prop) continue;
|
||||
hd->persistent_prop = read_properties(hd_data, hd->udi, hd->unique_id);
|
||||
prop2hd(hd_data, hd, 1);
|
||||
if(hd->status.available != status_unknown) hd->status.available = status_yes;
|
||||
}
|
||||
|
||||
/* check if it's necessary to reconfigure this hardware */
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
hd->status.reconfig = status_no;
|
||||
|
||||
if(hd->status.needed != status_yes) continue;
|
||||
|
||||
if(hd->status.available == status_no) {
|
||||
hd->status.reconfig = status_yes;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(hd->status.available != status_unknown) continue;
|
||||
|
||||
for(hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
|
||||
if(hd1 == hd) continue;
|
||||
|
||||
if(
|
||||
hd1->hw_class == hd->hw_class &&
|
||||
hd1->status.configured == status_new &&
|
||||
hd1->status.available == status_yes
|
||||
) break;
|
||||
}
|
||||
|
||||
if(hd1) hd->status.reconfig = status_yes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *hd_status_value_name(hd_status_value_t status)
|
||||
{
|
||||
return key2value(status_names, status);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read an entry - obsolete
|
||||
*/
|
||||
hd_manual_t *hd_manual_read_entry(hd_data_t *hd_data, const char *id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read an entry
|
||||
*/
|
||||
hal_prop_t *hd_manual_read_entry_old(const char *id)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int line;
|
||||
str_list_t *sl, *sl0;
|
||||
char *s, *s1, *s2;
|
||||
hal_prop_t *prop_list = NULL, *prop = NULL;
|
||||
|
||||
if(!id) return NULL;
|
||||
|
||||
snprintf(path, sizeof path, "%s/%s", hd_get_hddb_path("unique-keys"), id);
|
||||
|
||||
if(!(sl0 = read_file(path, 0, 0))) return prop_list;
|
||||
|
||||
for(line = 1, sl = sl0; sl; sl = sl->next, line++) {
|
||||
s = sl->str;
|
||||
while(isspace(*s)) s++;
|
||||
if(!*s || *s == '#' || *s == ';') continue; /* empty lines & comments */
|
||||
|
||||
s2 = s;
|
||||
s1 = strsep(&s2, "=");
|
||||
|
||||
if(!s2 && *s == '[') continue;
|
||||
|
||||
if(!s2) break;
|
||||
|
||||
if(s1) {
|
||||
if(prop) {
|
||||
prop->next = new_mem(sizeof *prop);
|
||||
prop = prop->next;
|
||||
}
|
||||
else {
|
||||
prop_list = prop = new_mem(sizeof *prop);
|
||||
}
|
||||
|
||||
prop->type = p_string;
|
||||
for(s = s1; *s; s++) if(*s >= 'A' && *s <= 'Z') *s += 'a' - 'A';
|
||||
str_printf(&prop->key, 0, "hwinfo.%s", s1);
|
||||
prop->val.str = canon_str(s2, strlen(s2));
|
||||
}
|
||||
}
|
||||
|
||||
free_str_list(sl0);
|
||||
|
||||
return prop_list;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* write an entry
|
||||
*/
|
||||
|
||||
int hd_manual_write_entry(hd_data_t *hd_data, hd_manual_t *entry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *prop2hd_str(hal_prop_t *prop, const char *id)
|
||||
{
|
||||
return (prop = hal_get_str(prop, id)) ? new_str(prop->val.str) : NULL;
|
||||
}
|
||||
|
||||
|
||||
int32_t prop2hd_int32(hal_prop_t *prop, const char *id)
|
||||
{
|
||||
return (prop = hal_get_int32(prop, id)) ? prop->val.int32 : 0;
|
||||
}
|
||||
|
||||
|
||||
str_list_t *prop2hd_list(hal_prop_t *prop, const char *id)
|
||||
{
|
||||
str_list_t *sl0 = NULL, *sl;
|
||||
|
||||
prop = hal_get_list(prop, id);
|
||||
|
||||
if(prop) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
add_str_list(&sl0, sl->str);
|
||||
}
|
||||
}
|
||||
|
||||
return sl0;
|
||||
}
|
||||
|
||||
|
||||
void prop2hd(hd_data_t *hd_data, hd_t *hd, int status_only)
|
||||
{
|
||||
hal_prop_t *prop, *list;
|
||||
hd_res_t *res;
|
||||
int i;
|
||||
unsigned u, u0, u1, u2, u3, u4;
|
||||
char *s;
|
||||
uint64_t u64_0, u64_1;
|
||||
str_list_t *sl;
|
||||
|
||||
list = hd->persistent_prop;
|
||||
|
||||
hd->config_string = prop2hd_str(list, "hwinfo.configstring");
|
||||
|
||||
if((prop = hal_get_str(list, "hwinfo.configured"))) {
|
||||
hd->status.configured = value2key(status_names, prop->val.str);
|
||||
}
|
||||
|
||||
if((prop = hal_get_str(list, "hwinfo.available"))) {
|
||||
hd->status.available_orig =
|
||||
hd->status.available = value2key(status_names, prop->val.str);
|
||||
}
|
||||
|
||||
if((prop = hal_get_str(list, "hwinfo.needed"))) {
|
||||
hd->status.needed = value2key(status_names, prop->val.str);
|
||||
}
|
||||
|
||||
if((prop = hal_get_str(list, "hwinfo.active"))) {
|
||||
hd->status.active = value2key(status_names, prop->val.str);
|
||||
}
|
||||
|
||||
/*
|
||||
* if the status info is completely missing, fake some:
|
||||
* new hardware, autodetectable, not needed
|
||||
*/
|
||||
if(
|
||||
!hd->status.configured &&
|
||||
!hd->status.available &&
|
||||
!hd->status.needed &&
|
||||
!hd->status.invalid
|
||||
) {
|
||||
hd->status.configured = status_new;
|
||||
hd->status.available = status_yes;
|
||||
hd->status.needed = status_no;
|
||||
}
|
||||
if(!hd->status.active) hd->status.active = status_unknown;
|
||||
|
||||
if(status_only || !list) return;
|
||||
|
||||
hd->udi = prop2hd_str(list, "info.udi");
|
||||
hd->unique_id = prop2hd_str(list, "hwinfo.uniqueid");
|
||||
hd->parent_id = prop2hd_str(list, "hwinfo.parentid");
|
||||
hd->child_ids = prop2hd_list(list, "hwinfo.childids");
|
||||
hd->model = prop2hd_str(list, "hwinfo.model");
|
||||
|
||||
if((prop = hal_get_str(list, "hwinfo.hwclass"))) {
|
||||
hd->hw_class = value2key(hw_items, prop->val.str);
|
||||
}
|
||||
|
||||
hd->broken = prop2hd_int32(list, "hwinfo.broken");
|
||||
|
||||
hd->bus.id = prop2hd_int32(list, "hwinfo.busid");
|
||||
hd->slot = prop2hd_int32(list, "hwinfo.slot");
|
||||
hd->func = prop2hd_int32(list, "hwinfo.func");
|
||||
|
||||
hd->base_class.id = prop2hd_int32(list, "hwinfo.baseclass");
|
||||
hd->sub_class.id = prop2hd_int32(list, "hwinfo.subclass");
|
||||
hd->prog_if.id = prop2hd_int32(list, "hwinfo.progif");
|
||||
|
||||
hd->revision.id = prop2hd_int32(list, "hwinfo.revisionid");
|
||||
hd->revision.name = prop2hd_str(list, "hwinfo.revisionname");
|
||||
|
||||
hd->vendor.id = prop2hd_int32(list, "hwinfo.vendorid");
|
||||
hd->vendor.name = prop2hd_str(list, "hwinfo.vendorname");
|
||||
|
||||
hd->device.id = prop2hd_int32(list, "hwinfo.deviceid");
|
||||
hd->device.name = prop2hd_str(list, "hwinfo.devicename");
|
||||
|
||||
hd->sub_vendor.id = prop2hd_int32(list, "hwinfo.subvendorid");
|
||||
hd->sub_vendor.name = prop2hd_str(list, "hwinfo.subvendorname");
|
||||
|
||||
hd->sub_device.id = prop2hd_int32(list, "hwinfo.subdeviceid");
|
||||
hd->sub_device.name = prop2hd_str(list, "hwinfo.subdevicename");
|
||||
|
||||
hd->compat_device.id = prop2hd_int32(list, "hwinfo.compatdeviceid");
|
||||
hd->compat_device.name = prop2hd_str(list, "hwinfo.compatdevicename");
|
||||
|
||||
hd->serial = prop2hd_str(list, "hwinfo.serial");
|
||||
hd->unix_dev_name = prop2hd_str(list, "hwinfo.unixdevice");
|
||||
hd->unix_dev_name2 = prop2hd_str(list, "hwinfo.unixdevicealt");
|
||||
|
||||
hd->unix_dev_names = prop2hd_list(list, "hwinfo.unixdevicelist");
|
||||
hd->drivers = prop2hd_list(list, "hwinfo.drivers");
|
||||
|
||||
hd->sysfs_id = prop2hd_str(list, "hwinfo.sysfsid");
|
||||
hd->sysfs_bus_id = prop2hd_str(list, "hwinfo.sysfsbusid");
|
||||
hd->sysfs_device_link = prop2hd_str(list, "hwinfo.sysfslink");
|
||||
hd->rom_id = prop2hd_str(list, "hwinfo.romid");
|
||||
hd->usb_guid = prop2hd_str(list, "hwinfo.usbguid");
|
||||
hd->hotplug = prop2hd_int32(list, "hwinfo.hotplug");
|
||||
|
||||
if((s = hal_get_useful_str(list, "hwinfo.hwclasslist"))) {
|
||||
for(u = 0; u < sizeof hd->hw_class_list / sizeof *hd->hw_class_list; u++) {
|
||||
if(*s && s[1] && (i = hex(s, 2)) >= 0) {
|
||||
hd->hw_class_list[u] = i;
|
||||
s += 2;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u = prop2hd_int32(list, "hwinfo.features");
|
||||
if(u & (1 << 0)) hd->is.agp = 1;
|
||||
if(u & (1 << 1)) hd->is.isapnp = 1;
|
||||
if(u & (1 << 2)) hd->is.softraiddisk = 1;
|
||||
if(u & (1 << 3)) hd->is.zip = 1;
|
||||
if(u & (1 << 4)) hd->is.cdr = 1;
|
||||
if(u & (1 << 5)) hd->is.cdrw = 1;
|
||||
if(u & (1 << 6)) hd->is.dvd = 1;
|
||||
if(u & (1 << 7)) hd->is.dvdr = 1;
|
||||
if(u & (1 << 8)) hd->is.dvdram = 1;
|
||||
if(u & (1 << 9)) hd->is.pppoe = 1;
|
||||
if(u & (1 << 10)) hd->is.wlan = 1;
|
||||
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.memory"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "0x%"SCNx64",0x%"SCNx64",%u,%u,%u", &u64_0, &u64_1, &u0, &u1, &u2) == 5) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_mem;
|
||||
res->mem.base = u64_0;
|
||||
res->mem.range = u64_1;
|
||||
res->mem.enabled = u0;
|
||||
res->mem.access = u1;
|
||||
res->mem.prefetch = u2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.physmemory"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "0x%"SCNx64"", &u64_0) == 1) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_phys_mem;
|
||||
res->phys_mem.range = u64_0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.io"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "0x%"SCNx64",0x%"SCNx64",%u,%u", &u64_0, &u64_1, &u0, &u1) == 4) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_io;
|
||||
res->io.base = u64_0;
|
||||
res->io.range = u64_1;
|
||||
res->io.enabled = u0;
|
||||
res->io.access = u1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.interrupts"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "%u,%u,%u", &u0, &u1, &u2) == 3) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_irq;
|
||||
res->irq.base = u0;
|
||||
res->irq.triggered = u1;
|
||||
res->irq.enabled = u2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.dma"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "%u,%u", &u0, &u1) == 2) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_dma;
|
||||
res->dma.base = u0;
|
||||
res->dma.enabled = u1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.size"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "%u,%u,%u", &u0, &u1, &u2) == 3) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_size;
|
||||
res->size.unit = u0;
|
||||
res->size.val1 = u1;
|
||||
res->size.val2 = u2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.baud"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "%u,%u,%u,%u,%u", &u0, &u1, &u2, &u3, &u4) == 5) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_baud;
|
||||
res->baud.speed = u0;
|
||||
res->baud.bits = u1;
|
||||
res->baud.stopbits = u2;
|
||||
res->baud.parity = (char) u3;
|
||||
res->baud.handshake = (char) u4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.cache"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "%u", &u0) == 1) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_cache;
|
||||
res->cache.size = u0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.diskgeometry"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "%u,%u,%u,%u", &u0, &u1, &u2, &u3) == 4) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_disk_geo;
|
||||
res->disk_geo.cyls = u0;
|
||||
res->disk_geo.heads = u1;
|
||||
res->disk_geo.sectors = u2;
|
||||
res->disk_geo.geotype = u3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.monitor"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "%u,%u,%u,%u", &u0, &u1, &u2, &u3) == 4) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_monitor;
|
||||
res->monitor.width = u0;
|
||||
res->monitor.height = u1;
|
||||
res->monitor.vfreq = u2;
|
||||
res->monitor.interlaced = u3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((prop = hal_get_list(list, "hwinfo.res.framebuffer"))) {
|
||||
for(sl = prop->val.list; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "%u,%u,%u,%u,%u", &u0, &u1, &u2, &u3, &u4) == 5) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->any.type = res_framebuffer;
|
||||
res->framebuffer.width = u0;
|
||||
res->framebuffer.height = u1;
|
||||
res->framebuffer.bytes_p_line = u2;
|
||||
res->framebuffer.colorbits = u3;
|
||||
res->framebuffer.mode = u4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hddb_add_info(hd_data, hd);
|
||||
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *hal_get_new(hal_prop_t **list, const char *key)
|
||||
{
|
||||
hal_prop_t *prop;
|
||||
|
||||
prop = hal_get_any(*list, key);
|
||||
if(!prop) {
|
||||
prop = new_mem(sizeof *prop);
|
||||
prop->next = *list;
|
||||
*list = prop;
|
||||
prop->key = new_str(key);
|
||||
}
|
||||
else {
|
||||
hal_invalidate_all(prop, key);
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
||||
void hd2prop_add_int32(hal_prop_t **list, const char *key, int32_t i)
|
||||
{
|
||||
hal_prop_t *prop;
|
||||
|
||||
if(i) {
|
||||
prop = hal_get_new(list, key);
|
||||
prop->type = p_int32;
|
||||
prop->val.int32 = i;
|
||||
}
|
||||
else {
|
||||
hal_invalidate_all(*list, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hd2prop_add_str(hal_prop_t **list, const char *key, const char *str)
|
||||
{
|
||||
hal_prop_t *prop;
|
||||
|
||||
if(str) {
|
||||
prop = hal_get_new(list, key);
|
||||
prop->type = p_string;
|
||||
prop->val.str = new_str(str);
|
||||
}
|
||||
else {
|
||||
hal_invalidate_all(*list, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hd2prop_add_list(hal_prop_t **list, const char *key, str_list_t *sl)
|
||||
{
|
||||
hal_prop_t *prop;
|
||||
|
||||
if(sl) {
|
||||
prop = hal_get_new(list, key);
|
||||
prop->type = p_list;
|
||||
for(; sl; sl = sl->next) {
|
||||
add_str_list(&prop->val.list, sl->str);
|
||||
}
|
||||
}
|
||||
else {
|
||||
hal_invalidate_all(*list, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hd2prop_append_list(hal_prop_t **list, const char *key, char *str)
|
||||
{
|
||||
hal_prop_t *prop;
|
||||
str_list_t *sl = NULL;
|
||||
|
||||
if(!str) return;
|
||||
|
||||
prop = hal_get_list(*list, key);
|
||||
|
||||
if(!prop) {
|
||||
add_str_list(&sl, str);
|
||||
hd2prop_add_list(list, key, sl);
|
||||
return;
|
||||
}
|
||||
|
||||
add_str_list(&prop->val.list, str);
|
||||
}
|
||||
|
||||
|
||||
void hd2prop(hd_data_t *hd_data, hd_t *hd)
|
||||
{
|
||||
hal_prop_t **list;
|
||||
char *s = NULL;
|
||||
unsigned u;
|
||||
hd_res_t *res;
|
||||
|
||||
list = &hd->persistent_prop;
|
||||
|
||||
hd2prop_add_str(list, "info.udi", hd->udi);
|
||||
|
||||
hd2prop_add_str(list, "hwinfo.uniqueid", hd->unique_id);
|
||||
hd2prop_add_str(list, "hwinfo.parentid", hd->parent_id);
|
||||
|
||||
hd2prop_add_list(list, "hwinfo.childids", hd->child_ids);
|
||||
|
||||
hd2prop_add_str(list, "hwinfo.model", hd->model);
|
||||
hd2prop_add_str(list, "hwinfo.configstring", hd->config_string);
|
||||
hd2prop_add_str(list, "hwinfo.hwclass", key2value(hw_items, hd->hw_class));
|
||||
hd2prop_add_str(list, "hwinfo.configured", key2value(status_names, hd->status.configured));
|
||||
hd2prop_add_str(list, "hwinfo.available", key2value(status_names, hd->status.available));
|
||||
hd2prop_add_str(list, "hwinfo.needed", key2value(status_names, hd->status.needed));
|
||||
hd2prop_add_str(list, "hwinfo.active", key2value(status_names, hd->status.active));
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.broken", hd->broken);
|
||||
hd2prop_add_int32(list, "hwinfo.bus", hd->bus.id);
|
||||
hd2prop_add_int32(list, "hwinfo.slot", hd->slot);
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.func", hd->func);
|
||||
hd2prop_add_int32(list, "hwinfo.baseclass", hd->base_class.id);
|
||||
hd2prop_add_int32(list, "hwinfo.subclass", hd->sub_class.id);
|
||||
hd2prop_add_int32(list, "hwinfo.progif", hd->prog_if.id);
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.revisionid", hd->revision.id);
|
||||
hd2prop_add_str(list, "hwinfo.revisionname", hd->revision.name);
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.vendorid", hd->vendor.id);
|
||||
hd2prop_add_str(list, "hwinfo.vendorname", hd->vendor.name);
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.deviceid", hd->device.id);
|
||||
hd2prop_add_str(list, "hwinfo.devicename", hd->device.name);
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.subvendorid", hd->sub_vendor.id);
|
||||
hd2prop_add_str(list, "hwinfo.subvendorname", hd->sub_vendor.name);
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.subdeviceid", hd->sub_device.id);
|
||||
hd2prop_add_str(list, "hwinfo.subdevicename", hd->sub_device.name);
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.compatvendorid", hd->compat_vendor.id);
|
||||
hd2prop_add_int32(list, "hwinfo.compatdeviceid", hd->compat_device.id);
|
||||
|
||||
hd2prop_add_str(list, "hwinfo.serial", hd->serial);
|
||||
hd2prop_add_str(list, "hwinfo.unixdevice", hd->unix_dev_name);
|
||||
hd2prop_add_str(list, "hwinfo.unixdevicealt", hd->unix_dev_name2);
|
||||
|
||||
hd2prop_add_list(list, "hwinfo.unixdevicelist", hd->unix_dev_names);
|
||||
hd2prop_add_list(list, "hwinfo.drivers", hd->drivers);
|
||||
|
||||
hd2prop_add_str(list, "hwinfo.sysfsid", hd->sysfs_id);
|
||||
hd2prop_add_str(list, "hwinfo.sysfsbusid", hd->sysfs_bus_id);
|
||||
hd2prop_add_str(list, "hwinfo.sysfslink", hd->sysfs_device_link);
|
||||
hd2prop_add_str(list, "hwinfo.romid", hd->rom_id);
|
||||
hd2prop_add_str(list, "hwinfo.usbguid", hd->usb_guid);
|
||||
hd2prop_add_int32(list, "hwinfo.hotplug", hd->hotplug);
|
||||
|
||||
for(u = 0; u < sizeof hd->hw_class_list / sizeof *hd->hw_class_list; u++) {
|
||||
str_printf(&s, -1, "%02x", hd->hw_class_list[u]);
|
||||
}
|
||||
hd2prop_add_str(list, "hwinfo.hwclasslist", s);
|
||||
s = free_mem(s);
|
||||
|
||||
u = 0;
|
||||
if(hd->is.agp) u |= 1 << 0;
|
||||
if(hd->is.isapnp) u |= 1 << 1;
|
||||
if(hd->is.softraiddisk) u |= 1 << 2;
|
||||
if(hd->is.zip) u |= 1 << 3;
|
||||
if(hd->is.cdr) u |= 1 << 4;
|
||||
if(hd->is.cdrw) u |= 1 << 5;
|
||||
if(hd->is.dvd) u |= 1 << 6;
|
||||
if(hd->is.dvdr) u |= 1 << 7;
|
||||
if(hd->is.dvdram) u |= 1 << 8;
|
||||
if(hd->is.pppoe) u |= 1 << 9;
|
||||
if(hd->is.wlan) u |= 1 << 10;
|
||||
|
||||
hd2prop_add_int32(list, "hwinfo.features", u);
|
||||
|
||||
hal_invalidate_all(*list, "hwinfo.res.memory");
|
||||
hal_invalidate_all(*list, "hwinfo.res.physmemory");
|
||||
hal_invalidate_all(*list, "hwinfo.res.io");
|
||||
hal_invalidate_all(*list, "hwinfo.res.interrupts");
|
||||
hal_invalidate_all(*list, "hwinfo.res.dma");
|
||||
hal_invalidate_all(*list, "hwinfo.res.size");
|
||||
hal_invalidate_all(*list, "hwinfo.res.baud");
|
||||
hal_invalidate_all(*list, "hwinfo.res.cache");
|
||||
hal_invalidate_all(*list, "hwinfo.res.diskgeometry");
|
||||
hal_invalidate_all(*list, "hwinfo.res.monitor");
|
||||
hal_invalidate_all(*list, "hwinfo.res.framebuffer");
|
||||
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
switch(res->any.type) {
|
||||
case res_mem:
|
||||
str_printf(&s, 0,
|
||||
"0x%"PRIx64",0x%"PRIx64",%u,%u,%u",
|
||||
res->mem.base, res->mem.range, res->mem.enabled, res->mem.access, res->mem.prefetch
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.memory", s);
|
||||
break;
|
||||
|
||||
case res_phys_mem:
|
||||
str_printf(&s, 0,
|
||||
"0x%"PRIx64,
|
||||
res->phys_mem.range
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.physmemory", s);
|
||||
break;
|
||||
|
||||
case res_io:
|
||||
str_printf(&s, 0,
|
||||
"0x%"PRIx64",0x%"PRIx64",%u,%u",
|
||||
res->io.base, res->io.range, res->io.enabled, res->io.access
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.io", s);
|
||||
break;
|
||||
|
||||
case res_irq:
|
||||
str_printf(&s, 0,
|
||||
"%u,%u,%u",
|
||||
res->irq.base, res->irq.triggered, res->irq.enabled
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.interrupts", s);
|
||||
break;
|
||||
|
||||
case res_dma:
|
||||
str_printf(&s, 0,
|
||||
"%u,%u",
|
||||
res->dma.base, res->dma.enabled
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.dma", s);
|
||||
break;
|
||||
|
||||
case res_size:
|
||||
str_printf(&s, 0,
|
||||
"%u,%"PRIu64",%"PRIu64,
|
||||
res->size.unit, res->size.val1, res->size.val2
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.size", s);
|
||||
break;
|
||||
|
||||
case res_baud:
|
||||
str_printf(&s, 0,
|
||||
"%u,%u,%u,0x%02x,0x%02x",
|
||||
res->baud.speed, res->baud.bits, res->baud.stopbits,
|
||||
(unsigned) res->baud.parity, (unsigned) res->baud.handshake
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.baud", s);
|
||||
break;
|
||||
|
||||
case res_cache:
|
||||
str_printf(&s, 0,
|
||||
"%u",
|
||||
res->cache.size
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.cache", s);
|
||||
break;
|
||||
|
||||
case res_disk_geo:
|
||||
str_printf(&s, 0,
|
||||
"%u,%u,%u,%u",
|
||||
res->disk_geo.cyls, res->disk_geo.heads, res->disk_geo.sectors, res->disk_geo.geotype
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.diskgeometry", s);
|
||||
break;
|
||||
|
||||
case res_monitor:
|
||||
str_printf(&s, 0,
|
||||
"%u,%u,%u,%u",
|
||||
res->monitor.width, res->monitor.height, res->monitor.vfreq, res->monitor.interlaced
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.monitor", s);
|
||||
break;
|
||||
|
||||
case res_framebuffer:
|
||||
str_printf(&s, 0,
|
||||
"%u,%u,%u,%u,%u",
|
||||
res->framebuffer.width, res->framebuffer.height, res->framebuffer.bytes_p_line,
|
||||
res->framebuffer.colorbits, res->framebuffer.mode
|
||||
);
|
||||
hd2prop_append_list(list, "hwinfo.res.framebuffer", s);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s = free_mem(s);
|
||||
|
||||
}
|
||||
|
||||
|
||||
hal_prop_t *read_properties(hd_data_t *hd_data, const char *udi, const char *id)
|
||||
{
|
||||
hd_t *hd;
|
||||
hal_prop_t *prop = NULL;
|
||||
|
||||
if(udi) {
|
||||
prop = hd_read_properties(udi);
|
||||
ADD2LOG(" prop read: %s (%s)\n", udi, prop ? "ok" : "failed");
|
||||
}
|
||||
|
||||
if(prop) return prop;
|
||||
|
||||
if(id && !udi) {
|
||||
/* try to find udi entry */
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->udi && hd->unique_id && !strcmp(id, hd->unique_id)) {
|
||||
udi = hd->udi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(udi) {
|
||||
prop = hd_read_properties(udi);
|
||||
ADD2LOG(" prop read: %s (%s)\n", udi, prop ? "ok" : "failed");
|
||||
}
|
||||
}
|
||||
|
||||
if(!prop) {
|
||||
prop = hd_read_properties(id);
|
||||
ADD2LOG(" prop read: %s (%s)\n", id, prop ? "ok" : "failed");
|
||||
}
|
||||
if(!prop) {
|
||||
prop = hd_manual_read_entry_old(id);
|
||||
ADD2LOG(" old prop read: %s (%s)\n", id, prop ? "ok" : "failed");
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
||||
hd_t *hd_read_config(hd_data_t *hd_data, const char *id)
|
||||
{
|
||||
hd_t *hd = NULL;
|
||||
hal_prop_t *prop = NULL;
|
||||
const char *udi = NULL;
|
||||
|
||||
/* only of we didn't already (check internal db pointer) */
|
||||
/* prop2hd() makes db lookups */
|
||||
if(!hd_data->hddb2[1]) hddb_init(hd_data);
|
||||
|
||||
if(id && *id == '/') {
|
||||
udi = id;
|
||||
id = NULL;
|
||||
}
|
||||
|
||||
prop = read_properties(hd_data, udi, id);
|
||||
|
||||
if(prop) {
|
||||
hd = new_mem(sizeof *hd);
|
||||
hd->idx = ++(hd_data->last_idx);
|
||||
hd->module = hd_data->module;
|
||||
hd->line = __LINE__;
|
||||
hd->tag.freeit = 1; /* make it a 'stand alone' entry */
|
||||
hd->persistent_prop = prop;
|
||||
prop2hd(hd_data, hd, 0);
|
||||
}
|
||||
|
||||
return hd;
|
||||
}
|
||||
|
||||
|
||||
int hd_write_config(hd_data_t *hd_data, hd_t *hd)
|
||||
{
|
||||
char *udi;
|
||||
|
||||
if(!hd_report_this(hd_data, hd)) return 0;
|
||||
|
||||
hd2prop(hd_data, hd);
|
||||
|
||||
udi = hd->unique_id;
|
||||
if(hd->udi) udi = hd->udi;
|
||||
|
||||
if(!udi) return 5;
|
||||
|
||||
return hd_write_properties(udi, hd->persistent_prop);
|
||||
}
|
||||
|
||||
|
||||
#endif /* LIBHD_TINY */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
void hd_scan_manual(hd_data_t *hd_data);
|
||||
void hd_scan_manual2(hd_data_t *hd_data);
|
|
@ -0,0 +1,851 @@
|
|||
#if defined(__i386__) || defined (__x86_64__)
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/io.h>
|
||||
#include <sys/time.h>
|
||||
#include <x86emu.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
|
||||
#define STR_SIZE 128
|
||||
|
||||
#define VBIOS_ROM 0xc0000
|
||||
#define VBIOS_ROM_SIZE 0x10000
|
||||
|
||||
#define VBIOS_MEM 0xa0000
|
||||
#define VBIOS_MEM_SIZE 0x10000
|
||||
|
||||
#define VBE_BUF 0x8000
|
||||
|
||||
#define ADD_RES(w, h, f, i) \
|
||||
res[res_cnt].width = w, \
|
||||
res[res_cnt].height = h, \
|
||||
res[res_cnt].vfreq = f, \
|
||||
res[res_cnt++].il = i;
|
||||
|
||||
#define LPRINTF(a...) hd_log_printf(vm->hd_data, a)
|
||||
|
||||
typedef struct vm_s {
|
||||
x86emu_t *emu;
|
||||
x86emu_memio_handler_t old_memio;
|
||||
|
||||
unsigned ports;
|
||||
unsigned force:1;
|
||||
unsigned timeout;
|
||||
unsigned no_io:1;
|
||||
|
||||
unsigned all_modes:1;
|
||||
unsigned mode;
|
||||
unsigned mode_set:1;
|
||||
|
||||
unsigned trace_flags;
|
||||
unsigned dump_flags;
|
||||
|
||||
int trace_only;
|
||||
int dump_only;
|
||||
|
||||
int exec_count;
|
||||
|
||||
hd_data_t *hd_data;
|
||||
} vm_t;
|
||||
|
||||
|
||||
static void flush_log(x86emu_t *emu, char *buf, unsigned size);
|
||||
|
||||
static void vm_write_byte(x86emu_t *emu, unsigned addr, unsigned val, unsigned perm);
|
||||
static void vm_write_word(x86emu_t *emu, unsigned addr, unsigned val, unsigned perm);
|
||||
// static void vm_write_dword(x86emu_t *emu, unsigned addr, unsigned val, unsigned perm);
|
||||
static void copy_to_vm(x86emu_t *emu, unsigned dst, unsigned char *src, unsigned size, unsigned perm);
|
||||
static void copy_from_vm(x86emu_t *emu, void *dst, unsigned src, unsigned len);
|
||||
|
||||
static int do_int(x86emu_t *emu, u8 num, unsigned type);
|
||||
static vm_t *vm_new(void);
|
||||
static void vm_free(vm_t *vm);
|
||||
static unsigned vm_run(x86emu_t *emu, double *t);
|
||||
static int vm_prepare(vm_t *vm);
|
||||
|
||||
static unsigned new_memio(x86emu_t *emu, u32 addr, u32 *val, unsigned type);
|
||||
static double get_time(void);
|
||||
static void *map_mem(vm_t *vm, unsigned start, unsigned size, int rw);
|
||||
|
||||
void print_vbe_info(vm_t *vm, x86emu_t *emu, unsigned mode);
|
||||
|
||||
void probe_all(vm_t *vm, vbe_info_t *vbe);
|
||||
void get_video_mode(vm_t *vm, vbe_info_t *vbe);
|
||||
void list_modes(vm_t *vm, vbe_info_t *vbe);
|
||||
|
||||
void print_edid(int port, unsigned char *edid);
|
||||
int chk_edid_info(unsigned char *edid);
|
||||
|
||||
|
||||
void get_vbe_info(hd_data_t *hd_data, vbe_info_t *vbe)
|
||||
{
|
||||
int i, err;
|
||||
char *t;
|
||||
unsigned u, tbits, dbits;
|
||||
str_list_t *sl;
|
||||
vm_t *vm;
|
||||
|
||||
PROGRESS(4, 1, "vbe info");
|
||||
|
||||
vm = vm_new();
|
||||
vm->hd_data = hd_data;
|
||||
hd_data->vm = vm;
|
||||
|
||||
for(sl = get_probe_val_list(hd_data, pr_x86emu); sl && (t = sl->str); sl = sl->next) {
|
||||
err = 0;
|
||||
u = 1;
|
||||
tbits = dbits = 0;
|
||||
while(*t == '+' || *t == '-') u = *t++ == '+' ? 1 : 0;
|
||||
if(!strcmp(t, "trace")) tbits = X86EMU_TRACE_DEFAULT;
|
||||
else if(!strcmp(t, "code")) tbits = X86EMU_TRACE_CODE;
|
||||
else if(!strcmp(t, "regs")) tbits = X86EMU_TRACE_REGS;
|
||||
else if(!strcmp(t, "data")) tbits = X86EMU_TRACE_DATA;
|
||||
else if(!strcmp(t, "acc")) tbits = X86EMU_TRACE_ACC;
|
||||
else if(!strcmp(t, "io")) tbits = X86EMU_TRACE_IO;
|
||||
else if(!strcmp(t, "ints")) tbits = X86EMU_TRACE_INTS;
|
||||
else if(!strcmp(t, "time")) tbits = X86EMU_TRACE_TIME;
|
||||
else if(!strcmp(t, "dump")) dbits = X86EMU_DUMP_DEFAULT;
|
||||
else if(!strcmp(t, "dump.regs")) dbits = X86EMU_DUMP_REGS;
|
||||
else if(!strcmp(t, "dump.mem")) dbits = X86EMU_DUMP_MEM;
|
||||
else if(!strcmp(t, "dump.mem.acc")) dbits = X86EMU_DUMP_ACC_MEM;
|
||||
else if(!strcmp(t, "dump.mem.inv")) dbits = X86EMU_DUMP_INV_MEM;
|
||||
else if(!strcmp(t, "dump.attr")) dbits = X86EMU_DUMP_ATTR;
|
||||
else if(!strcmp(t, "dump.io")) dbits = X86EMU_DUMP_IO;
|
||||
else if(!strcmp(t, "dump.ints")) dbits = X86EMU_DUMP_INTS;
|
||||
else if(!strcmp(t, "dump.time")) dbits = X86EMU_DUMP_TIME;
|
||||
else if(!strcmp(t, "force")) vm->force = u;
|
||||
else if(!strncmp(t, "timeout=", sizeof "timeout=" - 1)) {
|
||||
i = strtol(t + sizeof "timeout=" - 1, NULL, 0);
|
||||
if(i) vm->timeout = i;
|
||||
}
|
||||
else if(!strncmp(t, "trace.only=", sizeof "trace.only=" - 1)) {
|
||||
vm->trace_only = strtol(t + sizeof "trace.only=" - 1, NULL, 0);
|
||||
}
|
||||
else if(!strncmp(t, "dump.only=", sizeof "dump.only=" - 1)) {
|
||||
vm->dump_only = strtol(t + sizeof "dump.only=" - 1, NULL, 0);
|
||||
}
|
||||
else err = 5;
|
||||
if(err) {
|
||||
ADD2LOG("x86emu: invalid flag '%s'\n", t);
|
||||
}
|
||||
else {
|
||||
if(tbits) {
|
||||
if(u) {
|
||||
vm->trace_flags |= tbits;
|
||||
}
|
||||
else {
|
||||
vm->trace_flags &= ~tbits;
|
||||
}
|
||||
}
|
||||
if(dbits) {
|
||||
if(u) {
|
||||
vm->dump_flags |= dbits;
|
||||
}
|
||||
else {
|
||||
vm->dump_flags &= ~dbits;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!vm_prepare(vm)) {
|
||||
ADD2LOG("x86emu: could not init vm\n");
|
||||
vm_free(vm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
vm->ports = 3;
|
||||
|
||||
i = get_probe_val_int(hd_data, pr_bios_ddc_ports);
|
||||
if(i > sizeof vbe->ddc_port / sizeof *vbe->ddc_port) i = sizeof vbe->ddc_port / sizeof *vbe->ddc_port;
|
||||
if(i) vm->ports = i;
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_bios_fb)) {
|
||||
PROGRESS(4, 2, "mode info");
|
||||
|
||||
// there shouldn't any real io be needed for this
|
||||
vm->no_io = 1;
|
||||
list_modes(vm, vbe);
|
||||
}
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_bios_ddc)) {
|
||||
PROGRESS(4, 3, "ddc info");
|
||||
|
||||
ADD2LOG("vbe: probing %d ports\n", vm->ports);
|
||||
|
||||
// for ddc probing we have to allow direct io accesses
|
||||
vm->no_io = 0;
|
||||
probe_all(vm, vbe);
|
||||
}
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_bios_mode)) {
|
||||
PROGRESS(4, 4, "gfx mode");
|
||||
|
||||
// there shouldn't any real io be needed for this
|
||||
vm->no_io = 1;
|
||||
get_video_mode(vm, vbe);
|
||||
}
|
||||
|
||||
vm_free(vm);
|
||||
}
|
||||
|
||||
|
||||
void flush_log(x86emu_t *emu, char *buf, unsigned size)
|
||||
{
|
||||
vm_t *vm = emu->private;
|
||||
hd_data_t *hd_data = vm->hd_data;
|
||||
|
||||
if(!buf || !size || !hd_data) return;
|
||||
|
||||
hd_log(hd_data, buf, size);
|
||||
}
|
||||
|
||||
|
||||
unsigned vm_read_segofs16(x86emu_t *emu, unsigned addr)
|
||||
{
|
||||
return x86emu_read_word(emu, addr) + (x86emu_read_word(emu, addr + 2) << 4);
|
||||
}
|
||||
|
||||
|
||||
void vm_write_byte(x86emu_t *emu, unsigned addr, unsigned val, unsigned perm)
|
||||
{
|
||||
x86emu_write_byte_noperm(emu, addr, val);
|
||||
x86emu_set_perm(emu, addr, addr, perm | X86EMU_PERM_VALID);
|
||||
}
|
||||
|
||||
|
||||
void vm_write_word(x86emu_t *emu, unsigned addr, unsigned val, unsigned perm)
|
||||
{
|
||||
x86emu_write_byte_noperm(emu, addr, val);
|
||||
x86emu_write_byte_noperm(emu, addr + 1, val >> 8);
|
||||
x86emu_set_perm(emu, addr, addr + 1, perm | X86EMU_PERM_VALID);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void vm_write_dword(x86emu_t *emu, unsigned addr, unsigned val, unsigned perm)
|
||||
{
|
||||
x86emu_write_byte_noperm(emu, addr, val);
|
||||
x86emu_write_byte_noperm(emu, addr + 1, val >> 8);
|
||||
x86emu_write_byte_noperm(emu, addr + 2, val >> 16);
|
||||
x86emu_write_byte_noperm(emu, addr + 3, val >> 24);
|
||||
x86emu_set_perm(emu, addr, addr + 3, perm | X86EMU_PERM_VALID);
|
||||
}
|
||||
#endif
|
||||
|
||||
void copy_to_vm(x86emu_t *emu, unsigned dst, unsigned char *src, unsigned size, unsigned perm)
|
||||
{
|
||||
if(!size) return;
|
||||
|
||||
while(size--) vm_write_byte(emu, dst++, *src++, perm);
|
||||
}
|
||||
|
||||
|
||||
void copy_from_vm(x86emu_t *emu, void *dst, unsigned src, unsigned len)
|
||||
{
|
||||
unsigned char *p = dst;
|
||||
unsigned u;
|
||||
|
||||
for(u = 0; u < len; u++) {
|
||||
p[u] = x86emu_read_byte_noperm(emu, src + u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int do_int(x86emu_t *emu, u8 num, unsigned type)
|
||||
{
|
||||
if((type & 0xff) == INTR_TYPE_FAULT) {
|
||||
x86emu_stop(emu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ignore ints != (0x10 or 0x42 or 0x6d)
|
||||
if(num != 0x10 && num != 0x42 && num != 0x6d) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
vm_t *vm_new()
|
||||
{
|
||||
vm_t *vm;
|
||||
|
||||
vm = calloc(1, sizeof *vm);
|
||||
|
||||
vm->emu = x86emu_new(0, X86EMU_PERM_RW);
|
||||
vm->emu->private = vm;
|
||||
|
||||
x86emu_set_log(vm->emu, 200000000, flush_log);
|
||||
x86emu_set_intr_handler(vm->emu, do_int);
|
||||
|
||||
vm->trace_only = -1;
|
||||
vm->dump_only = -1;
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
|
||||
void vm_free(vm_t *vm)
|
||||
{
|
||||
if(!vm) return;
|
||||
|
||||
x86emu_done(vm->emu);
|
||||
|
||||
free(vm);
|
||||
}
|
||||
|
||||
|
||||
unsigned vm_run(x86emu_t *emu, double *t)
|
||||
{
|
||||
vm_t *vm = emu->private;
|
||||
unsigned err;
|
||||
|
||||
x86emu_log(emu, "=== emulation log %d %s===\n", vm->exec_count, vm->no_io ? "(no i/o) " : "");
|
||||
|
||||
*t = get_time();
|
||||
|
||||
if(vm->trace_only == -1 || vm->trace_only == vm->exec_count) {
|
||||
emu->log.trace = vm->trace_flags;
|
||||
}
|
||||
else {
|
||||
emu->log.trace = 0;
|
||||
}
|
||||
|
||||
x86emu_reset_access_stats(emu);
|
||||
|
||||
iopl(3);
|
||||
err = x86emu_run(emu, X86EMU_RUN_LOOP | X86EMU_RUN_NO_CODE | X86EMU_RUN_TIMEOUT);
|
||||
iopl(0);
|
||||
|
||||
*t = get_time() - *t;
|
||||
|
||||
if(
|
||||
vm->dump_flags &&
|
||||
(vm->dump_only == -1 || vm->dump_only == vm->exec_count)
|
||||
) {
|
||||
x86emu_log(emu, "\n; - - - final state\n");
|
||||
x86emu_dump(emu, vm->dump_flags);
|
||||
x86emu_log(emu, "; - - -\n");
|
||||
}
|
||||
|
||||
x86emu_log(emu, "=== emulation log %d end ===\n", vm->exec_count);
|
||||
|
||||
x86emu_clear_log(emu, 1);
|
||||
|
||||
vm->exec_count++;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int vm_prepare(vm_t *vm)
|
||||
{
|
||||
int ok = 0;
|
||||
unsigned u;
|
||||
unsigned char *p1, *p2;
|
||||
|
||||
LPRINTF("=== bios setup ===\n");
|
||||
|
||||
p1 = map_mem(vm, 0, 0x1000, 0);
|
||||
if(!p1) {
|
||||
LPRINTF("failed to read /dev/mem\n");
|
||||
return ok;
|
||||
}
|
||||
|
||||
copy_to_vm(vm->emu, 0x10*4, p1 + 0x10*4, 4, X86EMU_PERM_RW); // video bios entry
|
||||
copy_to_vm(vm->emu, 0x42*4, p1 + 0x42*4, 4, X86EMU_PERM_RW); // old video bios entry
|
||||
copy_to_vm(vm->emu, 0x6d*4, p1 + 0x6d*4, 4, X86EMU_PERM_RW); // saved video bios entry
|
||||
copy_to_vm(vm->emu, 0x400, p1 + 0x400, 0x100, X86EMU_PERM_RW);
|
||||
|
||||
munmap(p1, 0x1000);
|
||||
|
||||
p2 = map_mem(vm, VBIOS_ROM, VBIOS_ROM_SIZE, 0);
|
||||
if(!p2 || p2[0] != 0x55 || p2[1] != 0xaa || p2[2] == 0) {
|
||||
if(p2) munmap(p2, VBIOS_ROM_SIZE);
|
||||
LPRINTF("error: no video bios\n");
|
||||
return ok;
|
||||
}
|
||||
|
||||
copy_to_vm(vm->emu, VBIOS_ROM, p2, p2[2] * 0x200, X86EMU_PERM_RX);
|
||||
|
||||
munmap(p2, VBIOS_ROM_SIZE);
|
||||
|
||||
LPRINTF("video bios: size 0x%04x\n", x86emu_read_byte(vm->emu, VBIOS_ROM + 2) * 0x200);
|
||||
LPRINTF("video bios: entry 0x%04x:0x%04x\n",
|
||||
x86emu_read_word(vm->emu, 0x10*4 + 2),
|
||||
x86emu_read_word(vm->emu, 0x10*4)
|
||||
);
|
||||
|
||||
// initialize fake video memory
|
||||
for(u = VBIOS_MEM; u < VBIOS_MEM + VBIOS_MEM_SIZE; u++) {
|
||||
vm_write_byte(vm->emu, u, 0, X86EMU_PERM_RW);
|
||||
}
|
||||
|
||||
// start address 0:0x7c00
|
||||
x86emu_set_seg_register(vm->emu, vm->emu->x86.R_CS_SEL, 0);
|
||||
vm->emu->x86.R_EIP = 0x7c00;
|
||||
|
||||
// int 0x10 ; hlt
|
||||
vm_write_word(vm->emu, 0x7c00, 0x10cd, X86EMU_PERM_RX);
|
||||
vm_write_byte(vm->emu, 0x7c02, 0xf4, X86EMU_PERM_RX);
|
||||
|
||||
// stack & buffer space
|
||||
x86emu_set_perm(vm->emu, VBE_BUF, 0xffff, X86EMU_PERM_RW);
|
||||
|
||||
vm->emu->timeout = vm->timeout ?: 20;
|
||||
|
||||
vm->old_memio = x86emu_set_memio_handler(vm->emu, new_memio);
|
||||
|
||||
ok = 1;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Use our own memory and i/o access handler to block all i/o accesses if vm->no_io
|
||||
* is set.
|
||||
*/
|
||||
unsigned new_memio(x86emu_t *emu, u32 addr, u32 *val, unsigned type)
|
||||
{
|
||||
vm_t *vm = emu->private;
|
||||
|
||||
if(vm->no_io) {
|
||||
if((type & ~0xff) == X86EMU_MEMIO_I) {
|
||||
*val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((type & ~0xff) == X86EMU_MEMIO_O) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return vm->old_memio(emu, addr, val, type);
|
||||
}
|
||||
|
||||
|
||||
double get_time()
|
||||
{
|
||||
static struct timeval t0 = { };
|
||||
struct timeval t1 = { };
|
||||
|
||||
gettimeofday(&t1, NULL);
|
||||
|
||||
if(!timerisset(&t0)) t0 = t1;
|
||||
|
||||
timersub(&t1, &t0, &t1);
|
||||
|
||||
return t1.tv_sec + t1.tv_usec / 1e6;
|
||||
}
|
||||
|
||||
|
||||
void *map_mem(vm_t *vm, unsigned start, unsigned size, int rw)
|
||||
{
|
||||
int fd;
|
||||
void *p;
|
||||
|
||||
if(!size) return NULL;
|
||||
|
||||
fd = open("/dev/mem", rw ? O_RDWR : O_RDONLY);
|
||||
|
||||
if(fd == -1) return NULL;
|
||||
|
||||
p = mmap(NULL, size, rw ? PROT_READ | PROT_WRITE : PROT_READ, MAP_SHARED, fd, start);
|
||||
|
||||
if(p == MAP_FAILED) {
|
||||
LPRINTF("error: [0x%x, %u]: mmap failed: %s\n", start, size, strerror(errno));
|
||||
close(fd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LPRINTF("[0x%x, %u]: mmap ok\n", start, size);
|
||||
|
||||
close(fd);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void list_modes(vm_t *vm, vbe_info_t *vbe)
|
||||
{
|
||||
x86emu_t *emu = NULL;
|
||||
int err = 0, i;
|
||||
double d1, d2;
|
||||
unsigned char buf2[0x100], tmp[0x100];
|
||||
unsigned u, ml;
|
||||
unsigned modelist[0x100];
|
||||
unsigned bpp;
|
||||
int res_bpp;
|
||||
vbe_mode_info_t *mi;
|
||||
char s[64];
|
||||
|
||||
LPRINTF("=== running bios\n");
|
||||
|
||||
emu = x86emu_clone(vm->emu);
|
||||
|
||||
emu->x86.R_EAX = 0x4f00;
|
||||
emu->x86.R_EBX = 0;
|
||||
emu->x86.R_ECX = 0;
|
||||
emu->x86.R_EDX = 0;
|
||||
emu->x86.R_EDI = VBE_BUF;
|
||||
|
||||
x86emu_write_dword(emu, VBE_BUF, 0x32454256); // "VBE2"
|
||||
|
||||
err = vm_run(emu, &d1);
|
||||
|
||||
LPRINTF("=== vbe get info: %s (time %.3fs, eax 0x%x, err = 0x%x)\n",
|
||||
emu->x86.R_AX == 0x4f ? "ok" : "failed",
|
||||
d1,
|
||||
emu->x86.R_EAX,
|
||||
err
|
||||
);
|
||||
|
||||
if(!err && emu->x86.R_AX == 0x4f) {
|
||||
LPRINTF("=== vbe info\n");
|
||||
|
||||
vbe->ok = 1;
|
||||
|
||||
vbe->version = x86emu_read_word(emu, VBE_BUF + 0x04);
|
||||
vbe->oem_version = x86emu_read_word(emu, VBE_BUF + 0x14);
|
||||
vbe->memory = x86emu_read_word(emu, VBE_BUF + 0x12) << 16;
|
||||
|
||||
LPRINTF(
|
||||
"version = %u.%u, oem version = %u.%u\n",
|
||||
vbe->version >> 8, vbe->version & 0xff, vbe->oem_version >> 8, vbe->oem_version & 0xff
|
||||
);
|
||||
|
||||
LPRINTF("memory = %uk\n", vbe->memory >> 10);
|
||||
|
||||
buf2[sizeof buf2 - 1] = 0;
|
||||
|
||||
u = vm_read_segofs16(emu, VBE_BUF + 0x06);
|
||||
copy_from_vm(emu, buf2, u, sizeof buf2 - 1);
|
||||
vbe->oem_name = canon_str(buf2, strlen(buf2));
|
||||
LPRINTF("oem name [0x%05x] = \"%s\"\n", u, vbe->oem_name);
|
||||
|
||||
u = vm_read_segofs16(emu, VBE_BUF + 0x16);
|
||||
copy_from_vm(emu, buf2, u, sizeof buf2 - 1);
|
||||
vbe->vendor_name = canon_str(buf2, strlen(buf2));
|
||||
LPRINTF("vendor name [0x%05x] = \"%s\"\n", u, vbe->vendor_name);
|
||||
|
||||
u = vm_read_segofs16(emu, VBE_BUF + 0x1a);
|
||||
copy_from_vm(emu, buf2, u, sizeof buf2 - 1);
|
||||
vbe->product_name = canon_str(buf2, strlen(buf2));
|
||||
LPRINTF("product name [0x%05x] = \"%s\"\n", u, vbe->product_name);
|
||||
|
||||
u = vm_read_segofs16(emu, VBE_BUF + 0x1e);
|
||||
copy_from_vm(emu, buf2, u, sizeof buf2 - 1);
|
||||
vbe->product_revision = canon_str(buf2, strlen(buf2));
|
||||
LPRINTF("product revision [0x%05x] = \"%s\"\n", u, vbe->product_revision);
|
||||
|
||||
ml = vm_read_segofs16(emu, VBE_BUF + 0x0e);
|
||||
|
||||
for(vbe->modes = 0; vbe->modes < sizeof modelist / sizeof *modelist; ) {
|
||||
u = x86emu_read_word(emu, ml + 2 * vbe->modes);
|
||||
if(u == 0xffff) break;
|
||||
modelist[vbe->modes++] = u;
|
||||
}
|
||||
|
||||
LPRINTF("%u video modes:\n", vbe->modes);
|
||||
|
||||
vbe->mode = new_mem(vbe->modes * sizeof *vbe->mode);
|
||||
|
||||
for(i = 0; i < vbe->modes; i++) {
|
||||
|
||||
mi = vbe->mode + i;
|
||||
|
||||
mi->number = modelist[i];
|
||||
|
||||
emu = x86emu_done(emu);
|
||||
emu = x86emu_clone(vm->emu);
|
||||
|
||||
emu->x86.R_EAX = 0x4f01;
|
||||
emu->x86.R_EBX = 0;
|
||||
emu->x86.R_ECX = modelist[i];
|
||||
emu->x86.R_EDI = VBE_BUF;
|
||||
|
||||
err = vm_run(emu, &d1);
|
||||
d2 += d1;
|
||||
|
||||
LPRINTF("=== vbe mode info [0x%04x]: %s (time %.3fs, eax 0x%x, err = 0x%x)\n",
|
||||
modelist[i],
|
||||
emu->x86.R_AX == 0x4f ? "ok" : "failed",
|
||||
d1,
|
||||
emu->x86.R_EAX,
|
||||
err
|
||||
);
|
||||
|
||||
if(err || emu->x86.R_AX != 0x4f) continue;
|
||||
|
||||
copy_from_vm(emu, tmp, VBE_BUF, sizeof tmp);
|
||||
|
||||
mi->attributes = tmp[0x00] + (tmp[0x01] << 8);
|
||||
|
||||
mi->width = tmp[0x12] + (tmp[0x13] << 8);
|
||||
mi->height = tmp[0x14] + (tmp[0x15] << 8);
|
||||
mi->bytes_p_line = tmp[0x10] + (tmp[0x11] << 8);
|
||||
|
||||
mi->win_A_start = (tmp[0x08] + (tmp[0x09] << 8)) << 4;
|
||||
mi->win_B_start = (tmp[0x0a] + (tmp[0x0b] << 8)) << 4;
|
||||
|
||||
mi->win_A_attr = tmp[0x02];
|
||||
mi->win_B_attr = tmp[0x03];
|
||||
|
||||
mi->win_gran = (tmp[0x04] + (tmp[0x05] << 8)) << 10;
|
||||
mi->win_size = (tmp[0x06] + (tmp[0x07] << 8)) << 10;
|
||||
|
||||
bpp = res_bpp = 0;
|
||||
switch(tmp[0x1b]) {
|
||||
case 0:
|
||||
bpp = -1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
bpp = 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
bpp = 1;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
bpp = 4;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
bpp = 8;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
bpp = tmp[0x1f] + tmp[0x21] + tmp[0x23];
|
||||
res_bpp = tmp[0x19] - bpp;
|
||||
if(res_bpp < 0) res_bpp = 0;
|
||||
}
|
||||
|
||||
if(vbe->version >= 0x0200) {
|
||||
mi->fb_start = tmp[0x28] + (tmp[0x29] << 8) + (tmp[0x2a] << 16) + (tmp[0x2b] << 24);
|
||||
}
|
||||
|
||||
if(vbe->version >= 0x0300) {
|
||||
mi->pixel_clock = tmp[0x3e] + (tmp[0x3f] << 8) + (tmp[0x40] << 16) + (tmp[0x41] << 24);
|
||||
}
|
||||
|
||||
mi->pixel_size = bpp;
|
||||
|
||||
if(bpp == -1u) {
|
||||
LPRINTF(" 0x%04x[%02x]: %ux%u, text\n", mi->number, mi->attributes, mi->width, mi->height);
|
||||
}
|
||||
else {
|
||||
if(
|
||||
(mi->attributes & 1) && /* mode is supported */
|
||||
mi->fb_start
|
||||
) {
|
||||
if(!vbe->fb_start) vbe->fb_start = mi->fb_start;
|
||||
}
|
||||
*s = 0;
|
||||
if(res_bpp) sprintf(s, "+%d", res_bpp);
|
||||
LPRINTF(
|
||||
" 0x%04x[%02x]: %ux%u+%u, %u%s bpp",
|
||||
mi->number, mi->attributes, mi->width, mi->height, mi->bytes_p_line, mi->pixel_size, s
|
||||
);
|
||||
|
||||
if(mi->pixel_clock) LPRINTF(", max. %u MHz", mi->pixel_clock/1000000);
|
||||
|
||||
if(mi->fb_start) LPRINTF(", fb: 0x%08x", mi->fb_start);
|
||||
|
||||
LPRINTF(", %04x.%x", mi->win_A_start, mi->win_A_attr);
|
||||
|
||||
if(mi->win_B_start || mi->win_B_attr) LPRINTF("/%04x.%x", mi->win_B_start, mi->win_B_attr);
|
||||
|
||||
LPRINTF(": %uk", mi->win_size >> 10);
|
||||
|
||||
if(mi->win_gran != mi->win_size) LPRINTF("/%uk", mi->win_gran >> 10);
|
||||
|
||||
LPRINTF("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
LPRINTF("=== no vbe info\n");
|
||||
}
|
||||
|
||||
x86emu_done(emu);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void probe_all(vm_t *vm, vbe_info_t *vbe)
|
||||
{
|
||||
x86emu_t *emu = NULL;
|
||||
int err = 0, i;
|
||||
unsigned port, cnt;
|
||||
double d1, d2, timeout;
|
||||
unsigned char edid[0x80];
|
||||
|
||||
LPRINTF("=== running bios\n");
|
||||
|
||||
timeout = get_time() + (vm->timeout ?: 20);
|
||||
|
||||
for(port = 0; port < vm->ports; port++) {
|
||||
d1 = d2 = 0;
|
||||
|
||||
for(cnt = 0; cnt < 2 && get_time() <= timeout; cnt++) {
|
||||
if(!vm->force) {
|
||||
emu = x86emu_done(emu);
|
||||
emu = x86emu_clone(vm->emu);
|
||||
|
||||
emu->x86.R_EAX = 0x4f15;
|
||||
emu->x86.R_EBX = 0;
|
||||
emu->x86.R_ECX = port;
|
||||
emu->x86.R_EDX = 0;
|
||||
emu->x86.R_EDI = 0;
|
||||
emu->x86.R_ES = 0;
|
||||
|
||||
err = vm_run(emu, &d1);
|
||||
d2 += d1;
|
||||
|
||||
LPRINTF("=== port %u, try %u: %s (time %.3fs, eax 0x%x, err = 0x%x)\n",
|
||||
port,
|
||||
cnt,
|
||||
emu->x86.R_AX == 0x4f ? "ok" : "failed",
|
||||
d1,
|
||||
emu->x86.R_EAX,
|
||||
err
|
||||
);
|
||||
|
||||
if(err || emu->x86.R_AX != 0x4f) continue;
|
||||
|
||||
LPRINTF("=== port %u, try %u: bh = %d, bl = 0x%02x\n",
|
||||
port,
|
||||
cnt,
|
||||
emu->x86.R_BH,
|
||||
emu->x86.R_BL
|
||||
);
|
||||
|
||||
if(!(emu->x86.R_BL & 3)) {
|
||||
err = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
emu = x86emu_done(emu);
|
||||
emu = x86emu_clone(vm->emu);
|
||||
|
||||
emu->x86.R_EAX = 0x4f15;
|
||||
emu->x86.R_EBX = 1;
|
||||
emu->x86.R_ECX = port;
|
||||
emu->x86.R_EDX = 0;
|
||||
emu->x86.R_EDI = VBE_BUF;
|
||||
|
||||
err = vm_run(emu, &d1);
|
||||
d2 += d1;
|
||||
|
||||
LPRINTF("=== port %u, try %u: %s (time %.3fs, eax 0x%x, err = 0x%x)\n",
|
||||
port,
|
||||
cnt,
|
||||
emu->x86.R_AX == 0x4f ? "ok" : "failed",
|
||||
d1,
|
||||
emu->x86.R_EAX,
|
||||
err
|
||||
);
|
||||
|
||||
if(err || emu->x86.R_AX == 0x4f) break;
|
||||
}
|
||||
|
||||
if(!emu) {
|
||||
LPRINTF("=== timeout\n");
|
||||
break;
|
||||
}
|
||||
|
||||
LPRINTF("=== port %u: %s (time %.3fs, eax 0x%x, err = 0x%x)\n",
|
||||
port,
|
||||
emu->x86.R_AX == 0x4f ? "ok" : "failed",
|
||||
d2,
|
||||
emu->x86.R_EAX,
|
||||
err
|
||||
);
|
||||
|
||||
copy_from_vm(emu, edid, VBE_BUF, sizeof edid);
|
||||
|
||||
LPRINTF("=== port %u: ddc data ===\n", port);
|
||||
for(i = 0; i < 0x80; i++) {
|
||||
LPRINTF("%02x", edid[i]);
|
||||
LPRINTF((i & 15) == 15 ? "\n" : " ");
|
||||
}
|
||||
LPRINTF("=== port %u: ddc data end ===\n", port);
|
||||
|
||||
if(!err && emu->x86.R_AX == 0x4f) {
|
||||
LPRINTF("=== port %u: monitor info ok\n", port);
|
||||
|
||||
vbe->ok = 1;
|
||||
vbe->ddc_ports = port + 1;
|
||||
|
||||
memcpy(vbe->ddc_port[port], edid, sizeof *vbe->ddc_port);
|
||||
}
|
||||
else {
|
||||
if(!err) err = -1;
|
||||
LPRINTF("=== port %u: no monitor info\n", port);
|
||||
}
|
||||
|
||||
emu = x86emu_done(emu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void get_video_mode(vm_t *vm, vbe_info_t *vbe)
|
||||
{
|
||||
x86emu_t *emu = NULL;
|
||||
int err = 0;
|
||||
double d;
|
||||
|
||||
LPRINTF("=== running bios\n");
|
||||
|
||||
emu = x86emu_clone(vm->emu);
|
||||
|
||||
emu->x86.R_EAX = 0x4f03;
|
||||
emu->x86.R_EBX = 0;
|
||||
|
||||
err = vm_run(emu, &d);
|
||||
|
||||
LPRINTF("=== vbe get current video mode: %s (time %.3fs, eax 0x%x, err = 0x%x)\n",
|
||||
emu->x86.R_AX == 0x4f ? "ok" : "failed",
|
||||
d,
|
||||
emu->x86.R_EAX,
|
||||
err
|
||||
);
|
||||
|
||||
if(!err && emu->x86.R_AX == 0x4f) {
|
||||
vbe->ok = 1;
|
||||
vbe->current_mode = emu->x86.R_BX;
|
||||
|
||||
LPRINTF("=== current mode: 0x%04x\n", vbe->current_mode);
|
||||
}
|
||||
else {
|
||||
LPRINTF("=== current mode: no info\n");
|
||||
}
|
||||
|
||||
x86emu_done(emu);
|
||||
}
|
||||
|
||||
|
||||
#endif /* defined(__i386__) || defined (__x86_64__) */
|
|
@ -0,0 +1,240 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "memory.h"
|
||||
#include "klog.h"
|
||||
|
||||
/**
|
||||
* @defgroup MEMint Memory information
|
||||
* @ingroup libhdINFOint
|
||||
* @brief Memory information functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
uint64_t kcore_mem(hd_data_t *hd_data);
|
||||
uint64_t klog_mem(hd_data_t *hd_data, uint64_t *alt);
|
||||
uint64_t klog_mem2(hd_data_t *hd_data);
|
||||
uint64_t meminfo_mem(hd_data_t *hd_data);
|
||||
uint64_t meminfo_xen(hd_data_t *hd_data);
|
||||
|
||||
void hd_scan_memory(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
uint64_t kcore, klog, klog_alt, klog2, meminfo, msize0, msize1, memxen, u;
|
||||
hd_res_t *res;
|
||||
int i;
|
||||
int exact;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_memory)) return;
|
||||
|
||||
hd_data->module = mod_memory;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "main memory size");
|
||||
|
||||
kcore = kcore_mem(hd_data);
|
||||
klog = klog_mem(hd_data, &klog_alt);
|
||||
klog2 = klog_mem2(hd_data);
|
||||
if(klog2 > klog) klog = klog2;
|
||||
meminfo = meminfo_mem(hd_data);
|
||||
memxen = meminfo_xen(hd_data);
|
||||
|
||||
msize0 = meminfo > klog ? meminfo : klog;
|
||||
if(!msize0) msize0 = kcore;
|
||||
msize1 = msize0;
|
||||
|
||||
exact = 0;
|
||||
/* trust kcore value if it's approx. msize0 */
|
||||
if(msize0 && kcore >= msize0 && ((kcore - msize0) << 4) / msize0 == 0) {
|
||||
/* be a bit more restrictive here */
|
||||
if(((kcore - msize0) << 6) / msize0 == 0) {
|
||||
msize1 = kcore;
|
||||
exact = 1;
|
||||
}
|
||||
msize0 = kcore;
|
||||
}
|
||||
|
||||
if(meminfo > msize1) { msize1 = meminfo; exact = 0; }
|
||||
if(klog_alt > msize0) msize0 = klog_alt;
|
||||
|
||||
// if we are in a xen vm, trust this value
|
||||
if(memxen) {
|
||||
msize0 = msize1 = memxen;
|
||||
exact = 1;
|
||||
}
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_internal;
|
||||
hd->sub_class.id = sc_int_main_mem;
|
||||
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->mem.type = res_mem;
|
||||
res->mem.range = msize0;
|
||||
res->mem.access = acc_rw;
|
||||
res->mem.enabled = 1;
|
||||
|
||||
/* round it somewhat */
|
||||
for(i = 0, u = msize1; u; i++) {
|
||||
u >>= 1;
|
||||
}
|
||||
if(i > 10) { /* We *do* have at least 1k memory, do we? */
|
||||
msize1 >>= i - (exact ? 8 : 5);
|
||||
msize1++;
|
||||
msize1 >>= 1;
|
||||
msize1 <<= i - (exact ? 7 : 4);
|
||||
}
|
||||
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->phys_mem.type = res_phys_mem;
|
||||
res->phys_mem.range = msize1;
|
||||
}
|
||||
|
||||
uint64_t kcore_mem(hd_data_t *hd_data)
|
||||
{
|
||||
uint64_t u = 0;
|
||||
size_t ps = getpagesize();
|
||||
struct stat sb;
|
||||
|
||||
if(!stat(PROC_KCORE, &sb)) {
|
||||
u = sb.st_size;
|
||||
if(u > ps) u -= ps;
|
||||
|
||||
#if 0
|
||||
/* we'll assume no mem modules with less than 256k */
|
||||
u += 1 << 17;
|
||||
u &= -1 << 18;
|
||||
#endif
|
||||
}
|
||||
|
||||
ADD2LOG(" kcore mem: 0x%"PRIx64"\n", u);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
|
||||
uint64_t klog_mem(hd_data_t *hd_data, uint64_t *alt)
|
||||
{
|
||||
uint64_t u = 0, u0, u1, u2, u3, mem0 = 0, mem1 = 0;
|
||||
str_list_t *sl;
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
if(!hd_data->klog) read_klog(hd_data);
|
||||
|
||||
for(sl = hd_data->klog; sl; sl = sl->next) {
|
||||
if(strstr(sl->str, "<6>Memory: ") == sl->str) {
|
||||
if(sscanf(sl->str, "<6>Memory: %"SCNu64"k/%"SCNu64"k", &u0, &u1) == 2) {
|
||||
mem0 = u1 << 10;
|
||||
}
|
||||
if(
|
||||
(i = sscanf(sl->str, "<6>Memory: %"SCNu64"k available (%"SCNu64"k kernel code, %"SCNu64"k data, %"SCNu64"k", &u0, &u1, &u2, &u3)) == 4 || i == 1
|
||||
) {
|
||||
mem0 = (i == 1 ? u0 : u0 + u1 + u2 + u3) << 10;
|
||||
}
|
||||
if(
|
||||
(s = strstr(sl->str, "[")) &&
|
||||
sscanf(s, "[%"SCNx64",%"SCNx64"]", &u0, &u1) == 2 &&
|
||||
u1 > u0
|
||||
) {
|
||||
mem1 = u1 - u0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u = mem0 ? mem0 : mem1;
|
||||
|
||||
#if 0
|
||||
/* round it somewhat */
|
||||
for(i = 0, u0 = u; u0; i++) {
|
||||
u0 >>= 1;
|
||||
}
|
||||
if(i > 10) { /* We *do* have at least 1k memory, do we? */
|
||||
u >>= i - 6;
|
||||
u++;
|
||||
u >>= 1;
|
||||
u <<= i - 5;
|
||||
}
|
||||
#endif
|
||||
|
||||
ADD2LOG(" klog mem 0: 0x%"PRIx64"\n", mem0);
|
||||
ADD2LOG(" klog mem 1: 0x%"PRIx64"\n", mem1);
|
||||
ADD2LOG(" klog mem: 0x%"PRIx64"\n", u);
|
||||
|
||||
*alt = mem1;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
uint64_t klog_mem2(hd_data_t *hd_data)
|
||||
{
|
||||
uint64_t u0, u1, mem = 0;
|
||||
str_list_t *sl;
|
||||
char buf[64];
|
||||
|
||||
if(!hd_data->klog) read_klog(hd_data);
|
||||
|
||||
for(sl = hd_data->klog; sl; sl = sl->next) {
|
||||
if(strstr(sl->str, "<6>BIOS-provided physical RAM map:") == sl->str) {
|
||||
for(sl = sl->next ; sl; sl = sl->next) {
|
||||
ADD2LOG(" -- %s", sl->str);
|
||||
if(sscanf(sl->str, "<%*d> BIOS-e820: %"SCNx64" - %"SCNx64" (%63s", &u0, &u1, buf) != 3) break;
|
||||
if(strcmp(buf, "usable)")) continue;
|
||||
if(u1 < u0) break;
|
||||
mem += u1 - u0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ADD2LOG(" bios mem: 0x%"PRIx64"\n", mem);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
uint64_t meminfo_mem(hd_data_t *hd_data)
|
||||
{
|
||||
uint64_t u = 0, u0;
|
||||
str_list_t *sl;
|
||||
|
||||
sl = read_file(PROC_MEMINFO, 0, 1);
|
||||
|
||||
if(sl && sscanf(sl->str, "MemTotal: %"SCNu64"", &u0) == 1) {
|
||||
u = u0 << 10;
|
||||
}
|
||||
|
||||
free_str_list(sl);
|
||||
|
||||
ADD2LOG(" meminfo: 0x%"PRIx64"\n", u);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
uint64_t meminfo_xen(hd_data_t *hd_data)
|
||||
{
|
||||
uint64_t u = 0, u0;
|
||||
str_list_t *sl;
|
||||
|
||||
sl = read_file(PROC_XEN_BALLOON, 0, 1);
|
||||
|
||||
if(sl && sscanf(sl->str, "Current allocation: %"SCNu64"", &u0) == 1) {
|
||||
u = u0 << 10;
|
||||
}
|
||||
|
||||
free_str_list(sl);
|
||||
|
||||
ADD2LOG(" xen balloon: 0x%"PRIx64"\n", u);
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_memory(hd_data_t *hd_data);
|
|
@ -0,0 +1,735 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/hdreg.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "misc.h"
|
||||
#include "klog.h"
|
||||
|
||||
static void read_ioports(misc_t *m);
|
||||
static void read_dmas(misc_t *m);
|
||||
static void read_irqs(misc_t *m);
|
||||
static int active_vga_card(hd_t *);
|
||||
|
||||
static void dump_misc_proc_data(hd_data_t *hd_data);
|
||||
static void dump_misc_data(hd_data_t *hd_data);
|
||||
|
||||
/**
|
||||
* @defgroup MISCint Misc information
|
||||
* @ingroup libhdINFOint
|
||||
* @brief Misc information functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
void hd_scan_misc(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
hd_res_t *res;
|
||||
int fd, i;
|
||||
char *s = NULL;
|
||||
bios_info_t *bt = NULL;
|
||||
char par[] = "parport0";
|
||||
int fd_ser0, fd_ser1;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_misc)) return;
|
||||
|
||||
hd_data->module = mod_misc;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
hd_data->misc = free_misc(hd_data->misc);
|
||||
|
||||
PROGRESS(9, 0, "kernel log");
|
||||
read_klog(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "misc data");
|
||||
hd_data->misc = new_mem(sizeof *hd_data->misc);
|
||||
|
||||
/* this is enough to load the module */
|
||||
fd_ser0 = fd_ser1 = -1;
|
||||
|
||||
#if !defined(__sparc__)
|
||||
/* On sparc, the close needs too long */
|
||||
if(hd_probe_feature(hd_data, pr_misc_serial)) {
|
||||
PROGRESS(1, 1, "open serial");
|
||||
fd_ser0 = open("/dev/ttyS0", O_RDONLY | O_NONBLOCK);
|
||||
fd_ser1 = open("/dev/ttyS1", O_RDONLY | O_NONBLOCK);
|
||||
/* keep the devices open until the resources have been read */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* this is enough to load the module */
|
||||
if(!hd_data->flags.no_parport && hd_probe_feature(hd_data, pr_misc_par)) {
|
||||
PROGRESS(1, 2, "open parallel");
|
||||
/* what can the BIOS tell us? */
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_internal &&
|
||||
hd->sub_class.id == sc_int_bios &&
|
||||
hd->detail &&
|
||||
hd->detail->type == hd_detail_bios &&
|
||||
hd->detail->bios.data
|
||||
) break;
|
||||
}
|
||||
if(hd) {
|
||||
bt = hd->detail->bios.data;
|
||||
if(bt->par_port0) {
|
||||
str_printf(&s, 0, "io=0x%x", bt->par_port0);
|
||||
if(bt->par_port1) {
|
||||
str_printf(&s, -1, ",0x%x", bt->par_port1);
|
||||
if(bt->par_port2) str_printf(&s, -1, ",0x%x", bt->par_port2);
|
||||
}
|
||||
str_printf(&s, -1, " irq=none,none,none");
|
||||
}
|
||||
unload_module(hd_data, "parport_probe");
|
||||
unload_module(hd_data, "lp");
|
||||
unload_module(hd_data, "parport_pc");
|
||||
unload_module(hd_data, "parport");
|
||||
|
||||
/* now load it with the right io */
|
||||
load_module(hd_data, "parport");
|
||||
load_module_with_params(hd_data, "parport_pc", s);
|
||||
free_mem(s);
|
||||
}
|
||||
/* now load the rest of the modules */
|
||||
fd = open("/dev/lp0", O_RDONLY | O_NONBLOCK);
|
||||
if(fd >= 0) close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* floppy driver resources are allocated only temporarily,
|
||||
* so we access it just before we read the resources
|
||||
*/
|
||||
if(hd_probe_feature(hd_data, pr_misc_floppy)) {
|
||||
/* look for a floppy *device* entry... */
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_storage_device &&
|
||||
hd->sub_class.id == sc_sdev_floppy &&
|
||||
hd->unix_dev_name &&
|
||||
!strncmp(hd->unix_dev_name, "/dev/fd", sizeof "/dev/fd" - 1)
|
||||
) {
|
||||
|
||||
PROGRESS(1, 3, "read floppy");
|
||||
i = 5;
|
||||
hd->block0 = read_block0(hd_data, hd->unix_dev_name, &i);
|
||||
hd->is.notready = hd->block0 ? 0 : 1;
|
||||
if(i < 0) {
|
||||
hd->tag.remove = 1;
|
||||
ADD2LOG("misc.floppy: removing floppy entry %u (timed out)\n", hd->idx);
|
||||
}
|
||||
|
||||
if(!hd->is.notready) {
|
||||
struct hd_geometry geo;
|
||||
int fd;
|
||||
unsigned size, blk_size = 0x200;
|
||||
|
||||
fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK);
|
||||
if(fd >= 0) {
|
||||
if(!ioctl(fd, HDIO_GETGEO, &geo)) {
|
||||
ADD2LOG("floppy ioctl(geo) ok\n");
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->disk_geo.type = res_disk_geo;
|
||||
res->disk_geo.cyls = geo.cylinders;
|
||||
res->disk_geo.heads = geo.heads;
|
||||
res->disk_geo.sectors = geo.sectors;
|
||||
res->disk_geo.geotype = geo_logical;
|
||||
size = geo.cylinders * geo.heads * geo.sectors;
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(res->any.type == res_size && res->size.unit == size_unit_sectors) {
|
||||
res->size.val1 = size; res->size.val2 = blk_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!res) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->size.type = res_size;
|
||||
res->size.unit = size_unit_sectors;
|
||||
res->size.val1 = size; res->size.val2 = blk_size;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
remove_tagged_hd_entries(hd_data);
|
||||
}
|
||||
|
||||
PROGRESS(2, 1, "io");
|
||||
read_ioports(hd_data->misc);
|
||||
|
||||
PROGRESS(2, 2, "dma");
|
||||
read_dmas(hd_data->misc);
|
||||
|
||||
PROGRESS(2, 3, "irq");
|
||||
read_irqs(hd_data->misc);
|
||||
|
||||
if((hd_data->debug & HD_DEB_MISC)) dump_misc_proc_data(hd_data);
|
||||
|
||||
if(fd_ser0 >= 0) close(fd_ser0);
|
||||
if(fd_ser1 >= 0) close(fd_ser1);
|
||||
|
||||
/* now create some system generic entries */
|
||||
|
||||
/* FPU */
|
||||
PROGRESS(3, 0, "FPU");
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "fpu", 0);
|
||||
if(res) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_internal;
|
||||
hd->sub_class.id = sc_int_fpu;
|
||||
hd->res = res;
|
||||
}
|
||||
|
||||
/* DMA */
|
||||
PROGRESS(3, 1, "DMA");
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "dma1", 0);
|
||||
gather_resources(hd_data->misc, &res, "dma2", 0);
|
||||
gather_resources(hd_data->misc, &res, "dma page reg", 0);
|
||||
gather_resources(hd_data->misc, &res, "cascade", W_DMA);
|
||||
if(res) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_system;
|
||||
hd->sub_class.id = sc_sys_dma;
|
||||
hd->res = res;
|
||||
}
|
||||
|
||||
/* PIC */
|
||||
PROGRESS(3, 2, "PIC");
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "pic1", 0);
|
||||
gather_resources(hd_data->misc, &res, "pic2", 0);
|
||||
gather_resources(hd_data->misc, &res, "cascade", W_IRQ);
|
||||
if(res) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_system;
|
||||
hd->sub_class.id = sc_sys_pic;
|
||||
hd->res = res;
|
||||
}
|
||||
|
||||
/* timer */
|
||||
PROGRESS(3, 3, "timer");
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "timer", 0);
|
||||
if(res) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_system;
|
||||
hd->sub_class.id = sc_sys_timer;
|
||||
hd->res = res;
|
||||
}
|
||||
|
||||
/* real time clock */
|
||||
PROGRESS(3, 4, "RTC");
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "rtc", 0);
|
||||
if(res) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_system;
|
||||
hd->sub_class.id = sc_sys_rtc;
|
||||
hd->res = res;
|
||||
}
|
||||
|
||||
/* keyboard */
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "keyboard", 0);
|
||||
if(res) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_input;
|
||||
hd->sub_class.id = sc_inp_keyb;
|
||||
hd->res = res;
|
||||
}
|
||||
|
||||
/* parallel ports */
|
||||
for(i = 0; i < 1; i++, par[sizeof par - 2]++) {
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, par, 0);
|
||||
if(res) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_comm;
|
||||
hd->sub_class.id = sc_com_par;
|
||||
str_printf(&hd->unix_dev_name, 0, "/dev/lp%d", i);
|
||||
hd->res = res;
|
||||
}
|
||||
}
|
||||
|
||||
/* floppy controller */
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "floppy", 0);
|
||||
gather_resources(hd_data->misc, &res, "floppy DIR", 0);
|
||||
if(res) {
|
||||
/* look for an existing entry */
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_storage && hd->sub_class.id == sc_sto_floppy) break;
|
||||
}
|
||||
|
||||
/* missing, so create one */
|
||||
if(!hd) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_storage;
|
||||
hd->sub_class.id = sc_sto_floppy;
|
||||
}
|
||||
|
||||
hd->res = res;
|
||||
}
|
||||
|
||||
/*
|
||||
* look for PS/2 port
|
||||
*
|
||||
* The catch is, that sometimes /dev/psaux is accessible only for root,
|
||||
* so the open() may fail but there are irq events registered.
|
||||
*
|
||||
*/
|
||||
fd = open(DEV_PSAUX, O_RDONLY | O_NONBLOCK);
|
||||
if(fd >= 0) close(fd);
|
||||
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "PS/2 Mouse", 0);
|
||||
|
||||
if(res || fd >= 0) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_ps2;
|
||||
|
||||
if(res) {
|
||||
hd->res = res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hd_scan_misc2(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd1;
|
||||
misc_t *m;
|
||||
hd_res_t *res, *res1, *res2;
|
||||
int i;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_misc)) return;
|
||||
|
||||
hd_data->module = mod_misc;
|
||||
|
||||
PROGRESS(5, 0, "misc data");
|
||||
|
||||
/* create some more system generic entries */
|
||||
|
||||
/* IDE */
|
||||
|
||||
// ###### add special ide detail to hd_t!!!
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "ide0", 0);
|
||||
gather_resources(hd_data->misc, &res, "ide1", 0);
|
||||
gather_resources(hd_data->misc, &res, "ide2", 0);
|
||||
gather_resources(hd_data->misc, &res, "ide3", 0);
|
||||
if(res) {
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_storage &&
|
||||
hd->sub_class.id == sc_sto_ide &&
|
||||
have_common_res(hd->res, res)
|
||||
) break;
|
||||
}
|
||||
if(hd) {
|
||||
/* eg. PCI IDE controller, add resources */
|
||||
join_res_io(&hd->res, res);
|
||||
join_res_irq(&hd->res, res);
|
||||
join_res_dma(&hd->res, res);
|
||||
}
|
||||
free_res_list(res);
|
||||
}
|
||||
|
||||
/* VGA */
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "vga+", 0);
|
||||
gather_resources(hd_data->misc, &res, "vesafb", 0);
|
||||
if(res) {
|
||||
for(i = 0, hd1 = NULL, hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_display && hd->sub_class.id == sc_dis_vga) {
|
||||
i++;
|
||||
hd1 = hd;
|
||||
}
|
||||
}
|
||||
if(i == 0) {
|
||||
/* non-PCI VGA card ??? - really, we shouldn't care... */
|
||||
/* FIX THIS !!! ############### */
|
||||
#ifdef __alpha__
|
||||
free_res_list(res);
|
||||
#else
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_display;
|
||||
hd->sub_class.id = sc_dis_vga;
|
||||
hd->res = res;
|
||||
#endif
|
||||
}
|
||||
else if(i == 1) {
|
||||
/* 1 PCI vga card, add resources */
|
||||
join_res_io(&hd1->res, res);
|
||||
join_res_irq(&hd1->res, res);
|
||||
join_res_dma(&hd1->res, res);
|
||||
free_res_list(res);
|
||||
hd_data->display = hd1->idx;
|
||||
}
|
||||
else {
|
||||
/* more than 1: look again, now only 'active' cards */
|
||||
for(i = 0, hd1 = NULL, hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_display &&
|
||||
hd->sub_class.id == sc_dis_vga &&
|
||||
active_vga_card(hd)
|
||||
) {
|
||||
i++;
|
||||
hd1 = hd;
|
||||
}
|
||||
}
|
||||
if(i == 1) {
|
||||
/* 'the' active PCI vga card, add resources */
|
||||
join_res_io(&hd1->res, res);
|
||||
join_res_irq(&hd1->res, res);
|
||||
join_res_dma(&hd1->res, res);
|
||||
hd_data->display = hd1->idx;
|
||||
}
|
||||
else {
|
||||
/* now, what??? */
|
||||
ADD2LOG("Oopy, could not figure out *the* active display adapter!\n");
|
||||
}
|
||||
free_res_list(res);
|
||||
}
|
||||
}
|
||||
|
||||
/* serial ports */
|
||||
res = NULL;
|
||||
gather_resources(hd_data->misc, &res, "serial(auto)", 0);
|
||||
gather_resources(hd_data->misc, &res, "serial(set)", 0);
|
||||
gather_resources(hd_data->misc, &res, "serial", 0);
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_comm && hd->sub_class.id == sc_com_ser) {
|
||||
for(res1 = hd->res; res1; res1 = res1->next) {
|
||||
for(res2 = res; res2; res2 = res2->next) {
|
||||
if(res1->any.type == res2->any.type) {
|
||||
switch(res1->any.type) {
|
||||
case res_irq:
|
||||
if(res1->irq.base == res2->irq.base) {
|
||||
res2->any.type = res_any;
|
||||
}
|
||||
break;
|
||||
case res_io:
|
||||
if(
|
||||
res1->io.base == res2->io.base &&
|
||||
(!res1->io.range || res1->io.range == res2->io.range)
|
||||
) {
|
||||
res1->io.range = res2->io.range;
|
||||
res2->any.type = res_any;
|
||||
}
|
||||
break;
|
||||
default: /* gcc -Wall */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if any of the serial resources are unaccounted for, make an extra entry */
|
||||
for(res2 = res; res2; res2 = res2->next) {
|
||||
if(res2->any.type != res_any) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_comm;
|
||||
hd->sub_class.id = sc_com_ser;
|
||||
hd->prog_if.id = 0x80;
|
||||
for(; res2; res2 = res2->next) {
|
||||
if(res2->any.type != res_any) {
|
||||
res1 = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
*res1 = *res2;
|
||||
res1->next = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
free_res_list(res);
|
||||
|
||||
/* go through our list and assign event counts to irq entries */
|
||||
m = hd_data->misc;
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(res->irq.type == res_irq) {
|
||||
for(i = 0; (unsigned) i < m->irq_len; i++) {
|
||||
if(res->irq.base == m->irq[i].irq) {
|
||||
res->irq.triggered = m->irq[i].events;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* look for entries with matching start address */
|
||||
m = hd_data->misc;
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(res->io.type == res_io) {
|
||||
for(i = 0; (unsigned) i < m->io_len; i++) {
|
||||
if(res->io.base == m->io[i].addr && res->io.range < m->io[i].size) {
|
||||
res->io.range = m->io[i].size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((hd_data->debug & HD_DEB_MISC)) dump_misc_data(hd_data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read /proc/ioports
|
||||
*/
|
||||
void read_ioports(misc_t *m)
|
||||
{
|
||||
char buf[100];
|
||||
misc_io_t *r;
|
||||
uint64_t u, v;
|
||||
str_list_t *sl;
|
||||
|
||||
if(!(m->proc_io = read_file(PROC_IOPORTS, 0, 0))) return;
|
||||
|
||||
for(sl = m->proc_io; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, " %"PRIx64" - %"PRIx64" : %99[^\n]", &u, &v, buf) == 3) {
|
||||
m->io = add_mem(m->io, sizeof *m->io, m->io_len);
|
||||
r = m->io + m->io_len++;
|
||||
r->addr = u;
|
||||
r->size = v >= u ? v - u + 1 : 0;
|
||||
r->dev = new_str(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* read /proc/dma
|
||||
*/
|
||||
void read_dmas(misc_t *m)
|
||||
{
|
||||
char buf[100];
|
||||
misc_dma_t *d;
|
||||
unsigned u;
|
||||
str_list_t *sl;
|
||||
|
||||
if(!(m->proc_dma = read_file(PROC_DMA, 0, 0))) return;
|
||||
|
||||
for(sl = m->proc_dma; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, " %u : %99[^\n]", &u, buf) == 2) {
|
||||
m->dma = add_mem(m->dma, sizeof *m->dma, m->dma_len);
|
||||
d = m->dma + m->dma_len++;
|
||||
d->channel = u;
|
||||
d->dev = new_str(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* read /proc/interrupts
|
||||
*
|
||||
* This is somewhat more tricky, as the irq event counts are done separately
|
||||
* per cpu *and* there may be irq sharing.
|
||||
*/
|
||||
void read_irqs(misc_t *m)
|
||||
{
|
||||
char buf[100], buf2[100], *s;
|
||||
misc_irq_t *ir;
|
||||
int i, j;
|
||||
unsigned u, v, k;
|
||||
str_list_t *sl;
|
||||
|
||||
if(!(m->proc_irq = read_file(PROC_INTERRUPTS, 1, 0))) return;
|
||||
|
||||
for(sl = m->proc_irq; sl; sl = sl->next) {
|
||||
/* irq */
|
||||
i = 0;
|
||||
if(sscanf(sl->str, " %u: %n", &u, &i) < 1) continue;
|
||||
v = 0;
|
||||
j = i;
|
||||
/* add up all event counters */
|
||||
while(j < (int) strlen(sl->str) && sscanf(sl->str + j, " %u %n", &k, &i) >= 1) {
|
||||
if(!i) break;
|
||||
v += k;
|
||||
j += i;
|
||||
}
|
||||
/* device driver name string */
|
||||
#if defined(__PPC__)
|
||||
if(
|
||||
sscanf(sl->str + j, " %*s Edge %99[^\n]", buf) == 1 ||
|
||||
sscanf(sl->str + j, " %*s Level %99[^\n]", buf) == 1 ||
|
||||
sscanf(sl->str + j, " %*s %99[^\n]", buf) == 1
|
||||
) {
|
||||
#else
|
||||
#if defined(__alpha__) || defined(__sparc__)
|
||||
if(sscanf(sl->str + j, " %99[^\n]", buf) == 1) {
|
||||
#else /* __i386__ || __x86_64__ || __ia64__ */
|
||||
if(sscanf(sl->str + j, " %*s %99[^\n]", buf) == 1) {
|
||||
#endif
|
||||
#endif
|
||||
m->irq = add_mem(m->irq, sizeof *m->irq, m->irq_len);
|
||||
ir = m->irq + m->irq_len++;
|
||||
ir->irq = u;
|
||||
ir->events = v;
|
||||
|
||||
/* split device driver names (separated by ',') */
|
||||
s = buf;
|
||||
while(*s && sscanf(s, " %99[^,] %n", buf2, &j) >= 1) {
|
||||
ir->dev = add_mem(ir->dev, sizeof *ir->dev, ir->devs);
|
||||
ir->dev[ir->devs++] = new_str(buf2);
|
||||
s += j;
|
||||
if(*s) s++; /* skip ',' */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gather_resources(misc_t *m, hd_res_t **r, char *name, unsigned which)
|
||||
{
|
||||
int i, j;
|
||||
hd_res_t *res;
|
||||
|
||||
if(!m) return;
|
||||
|
||||
if(!which) which = W_IO | W_DMA | W_IRQ;
|
||||
|
||||
if((which & W_IO)) for(i = 0; (unsigned) i < m->io_len; i++) {
|
||||
if(!strcmp(name, m->io[i].dev)) {
|
||||
res = add_res_entry(r, new_mem(sizeof **r));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = m->io[i].addr;
|
||||
res->io.range = m->io[i].size;
|
||||
res->io.access = acc_rw;
|
||||
m->io[i].tag++;
|
||||
}
|
||||
}
|
||||
|
||||
if((which & W_DMA)) for(i = 0; (unsigned) i < m->dma_len; i++) {
|
||||
if(!strcmp(name, m->dma[i].dev)) {
|
||||
res = add_res_entry(r, new_mem(sizeof **r));
|
||||
res->dma.type = res_dma;
|
||||
res->dma.enabled = 1;
|
||||
res->dma.base = m->dma[i].channel;
|
||||
m->dma[i].tag++;
|
||||
}
|
||||
}
|
||||
|
||||
if((which & W_IRQ)) for(i = 0; (unsigned) i < m->irq_len; i++) {
|
||||
for(j = 0; j < m->irq[i].devs; j++) {
|
||||
if(!strcmp(name, m->irq[i].dev[j])) {
|
||||
res = add_res_entry(r, new_mem(sizeof **r));
|
||||
res->irq.type = res_irq;
|
||||
res->irq.enabled = 1;
|
||||
res->irq.base = m->irq[i].irq;
|
||||
res->irq.triggered = m->irq[i].events;
|
||||
m->irq[i].tag++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int active_vga_card(hd_t *hd)
|
||||
{
|
||||
hd_res_t *res;
|
||||
|
||||
if(hd->bus.id != bus_pci) return 1;
|
||||
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(
|
||||
(res->mem.type == res_mem && res->mem.enabled) ||
|
||||
(res->io.type == res_io && res->io.enabled)
|
||||
) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add some proc info to the global log.
|
||||
*/
|
||||
void dump_misc_proc_data(hd_data_t *hd_data)
|
||||
{
|
||||
str_list_t *sl;
|
||||
|
||||
ADD2LOG("----- /proc/ioports -----\n");
|
||||
for(sl = hd_data->misc->proc_io; sl; sl = sl->next) {
|
||||
ADD2LOG(" %s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- /proc/ioports end -----\n");
|
||||
|
||||
ADD2LOG("----- /proc/interrupts -----\n");
|
||||
for(sl = hd_data->misc->proc_irq; sl; sl = sl->next) {
|
||||
ADD2LOG(" %s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- /proc/interrupts end -----\n");
|
||||
|
||||
ADD2LOG("----- /proc/dma -----\n");
|
||||
for(sl = hd_data->misc->proc_dma; sl; sl = sl->next) {
|
||||
ADD2LOG(" %s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- /proc/dma end -----\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add the resource usage to the global log.
|
||||
*/
|
||||
void dump_misc_data(hd_data_t *hd_data)
|
||||
{
|
||||
misc_t *m = hd_data->misc;
|
||||
int i, j;
|
||||
|
||||
ADD2LOG("----- misc resources -----\n");
|
||||
|
||||
for(i = 0; (unsigned) i < m->io_len; i++) {
|
||||
ADD2LOG(
|
||||
"i/o:%u 0x%04"PRIx64" - 0x%04"PRIx64" (0x%02"PRIx64") \"%s\"\n",
|
||||
m->io[i].tag,
|
||||
m->io[i].addr, m->io[i].addr + m->io[i].size - 1,
|
||||
m->io[i].size, m->io[i].dev
|
||||
);
|
||||
}
|
||||
|
||||
for(i = 0; (unsigned) i < m->irq_len; i++) {
|
||||
ADD2LOG(
|
||||
"irq:%u %2u (%9u)",
|
||||
m->irq[i].tag, m->irq[i].irq, m->irq[i].events
|
||||
);
|
||||
for(j = 0; j < m->irq[i].devs; j++) {
|
||||
ADD2LOG(" \"%s\"", m->irq[i].dev[j]);
|
||||
}
|
||||
ADD2LOG("\n");
|
||||
}
|
||||
|
||||
for(i = 0; (unsigned) i < m->dma_len; i++) {
|
||||
ADD2LOG(
|
||||
"dma:%u %u \"%s\"\n",
|
||||
m->dma[i].tag, m->dma[i].channel, m->dma[i].dev
|
||||
);
|
||||
}
|
||||
|
||||
ADD2LOG("----- misc resources end -----\n");
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
void hd_scan_misc(hd_data_t *hd_data);
|
||||
void hd_scan_misc2(hd_data_t *hd_data);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
void hd_scan_modem(hd_data_t *hd_data);
|
|
@ -0,0 +1,674 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "hddb.h"
|
||||
#include "monitor.h"
|
||||
|
||||
/**
|
||||
* @defgroup MONITORint Monitor (DDC) information
|
||||
* @ingroup libhdINFOint
|
||||
* @brief Monitor information functions
|
||||
* @see http://en.wikipedia.org/wiki/Extended_Display_Identification_Data#EDID_1.3_data_format
|
||||
* for the detailed EDID data structure description
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* monitor info
|
||||
*
|
||||
* Read the info out of the 'SuSE=' entry in /proc/cmdline. It contains
|
||||
* (among others) info from the EDID record got by our syslinux extension.
|
||||
*
|
||||
* We will try to look up our monitor id in the id file to get additional
|
||||
* info.
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*/
|
||||
|
||||
#ifdef __PPC__
|
||||
static void add_old_mac_monitor(hd_data_t *hd_data);
|
||||
#endif
|
||||
static void add_monitor(hd_data_t *hd_data, devtree_t *dt);
|
||||
static int chk_edid_info(hd_data_t *hd_data, unsigned char *edid);
|
||||
static void add_lcd_info(hd_data_t *hd_data, hd_t *hd, bios_info_t *bt);
|
||||
static int mi_cmp(monitor_info_t **mi0, monitor_info_t **mi1);
|
||||
static void add_edid_info(hd_data_t *hd_data, hd_t *hd, unsigned char *edid);
|
||||
static void add_monitor_res(hd_t *hd, unsigned x, unsigned y, unsigned hz, unsigned il);
|
||||
static void fix_edid_info(hd_data_t *hd_data, unsigned char *edid);
|
||||
|
||||
void hd_scan_monitor(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd2;
|
||||
bios_info_t *bt;
|
||||
devtree_t *dt;
|
||||
pci_t *pci;
|
||||
int found;
|
||||
unsigned u;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_monitor)) return;
|
||||
|
||||
hd_data->module = mod_monitor;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
PROGRESS(1, 0, "ddc");
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_internal && hd->sub_class.id == sc_int_bios) break;
|
||||
}
|
||||
|
||||
/* first, see if we got the full edid record from bios */
|
||||
bt = NULL;
|
||||
|
||||
/* for testing: LIBHD_EDID points to a file with valid edid record */
|
||||
{
|
||||
char *s = getenv("LIBHD_EDID");
|
||||
unsigned char edid[0x80];
|
||||
FILE *f;
|
||||
|
||||
if(s && (f = fopen(s, "r"))) {
|
||||
if(fread(edid, sizeof edid, 1, f) == 1) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_monitor;
|
||||
add_edid_info(hd_data, hd, edid);
|
||||
}
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PROGRESS(2, 0, "bios");
|
||||
|
||||
if(
|
||||
hd &&
|
||||
hd->detail &&
|
||||
hd->detail->type == hd_detail_bios &&
|
||||
(bt = hd->detail->bios.data) &&
|
||||
bt->vbe.ok
|
||||
) {
|
||||
int pid = 0;
|
||||
int got_ddc_data = 0;
|
||||
for(pid = 0; pid < bt->vbe.ddc_ports; pid++) {
|
||||
if(chk_edid_info(hd_data, bt->vbe.ddc_port[pid])) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_monitor;
|
||||
|
||||
hd_set_hw_class(hd, hw_vbe);
|
||||
|
||||
hd->func = pid;
|
||||
|
||||
add_edid_info(hd_data, hd, bt->vbe.ddc_port[pid]);
|
||||
|
||||
got_ddc_data = 1;
|
||||
}
|
||||
}
|
||||
if(got_ddc_data) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PROGRESS(3, 0, "pci");
|
||||
found = 0;
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd &&
|
||||
hd->detail &&
|
||||
hd->detail->type == hd_detail_pci &&
|
||||
(pci = hd->detail->pci.data)
|
||||
) {
|
||||
for(u = 0; u < sizeof pci->edid_len / sizeof *pci->edid_len; u++) {
|
||||
if(pci->edid_len[u] >= 0x80 && chk_edid_info(hd_data, pci->edid_data[u])) {
|
||||
hd2 = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd2->base_class.id = bc_monitor;
|
||||
hd2->slot = u;
|
||||
hd2->attached_to = hd->idx;
|
||||
add_edid_info(hd_data, hd2, pci->edid_data[u]);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(found) return;
|
||||
|
||||
PROGRESS(4, 0, "internal db");
|
||||
|
||||
/* Maybe a LCD panel? */
|
||||
if(bt && bt->lcd.width) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_monitor;
|
||||
hd->sub_class.id = sc_mon_lcd;
|
||||
|
||||
hd_set_hw_class(hd, hw_vbe);
|
||||
|
||||
add_lcd_info(hd_data, hd, bt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PROGRESS(5, 0, "prom");
|
||||
|
||||
found = 0;
|
||||
for(dt = hd_data->devtree; dt; dt = dt->next) {
|
||||
if(dt->edid) {
|
||||
add_monitor(hd_data, dt);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__PPC__)
|
||||
PROGRESS(6, 0, "old mac");
|
||||
|
||||
if(!found) {
|
||||
add_old_mac_monitor(hd_data);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if defined(__PPC__)
|
||||
void add_old_mac_monitor(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
unsigned u1, u2;
|
||||
str_list_t *sl;
|
||||
static struct {
|
||||
unsigned width, height, vfreq, interlaced;
|
||||
} mode_list[20] = {
|
||||
{ 512, 384, 60, 1 },
|
||||
{ 512, 384, 60, 0 },
|
||||
{ 640, 480, 50, 1 },
|
||||
{ 640, 480, 60, 1 },
|
||||
{ 640, 480, 60, 0 },
|
||||
{ 640, 480, 67, 0 },
|
||||
{ 640, 870, 75, 0 },
|
||||
{ 768, 576, 50, 1 },
|
||||
{ 800, 600, 56, 0 },
|
||||
{ 800, 600, 60, 0 },
|
||||
{ 800, 600, 72, 0 },
|
||||
{ 800, 600, 75, 0 },
|
||||
{ 832, 624, 75, 0 },
|
||||
{ 1024, 768, 60, 0 },
|
||||
{ 1024, 768, 70, 0 },
|
||||
{ 1024, 768, 75, 0 },
|
||||
{ 1024, 768, 75, 0 },
|
||||
{ 1152, 870, 75, 0 },
|
||||
{ 1280, 960, 75, 0 },
|
||||
{ 1280, 1024, 75, 0 }
|
||||
};
|
||||
|
||||
for(sl = hd_data->klog; sl; sl = sl->next) {
|
||||
if(sscanf(sl->str, "<%*d>Monitor sense value = %i, using video mode %i", &u1, &u2) == 2) {
|
||||
u2--;
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_monitor;
|
||||
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0401);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, (u1 & 0xfff) + 0x1000);
|
||||
|
||||
if((u1 = hd_display_adapter(hd_data))) {
|
||||
hd->attached_to = u1;
|
||||
}
|
||||
|
||||
if(u2 < sizeof mode_list / sizeof *mode_list) {
|
||||
add_monitor_res(hd, mode_list[u2].width, mode_list[u2].height, mode_list[u2].vfreq, mode_list[u2].interlaced);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined(__PPC__) */
|
||||
|
||||
|
||||
void add_monitor(hd_data_t *hd_data, devtree_t *dt)
|
||||
{
|
||||
hd_t *hd, *hd2;
|
||||
unsigned char *edid = dt->edid;
|
||||
|
||||
if(!chk_edid_info(hd_data, edid)) return;
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
|
||||
hd->base_class.id = bc_monitor;
|
||||
|
||||
for(hd2 = hd_data->hd; hd2; hd2 = hd2->next) {
|
||||
if(
|
||||
hd2->detail &&
|
||||
hd2->detail->type == hd_detail_devtree &&
|
||||
hd2->detail->devtree.data == dt
|
||||
) {
|
||||
hd->attached_to = hd2->idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
add_edid_info(hd_data, hd, edid);
|
||||
}
|
||||
|
||||
|
||||
/* do some checks to ensure we got a reasonable block */
|
||||
int chk_edid_info(hd_data_t *hd_data, unsigned char *edid)
|
||||
{
|
||||
// no vendor or model info
|
||||
if(!(edid[0x08] || edid[0x09] || edid[0x0a] || edid[0x0b])) return 0;
|
||||
|
||||
// no edid version or revision
|
||||
if(!(edid[0x12] || edid[0x13])) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void add_lcd_info(hd_data_t *hd_data, hd_t *hd, bios_info_t *bt)
|
||||
{
|
||||
monitor_info_t *mi = NULL;
|
||||
hd_res_t *res = NULL;
|
||||
|
||||
hd->vendor.name = new_str(bt->lcd.vendor);
|
||||
hd->device.name = new_str(bt->lcd.name);
|
||||
|
||||
add_monitor_res(hd, bt->lcd.width, bt->lcd.height, 60, 0);
|
||||
|
||||
mi = new_mem(sizeof *mi);
|
||||
hd->detail = new_mem(sizeof *hd->detail);
|
||||
hd->detail->type = hd_detail_monitor;
|
||||
hd->detail->monitor.data = mi;
|
||||
|
||||
mi->min_vsync = 50;
|
||||
mi->min_hsync = 31;
|
||||
mi->max_vsync = 75;
|
||||
mi->max_hsync = (mi->max_vsync * bt->lcd.height * 12) / 10000;
|
||||
|
||||
if (bt->lcd.xsize) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->size.type = res_size;
|
||||
res->size.unit = size_unit_mm;
|
||||
res->size.val1 = bt->lcd.xsize;
|
||||
res->size.val2 = bt->lcd.ysize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mi_cmp(monitor_info_t **mi0, monitor_info_t **mi1)
|
||||
{
|
||||
return (*mi0)->hdisp * (*mi0)->vdisp - (*mi1)->hdisp * (*mi1)->vdisp;
|
||||
}
|
||||
|
||||
|
||||
void add_edid_info(hd_data_t *hd_data, hd_t *hd, unsigned char *edid)
|
||||
{
|
||||
hd_res_t *res;
|
||||
hd_detail_monitor_t *mdetail;
|
||||
monitor_info_t *mi_list[4], *mi;
|
||||
unsigned mi_cnt = 0;
|
||||
int i;
|
||||
unsigned u, u1, u2, tag;
|
||||
char *s;
|
||||
unsigned width_mm = 0, height_mm = 0, manu_year = 0, manu_week = 0;
|
||||
unsigned min_vsync = 0, max_vsync = 0, min_hsync = 0, max_hsync = 0;
|
||||
unsigned hblank, hsync_ofs, hsync, vblank, vsync_ofs, vsync;
|
||||
char *vendor = NULL, *serial = NULL, *name = NULL;
|
||||
|
||||
fix_edid_info(hd_data, edid);
|
||||
|
||||
if(edid[0x14] & 0x80) {
|
||||
/* digital signal -> assume lcd */
|
||||
hd->sub_class.id = 2;
|
||||
}
|
||||
|
||||
u = (edid[8] << 8) + edid[9];
|
||||
hd->vendor.id = MAKE_ID(TAG_EISA, u);
|
||||
u = (edid[0xb] << 8) + edid[0xa];
|
||||
hd->device.id = MAKE_ID(TAG_EISA, u);
|
||||
if((u = device_class(hd_data, hd->vendor.id, hd->device.id))) {
|
||||
if((u >> 8) == bc_monitor) hd->sub_class.id = u & 0xff;
|
||||
}
|
||||
|
||||
if(edid[0x15] > 0 && edid[0x16] > 0) {
|
||||
width_mm = edid[0x15] * 10;
|
||||
height_mm = edid[0x16] * 10;
|
||||
}
|
||||
|
||||
u = edid[0x23];
|
||||
if(u & (1 << 7)) add_monitor_res(hd, 720, 400, 70, 0);
|
||||
if(u & (1 << 6)) add_monitor_res(hd, 720, 400, 88, 0);
|
||||
if(u & (1 << 5)) add_monitor_res(hd, 640, 480, 60, 0);
|
||||
if(u & (1 << 4)) add_monitor_res(hd, 640, 480, 67, 0);
|
||||
if(u & (1 << 3)) add_monitor_res(hd, 640, 480, 72, 0);
|
||||
if(u & (1 << 2)) add_monitor_res(hd, 640, 480, 75, 0);
|
||||
if(u & (1 << 1)) add_monitor_res(hd, 800, 600, 56, 0);
|
||||
if(u & (1 << 0)) add_monitor_res(hd, 800, 600, 60, 0);
|
||||
|
||||
u = edid[0x24];
|
||||
if(u & (1 << 7)) add_monitor_res(hd, 800, 600, 72, 0);
|
||||
if(u & (1 << 6)) add_monitor_res(hd, 800, 600, 75, 0);
|
||||
if(u & (1 << 5)) add_monitor_res(hd, 832, 624, 75, 0);
|
||||
if(u & (1 << 4)) add_monitor_res(hd, 1024, 768, 87, 1);
|
||||
if(u & (1 << 3)) add_monitor_res(hd, 1024, 768, 60, 0);
|
||||
if(u & (1 << 2)) add_monitor_res(hd, 1024, 768, 70, 0);
|
||||
if(u & (1 << 1)) add_monitor_res(hd, 1024, 768, 75, 0);
|
||||
if(u & (1 << 0)) add_monitor_res(hd, 1280, 1024, 75, 0);
|
||||
|
||||
for(i = 0; i < 4; i++) {
|
||||
u1 = (edid[0x26 + 2 * i] + 31) * 8;
|
||||
u2 = edid[0x27 + 2 * i];
|
||||
u = 0;
|
||||
switch((u2 >> 6) & 3) {
|
||||
case 1: u = (u1 * 3) / 4; break;
|
||||
case 2: u = (u1 * 4) / 5; break;
|
||||
case 3: u = (u1 * 9) / 16; break;
|
||||
}
|
||||
if(u) add_monitor_res(hd, u1, u, (u2 & 0x3f) + 60, 0);
|
||||
}
|
||||
|
||||
manu_year = 1990 + edid[0x11];
|
||||
manu_week = edid[0x10];
|
||||
|
||||
ADD2LOG(" detailed timings:\n");
|
||||
|
||||
/* max. 4 mi_list[] entries */
|
||||
for(i = 0x36; i < 0x36 + 4 * 0x12; i += 0x12) {
|
||||
tag = (edid[i] << 24) + (edid[i + 1] << 16) + (edid[i + 2] << 8) + edid[i + 3];
|
||||
|
||||
ADD2LOG(" #%d: ", (i - 0x36)/0x12);
|
||||
hd_log_hex(hd_data, 1, 0x12, edid + i);
|
||||
ADD2LOG("\n");
|
||||
|
||||
switch(tag) {
|
||||
case 0xfc:
|
||||
if(edid[i + 5]) {
|
||||
/* name entry is splitted some times */
|
||||
str_printf(&name, -1, "%s%s", name ? " " : "", canon_str(edid + i + 5, 0xd));
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xfd:
|
||||
u = 0;
|
||||
u1 = edid[i + 5];
|
||||
u2 = edid[i + 6];
|
||||
if(u1 > u2 || !u1) u = 1;
|
||||
min_vsync = u1;
|
||||
max_vsync = u2;
|
||||
u1 = edid[i + 7];
|
||||
u2 = edid[i + 8];
|
||||
if(u1 > u2 || !u1) u = 1;
|
||||
min_hsync = u1;
|
||||
max_hsync = u2;
|
||||
if(u) {
|
||||
min_vsync = max_vsync = min_hsync = max_hsync = 0;
|
||||
ADD2LOG(" ddc oops: invalid freq data\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xfe:
|
||||
if(!vendor && edid[i + 5]) {
|
||||
vendor = canon_str(edid + i + 5, 0xd);
|
||||
for(s = vendor; *s; s++) if(*s < ' ') *s = ' ';
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xff:
|
||||
if(!serial && edid[i + 5]) {
|
||||
serial = canon_str(edid + i + 5, 0xd);
|
||||
for(s = serial; *s; s++) if(*s < ' ') *s = ' ';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if(tag < 0x100) {
|
||||
ADD2LOG(" unknown tag 0x%02x\n", tag);
|
||||
}
|
||||
else {
|
||||
/* check for duplicates */
|
||||
|
||||
for(u1 = 1, u = 0x36; u < i; u += 0x12) {
|
||||
u1 = memcmp(edid + u, edid + i, 0x12);
|
||||
if(!u1) break;
|
||||
}
|
||||
|
||||
if(!u1) {
|
||||
ADD2LOG(" duplicate of #%d - skipped\n", (u - 0x36)/0x12);
|
||||
break;
|
||||
}
|
||||
|
||||
mi_list[mi_cnt++] = mi = new_mem(sizeof *mi);
|
||||
|
||||
mi->width_mm = width_mm;
|
||||
mi->height_mm = height_mm;
|
||||
mi->manu_year = manu_year;
|
||||
mi->manu_week = manu_week;
|
||||
|
||||
u = (edid[i + 0] + (edid[i + 1] << 8)) * 10; /* pixel clock in kHz */
|
||||
if(!u) break;
|
||||
mi->clock = u;
|
||||
|
||||
u1 = edid[i + 2] + ((edid[i + 4] & 0xf0) << 4);
|
||||
u2 = edid[i + 5] + ((edid[i + 7] & 0xf0) << 4);
|
||||
if(!u1 || !u2 || u1 == 0xfff || u2 == 0xfff) break;
|
||||
mi->width = u1;
|
||||
mi->height = u2;
|
||||
|
||||
u1 = edid[i + 12] + ((edid[i + 14] & 0xf0) << 4);
|
||||
u2 = edid[i + 13] + ((edid[i + 14] & 0xf) << 8);
|
||||
if(!u1 || !u2 || u1 == 0xfff || u2 == 0xfff) break;
|
||||
mi->width_mm = u1;
|
||||
mi->height_mm = u2;
|
||||
|
||||
|
||||
hblank = edid[i + 3] + ((edid[i + 4] & 0xf) << 8);
|
||||
hsync_ofs = edid[i + 8] + ((edid[i + 11] & 0xc0) << 2);
|
||||
hsync = edid[i + 9] + ((edid[i + 11] & 0x30) << 4);
|
||||
|
||||
vblank = edid[i + 6] + ((edid[i + 7] & 0xf) << 8);
|
||||
vsync_ofs = ((edid[i + 10] & 0xf0) >> 4) + ((edid[i + 11] & 0x0c) << 2);
|
||||
vsync = (edid[i + 10] & 0xf) + ((edid[i + 11] & 0x03) << 4);
|
||||
|
||||
mi->hdisp = mi->width;
|
||||
mi->hsyncstart = mi->width + hsync_ofs;
|
||||
mi->hsyncend = mi->width + hsync_ofs + hsync;
|
||||
mi->htotal = mi->width + hblank;
|
||||
ADD2LOG(
|
||||
" h: %4u %4u %4u %4u (+%u +%u +%u)\n",
|
||||
mi->hdisp, mi->hsyncstart, mi->hsyncend, mi->htotal,
|
||||
hsync_ofs, hsync_ofs + hsync, hblank
|
||||
);
|
||||
|
||||
mi->vdisp = mi->height;
|
||||
mi->vsyncstart = mi->height + vsync_ofs;
|
||||
mi->vsyncend = mi->height + vsync_ofs + vsync;
|
||||
mi->vtotal = mi->height + vblank;
|
||||
ADD2LOG(
|
||||
" v: %4u %4u %4u %4u (+%u +%u +%u)\n",
|
||||
mi->vdisp, mi->vsyncstart, mi->vsyncend, mi->vtotal,
|
||||
vsync_ofs, vsync_ofs + vsync, vblank
|
||||
);
|
||||
|
||||
u = edid[i + 17];
|
||||
|
||||
if(((u >> 3) & 3) == 3) {
|
||||
mi->hflag = (u & 4) ? '+' : '-';
|
||||
mi->vflag = (u & 2) ? '+' : '-';
|
||||
ADD2LOG(" %chsync %cvsync\n", mi->hflag, mi->vflag);
|
||||
}
|
||||
|
||||
u1 = mi->width + hblank;
|
||||
u2 = mi->height + vblank;
|
||||
|
||||
if(u1 && u2) {
|
||||
ADD2LOG(
|
||||
" %.1f MHz, %.1f kHz, %.1f Hz\n",
|
||||
(double) mi->clock / 1000,
|
||||
(double) mi->clock / u1,
|
||||
(double) mi->clock / u1 / u2 * 1000
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(u = 0; u < mi_cnt; u++) {
|
||||
mi = mi_list[u];
|
||||
|
||||
mi->min_vsync = min_vsync;
|
||||
mi->max_vsync = max_vsync;
|
||||
mi->min_hsync = min_hsync;
|
||||
mi->max_hsync = max_hsync;
|
||||
|
||||
mi->name = new_str(name);
|
||||
mi->vendor = new_str(vendor);
|
||||
mi->serial = new_str(serial);
|
||||
}
|
||||
|
||||
if(mi_cnt) {
|
||||
qsort(mi_list, mi_cnt, sizeof *mi_list, (int (*)(const void *, const void *)) mi_cmp);
|
||||
|
||||
for(i = 0; i < mi_cnt; i++) {
|
||||
mi = mi_list[i];
|
||||
|
||||
mdetail = hd->detail && hd->detail->type == hd_detail_monitor ? &hd->detail->monitor : NULL;
|
||||
|
||||
hd->detail = new_mem(sizeof *hd->detail);
|
||||
hd->detail->type = hd_detail_monitor;
|
||||
hd->detail->monitor.data = mi;
|
||||
hd->detail->monitor.next = mdetail;
|
||||
|
||||
hd->serial = new_str(mi->serial);
|
||||
hd->vendor.name = new_str(mi->vendor);
|
||||
hd->device.name = new_str(mi->name);
|
||||
|
||||
if(mi->width && mi->height) {
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(
|
||||
res->any.type == res_monitor &&
|
||||
res->monitor.width == mi->width &&
|
||||
res->monitor.height == mi->height
|
||||
) break;
|
||||
}
|
||||
/* actually we could calculate the vsync value */
|
||||
if(!res) add_monitor_res(hd, mi->width, mi->height, 60, 0);
|
||||
|
||||
/* do some sanity checks on display size, see bugs 155096, 186096, 213630 */
|
||||
if(mi->width_mm && mi->height_mm) {
|
||||
u = (mi->width_mm * mi->height * 16) / (mi->height_mm * mi->width);
|
||||
u1 = width_mm ? (width_mm * 16) / mi->width_mm : 16;
|
||||
u2 = height_mm ? (height_mm * 16) / mi->height_mm : 16;
|
||||
if(
|
||||
u <= 8 || u >= 32 || /* allow 1:2 distortion */
|
||||
u1 <= 8 || u1 >= 32 || /* width cm & mm values disagree by factor >2 --> use cm values */
|
||||
u2 <= 8 || u2 >= 32 || /* dto, height */
|
||||
mi->width_mm < 100 || /* too small to be true... */
|
||||
mi->height_mm < 100
|
||||
) {
|
||||
ADD2LOG(" ddc: strange size data (%ux%u mm^2), trying cm values\n", mi->width_mm, mi->height_mm);
|
||||
/* ok, try cm values */
|
||||
if(width_mm && height_mm) {
|
||||
u = (width_mm * mi->height * 16) / (height_mm * mi->width);
|
||||
if(u > 8 && u < 32 && width_mm >= 100 && height_mm >= 100) {
|
||||
mi->width_mm = width_mm;
|
||||
mi->height_mm = height_mm;
|
||||
}
|
||||
}
|
||||
/* could not fix, clear */
|
||||
if(u <= 8 || u >= 32 || mi->width_mm < 100 || mi->height_mm < 100) {
|
||||
ADD2LOG(" ddc: cm values (%ux%u mm^2) didn't work either - giving up\n", width_mm, height_mm);
|
||||
mi->width_mm = mi->height_mm = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mi = mi_list[0];
|
||||
|
||||
if(mi->width_mm && mi->height_mm) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->size.type = res_size;
|
||||
res->size.unit = size_unit_mm;
|
||||
res->size.val1 = mi->width_mm; /* width */
|
||||
res->size.val2 = mi->height_mm; /* height */
|
||||
}
|
||||
|
||||
if(hd_data->debug) {
|
||||
ADD2LOG("----- DDC info -----\n");
|
||||
if(mi->vendor) {
|
||||
ADD2LOG(" vendor: \"%s\"\n", mi->vendor);
|
||||
}
|
||||
if(mi->name) {
|
||||
ADD2LOG(" model: \"%s\"\n", mi->name);
|
||||
}
|
||||
if(mi->serial) {
|
||||
ADD2LOG(" serial: \"%s\"\n", mi->serial);
|
||||
}
|
||||
if(mi->width || mi->height) {
|
||||
ADD2LOG(" size: %u x %u\n", mi->width, mi->height);
|
||||
}
|
||||
if(mi->width_mm || mi->height_mm) {
|
||||
ADD2LOG(" size (mm): %u x %u\n", mi->width_mm, mi->height_mm);
|
||||
}
|
||||
if(mi->clock) {
|
||||
ADD2LOG(" clock: %u kHz\n", mi->clock);
|
||||
}
|
||||
if(mi->min_hsync) {
|
||||
ADD2LOG(" hsync: %u-%u kHz\n", mi->min_hsync, mi->max_hsync);
|
||||
}
|
||||
if(mi->min_vsync) {
|
||||
ADD2LOG(" vsync: %u-%u Hz\n", mi->min_vsync, mi->max_vsync);
|
||||
}
|
||||
if(mi->manu_year) {
|
||||
ADD2LOG(" manu. year: %u\n", mi->manu_year);
|
||||
}
|
||||
ADD2LOG("----- DDC info end -----\n");
|
||||
}
|
||||
}
|
||||
|
||||
free_mem(serial);
|
||||
free_mem(vendor);
|
||||
free_mem(name);
|
||||
}
|
||||
|
||||
void add_monitor_res(hd_t *hd, unsigned width, unsigned height, unsigned vfreq, unsigned il)
|
||||
{
|
||||
hd_res_t *res;
|
||||
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->monitor.type = res_monitor;
|
||||
res->monitor.width = width;
|
||||
res->monitor.height = height;
|
||||
res->monitor.vfreq = vfreq;
|
||||
res->monitor.interlaced = il;
|
||||
}
|
||||
|
||||
/*
|
||||
* This looks evil, but some Mac displays really lie at us.
|
||||
*/
|
||||
void fix_edid_info(hd_data_t *hd_data, unsigned char *edid)
|
||||
{
|
||||
unsigned vend, dev;
|
||||
unsigned timing;
|
||||
int fix = 0;
|
||||
|
||||
vend = (edid[8] << 8) + edid[9];
|
||||
dev = (edid[0xb] << 8) + edid[0xa];
|
||||
|
||||
timing = (edid[0x24] << 8) + edid[0x23];
|
||||
|
||||
/* APP9214: Apple Studio Display */
|
||||
if(vend == 0x0610 && dev == 0x9214 && timing == 0x0800) {
|
||||
timing = 0x1000;
|
||||
fix = 1;
|
||||
}
|
||||
|
||||
if(fix) {
|
||||
edid[0x23] = timing & 0xff;
|
||||
edid[0x24] = (timing >> 8) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_monitor(hd_data_t *hd_data);
|
|
@ -0,0 +1,789 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "mouse.h"
|
||||
|
||||
/**
|
||||
* @defgroup MOUSEdev Mouse devices
|
||||
* @ingroup libhdDEVint
|
||||
* @brief Mouse detection
|
||||
*
|
||||
* @todo reset serial lines to old values (cf. modem.c)
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef LIBHD_TINY
|
||||
|
||||
#if 0
|
||||
static unsigned read_data(hd_data_t *hd_data, int fd, unsigned char *buf, unsigned buf_size);
|
||||
static void get_ps2_mouse(hd_data_t *hd_data);
|
||||
static void test_ps2_open(void *arg);
|
||||
#endif
|
||||
|
||||
static void get_serial_mouse(hd_data_t* hd_data);
|
||||
static void add_serial_mouse(hd_data_t* hd_data);
|
||||
static int _setspeed(int fd, int old, int new, int needtowrite, unsigned short flags);
|
||||
static void setspeed(int fd, int new, int needtowrite, unsigned short flags);
|
||||
static unsigned chk4id(ser_device_t *mi);
|
||||
static ser_device_t *add_ser_mouse_entry(ser_device_t **sm, ser_device_t *new_sm);
|
||||
static void dump_ser_mouse_data(hd_data_t *hd_data);
|
||||
#if 0
|
||||
static void get_sunmouse(hd_data_t *hd_data);
|
||||
#endif
|
||||
|
||||
void hd_scan_mouse(hd_data_t *hd_data)
|
||||
{
|
||||
ser_device_t *sm, *sm_next;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_mouse)) return;
|
||||
|
||||
hd_data->module = mod_mouse;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
hd_data->ser_mouse = NULL;
|
||||
|
||||
#if 0
|
||||
PROGRESS(1, 0, "ps/2");
|
||||
|
||||
get_ps2_mouse(hd_data);
|
||||
#endif
|
||||
|
||||
PROGRESS(2, 0, "serial");
|
||||
|
||||
hd_fork(hd_data, 20, 20);
|
||||
|
||||
if(hd_data->flags.forked) {
|
||||
get_serial_mouse(hd_data);
|
||||
hd_move_to_shm(hd_data);
|
||||
if((hd_data->debug & HD_DEB_MOUSE)) dump_ser_mouse_data(hd_data);
|
||||
}
|
||||
else {
|
||||
/* take data from shm */
|
||||
hd_data->ser_mouse = ((hd_data_t *) (hd_data->shm.data))->ser_mouse;
|
||||
if((hd_data->debug & HD_DEB_MOUSE)) dump_ser_mouse_data(hd_data);
|
||||
}
|
||||
|
||||
hd_fork_done(hd_data);
|
||||
|
||||
add_serial_mouse(hd_data);
|
||||
|
||||
hd_shm_clean(hd_data);
|
||||
|
||||
for(sm = hd_data->ser_mouse; sm; sm = sm_next) {
|
||||
sm_next = sm->next;
|
||||
|
||||
free_mem(sm->dev_name);
|
||||
free_mem(sm);
|
||||
}
|
||||
hd_data->ser_mouse = NULL;
|
||||
|
||||
#if 0
|
||||
PROGRESS(3, 0, "sunmouse");
|
||||
|
||||
get_sunmouse(hd_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
unsigned read_data(hd_data_t *hd_data, int fd, unsigned char *buf, unsigned buf_size)
|
||||
{
|
||||
int k, len = 0;
|
||||
unsigned char *bp;
|
||||
|
||||
while(
|
||||
(unsigned) len < buf_size &&
|
||||
(k = read(fd, buf + len, buf_size - len)) >= 0
|
||||
) len += k;
|
||||
|
||||
bp = buf;
|
||||
if(len && (*bp == 0xfe || *bp == 0xfa)) { bp++; len--; }
|
||||
|
||||
for(k = 0; k < len; k++) buf[k] = bp[k];
|
||||
|
||||
if((hd_data->debug & HD_DEB_MOUSE)) {
|
||||
ADD2LOG("ps/2[%d]: ", len);
|
||||
hd_log_hex(hd_data, 1, len, buf);
|
||||
ADD2LOG("\n");
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* How it works:
|
||||
*
|
||||
* 1. There must exist a PS/2 controller entry (-> there is a PS/2 port).
|
||||
* 2. If there are PS/2 mouse irq events, assume a PS/2 mouse is attached.
|
||||
* 3. Otherwise:
|
||||
* - open /dev/psaux
|
||||
* - write the "get mouse info" command (0xe9)
|
||||
* - read back the response, which should be either 0xfe "resend data"
|
||||
* or, e.g. (0xfa) 0x20 0x02 0x3c (0xfa = "ACK" (should be swallowed
|
||||
* by the psaux driver, but isn't), the rest are settings)
|
||||
* - ignore the first byte if it is 0xfa or 0xfe
|
||||
* - if there are at least 2 bytes left, assume a mouse is attached.
|
||||
*
|
||||
* Note1: we could use the command 0xfe "get mouse ID" instead. But that turned
|
||||
* out to be less reliable, as this command returns only one byte, which
|
||||
* is even 0.
|
||||
* Note2: step 2 is mainly relevant if the mouse is already in use. In that
|
||||
* case we would have problems reading back the respose of our command.
|
||||
* (Typically the mouse driver will get it (and choke on it).)
|
||||
*/
|
||||
|
||||
static void get_ps2_mouse(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd1;
|
||||
hd_res_t *res;
|
||||
int fd;
|
||||
fd_set set;
|
||||
struct timeval tv;
|
||||
unsigned char cmd_mouse_info = 0xe9; /* read mouse info (3 bytes) */
|
||||
unsigned char cmd_mouse_id = 0xf2; /* read mouse id (1 byte) */
|
||||
unsigned char buf[100];
|
||||
unsigned mouse_id = -1;
|
||||
static unsigned char intelli_init[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
|
||||
int buf_len = 0;
|
||||
#ifdef __PPC__
|
||||
int always_ps2_mouse = 0;
|
||||
#endif
|
||||
|
||||
for(hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
|
||||
/* look for a PS/2 controller entry... */
|
||||
if(hd1->base_class.id == bc_ps2) {
|
||||
/* ...and see if there were irq events... */
|
||||
for(res = hd1->res; res; res = res->next) {
|
||||
if(res->irq.type == res_irq && res->irq.triggered) break;
|
||||
}
|
||||
|
||||
#ifdef __PPC__
|
||||
/*
|
||||
* On PReP & CHRP, assume a PS/2 mouse to be attached.
|
||||
* There seems to be no way to actually *detect* it.
|
||||
*/
|
||||
if(!res) {
|
||||
hd_t *hd;
|
||||
sys_info_t *st;
|
||||
|
||||
if((hd = hd_list(hd_data, hw_sys, 0, NULL))) {
|
||||
if(
|
||||
hd->detail &&
|
||||
hd->detail->type == hd_detail_sys &&
|
||||
(st = hd->detail->sys.data) &&
|
||||
(
|
||||
!strcmp(st->system_type, "PReP") ||
|
||||
strstr(st->system_type, "CHRP") == st->system_type /* CHRP && CHRP64 */
|
||||
)
|
||||
) {
|
||||
always_ps2_mouse = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PROGRESS(1, 1, "ps/2");
|
||||
|
||||
/* open the mouse device... */
|
||||
if(hd_timeout(test_ps2_open, NULL, 2) > 0) {
|
||||
ADD2LOG("ps/2: open(%s) timed out\n", DEV_PSAUX);
|
||||
fd = -2;
|
||||
}
|
||||
else {
|
||||
fd = open(DEV_PSAUX, O_RDWR | O_NONBLOCK);
|
||||
}
|
||||
|
||||
PROGRESS(1, 2, "ps/2");
|
||||
|
||||
if(fd >= 0) {
|
||||
/* ...write the id command... */
|
||||
|
||||
PROGRESS(1, 3, "ps/2");
|
||||
|
||||
write(fd, intelli_init, sizeof intelli_init);
|
||||
usleep(25000);
|
||||
read_data(hd_data, fd, buf, sizeof buf);
|
||||
|
||||
if(write(fd, &cmd_mouse_id, 1) == 1) {
|
||||
|
||||
PROGRESS(1, 4, "ps/2");
|
||||
usleep(50000); /* ...give it a chance to react... */
|
||||
|
||||
/* ...read the response... */
|
||||
buf_len = read_data(hd_data, fd, buf, sizeof buf);
|
||||
|
||||
if(buf_len >= 1) mouse_id = buf[buf_len - 1];
|
||||
|
||||
// if we didn't get any response, try this
|
||||
if(buf_len == 0 || (hd_data->debug & HD_DEB_MOUSE)) {
|
||||
PROGRESS(1, 5, "ps/2");
|
||||
if(write(fd, &cmd_mouse_info, 1) == 1) {
|
||||
usleep(50000);
|
||||
buf_len = read_data(hd_data, fd, buf, sizeof buf);
|
||||
/*
|
||||
* Assume a mouse to be attached if at least 2 bytes are
|
||||
* returned.
|
||||
*/
|
||||
if(mouse_id == -1u && buf_len >= 2) mouse_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PROGRESS(1, 6, "ps/2");
|
||||
}
|
||||
close(fd);
|
||||
|
||||
PROGRESS(1, 7, "ps/2");
|
||||
|
||||
/*
|
||||
* The following code is apparently necessary on some board/mouse
|
||||
* combinations. Otherwise the PS/2 mouse won't work.
|
||||
*/
|
||||
if((fd = open(DEV_PSAUX, O_RDONLY | O_NONBLOCK)) >= 0) {
|
||||
PROGRESS(1, 8, "ps/2");
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fd, &set);
|
||||
tv.tv_sec = 0; tv.tv_usec = 1;
|
||||
if(select(fd + 1, &set, NULL, NULL, &tv) == 1) {
|
||||
PROGRESS(1, 9, "ps/2");
|
||||
|
||||
read(fd, buf, sizeof buf);
|
||||
|
||||
PROGRESS(1, 10, "ps/2");
|
||||
}
|
||||
PROGRESS(1, 11, "ps/2");
|
||||
|
||||
close(fd);
|
||||
|
||||
PROGRESS(1, 12, "ps/2");
|
||||
}
|
||||
}
|
||||
else {
|
||||
ADD2LOG("open(" DEV_PSAUX "): %s\n", fd == -1 ? strerror(errno) : "timeout");
|
||||
}
|
||||
|
||||
if(mouse_id == -1u) {
|
||||
|
||||
/*
|
||||
* Assume a PS/2 mouse is attached if the ps/2 controller has
|
||||
* genetrated some events.
|
||||
*/
|
||||
|
||||
if(
|
||||
res
|
||||
#ifdef __PPC__
|
||||
|| always_ps2_mouse
|
||||
#endif
|
||||
) {
|
||||
PROGRESS(1, 13, "ps/2");
|
||||
mouse_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(mouse_id != -1u) {
|
||||
PROGRESS(1, 14, "ps/2");
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_mouse;
|
||||
hd->sub_class.id = sc_mou_ps2;
|
||||
hd->bus.id = bus_ps2;
|
||||
hd->unix_dev_name = new_str(DEV_MICE);
|
||||
hd->attached_to = hd1->idx;
|
||||
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0200);
|
||||
switch(mouse_id) {
|
||||
case 3: /* 3 buttons + wheel */
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0004);
|
||||
break;
|
||||
|
||||
case 4: /* 5 buttons + wheel */
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0005);
|
||||
break;
|
||||
|
||||
default: /* 0 */
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0002);
|
||||
}
|
||||
}
|
||||
|
||||
/* there can only be one... */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_ps2_open(void *arg)
|
||||
{
|
||||
open(DEV_PSAUX, O_RDWR | O_NONBLOCK);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void get_sunmouse(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
int fd;
|
||||
int found;
|
||||
|
||||
found = 0;
|
||||
|
||||
/* Only search for Sun mouse if we have a Sun keyboard */
|
||||
for(hd = hd_data->hd; hd; hd = hd->next)
|
||||
{
|
||||
if(hd->base_class.id == bc_keyboard &&
|
||||
hd->sub_class.id == sc_keyboard_kbd &&
|
||||
ID_TAG(hd->vendor.id) == TAG_SPECIAL && ID_VALUE(hd->vendor.id) == 0x0202)
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
if ((fd = open(DEV_SUNMOUSE, O_RDONLY)) != -1)
|
||||
{
|
||||
/* FIXME: Should probably talk to the mouse to see
|
||||
if the connector is not empty. */
|
||||
close (fd);
|
||||
|
||||
PROGRESS(1, 1, "Sun Mouse");
|
||||
|
||||
hd = add_hd_entry (hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_mouse;
|
||||
hd->sub_class.id = sc_mou_sun;
|
||||
hd->bus.id = bus_serial;
|
||||
hd->unix_dev_name = new_str(DEV_SUNMOUSE);
|
||||
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0202);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0000);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Gather serial mouse data and put it into hd_data->ser_mouse.
|
||||
*/
|
||||
void get_serial_mouse(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
int j, fd, fd_max = 0, sel, max_len;
|
||||
unsigned modem_info;
|
||||
fd_set set, set0;
|
||||
struct timeval to;
|
||||
ser_device_t *sm;
|
||||
struct termios tio;
|
||||
|
||||
FD_ZERO(&set);
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_comm &&
|
||||
hd->sub_class.id == sc_com_ser &&
|
||||
hd->unix_dev_name &&
|
||||
!hd->tag.skip_mouse &&
|
||||
!has_something_attached(hd_data, hd)
|
||||
) {
|
||||
if((fd = open(hd->unix_dev_name, O_RDWR | O_NONBLOCK)) >= 0) {
|
||||
if(tcgetattr(fd, &tio)) continue;
|
||||
sm = add_ser_mouse_entry(&hd_data->ser_mouse, new_mem(sizeof *sm));
|
||||
sm->dev_name = new_str(hd->unix_dev_name);
|
||||
sm->fd = fd;
|
||||
sm->tio = tio;
|
||||
sm->hd_idx = hd->idx;
|
||||
if(fd > fd_max) fd_max = fd;
|
||||
FD_SET(fd, &set);
|
||||
|
||||
/*
|
||||
* PnP COM spec black magic...
|
||||
*/
|
||||
setspeed(fd, 1200, 1, CS7);
|
||||
modem_info = TIOCM_DTR | TIOCM_RTS;
|
||||
ioctl(fd, TIOCMBIC, &modem_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!hd_data->ser_mouse) return;
|
||||
|
||||
/*
|
||||
* 200 ms seems to be too fast for some mice...
|
||||
*/
|
||||
usleep(300000); /* PnP protocol */
|
||||
|
||||
for(sm = hd_data->ser_mouse; sm; sm = sm->next) {
|
||||
modem_info = TIOCM_DTR | TIOCM_RTS;
|
||||
ioctl(sm->fd, TIOCMBIS, &modem_info);
|
||||
}
|
||||
|
||||
/* smaller buffer size, otherwise we might wait really long... */
|
||||
max_len = sizeof sm->buf < 128 ? sizeof sm->buf : 128;
|
||||
|
||||
to.tv_sec = 0; to.tv_usec = 300000;
|
||||
|
||||
set0 = set;
|
||||
for(;;) {
|
||||
to.tv_sec = 0; to.tv_usec = 300000;
|
||||
set = set0;
|
||||
if((sel = select(fd_max + 1, &set, NULL, NULL, &to)) > 0) {
|
||||
for(sm = hd_data->ser_mouse; sm; sm = sm->next) {
|
||||
if(FD_ISSET(sm->fd, &set)) {
|
||||
if((j = read(sm->fd, sm->buf + sm->buf_len, max_len - sm->buf_len)) > 0)
|
||||
sm->buf_len += j;
|
||||
if(j <= 0) FD_CLR(sm->fd, &set0); // #####
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(sm = hd_data->ser_mouse; sm; sm = sm->next) {
|
||||
chk4id(sm);
|
||||
/* reset serial lines */
|
||||
tcflush(sm->fd, TCIOFLUSH);
|
||||
tcsetattr(sm->fd, TCSAFLUSH, &sm->tio);
|
||||
close(sm->fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Go through serial mouse data and add hd entries.
|
||||
*/
|
||||
void add_serial_mouse(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd;
|
||||
char buf[4];
|
||||
ser_device_t *sm;
|
||||
|
||||
for(sm = hd_data->ser_mouse; sm; sm = sm->next) {
|
||||
if(sm->is_mouse) {
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_mouse;
|
||||
hd->sub_class.id = sc_mou_ser;
|
||||
hd->bus.id = bus_serial;
|
||||
hd->unix_dev_name = new_str(sm->dev_name);
|
||||
hd->attached_to = sm->hd_idx;
|
||||
if(*sm->pnp_id) {
|
||||
strncpy(buf, sm->pnp_id, 3);
|
||||
buf[3] = 0;
|
||||
hd->vendor.id = name2eisa_id(buf);
|
||||
if(!hd->vendor.id) { /* in case it's a really strange one... */
|
||||
hd->vendor.name = new_str(buf);
|
||||
}
|
||||
hd->device.id = MAKE_ID(TAG_EISA, strtol(sm->pnp_id + 3, NULL, 16));
|
||||
|
||||
hd->serial = new_str(sm->serial);
|
||||
if(sm->user_name) hd->device.name = new_str(sm->user_name);
|
||||
if(sm->vend) {
|
||||
free_mem(hd->vendor.name);
|
||||
hd->vendor.name = new_str(sm->vend);
|
||||
}
|
||||
|
||||
if(sm->dev_id && strlen(sm->dev_id) >= 7) {
|
||||
char buf[5], *s;
|
||||
unsigned u1, u2;
|
||||
|
||||
u1 = name2eisa_id(sm->dev_id);
|
||||
if(u1) {
|
||||
strncpy(buf, sm->dev_id + 3, 4);
|
||||
buf[4] = 0;
|
||||
u2 = strtol(sm->dev_id + 3, &s, 16);
|
||||
if(!*s) {
|
||||
hd->compat_vendor.id = u1;
|
||||
hd->compat_device.id = MAKE_ID(TAG_EISA, u2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0200);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0003);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Baud setting magic taken from gpm.
|
||||
*/
|
||||
|
||||
int _setspeed(int fd, int old, int new, int needtowrite, unsigned short flags)
|
||||
{
|
||||
struct termios tty;
|
||||
char *c;
|
||||
int err = 0;
|
||||
|
||||
flags |= CREAD | CLOCAL | HUPCL;
|
||||
|
||||
if(tcgetattr(fd, &tty)) return errno;
|
||||
|
||||
tty.c_iflag = IGNBRK | IGNPAR;
|
||||
tty.c_oflag = 0;
|
||||
tty.c_lflag = 0;
|
||||
tty.c_line = 0;
|
||||
tty.c_cc[VTIME] = 0;
|
||||
tty.c_cc[VMIN] = 1;
|
||||
|
||||
switch (old)
|
||||
{
|
||||
case 9600: tty.c_cflag = flags | B9600; break;
|
||||
case 4800: tty.c_cflag = flags | B4800; break;
|
||||
case 2400: tty.c_cflag = flags | B2400; break;
|
||||
case 1200:
|
||||
default: tty.c_cflag = flags | B1200; break;
|
||||
}
|
||||
|
||||
if(tcsetattr(fd, TCSAFLUSH, &tty)) return errno;
|
||||
|
||||
switch (new)
|
||||
{
|
||||
case 9600: c = "*q"; tty.c_cflag = flags | B9600; break;
|
||||
case 4800: c = "*p"; tty.c_cflag = flags | B4800; break;
|
||||
case 2400: c = "*o"; tty.c_cflag = flags | B2400; break;
|
||||
case 1200:
|
||||
default: c = "*n"; tty.c_cflag = flags | B1200; break;
|
||||
}
|
||||
|
||||
if(needtowrite) {
|
||||
err = 2 - write(fd, c, 2);
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
|
||||
if(tcsetattr(fd, TCSAFLUSH, &tty)) return errno;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void setspeed(int fd, int new, int needtowrite, unsigned short flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 9600; i >= 1200; i >>= 1) {
|
||||
_setspeed(fd, i, new, needtowrite, flags);
|
||||
#if 0
|
||||
if(err) {
|
||||
fprintf(stderr, "%d, %d ", i, err);
|
||||
perror("");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Check for a PnP info field starting at ofs;
|
||||
* returns either the length of the field or 0 if none was found.
|
||||
*
|
||||
* the minfo_t struct is updated with the PnP data
|
||||
*/
|
||||
int is_pnpinfo(ser_device_t *mi, int ofs)
|
||||
{
|
||||
int i;
|
||||
unsigned char *s = mi->buf + ofs;
|
||||
int len = mi->buf_len - ofs;
|
||||
|
||||
if(len <= 0) return 0;
|
||||
|
||||
switch(*s) {
|
||||
case 0x08:
|
||||
mi->bits = 6; break;
|
||||
case 0x28:
|
||||
mi->bits = 7; break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(len < 11) return 0;
|
||||
|
||||
/* six bit values */
|
||||
if((s[1] & ~0x3f) || (s[2] & ~0x3f)) return 0;
|
||||
mi->pnp_rev = (s[1] << 6) + s[2];
|
||||
|
||||
/* the eisa id */
|
||||
for(i = 0; i < 7; i++) {
|
||||
mi->pnp_id[i] = s[i + 3];
|
||||
if(mi->bits == 6) mi->pnp_id[i] += 0x20;
|
||||
}
|
||||
mi->pnp_id[7] = 0;
|
||||
|
||||
/* now check the id */
|
||||
for(i = 0; i < 3; i++) {
|
||||
if(
|
||||
(mi->pnp_id[i] < 'A' || mi->pnp_id[i] > 'Z') &&
|
||||
mi->pnp_id[i] != '_'
|
||||
) return 0;
|
||||
}
|
||||
|
||||
for(i = 3; i < 7; i++) {
|
||||
if(
|
||||
(mi->pnp_id[i] < '0' || mi->pnp_id[i] > '9') &&
|
||||
(mi->pnp_id[i] < 'A' || mi->pnp_id[i] > 'F')
|
||||
) return 0;
|
||||
}
|
||||
|
||||
if(
|
||||
(mi->bits == 6 && s[10] == 0x09) ||
|
||||
(mi->bits == 7 && s[10] == 0x29)
|
||||
) {
|
||||
return 11;
|
||||
}
|
||||
|
||||
if(
|
||||
(mi->bits != 6 || s[10] != 0x3c) &&
|
||||
(mi->bits != 7 || s[10] != 0x5c)
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip extended info */
|
||||
for(i = 11; i < len; i++) {
|
||||
if(
|
||||
(mi->bits == 6 && s[i] == 0x09) ||
|
||||
(mi->bits == 7 && s[i] == 0x29)
|
||||
) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* some mice have problems providing the extended info -> return ok in
|
||||
* these cases too
|
||||
*/
|
||||
if(
|
||||
(mi->bits == 6 && s[10] == 0x3c) ||
|
||||
(mi->bits == 7 && s[10] == 0x5c)
|
||||
) {
|
||||
return 11;
|
||||
}
|
||||
|
||||
/* no end token... */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned chk4id(ser_device_t *mi)
|
||||
{
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
unsigned char fake[] =
|
||||
{
|
||||
// fake pnp data
|
||||
};
|
||||
|
||||
mi->buf_len = sizeof fake;
|
||||
memcpy(mi->buf, fake, mi->buf_len);
|
||||
// for(i = 0; i < mi->buf_len; i++) mi->buf[i] += ' ';
|
||||
#endif
|
||||
|
||||
if(!mi->buf_len) return 0;
|
||||
|
||||
for(i = 0; i < mi->buf_len; i++) {
|
||||
if((mi->pnp = is_pnpinfo(mi, i))) break;
|
||||
}
|
||||
if(i == mi->buf_len) {
|
||||
/* non PnP, but MS compatible */
|
||||
if(*mi->buf == 'M')
|
||||
mi->non_pnp = mi->buf_len - 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
mi->garbage = i;
|
||||
|
||||
for(i = 0; i < mi->garbage; i++) {
|
||||
if(mi->buf[i] == 'M') {
|
||||
mi->non_pnp = mi->garbage - i;
|
||||
mi->garbage = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(mi->non_pnp || mi->bits == 6) mi->is_mouse = 1;
|
||||
|
||||
return mi->is_mouse;
|
||||
}
|
||||
|
||||
ser_device_t *add_ser_mouse_entry(ser_device_t **sm, ser_device_t *new_sm)
|
||||
{
|
||||
while(*sm) sm = &(*sm)->next;
|
||||
return *sm = new_sm;
|
||||
}
|
||||
|
||||
|
||||
void dump_ser_mouse_data(hd_data_t *hd_data)
|
||||
{
|
||||
int j;
|
||||
ser_device_t *sm;
|
||||
|
||||
if(!(sm = hd_data->ser_mouse)) return;
|
||||
|
||||
ADD2LOG("----- serial mice -----\n");
|
||||
|
||||
for(; sm; sm = sm->next) {
|
||||
ADD2LOG("%s\n", sm->dev_name);
|
||||
if(sm->serial) ADD2LOG("serial: \"%s\"\n", sm->serial);
|
||||
if(sm->class_name) ADD2LOG("class_name: \"%s\"\n", sm->class_name);
|
||||
if(sm->dev_id) ADD2LOG("dev_id: \"%s\"\n", sm->dev_id);
|
||||
if(sm->user_name) ADD2LOG("user_name: \"%s\"\n", sm->user_name);
|
||||
|
||||
if(sm->garbage) {
|
||||
ADD2LOG(" garbage[%u]: ", sm->garbage);
|
||||
hd_log_hex(hd_data, 1, sm->garbage, sm->buf);
|
||||
ADD2LOG("\n");
|
||||
}
|
||||
|
||||
if(sm->non_pnp) {
|
||||
ADD2LOG(" non-pnp[%u]: ", sm->non_pnp);
|
||||
hd_log_hex(hd_data, 1, sm->non_pnp, sm->buf + sm->garbage);
|
||||
ADD2LOG("\n");
|
||||
}
|
||||
|
||||
if(sm->pnp) {
|
||||
ADD2LOG(" pnp[%u]: ", sm->pnp);
|
||||
hd_log_hex(hd_data, 1, sm->pnp, sm->buf + sm->garbage + sm->non_pnp);
|
||||
ADD2LOG("\n");
|
||||
}
|
||||
|
||||
if((j = sm->buf_len - (sm->garbage + sm->non_pnp + sm->pnp))) {
|
||||
ADD2LOG(" moves[%u]: ", j);
|
||||
hd_log_hex(hd_data, 1, j, sm->buf + sm->garbage + sm->non_pnp + sm->pnp);
|
||||
ADD2LOG("\n");
|
||||
}
|
||||
|
||||
if(sm->is_mouse) ADD2LOG(" is mouse\n");
|
||||
|
||||
if(sm->pnp) {
|
||||
ADD2LOG(" bits: %u\n", sm->bits);
|
||||
ADD2LOG(" PnP Rev: %u.%02u\n", sm->pnp_rev / 100, sm->pnp_rev % 100);
|
||||
ADD2LOG(" PnP ID: \"%s\"\n", sm->pnp_id);
|
||||
}
|
||||
|
||||
if(sm->next) ADD2LOG("\n");
|
||||
}
|
||||
|
||||
ADD2LOG("----- serial mice end -----\n");
|
||||
}
|
||||
|
||||
#endif /* !defined(LIBHD_TINY) */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_mouse(hd_data_t *hd_data);
|
|
@ -0,0 +1,804 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define u64 uint64_t
|
||||
#include <linux/if.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_arp.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "net.h"
|
||||
|
||||
/**
|
||||
* @defgroup NETint Network devices
|
||||
* @ingroup libhdDEVint
|
||||
* @brief Network device scan functions
|
||||
*
|
||||
* Gather network interface info
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
static void get_ethtool_priv(hd_data_t *hd_data, hd_t *hd);
|
||||
static void get_driverinfo(hd_data_t *hd_data, hd_t *hd);
|
||||
static void get_linkstate(hd_data_t *hd_data, hd_t *hd);
|
||||
static hd_res_t *get_phwaddr(hd_data_t *hd_data, hd_t *hd);
|
||||
static void add_xpnet(hd_data_t *hdata);
|
||||
static void add_uml(hd_data_t *hdata);
|
||||
static void add_kma(hd_data_t *hdata);
|
||||
static void add_if_name(hd_t *hd_card, hd_t *hd);
|
||||
|
||||
/*
|
||||
* This is independent of the other scans.
|
||||
*/
|
||||
|
||||
void hd_scan_net(hd_data_t *hd_data)
|
||||
{
|
||||
unsigned u;
|
||||
int if_type, if_carrier;
|
||||
hd_t *hd, *hd_card;
|
||||
char *s, *t, *hw_addr;
|
||||
hd_res_t *res, *res_hw, *res_phw, *res_lnk;
|
||||
uint64_t ul0;
|
||||
str_list_t *sf_class, *sf_class_e;
|
||||
char *sf_cdev = NULL, *sf_dev = NULL;
|
||||
char *sf_drv_name, *sf_drv;
|
||||
|
||||
if(!hd_probe_feature(hd_data, pr_net)) return;
|
||||
|
||||
hd_data->module = mod_net;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
hd_data->net = free_str_list(hd_data->net);
|
||||
|
||||
PROGRESS(1, 0, "get network data");
|
||||
|
||||
sf_class = read_dir("/sys/class/net", 'l');
|
||||
if(!sf_class) sf_class = read_dir("/sys/class/net", 'd');
|
||||
|
||||
if(!sf_class) {
|
||||
ADD2LOG("sysfs: no such class: net\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for(sf_class_e = sf_class; sf_class_e; sf_class_e = sf_class_e->next) {
|
||||
str_printf(&sf_cdev, 0, "/sys/class/net/%s", sf_class_e->str);
|
||||
|
||||
hd_card = NULL;
|
||||
|
||||
ADD2LOG(
|
||||
" net interface: name = %s, path = %s\n",
|
||||
sf_class_e->str,
|
||||
hd_sysfs_id(sf_cdev)
|
||||
);
|
||||
|
||||
if_type = -1;
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_cdev, "type"), &ul0, 0)) {
|
||||
if_type = ul0;
|
||||
ADD2LOG(" type = %d\n", if_type);
|
||||
}
|
||||
|
||||
if_carrier = -1;
|
||||
if(hd_attr_uint(get_sysfs_attr_by_path(sf_cdev, "carrier"), &ul0, 0)) {
|
||||
if_carrier = ul0;
|
||||
ADD2LOG(" carrier = %d\n", if_carrier);
|
||||
}
|
||||
|
||||
hw_addr = NULL;
|
||||
if((s = get_sysfs_attr_by_path(sf_cdev, "address"))) {
|
||||
hw_addr = canon_str(s, strlen(s));
|
||||
ADD2LOG(" hw_addr = %s\n", hw_addr);
|
||||
}
|
||||
|
||||
sf_dev = new_str(hd_read_sysfs_link(sf_cdev, "device"));
|
||||
if(sf_dev) {
|
||||
ADD2LOG(" net device: path = %s\n", hd_sysfs_id(sf_dev));
|
||||
}
|
||||
|
||||
sf_drv_name = NULL;
|
||||
sf_drv = hd_read_sysfs_link(sf_dev, "driver");
|
||||
if(sf_drv) {
|
||||
sf_drv_name = strrchr(sf_drv, '/');
|
||||
if(sf_drv_name) sf_drv_name++;
|
||||
ADD2LOG(
|
||||
" net driver: name = %s, path = %s\n",
|
||||
sf_drv_name,
|
||||
hd_sysfs_id(sf_drv)
|
||||
);
|
||||
}
|
||||
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_network_interface;
|
||||
hd->sub_class.id = sc_nif_other;
|
||||
|
||||
hd->unix_dev_name = new_str(sf_class_e->str);
|
||||
hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev));
|
||||
|
||||
res_hw = NULL;
|
||||
if(hw_addr && strspn(hw_addr, "0:") != strlen(hw_addr)) {
|
||||
res_hw = new_mem(sizeof *res_hw);
|
||||
res_hw->hwaddr.type = res_hwaddr;
|
||||
res_hw->hwaddr.addr = new_str(hw_addr);
|
||||
add_res_entry(&hd->res, res_hw);
|
||||
}
|
||||
|
||||
res_phw = get_phwaddr(hd_data, hd);
|
||||
|
||||
if(if_carrier >= 0) {
|
||||
res = new_mem(sizeof *res);
|
||||
res->link.type = res_link;
|
||||
res->link.state = if_carrier ? 1 : 0;
|
||||
add_res_entry(&hd->res, res);
|
||||
}
|
||||
|
||||
if(sf_drv_name) {
|
||||
add_str_list(&hd->drivers, sf_drv_name);
|
||||
}
|
||||
else if(hd->res) {
|
||||
get_driverinfo(hd_data, hd);
|
||||
}
|
||||
|
||||
get_ethtool_priv(hd_data, hd);
|
||||
|
||||
switch(if_type) {
|
||||
case ARPHRD_ETHER: /* eth */
|
||||
hd->sub_class.id = sc_nif_ethernet;
|
||||
break;
|
||||
case ARPHRD_LOOPBACK: /* lo */
|
||||
hd->sub_class.id = sc_nif_loopback;
|
||||
break;
|
||||
case ARPHRD_SIT: /* sit */
|
||||
hd->sub_class.id = sc_nif_sit;
|
||||
break;
|
||||
case ARPHRD_FDDI: /* fddi */
|
||||
hd->sub_class.id = sc_nif_fddi;
|
||||
break;
|
||||
case ARPHRD_IEEE802_TR: /* tr */
|
||||
hd->sub_class.id = sc_nif_tokenring;
|
||||
break;
|
||||
#if 0
|
||||
case ARPHRD_IEEE802: /* fc */
|
||||
hd->sub_class.id = sc_nif_fc;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
hd->sub_class.id = sc_nif_other;
|
||||
}
|
||||
|
||||
if(!strcmp(hd->unix_dev_name, "lo")) {
|
||||
hd->sub_class.id = sc_nif_loopback;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "eth%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_ethernet;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "tr%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_tokenring;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "fddi%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_fddi;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "ctc%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_ctc;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "iucv%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_iucv;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "hsi%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_hsi;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "qeth%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_qeth;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "escon%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_escon;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "myri%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_myrinet;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "sit%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_sit; /* ipv6 over ipv4 tunnel */
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "wlan%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_wlan;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "xp%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_xp;
|
||||
hd->slot = u;
|
||||
}
|
||||
else if(sscanf(hd->unix_dev_name, "usb%u", &u) == 1) {
|
||||
hd->sub_class.id = sc_nif_usb;
|
||||
hd->slot = u;
|
||||
}
|
||||
/* ##### add more interface names here */
|
||||
else {
|
||||
for(s = hd->unix_dev_name; *s; s++) if(isdigit(*s)) break;
|
||||
if(*s && (u = strtoul(s, &s, 10), !*s)) {
|
||||
hd->slot = u;
|
||||
}
|
||||
}
|
||||
|
||||
hd->bus.id = bus_none;
|
||||
|
||||
hd_card = NULL;
|
||||
|
||||
if(sf_dev) {
|
||||
s = new_str(hd_sysfs_id(sf_dev));
|
||||
|
||||
hd->sysfs_device_link = new_str(s);
|
||||
|
||||
hd_card = hd_find_sysfs_id(hd_data, s);
|
||||
|
||||
// try one above, if not found
|
||||
if(!hd_card) {
|
||||
t = strrchr(s, '/');
|
||||
if(t) {
|
||||
*t = 0;
|
||||
hd_card = hd_find_sysfs_id(hd_data, s);
|
||||
}
|
||||
}
|
||||
|
||||
/* if one card has several interfaces (as with PS3), check interface names, too */
|
||||
if(
|
||||
hd_card &&
|
||||
hd_card->unix_dev_name &&
|
||||
hd->unix_dev_name &&
|
||||
strcmp(hd->unix_dev_name, hd_card->unix_dev_name)
|
||||
) {
|
||||
hd_card = hd_find_sysfs_id_devname(hd_data, s, hd->unix_dev_name);
|
||||
}
|
||||
|
||||
s = free_mem(s);
|
||||
|
||||
if(hd_card) {
|
||||
hd->attached_to = hd_card->idx;
|
||||
|
||||
/* for cards with strange pci classes */
|
||||
hd_set_hw_class(hd_card, hw_network_ctrl);
|
||||
|
||||
/* add hw addr to network card */
|
||||
if(res_hw) {
|
||||
u = 0;
|
||||
for(res = hd_card->res; res; res = res->next) {
|
||||
if(
|
||||
res->any.type == res_hwaddr &&
|
||||
!strcmp(res->hwaddr.addr, res_hw->hwaddr.addr)
|
||||
) {
|
||||
u = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!u) {
|
||||
res = new_mem(sizeof *res);
|
||||
res->hwaddr.type = res_hwaddr;
|
||||
res->hwaddr.addr = new_str(res_hw->hwaddr.addr);
|
||||
add_res_entry(&hd_card->res, res);
|
||||
}
|
||||
}
|
||||
|
||||
/* add permanent hw addr to network card */
|
||||
if(res_phw) {
|
||||
u = 0;
|
||||
for(res = hd_card->res; res; res = res->next) {
|
||||
if(
|
||||
res->any.type == res_phwaddr &&
|
||||
!strcmp(res->hwaddr.addr, res_phw->hwaddr.addr)
|
||||
) {
|
||||
u = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!u) {
|
||||
res = new_mem(sizeof *res);
|
||||
res->hwaddr.type = res_phwaddr;
|
||||
res->hwaddr.addr = new_str(res_phw->hwaddr.addr);
|
||||
add_res_entry(&hd_card->res, res);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* add interface names...
|
||||
* but not wmasterX (bnc #441778)
|
||||
*/
|
||||
if(if_type != 801) add_if_name(hd_card, hd);
|
||||
}
|
||||
}
|
||||
|
||||
if(!hd_card && hw_addr) {
|
||||
/* try to find card based on hwaddr (for prom-based cards) */
|
||||
|
||||
for(hd_card = hd_data->hd; hd_card; hd_card = hd_card->next) {
|
||||
if(
|
||||
hd_card->base_class.id != bc_network ||
|
||||
hd_card->sub_class.id != 0
|
||||
) continue;
|
||||
for(res = hd_card->res; res; res = res->next) {
|
||||
if(
|
||||
res->any.type == res_hwaddr &&
|
||||
!strcmp(hw_addr, res->hwaddr.addr)
|
||||
) break;
|
||||
}
|
||||
if(res) {
|
||||
hd->attached_to = hd_card->idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hw_addr = free_mem(hw_addr);
|
||||
|
||||
/* fix card type */
|
||||
if(hd_card) {
|
||||
if(
|
||||
(hd_card->base_class.id == 0 && hd_card->sub_class.id == 0) ||
|
||||
(hd_card->base_class.id == bc_network && hd_card->sub_class.id == 0x80)
|
||||
) {
|
||||
switch(hd->sub_class.id) {
|
||||
case sc_nif_ethernet:
|
||||
hd_card->base_class.id = bc_network;
|
||||
hd_card->sub_class.id = 0;
|
||||
break;
|
||||
|
||||
case sc_nif_usb:
|
||||
hd_card->base_class.id = bc_network;
|
||||
hd_card->sub_class.id = 0x91;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sf_dev = free_mem(sf_dev);
|
||||
}
|
||||
|
||||
sf_cdev = free_mem(sf_cdev);
|
||||
sf_class = free_str_list(sf_class);
|
||||
|
||||
if(hd_is_sgi_altix(hd_data)) add_xpnet(hd_data);
|
||||
add_uml(hd_data);
|
||||
add_kma(hd_data);
|
||||
|
||||
/* add link status info & dump eeprom */
|
||||
for(hd = hd_data->hd ; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->module == hd_data->module &&
|
||||
hd->base_class.id == bc_network_interface
|
||||
) {
|
||||
char *buf = NULL;
|
||||
str_list_t *sl0, *sl;
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_net_eeprom) && hd->unix_dev_name) {
|
||||
PROGRESS(2, 0, "eeprom dump");
|
||||
|
||||
str_printf(&buf, 0, "|/usr/sbin/ethtool -e %s 2>/dev/null", hd->unix_dev_name);
|
||||
if((sl0 = read_file(buf, 0, 0))) {
|
||||
ADD2LOG("----- %s %s -----\n", hd->unix_dev_name, "EEPROM dump");
|
||||
for(sl = sl0; sl; sl = sl->next) {
|
||||
ADD2LOG("%s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- %s end -----\n", "EEPROM dump");
|
||||
free_str_list(sl0);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(res->any.type == res_link) break;
|
||||
}
|
||||
|
||||
if(!res) get_linkstate(hd_data, hd);
|
||||
|
||||
if(!(hd_card = hd_get_device_by_idx(hd_data, hd->attached_to))) continue;
|
||||
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(res->any.type == res_link) break;
|
||||
}
|
||||
|
||||
if(res) {
|
||||
for(res_lnk = hd_card->res; res_lnk; res_lnk = res_lnk->next) {
|
||||
if(res_lnk->any.type == res_link) break;
|
||||
}
|
||||
if(res && !res_lnk) {
|
||||
res_lnk = new_mem(sizeof *res_lnk);
|
||||
res_lnk->link.type = res_link;
|
||||
res_lnk->link.state = res->link.state;
|
||||
add_res_entry(&hd_card->res, res_lnk);
|
||||
}
|
||||
}
|
||||
|
||||
hd_card->is.fcoe_offload = hd->is.fcoe_offload;
|
||||
hd_card->is.iscsi_offload = hd->is.iscsi_offload;
|
||||
hd_card->is.storage_only = hd->is.storage_only;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get private flags via ethtool.
|
||||
*/
|
||||
void get_ethtool_priv(hd_data_t *hd_data, hd_t *hd)
|
||||
{
|
||||
int fd, err = 0;
|
||||
unsigned u, len = 0;
|
||||
struct ifreq ifr = {};
|
||||
struct {
|
||||
struct ethtool_sset_info hdr;
|
||||
uint32_t buf[1];
|
||||
} sset_info = { hdr:{ cmd:ETHTOOL_GSSET_INFO, sset_mask:1ULL << ETH_SS_PRIV_FLAGS } };
|
||||
struct ethtool_gstrings *strings = NULL;
|
||||
struct ethtool_value flags = { cmd:ETHTOOL_GPFLAGS };
|
||||
|
||||
if(!hd->unix_dev_name) return;
|
||||
|
||||
if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return;
|
||||
strcpy(ifr.ifr_name, hd->unix_dev_name);
|
||||
|
||||
if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return;
|
||||
|
||||
ifr.ifr_data = &sset_info;
|
||||
if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
|
||||
len = sset_info.hdr.sset_mask ? sset_info.hdr.data[0] : 0;
|
||||
ADD2LOG(" ethtool private flags: %u\n", len);
|
||||
}
|
||||
else {
|
||||
ADD2LOG(" GSSET_INFO ethtool error: %s\n", strerror(errno));
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if(len) strings = calloc(1, sizeof *strings + len * ETH_GSTRING_LEN);
|
||||
|
||||
if(!strings) err = 1;
|
||||
|
||||
if(!err) {
|
||||
strings->cmd = ETHTOOL_GSTRINGS;
|
||||
strings->string_set = ETH_SS_PRIV_FLAGS;
|
||||
strings->len = len;
|
||||
|
||||
ifr.ifr_data = strings;
|
||||
if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
|
||||
for(u = 0; u < len; u++) strings->data[(u + 1) * ETH_GSTRING_LEN - 1] = 0;
|
||||
}
|
||||
else {
|
||||
ADD2LOG(" GSTRINGS ethtool error: %s\n", strerror(errno));
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(len > 32) len = 32;
|
||||
|
||||
if(!err) {
|
||||
ifr.ifr_data = &flags;
|
||||
if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
|
||||
for(u = 0; u < len; u++) {
|
||||
char *key = strings->data + u * ETH_GSTRING_LEN;
|
||||
unsigned val = (flags.data >> u) & 1;
|
||||
ADD2LOG(" %s = %u\n", key, val);
|
||||
// add 1 to get tri-state flags: 0 = unset, 1 = false, 2 = true
|
||||
if(!strcmp(key, "FCoE offload support")) hd->is.fcoe_offload = val + 1;
|
||||
if(!strcmp(key, "iSCSI offload support")) hd->is.iscsi_offload = val + 1;
|
||||
if(!strcmp(key, "Storage only interface")) hd->is.storage_only = val + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ADD2LOG(" GPFLAGS ethtool error: %s\n", strerror(errno));
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(strings);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get it the classical way, for drivers that don't support sysfs (veth).
|
||||
*/
|
||||
void get_driverinfo(hd_data_t *hd_data, hd_t *hd)
|
||||
{
|
||||
int fd;
|
||||
struct ethtool_drvinfo drvinfo = { cmd:ETHTOOL_GDRVINFO };
|
||||
struct ifreq ifr;
|
||||
|
||||
if(!hd->unix_dev_name) return;
|
||||
|
||||
if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return;
|
||||
|
||||
if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return;
|
||||
|
||||
/* get driver info */
|
||||
memset(&ifr, 0, sizeof ifr);
|
||||
strcpy(ifr.ifr_name, hd->unix_dev_name);
|
||||
ifr.ifr_data = (caddr_t) &drvinfo;
|
||||
if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
|
||||
ADD2LOG(" ethtool driver: %s\n", drvinfo.driver);
|
||||
ADD2LOG(" ethtool bus: %s\n", drvinfo.bus_info);
|
||||
|
||||
add_str_list(&hd->drivers, drvinfo.driver);
|
||||
}
|
||||
else {
|
||||
ADD2LOG(" GDRVINFO ethtool error: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check network link status.
|
||||
*/
|
||||
void get_linkstate(hd_data_t *hd_data, hd_t *hd)
|
||||
{
|
||||
int fd;
|
||||
struct ethtool_value linkstatus = { cmd:ETHTOOL_GLINK };
|
||||
struct ifreq ifr;
|
||||
hd_res_t *res;
|
||||
|
||||
if(!hd->unix_dev_name) return;
|
||||
|
||||
if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return;
|
||||
|
||||
if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return;
|
||||
|
||||
/* get driver info */
|
||||
memset(&ifr, 0, sizeof ifr);
|
||||
strcpy(ifr.ifr_name, hd->unix_dev_name);
|
||||
ifr.ifr_data = (caddr_t) &linkstatus;
|
||||
if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
|
||||
ADD2LOG(" %s: ethtool link state: %d\n", hd->unix_dev_name, linkstatus.data);
|
||||
res = new_mem(sizeof *res);
|
||||
res->link.type = res_link;
|
||||
res->link.state = linkstatus.data ? 1 : 0;
|
||||
add_res_entry(&hd->res, res);
|
||||
}
|
||||
else {
|
||||
ADD2LOG(" %s: GLINK ethtool error: %s\n", hd->unix_dev_name, strerror(errno));
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get permanent hardware address (it's not in sysfs).
|
||||
*/
|
||||
hd_res_t *get_phwaddr(hd_data_t *hd_data, hd_t *hd)
|
||||
{
|
||||
int fd;
|
||||
struct ethtool_perm_addr *phwaddr = new_mem(sizeof (struct ethtool_perm_addr) + MAX_ADDR_LEN);
|
||||
struct ifreq ifr;
|
||||
hd_res_t *res = NULL;
|
||||
|
||||
phwaddr->cmd = ETHTOOL_GPERMADDR;
|
||||
phwaddr->size = MAX_ADDR_LEN;
|
||||
|
||||
if(!hd->unix_dev_name) return res;
|
||||
|
||||
if(strlen(hd->unix_dev_name) > sizeof ifr.ifr_name - 1) return res;
|
||||
|
||||
if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) return res;
|
||||
|
||||
/* get permanent hardware addr */
|
||||
memset(&ifr, 0, sizeof ifr);
|
||||
strcpy(ifr.ifr_name, hd->unix_dev_name);
|
||||
ifr.ifr_data = (caddr_t) phwaddr;
|
||||
if(ioctl(fd, SIOCETHTOOL, &ifr) == 0) {
|
||||
int i;
|
||||
char *addr = NULL;
|
||||
if(phwaddr->size > 0) {
|
||||
addr = new_mem(phwaddr->size * 3 + 1); // yes, we need an extra byte
|
||||
for(i = 0; i < phwaddr->size; i++) {
|
||||
sprintf(addr + 3 * i, "%02x:", phwaddr->data[i]);
|
||||
}
|
||||
addr[3 * i - 1] = 0;
|
||||
}
|
||||
|
||||
ADD2LOG(" %s: ethtool permanent hw address[%d]: %s\n", hd->unix_dev_name, phwaddr->size, addr);
|
||||
|
||||
if(addr && strspn(addr, "0:") != strlen(addr)) {
|
||||
res = new_mem(sizeof *res);
|
||||
res->hwaddr.type = res_phwaddr;
|
||||
res->hwaddr.addr = new_str(addr);
|
||||
add_res_entry(&hd->res, res);
|
||||
}
|
||||
|
||||
free_mem(addr);
|
||||
}
|
||||
else {
|
||||
ADD2LOG(" %s: GLINK ethtool error: %s\n", hd->unix_dev_name, strerror(errno));
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SGI Altix cross partition network.
|
||||
*/
|
||||
void add_xpnet(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd_card;
|
||||
hd_res_t *res, *res2;
|
||||
|
||||
hd_card = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd_card->base_class.id = bc_network;
|
||||
hd_card->sub_class.id = 0x83;
|
||||
|
||||
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x4002);
|
||||
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 1);
|
||||
|
||||
if(hd_module_is_active(hd_data, "xpnet")) {
|
||||
add_str_list(&hd_card->drivers, "xpnet");
|
||||
}
|
||||
|
||||
for(hd = hd_data->hd ; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->module == hd_data->module &&
|
||||
hd->base_class.id == bc_network_interface &&
|
||||
hd->sub_class.id == sc_nif_xp
|
||||
) {
|
||||
hd->attached_to = hd_card->idx;
|
||||
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(res->any.type == res_hwaddr) break;
|
||||
}
|
||||
|
||||
if(res) {
|
||||
res2 = new_mem(sizeof *res2);
|
||||
res2->hwaddr.type = res_hwaddr;
|
||||
res2->hwaddr.addr = new_str(res->hwaddr.addr);
|
||||
add_res_entry(&hd_card->res, res2);
|
||||
}
|
||||
|
||||
add_if_name(hd_card, hd);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* UML veth devices.
|
||||
*/
|
||||
void add_uml(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd_card;
|
||||
hd_res_t *res, *res2;
|
||||
unsigned card_cnt = 0;
|
||||
|
||||
for(hd = hd_data->hd ; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->module == hd_data->module &&
|
||||
hd->base_class.id == bc_network_interface &&
|
||||
search_str_list(hd->drivers, "uml virtual ethernet")
|
||||
) {
|
||||
hd_card = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd_card->base_class.id = bc_network;
|
||||
hd_card->sub_class.id = 0x00;
|
||||
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6010); // UML
|
||||
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
|
||||
hd_card->slot = card_cnt++;
|
||||
str_printf(&hd_card->device.name, 0, "Virtual Ethernet card %d", hd_card->slot);
|
||||
|
||||
hd->attached_to = hd_card->idx;
|
||||
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(res->any.type == res_hwaddr) break;
|
||||
}
|
||||
|
||||
if(res) {
|
||||
res2 = new_mem(sizeof *res2);
|
||||
res2->hwaddr.type = res_hwaddr;
|
||||
res2->hwaddr.addr = new_str(res->hwaddr.addr);
|
||||
add_res_entry(&hd_card->res, res2);
|
||||
}
|
||||
|
||||
add_if_name(hd_card, hd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* KMA veth devices.
|
||||
*/
|
||||
void add_kma(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd_card;
|
||||
hd_res_t *res, *res2;
|
||||
unsigned card_cnt = 0;
|
||||
|
||||
for(hd = hd_data->hd ; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->module == hd_data->module &&
|
||||
hd->base_class.id == bc_network_interface &&
|
||||
search_str_list(hd->drivers, "kveth2")
|
||||
) {
|
||||
hd_card = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd_card->base_class.id = bc_network;
|
||||
hd_card->sub_class.id = 0x00;
|
||||
hd_card->vendor.id = MAKE_ID(TAG_SPECIAL, 0x6012); // VirtualIron
|
||||
hd_card->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
|
||||
hd_card->slot = card_cnt++;
|
||||
str_printf(&hd_card->device.name, 0, "Ethernet card %d", hd_card->slot);
|
||||
|
||||
hd->attached_to = hd_card->idx;
|
||||
|
||||
for(res = hd->res; res; res = res->next) {
|
||||
if(res->any.type == res_hwaddr) break;
|
||||
}
|
||||
|
||||
if(res) {
|
||||
res2 = new_mem(sizeof *res2);
|
||||
res2->hwaddr.type = res_hwaddr;
|
||||
res2->hwaddr.addr = new_str(res->hwaddr.addr);
|
||||
add_res_entry(&hd_card->res, res2);
|
||||
}
|
||||
|
||||
add_if_name(hd_card, hd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add interface name to card
|
||||
*/
|
||||
void add_if_name(hd_t *hd_card, hd_t *hd)
|
||||
{
|
||||
str_list_t *sl0;
|
||||
|
||||
if(hd->unix_dev_name) {
|
||||
if(!search_str_list(hd_card->unix_dev_names, hd->unix_dev_name)) {
|
||||
if(hd->sub_class.id == sc_nif_other) {
|
||||
/* add at end */
|
||||
add_str_list(&hd_card->unix_dev_names, hd->unix_dev_name);
|
||||
}
|
||||
else {
|
||||
/* add at top */
|
||||
sl0 = new_mem(sizeof *sl0);
|
||||
sl0->next = hd_card->unix_dev_names;
|
||||
sl0->str = new_str(hd->unix_dev_name);
|
||||
hd_card->unix_dev_names = sl0;
|
||||
}
|
||||
free_mem(hd_card->unix_dev_name);
|
||||
hd_card->unix_dev_name = new_str(hd_card->unix_dev_names->str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_net(hd_data_t *hd_data);
|
|
@ -0,0 +1,300 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "hd_int.h"
|
||||
#include "parallel.h"
|
||||
|
||||
/**
|
||||
* @defgroup PPORTint Parallel port devices
|
||||
* @ingroup libhdDEVint
|
||||
* @brief Parallel port device information
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef LIBHD_TINY
|
||||
|
||||
static void do_lp(hd_data_t *hd_data);
|
||||
static void do_zip(hd_data_t *hd_data);
|
||||
static void dump_parallel_data(hd_data_t *hd_data, str_list_t *sl);
|
||||
|
||||
void hd_scan_parallel(hd_data_t *hd_data)
|
||||
{
|
||||
if(!hd_probe_feature(hd_data, pr_parallel)) return;
|
||||
|
||||
hd_data->module = mod_parallel;
|
||||
|
||||
/* some clean-up */
|
||||
remove_hd_entries(hd_data);
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_parallel_lp)) do_lp(hd_data);
|
||||
|
||||
if(hd_probe_feature(hd_data, pr_parallel_zip)) do_zip(hd_data);
|
||||
}
|
||||
|
||||
void do_lp(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd_i;
|
||||
str_list_t *sl, *sl0;
|
||||
hd_res_t *res;
|
||||
char *pp = NULL, buf[256], unix_dev[] = "/dev/lp0", *s = NULL;
|
||||
char *base_class, *device, *vendor, *cmd_set;
|
||||
int i, j, port;
|
||||
str_list_t *log = NULL;
|
||||
|
||||
PROGRESS(1, 0, "pp mod");
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_comm && hd->sub_class.id == sc_com_par) break;
|
||||
}
|
||||
|
||||
/* ... if there seems to be a parallel interface, try to load it */
|
||||
if(hd || 1) { /* always load it */
|
||||
if(hd_data->kernel_version == KERNEL_22) {
|
||||
unload_module(hd_data, "parport_probe");
|
||||
probe_module(hd_data, "parport_probe");
|
||||
} else {
|
||||
unload_module(hd_data, "lp");
|
||||
unload_module(hd_data, "parport_pc");
|
||||
probe_module(hd_data, "parport_pc");
|
||||
probe_module(hd_data, "lp");
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < 3; i++, unix_dev[sizeof unix_dev - 2]++) {
|
||||
PROGRESS(2, 1 + i, "lp read info");
|
||||
|
||||
port = 0;
|
||||
// ##### read modes as well? (e.g: SPP,ECP,ECPEPP,ECPPS2)
|
||||
if(hd_data->kernel_version == KERNEL_22)
|
||||
str_printf(&pp, 0, PROC_PARPORT_22 "%d/hardware", i);
|
||||
else
|
||||
str_printf(&pp, 0, PROC_PARPORT_24 "%d/base-addr", i);
|
||||
sl0 = read_file(pp, 0, 0);
|
||||
if(!sl0) continue; /* file doesn't exist -> no parport entry */
|
||||
str_printf(&s, 0, "%s\n", pp);
|
||||
add_str_list(&log, s);
|
||||
for(sl = sl0; sl; sl = sl->next) {
|
||||
str_printf(&s, 0, " %s", sl->str);
|
||||
add_str_list(&log, s);
|
||||
if(hd_data->kernel_version == KERNEL_22) {
|
||||
if(sscanf(sl->str, "base: %i", &j) == 1) port = j;
|
||||
} else {
|
||||
if(sscanf(sl->str, "%i", &j) == 1) port = j;
|
||||
}
|
||||
}
|
||||
free_str_list(sl0);
|
||||
|
||||
if(hd_data->kernel_version == KERNEL_22)
|
||||
str_printf(&pp, 0, PROC_PARPORT_22 "%d/autoprobe", i);
|
||||
else
|
||||
str_printf(&pp, 0, PROC_PARPORT_24 "%d/autoprobe", i);
|
||||
sl0 = read_file(pp, 0, 0);
|
||||
str_printf(&s, 0, "%s\n", pp);
|
||||
add_str_list(&log, s);
|
||||
base_class = device = vendor = cmd_set = NULL;
|
||||
for(sl = sl0; sl; sl = sl->next) {
|
||||
str_printf(&s, 0, " %s", sl->str);
|
||||
add_str_list(&log, s);
|
||||
// fprintf(stderr, "str = \"%s\"\n", sl->str);
|
||||
if(sscanf(sl->str, "CLASS: %255[^\n;]", buf) == 1) base_class = new_str(buf);
|
||||
if(sscanf(sl->str, "MODEL: %255[^\n;]", buf) == 1) device = new_str(buf);
|
||||
if(sscanf(sl->str, "MANUFACTURER: %255[^\n;]", buf) == 1) vendor = new_str(buf);
|
||||
if(sscanf(sl->str, "COMMAND SET: %255[^\n;]", buf) == 1) cmd_set = new_str(buf);
|
||||
}
|
||||
free_str_list(sl0);
|
||||
|
||||
/* default to printer */
|
||||
if(!base_class && vendor && device) base_class = new_str("printer");
|
||||
|
||||
s = free_mem(s);
|
||||
|
||||
// fprintf(stderr, "port <0x%x\n", port);
|
||||
// fprintf(stderr, "class <%s>\n", base_class);
|
||||
// fprintf(stderr, "device <%s>\n", device);
|
||||
// fprintf(stderr, "vendor <%s>\n", vendor);
|
||||
// fprintf(stderr, "cmds <%s>\n", cmd_set);
|
||||
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_comm &&
|
||||
hd->sub_class.id == sc_com_par &&
|
||||
hd->unix_dev_name &&
|
||||
!strcmp(hd->unix_dev_name, unix_dev)
|
||||
) break;
|
||||
}
|
||||
|
||||
if(!hd) {
|
||||
/* no entry ??? */
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_comm;
|
||||
hd->sub_class.id = sc_com_par;
|
||||
hd->unix_dev_name = new_str(unix_dev);
|
||||
if(port) {
|
||||
res = add_res_entry(&hd->res, new_mem(sizeof *res));
|
||||
res->io.type = res_io;
|
||||
res->io.enabled = 1;
|
||||
res->io.base = port;
|
||||
res->io.access = acc_rw;
|
||||
}
|
||||
}
|
||||
|
||||
// ##### check if ports match?
|
||||
|
||||
if(
|
||||
base_class ||
|
||||
(device && strcmp(device, "Unknown device")) ||
|
||||
(vendor && strcmp(vendor, "Unknown vendor"))
|
||||
) {
|
||||
hd_i = hd;
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->attached_to = hd_i->idx;
|
||||
hd->unix_dev_name = new_str(hd_i->unix_dev_name);
|
||||
hd->base_class.id = bc_none;
|
||||
if(base_class && !strcasecmp(base_class, "printer")) hd->base_class.id = bc_printer;
|
||||
hd->bus.id = bus_parallel;
|
||||
|
||||
hd->vendor.name = new_str(vendor);
|
||||
hd->device.name = new_str(device);
|
||||
}
|
||||
|
||||
free_mem(base_class);
|
||||
free_mem(device);
|
||||
free_mem(vendor);
|
||||
free_mem(cmd_set);
|
||||
}
|
||||
|
||||
pp = free_mem(pp);
|
||||
|
||||
if((hd_data->debug & HD_DEB_PARALLEL)) dump_parallel_data(hd_data, log);
|
||||
|
||||
free_str_list(log);
|
||||
|
||||
}
|
||||
|
||||
void do_zip(hd_data_t *hd_data)
|
||||
{
|
||||
hd_t *hd, *hd_i;
|
||||
int i, j, port, is_imm, is_ppa, is_imm0, is_ppa0;
|
||||
char *pp = NULL, *s = NULL, *unix_dev = NULL;
|
||||
str_list_t *log = NULL, *sl, *sl0;
|
||||
int do_imm = hd_probe_feature(hd_data, pr_parallel_imm);
|
||||
|
||||
is_imm = is_imm0 = hd_module_is_active(hd_data, "imm");
|
||||
is_ppa = is_ppa0 = hd_module_is_active(hd_data, "ppa");
|
||||
|
||||
if(!(is_imm || is_ppa)) {
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(hd->base_class.id == bc_comm && hd->sub_class.id == sc_com_par) break;
|
||||
}
|
||||
/* ... if there seems to be a parallel interface, try to load it */
|
||||
if(hd) {
|
||||
if(do_imm) {
|
||||
PROGRESS(5, 0, "imm mod");
|
||||
load_module(hd_data, "imm");
|
||||
}
|
||||
PROGRESS(5, 0, "ppa mod");
|
||||
load_module(hd_data, "ppa");
|
||||
is_imm = hd_module_is_active(hd_data, "imm");
|
||||
is_ppa = hd_module_is_active(hd_data, "ppa");
|
||||
if(do_imm && !is_imm) {
|
||||
int fd;
|
||||
char flush[2] = { 4, 12 };
|
||||
|
||||
fd = open("/dev/lp0", O_NONBLOCK | O_WRONLY);
|
||||
if(fd != -1) {
|
||||
write(fd, flush, sizeof flush);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!(is_imm || is_ppa)) return;
|
||||
|
||||
PROGRESS(6, 0, "zip read info");
|
||||
|
||||
for(i = 0; i < 16; i++) {
|
||||
str_printf(&pp, 0, PROC_SCSI "/%s/%d", (i % 2) ? "ppa" : "imm", i / 2);
|
||||
sl0 = read_file(pp, 0, 0);
|
||||
if(!sl0) continue;
|
||||
str_printf(&s, 0, "%s\n", pp);
|
||||
add_str_list(&log, s);
|
||||
port = -1;
|
||||
for(sl = sl0; sl; sl = sl->next) {
|
||||
str_printf(&s, 0, " %s", sl->str);
|
||||
add_str_list(&log, s);
|
||||
if(sscanf(sl->str, "Parport : parport%d", &j) == 1) port = j;
|
||||
}
|
||||
free_str_list(sl0);
|
||||
pp = free_mem(pp);
|
||||
s = free_mem(s);
|
||||
|
||||
unix_dev = free_mem(unix_dev);
|
||||
if(port >= 0) {
|
||||
str_printf(&unix_dev, 0, "/dev/lp%d", port);
|
||||
}
|
||||
|
||||
hd = NULL;
|
||||
if(unix_dev) {
|
||||
for(hd = hd_data->hd; hd; hd = hd->next) {
|
||||
if(
|
||||
hd->base_class.id == bc_comm &&
|
||||
hd->sub_class.id == sc_com_par &&
|
||||
hd->unix_dev_name &&
|
||||
!strcmp(hd->unix_dev_name, unix_dev)
|
||||
) break;
|
||||
}
|
||||
|
||||
if(!hd) {
|
||||
/* no entry ??? */
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
hd->base_class.id = bc_comm;
|
||||
hd->sub_class.id = sc_com_par;
|
||||
hd->unix_dev_name = new_str(unix_dev);
|
||||
}
|
||||
}
|
||||
|
||||
hd_i = hd;
|
||||
hd = add_hd_entry(hd_data, __LINE__, 0);
|
||||
if(hd_i) {
|
||||
hd->attached_to = hd_i->idx;
|
||||
hd->unix_dev_name = new_str(hd_i->unix_dev_name);
|
||||
}
|
||||
hd->base_class.id = bc_storage;
|
||||
hd->sub_class.id = sc_sto_scsi;
|
||||
hd->bus.id = bus_parallel;
|
||||
hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x1800);
|
||||
hd->device.id = MAKE_ID(TAG_SPECIAL, (i % 2) ? 2 : 1);
|
||||
}
|
||||
|
||||
if(!is_imm0) unload_module(hd_data, "imm");
|
||||
if(!is_ppa0) unload_module(hd_data, "ppa");
|
||||
|
||||
if((hd_data->debug & HD_DEB_PARALLEL)) dump_parallel_data(hd_data, log);
|
||||
|
||||
free_mem(unix_dev);
|
||||
|
||||
free_str_list(log);
|
||||
|
||||
}
|
||||
|
||||
void dump_parallel_data(hd_data_t *hd_data, str_list_t *sl)
|
||||
{
|
||||
ADD2LOG("----- parallel info -----\n");
|
||||
for(; sl; sl = sl->next) {
|
||||
ADD2LOG("%s", sl->str);
|
||||
}
|
||||
ADD2LOG("----- parallel info end -----\n");
|
||||
}
|
||||
|
||||
#endif /* ifndef LIBHD_TINY */
|
||||
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1 @@
|
|||
void hd_scan_parallel(hd_data_t *hd_data);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue