Compare commits

..
Author SHA1 Message Date
Vladimir Serbinenko 125f436763 Import from bzr to git 2013-10-22 20:12:42 +02:00
Colin Watson 3af093a503 * configure.ac: Build stage2 with -fno-reorder-functions to prevent
unlikely-to-be-executed functions being reordered before _start with
GCC 4.6.
Fixes Ubuntu bug #837815.
2011-09-26 10:15:32 +01:00
Robert Millan 9a43953b56 2010-01-25 Robert Millan <rmh.grub@aybabtu.com>
* stage2/imgact_aout.h: Rewrite using aout.h from GRUB 1.97.2 as
	a base.
	* stage2/boot.c (load_image): Remove a.out handler for *BSD kernels.
2010-01-25 19:13:33 +00:00
Robert Millan 8dbf5c8999 2010-01-21 Robert Millan <rmh.grub@aybabtu.com>
* configure.ac: Remove `--enable-example-kernel' option.
	* docs/Makefile.am
	* docs/grub.texi: Remove referenced to `mbchk'.
	
	* docs/boot.S: Remove.  Update all users.
	* docs/boot.S.texi: Likewise.
	* docs/kernel.c: Likewise.
	* docs/kernel.c.texi: Likewise.
	* docs/mbchk.1: Likewise.
	* docs/multiboot.h: Likewise.
	* docs/multiboot.h.texi: Likewise.
	* docs/multiboot.texi: Likewise.
	* util/mbchk.c: Likewise.
2010-01-21 17:17:59 +00:00
Robert Millan e8b13ced38 2010-01-21 Robert Millan <rmh@aybabtu.com>
* autogen.sh: New file.
	
	* INSTALL: Remove from version control.
	* Makefile.in: Likewise.
	* aclocal.m4: Likewise.
	* config.guess: Likewise.
	* config.sub: Likewise.
	* configure: Likewise.
	* depcomp: Likewise.
	* docs/Makefile.in: Likewise.
	* docs/mdate-sh: Likewise.
	* docs/texinfo.tex: Likewise.
	* grub/Makefile.in: Likewise.
	* install-sh: Likewise.
	* lib/Makefile.in: Likewise.
	* missing: Likewise.
	* mkinstalldirs: Likewise.
	* netboot/Makefile.in: Likewise.
	* stage1/Makefile.in: Likewise.
	* stage2/Makefile.in: Likewise.
	* util/Makefile.in: Likewise.
2010-01-21 16:56:22 +00:00
Robert Millan f557cee7dc 2010-01-21 Robert Millan <rmh@aybabtu.com>
* configure.ac: Add AM_PROG_AS (to fix automake generation).
2010-01-21 16:50:52 +00:00
Colin Watson 53f9ac3175 2009-12-07 Richard Hartmann <richih.mailinglist@gmail.com>
* stage2/builtins.c (builtin_halt): Fix typo.
	(builtin_password): Likewise.
2009-12-07 12:39:54 +00:00
181 changed files with 82484 additions and 3296 deletions

No files matched your search

-30
View File
@@ -1,30 +0,0 @@
gendocs.sh
lib
m4
.deps
Makefile
autom4te.cache
config.cache
config.h
config.log
config.status
stamp-h
stamp-h1
doc/Makefile
doc/*.info*
doc/.deps
doc/gendocs_template
doc/mdate-sh
doc/Makefile.in
doc/boot.S.texi
doc/kernel
doc/kernel.c.texi
doc/multiboot.h.texi
doc/texinfo.tex
Makefile.in
aclocal.m4
config.h.in
configure
depcomp
install-sh
missing
+9
View File
@@ -0,0 +1,9 @@
.deps
Makefile
autom4te.cache
config.cache
config.h
config.log
config.status
stamp-h
stamp-h1
+47 -6
View File
@@ -1,13 +1,54 @@
VaX#n8 (real name unknown) wrote shared_src/fsys_ext2fs.c.
Bryan Ford and Erich Stefan Boleyn wrote the initial version of the Multiboot
specification.
Heiko Schroeder rewrote shared_src/stage1.S to be more readable.
The following authors assigned copyright on their work to the Free
Software Foundation:
In year 1999, Kunihiro Ishiguro provided the first version that would be
imported into GNU GRUB.
Erich Stefan Boleyn originally designed and implemented GRUB.
Yoshinori K. Okuji maintained it during the 1999-2006 period.
Gordon Matzigkeit adopted GRUB into the GNU Project. He fixed several
bugs, added symbolic link support to shared_src/fsys_ext2fs.c, and
began the implementation of /sbin/grub. He was an official maintainer.
In year 2000, Per Lundberg added graphics support.
Yoshinori K. Okuji contributed many bugfixes and new features, such as
working LBA support, /sbin/grub support for configuration files, the
script /sbin/grub-install, the utility /bin/mbchk, the new engine for
builtin commands, disk swapping support, keyboard configuration support,
network support, online help support, command-line history support,
hidden menu support, the new Linux loader, serial terminal support,
single-line editing support, the utility /sbin/grub-md5-crypt, the new
GRUB manual, and several new commands. He is the current official
maintainer.
Peter Astrand added support for a color menu.
Pavel Roskin contributed many bugfixes and new features, such as FreeBSD
support for the grub shell, and configure process cleanups.
Klaus Reichl wrote stage2/fsys_minix.c.
Per Lundberg added graphics support to the Multiboot Specification.
Jochen Hoenicke rewrote stage2/fsys_fat.c and wrote
stage2/fsys_reiserfs.c and stage2/md5.c.
Christoph Plattner added support for Net Boot Image Proposal.
Frank Mehnert added support for hercules console.
Kristoffer Branemyr added VSTa filesystem support.
Serguei Tzukanov added JFS and XFS support.
Jason Thomas added Linux DAC960 support and support for hiding/unhiding
logical partitions, and did a significant bugfix for the terminal stuff.
Tilmann Bubeck added support for vt100-incompatible terminals.
KB Sriram added a better detection of FAT filesystem and fixed a
network device completion.
Eric Kvaalen fixed a lot of problems in the GRUB manual.
Leonid Lisovskiy added El Torito support.
+7
View File
@@ -0,0 +1,7 @@
See the Bug Tracking System for GNU GRUB on Savannah. The URL is:
http://savannah.gnu.org/bugs/?group_id=68 (without SSL)
or
https://savannah.gnu.org/bugs/?group_id=68 (with SSL)
+272 -606
View File
@@ -1,625 +1,284 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Version 2, June 1991
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
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
them 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.
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 prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
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 pass on to the recipients the same
freedoms that you received. 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.
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.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
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.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
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.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
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.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey 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;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
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.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
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.
13. Use with the GNU Affero General Public License.
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.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
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.
14. Revised Versions of this License.
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.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
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 that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
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.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
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.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
NO WARRANTY
15. Disclaimer of 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.
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.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
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.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
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
@@ -628,15 +287,15 @@ 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
state the exclusion of warranty; and each file should have at least
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
Copyright (C) 19yy <name of author>
This program is free software: you can redistribute it and/or modify
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 3 of the License, or
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,
@@ -645,30 +304,37 @@ the "copyright" line and a pointer to where the full notice is found.
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, see <http://www.gnu.org/licenses/>.
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
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, your program's commands
might be different; for a GUI interface, you would use an "about box".
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 school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
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:
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
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.
+9028 -255
View File
File diff suppressed because it is too large. Load diff
+60
View File
@@ -0,0 +1,60 @@
-*- text -*-
This is a list of random notes for GRUB maintainers. If you are not a
maintainer, you need to ask maintainers to do these instead of doing
these yourself.
How to update the online manual: (FIXME: this is obsoelete)
1. Copy docs/*.texi (excluding "multiboot.texi") to fencepost.gnu.org.
2. Make a symbolic link from ~mohit/gnudoc/gnudoc_template to the
directory under which *.texi were copied, if the link isn't present.
3. Run ``~mohit/gnudoc/gendocs.sh grub "GNU GRUB Manual"''.
4. Copy the contents of the directory ``manual'' to
gnudist.gnu.org:~ftp/gnu/Manuals/grub-VERSION (VERSION is, for
example, 1.0).
5. Run ``ln -sf grub-VERSION grub'' in gnudist.gnu.org:~ftp/gnu/Manuals.
6. Run ``cd grub; ln -s grub.html index.html''.
7. Verify the new online manual with a WWW browser.
8. Update manual.html by hand.
How to release a version:
1. Check out the source tree from the CVS from scratch.
2. Check if ``make distcheck'' succeeds.
3. Run ``util/grub-image''.
4. Check the resulted images, for example, using bochs.
5. Copy grub-VERSION.tar.gz, grub-VERSION-i386-pc.tar.gz and
grub-VERSION-i386-pc.ext2fs to fencepost.gnu.org:~ftp/gnu/grub.
6. Move older files in that directory above to the directory ``old'',
if you think they are eyesores.
7. Post an announcement to bug-grub@gnu.org. It would be a good idea to
send a carbon copy to bug-hurd@gnu.org and
debian-hurd@lists.debian.org. If the announcement is for a stable
version, you can inform info-gnu@gnu.org as well.
8. Optionally, post an announcement to Freshmeat.net.
Legal issues:
1. If a patch is not significant (in size), you don't have to care about
the copyright.
2. If a patch is significant, you shouldn't apply the patch to the CVS.
Before doing that, you must ask the contributor to assign or disclaim
the copyright. Send ``/gd/gnuorg/request-assign.changes'' or
``/gd/gnuorg/request-assign.future'' to the contributor, and wait
until the FSF finishes the legal work.
3. You can check if a contributor has already assigned his/her copyright
to the FSF by looking at ``/gd/gnuorg/copyright.list''.
What you should have in your mind:
1. Don't add features unnecessarily! You may think it is a Good Thing to
have more features, but you must be prepared for more burdens.
DO THAT ONLY IF YOU BELIEVE THAT THE FEATURE IS ESSENTIAL.
2. Don't break backward-compatibility! Don't apply any patch which could
break existing features. Otherwise you would receive a lot of
complaints. DO THAT ONLY IF YOU BELIEVE THAT THE INCOMPATIBILITY IS
INEVITABLE.
3. Write good code. Be not satisfied with ad hoc workarounds or quick
hacks. NEVER WRITE BAD CODE.
Resources:
* http://www.gnu.org/prep/maintain_toc.html
* http://www.gnu.org/prep/standards_toc.html
* http://www.gnu.org/server/fsf-html-style-sheet.html
+2 -9
View File
@@ -1,11 +1,4 @@
# Do not change this order if you don't know what you are doing.
AUTOMAKE_OPTIONS = 1.7 gnu
SUBDIRS = doc util
.PHONY: web-manual
web-manual: all
@cd '$(srcdir)/doc' ; \
$(SHELL) ../gendocs.sh -o '$(abs_builddir)/doc/manual' \
--email $(PACKAGE_BUGREPORT) $(PACKAGE) \
"$(PACKAGE_NAME) - $(manual_title)"
@echo " *** Upload the doc/manual directory to web-cvs."
SUBDIRS = netboot stage2 stage1 lib grub util docs
EXTRA_DIST = BUGS MAINTENANCE
+558
View File
@@ -0,0 +1,558 @@
NEWS - list of user-visible changes between releases of GRUB
New in 0.97 - 2005-05-08:
* Fix the prototypes and the definitions of nested functions. This was
required for gcc-4.
* Implement a more robust workaround for buggy BIOSes which don't pass
boot drive correctly (notably for HP Vectra).
New in 0.96 - 2005-01-30:
* The command "fallback" supports mutiple fallback entries.
* The command "savedefault" supports an optional argument which
is the number of next boot entry or the special keyword `fallback'.
* New utility "grub-set-default".
* New section "Making your system robust" in the manual.
New in 0.95 - 2004-06-13:
* Add support for ReiserFS 3.
* Fix support for FreeBSD 5.
* Support ATARAID for Linux in the grub shell and grub-install.
* Add CDROM support for El Torito with no emulation mode. You can use
(cd) as a CDROM drive in the config file.
* Option --no-mem-option is implied for Linux 2.4.18 and newer.
* Add support for UFS2.
New in 0.94 - 2004-01-25:
* Support building on x86-64 with gcc -m32.
* Use a BIOS call to turn on/off Gate A20. This should solve various
problems related to Gate A20 in modern BIOSes.
* Add a workaround for buggy BIOSes (notably HP Vectra series) which
don't pass the boot drive correctly.
* Display "GNU GRUB" instead of "GRUB" in the menu.
* Add support for QNX RTP into the grub shell.
* Add support for the initrd max address of a kernel header in Linux.
* Support 32 bit and 64 bit dev_t.
* Add support for an install device in GRUB's notation with no
parenthesis (e.g. grub-install hd0).
* Improve the manual a lot.
New in 0.93 - 2002-12-08:
* Define the behavior of the boot loader when the load end address is
zero and the bss end address is zero in the Multiboot Specification.
Also, add the support into GRUB.
* Finally, we have a Bug Tracking System! Now the preferable way to
report bugs is to use the BTS rather than sending e-mail to bug-grub.
See <http://bugcomm.enbug.org/?project=grub&mode=project>, for more
details.
* The appendix "FAQ" in the manual is removed. See the GNU GRUB FAQ on
the web <http://www.gnu.org/software/grub/grub-faq.html> instead.
* The terminal handling code is rewritten radically, and many bugfixes
are made at the same time.
* The command "color" is effective even in the command-line.
* The command "terminal" takes two new options, ``--no-echo'' and
``--no-edit''. If you specify ``--no-echo'', GRUB won't echo back
input characters. If you specify ``--no-edit'', GRUB will disable the
BASH-like editing feature. These options are useful when using an
intelligent terminal (such as the comint mode in GNU Emacs).
* The utility ``grub-md5-crypt'' prompts to retype a password and checks
if the passwords match.
* Support for booting Linux is rewritten, so GRUB now supports
large-EBDA systems.
* The menu interfaces supports Page Up, Page Down, and Right Key.
* New command "terminfo", for vt100-incompatible terminals.
* New options, ``-D'', ``-g'' and ``-m'' are supported for FreeBSD.
New in 0.92 - 2002-04-30:
* The command "displaymem" uses only hex digits for consistency.
* The netboot code goes back to the progress bars instead of dots, for
the notation of data transfers. And, that is displayed only in debug
mode, that is to say, nothing is displayed by default. Remember that
you can turn on debug mode via the command "debug".
* The command "help" doesn't show all the available commands by default,
when no argument is specified. Rarely used commands (such as
"testload") and useless commands in interactive use (such as
"savedefault") are hidden. If you want to see help messages for those
commands, specify the new option "--all".
* A built-in, `more'-like pager is added. When a command prints too many
lines to fit the screen, GRUB waits until you hit return key. This
feature can be turned off by the new command "pager".
* The command "terminal" accepts a new option, "--lines=LINES". You can
set the maximum number of lines arbitrarily with this option. If you
don't specify it, the maximum number will be 24.
* The command "terminal" accepts another new option, "--silent". You can
suppress the "Press any key to continue" message with this option.
* The mem= option for Linux is recognized and used to limit the maximum
address of initrd.
* A fallback entry is executed immediately after a default entry,
without prompting a user's intervention, as the manual has ever been
saying.
* The utility ``grub-install'' makes sure that GRUB images have been
written to a physical disk completely. To assist this feature, a new
command "dump" is added.
New in 0.91 - 2002-01-21:
* Support for Linux DAC960 is added.
* JFS and XFS support is added.
* The commands "hide" and "unhide" support logical partitions.
* The utility ``grub-install'' supports NetBSD.
* The network support is updated to Etherboot-5.0.5.
* The manner of handling the preset menu changes. In the previous
implementation, the preset menu is used only when opening the
configuration file failed. Now try to use the preset menu first. And,
if the configuration file is available, it is read after readoing the
preset menu. In this case, menu entries in the preset menu (if any)
are overrided by the configuration file.
* Diskless support is a bit changed. In the previous, GRUB set up a
network automatically via a special function. In the current, the
function is gone and the preset menu feature is used (i.e. just
execute the command "bootp" as if you specified it in the preset
menu). This has no impact against most users, but you should take care
if using the preset menu for your own purpose, because GRUB doesn't
call "bootp" implicitly when the preset menu is used explicitly. In
this case, you would probably need to insert commands to initialize a
network into your preset menu.
* Important bugfixes are made for ReiserFS, APM, TFTP, LBA, etc.
New in 0.90 - 2001-07-11:
* The command "setkey" resets key mappings, when no argument is
specified.
* Linux devfs support is added.
* The utility ``grub-install'' accepts a new option, `--recheck'. If
this option is specified, probe a device map, even if it already
exists. You should use this option whenever you add/remove a disk.
* The command "password" supports a md5 password if the option `--md5'
is given. This command can now also be used to protect specific menu
items with their own passwords.
* New command, "displayapm".
* New command, "md5crypt".
* The new utility ``grub-md5-crypt'' is a frontend of the grub shell. It
encrypts a password in MD5 format.
* New commands, "testvbe" and "vbeprobe".
* The configure script accepts a new option, `--enable-preset-menu'. You
can embed an arbitrary configuration which will be used when Stage 2
cannot open a real configuration file, with this option. The argument
must be an existing file.
* EZ-BIOS support is added.
* Booting Windows from a logical partition is supported.
* The example Multiboot kernel in the directory "docs" is built, if you
specify the option `--enable-example-kernel' to the configure script.
* New command, "ifconfig".
* Linux software RAID support is added (only for RAID-1).
* Hercules support is added.
* The configure script now accepts `--disable-auto-linux-mem-opt', which
has the same meaning as you specify the option `--no-mem-option' to the
command "kernel".
* Jump to the physical entry address of a Multiboot kernel when booting
it up. The old behavior was to use the virtual one, regardless of the
setting of the physical address.
* The commands "bootp" and "dhcp" accepts a new option
`--with-configfile', so that you can load a remotely specified
configuration file automatically, like the network boot images.
* VSTa filesystem support is added.
* ELF symbol loading support is added.
New in 0.5.96 - 2000-10-04:
* New commands, "reboot" and "halt".
* New command, "hiddenmenu". You can hide the menu interface by default
with this command.
* You can specify `--no-mem-option' to the command "kernel", if you want
GRUB not to pass a Linux's mem option automatically.
* Now GRUB is compliant with the Linux/i386 boot protocol version 2.02.
* The network support is updated to Etherboot-4.6.4.
* Symlinks in ReiserFS are supported.
* Add a workaround into the grub shell, so that it works fine even under
Linux 2.4.
* Add a new option `--stage2' into the commands "install" and "setup",
to let the grub shell know what the file name of Stage 2 is under your
operating system. You must specify the option correctly, if you cannot
unmount the partition where GRUB images reside. We'd recommend _not_
using those commands directly, but using the utility "grub-install"
instead, because this is safer.
* One violation against the Network Boot Image Proposal was found and
fixed. So now the image `nbgrub' can work fine even with a card such
as rtl8139.
* Serial terminal support is added. The configure script accepts
a new option `--disable-serial'. Unless it is specified, you can use
two new commands, "serial" and "terminal" in the command-line and the
menu. See the manual, for more details.
* Preserve the possible magic number used by Windows NT in a MBR.
* The command-line interface is switched to single-line editing mode.
* Only for developers: the configure script accepts
`--enable-serial-speed-simulation', which is useful when you want to
simulate the speed of a serial device on a psuedo terminal.
* Also only for developers: you can specify an optional argument to the
option `--hold' for the grub shell. The argument means how many
seconds the grub shell should wait until diving into the main routine.
* New command, "savedefault". Now you can save current entry number to
your disk with this command and then you can set the default boot
entry to it by the command "default saved".
* Add a new option `--prefix' into the command "setup", so that you can
specify the name of a directory which contains GRUB images. And, the
behavior of this command changed slightly, that is, this command now
searchs stage1 automatically under "/boot/grub" and "/grub", unless
you specify the option `--prefix'.
* The utility `grub-install' recognizes a separate boot partition
automatically.
* New commands, "partnew" and "parttype". You can modify partition
tables with these commands.
New in 0.5.95 - 2000-06-27:
* NetBSD ELF kernel support is added. You have to specify the new option
to the command "kernel". See below.
* Added a new option `--type=TYPE' into the command "kernel". This
option suggests what type of kernel you want to load. TYPE must be
either of "netbsd", "freebsd", "openbsd", "linux", "biglinux" and
"multiboot". Actually, this option will be necessary only if you want
to load a NetBSD ELF kernel, because GRUB can automatically determine
a kernel type in the other cases.
* ReiserFS support is added.
* Added a new option `--force-lba' into the command "install". This
option disables some sanity checks for LBA mode (but not all). If you
are sure that your machine supports LBA mode but GRUB doesn't work in
LBA mode, you should specify it. It is necessary if your BIOS is too
buggy. In the previous version, it was a compile-time option, but you
don't have to recompile GRUB any longer.
* Likewise, now the command "setup" and the script "grub-install" also
accept `--force-lba' option. Specifying this option to "setup" or
"grub-install" has the same effect as to the command "install".
* The configure script doesn't accept the option
`--disable-lba-support-bitmap-check' any longer. Use the option above.
* The network support is updated to Etherboot-4.6.1. So now we have
3Com59x and DEPCA drivers.
* Now you can omit the configuration file argument to the command
"password". If you omit it, then GRUB will just unlock privileged
instructions (such as `c') when you enter a correct password.
* The new command "lock" can be used to prevent end-users from executing
arbitrary menu entries. This command will emit an error until the user
enters a correct password.
* Recognize the Linux extended partition type.
* Pass a correct memory size to Linux and *BSD.
* Diskless support is added. Now configure accepts --enable-diskless,
and "make" will produce two additional images, ``nbgrub'' for Net Boot
Image Proposal and ``pxegrub'' for Preboot Execution Environment. See
the documentation, for more details.
* The command "tftpserver" overrides a TFTP server address returned by a
BOOTP server, a DHCP server or a RARP server.
* Fix a serious bug about LBA support. It is possible that you don't
disable the LBA support bitmap check any longer. Please send a report,
if you must still disable it. We need to know if we should get rid of
the option.
New in 0.5.94 - 2000-03-06:
* Stage 1 supports both the LBA mode and the CHS mode.
* The NetBSD and OpenBSD boot bug is fixed.
* The more automatic installation command "setup" is added.
* The command "embed" embeds a Stage 1.5 in the sectors after a MBR.
* Support symbolic color name syntax in the command "color".
* The grub shell loads the BIOS drive mapping information from a device
map file if it is specified and can be opened. If not found, try to
create it based on the guessed information.
* NetBSD support in the grub shell is improved.
* A simple checker for the format of a Multiboot kernel, ``mbchk'', is
added.
* The command "find" searches for a filename in all devices and print
the list of the devices which contain the file.
* The command "map" maps a drive to another drive so that we can
chain-load some foolish operating systems (such as DOS) even if such
an operating system resides at a non-first drive.
* The command "setkey" maps a key to another.
* The GRUB manual is rewritten, and now consists of three parts and
appendices.
* The command "ioprobe" detects what I/O ports are used for a BIOS
drive.
* OpenBSD support in the grub shell is improved.
* The command "install" can now patch a Stage 2 with a different
filename from "/boot/grub/menu.lst" even if a Stage 1.5 is used.
* New program, ``grub-install''.
* The command "blocklist" prints the blocklist notation of a file.
* The command "chainloader" now accepts an option "--force", which is
required if you want to chain-load a boot loader defective in the
signature, such as SCO Unixware 7.1.
* The netboot support is heavily rewritten, based on Etherboot-4.4.3.
Most of the device drivers are stolen from it, so we now have many
network drivers. See netboot/README.netboot for more details.
* Now configure accepts the option `--disable-lba-support-bitmap-check'
to ignore an incorrect LBA support bitmap returned by a buggy BIOS. If
you are sure that your BIOS does support LBA mode but GRUB doesn't
work in LBA mode, recompile GRUB with this option specified. You can
check if GRUB accesses a drive in LBA mode by the command "geometry".
* New commands "bootp", "dhcp" and "rarp" can be used to initialize a
network device and get IP addresses from a network.
* Long filename support in the FAT filesystem is added.
* The command "cmp" compares each bytes in two files.
New in 0.5.93 - 1999-10-30:
* ELF format of FreeBSD kernel is supported.
* Support the partition ids for NetBSD and OpenBSD.
* Exit from the grub shell just by pushing the key `q' in the menu.
* New options for configure can disable some functions in Stage 2. See
the output from `configure --help' for more information.
* FAT32 support is added.
* Minix fs support is added.
* New commands "hide" and "unhide".
* The character `=' after a command is not necessary any longer, but it
is supported for backward compatibility.
* The command "help" displays helpful information about builtin
commands.
* The command "geometry" displays the information of a drive specified
and set the geometry to arbitrary C/H/S values if the optional
arguments are used.
* The command "configfile" loads a configuration file interactively.
* The command "device" assigns a BIOS drive to an arbitrary filename in
the grub shell.
* The option `--no-floppy' force the grub shell to assume that there is
no floppy, and the option `--probe-second-floppy' enables the probe of
the second floppy drive.
* Integrated the netboot support in the Dresden version of GRUB.
* FreeBSD support in the grub shell is improved.
* Killing (C-u and C-k), yanking (C-y) and manipulating the history
(C-p and C-n) are supported.
* The address argument for the command "install" is now optional.
* Better completion support.
* The command "cat" displays the contents of a file.
New in 0.5.92 - 1999-07-26:
* Bug fixes (i.e. Stage 1.5 can work fine again).
* The /sbin/grub stage2 simulator now works at least on GNU/Linux, and
uses the Linux HDIO_GETGEO ioctl to determine hard disk geometry.
* TAB not only lists filenames, but also completes a filename when the
filename is unique.
* Password is not echoed back, put an asterisk for each of input
characters.
* stage2_debug is removed, and the debugging features are added into
stage2.
* Color menu support.
* New command "quit".
* The man page for /sbin/grub.
* All documents become Texinfo.
* Linux video mode selection is supported.
* The new Stage 1 `stage1_lba' supports LBA addressing mode.
New in 0.5.91 - 1999-03-14, Gordon Matzigkeit:
* LBA and preliminary AWARD BIOS disk extension support.
* Started docs/grub.texi.
* /sbin/grub GUI now works (but it doesn't yet access disks properly).
Run `configure --enable-sbin-grub' to build this program in the grub
subdirectory.
New in 0.5.90 - 1999-03-01, Gordon Matzigkeit:
* Bug fixes.
* GRUB understands symlinks on ext2fs (but still not ffs).
* Many source code and build cleanups to comply with GNU standards.
New in 0.5 - 1998-08-20, Erich Boleyn:
* Improved error messages in the stage1 to be strings (easier to read
than the previous case of single characters), and removed any
display in the case of no error (less confusing).
* New document describing error conditions and messages.
* Improved configure/build process.
* Made the early bootup interrupt-safe. Wasn't doing cli/sti when
necessary sometimes.
* GRUB now shuts off the floppy before transferring control to any
other programs/modules/loaders. (chain-loading doesn't matter here,
just loading 32-bit modules/kernels)
* Fixed a few stupid bugs, including a several in the ext2fs code.
* Linux boot format support extended from just "zImage" to include
"bzImage" and initial ramdisk (also called "initrd") support for
both. "initrd" support is untested, but the critical parts were
taken from a supplied patch and seem OK.
* Several new command features. See the command-listing for details.
New in 0.4 - 1998-03-19, Erich Boleyn:
* GRUB now correctly points ES:SI at a partition descriptor when
chain-loading.
* Many minor bugs fixed (some in the build scripts).
* Intel MPS 1.4 config/check code is totally new, and the "syscmd="
command is completely removed. Check command-listing for details.
Version 0.4-pre, Erich Boleyn:
* Reorganized docs, moved most "NOTE" items to a FAQ (with new entries
as well).
* Now supports automatic decompression of any files loaded via the
GRUB stage2 filesystem code. Simply compress the file using GNU
gzip normally, then when loading, the GRUB internals will see the
contents in the decompressed state... i.e. all GRUB functions
operate normally as if it is the uncompressed file. An extra
version of the "module" loading function has been added which
disables this functionality if desired (in all the other cases, not
decompressing doesn't make sense).
* Changed device strings used in filesystem code to more logical
format. Added "relative" disk and partition capability, see
command-listing and filesystem syntax description for details.
* "install=" command vastly improved. Also moved to non-debug area.
Check command-listing and install documentation for details.
* Added several new commands: "rootnoverify=", "uppermem=", and a new
debug command "displaymem". Check command-listing for details.
* Added versioning numbers (and subsequently broke compatibility with
some of the previous code, so GRUB should be re-installed!).
* Added unattended booting support via new "fallback=" command.
* During debug probe of SMP configuration table compatible with Intel
MPS 1.4 standard, GRUB now checks for a pointer in the EBDA.
* Using a "default=" entry greater than 11 caused the UI to do funny
things (it didn't pre-scroll the list to the appropriate place).
* Reading files on FAT floppies had yet more problems related by many
users of version 0.3 6/17/96. Again, all known problems fixed.
* "Extended" partitions now work (still cannot make an extended
partition active with "makeactive" command).
* The build environment is greatly simplified, now using an
autoconf-like "configure" script.
New in 0.3-19960617 - 1996-06-17, Erich Boleyn:
* Yet more documentation improvements.
* Known bugs in floppy operation fixed (12-bit FAT didn't work for
most cases, and inserting other floppies didn't flush the filesystem
cache).
* NASTY uninitialized pointer bug causing "raw" floppy operation to
crash on several PCs is now fixed. This seems to have been the root
cause of all of the compatibility problems that have currently been
observed.
* debug-mode command added to automate most difficult step of
installation for common cases (new install method #4).
* Testing "mini-debugger" now merged with command-line when "DEBUG"
defined in compile (no SYSDEBUG option anymore). See description of
commands in the command-line for details.
New in 0.3-19960602 - 1996-06-02, Erich Boleyn:
* Completed initial licenses.
* Initial filesystem documentation written.
* Block-list and FAT filesystems now work as documented (in
particular, for the blocklist filesystem, shortcuts like "+1" for
"0+1,512" now work correctly).
* Fixed several problems (old and new) in the various filesystems (for
example, the ext2fs filesystem code is now much faster, as it caches
some mapping blocks where it didn't at all before). Filesystem
semantics are much more uniform as well (symbolic links and reading
a directory as a file now return errors where it would silently fail
before).
* "makeactive" now works for standard PC partitions on hard disks (not
extended partitions... so any PC partition number above 3 will give
a "no such partition" error). If a BSD sub-partition is is used, it
will ignore it, and only use the primary PC partition number.
New in 0.3-19960520 - 1996-05-20, Erich Boleyn:
* Updated instructions (though still very sparse).
* New floppy probe (works much like the Linux floppy boot probe)
attempts to find the size of a floppy in a drive. Might still need
work! Please try on various floppy drives with various media!
* New floppy handler will claim a non-existent drive if the floppy
disk isn't present in the drive. (for example, it won't be on the
list of installed drives unless a floppy is present)
* Stage1 now compatible with both a hard disk MBR and the DOS BIOS
parameter block (see "install/README" for more details on how this
can be used).
* Block-list filesystem partially works, as described in the file
"NOTES". Loading an a.out or elf kernel won't work with it, but all
other filetypes pretty much should. (certainly chain-loading works
OK)
NOTE: you must use the full format "0+1,512" for just he first
block... no parameters can be implicit in this version.. THis is
being fixed too.
* Linux ext2 filesystem works. (it's very slow for big files, but
this is being fixed)
* Linux boot type now supported. Use a standard piggybacked image as
with LILO. Put in hack to support >64MB via GRUB placing the RAM
size as the first item on the command-line automatically. Must pass
root partition on command-line using normal Linux syntax... if not,
it uses it's builtin root partition.
* Supports chain-loading. For details, see "COMMANDS" and the
examples directory. (was able to boot DOS and Windows NT on my test
box). NOTE that the "root partition" must be set to work right.
"makeactive" is currently a no-op.
* Several weird bugs fixed. One important note: If you recompile, it
will warn about a clash with builtin "strcmp". This is normal...
do NOT remove the strcmp definition, as then GCC will possibly put
inline code from it's own builtin function in some places. (my
strcmp has slightly different functionality, hence the problem)
* Mini-debugger is currently broken.
New in 0.2 - 1996-04-12, Erich Boleyn:
* Completely new menu-based UI. See "COMMANDS" and the examples
directory for details. NOTE that the argument to a command must be
preceded by a space between it and the '=', in both the config file
and the command-line. This will be fixed.
New in 0.1 - 1996-03-31, Erich Boleyn:
* Newer version of Multiboot Standard (version 0.6) supported.
* Autodetects kernel types. Supports Multiboot, FreeBSD, NetBSD
(Linux isn't finished).
* Stage 1.5 works now. Default setup is now for working with a BSD
FFS floppy loading "/grub/stage2" as the main bootloader.
* Filesystem support improved. It didn't work on many floppies before
(problem with the partition-detection code).
* Memory probe now supports arbitrary amounts of RAM (some technical
limitations exist, see Multiboot standard version 0.6 for details).
* A mini-debugger is included by default, activated by hitting '~' on
the command-line (it might interfere with things, but it seems OK
for my alpha-testing). The commands are in the function
"enter_sysdebug" defined in "common.c". If you have an Intel MPS-
compatible machine, there are extra commands enabled for SMP cpu
testing. 'q' exits and goes back to what you were doing before.
New in 0.0-19960206 - 1996-02-06, Erich Boleyn:
* Newer version of Multiboot Standard (version 0.4) supported.
New in 0.0-19951210 - 1995-12-10, Erich Boleyn:
* You can now perform TAB-based completion listing of any valid
partially completed disk/partition/file-name combination. Try it
out to see what you like, examples are in the NOTES file under
"Device completion".
* Fixed a bug causing the memory size routine to sometimes report
ridiculous values.
* Fixed some documentation (what little there is :-/ and a few
assembly bugs in the BIOS access routines that nobody reported yet,
so I won't detail it here.
+23
View File
@@ -0,0 +1,23 @@
This is GNU GRUB, the GRand Unified Bootloader. GRUB is intended to
provide important bootloader features that are missing from typical
personal computer BIOSes:
- provides fully-featured command line and graphical interfaces
- recognizes fdisk partitions and BSD disklabels
- can dynamically read Linux ext2fs, ReiserFS, JFS and XFS, BSD ufs,
MS-DOS FAT16 and FAT32, Minix fs, and VSTa fs filesystems, plus
hardcoded blocklists
- can boot Multiboot-compliant kernels (such as GNU Mach), as well
as standard Linux and *BSD kernels
See the file NEWS for a description of recent changes to GRUB.
If you are interested in the network support, see the file
README.netboot under the directory netboot.
See the file INSTALL for instructions on how to build and install the
GRUB data and program files. See the GRUB manual for details about
using GRUB as your boot loader. Type "info grub" in the shell prompt.
Please visit the official web page of GNU GRUB, for more information.
The URL is <http://www.gnu.org/software/grub/grub.html>.
+124
View File
@@ -0,0 +1,124 @@
GRUB would not be what it is today without the invaluable help of
everybody who was kind enough to spend time testing it and reporting
bugs.
The following people made especially gracious contributions of their
time and energy in helping to track down bugs, add new features, and
generally assist in the GRUB maintainership process:
Adam Lackorzynski <adam@os.inf.tu-dresden.de>
Adrian Phillips <a.phillips@dnmi.no>
Alban Crequy <alban.crequy@apinc.org>
Alessandro Rubini <rubini@gnu.org>
Alexander K. Hudek <alexhudek@home.com>
Alexander Langer <alex@big.endian.de>
Alfred M. Szmidt <ams@kemisten.nu>
Andrew Clausen <clausen@gnu.org>
Andrew Walrond <andrew@walrond.org>
Ben Liblit <liblit@eecs.berkeley.edu>
Bernhard Treutwein <Bernhard.Treutwein@Verwaltung.Uni-Muenchen.DE>
Bodo Rueskamp <br@itchigo.com>.
Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>
Bradford Hovinen <hovinen@redrose.net>
Brian Brunswick <brian@skarpsey.demon.co.uk>
Bryan Ford <baford@cs.utah.edu>
Cedric Ware <ware@com.enst.fr>
Chip Salzenberg <chip@valinux.com>
Christian Jones <chjones@aleph0.com>
Christoph Plattner <Christoph.Plattner@dot.at>
Damian Ivereigh <damian@cisco.com>
David Weinehall <tao@debian.org>
Dan J. Walters <djw@cs.utexas.edu>
Daniel Farrell <s2108287@student.rmit.edu.au>
Daniel Pittman <daniel@rimspace.net>
Daniel Wagner <wagi@gmx.ch>
Danilo Godec <danci@agenda.si>
Dennis Kitzman <dennis-kitzman@uiowa.edu>
Derrik Pates <dpates@dsdk12.net>
Edmund GRIMLEY EVANS <edmundo@rano.demon.co.uk>
Eduard Guzovsky <eguzovsk@enterasys.com>
Edward Killips <ekillips@triton.net>
Egmont Koblinger <egmont@uhulinux.hu>
Eric Hanchrow <erich@microsoft.com>
Erik Schoenfelder <schoenfr@gaertner.de>
Eugene Doudine <dudin@np.nk.nornik.ru>
Florian Hatat <mininet@wanadoo.fr>
Frank Mehnert <fm3@os.inf.tu-dresden.de>
Gary Poppitz <gpoppitz@tachyon.net>
Goran Koruga <goran.koruga@hermes.si>
Hal Snyder <hal@vailsys.com>
HASEGAWA Tomoki <thasegawa@mta.biglobe.ne.jp>
Heikki Vatiainen <hessu@cs.tut.fi>
Heiko Schroeder <heiko@pool.informatik.rwth-aachen.de>
Henrik Nordstrom <hno@marasystems.com>
Herbert Nachtnebel <nachtneb@iaee.tuwien.ac.at>
Hidetoshi Nishimaki <nishimaki@mxs.nes.nec.co.jp>
Hisazumi Kenji <nel@soraneko.com>
HORIKAWA Kazunori <kaz-hori@tkd.att.ne.jp>
Ilguiz Latypov <ilatypov@superbt.com>
Jan Fricke <fricke@uni-greifswald.de>
Jan Zerebecki <jan.list@elite-pferde.de>
Jason Thomas <jason@topic.com.au>
Jean-Jacques Michel <jjmichel@linbox.com>
Jeremy Katz <katzj@redhat.com>
Jochen Hoenicke <jochen@gnu.org>
Johannes Kroeger <hanne@squirrel.owl.de>
John Goerzen <jgoerzen@complete.org>
John Tobey <spam@john-edwin-tobey.org>
Josip Rodin <joy@cibalia.gkvk.hr>
Julien Bordet <julien.bordet@int-evry.fr>
Julien Perrot <julien.perrot@iie.cnam.fr>
Kalle Olavi Niemitalo <tosi@ees2.oulu.fi>
Karsten Scheibler <karsten.scheibler@student.uni-halle.de>
KB Sriram <mail_kb@yahoo.com>
Khimenko Victor <grub@khim.sch57.msk.ru>
Klaus Reichl <klaus.reichl@alcatel.at>
Kristoffer Branemyr <ztion@swipnet.se>
Kunihiro Ishiguro <kunihiro@zebra.org>
Leendert Meyer <leen.meyer@home.nl>
Leonid Lisovskiy <lly@pisem.net>
M. Meiarashi <mes@st.rim.or.jp>
Mark Kettenis <kettenis@chello.nl>
Mark Lundeberg <aa026@pgfn.bc.ca>
Matt Perry <matt@primefactor.com>
Matt Yourst <yourst@mit.edu>
Matthias Granberry <matthias@slurpee.org>
Matthias Kretschmer <m.kretschmer@bsdger.org>
Michael Hohmuth <hohmuth@innocent.com>
Michael Sullivan <mike@trdlnk.com>
Mike Meyer <mwm@mired.org>
Miles Bader <miles@gnu.org>
NATORI Shin <natori@adm.s.u-tokyo.ac.jp>
Neal H Walfield <neal@walfield.org>
Neelkanth Natu <neelnatu@yahoo.com>
OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
Pavel Roskin <proski@gnu.org>
Per Lundberg <plundis@byggdok.se>
Peter Astrand <altic@lysator.liu.se>
Ralf Medow <ralf.medow@t-online.de>
Ramon van Handel <vhandel@chem.vu.nl>
Robert Millan <robertmh@gnu.org>
Roderich Schupp <rsch@ExperTeam.de>
Rogelio M. Serrano Jr. <rogelio@victorio.com>
Sergey Matveychuk <sem@ciam.ru>
Serguei Tzukanov <tzukanov@narod.ru>
Stefan Ondrejicka <ondrej@idata.sk>
Stephen Early <steve@greenend.org.uk>
Steven Dick <ssd.gnu@mmae.ucf.edu>
Sven Wegener <swegener@gentoo.org>
Takehiro Suzuki <takehiro@coral.ocn.ne.jp>
Taketo Kabe <kabe@sra-tohoku.co.jp>
Thierry DELHAISE <thierry.delhaise@delhaise.com>
Thierry Laronde <thierry.laronde@polynum.com>
Thomas Schweikle <tschweikle@fiducia.de>
Thomas Schwinge <kischde@gmx.net>
Tilmann Bubeck <t.bubeck@reinform.de>
Timothy Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
Torsten Duwe <duwe@caldera.de>
Uwe Dannowski <ud3@ira.uka.de>
VaX#n8 <vax@linkdead.paranoia.com>
Vesa Jaaskelainen <jaaskela@tietomyrsky.fi>
Yedidyah Bar-David <didi@post.tau.ac.il>
Yury V. Umanets <umka@namesys.com>
Yuri Zaporogets <yuriz@ukr.net>
Vitaly Fertman <vitaly@namesys.com>
+102
View File
@@ -0,0 +1,102 @@
-*- Mode: Outline -*-
Before working on anything in this file, it's very important that you
make contact with the core GRUB developers. Things herein might be
slightly out of date or otherwise not easy to understand at first
glance. So write to <bug-grub@gnu.org> first.
Priorities:
Reported bugs generally have top priority.
Non-reported and non-encountered bugs (things we know don't work,
but don't really impede things) have lower priority.
Things in this file are ranked with one to three !; the more, the
higher priority.
Things that should be done before 1.0:
* Finish the Multiboot Speicification 0.7. !!!
* Add more --disable-FOO options to configure, so that you can create a
minimum GRUB image. This is useful for boot floppies because of the size
restriction. !
* Implement a new version of track_int13, using Virtual 8086 Mode. !!!
* Add missing features of graphics support. !!
Things that should _not_ be done before 1.0:
* Add configuration inclusion support by adding a command "include". !
* Add automatic configuration support.
* Add bunzip2 support.
* Define the module system.
* Add BSD syntax support, using results of ioprobe to map drives. !
(0x1f0-0x1f7 = primary IDE, 0x170-0x176 = secondary,
0x1e8-0x1ef = tertiary, 0x168-0x16f = quaternary).
* Add a real scripting language, possibly retaining backward
compatibility so that old config files can be used.
* Add internationalization support, emulating gettext as much as is
feasible.
* Support other architectures than i386-pc.
* Add real memory management.
Things that may be done anytime:
* Port the script ``grub-install'' to OpenBSD. At least you will have to
modify the function `convert' so that it can translate a native device
name into the corresponding GRUB drive representation. !
* Add a command to run a GRUB script file. !!
* Add commands to manipulate the menu from the command-line interface. !
* Make symbolic links work for BSD FFS.
* Add indirect block support to the BSD FFS filesystem code, so files
larger than 16MB can be read.
* Fix-up FreeBSD, NetBSD (and OpenBSD ?) command-line boot
parameters.
* Support embedding a Stage 1.5 in the "bootloader" area of a FFS
partition. (We already have the code, but need an approval by an
expert before turning on the support. Any volunteers?)
* Support embedding a Stage 1.5 in the EXT2_BOOT_LOADER_INO of an ext2fs
partition, so that it won't be accidentally erased or modified by
the kernel.
* Add ISA PnP support.
* Add more filesystems support (NTFS, etc.)
* Add more remote console support (parallel and net).
* Add (real) RAID support.
? Add a partition naming syntax that means ``the first partition of
this type''. We need this for clean Hurd install floppies.
Nope. Improving the `find' command would solve this problem.
* Add CDROM-chainloading support. It would be enough to support only
BIOSes which have bootable-CDROM support (so you may use the "Bootable
CDROM" BIOS calls). It is not trivial to support BIOSes without the
capability to boot CDROM.
? Divide pxegrub into two parts, so the initial image doesn't exceed
the 32KB limit. I'm not sure if this is really necessary, because the
PXE standard just says that it is _recommended_ to improve the
modularity of a boot image. Obviously, this reason doesn't apply to
GRUB, as pxegrub is merely a secondary boot loader. So whether this
task should be done depends on if existing PXE ROMs support >32KB
images or not, after all.
+366
View File
@@ -0,0 +1,366 @@
dnl grub_ASM_USCORE checks if C symbols get an underscore after
dnl compiling to assembler.
dnl Written by Pavel Roskin. Based on grub_ASM_EXT_C written by
dnl Erich Boleyn and modified by OKUJI Yoshinori
AC_DEFUN([grub_ASM_USCORE],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if C symbols get an underscore after compilation])
AC_CACHE_VAL(grub_cv_asm_uscore,
[cat > conftest.c <<\EOF
int
func (int *list)
{
*list = 0;
return *list;
}
EOF
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -S conftest.c]) && test -s conftest.s; then
true
else
AC_MSG_ERROR([${CC-cc} failed to produce assembly code])
fi
if grep _func conftest.s >/dev/null 2>&1; then
grub_cv_asm_uscore=yes
else
grub_cv_asm_uscore=no
fi
rm -f conftest*])
if test "x$grub_cv_asm_uscore" = xyes; then
AC_DEFINE_UNQUOTED([HAVE_ASM_USCORE], $grub_cv_asm_uscore,
[Define if C symbols get an underscore after compilation])
fi
AC_MSG_RESULT([$grub_cv_asm_uscore])
])
dnl Some versions of `objcopy -O binary' vary their output depending
dnl on the link address.
AC_DEFUN([grub_PROG_OBJCOPY_ABSOLUTE],
[AC_MSG_CHECKING([whether ${OBJCOPY} works for absolute addresses])
AC_CACHE_VAL(grub_cv_prog_objcopy_absolute,
[cat > conftest.c <<\EOF
void
cmain (void)
{
*((int *) 0x1000) = 2;
}
EOF
if AC_TRY_EVAL(ac_compile) && test -s conftest.o; then :
else
AC_MSG_ERROR([${CC-cc} cannot compile C source code])
fi
grub_cv_prog_objcopy_absolute=yes
for link_addr in 2000 8000 7C00; do
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} ${LDFLAGS} -nostdlib -Wl,-N -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then :
else
AC_MSG_ERROR([${CC-cc} cannot link at address $link_addr])
fi
if AC_TRY_COMMAND([${OBJCOPY-objcopy} -O binary conftest.exec conftest]); then :
else
AC_MSG_ERROR([${OBJCOPY-objcopy} cannot create binary files])
fi
if test ! -f conftest.old || AC_TRY_COMMAND([cmp -s conftest.old conftest]); then
mv -f conftest conftest.old
else
grub_cv_prog_objcopy_absolute=no
break
fi
done
rm -f conftest*])
AC_MSG_RESULT([$grub_cv_prog_objcopy_absolute])])
dnl Mass confusion!
dnl Older versions of GAS interpret `.code16' to mean ``generate 32-bit
dnl instructions, but implicitly insert addr32 and data32 bytes so
dnl that the code works in real mode''.
dnl
dnl Newer versions of GAS interpret `.code16' to mean ``generate 16-bit
dnl instructions,'' which seems right. This requires the programmer
dnl to explicitly insert addr32 and data32 instructions when they want
dnl them.
dnl
dnl We only support the newer versions, because the old versions cause
dnl major pain, by requiring manual assembly to get 16-bit instructions into
dnl stage1/stage1.S.
AC_DEFUN([grub_ASM_ADDR32],
[AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([grub_ASM_PREFIX_REQUIREMENT])
AC_MSG_CHECKING([for .code16 addr32 assembler support])
AC_CACHE_VAL(grub_cv_asm_addr32,
[cat > conftest.s.in <<\EOF
.code16
l1: @ADDR32@ movb %al, l1
EOF
if test "x$grub_cv_asm_prefix_requirement" = xyes; then
sed -e s/@ADDR32@/addr32/ < conftest.s.in > conftest.s
else
sed -e s/@ADDR32@/addr32\;/ < conftest.s.in > conftest.s
fi
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -c conftest.s]) && test -s conftest.o; then
grub_cv_asm_addr32=yes
else
grub_cv_asm_addr32=no
fi
rm -f conftest*])
AC_MSG_RESULT([$grub_cv_asm_addr32])])
dnl
dnl Later versions of GAS requires that addr32 and data32 prefixes
dnl appear in the same lines as the instructions they modify, while
dnl earlier versions requires that they appear in separate lines.
AC_DEFUN([grub_ASM_PREFIX_REQUIREMENT],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING(dnl
[whether addr32 must be in the same line as the instruction])
AC_CACHE_VAL(grub_cv_asm_prefix_requirement,
[cat > conftest.s <<\EOF
.code16
l1: addr32 movb %al, l1
EOF
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -c conftest.s]) && test -s conftest.o; then
grub_cv_asm_prefix_requirement=yes
else
grub_cv_asm_prefix_requirement=no
fi
rm -f conftest*])
if test "x$grub_cv_asm_prefix_requirement" = xyes; then
grub_tmp_addr32="addr32"
grub_tmp_data32="data32"
else
grub_tmp_addr32="addr32;"
grub_tmp_data32="data32;"
fi
AC_DEFINE_UNQUOTED([ADDR32], $grub_tmp_addr32,
[Define it to \"addr32\" or \"addr32;\" to make GAS happy])
AC_DEFINE_UNQUOTED([DATA32], $grub_tmp_data32,
[Define it to \"data32\" or \"data32;\" to make GAS happy])
AC_MSG_RESULT([$grub_cv_asm_prefix_requirement])])
dnl
dnl Older versions of GAS require that absolute indirect calls/jumps are
dnl not prefixed with `*', while later versions warn if not prefixed.
AC_DEFUN([grub_ASM_ABSOLUTE_WITHOUT_ASTERISK],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING(dnl
[whether an absolute indirect call/jump must not be prefixed with an asterisk])
AC_CACHE_VAL(grub_cv_asm_absolute_without_asterisk,
[cat > conftest.s <<\EOF
lcall *(offset)
offset:
.long 0
.word 0
EOF
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -c conftest.s]) && test -s conftest.o; then
grub_cv_asm_absolute_without_asterisk=no
else
grub_cv_asm_absolute_without_asterisk=yes
fi
rm -f conftest*])
if test "x$grub_cv_asm_absolute_without_asterisk" = xyes; then
AC_DEFINE(ABSOLUTE_WITHOUT_ASTERISK, 1, [Define if an absolute indirect call/jump must NOT be prefixed with `*'])
fi
AC_MSG_RESULT([$grub_cv_asm_absolute_without_asterisk])])
dnl
dnl grub_CHECK_START_SYMBOL checks if start is automatically defined by
dnl the compiler.
dnl Written by OKUJI Yoshinori
AC_DEFUN([grub_CHECK_START_SYMBOL],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if start is defined by the compiler])
AC_CACHE_VAL(grub_cv_check_start_symbol,
[AC_TRY_LINK([], [asm ("incl start")],
grub_cv_check_start_symbol=yes,
grub_cv_check_start_symbol=no)])
if test "x$grub_cv_check_start_symbol" = xyes; then
AC_DEFINE(HAVE_START_SYMBOL, 1, [Define if start is defined])
fi
AC_MSG_RESULT([$grub_cv_check_start_symbol])
])
dnl
dnl grub_CHECK_USCORE_START_SYMBOL checks if _start is automatically
dnl defined by the compiler.
dnl Written by OKUJI Yoshinori
AC_DEFUN([grub_CHECK_USCORE_START_SYMBOL],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if _start is defined by the compiler])
AC_CACHE_VAL(grub_cv_check_uscore_start_symbol,
[AC_TRY_LINK([], [asm ("incl _start")],
grub_cv_check_uscore_start_symbol=yes,
grub_cv_check_uscore_start_symbol=no)])
if test "x$grub_cv_check_uscore_start_symbol" = xyes; then
AC_DEFINE(HAVE_USCORE_START_SYMBOL, 1, [Define if _start is defined])
fi
AC_MSG_RESULT([$grub_cv_check_uscore_start_symbol])
])
dnl
dnl grub_CHECK_USCORE_USCORE_BSS_START_SYMBOL checks if __bss_start is
dnl automatically defined by the compiler.
dnl Written by Michael Hohmoth.
AC_DEFUN([grub_CHECK_USCORE_USCORE_BSS_START_SYMBOL],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if __bss_start is defined by the compiler])
AC_CACHE_VAL(grub_cv_check_uscore_uscore_bss_start_symbol,
[AC_TRY_LINK([], [asm ("incl __bss_start")],
grub_cv_check_uscore_uscore_bss_start_symbol=yes,
grub_cv_check_uscore_uscore_bss_start_symbol=no)])
if test "x$grub_cv_check_uscore_uscore_bss_start_symbol" = xyes; then
AC_DEFINE(HAVE_USCORE_USCORE_BSS_START_SYMBOL, 1, [Define if __bss_start is defined])
fi
AC_MSG_RESULT([$grub_cv_check_uscore_uscore_bss_start_symbol])
])
dnl
dnl grub_CHECK_EDATA_SYMBOL checks if edata is automatically defined by the
dnl compiler.
dnl Written by Michael Hohmuth.
AC_DEFUN([grub_CHECK_EDATA_SYMBOL],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if edata is defined by the compiler])
AC_CACHE_VAL(grub_cv_check_edata_symbol,
[AC_TRY_LINK([], [asm ("incl edata")],
grub_cv_check_edata_symbol=yes,
grub_cv_check_edata_symbol=no)])
if test "x$grub_cv_check_edata_symbol" = xyes; then
AC_DEFINE(HAVE_EDATA_SYMBOL, 1, [Define if edata is defined])
fi
AC_MSG_RESULT([$grub_cv_check_edata_symbol])
])
dnl
dnl grub_CHECK_USCORE_EDATA_SYMBOL checks if _edata is automatically
dnl defined by the compiler.
dnl Written by Michael Hohmuth.
AC_DEFUN([grub_CHECK_USCORE_EDATA_SYMBOL],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if _edata is defined by the compiler])
AC_CACHE_VAL(grub_cv_check_uscore_edata_symbol,
[AC_TRY_LINK([], [asm ("incl _edata")],
grub_cv_check_uscore_edata_symbol=yes,
grub_cv_check_uscore_edata_symbol=no)])
if test "x$grub_cv_check_uscore_edata_symbol" = xyes; then
AC_DEFINE(HAVE_USCORE_EDATA_SYMBOL, 1, [Define if _edata is defined])
fi
AC_MSG_RESULT([$grub_cv_check_uscore_edata_symbol])
])
dnl
dnl grub_CHECK_END_SYMBOL checks if end is automatically defined by the
dnl compiler.
dnl Written by OKUJI Yoshinori
AC_DEFUN([grub_CHECK_END_SYMBOL],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if end is defined by the compiler])
AC_CACHE_VAL(grub_cv_check_end_symbol,
[AC_TRY_LINK([], [asm ("incl end")],
grub_cv_check_end_symbol=yes,
grub_cv_check_end_symbol=no)])
if test "x$grub_cv_check_end_symbol" = xyes; then
AC_DEFINE(HAVE_END_SYMBOL, 1, [Define if end is defined])
fi
AC_MSG_RESULT([$grub_cv_check_end_symbol])
])
dnl
dnl grub_CHECK_USCORE_END_SYMBOL checks if _end is automatically defined
dnl by the compiler.
dnl Written by OKUJI Yoshinori
AC_DEFUN([grub_CHECK_USCORE_END_SYMBOL],
[AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING([if _end is defined by the compiler])
AC_CACHE_VAL(grub_cv_check_uscore_end_symbol,
[AC_TRY_LINK([], [asm ("incl _end")],
grub_cv_check_uscore_end_symbol=yes,
grub_cv_check_uscore_end_symbol=no)])
if test "x$grub_cv_check_uscore_end_symbol" = xyes; then
AC_DEFINE(HAVE_USCORE_END_SYMBOL, 1, [Define if end is defined])
fi
AC_MSG_RESULT([$grub_cv_check_uscore_end_symbol])
])
dnl grub_DEFINE_FILE(MACRO_NAME, FILE_NAME, DESCRIPTION)
dnl grub_DEFINE_FILE defines a macro as the contents of a file safely.
dnl Replace some escape sequences, because autoconf doesn't handle them
dnl gracefully.
dnl Written by OKUJI Yoshinori.
AC_DEFUN([grub_DEFINE_FILE],
[AC_REQUIRE([AC_PROG_CC])
# Because early versions of GNU sed 3.x are too buggy, use a C program
# instead of shell commands. *sigh*
cat >conftest.c <<\EOF
#include <stdio.h>
int
main (void)
{
int c;
while ((c = getchar ()) != EOF)
{
switch (c)
{
case '\n':
fputs ("\\n", stdout);
break;
case '\r':
fputs ("\\r", stdout);
break;
case '\\':
fputs ("\\\\", stdout);
break;
case '"':
fputs ("\\\"", stdout);
break;
default:
putchar (c);
}
}
return 0;
}
EOF
if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} conftest.c -o conftest]) && test -s conftest; then
grub_tmp_value=`./conftest < "[$2]"`
else
AC_MSG_ERROR([${CC-cc} failed to produce an executable file])
fi
AC_DEFINE_UNQUOTED([$1], "$grub_tmp_value", [$3])
rm -f conftest*
])
+2 -8
View File
@@ -1,15 +1,9 @@
#! /bin/sh
#!/bin/sh
set -ex
gnulib-tool --import gendocs
aclocal
autoconf
autoheader
# Automake is unhappy without NEWS and README, but we don't have any
touch NEWS README
automake -a -c -f
autoconf
exit 0
+142
View File
@@ -0,0 +1,142 @@
#! /bin/sh
# Wrapper for compilers which do not understand `-c -o'.
scriptversion=2004-10-12.08
# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
case $1 in
'')
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand `-c -o'.
Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file `INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit 0
;;
-v | --v*)
echo "compile $scriptversion"
exit 0
;;
esac
ofile=
cfile=
eat=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as `compile cc -o foo foo.c'.
# So we strip `-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no `-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# `.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
# Create the lock directory.
# Note: use `[/.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:
+106
View File
@@ -0,0 +1,106 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if an absolute indirect call/jump must NOT be prefixed with `*' */
#undef ABSOLUTE_WITHOUT_ASTERISK
/* Define it to \"addr32\" or \"addr32;\" to make GAS happy */
#undef ADDR32
/* Define if you don't want to pass the mem= option to Linux */
#undef AUTO_LINUX_MEM_OPT
/* Define it to \"data32\" or \"data32;\" to make GAS happy */
#undef DATA32
/* Define if C symbols get an underscore after compilation */
#undef HAVE_ASM_USCORE
/* Define to 1 if you have the <curses.h> header file. */
#undef HAVE_CURSES_H
/* Define if edata is defined */
#undef HAVE_EDATA_SYMBOL
/* Define if end is defined */
#undef HAVE_END_SYMBOL
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define if you have a curses library */
#undef HAVE_LIBCURSES
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <ncurses/curses.h> header file. */
#undef HAVE_NCURSES_CURSES_H
/* Define to 1 if you have the <ncurses.h> header file. */
#undef HAVE_NCURSES_H
/* Define if opendisk() in -lutil can be used */
#undef HAVE_OPENDISK
/* Define if start is defined */
#undef HAVE_START_SYMBOL
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define if _edata is defined */
#undef HAVE_USCORE_EDATA_SYMBOL
/* Define if end is defined */
#undef HAVE_USCORE_END_SYMBOL
/* Define if _start is defined */
#undef HAVE_USCORE_START_SYMBOL
/* Define if __bss_start is defined */
#undef HAVE_USCORE_USCORE_BSS_START_SYMBOL
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define if there is user specified preset menu string */
#undef PRESET_MENU_STRING
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION
+655 -20
View File
@@ -1,5 +1,5 @@
dnl Configure script for GRUB.
dnl Copyright 1999,2000,2001,2002,2003,2004,2005,2008,2009,2010 Free Software Foundation, Inc.
dnl Copyright 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
dnl Permission to use, copy, modify and distribute this software and its
dnl documentation is hereby granted, provided that both the copyright
@@ -12,12 +12,44 @@ dnl "AS IS" CONDITION. THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
dnl LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
dnl USE OF THIS SOFTWARE.
AC_PREREQ(2.59)
AC_INIT([Multiboot], [0.6.96], [bug-grub@gnu.org])
AC_CONFIG_SRCDIR([doc/multiboot.texi])
AC_PREREQ(2.57)
AC_INIT([GRUB], [0.97], [bug-grub@gnu.org])
AC_CONFIG_SRCDIR([stage2/stage2.c])
AC_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE
AC_CANONICAL_HOST
case "$host_cpu" in
i[[3456]]86) host_cpu=i386 ;;
x86_64) host_cpu=x86_64 ;;
*) AC_MSG_ERROR([unsupported CPU type]) ;;
esac
AC_SUBST(host_cpu)
AC_SUBST(host_vendor)
#
# Options
#
AM_MAINTAINER_MODE
if test "x$enable_maintainer_mode" = xyes; then
AC_PATH_PROG(PERL,perl)
if test -z "$PERL"; then
AC_MSG_ERROR([perl not found])
fi
fi
# This should be checked before AC_PROG_CC
if test "x$CFLAGS" = x; then
default_CFLAGS=yes
fi
if test "x$host_cpu" = xx86_64; then
CFLAGS="-m32 $CFLAGS"
fi
#
# Programs
#
@@ -25,6 +57,7 @@ AM_INIT_AUTOMAKE
AC_CHECK_TOOL(CC, gcc)
AC_PROG_CC
AM_PROG_AS
# We need this for older versions of Autoconf.
_AM_DEPENDENCIES(CC)
@@ -32,27 +65,629 @@ dnl Because recent automake complains about AS, set it here.
CCAS="$CC"
AC_SUBST(CCAS)
dnl Build the example Multiboot kernel.
AC_ARG_ENABLE(example-kernel,
[ --enable-example-kernel
build the example Multiboot kernel])
AM_CONDITIONAL(BUILD_EXAMPLE_KERNEL, test "x$enable_example_kernel" = xyes)
AC_ARG_WITH(binutils,
[ --with-binutils=DIR search the directory DIR to find binutils])
if test "x$with_binutils" != x; then
dnl AC_PATH_TOOL is not seen in autoconf 2.13, so use AC_PATH_PROG
dnl instead for now. It is preferable when you cross-compile GRUB.
dnl AC_PATH_TOOL(RANLIB, ranlib, :, "$with_binutils:$PATH")
AC_PATH_PROG(RANLIB, ranlib, :, "$with_binutils:$PATH")
else
AC_PROG_RANLIB
fi
# optimization flags
if test "x$ac_cv_prog_gcc" = xyes; then
if test "x$default_CFLAGS" = xyes; then
# Autoconf may set CFLAGS to -O2 and/or -g. So eliminate them.
CFLAGS="`echo $CFLAGS | sed -e 's/-g//g' -e 's/-O[[0-9]]//g'` -g"
# If the user specify the directory for binutils, add the option `-B'.
if test "x$with_binutils" != x; then
CFLAGS="-B$with_binutils/ $CFLAGS"
fi
STAGE1_CFLAGS="-O2"
GRUB_CFLAGS="-O2"
AC_CACHE_CHECK([whether optimization for size works], grub_cv_cc_Os, [
saved_CFLAGS=$CFLAGS
CFLAGS="-Os -g"
AC_TRY_COMPILE(, , grub_cv_cc_Os=yes, grub_cv_cc_Os=no)
CFLAGS=$saved_CFLAGS
])
if test "x$grub_cv_cc_Os" = xyes; then
STAGE2_CFLAGS="-Os"
else
STAGE2_CFLAGS="-O2 -fno-strength-reduce -fno-unroll-loops"
fi
# OpenBSD has a GCC extension for protecting applications from
# stack smashing attacks, but GRUB doesn't want this feature.
AC_CACHE_CHECK([whether gcc has -fno-stack-protector],
grub_cv_cc_no_stack_protector, [
saved_CFLAGS=$CFLAGS
CFLAGS="-fno-stack-protector"
AC_TRY_COMPILE(,
,
grub_cv_cc_no_stack_protector=yes,
grub_cv_cc_no_stack_protector=no)
CFLAGS=$saved_CFLAGS
])
if test "x$grub_cv_cc_no_stack_protector" = xyes; then
STAGE2_CFLAGS="$STAGE2_CFLAGS -fno-stack-protector"
fi
# GCC >= 3.3 supports -fno-reorder-functions; this defends us against
# unlikely-to-be-executed functions being linked before _start with GCC
# >= 4.6.
AC_CACHE_CHECK([whether gcc has -fno-reorder-functions],
no_reorder_functions_flag, [
saved_CFLAGS=$CFLAGS
CFLAGS="-fno-reorder-functions"
AC_TRY_COMPILE(,
,
no_reorder_functions_flag=yes,
no_reorder_functions_flag=no)
CFLAGS=$saved_CFLAGS
])
if test "x$no_reorder_functions_flag" = xyes; then
STAGE2_CFLAGS="$STAGE2_CFLAGS -fno-reorder-functions"
fi
fi
fi
AC_SUBST(STAGE1_CFLAGS)
AC_SUBST(STAGE2_CFLAGS)
AC_SUBST(GRUB_CFLAGS)
# Enforce coding standards.
CPPFLAGS="$CPPFLAGS -Wall -Wmissing-prototypes -Wunused -Wshadow"
CPPFLAGS="$CPPFLAGS -Wpointer-arith"
AC_CACHE_CHECK([whether -Wundef works], grub_cv_cc_Wundef, [
saved_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="-Wundef"
AC_TRY_COMPILE(, , grub_cv_cc_Wundef=yes, grub_cv_cc_Wundef=no)
CPPFLAGS="$saved_CPPFLAGS"
])
# The options `-falign-*' are supported by gcc 3.0 or later.
# Probably it is sufficient to only check for -falign-loops.
AC_CACHE_CHECK([whether -falign-loops works], [grub_cv_cc_falign_loop], [
saved_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="-falign-loops=1"
AC_TRY_COMPILE(, , [grub_cv_cc_falign_loop=yes], [grub_cv_cc_falign_loop=no])
CPPFLAGS="$saved_CPPFLAGS"
])
# Force no alignment to save space.
if test "x$grub_cv_cc_falign_loop" = xyes; then
CPPFLAGS="$CPPFLAGS -falign-jumps=1 -falign-loops=1 -falign-functions=1"
else
CPPFLAGS="$CPPFLAGS -malign-jumps=1 -malign-loops=1 -malign-functions=1"
fi
if test "x$grub_cv_cc_Wundef" = xyes; then
CPPFLAGS="$CPPFLAGS -Wundef"
fi
# Check if build ID can be disabled in the linker
AC_MSG_CHECKING([whether linker accepts `--build-id=none'])
save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -Wl,--build-id=none"
AC_TRY_LINK(, , build_id_flag=yes, build_id_flag=no)
AC_MSG_RESULT([$build_id_flag])
LDFLAGS="$save_LDFLAGS"
if test "x$build_id_flag" = xyes; then
LDFLAGS="$LDFLAGS -Wl,--build-id=none"
fi
if test "x$with_binutils" != x; then
dnl AC_PATH_TOOL(OBJCOPY, objcopy, , "$with_binutils:$PATH")
AC_PATH_PROG(OBJCOPY, objcopy, , "$with_binutils:$PATH")
else
AC_CHECK_TOOL(OBJCOPY, objcopy)
fi
# Defined in acinclude.m4.
grub_ASM_USCORE
grub_PROG_OBJCOPY_ABSOLUTE
if test "x$grub_cv_prog_objcopy_absolute" != xyes; then
AC_MSG_ERROR([GRUB requires a working absolute objcopy; upgrade your binutils])
fi
grub_ASM_PREFIX_REQUIREMENT
grub_ASM_ADDR32
if test "x$grub_cv_asm_addr32" != xyes; then
AC_MSG_ERROR([GRUB requires GAS .code16 addr32 support; upgrade your binutils])
fi
grub_ASM_ABSOLUTE_WITHOUT_ASTERISK
grub_CHECK_START_SYMBOL
grub_CHECK_USCORE_START_SYMBOL
if test "x$grub_cv_check_start_symbol" != "xyes" \
-a "x$grub_cv_check_uscore_start_symbol" != "xyes"; then
AC_MSG_ERROR([Neither start nor _start is defined])
fi
grub_CHECK_USCORE_USCORE_BSS_START_SYMBOL
grub_CHECK_USCORE_EDATA_SYMBOL
grub_CHECK_EDATA_SYMBOL
if test "x$grub_cv_check_uscore_uscore_bss_start_symbol" != "xyes" \
-a "x$grub_cv_check_uscore_edata_symbol" != "xyes" \
-a "x$grub_cv_check_edata_symbol" != "xyes"; then
AC_MSG_ERROR([None of __bss_start, _edata, edata defined])
fi
grub_CHECK_END_SYMBOL
grub_CHECK_USCORE_END_SYMBOL
if test "x$grub_cv_check_end_symbol" != "xyes" \
-a "x$grub_cv_check_uscore_end_symbol" != "xyes"; then
AC_MSG_ERROR([Neither end nor _end is defined])
fi
# Check for curses libraries.
AC_ARG_WITH(curses,
[ --without-curses do not use curses])
# Get the filename or the whole disk and open it.
# Known to work on NetBSD.
AC_CHECK_LIB(util, opendisk, [GRUB_LIBS="$GRUB_LIBS -lutil"
AC_DEFINE(HAVE_OPENDISK, 1, [Define if opendisk() in -lutil can be used])])
# Unless the user specify --without-curses, check for curses.
if test "x$with_curses" != "xno"; then
AC_CHECK_LIB(ncurses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lncurses"
AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])],
[AC_CHECK_LIB(curses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lcurses"
AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])])])
fi
AC_SUBST(GRUB_LIBS)
# Check for headers.
AC_CHECK_HEADERS(string.h strings.h ncurses/curses.h ncurses.h curses.h)
# Check for user options.
# filesystems support.
AC_ARG_ENABLE(ext2fs,
[ --disable-ext2fs disable ext2fs support in Stage 2])
if test x"$enable_ext2fs" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_EXT2FS=1"
fi
AC_ARG_ENABLE(fat,
[ --disable-fat disable FAT support in Stage 2])
if test x"$enable_fat" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FAT=1"
fi
AC_ARG_ENABLE(ffs,
[ --disable-ffs disable FFS support in Stage 2])
if test x"$enable_ffs" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FFS=1"
fi
AC_ARG_ENABLE(ufs2,
[ --disable-ufs2 disable UFS2 support in Stage 2])
if test x"$enable_ufs2" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_UFS2=1"
fi
AC_ARG_ENABLE(minix,
[ --disable-minix disable Minix fs support in Stage 2])
if test x"$enable_minix" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_MINIX=1"
fi
AC_ARG_ENABLE(reiserfs,
[ --disable-reiserfs disable ReiserFS support in Stage 2])
if test x"$enable_reiserfs" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_REISERFS=1"
fi
AC_ARG_ENABLE(vstafs,
[ --disable-vstafs disable VSTa FS support in Stage 2])
if test x"$enable_vstafs" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_VSTAFS=1"
fi
AC_ARG_ENABLE(jfs,
[ --disable-jfs disable IBM JFS support in Stage 2])
if test x"$enable_jfs" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_JFS=1"
fi
AC_ARG_ENABLE(xfs,
[ --disable-xfs disable SGI XFS support in Stage 2])
if test x"$enable_xfs" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_XFS=1"
fi
AC_ARG_ENABLE(iso9660,
[ --disable-iso9660 disable ISO9660 support in Stage 2])
if test x"$enable_iso9660" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_ISO9660=1"
fi
dnl AC_ARG_ENABLE(tftp,
dnl [ --enable-tftp enable TFTP support in Stage 2])
dnl
dnl #if test x"$enable_tftp" = xyes; then
dnl FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1"
dnl fi
AC_ARG_ENABLE(gunzip,
[ --disable-gunzip disable decompression in Stage 2])
if test x"$enable_gunzip" = xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DNO_DECOMPRESSION=1"
fi
AC_ARG_ENABLE(md5-password,
[ --disable-md5-password disable MD5 password support in Stage 2])
if test "x$enable_md5_password" != xno; then
FSYS_CFLAGS="$FSYS_CFLAGS -DUSE_MD5_PASSWORDS=1"
fi
dnl The netboot support.
dnl General options.
AC_ARG_ENABLE(packet-retransmission,
[ --disable-packet-retransmission
turn off packet retransmission])
if test "x$enable_packet_retransmission" != xno; then
NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCONGESTED=1"
fi
AC_ARG_ENABLE(pci-direct,
[ --enable-pci-direct access PCI directly instead of using BIOS])
if test "x$enable_pci_direct" = xyes; then
NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCONFIG_PCI_DIRECT=1"
fi
dnl Device drivers.
AC_ARG_ENABLE(3c509,
[ --enable-3c509 enable 3Com509 driver])
if test "x$enable_3c509" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C509"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c509.o"
fi
AC_ARG_ENABLE(3c529,
[ --enable-3c529 enable 3Com529 driver])
if test "x$enable_3c529" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C529=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c529.o"
fi
AC_ARG_ENABLE(3c595,
[ --enable-3c595 enable 3Com595 driver])
if test "x$enable_3c595" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C595=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c595.o"
fi
AC_ARG_ENABLE(3c90x,
[ --enable-3c90x enable 3Com90x driver])
if test "x$enable_3c90x" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C90X=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c90x.o"
fi
AC_ARG_ENABLE(cs89x0,
[ --enable-cs89x0 enable CS89x0 driver])
if test "x$enable_cs89x0" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_CS89X0=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS cs89x0.o"
fi
AC_ARG_ENABLE(davicom,
[ --enable-davicom enable Davicom driver])
if test "x$enable_davicom" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DAVICOM=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS davicom.o"
fi
AC_ARG_ENABLE(depca,
[ --enable-depca enable DEPCA and EtherWORKS driver])
if test "x$enable_depca" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DEPCA=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS depca.o"
fi
AC_ARG_ENABLE(eepro,
[ --enable-eepro enable Etherexpress Pro/10 driver])
if test "x$enable_eepro" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro.o"
fi
AC_ARG_ENABLE(eepro100,
[ --enable-eepro100 enable Etherexpress Pro/100 driver])
if test "x$enable_eepro100" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO100=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro100.o"
fi
AC_ARG_ENABLE(epic100,
[ --enable-epic100 enable SMC 83c170 EPIC/100 driver])
if test "x$enable_epic100" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EPIC100=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS epic100.o"
fi
AC_ARG_ENABLE(3c507,
[ --enable-3c507 enable 3Com507 driver])
if test "x$enable_3c507" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C507=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c507.o"
fi
AC_ARG_ENABLE(exos205,
[ --enable-exos205 enable EXOS205 driver])
if test "x$enable_exos205" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EXOS205=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS exos205.o"
fi
AC_ARG_ENABLE(ni5210,
[ --enable-ni5210 enable Racal-Interlan NI5210 driver])
if test "x$enable_ni5210" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5210=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5210.o"
fi
AC_ARG_ENABLE(lance,
[ --enable-lance enable Lance PCI PCNet/32 driver])
if test "x$enable_lance" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_LANCE=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS lance.o"
fi
AC_ARG_ENABLE(ne2100,
[ --enable-ne2100 enable Novell NE2100 driver])
if test "x$enable_ne2100" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE2100=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS ne2100.o"
fi
AC_ARG_ENABLE(ni6510,
[ --enable-ni6510 enable Racal-Interlan NI6510 driver])
if test "x$enable_ni6510" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI6510=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni6510.o"
fi
AC_ARG_ENABLE(natsemi,
[ --enable-natsemi enable NatSemi DP8381x driver])
if test "x$enable_natsemi" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NATSEMI=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS natsemi.o"
fi
AC_ARG_ENABLE(ni5010,
[ --enable-ni5010 enable Racal-Interlan NI5010 driver])
if test "x$enable_ni5010" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5010=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5010.o"
fi
AC_ARG_ENABLE(3c503,
[ --enable-3c503 enable 3Com503 driver])
if test "x$enable_3c503" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C503=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c503.o"
fi
AC_ARG_ENABLE(ne,
[ --enable-ne enable NE1000/2000 ISA driver])
if test "x$enable_ne" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS ne.o"
fi
AC_ARG_ENABLE(ns8390,
[ --enable-ns8390 enable NE2000 PCI driver])
if test "x$enable_ns8390" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NS8390=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS ns8390.o"
fi
AC_ARG_ENABLE(wd,
[ --enable-wd enable WD8003/8013, SMC8216/8416 driver])
if test "x$enable_wd" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_WD=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS wd.o"
fi
AC_ARG_ENABLE(otulip,
[ --enable-otulip enable old Tulip driver])
if test "x$enable_otulip" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_OTULIP=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS otulip.o"
fi
AC_ARG_ENABLE(rtl8139,
[ --enable-rtl8139 enable Realtek 8139 driver])
if test "x$enable_rtl8139" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_RTL8139=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS rtl8139.o"
fi
AC_ARG_ENABLE(sis900,
[ --enable-sis900 enable SIS 900 and SIS 7016 driver])
if test "x$enable_sis900" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SIS900=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS sis900.o"
fi
AC_ARG_ENABLE(sk-g16,
[ --enable-sk-g16 enable Schneider and Koch G16 driver])
if test "x$enable_sk_g16" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SK_G16=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS sk_g16.o"
fi
AC_ARG_ENABLE(smc9000,
[ --enable-smc9000 enable SMC9000 driver])
if test "x$enable_smc9000" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SMC9000=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS smc9000.o"
fi
AC_ARG_ENABLE(tiara,
[ --enable-tiara enable Tiara driver])
if test "x$enable_tiara" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TIARA=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS tiara.o"
fi
AC_ARG_ENABLE(tulip,
[ --enable-tulip enable Tulip driver])
if test "x$enable_tulip" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TULIP=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS tulip.o"
fi
AC_ARG_ENABLE(via-rhine,
[ --enable-via-rhine enable Rhine-I/II driver])
if test "x$enable_via_rhine" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_VIA_RHINE=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS via_rhine.o"
fi
AC_ARG_ENABLE(w89c840,
[ --enable-w89c840 enable Winbond W89c840, Compex RL100-ATX driver])
if test "x$enable_w89c840" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_W89C840=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS w89c840.o"
fi
dnl Check if the netboot support is turned on.
AM_CONDITIONAL(NETBOOT_SUPPORT, test "x$NET_CFLAGS" != x)
if test "x$NET_CFLAGS" != x; then
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1"
fi
dnl Extra options.
AC_ARG_ENABLE(3c503-shmem,
[ --enable-3c503-shmem use 3c503 shared memory mode])
if test "x$enable_3c503_shmem" = xyes; then
NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_SHMEM=1"
fi
AC_ARG_ENABLE(3c503-aui,
[ --enable-3c503-aui use AUI by default on 3c503 cards])
if test "x$enable_3c503_aui" = xyes; then
NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_AUI=1"
fi
AC_ARG_ENABLE(compex-rl2000-fix,
[ --enable-compex-rl2000-fix
specify this if you have a Compex RL2000 PCI])
if test "x$enable_compex_rl2000_fix" = xyes; then
NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCOMPEX_RL2000_FIX=1"
fi
AC_ARG_ENABLE(smc9000-scan,
[ --enable-smc9000-scan=LIST
probe for SMC9000 I/O addresses using LIST],
[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DSMC9000_SCAN=$enable_smc9000_scan"])
AC_ARG_ENABLE(ne-scan,
[ --enable-ne-scan=LIST probe for NE base address using LIST],
[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=$enable_ne_scan"],
[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=0x280,0x300,0x320,0x340"])
AC_ARG_ENABLE(wd-default-mem,
[ --enable-wd-default-mem=MEM
set the default memory location for WD/SMC],
[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=$enable_wd_default_mem"],
[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=0xCC000"])
AC_ARG_ENABLE(cs-scan,
[ --enable-cs-scan=LIST probe for CS89x0 base address using LIST],
[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCS_SCAN=$enable_cs_scan"])
dnl Diskless
AC_ARG_ENABLE(diskless,
[ --enable-diskless enable diskless support])
AM_CONDITIONAL(DISKLESS_SUPPORT, test "x$enable_diskless" = xyes)
dnl Hercules terminal
AC_ARG_ENABLE(hercules,
[ --disable-hercules disable hercules terminal support])
AM_CONDITIONAL(HERCULES_SUPPORT, test "x$enable_hercules" != xno)
dnl Serial terminal
AC_ARG_ENABLE(serial,
[ --disable-serial disable serial terminal support])
AM_CONDITIONAL(SERIAL_SUPPORT, test "x$enable_serial" != xno)
dnl Simulation of the slowness of a serial device.
AC_ARG_ENABLE(serial-speed-simulation,
[ --enable-serial-speed-simulation
simulate the slowness of a serial device])
AM_CONDITIONAL(SERIAL_SPEED_SIMULATION,
test "x$enable_serial_speed_simulation" = xyes)
# Sanity check.
if test "x$enable_diskless" = xyes; then
if test "x$NET_CFLAGS" = x; then
AC_MSG_ERROR([You must enable at least one network driver])
fi
fi
dnl Embed a menu string in GRUB itself.
AC_ARG_ENABLE(preset-menu,
[ --enable-preset-menu=FILE
preset a menu file FILE in Stage 2])
if test "x$enable_preset_menu" = x; then
:
else
if test -r $enable_preset_menu; then
grub_DEFINE_FILE(PRESET_MENU_STRING, [$enable_preset_menu],
[Define if there is user specified preset menu string])
else
AC_MSG_ERROR([Cannot read the preset menu file $enable_preset_menu])
fi
fi
dnl Automatic Linux mem= option.
AC_ARG_ENABLE(auto-linux-mem-opt,
[ --disable-auto-linux-mem-opt
don't pass Linux mem= option automatically])
if test "x$enable_auto_linux_mem_opt" = xno; then
:
else
AC_DEFINE(AUTO_LINUX_MEM_OPT, 1, [Define if you don't want to pass the mem= option to Linux])
fi
dnl Now substitute the variables.
AC_SUBST(FSYS_CFLAGS)
AC_SUBST(NET_CFLAGS)
AC_SUBST(NET_EXTRAFLAGS)
AC_SUBST(NETBOOT_DRIVERS)
dnl Because recent automake complains about CCASFLAGS, set it here.
CCASFLAGS='$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)'
AC_SUBST(CCASFLAGS)
AC_ARG_ENABLE(mbchk,
[ --enable-mbchk
build the mbchk (multiboot checker)])
AM_CONDITIONAL(BUILD_MBCHK, test "x$enable_mbchk" = xyes)
if test "x$enable_mbchk" = xyes; then
AC_PATH_PROG(HELP2MAN, help2man)
fi
AM_CONDITIONAL([COND_MAN_PAGES], [test x$enable_mbchk = xyes -a x$HELP2MAN != x])
dnl Output.
AC_CONFIG_FILES([Makefile doc/Makefile util/Makefile])
AC_CONFIG_FILES([Makefile stage1/Makefile stage2/Makefile \
docs/Makefile lib/Makefile util/Makefile \
grub/Makefile netboot/Makefile util/grub-image \
util/grub-install util/grub-md5-crypt \
util/grub-terminfo util/grub-set-default])
AC_OUTPUT
-35
View File
@@ -1,35 +0,0 @@
info_TEXINFOS = multiboot.texi
EXAMPLES = boot.S kernel.c multiboot.h
multiboot_TEXINFOS = boot.S.texi kernel.c.texi multiboot.h.texi
SRC2TEXI = src2texi
noinst_SCRIPTS = $(SRC2TEXI)
EXTRA_PROGRAMS = kernel
pkginclude_HEADERS = multiboot.h
# The example kernel is built if you specify --enable-example-kernel.
if BUILD_EXAMPLE_KERNEL
noinst_PROGRAMS = kernel
kernel_SOURCES = $(EXAMPLES)
kernel_CPPFLAGS = -m32 -nostdlib -fno-builtin -nostdinc -O -g -Wall \
-imacros $(top_builddir)/config.h
kernel_LDFLAGS = -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,100000 -Wl,--build-id=none
boot.o: multiboot.h
endif
EXTRA_DIST = $(man_MANS) $(noinst_SCRIPTS) \
$(EXAMPLES) $(multiboot_TEXINFOS)
CLEANFILES = $(noinst_PROGRAMS)
# Cancel the rule %.texi -> %. This rule may confuse make to determine
# the dependecies.
.texi:
%.c.texi: %.c $(srcdir)/$(SRC2TEXI)
$(SHELL) $(srcdir)/$(SRC2TEXI) $(srcdir) $< $@
%.h.texi: %.h $(srcdir)/$(SRC2TEXI)
$(SHELL) $(srcdir)/$(SRC2TEXI) $(srcdir) $< $@
%.S.texi: %.S $(srcdir)/$(SRC2TEXI)
$(SHELL) $(srcdir)/$(SRC2TEXI) $(srcdir) $< $@
-107
View File
@@ -1,107 +0,0 @@
/* boot.S - bootstrap the kernel */
/* Copyright (C) 1999, 2001, 2010 Free Software Foundation, Inc.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#define ASM_FILE 1
#include <multiboot.h>
/* C symbol format. HAVE_ASM_USCORE is defined by configure. */
#ifdef HAVE_ASM_USCORE
# define EXT_C(sym) _ ## sym
#else
# define EXT_C(sym) sym
#endif
/* The size of our stack (16KB). */
#define STACK_SIZE 0x4000
/* The flags for the Multiboot header. */
#ifdef __ELF__
# define AOUT_KLUDGE 0
#else
# define AOUT_KLUDGE MULTIBOOT_AOUT_KLUDGE
#endif
#define MULTIBOOT_HEADER_FLAGS MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE | AOUT_KLUDGE
.text
.globl start, _start
start:
_start:
jmp multiboot_entry
/* Align 32 bits boundary. */
.align 4
/* Multiboot header. */
multiboot_header:
/* magic */
.long MULTIBOOT_HEADER_MAGIC
/* flags */
.long MULTIBOOT_HEADER_FLAGS
/* checksum */
.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
#ifndef __ELF__
/* header_addr */
.long multiboot_header
/* load_addr */
.long _start
/* load_end_addr */
.long _edata
/* bss_end_addr */
.long _end
/* entry_addr */
.long multiboot_entry
#else /* ! __ELF__ */
.long 0
.long 0
.long 0
.long 0
.long 0
#endif /* __ELF__ */
.long 0
.long 1024
.long 768
.long 32
multiboot_entry:
/* Initialize the stack pointer. */
movl $(stack + STACK_SIZE), %esp
/* Reset EFLAGS. */
pushl $0
popf
/* Push the pointer to the Multiboot information structure. */
pushl %ebx
/* Push the magic value. */
pushl %eax
/* Now enter the C main function... */
call EXT_C(cmain)
/* Halt. */
pushl $halt_message
call EXT_C(printf)
loop: hlt
jmp loop
halt_message:
.asciz "Halted."
/* Our stack area. */
.comm stack, STACK_SIZE
-385
View File
@@ -1,385 +0,0 @@
/* kernel.c - the C part of the kernel */
/* Copyright (C) 1999, 2010 Free Software Foundation, Inc.
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <multiboot.h>
/* Macros. */
/* Check if the bit BIT in FLAGS is set. */
#define CHECK_FLAG(flags,bit) ((flags) & (1 << (bit)))
/* Some screen stuff. */
/* The number of columns. */
#define COLUMNS 80
/* The number of lines. */
#define LINES 24
/* The attribute of an character. */
#define ATTRIBUTE 7
/* The video memory address. */
#define VIDEO 0xB8000
/* Variables. */
/* Save the X position. */
static int xpos;
/* Save the Y position. */
static int ypos;
/* Point to the video memory. */
static volatile unsigned char *video;
/* Forward declarations. */
void cmain (unsigned long magic, unsigned long addr);
static void cls (void);
static void itoa (char *buf, int base, int d);
static void putchar (int c);
void printf (const char *format, ...);
/* Check if MAGIC is valid and print the Multiboot information structure
pointed by ADDR. */
void
cmain (unsigned long magic, unsigned long addr)
{
multiboot_info_t *mbi;
/* Clear the screen. */
cls ();
/* Am I booted by a Multiboot-compliant boot loader? */
if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
{
printf ("Invalid magic number: 0x%x\n", (unsigned) magic);
return;
}
/* Set MBI to the address of the Multiboot information structure. */
mbi = (multiboot_info_t *) addr;
/* Print out the flags. */
printf ("flags = 0x%x\n", (unsigned) mbi->flags);
/* Are mem_* valid? */
if (CHECK_FLAG (mbi->flags, 0))
printf ("mem_lower = %uKB, mem_upper = %uKB\n",
(unsigned) mbi->mem_lower, (unsigned) mbi->mem_upper);
/* Is boot_device valid? */
if (CHECK_FLAG (mbi->flags, 1))
printf ("boot_device = 0x%x\n", (unsigned) mbi->boot_device);
/* Is the command line passed? */
if (CHECK_FLAG (mbi->flags, 2))
printf ("cmdline = %s\n", (char *) mbi->cmdline);
/* Are mods_* valid? */
if (CHECK_FLAG (mbi->flags, 3))
{
multiboot_module_t *mod;
int i;
printf ("mods_count = %d, mods_addr = 0x%x\n",
(int) mbi->mods_count, (int) mbi->mods_addr);
for (i = 0, mod = (multiboot_module_t *) mbi->mods_addr;
i < mbi->mods_count;
i++, mod++)
printf (" mod_start = 0x%x, mod_end = 0x%x, cmdline = %s\n",
(unsigned) mod->mod_start,
(unsigned) mod->mod_end,
(char *) mod->cmdline);
}
/* Bits 4 and 5 are mutually exclusive! */
if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG (mbi->flags, 5))
{
printf ("Both bits 4 and 5 are set.\n");
return;
}
/* Is the symbol table of a.out valid? */
if (CHECK_FLAG (mbi->flags, 4))
{
multiboot_aout_symbol_table_t *multiboot_aout_sym = &(mbi->u.aout_sym);
printf ("multiboot_aout_symbol_table: tabsize = 0x%0x, "
"strsize = 0x%x, addr = 0x%x\n",
(unsigned) multiboot_aout_sym->tabsize,
(unsigned) multiboot_aout_sym->strsize,
(unsigned) multiboot_aout_sym->addr);
}
/* Is the section header table of ELF valid? */
if (CHECK_FLAG (mbi->flags, 5))
{
multiboot_elf_section_header_table_t *multiboot_elf_sec = &(mbi->u.elf_sec);
printf ("multiboot_elf_sec: num = %u, size = 0x%x,"
" addr = 0x%x, shndx = 0x%x\n",
(unsigned) multiboot_elf_sec->num, (unsigned) multiboot_elf_sec->size,
(unsigned) multiboot_elf_sec->addr, (unsigned) multiboot_elf_sec->shndx);
}
/* Are mmap_* valid? */
if (CHECK_FLAG (mbi->flags, 6))
{
multiboot_memory_map_t *mmap;
printf ("mmap_addr = 0x%x, mmap_length = 0x%x\n",
(unsigned) mbi->mmap_addr, (unsigned) mbi->mmap_length);
for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr;
(unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
mmap = (multiboot_memory_map_t *) ((unsigned long) mmap
+ mmap->size + sizeof (mmap->size)))
printf (" size = 0x%x, base_addr = 0x%x%08x,"
" length = 0x%x%08x, type = 0x%x\n",
(unsigned) mmap->size,
(unsigned) (mmap->addr >> 32),
(unsigned) (mmap->addr & 0xffffffff),
(unsigned) (mmap->len >> 32),
(unsigned) (mmap->len & 0xffffffff),
(unsigned) mmap->type);
}
/* Draw diagonal blue line. */
if (CHECK_FLAG (mbi->flags, 12))
{
multiboot_uint32_t color;
unsigned i;
void *fb = (void *) (unsigned long) mbi->framebuffer_addr;
switch (mbi->framebuffer_type)
{
case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
{
unsigned best_distance, distance;
struct multiboot_color *palette;
palette = (struct multiboot_color *) mbi->framebuffer_palette_addr;
color = 0;
best_distance = 4*256*256;
for (i = 0; i < mbi->framebuffer_palette_num_colors; i++)
{
distance = (0xff - palette[i].blue) * (0xff - palette[i].blue)
+ palette[i].red * palette[i].red
+ palette[i].green * palette[i].green;
if (distance < best_distance)
{
color = i;
best_distance = distance;
}
}
}
break;
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
color = ((1 << mbi->framebuffer_blue_mask_size) - 1)
<< mbi->framebuffer_blue_field_position;
break;
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
color = '\\' | 0x0100;
break;
default:
color = 0xffffffff;
break;
}
for (i = 0; i < mbi->framebuffer_width
&& i < mbi->framebuffer_height; i++)
{
switch (mbi->framebuffer_bpp)
{
case 8:
{
multiboot_uint8_t *pixel = fb + mbi->framebuffer_pitch * i + i;
*pixel = color;
}
break;
case 15:
case 16:
{
multiboot_uint16_t *pixel
= fb + mbi->framebuffer_pitch * i + 2 * i;
*pixel = color;
}
break;
case 24:
{
multiboot_uint32_t *pixel
= fb + mbi->framebuffer_pitch * i + 3 * i;
*pixel = (color & 0xffffff) | (*pixel & 0xff000000);
}
break;
case 32:
{
multiboot_uint32_t *pixel
= fb + mbi->framebuffer_pitch * i + 4 * i;
*pixel = color;
}
break;
}
}
}
}
/* Clear the screen and initialize VIDEO, XPOS and YPOS. */
static void
cls (void)
{
int i;
video = (unsigned char *) VIDEO;
for (i = 0; i < COLUMNS * LINES * 2; i++)
*(video + i) = 0;
xpos = 0;
ypos = 0;
}
/* Convert the integer D to a string and save the string in BUF. If
BASE is equal to 'd', interpret that D is decimal, and if BASE is
equal to 'x', interpret that D is hexadecimal. */
static void
itoa (char *buf, int base, int d)
{
char *p = buf;
char *p1, *p2;
unsigned long ud = d;
int divisor = 10;
/* If %d is specified and D is minus, put `-' in the head. */
if (base == 'd' && d < 0)
{
*p++ = '-';
buf++;
ud = -d;
}
else if (base == 'x')
divisor = 16;
/* Divide UD by DIVISOR until UD == 0. */
do
{
int remainder = ud % divisor;
*p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
}
while (ud /= divisor);
/* Terminate BUF. */
*p = 0;
/* Reverse BUF. */
p1 = buf;
p2 = p - 1;
while (p1 < p2)
{
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2--;
}
}
/* Put the character C on the screen. */
static void
putchar (int c)
{
if (c == '\n' || c == '\r')
{
newline:
xpos = 0;
ypos++;
if (ypos >= LINES)
ypos = 0;
return;
}
*(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
*(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;
xpos++;
if (xpos >= COLUMNS)
goto newline;
}
/* Format a string and print it on the screen, just like the libc
function printf. */
void
printf (const char *format, ...)
{
char **arg = (char **) &format;
int c;
char buf[20];
arg++;
while ((c = *format++) != 0)
{
if (c != '%')
putchar (c);
else
{
char *p, *p2;
int pad0 = 0, pad = 0;
c = *format++;
if (c == '0')
{
pad0 = 1;
c = *format++;
}
if (c >= '0' && c <= '9')
{
pad = c - '0';
c = *format++;
}
switch (c)
{
case 'd':
case 'u':
case 'x':
itoa (buf, c, *((int *) arg++));
p = buf;
goto string;
break;
case 's':
p = *arg++;
if (! p)
p = "(null)";
string:
for (p2 = p; *p2; p2++);
for (; p2 < p + pad; p2++)
putchar (pad0 ? '0' : ' ');
while (*p)
putchar (*p++);
break;
default:
putchar (*((int *) arg++));
break;
}
}
}
}
-274
View File
@@ -1,274 +0,0 @@
/* multiboot.h - Multiboot header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MULTIBOOT_HEADER
#define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 8192
#define MULTIBOOT_HEADER_ALIGN 4
/* The magic field should contain this. */
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
/* This should be in %eax. */
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000004
/* Flags set in the 'flags' member of the multiboot header. */
/* Align all boot modules on i386 page (4KB) boundaries. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001
/* Must pass memory information to OS. */
#define MULTIBOOT_MEMORY_INFO 0x00000002
/* Must pass video information to OS. */
#define MULTIBOOT_VIDEO_MODE 0x00000004
/* This flag indicates the use of the address fields in the header. */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
/* Flags to be set in the 'flags' member of the multiboot info structure. */
/* is there basic lower/upper memory information? */
#define MULTIBOOT_INFO_MEMORY 0x00000001
/* is there a boot device set? */
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
/* is the command-line defined? */
#define MULTIBOOT_INFO_CMDLINE 0x00000004
/* are there modules to do something with? */
#define MULTIBOOT_INFO_MODS 0x00000008
/* These next two are mutually exclusive */
/* is there a symbol table loaded? */
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
/* is there an ELF section header table? */
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
/* is there a full memory map? */
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
/* Is there drive info? */
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
/* Is there a config table? */
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
/* Is there a boot loader name? */
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
/* Is there a APM table? */
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
/* Is there video information? */
#define MULTIBOOT_INFO_VBE_INFO 0x00000800
#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
#ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* Feature flags. */
multiboot_uint32_t flags;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
multiboot_uint32_t entry_addr;
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
multiboot_uint32_t mode_type;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
/* The symbol table for a.out. */
struct multiboot_aout_symbol_table
{
multiboot_uint32_t tabsize;
multiboot_uint32_t strsize;
multiboot_uint32_t addr;
multiboot_uint32_t reserved;
};
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
/* The section header table for ELF. */
struct multiboot_elf_section_header_table
{
multiboot_uint32_t num;
multiboot_uint32_t size;
multiboot_uint32_t addr;
multiboot_uint32_t shndx;
};
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
struct multiboot_info
{
/* Multiboot info version number */
multiboot_uint32_t flags;
/* Available memory from BIOS */
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
/* "root" partition */
multiboot_uint32_t boot_device;
/* Kernel command line */
multiboot_uint32_t cmdline;
/* Boot-Module list */
multiboot_uint32_t mods_count;
multiboot_uint32_t mods_addr;
union
{
multiboot_aout_symbol_table_t aout_sym;
multiboot_elf_section_header_table_t elf_sec;
} u;
/* Memory Mapping buffer */
multiboot_uint32_t mmap_length;
multiboot_uint32_t mmap_addr;
/* Drive Info buffer */
multiboot_uint32_t drives_length;
multiboot_uint32_t drives_addr;
/* ROM configuration table */
multiboot_uint32_t config_table;
/* Boot Loader Name */
multiboot_uint32_t boot_loader_name;
/* APM table */
multiboot_uint32_t apm_table;
/* Video */
multiboot_uint32_t vbe_control_info;
multiboot_uint32_t vbe_mode_info;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
union
{
struct
{
multiboot_uint32_t framebuffer_palette_addr;
multiboot_uint16_t framebuffer_palette_num_colors;
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
typedef struct multiboot_info multiboot_info_t;
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint32_t size;
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
} __attribute__((packed));
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_mod_list
{
/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
/* Module command line */
multiboot_uint32_t cmdline;
/* padding to take it to 16 bytes (must be zero) */
multiboot_uint32_t pad;
};
typedef struct multiboot_mod_list multiboot_module_t;
/* APM BIOS info. */
struct multiboot_apm_info
{
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
#endif /* ! ASM_FILE */
#endif /* ! MULTIBOOT_HEADER */
-1316
View File
File diff suppressed because it is too large. Load diff
+3
View File
@@ -0,0 +1,3 @@
.deps
Makefile
*.info*
+45
View File
@@ -0,0 +1,45 @@
info_TEXINFOS = grub.texi
grub_TEXINFOS = internals.texi fdl.texi
man_MANS = grub.8 grub-install.8 grub-md5-crypt.8 grub-terminfo.8
HELP2MAN = help2man
SRC2TEXI = src2texi
noinst_SCRIPTS = $(HELP2MAN) $(SRC2TEXI)
EXTRA_DIST = menu.lst $(man_MANS) $(noinst_SCRIPTS)
CLEANFILES = $(noinst_PROGRAMS)
# Cancel the rule %.texi -> %. This rule may confuse make to determine
# the dependecies.
.texi:
%.c.texi: %.c $(srcdir)/$(SRC2TEXI)
$(SHELL) $(srcdir)/$(SRC2TEXI) $(srcdir) $< $@
%.h.texi: %.h $(srcdir)/$(SRC2TEXI)
$(SHELL) $(srcdir)/$(SRC2TEXI) $(srcdir) $< $@
%.S.texi: %.S $(srcdir)/$(SRC2TEXI)
$(SHELL) $(srcdir)/$(SRC2TEXI) $(srcdir) $< $@
if MAINTAINER_MODE
$(srcdir)/grub.8: ../grub/grub $(srcdir)/$(HELP2MAN)
$(PERL) $(srcdir)/$(HELP2MAN) --name="the grub shell" \
--section=8 --output=$@ $<
$(srcdir)/grub-install.8: ../util/grub-install $(srcdir)/$(HELP2MAN)
chmod 755 $<
$(PERL) $(srcdir)/$(HELP2MAN) --name="install GRUB on your drive" \
--section=8 --output=$@ $<
$(srcdir)/grub-md5-crypt.8: ../util/grub-md5-crypt $(srcdir)/$(HELP2MAN)
chmod 755 $<
$(PERL) $(srcdir)/$(HELP2MAN) \
--name="Encrypt a password in MD5 format" \
--section=8 --output=$@ $<
$(srcdir)/grub-terminfo.8: ../util/grub-terminfo $(srcdir)/$(HELP2MAN)
chmod 755 $<
$(PERL) $(srcdir)/$(HELP2MAN) \
--name="Generate a terminfo command from a terminfo name" \
--section=8 --output=$@ $<
endif
+452
View File
@@ -0,0 +1,452 @@
@node GNU Free Documentation License
@appendixsec GNU Free Documentation License
@cindex FDL, GNU Free Documentation License
@center Version 1.2, November 2002
@display
Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@end display
@enumerate 0
@item
PREAMBLE
The purpose of this License is to make a manual, textbook, or other
functional and useful document @dfn{free} in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.
This License is a kind of ``copyleft'', which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
@item
APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The ``Document'', below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as ``you''. You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.
A ``Modified Version'' of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.
A ``Secondary Section'' is a named appendix or a front-matter section
of the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall
subject (or to related matters) and contains nothing that could fall
directly within that overall subject. (Thus, if the Document is in
part a textbook of mathematics, a Secondary Section may not explain
any mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.
The ``Invariant Sections'' are certain Secondary Sections whose titles
are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.
The ``Cover Texts'' are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.
A ``Transparent'' copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not ``Transparent'' is called ``Opaque''.
Examples of suitable formats for Transparent copies include plain
@sc{ascii} without markup, Texinfo input format, La@TeX{} input
format, @acronym{SGML} or @acronym{XML} using a publicly available
@acronym{DTD}, and standard-conforming simple @acronym{HTML},
PostScript or @acronym{PDF} designed for human modification. Examples
of transparent image formats include @acronym{PNG}, @acronym{XCF} and
@acronym{JPG}. Opaque formats include proprietary formats that can be
read and edited only by proprietary word processors, @acronym{SGML} or
@acronym{XML} for which the @acronym{DTD} and/or processing tools are
not generally available, and the machine-generated @acronym{HTML},
PostScript or @acronym{PDF} produced by some word processors for
output purposes only.
The ``Title Page'' means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, ``Title Page'' means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
A section ``Entitled XYZ'' means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as ``Acknowledgements'',
``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
of such a section when you modify the Document means that it remains a
section ``Entitled XYZ'' according to this definition.
The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.
@item
VERBATIM COPYING
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.
@item
COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
If you publish or distribute Opaque copies of the Document numbering
more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give
them a chance to provide you with an updated version of the Document.
@item
MODIFICATIONS
You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:
@enumerate A
@item
Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
@item
List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
@item
State on the Title page the name of the publisher of the
Modified Version, as the publisher.
@item
Preserve all the copyright notices of the Document.
@item
Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
@item
Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
@item
Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
@item
Include an unaltered copy of this License.
@item
Preserve the section Entitled ``History'', Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled ``History'' in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
@item
Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the ``History'' section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
@item
For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
the Title of the section, and preserve in the section all the
substance and tone of each of the contributor acknowledgements and/or
dedications given therein.
@item
Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
@item
Delete any section Entitled ``Endorsements''. Such a section
may not be included in the Modified Version.
@item
Do not retitle any existing section to be Entitled ``Endorsements'' or
to conflict in title with any Invariant Section.
@item
Preserve any Warranty Disclaimers.
@end enumerate
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
You may add a section Entitled ``Endorsements'', provided it contains
nothing but endorsements of your Modified Version by various
parties---for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License
give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.
@item
COMBINING DOCUMENTS
You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled ``History''
in the various original documents, forming one section Entitled
``History''; likewise combine any sections Entitled ``Acknowledgements'',
and any sections Entitled ``Dedications''. You must delete all
sections Entitled ``Endorsements.''
@item
COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in
the collection, provided that you follow the rules of this License for
verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute
it individually under this License, provided you insert a copy of this
License into the extracted document, and follow this License in all
other respects regarding verbatim copying of that document.
@item
AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate
and independent documents or works, in or on a volume of a storage or
distribution medium, is called an ``aggregate'' if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.
@item
TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.
If a section in the Document is Entitled ``Acknowledgements'',
``Dedications'', or ``History'', the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.
@item
TERMINATION
You may not copy, modify, sublicense, or distribute the Document except
as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document 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.
@item
FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions
of the GNU Free Documentation 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. See
@uref{http://www.gnu.org/copyleft/}.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
License ``or any later version'' applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
@end enumerate
@page
@appendixsubsec ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
license notices just after the title page:
@smallexample
@group
Copyright (C) @var{year} @var{your name}.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled ``GNU
Free Documentation License''.
@end group
@end smallexample
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the ``with...Texts.'' line with this:
@smallexample
@group
with the Invariant Sections being @var{list their titles}, with
the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
being @var{list}.
@end group
@end smallexample
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.
@c Local Variables:
@c ispell-local-pdict: "ispell-dict"
@c End:
+52
View File
@@ -0,0 +1,52 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
.TH GRUB-INSTALL "8" "June 2006" "grub-install (GNU GRUB 0.97)" FSF
.SH NAME
grub-install \- install GRUB on your drive
.SH SYNOPSIS
.B grub-install
[\fIOPTION\fR] \fIinstall_device\fR
.SH DESCRIPTION
Install GRUB on your drive.
.TP
\fB\-h\fR, \fB\-\-help\fR
print this message and exit
.TP
\fB\-v\fR, \fB\-\-version\fR
print the version information and exit
.TP
\fB\-\-root\-directory\fR=\fIDIR\fR
install GRUB images under the directory DIR
instead of the root directory
.TP
\fB\-\-grub\-shell\fR=\fIFILE\fR
use FILE as the grub shell
.TP
\fB\-\-no\-floppy\fR
do not probe any floppy drive
.TP
\fB\-\-force\-lba\fR
force GRUB to use LBA mode even for a buggy
BIOS
.TP
\fB\-\-recheck\fR
probe a device map even if it already exists
.PP
INSTALL_DEVICE can be a GRUB device name or a system device filename.
.PP
grub-install copies GRUB images into the DIR/boot directory specfied by
\fB\-\-root\-directory\fR, and uses the grub shell to install grub into the boot
sector.
.SH "REPORTING BUGS"
Report bugs to <bug-grub@gnu.org>.
.SH "SEE ALSO"
The full documentation for
.B grub-install
is maintained as a Texinfo manual. If the
.B info
and
.B grub-install
programs are properly installed at your site, the command
.IP
.B info grub-install
.PP
should give you access to the complete manual.
+32
View File
@@ -0,0 +1,32 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
.TH GRUB-MD5-CRYPT "8" "June 2006" "grub-md5-crypt (GNU GRUB )" FSF
.SH NAME
grub-md5-crypt \- Encrypt a password in MD5 format
.SH SYNOPSIS
.B grub-md5-crypt
[\fIOPTION\fR]
.SH DESCRIPTION
Encrypt a password in MD5 format.
.TP
\fB\-h\fR, \fB\-\-help\fR
print this message and exit
.TP
\fB\-v\fR, \fB\-\-version\fR
print the version information and exit
.TP
\fB\-\-grub\-shell\fR=\fIFILE\fR
use FILE as the grub shell
.SH "REPORTING BUGS"
Report bugs to <bug-grub@gnu.org>.
.SH "SEE ALSO"
The full documentation for
.B grub-md5-crypt
is maintained as a Texinfo manual. If the
.B info
and
.B grub-md5-crypt
programs are properly installed at your site, the command
.IP
.B info grub-md5-crypt
.PP
should give you access to the complete manual.
+29
View File
@@ -0,0 +1,29 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
.TH GRUB-TERMINFO "8" "June 2006" "grub-terminfo (GNU GRUB 0.97)" FSF
.SH NAME
grub-terminfo \- Generate a terminfo command from a terminfo name
.SH SYNOPSIS
.B grub-terminfo
\fITERMNAME\fR
.SH DESCRIPTION
Generate a terminfo command from a terminfo name.
.TP
\fB\-h\fR, \fB\-\-help\fR
print this message and exit
.TP
\fB\-v\fR, \fB\-\-version\fR
print the version information and exit
.SH "REPORTING BUGS"
Report bugs to <bug-grub@gnu.org>.
.SH "SEE ALSO"
The full documentation for
.B grub-terminfo
is maintained as a Texinfo manual. If the
.B info
and
.B grub-terminfo
programs are properly installed at your site, the command
.IP
.B info grub-terminfo
.PP
should give you access to the complete manual.
+71
View File
@@ -0,0 +1,71 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
.TH GRUB "8" "June 2006" "grub (GNU GRUB 0.97)" FSF
.SH NAME
grub \- the grub shell
.SH SYNOPSIS
.B grub
[\fIOPTION\fR]...
.SH DESCRIPTION
Enter the GRand Unified Bootloader command shell.
.TP
\fB\-\-batch\fR
turn on batch mode for non-interactive use
.TP
\fB\-\-boot\-drive\fR=\fIDRIVE\fR
specify stage2 boot_drive [default=0x0]
.TP
\fB\-\-config\-file\fR=\fIFILE\fR
specify stage2 config_file [default=/boot/grub/menu.lst]
.TP
\fB\-\-device\-map\fR=\fIFILE\fR
use the device map file FILE
.TP
\fB\-\-help\fR
display this message and exit
.TP
\fB\-\-hold\fR
wait until a debugger will attach
.TP
\fB\-\-install\-partition\fR=\fIPAR\fR
specify stage2 install_partition [default=0x20000]
.TP
\fB\-\-no\-config\-file\fR
do not use the config file
.TP
\fB\-\-no\-curses\fR
do not use curses
.TP
\fB\-\-no\-floppy\fR
do not probe any floppy drive
.TP
\fB\-\-no\-pager\fR
do not use internal pager
.TP
\fB\-\-preset\-menu\fR
use the preset menu
.TP
\fB\-\-probe\-second\-floppy\fR
probe the second floppy drive
.TP
\fB\-\-read\-only\fR
do not write anything to devices
.TP
\fB\-\-verbose\fR
print verbose messages
.TP
\fB\-\-version\fR
print version information and exit
.SH "REPORTING BUGS"
Report bugs to <bug-grub@gnu.org>.
.SH "SEE ALSO"
The full documentation for
.B grub
is maintained as a Texinfo manual. If the
.B info
and
.B grub
programs are properly installed at your site, the command
.IP
.B info grub
.PP
should give you access to the complete manual.
+3955
View File
File diff suppressed because it is too large. Load diff
+517
View File
@@ -0,0 +1,517 @@
#!/usr/bin/perl -w
# Generate a short man page from --help and --version output.
# Copyright © 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
# 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Written by Brendan O'Dea <bod@compusol.com.au>
# Available from ftp://ftp.gnu.org/gnu/help2man/
use 5.004;
use strict;
use Getopt::Long;
use Text::Tabs qw(expand);
use POSIX qw(strftime setlocale LC_TIME);
my $this_program = 'help2man';
my $this_version = '1.23';
my $version_info = <<EOT;
GNU $this_program $this_version
Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Brendan O'Dea <bod\@compusol.com.au>
EOT
my $help_info = <<EOT;
`$this_program' generates a man page out of `--help' and `--version' output.
Usage: $this_program [OPTION]... EXECUTABLE
-n, --name=STRING use `STRING' as the description for the NAME paragraph
-s, --section=SECTION use `SECTION' as the section for the man page
-i, --include=FILE include material from `FILE'
-I, --opt-include=FILE include material from `FILE' if it exists
-o, --output=FILE send output to `FILE'
-N, --no-info suppress pointer to Texinfo manual
--help print this help, then exit
--version print version number, then exit
EXECUTABLE should accept `--help' and `--version' options.
Report bugs to <bug-help2man\@gnu.org>.
EOT
my $section = 1;
my ($opt_name, @opt_include, $opt_output, $opt_no_info);
# Parse options.
Getopt::Long::config('bundling');
GetOptions (
'n|name=s' => \$opt_name,
's|section=s' => \$section,
'i|include=s' => sub { push @opt_include, [ pop, 1 ] },
'I|opt-include=s' => sub { push @opt_include, [ pop, 0 ] },
'o|output=s' => \$opt_output,
'N|no-info' => \$opt_no_info,
help => sub { print $help_info; exit },
version => sub { print $version_info; exit },
) or die $help_info;
die $help_info unless @ARGV == 1;
my %include = ();
my %append = ();
my @include = (); # retain order given in include file
# Provide replacement `quote-regex' operator for pre-5.005.
BEGIN { eval q(sub qr { '' =~ $_[0]; $_[0] }) if $] < 5.005 }
# Process include file (if given). Format is:
#
# [section name]
# verbatim text
#
# or
#
# /pattern/
# verbatim text
#
for (@opt_include)
{
my ($inc, $required) = @$_;
next unless -f $inc or $required;
die "$this_program: can't open `$inc' ($!)\n"
unless open INC, $inc;
my $key;
my $hash = \%include;
while (<INC>)
{
# [section]
if (/^\[([^]]+)\]/)
{
$key = uc $1;
$key =~ s/^\s+//;
$key =~ s/\s+$//;
$hash = \%include;
push @include, $key unless $include{$key};
next;
}
# /pattern/
if (m!^/(.*)/([ims]*)!)
{
my $pat = $2 ? "(?$2)$1" : $1;
# Check pattern.
eval { $key = qr($pat) };
if ($@)
{
$@ =~ s/ at .*? line \d.*//;
die "$inc:$.:$@";
}
$hash = \%append;
next;
}
# Silently ignore anything before the first
# section--allows for comments and revision info.
next unless $key;
$hash->{$key} ||= '';
$hash->{$key} .= $_;
}
close INC;
die "$this_program: no valid information found in `$inc'\n"
unless $key;
}
# Compress trailing blank lines.
for my $hash (\(%include, %append))
{
for (keys %$hash) { $hash->{$_} =~ s/\n+$/\n/ }
}
# Turn off localisation of executable's ouput.
@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
# Turn off localisation of date (for strftime).
setlocale LC_TIME, 'C';
# Grab help and version info from executable.
my ($help_text, $version_text) = map {
join '', map { s/ +$//; expand $_ } `$ARGV[0] --$_ 2>/dev/null`
or die "$this_program: can't get `--$_' info from $ARGV[0]\n"
} qw(help version);
my $date = strftime "%B %Y", localtime;
(my $program = $ARGV[0]) =~ s!.*/!!;
my $package = $program;
my $version;
if ($opt_output)
{
unlink $opt_output
or die "$this_program: can't unlink $opt_output ($!)\n"
if -e $opt_output;
open STDOUT, ">$opt_output"
or die "$this_program: can't create $opt_output ($!)\n";
}
# The first line of the --version information is assumed to be in one
# of the following formats:
#
# <version>
# <program> <version>
# {GNU,Free} <program> <version>
# <program> ({GNU,Free} <package>) <version>
# <program> - {GNU,Free} <package> <version>
#
# and seperated from any copyright/author details by a blank line.
($_, $version_text) = split /\n+/, $version_text, 2;
if (/^(\S+) +\(((?:GNU|Free) +[^)]+)\) +(.*)/ or
/^(\S+) +- *((?:GNU|Free) +\S+) +(.*)/)
{
$program = $1;
$package = $2;
$version = $3;
}
elsif (/^((?:GNU|Free) +)?(\S+) +(.*)/)
{
$program = $2;
$package = $1 ? "$1$2" : $2;
$version = $3;
}
else
{
$version = $_;
}
$program =~ s!.*/!!;
# No info for `info' itself.
$opt_no_info = 1 if $program eq 'info';
# --name overrides --include contents.
$include{NAME} = "$program \\- $opt_name\n" if $opt_name;
# Default (useless) NAME paragraph.
$include{NAME} ||= "$program \\- manual page for $program $version\n";
# Man pages traditionally have the page title in caps.
my $PROGRAM = uc $program;
# Extract usage clause(s) [if any] for SYNOPSIS.
if ($help_text =~ s/^Usage:( +(\S+))(.*)((?:\n(?: {6}\1| *or: +\S).*)*)//m)
{
my @syn = $2 . $3;
if ($_ = $4)
{
s/^\n//;
for (split /\n/) { s/^ *(or: +)?//; push @syn, $_ }
}
my $synopsis = '';
for (@syn)
{
$synopsis .= ".br\n" if $synopsis;
s!^\S*/!!;
s/^(\S+) *//;
$synopsis .= ".B $1\n";
s/\s+$//;
s/(([][]|\.\.+)+)/\\fR$1\\fI/g;
s/^/\\fI/ unless s/^\\fR//;
$_ .= '\fR';
s/(\\fI)( *)/$2$1/g;
s/\\fI\\fR//g;
s/^\\fR//;
s/\\fI$//;
s/^\./\\&./;
$synopsis .= "$_\n";
}
$include{SYNOPSIS} ||= $synopsis;
}
# Process text, initial section is DESCRIPTION.
my $sect = 'DESCRIPTION';
$_ = "$help_text\n\n$version_text";
# Normalise paragraph breaks.
s/^\n+//;
s/\n*$/\n/;
s/\n\n+/\n\n/g;
# Temporarily exchange leading dots, apostrophes and backslashes for
# tokens.
s/^\./\x80/mg;
s/^'/\x81/mg;
s/\\/\x82/g;
# Start a new paragraph (if required) for these.
s/([^\n])\n(Report +bugs|Email +bug +reports +to|Written +by)/$1\n\n$2/g;
sub convert_option;
while (length)
{
# Convert some standard paragraph names.
if (s/^(Options|Examples): *\n//)
{
$sect = uc $1;
next;
}
# Copyright section
if (/^Copyright +[(\xa9]/)
{
$sect = 'COPYRIGHT';
$include{$sect} ||= '';
$include{$sect} .= ".PP\n" if $include{$sect};
my $copy;
($copy, $_) = split /\n\n/, $_, 2;
for ($copy)
{
# Add back newline
s/\n*$/\n/;
# Convert iso9959-1 copyright symbol or (c) to nroff
# character.
s/^Copyright +(?:\xa9|\([Cc]\))/Copyright \\(co/mg;
# Insert line breaks before additional copyright messages
# and the disclaimer.
s/(.)\n(Copyright |This +is +free +software)/$1\n.br\n$2/g;
# Join hyphenated lines.
s/([A-Za-z])-\n */$1/g;
}
$include{$sect} .= $copy;
$_ ||= '';
next;
}
# Catch bug report text.
if (/^(Report +bugs|Email +bug +reports +to) /)
{
$sect = 'REPORTING BUGS';
}
# Author section.
elsif (/^Written +by/)
{
$sect = 'AUTHOR';
}
# Examples, indicated by an indented leading $, % or > are
# rendered in a constant width font.
if (/^( +)([\$\%>] )\S/)
{
my $indent = $1;
my $prefix = $2;
my $break = '.IP';
$include{$sect} ||= '';
while (s/^$indent\Q$prefix\E(\S.*)\n*//)
{
$include{$sect} .= "$break\n\\f(CW$prefix$1\\fR\n";
$break = '.br';
}
next;
}
my $matched = '';
$include{$sect} ||= '';
# Sub-sections have a trailing colon and the second line indented.
if (s/^(\S.*:) *\n / /)
{
$matched .= $& if %append;
$include{$sect} .= qq(.SS "$1"\n);
}
my $indent = 0;
my $content = '';
# Option with description.
if (s/^( {1,10}([+-]\S.*?))(?:( +)|\n( {20,}))(\S.*)\n//)
{
$matched .= $& if %append;
$indent = length ($4 || "$1$3");
$content = ".TP\n\x83$2\n\x83$5\n";
unless ($4)
{
# Indent may be different on second line.
$indent = length $& if /^ {20,}/;
}
}
# Option without description.
elsif (s/^ {1,10}([+-]\S.*)\n//)
{
$matched .= $& if %append;
$content = ".HP\n\x83$1\n";
$indent = 80; # not continued
}
# Indented paragraph with tag.
elsif (s/^( +(\S.*?) +)(\S.*)\n//)
{
$matched .= $& if %append;
$indent = length $1;
$content = ".TP\n\x83$2\n\x83$3\n";
}
# Indented paragraph.
elsif (s/^( +)(\S.*)\n//)
{
$matched .= $& if %append;
$indent = length $1;
$content = ".IP\n\x83$2\n";
}
# Left justified paragraph.
else
{
s/(.*)\n//;
$matched .= $& if %append;
$content = ".PP\n" if $include{$sect};
$content .= "$1\n";
}
# Append continuations.
while (s/^ {$indent}(\S.*)\n//)
{
$matched .= $& if %append;
$content .= "\x83$1\n"
}
# Move to next paragraph.
s/^\n+//;
for ($content)
{
# Leading dot and apostrophe protection.
s/\x83\./\x80/g;
s/\x83'/\x81/g;
s/\x83//g;
# Convert options.
s/(^| )(-[][\w=-]+)/$1 . convert_option $2/mge;
}
# Check if matched paragraph contains /pat/.
if (%append)
{
for my $pat (keys %append)
{
if ($matched =~ $pat)
{
$content .= ".PP\n" unless $append{$pat} =~ /^\./;
$content .= $append{$pat};
}
}
}
$include{$sect} .= $content;
}
# Refer to the real documentation.
unless ($opt_no_info)
{
$sect = 'SEE ALSO';
$include{$sect} ||= '';
$include{$sect} .= ".PP\n" if $include{$sect};
$include{$sect} .= <<EOT;
The full documentation for
.B $program
is maintained as a Texinfo manual. If the
.B info
and
.B $program
programs are properly installed at your site, the command
.IP
.B info $program
.PP
should give you access to the complete manual.
EOT
}
# Output header.
print <<EOT;
.\\" DO NOT MODIFY THIS FILE! It was generated by $this_program $this_version.
.TH $PROGRAM "$section" "$date" "$package $version" FSF
EOT
# Section ordering.
my @pre = qw(NAME SYNOPSIS DESCRIPTION OPTIONS EXAMPLES);
my @post = ('AUTHOR', 'REPORTING BUGS', 'COPYRIGHT', 'SEE ALSO');
my $filter = join '|', @pre, @post;
# Output content.
for (@pre, (grep ! /^($filter)$/o, @include), @post)
{
if ($include{$_})
{
my $quote = /\W/ ? '"' : '';
print ".SH $quote$_$quote\n";
for ($include{$_})
{
# Replace leading dot, apostrophe and backslash tokens.
s/\x80/\\&./g;
s/\x81/\\&'/g;
s/\x82/\\e/g;
print;
}
}
}
exit;
# Convert option dashes to \- to stop nroff from hyphenating 'em, and
# embolden. Option arguments get italicised.
sub convert_option
{
local $_ = '\fB' . shift;
s/-/\\-/g;
unless (s/\[=(.*)\]$/\\fR[=\\fI$1\\fR]/)
{
s/=(.)/\\fR=\\fI$1/;
s/ (.)/ \\fI$1/;
$_ .= '\fR';
}
$_;
}
+427
View File
@@ -0,0 +1,427 @@
@node Internals
@appendix Hacking GRUB
This chapter documents the user-invisible aspect of GRUB.
As a general rule of software development, it is impossible to keep the
descriptions of the internals up-to-date, and it is quite hard to
document everything. So refer to the source code, whenever you are not
satisfied with this documentation. Please assume that this gives just
hints to you.
@menu
* Memory map:: The memory map of various components
* Embedded data:: Embedded variables in GRUB
* Filesystem interface:: The generic interface for filesystems
* Command interface:: The generic interface for built-ins
* Bootstrap tricks:: The bootstrap mechanism used in GRUB
* I/O ports detection:: How to probe I/O ports used by INT 13H
* Memory detection:: How to detect all installed RAM
* Low-level disk I/O:: INT 13H disk I/O interrupts
* MBR:: The structure of Master Boot Record
* Partition table:: The format of partition tables
* Submitting patches:: Where and how you should send patches
@end menu
@node Memory map
@section The memory map of various components
GRUB consists of two distinct components, called @dfn{stages}, which are
loaded at different times in the boot process. Because they run
mutual-exclusively, sometimes a memory area overlaps with another
memory area. And, even in one stage, a single memory area can be used
for various purposes, because their usages are mutually exclusive.
Here is the memory map of the various components:
@table @asis
@item 0 to 4K-1
BIOS and real mode interrupts
@item 0x07BE to 0x07FF
Partition table passed to another boot loader
@item down from 8K-1
Real mode stack
@item 0x2000 to ?
The optional Stage 1.5 is loaded here
@item 0x2000 to 0x7FFF
Command-line buffer for Multiboot kernels and modules
@item 0x7C00 to 0x7DFF
Stage 1 is loaded here by BIOS or another boot loader
@item 0x7F00 to 0x7F42
LBA drive parameters
@item 0x8000 to ?
Stage2 is loaded here
@item The end of Stage 2 to 416K-1
Heap, in particular used for the menu
@item down from 416K-1
Protected mode stack
@item 416K to 448K-1
Filesystem buffer
@item 448K to 479.5K-1
Raw device buffer
@item 479.5K to 480K-1
512-byte scratch area
@item 480K to 512K-1
Buffers for various functions, such as password, command-line, cut and
paste, and completion.
@item The last 1K of lower memory
Disk swapping code and data
@end table
See the file @file{stage2/shared.h}, for more information.
@node Embedded data
@section Embedded variables in GRUB
Stage 1 and Stage 2 have embedded variables whose locations are
well-defined, so that the installation can patch the binary file
directly without recompilation of the stages.
In Stage 1, these are defined:
@table @code
@item 0x3E
The version number (not GRUB's, but the installation mechanism's).
@item 0x40
The boot drive. If it is 0xFF, use a drive passed by BIOS.
@item 0x41
The flag for if forcing LBA.
@item 0x42
The starting address of Stage 2.
@item 0x44
The first sector of Stage 2.
@item 0x48
The starting segment of Stage 2.
@item 0x1FE
The signature (@code{0xAA55}).
@end table
See the file @file{stage1/stage1.S}, for more information.
In the first sector of Stage 1.5 and Stage 2, the blocklists are
recorded between @code{firstlist} and @code{lastlist}. The address of
@code{lastlist} is determined when assembling the file
@file{stage2/start.S}.
The trick here is that it is actually read backward, and the first
8-byte blocklist is not read here, but after the pointer is decremented
8 bytes, then after reading it, it decrements again, reads, and so on,
until it is finished. The terminating condition is when the number of
sectors to be read in the next blocklist is zero.
The format of a blocklist can be seen from the example in the code just
before the @code{firstlist} label. Note that it is always from the
beginning of the disk, but @emph{not} relative to the partition
boundaries.
In the second sector of Stage 1.5 and Stage 2, these are defined:
@table @asis
@item @code{0x6}
The version number (likewise, the installation mechanism's).
@item @code{0x8}
The installed partition.
@item @code{0xC}
The saved entry number.
@item @code{0x10}
The identifier.
@item @code{0x11}
The flag for if forcing LBA.
@item @code{0x12}
The version string (GRUB's).
@item @code{0x12} + @dfn{the length of the version string}
The name of a configuration file.
@end table
See the file @file{stage2/asm.S}, for more information.
@node Filesystem interface
@section The generic interface for filesystems
For any particular partition, it is presumed that only one of the
@dfn{normal} filesystems such as FAT, FFS, or ext2fs can be used, so
there is a switch table managed by the functions in
@file{disk_io.c}. The notation is that you can only @dfn{mount} one at a
time.
The blocklist filesystem has a special place in the system. In addition
to the @dfn{normal} filesystem (or even without one mounted), you can
access disk blocks directly (in the indicated partition) via the block
list notation. Using the blocklist filesystem doesn't effect any other
filesystem mounts.
The variables which can be read by the filesystem backend are:
@vtable @code
@item current_drive
The current BIOS drive number (numbered from 0, if a floppy, and
numbered from 0x80, if a hard disk).
@item current_partition
The current partition number.
@item current_slice
The current partition type.
@item saved_drive
The @dfn{drive} part of the root device.
@item saved_partition
The @dfn{partition} part of the root device.
@item part_start
The current partition starting address, in sectors.
@item part_length
The current partition length, in sectors.
@item print_possibilities
True when the @code{dir} function should print the possible completions
of a file, and false when it should try to actually open a file of that
name.
@item FSYS_BUF
Filesystem buffer which is 32K in size, to use in any way which the
filesystem backend desires.
@end vtable
The variables which need to be written by a filesystem backend are:
@vtable @code
@item filepos
The current position in the file, in sectors.
@strong{Caution:} the value of @var{filepos} can be changed out from
under the filesystem code in the current implementation. Don't depend on
it being the same for later calls into the backend code!
@item filemax
The length of the file.
@item disk_read_func
The value of @var{disk_read_hook} @emph{only} during reading of data
for the file, not any other fs data, inodes, FAT tables, whatever, then
set to @code{NULL} at all other times (it will be @code{NULL} by
default). If this isn't done correctly, then the @command{testload} and
@command{install} commands won't work correctly.
@end vtable
The functions expected to be used by the filesystem backend are:
@ftable @code
@item devread
Only read sectors from within a partition. Sector 0 is the first sector
in the partition.
@item grub_read
If the backend uses the blocklist code, then @code{grub_read} can be
used, after setting @var{block_file} to 1.
@item print_a_completion
If @var{print_possibilities} is true, call @code{print_a_completion} for
each possible file name. Otherwise, the file name completion won't work.
@end ftable
The functions expected to be defined by the filesystem backend are
described at least moderately in the file @file{filesys.h}. Their usage
is fairly evident from their use in the functions in @file{disk_io.c},
look for the use of the @var{fsys_table} array.
@strong{Caution:} The semantics are such that then @samp{mount}ing the
filesystem, presume the filesystem buffer @code{FSYS_BUF} is corrupted,
and (re-)load all important contents. When opening and reading a file,
presume that the data from the @samp{mount} is available, and doesn't
get corrupted by the open/read (i.e. multiple opens and/or reads will be
done with only one mount if in the same filesystem).
@node Command interface
@section The generic interface for built-ins
GRUB built-in commands are defined in a uniform interface, whether
they are menu-specific or can be used anywhere. The definition of a
built-in command consists of two parts: the code itself and the table of
the information.
The code must be a function which takes two arguments, a command-line
string and flags, and returns an @samp{int} value. The @dfn{flags}
argument specifies how the function is called, using a bit mask. The
return value must be zero if successful, otherwise non-zero. So it is
normally enough to return @var{errnum}.
The table of the information is represented by the structure
@code{struct builtin}, which contains the name of the command, a pointer
to the function, flags, a short description of the command and a long
description of the command. Since the descriptions are used only for
help messages interactively, you don't have to define them, if the
command may not be called interactively (such as @command{title}).
The table is finally registered in the table @var{builtin_table}, so
that @code{run_script} and @code{enter_cmdline} can find the
command. See the files @file{cmdline.c} and @file{builtins.c}, for more
details.
@node Bootstrap tricks
@section The bootstrap mechanism used in GRUB
The disk space can be used in a boot loader is very restricted because
a MBR (@pxref{MBR}) is only 512 bytes but it also contains a partition
table (@pxref{Partition table}) and a BPB. So the question is how to
make a boot loader code enough small to be fit in a MBR.
However, GRUB is a very large program, so we break GRUB into 2 (or 3)
distinct components, @dfn{Stage 1} and @dfn{Stage 2} (and optionally
@dfn{Stage 1.5}). @xref{Memory map}, for more information.
We embed Stage 1 in a MBR or in the boot sector of a partition, and
place Stage 2 in a filesystem. The optional Stage 1.5 can be installed
in a filesystem, in the @dfn{boot loader} area in a FFS or a ReiserFS,
and in the sectors right after a MBR, because Stage 1.5 is enough small
and the sectors right after a MBR is normally an unused region. The size
of this region is the number of sectors per head minus 1.
Thus, all Stage1 must do is just load Stage2 or Stage1.5. But even if
Stage 1 needs not to support the user interface or the filesystem
interface, it is impossible to make Stage 1 less than 400 bytes, because
GRUB should support both the CHS mode and the LBA mode (@pxref{Low-level
disk I/O}).
The solution used by GRUB is that Stage 1 loads only the first sector of
Stage 2 (or Stage 1.5) and Stage 2 itself loads the rest. The flow of
Stage 1 is:
@enumerate
@item
Initialize the system briefly.
@item
Detect the geometry and the accessing mode of the @dfn{loading drive}.
@item
Load the first sector of Stage 2.
@item
Jump to the starting address of the Stage 2.
@end enumerate
The flow of Stage 2 (and Stage 1.5) is:
@enumerate
@item
Load the rest of itself to the real starting address, that is, the
starting address plus 512 bytes. The blocklists are stored in the last
part of the first sector.
@item
Long jump to the real starting address.
@end enumerate
Note that Stage 2 (or Stage 1.5) does not probe the geometry
or the accessing mode of the @dfn{loading drive}, since Stage 1 has
already probed them.
@node I/O ports detection
@section How to probe I/O ports used by INT 13H
FIXME: I will write this chapter after implementing the new technique.
@node Memory detection
@section How to detect all installed RAM
FIXME: I doubt if Erich didn't write this chapter only himself wholly,
so I will rewrite this chapter.
@node Low-level disk I/O
@section INT 13H disk I/O interrupts
FIXME: I'm not sure where some part of the original chapter is derived,
so I will rewrite this chapter.
@node MBR
@section The structure of Master Boot Record
FIXME: Likewise.
@node Partition table
@section The format of partition tables
FIXME: Probably the original chapter is derived from "How It Works", so
I will rewrite this chapter.
@node Submitting patches
@section Where and how you should send patches
When you write patches for GRUB, please send them to the mailing list
@email{bug-grub@@gnu.org}. Here is the list of items of which you
should take care:
@itemize @bullet
@item
Please make your patch as small as possible. Generally, it is not a good
thing to make one big patch which changes many things. Instead,
segregate features and produce many patches.
@item
Use as late code as possible, for the original code. The CVS repository
always has the current version (@pxref{Obtaining and Building GRUB}).
@item
Write ChangeLog entries. @xref{Change Logs, , Change Logs, standards,
GNU Coding Standards}, if you don't know how to write ChangeLog.
@item
Make patches in unified diff format. @samp{diff -urN} is appropriate in
most cases.
@item
Don't make patches reversely. Reverse patches are difficult to read and
use.
@item
Be careful enough of the license term and the copyright. Because GRUB
is under GNU General Public License, you may not steal code from
software whose license is incompatible against GPL. And, if you copy
code written by others, you must not ignore their copyrights. Feel free
to ask GRUB maintainers, whenever you are not sure what you should do.
@item
If your patch is too large to send in e-mail, put it at somewhere we can
see. Usually, you shouldn't send e-mail over 20K.
@end itemize
+82
View File
@@ -0,0 +1,82 @@
#
# Sample boot menu configuration file
#
# Boot automatically after 30 secs.
timeout 30
# By default, boot the first entry.
default 0
# Fallback to the second entry.
fallback 1
# For booting GNU/Hurd
title GNU/Hurd
root (hd0,0)
kernel /boot/gnumach.gz root=hd0s1
module /boot/serverboot.gz
# For booting GNU/Linux
title GNU/Linux
root (hd1,0)
kernel /vmlinuz root=/dev/hdb1
#initrd /initrd.img
# For booting GNU/kFreeBSD
title GNU/kFreeBSD
root (hd0,2,a)
kernel /boot/loader.gz
# For booting GNU/kNetBSD
title GNU/kNetBSD
root (hd0,2,a)
kernel --type=netbsd /boot/knetbsd.gz
# For booting Mach (getting kernel from floppy)
title Utah Mach4 multiboot
root (hd0,2)
pause Insert the diskette now!!
kernel (fd0)/boot/kernel root=hd0s3
module (fd0)/boot/bootstrap
# For booting FreeBSD
title FreeBSD
root (hd0,2,a)
kernel /boot/loader
# For booting NetBSD
title NetBSD
root (hd0,2,a)
kernel --type=netbsd /netbsd
# For booting OpenBSD
title OpenBSD
root (hd0,2,a)
kernel --type=netbsd /bsd
# For booting OS/2
title OS/2
root (hd0,1)
makeactive
# chainload OS/2 bootloader from the first sector
chainloader +1
# This is similar to "chainload", but loads a specific file
#chainloader /boot/chain.os2
# For booting Windows NT or Windows95
title Windows NT / Windows 95 boot menu
rootnoverify (hd0,0)
makeactive
chainloader +1
# For loading DOS if Windows NT is installed
# chainload /bootsect.dos
# For installing GRUB into the hard disk
title Install GRUB into the hard disk
root (hd0,0)
setup (hd0)
# Change the colors.
title Change the colors
color light-green/brown blink-red/blue
View File
File renamed without changes.
+4
View File
@@ -0,0 +1,4 @@
@set UPDATED 8 May 2005
@set UPDATED-MONTH May 2005
@set EDITION 0.97
@set VERSION 0.97
+4
View File
@@ -0,0 +1,4 @@
@set UPDATED 8 May 2005
@set UPDATED-MONTH May 2005
@set EDITION 0.97
@set VERSION 0.97
+3
View File
@@ -0,0 +1,3 @@
.deps
Makefile
grub
+19
View File
@@ -0,0 +1,19 @@
sbin_PROGRAMS = grub
if SERIAL_SPEED_SIMULATION
SERIAL_FLAGS = -DSUPPORT_SERIAL=1 -DSIMULATE_SLOWNESS_OF_SERIAL=1
else
SERIAL_FLAGS = -DSUPPORT_SERIAL=1
endif
AM_CPPFLAGS = -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
-DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \
-DFSYS_UFS2=1 -DFSYS_VSTAFS=1 -DFSYS_XFS=1 \
-DUSE_MD5_PASSWORDS=1 -DSUPPORT_HERCULES=1 \
$(SERIAL_FLAGS) -I$(top_srcdir)/stage2 \
-I$(top_srcdir)/stage1 -I$(top_srcdir)/lib
AM_CFLAGS = $(GRUB_CFLAGS)
grub_SOURCES = main.c asmstub.c
grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS)
+1311
View File
File diff suppressed because it is too large. Load diff
+272
View File
@@ -0,0 +1,272 @@
/* main.c - experimental GRUB stage2 that runs under Unix */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
*
* 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.
*/
/* Simulator entry point. */
int grub_stage2 (void);
#include <stdio.h>
#include <getopt.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <setjmp.h>
#define WITHOUT_LIBC_STUBS 1
#include <shared.h>
#include <term.h>
#include <device.h>
char *program_name = 0;
int use_config_file = 1;
int use_preset_menu = 0;
#ifdef HAVE_LIBCURSES
int use_curses = 1;
#else
int use_curses = 0;
#endif
int verbose = 0;
int read_only = 0;
int floppy_disks = 1;
char *device_map_file = 0;
static int default_boot_drive;
static int default_install_partition;
static char *default_config_file;
#define OPT_HELP -2
#define OPT_VERSION -3
#define OPT_HOLD -4
#define OPT_CONFIG_FILE -5
#define OPT_INSTALL_PARTITION -6
#define OPT_BOOT_DRIVE -7
#define OPT_NO_CONFIG_FILE -8
#define OPT_NO_CURSES -9
#define OPT_BATCH -10
#define OPT_VERBOSE -11
#define OPT_READ_ONLY -12
#define OPT_PROBE_SECOND_FLOPPY -13
#define OPT_NO_FLOPPY -14
#define OPT_DEVICE_MAP -15
#define OPT_PRESET_MENU -16
#define OPT_NO_PAGER -17
#define OPTSTRING ""
static struct option longopts[] =
{
{"batch", no_argument, 0, OPT_BATCH},
{"boot-drive", required_argument, 0, OPT_BOOT_DRIVE},
{"config-file", required_argument, 0, OPT_CONFIG_FILE},
{"device-map", required_argument, 0, OPT_DEVICE_MAP},
{"help", no_argument, 0, OPT_HELP},
{"hold", optional_argument, 0, OPT_HOLD},
{"install-partition", required_argument, 0, OPT_INSTALL_PARTITION},
{"no-config-file", no_argument, 0, OPT_NO_CONFIG_FILE},
{"no-curses", no_argument, 0, OPT_NO_CURSES},
{"no-floppy", no_argument, 0, OPT_NO_FLOPPY},
{"no-pager", no_argument, 0, OPT_NO_PAGER},
{"preset-menu", no_argument, 0, OPT_PRESET_MENU},
{"probe-second-floppy", no_argument, 0, OPT_PROBE_SECOND_FLOPPY},
{"read-only", no_argument, 0, OPT_READ_ONLY},
{"verbose", no_argument, 0, OPT_VERBOSE},
{"version", no_argument, 0, OPT_VERSION},
{0},
};
static void
usage (int status)
{
if (status)
fprintf (stderr, "Try ``grub --help'' for more information.\n");
else
printf ("\
Usage: grub [OPTION]...\n\
\n\
Enter the GRand Unified Bootloader command shell.\n\
\n\
--batch turn on batch mode for non-interactive use\n\
--boot-drive=DRIVE specify stage2 boot_drive [default=0x%x]\n\
--config-file=FILE specify stage2 config_file [default=%s]\n\
--device-map=FILE use the device map file FILE\n\
--help display this message and exit\n\
--hold wait until a debugger will attach\n\
--install-partition=PAR specify stage2 install_partition [default=0x%x]\n\
--no-config-file do not use the config file\n\
--no-curses do not use curses\n\
--no-floppy do not probe any floppy drive\n\
--no-pager do not use internal pager\n\
--preset-menu use the preset menu\n\
--probe-second-floppy probe the second floppy drive\n\
--read-only do not write anything to devices\n\
--verbose print verbose messages\n\
--version print version information and exit\n\
\n\
Report bugs to <bug-grub@gnu.org>.\n\
",
default_boot_drive, default_config_file,
default_install_partition);
exit (status);
}
int
main (int argc, char **argv)
{
int c;
int hold = 0;
/* First of all, call sync so that all in-core data is scheduled to be
actually written to disks. This is very important because GRUB does
not use ordinary stdio interface but raw devices. */
sync ();
program_name = argv[0];
default_boot_drive = boot_drive;
default_install_partition = install_partition;
if (config_file)
default_config_file = config_file;
else
default_config_file = "NONE";
/* Parse command-line options. */
do
{
c = getopt_long (argc, argv, OPTSTRING, longopts, 0);
switch (c)
{
case EOF:
/* Fall through the bottom of the loop. */
break;
case OPT_HELP:
usage (0);
break;
case OPT_VERSION:
printf ("grub (GNU GRUB " VERSION ")\n");
exit (0);
break;
case OPT_HOLD:
if (! optarg)
hold = -1;
else
hold = atoi (optarg);
break;
case OPT_CONFIG_FILE:
strncpy (config_file, optarg, 127); /* FIXME: arbitrary */
config_file[127] = '\0';
break;
case OPT_INSTALL_PARTITION:
install_partition = strtoul (optarg, 0, 0);
if (install_partition == ULONG_MAX)
{
perror ("strtoul");
exit (1);
}
break;
case OPT_BOOT_DRIVE:
boot_drive = strtoul (optarg, 0, 0);
if (boot_drive == ULONG_MAX)
{
perror ("strtoul");
exit (1);
}
if (boot_drive >= NUM_DISKS)
{
fprintf (stderr, "boot_drive should be from 0 to %d\n",
NUM_DISKS - 1);
exit (1);
}
break;
case OPT_NO_CONFIG_FILE:
use_config_file = 0;
break;
case OPT_NO_CURSES:
use_curses = 0;
break;
case OPT_NO_PAGER:
use_pager = 0;
break;
case OPT_BATCH:
/* This is the same as "--no-config-file --no-curses --no-pager". */
use_config_file = 0;
use_curses = 0;
use_pager = 0;
break;
case OPT_READ_ONLY:
read_only = 1;
break;
case OPT_VERBOSE:
verbose = 1;
break;
case OPT_NO_FLOPPY:
floppy_disks = 0;
break;
case OPT_PROBE_SECOND_FLOPPY:
floppy_disks = 2;
break;
case OPT_DEVICE_MAP:
device_map_file = strdup (optarg);
break;
case OPT_PRESET_MENU:
use_preset_menu = 1;
break;
default:
usage (1);
}
}
while (c != EOF);
/* Wait until the HOLD variable is cleared by an attached debugger. */
if (hold && verbose)
printf ("Run \"gdb %s %d\", and set HOLD to zero.\n",
program_name, (int) getpid ());
while (hold)
{
if (hold > 0)
hold--;
sleep (1);
}
/* If we don't have curses (!HAVE_LIBCURSES or --no-curses or
--batch) put terminal to dumb for better handling of line i/o */
if (! use_curses)
current_term->flags = TERM_NO_EDIT | TERM_DUMB;
/* Transfer control to the stage2 simulator. */
exit (grub_stage2 ());
}
+2
View File
@@ -0,0 +1,2 @@
.deps
Makefile
+6
View File
@@ -0,0 +1,6 @@
noinst_LIBRARIES = libcommon.a
AM_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/stage2 \
-I$(top_srcdir)/stage1
libcommon_a_SOURCES = getopt.c getopt1.c getopt.h device.c device.h
+950
View File
@@ -0,0 +1,950 @@
/* device.c - Some helper functions for OS devices and BIOS drives */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
*
* 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.
*/
/* Try to use glibc's transparant LFS support. */
#define _LARGEFILE_SOURCE 1
/* lseek becomes synonymous with lseek64. */
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#ifdef __linux__
# if !defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
/* Maybe libc doesn't have large file support. */
# include <linux/unistd.h> /* _llseek */
# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
# include <sys/ioctl.h> /* ioctl */
# ifndef HDIO_GETGEO
# define HDIO_GETGEO 0x0301 /* get device geometry */
/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
defined. */
struct hd_geometry
{
unsigned char heads;
unsigned char sectors;
unsigned short cylinders;
unsigned long start;
};
# endif /* ! HDIO_GETGEO */
# ifndef FLOPPY_MAJOR
# define FLOPPY_MAJOR 2 /* the major number for floppy */
# endif /* ! FLOPPY_MAJOR */
# ifndef MAJOR
# define MAJOR(dev) \
({ \
unsigned long long __dev = (dev); \
(unsigned) ((__dev >> 8) & 0xfff) \
| ((unsigned int) (__dev >> 32) & ~0xfff); \
})
# endif /* ! MAJOR */
# ifndef CDROM_GET_CAPABILITY
# define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
# endif /* ! CDROM_GET_CAPABILITY */
# ifndef BLKGETSIZE64
# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
# endif /* ! BLKGETSIZE64 */
#endif /* __linux__ */
/* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
#if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
# define __FreeBSD_kernel__
#endif
#ifdef __FreeBSD_kernel__
/* Obtain version of kFreeBSD headers */
# include <osreldate.h>
# ifndef __FreeBSD_kernel_version
# define __FreeBSD_kernel_version __FreeBSD_version
# endif
/* Runtime detection of kernel */
# include <sys/utsname.h>
int
get_kfreebsd_version ()
{
struct utsname uts;
int major; int minor, v[2];
uname (&uts);
sscanf (uts.release, "%d.%d", &major, &minor);
if (major >= 9)
major = 9;
if (major >= 5)
{
v[0] = minor/10; v[1] = minor%10;
}
else
{
v[0] = minor%10; v[1] = minor/10;
}
return major*100000+v[0]*10000+v[1]*1000;
}
#endif /* __FreeBSD_kernel__ */
#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/ioctl.h> /* ioctl */
# include <sys/disklabel.h>
# include <sys/cdio.h> /* CDIOCCLRDEBUG */
# if defined(__FreeBSD_kernel__)
# include <sys/param.h>
# if __FreeBSD_kernel_version >= 500040
# include <sys/disk.h>
# endif
# endif /* __FreeBSD_kernel__ */
#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
#ifdef HAVE_OPENDISK
# include <util.h>
#endif /* HAVE_OPENDISK */
#define WITHOUT_LIBC_STUBS 1
#include <shared.h>
#include <device.h>
/* Get the geometry of a drive DRIVE. */
void
get_drive_geometry (struct geometry *geom, char **map, int drive)
{
int fd;
if (geom->flags == -1)
{
fd = open (map[drive], O_RDONLY);
assert (fd >= 0);
}
else
fd = geom->flags;
/* XXX This is the default size. */
geom->sector_size = SECTOR_SIZE;
#if defined(__linux__)
/* Linux */
{
struct hd_geometry hdg;
unsigned long long nr;
if (ioctl (fd, HDIO_GETGEO, &hdg))
goto fail;
if (ioctl (fd, BLKGETSIZE64, &nr))
goto fail;
/* Got the geometry, so save it. */
geom->cylinders = hdg.cylinders;
geom->heads = hdg.heads;
geom->sectors = hdg.sectors;
geom->total_sectors = nr / 512;
goto success;
}
#elif defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
# if defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040
/* kFreeBSD version 5 or later */
if (get_kfreebsd_version () >= 500040)
{
unsigned int sector_size;
off_t media_size;
unsigned int tmp;
if(ioctl (fd, DIOCGSECTORSIZE, &sector_size) != 0)
sector_size = 512;
if (ioctl (fd, DIOCGMEDIASIZE, &media_size) != 0)
goto fail;
geom->total_sectors = media_size / sector_size;
if (ioctl (fd, DIOCGFWSECTORS, &tmp) == 0)
geom->sectors = tmp;
else
geom->sectors = 63;
if (ioctl (fd, DIOCGFWHEADS, &tmp) == 0)
geom->heads = tmp;
else if (geom->total_sectors <= 63 * 1 * 1024)
geom->heads = 1;
else if (geom->total_sectors <= 63 * 16 * 1024)
geom->heads = 16;
else
geom->heads = 255;
geom->cylinders = (geom->total_sectors
/ geom->heads
/ geom->sectors);
goto success;
}
else
#endif /* defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040 */
/* kFreeBSD < 5, NetBSD or OpenBSD */
{
struct disklabel hdg;
if (ioctl (fd, DIOCGDINFO, &hdg))
goto fail;
geom->cylinders = hdg.d_ncylinders;
geom->heads = hdg.d_ntracks;
geom->sectors = hdg.d_nsectors;
geom->total_sectors = hdg.d_secperunit;
goto success;
}
#else
/* Notably, defined(__GNU__) */
# warning "Automatic detection of geometries will be performed only \
partially. This is not fatal."
#endif
fail:
{
struct stat st;
/* FIXME: It would be nice to somehow compute fake C/H/S settings,
given a proper st_blocks size. */
if (drive & 0x80)
{
geom->cylinders = DEFAULT_HD_CYLINDERS;
geom->heads = DEFAULT_HD_HEADS;
geom->sectors = DEFAULT_HD_SECTORS;
}
else
{
geom->cylinders = DEFAULT_FD_CYLINDERS;
geom->heads = DEFAULT_FD_HEADS;
geom->sectors = DEFAULT_FD_SECTORS;
}
/* Set the total sectors properly, if we can. */
if (! fstat (fd, &st) && st.st_size)
geom->total_sectors = st.st_size >> SECTOR_BITS;
else
geom->total_sectors = geom->cylinders * geom->heads * geom->sectors;
}
success:
if (geom->flags == -1)
close (fd);
}
#ifdef __linux__
/* Check if we have devfs support. */
static int
have_devfs (void)
{
static int dev_devfsd_exists = -1;
if (dev_devfsd_exists < 0)
{
struct stat st;
dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
}
return dev_devfsd_exists;
}
#endif /* __linux__ */
/* These three functions are quite different among OSes. */
static void
get_floppy_disk_name (char *name, int unit)
{
#if defined(__linux__)
/* GNU/Linux */
if (have_devfs ())
sprintf (name, "/dev/floppy/%d", unit);
else
sprintf (name, "/dev/fd%d", unit);
#elif defined(__GNU__)
/* GNU/Hurd */
sprintf (name, "/dev/fd%d", unit);
#elif defined(__FreeBSD_kernel__)
/* kFreeBSD */
if (get_kfreebsd_version () >= 400000)
sprintf (name, "/dev/fd%d", unit);
else
sprintf (name, "/dev/rfd%d", unit);
#elif defined(__NetBSD__)
/* NetBSD */
/* opendisk() doesn't work for floppies. */
sprintf (name, "/dev/rfd%da", unit);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rfd%dc", unit);
#elif defined(__QNXNTO__)
/* QNX RTP */
sprintf (name, "/dev/fd%d", unit);
#else
# warning "BIOS floppy drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
static void
get_ide_disk_name (char *name, int unit)
{
#if defined(__linux__)
/* GNU/Linux */
sprintf (name, "/dev/hd%c", unit + 'a');
#elif defined(__GNU__)
/* GNU/Hurd */
sprintf (name, "/dev/hd%d", unit);
#elif defined(__FreeBSD_kernel__)
/* kFreeBSD */
if (get_kfreebsd_version () >= 400000)
sprintf (name, "/dev/ad%d", unit);
else
sprintf (name, "/dev/rwd%d", unit);
#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
/* NetBSD */
char shortname[16];
int fd;
sprintf (shortname, "wd%d", unit);
fd = opendisk (shortname, O_RDONLY, name,
16, /* length of NAME */
0 /* char device */
);
close (fd);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rwd%dc", unit);
#elif defined(__QNXNTO__)
/* QNX RTP */
/* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
contain SCSI disks. */
sprintf (name, "/dev/hd%d", unit);
#else
# warning "BIOS IDE drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
static void
get_scsi_disk_name (char *name, int unit)
{
#if defined(__linux__)
/* GNU/Linux */
sprintf (name, "/dev/sd%c", unit + 'a');
#elif defined(__GNU__)
/* GNU/Hurd */
sprintf (name, "/dev/sd%d", unit);
#elif defined(__FreeBSD_kernel__)
/* kFreeBSD */
if (get_kfreebsd_version () >= 400000)
sprintf (name, "/dev/da%d", unit);
else
sprintf (name, "/dev/rda%d", unit);
#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
/* NetBSD */
char shortname[16];
int fd;
sprintf (shortname, "sd%d", unit);
fd = opendisk (shortname, O_RDONLY, name,
16, /* length of NAME */
0 /* char device */
);
close (fd);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rsd%dc", unit);
#elif defined(__QNXNTO__)
/* QNX RTP */
/* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
disable the detection of SCSI disks here. */
*name = 0;
#else
# warning "BIOS SCSI drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
#ifdef __linux__
static void
get_dac960_disk_name (char *name, int controller, int drive)
{
sprintf (name, "/dev/rd/c%dd%d", controller, drive);
}
static void
get_ataraid_disk_name (char *name, int unit)
{
sprintf (name, "/dev/ataraid/d%c", unit + '0');
}
static void
get_i2o_disk_name (char *name, char unit)
{
sprintf (name, "/dev/i2o/hd%c", unit);
}
#endif
/* Check if DEVICE can be read. If an error occurs, return zero,
otherwise return non-zero. */
int
check_device (const char *device)
{
char buf[512];
FILE *fp;
/* If DEVICE is empty, just return 1. */
if (*device == 0)
return 1;
fp = fopen (device, "r");
if (! fp)
{
switch (errno)
{
#ifdef ENOMEDIUM
case ENOMEDIUM:
# if 0
/* At the moment, this finds only CDROMs, which can't be
read anyway, so leave it out. Code should be
reactivated if `removable disks' and CDROMs are
supported. */
/* Accept it, it may be inserted. */
return 1;
# endif
break;
#endif /* ENOMEDIUM */
default:
/* Break case and leave. */
break;
}
/* Error opening the device. */
return 0;
}
/* Make sure CD-ROMs don't get assigned a BIOS disk number
before SCSI disks! */
#ifdef __linux__
# ifdef CDROM_GET_CAPABILITY
if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
return 0;
# else /* ! CDROM_GET_CAPABILITY */
/* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
{
struct hd_geometry hdg;
struct stat st;
if (fstat (fileno (fp), &st))
return 0;
/* If it is a block device and isn't a floppy, check if HDIO_GETGEO
succeeds. */
if (S_ISBLK (st.st_mode)
&& MAJOR (st.st_rdev) != FLOPPY_MAJOR
&& ioctl (fileno (fp), HDIO_GETGEO, &hdg))
return 0;
}
# endif /* ! CDROM_GET_CAPABILITY */
#endif /* __linux__ */
#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
# ifdef CDIOCCLRDEBUG
if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
return 0;
# endif /* CDIOCCLRDEBUG */
#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
/* Attempt to read the first sector. */
if (fread (buf, 1, 512, fp) != 512)
{
fclose (fp);
return 0;
}
fclose (fp);
return 1;
}
/* Read mapping information from FP, and write it to MAP. */
static int
read_device_map (FILE *fp, char **map, const char *map_file)
{
auto void show_error (int no, const char *msg);
auto void show_warning (int no, const char *msg, ...);
auto void show_error (int no, const char *msg)
{
fprintf (stderr, "%s:%d: error: %s\n", map_file, no, msg);
}
auto void show_warning (int no, const char *msg, ...)
{
va_list ap;
va_start (ap, msg);
fprintf (stderr, "%s:%d: warning: ", map_file, no);
vfprintf (stderr, msg, ap);
va_end (ap);
}
/* If there is the device map file, use the data in it instead of
probing devices. */
char buf[1024]; /* XXX */
int line_number = 0;
while (fgets (buf, sizeof (buf), fp))
{
char *ptr, *eptr;
int drive;
int is_floppy = 0;
/* Increase the number of lines. */
line_number++;
/* If the first character is '#', skip it. */
if (buf[0] == '#')
continue;
ptr = buf;
/* Skip leading spaces. */
while (*ptr && isspace (*ptr))
ptr++;
/* Skip empty lines. */
if (! *ptr)
continue;
if (*ptr != '(')
{
show_error (line_number, "No open parenthesis found");
return 0;
}
ptr++;
if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd')
{
show_error (line_number, "Bad drive name");
return 0;
}
if (*ptr == 'f')
is_floppy = 1;
ptr += 2;
drive = strtoul (ptr, &ptr, 10);
if (drive < 0)
{
show_error (line_number, "Bad device number");
return 0;
}
else if (drive > 127)
{
show_warning (line_number,
"Ignoring %cd%d due to a BIOS limitation",
is_floppy ? 'f' : 'h', drive);
continue;
}
if (! is_floppy)
drive += 0x80;
if (*ptr != ')')
{
show_error (line_number, "No close parenthesis found");
return 0;
}
ptr++;
/* Skip spaces. */
while (*ptr && isspace (*ptr))
ptr++;
if (! *ptr)
{
show_error (line_number, "No filename found");
return 0;
}
/* Terminate the filename. */
eptr = ptr;
while (*eptr && ! isspace (*eptr))
eptr++;
*eptr = 0;
/* Multiple entries for a given drive is not allowed. */
if (map[drive])
{
show_error (line_number, "Duplicated entry found");
return 0;
}
map[drive] = strdup (ptr);
assert (map[drive]);
}
return 1;
}
/* Initialize the device map MAP. *MAP will be allocated from the heap
space. If MAP_FILE is not NULL, then read mappings from the file
MAP_FILE if it exists, otherwise, write guessed mappings to the file.
FLOPPY_DISKS is the number of floppy disk drives which will be probed.
If it is zero, don't probe any floppy at all. If it is one, probe one
floppy. If it is two, probe two floppies. And so on. */
int
init_device_map (char ***map, const char *map_file, int floppy_disks)
{
int i;
int num_hd = 0;
FILE *fp = 0;
assert (map);
assert (*map == 0);
*map = malloc (NUM_DISKS * sizeof (char *));
assert (*map);
/* Probe devices for creating the device map. */
/* Initialize DEVICE_MAP. */
for (i = 0; i < NUM_DISKS; i++)
(*map)[i] = 0;
if (map_file)
{
/* Open the device map file. */
fp = fopen (map_file, "r");
if (fp)
{
int ret;
ret = read_device_map (fp, *map, map_file);
fclose (fp);
return ret;
}
}
/* Print something so that the user does not think GRUB has been
crashed. */
fprintf (stderr,
"Probing devices to guess BIOS drives. "
"This may take a long time.\n");
if (map_file)
/* Try to open the device map file to write the probed data. */
fp = fopen (map_file, "w");
/* Floppies. */
for (i = 0; i < floppy_disks; i++)
{
char name[16];
get_floppy_disk_name (name, i);
/* In floppies, write the map, whether check_device succeeds
or not, because the user just does not insert floppies. */
if (fp)
fprintf (fp, "(fd%d)\t%s\n", i, name);
if (check_device (name))
{
(*map)[i] = strdup (name);
assert ((*map)[i]);
}
}
#ifdef __linux__
if (have_devfs ())
{
while (1)
{
char discn[32];
char name[PATH_MAX];
struct stat st;
/* Linux creates symlinks "/dev/discs/discN" for convenience.
The way to number disks is the same as GRUB's. */
sprintf (discn, "/dev/discs/disc%d", num_hd);
if (stat (discn, &st) < 0)
break;
if (realpath (discn, name))
{
strcat (name, "/disc");
(*map)[num_hd + 0x80] = strdup (name);
assert ((*map)[num_hd + 0x80]);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
}
num_hd++;
}
/* OK, close the device map file if opened. */
if (fp)
fclose (fp);
return 1;
}
#endif /* __linux__ */
/* IDE disks. */
for (i = 0; i < 8; i++)
{
char name[16];
get_ide_disk_name (name, i);
if (check_device (name))
{
(*map)[num_hd + 0x80] = strdup (name);
assert ((*map)[num_hd + 0x80]);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
#ifdef __linux__
/* ATARAID disks. */
for (i = 0; i < 8; i++)
{
char name[20];
get_ataraid_disk_name (name, i);
if (check_device (name))
{
(*map)[num_hd + 0x80] = strdup (name);
assert ((*map)[num_hd + 0x80]);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
#endif /* __linux__ */
/* The rest is SCSI disks. */
for (i = 0; i < 16; i++)
{
char name[16];
get_scsi_disk_name (name, i);
if (check_device (name))
{
(*map)[num_hd + 0x80] = strdup (name);
assert ((*map)[num_hd + 0x80]);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
#ifdef __linux__
/* This is for DAC960 - we have
/dev/rd/c<controller>d<logical drive>p<partition>.
DAC960 driver currently supports up to 8 controllers, 32 logical
drives, and 7 partitions. */
{
int controller, drive;
for (controller = 0; controller < 8; controller++)
{
for (drive = 0; drive < 15; drive++)
{
char name[24];
get_dac960_disk_name (name, controller, drive);
if (check_device (name))
{
(*map)[num_hd + 0x80] = strdup (name);
assert ((*map)[num_hd + 0x80]);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
}
}
/* This is for I2O - we have /dev/i2o/hd<logical drive><partition> */
{
int unit;
for (unit = 'a'; unit < 'f'; unit++)
{
char name[24];
get_i2o_disk_name (name, unit);
if (check_device (name))
{
(*map)[num_hd + 0x80] = strdup (name);
assert ((*map)[num_hd + 0x80]);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
}
#endif /* __linux__ */
/* OK, close the device map file if opened. */
if (fp)
fclose (fp);
return 1;
}
/* Restore the memory consumed for MAP. */
void
restore_device_map (char **map)
{
int i;
for (i = 0; i < NUM_DISKS; i++)
if (map[i])
free (map[i]);
free (map);
}
#ifdef __linux__
/* Linux-only functions, because Linux has a bug that the disk cache for
a whole disk is not consistent with the one for a partition of the
disk. */
int
is_disk_device (char **map, int drive)
{
struct stat st;
assert (map[drive] != 0);
assert (stat (map[drive], &st) == 0);
/* For now, disk devices under Linux are all block devices. */
return S_ISBLK (st.st_mode);
}
int
write_to_partition (char **map, int drive, int partition,
int sector, int size, const char *buf)
{
char dev[PATH_MAX]; /* XXX */
int fd;
if ((partition & 0x00FF00) != 0x00FF00)
{
/* If the partition is a BSD partition, it is difficult to
obtain the representation in Linux. So don't support that. */
errnum = ERR_DEV_VALUES;
return 1;
}
assert (map[drive] != 0);
strcpy (dev, map[drive]);
if (have_devfs ())
{
if (strcmp (dev + strlen(dev) - 5, "/disc") == 0)
strcpy (dev + strlen(dev) - 5, "/part");
}
else
{
if ((strncmp (dev, "/dev/ataraid/", 13) == 0) ||
(strncmp (dev, "/dev/rd/", 8) == 0))
strcpy (dev + strlen(dev), "p");
}
sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1);
/* Open the partition. */
fd = open (dev, O_RDWR);
if (fd < 0)
{
errnum = ERR_NO_PART;
return 0;
}
#if defined(__linux__) && (!defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
/* Maybe libc doesn't have large file support. */
{
loff_t offset, result;
static int _llseek (uint filedes, ulong hi, ulong lo,
loff_t *res, uint wh);
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
{
errnum = ERR_DEV_VALUES;
return 0;
}
}
#else
{
off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
if (lseek (fd, offset, SEEK_SET) != offset)
{
errnum = ERR_DEV_VALUES;
return 0;
}
}
#endif
if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE))
{
close (fd);
errnum = ERR_WRITE;
return 0;
}
sync (); /* Paranoia. */
close (fd);
return 1;
}
#endif /* __linux__ */
+48
View File
@@ -0,0 +1,48 @@
/* device.h - Define macros and declare prototypes for device.c */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2004 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DEVICE_MAP_HEADER
#define DEVICE_MAP_HEADER 1
/* The maximum number of BIOS disks. */
#define NUM_DISKS 256
/* Simulated disk sizes. */
#define DEFAULT_FD_CYLINDERS 80
#define DEFAULT_FD_HEADS 2
#define DEFAULT_FD_SECTORS 18
#define DEFAULT_HD_CYLINDERS 620
#define DEFAULT_HD_HEADS 128
#define DEFAULT_HD_SECTORS 63
/* Function prototypes. */
extern void get_drive_geometry (struct geometry *geom, char **map, int drive);
extern int check_device (const char *device);
extern int init_device_map (char ***map, const char *map_file,
int no_floppies);
extern void restore_device_map (char **map);
#ifdef __linux__
extern int is_disk_device (char **map, int drive);
extern int write_to_partition (char **map, int drive, int partition,
int offset, int size, const char *buf);
#endif /* __linux__ */
#endif /* DEVICE_MAP_HEADER */
+1053
View File
File diff suppressed because it is too large. Load diff
+133
View File
@@ -0,0 +1,133 @@
/* Declarations for getopt.
Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org.
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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if defined (__STDC__) && __STDC__
#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* getopt.h */
+190
View File
@@ -0,0 +1,190 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org.
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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "getopt.h"
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE
#endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* Not ELIDE_CODE. */
#ifdef TEST
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */
+2
View File
@@ -0,0 +1,2 @@
.deps
Makefile
+620
View File
@@ -0,0 +1,620 @@
/**************************************************************************
ETHERBOOT - BOOTP/TFTP Bootstrap Program
Author: Martin Renters.
Date: Mar 22 1995
This code is based heavily on David Greenman's if_ed.c driver and
Andres Vega Garcia's if_ep.c driver.
Copyright (C) 1993-1994, David Greenman, Martin Renters.
Copyright (C) 1993-1995, Andres Vega Garcia.
Copyright (C) 1995, Serge Babkin.
This software may be used, modified, copied, distributed, and sold, in
both source and binary form provided that the above copyright and these
terms are retained. Under no circumstances are the authors responsible for
the proper functioning of this software, nor do the authors assume any
responsibility for damages incurred with its use.
3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
$Id$
***************************************************************************/
/* #define EDEBUG */
#include "etherboot.h"
#include "nic.h"
#include "cards.h"
#include "timer.h"
#include "3c509.h"
#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000)
static unsigned short eth_nic_base;
static enum { none, bnc, utp } connector = none; /* for 3C509 */
#ifdef INCLUDE_3C529
/*
* This table and several other pieces of the MCA support
* code were shamelessly borrowed from the Linux kernel source.
*
* MCA support added by Adam Fritzler (mid@auk.cx)
*
*/
struct el3_mca_adapters_struct {
const char *name;
int id;
};
static struct el3_mca_adapters_struct el3_mca_adapters[] = {
{ "3Com 3c529 EtherLink III (10base2)", 0x627c },
{ "3Com 3c529 EtherLink III (10baseT)", 0x627d },
{ "3Com 3c529 EtherLink III (test mode)", 0x62db },
{ "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 },
{ "3Com 3c529 EtherLink III (TP)", 0x62f7 },
{ NULL, 0 },
};
#endif
/**************************************************************************
ETH_RESET - Reset adapter
***************************************************************************/
static void t509_reset(struct nic *nic)
{
int i;
/***********************************************************
Reset 3Com 509 card
*************************************************************/
/* stop card */
outw(RX_DISABLE, BASE + EP_COMMAND);
outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
outw(TX_DISABLE, BASE + EP_COMMAND);
outw(STOP_TRANSCEIVER, BASE + EP_COMMAND);
udelay(1000);
outw(RX_RESET, BASE + EP_COMMAND);
outw(TX_RESET, BASE + EP_COMMAND);
outw(C_INTR_LATCH, BASE + EP_COMMAND);
outw(SET_RD_0_MASK, BASE + EP_COMMAND);
outw(SET_INTR_MASK, BASE + EP_COMMAND);
outw(SET_RX_FILTER, BASE + EP_COMMAND);
/*
* initialize card
*/
while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
GO_WINDOW(0);
/* Disable the card */
outw(0, BASE + EP_W0_CONFIG_CTRL);
/* Configure IRQ to none */
outw(SET_IRQ(0), BASE + EP_W0_RESOURCE_CFG);
/* Enable the card */
outw(ENABLE_DRQ_IRQ, BASE + EP_W0_CONFIG_CTRL);
GO_WINDOW(2);
/* Reload the ether_addr. */
for (i = 0; i < ETH_ALEN; i++)
outb(nic->node_addr[i], BASE + EP_W2_ADDR_0 + i);
outw(RX_RESET, BASE + EP_COMMAND);
outw(TX_RESET, BASE + EP_COMMAND);
/* Window 1 is operating window */
GO_WINDOW(1);
for (i = 0; i < 31; i++)
inb(BASE + EP_W1_TX_STATUS);
/* get rid of stray intr's */
outw(ACK_INTR | 0xff, BASE + EP_COMMAND);
outw(SET_RD_0_MASK | S_5_INTS, BASE + EP_COMMAND);
outw(SET_INTR_MASK, BASE + EP_COMMAND);
outw(SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST, BASE + EP_COMMAND);
/* configure BNC */
if (connector == bnc) {
outw(START_TRANSCEIVER, BASE + EP_COMMAND);
udelay(1000);
}
/* configure UTP */
else if (connector == utp) {
GO_WINDOW(4);
outw(ENABLE_UTP, BASE + EP_W4_MEDIA_TYPE);
sleep(2); /* Give time for media to negotiate */
GO_WINDOW(1);
}
/* start transceiver and receiver */
outw(RX_ENABLE, BASE + EP_COMMAND);
outw(TX_ENABLE, BASE + EP_COMMAND);
/* set early threshold for minimal packet length */
outw(SET_RX_EARLY_THRESH | ETH_ZLEN, BASE + EP_COMMAND);
outw(SET_TX_START_THRESH | 16, BASE + EP_COMMAND);
}
/**************************************************************************
ETH_TRANSMIT - Transmit a frame
***************************************************************************/
static char padmap[] = {
0, 3, 2, 1};
static void t509_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
register unsigned int len;
int pad;
int status;
#ifdef EDEBUG
printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
#endif
/* swap bytes of type */
t= htons(t);
len=s+ETH_HLEN; /* actual length of packet */
pad = padmap[len & 3];
/*
* The 3c509 automatically pads short packets to minimum ethernet length,
* but we drop packets that are too large. Perhaps we should truncate
* them instead?
*/
if (len + pad > ETH_FRAME_LEN) {
return;
}
/* drop acknowledgements */
while ((status=inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
outw(TX_RESET, BASE + EP_COMMAND);
outw(TX_ENABLE, BASE + EP_COMMAND);
}
outb(0x0, BASE + EP_W1_TX_STATUS);
}
while (inw(BASE + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
; /* no room in FIFO */
outw(len, BASE + EP_W1_TX_PIO_WR_1);
outw(0x0, BASE + EP_W1_TX_PIO_WR_1); /* Second dword meaningless */
/* write packet */
outsw(BASE + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
outsw(BASE + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
outw(t, BASE + EP_W1_TX_PIO_WR_1);
outsw(BASE + EP_W1_TX_PIO_WR_1, p, s / 2);
if (s & 1)
outb(*(p+s - 1), BASE + EP_W1_TX_PIO_WR_1);
while (pad--)
outb(0, BASE + EP_W1_TX_PIO_WR_1); /* Padding */
/* wait for Tx complete */
while((inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
;
}
/**************************************************************************
ETH_POLL - Wait for a frame
***************************************************************************/
static int t509_poll(struct nic *nic)
{
/* common variables */
unsigned short type = 0; /* used by EDEBUG */
/* variables for 3C509 */
short status, cst;
register short rx_fifo;
cst=inw(BASE + EP_STATUS);
#ifdef EDEBUG
if(cst & 0x1FFF)
printf("-%hX-",cst);
#endif
if( (cst & S_RX_COMPLETE)==0 ) {
/* acknowledge everything */
outw(ACK_INTR| (cst & S_5_INTS), BASE + EP_COMMAND);
outw(C_INTR_LATCH, BASE + EP_COMMAND);
return 0;
}
status = inw(BASE + EP_W1_RX_STATUS);
#ifdef EDEBUG
printf("*%hX*",status);
#endif
if (status & ERR_RX) {
outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
return 0;
}
rx_fifo = status & RX_BYTES_MASK;
if (rx_fifo==0)
return 0;
/* read packet */
#ifdef EDEBUG
printf("[l=%d",rx_fifo);
#endif
insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
if(rx_fifo & 1)
nic->packet[rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1);
nic->packetlen=rx_fifo;
while(1) {
status = inw(BASE + EP_W1_RX_STATUS);
#ifdef EDEBUG
printf("*%hX*",status);
#endif
rx_fifo = status & RX_BYTES_MASK;
if(rx_fifo>0) {
insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
if(rx_fifo & 1)
nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1);
nic->packetlen+=rx_fifo;
#ifdef EDEBUG
printf("+%d",rx_fifo);
#endif
}
if(( status & RX_INCOMPLETE )==0) {
#ifdef EDEBUG
printf("=%d",nic->packetlen);
#endif
break;
}
udelay(1000); /* if incomplete wait 1 ms */
}
/* acknowledge reception of packet */
outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
;
#ifdef EDEBUG
type = (nic->packet[12]<<8) | nic->packet[13];
if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
nic->packet[5] == 0xFF*ETH_ALEN)
printf(",t=%hX,b]",type);
else
printf(",t=%hX]",type);
#endif
return (1);
}
/*************************************************************************
3Com 509 - specific routines
**************************************************************************/
static int
eeprom_rdy(void)
{
int i;
for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++);
if (i >= MAX_EEPROMBUSY) {
/* printf("3c509: eeprom failed to come ready.\n"); */
printf("3c509: eeprom busy.\n"); /* memory in EPROM is tight */
return (0);
}
return (1);
}
/*
* get_e: gets a 16 bits word from the EEPROM. we must have set the window
* before
*/
static int
get_e(int offset)
{
if (!eeprom_rdy())
return (0xffff);
outw(EEPROM_CMD_RD | offset, IS_BASE + EP_W0_EEPROM_COMMAND);
if (!eeprom_rdy())
return (0xffff);
return (inw(IS_BASE + EP_W0_EEPROM_DATA));
}
static int
send_ID_sequence(int port)
{
int cx, al;
for (al = 0xff, cx = 0; cx < 255; cx++) {
outb(al, port);
al <<= 1;
if (al & 0x100)
al ^= 0xcf;
}
return (1);
}
/*
* We get eeprom data from the id_port given an offset into the eeprom.
* Basically; after the ID_sequence is sent to all of the cards; they enter
* the ID_CMD state where they will accept command requests. 0x80-0xbf loads
* the eeprom data. We then read the port 16 times and with every read; the
* cards check for contention (ie: if one card writes a 0 bit and another
* writes a 1 bit then the host sees a 0. At the end of the cycle; each card
* compares the data on the bus; if there is a difference then that card goes
* into ID_WAIT state again). In the meantime; one bit of data is returned in
* the AX register which is conveniently returned to us by inb(). Hence; we
* read 16 times getting one bit of data with each read.
*/
static int
get_eeprom_data(int id_port, int offset)
{
int i, data = 0;
outb(0x80 + offset, id_port);
/* Do we really need this wait? Won't be noticeable anyway */
udelay(10000);
for (i = 0; i < 16; i++)
data = (data << 1) | (inw(id_port) & 1);
return (data);
}
static void t509_disable(struct nic *nic)
{
outb(0xc0, EP_ID_PORT);
}
/**************************************************************************
ETH_PROBE - Look for an adapter
***************************************************************************/
#ifdef INCLUDE_3C529
struct nic *t529_probe(struct nic *nic, unsigned short *probe_addrs)
#else
struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs)
#endif
{
/* common variables */
int i;
int failcount;
#ifdef INCLUDE_3C529
struct el3_mca_adapters_struct *mcafound = NULL;
int mca_pos4 = 0, mca_pos5 = 0, mca_irq = 0;
#endif
t509_disable(nic); /* in case board was active */
/* note that nic is not used */
for (failcount = 0; failcount < 4000; failcount++) {
int data, j, io_base, id_port;
unsigned short k;
int ep_current_tag;
short *p;
#ifdef INCLUDE_3C529
int curboard;
#endif
id_port = EP_ID_PORT;
ep_current_tag = EP_LAST_TAG + 1;
/*********************************************************
Search for 3Com 509 card
***********************************************************/
#ifdef INCLUDE_3C529
/*
* XXX: We should really check to make sure we have an MCA
* bus controller before going ahead with this...
*
* For now, we avoid any hassle by making it a compile
* time option.
*
*/
printf("\nWarning: Assuming presence of MCA bus\n");
/* Make sure motherboard setup is off */
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
/* Cycle through slots */
for(curboard=0; curboard<MCA_MAX_SLOT_NR; curboard++) {
int boardid;
int curcard;
outb_p(0x8|(curboard&0xf), MCA_ADAPTER_SETUP_REG);
boardid = inb_p(MCA_POS_REG(0));
boardid += inb_p(MCA_POS_REG(1)) << 8;
curcard = 0;
while (el3_mca_adapters[curcard].name) {
if (el3_mca_adapters[curcard].id == boardid) {
mcafound = &el3_mca_adapters[curcard];
mca_pos4 = inb_p(MCA_POS_REG(4));
mca_pos5 = inb_p(MCA_POS_REG(5));
goto donewithdetect;
}
else
curcard++;
}
}
donewithdetect:
/* Kill all setup modes */
outb_p(0, MCA_ADAPTER_SETUP_REG);
if (mcafound) {
eth_nic_base = ((short)((mca_pos4&0xfc)|0x02)) << 8;
mca_irq = mca_pos5 & 0x0f;
ep_current_tag--;
}
else
printf("MCA Card not found\n");
#endif
/* Look for the EISA boards, leave them activated */
/* search for the first card, ignore all others */
for(j = 1; j < 16; j++) {
io_base = (j * EP_EISA_START) | EP_EISA_W0;
if (inw(io_base + EP_W0_MFG_ID) != MFG_ID)
continue;
/* we must have found 0x1f if the board is EISA configurated */
if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f)
continue;
/* Reset and Enable the card */
outb(W0_P4_CMD_RESET_ADAPTER, io_base + EP_W0_CONFIG_CTRL);
udelay(1000); /* Must wait 800 µs, be conservative */
outb(W0_P4_CMD_ENABLE_ADAPTER, io_base + EP_W0_CONFIG_CTRL);
/*
* Once activated, all the registers are mapped in the range
* x000 - x00F, where x is the slot number.
*/
eth_nic_base = j * EP_EISA_START;
break;
}
ep_current_tag--;
/* Look for the ISA boards. Init and leave them actived */
/* search for the first card, ignore all others */
outb(0xc0, id_port); /* Global reset */
udelay(1000); /* wait 1 ms */
for (i = 0; i < EP_MAX_BOARDS; i++) {
outb(0, id_port);
outb(0, id_port);
send_ID_sequence(id_port);
data = get_eeprom_data(id_port, EEPROM_MFG_ID);
if (data != MFG_ID)
break;
/* resolve contention using the Ethernet address */
for (j = 0; j < 3; j++)
data = get_eeprom_data(id_port, j);
eth_nic_base =
(get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
outb(ep_current_tag, id_port); /* tags board */
outb(ACTIVATE_ADAPTER_TO_CONFIG, id_port);
ep_current_tag--;
break;
}
if (i >= EP_MAX_BOARDS)
goto no3c509;
/*
* The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
* 0x9[0-f]50
*/
GO_WINDOW(0);
k = get_e(EEPROM_PROD_ID);
#ifdef INCLUDE_3C529
/*
* On MCA, the PROD_ID matches the MCA card ID (POS0+POS1)
*/
if (mcafound) {
if (mcafound->id != k) {
printf("MCA: PROD_ID in EEPROM does not match MCA card ID! (%hX != %hX)\n", k, mcafound->id);
goto no3c509;
}
} else { /* for ISA/EISA */
if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
goto no3c509;
}
#else
if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
goto no3c509;
#endif
#ifdef INCLUDE_3C529
if (mcafound) {
printf("%s board found on MCA at %#hx IRQ %d -",
mcafound->name, eth_nic_base, mca_irq);
} else {
#endif
if(eth_nic_base >= EP_EISA_START)
printf("3C5x9 board on EISA at %#hx - ",eth_nic_base);
else
printf("3C5x9 board on ISA at %#hx - ",eth_nic_base);
#ifdef INCLUDE_3C529
}
#endif
/* test for presence of connectors */
i = inw(IS_BASE + EP_W0_CONFIG_CTRL);
j = (inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14) & 0x3;
switch(j) {
case 0:
if (i & IS_UTP) {
printf("10baseT\n");
connector = utp;
}
else {
printf("10baseT not present\n");
goto no3c509;
}
break;
case 1:
if (i & IS_AUI)
printf("10base5\n");
else {
printf("10base5 not present\n");
goto no3c509;
}
break;
case 3:
if (i & IS_BNC) {
printf("10base2\n");
connector = bnc;
}
else {
printf("10base2 not present\n");
goto no3c509;
}
break;
default:
printf("unknown connector\n");
goto no3c509;
}
/*
* Read the station address from the eeprom
*/
p = (unsigned short *) nic->node_addr;
for (i = 0; i < ETH_ALEN / 2; i++) {
GO_WINDOW(0);
p[i] = htons(get_e(i));
GO_WINDOW(2);
outw(ntohs(p[i]), BASE + EP_W2_ADDR_0 + (i * 2));
}
printf("Ethernet address: %!\n", nic->node_addr);
t509_reset(nic);
nic->reset = t509_reset;
nic->poll = t509_poll;
nic->transmit = t509_transmit;
nic->disable = t509_disable;
return nic;
no3c509:
printf("(probe fail)");
}
return 0;
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+397
View File
@@ -0,0 +1,397 @@
/*
* Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. 2. The name
* of the author may not be used to endorse or promote products derived from
* this software withough specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* if_epreg.h,v 1.4 1994/11/13 10:12:37 gibbs Exp Modified by:
*
October 2, 1994
Modified by: Andres Vega Garcia
INRIA - Sophia Antipolis, France
e-mail: avega@sophia.inria.fr
finger: avega@pax.inria.fr
*/
/*
* Ethernet software status per interface.
*/
/*
* Some global constants
*/
#define TX_INIT_RATE 16
#define TX_INIT_MAX_RATE 64
#define RX_INIT_LATENCY 64
#define RX_INIT_EARLY_THRESH 64
#define MIN_RX_EARLY_THRESHF 16 /* not less than ether_header */
#define MIN_RX_EARLY_THRESHL 4
#define EEPROMSIZE 0x40
#define MAX_EEPROMBUSY 1000
#define EP_LAST_TAG 0xd7
#define EP_MAX_BOARDS 16
#define EP_ID_PORT 0x100
/*
* some macros to acces long named fields
*/
#define IS_BASE (eth_nic_base)
#define BASE (eth_nic_base)
/*
* Commands to read/write EEPROM trough EEPROM command register (Window 0,
* Offset 0xa)
*/
#define EEPROM_CMD_RD 0x0080 /* Read: Address required (5 bits) */
#define EEPROM_CMD_WR 0x0040 /* Write: Address required (5 bits) */
#define EEPROM_CMD_ERASE 0x00c0 /* Erase: Address required (5 bits) */
#define EEPROM_CMD_EWEN 0x0030 /* Erase/Write Enable: No data required */
#define EEPROM_BUSY (1<<15)
#define EEPROM_TST_MODE (1<<14)
/*
* Some short functions, worth to let them be a macro
*/
#define is_eeprom_busy(b) (inw((b)+EP_W0_EEPROM_COMMAND)&EEPROM_BUSY)
#define GO_WINDOW(x) outw(WINDOW_SELECT|(x), BASE+EP_COMMAND)
/**************************************************************************
*
* These define the EEPROM data structure. They are used in the probe
* function to verify the existance of the adapter after having sent
* the ID_Sequence.
*
* There are others but only the ones we use are defined here.
*
**************************************************************************/
#define EEPROM_NODE_ADDR_0 0x0 /* Word */
#define EEPROM_NODE_ADDR_1 0x1 /* Word */
#define EEPROM_NODE_ADDR_2 0x2 /* Word */
#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */
#define EEPROM_MFG_ID 0x7 /* 0x6d50 */
#define EEPROM_ADDR_CFG 0x8 /* Base addr */
#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */
/**************************************************************************
*
* These are the registers for the 3Com 3c509 and their bit patterns when
* applicable. They have been taken out the the "EtherLink III Parallel
* Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual
* from 3com.
*
**************************************************************************/
#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a
* command reg. */
#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status
* reg. */
#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window
* reg. */
/*
* Window 0 registers. Setup.
*/
/* Write */
#define EP_W0_EEPROM_DATA 0x0c
#define EP_W0_EEPROM_COMMAND 0x0a
#define EP_W0_RESOURCE_CFG 0x08
#define EP_W0_ADDRESS_CFG 0x06
#define EP_W0_CONFIG_CTRL 0x04
/* Read */
#define EP_W0_PRODUCT_ID 0x02
#define EP_W0_MFG_ID 0x00
/*
* Window 1 registers. Operating Set.
*/
/* Write */
#define EP_W1_TX_PIO_WR_2 0x02
#define EP_W1_TX_PIO_WR_1 0x00
/* Read */
#define EP_W1_FREE_TX 0x0c
#define EP_W1_TX_STATUS 0x0b /* byte */
#define EP_W1_TIMER 0x0a /* byte */
#define EP_W1_RX_STATUS 0x08
#define EP_W1_RX_PIO_RD_2 0x02
#define EP_W1_RX_PIO_RD_1 0x00
/*
* Window 2 registers. Station Address Setup/Read
*/
/* Read/Write */
#define EP_W2_ADDR_5 0x05
#define EP_W2_ADDR_4 0x04
#define EP_W2_ADDR_3 0x03
#define EP_W2_ADDR_2 0x02
#define EP_W2_ADDR_1 0x01
#define EP_W2_ADDR_0 0x00
/*
* Window 3 registers. FIFO Management.
*/
/* Read */
#define EP_W3_FREE_TX 0x0c
#define EP_W3_FREE_RX 0x0a
/*
* Window 4 registers. Diagnostics.
*/
/* Read/Write */
#define EP_W4_MEDIA_TYPE 0x0a
#define EP_W4_CTRLR_STATUS 0x08
#define EP_W4_NET_DIAG 0x06
#define EP_W4_FIFO_DIAG 0x04
#define EP_W4_HOST_DIAG 0x02
#define EP_W4_TX_DIAG 0x00
/*
* Window 5 Registers. Results and Internal status.
*/
/* Read */
#define EP_W5_READ_0_MASK 0x0c
#define EP_W5_INTR_MASK 0x0a
#define EP_W5_RX_FILTER 0x08
#define EP_W5_RX_EARLY_THRESH 0x06
#define EP_W5_TX_AVAIL_THRESH 0x02
#define EP_W5_TX_START_THRESH 0x00
/*
* Window 6 registers. Statistics.
*/
/* Read/Write */
#define TX_TOTAL_OK 0x0c
#define RX_TOTAL_OK 0x0a
#define TX_DEFERRALS 0x08
#define RX_FRAMES_OK 0x07
#define TX_FRAMES_OK 0x06
#define RX_OVERRUNS 0x05
#define TX_COLLISIONS 0x04
#define TX_AFTER_1_COLLISION 0x03
#define TX_AFTER_X_COLLISIONS 0x02
#define TX_NO_SQE 0x01
#define TX_CD_LOST 0x00
/****************************************
*
* Register definitions.
*
****************************************/
/*
* Command register. All windows.
*
* 16 bit register.
* 15-11: 5-bit code for command to be executed.
* 10-0: 11-bit arg if any. For commands with no args;
* this can be set to anything.
*/
#define GLOBAL_RESET (unsigned short) 0x0000 /* Wait at least 1ms
* after issuing */
#define WINDOW_SELECT (unsigned short) (0x1<<11)
#define START_TRANSCEIVER (unsigned short) (0x2<<11) /* Read ADDR_CFG reg to
* determine whether
* this is needed. If
* so; wait 800 uSec
* before using trans-
* ceiver. */
#define RX_DISABLE (unsigned short) (0x3<<11) /* state disabled on
* power-up */
#define RX_ENABLE (unsigned short) (0x4<<11)
#define RX_RESET (unsigned short) (0x5<<11)
#define RX_DISCARD_TOP_PACK (unsigned short) (0x8<<11)
#define TX_ENABLE (unsigned short) (0x9<<11)
#define TX_DISABLE (unsigned short) (0xa<<11)
#define TX_RESET (unsigned short) (0xb<<11)
#define REQ_INTR (unsigned short) (0xc<<11)
#define SET_INTR_MASK (unsigned short) (0xe<<11)
#define SET_RD_0_MASK (unsigned short) (0xf<<11)
#define SET_RX_FILTER (unsigned short) (0x10<<11)
#define FIL_INDIVIDUAL (unsigned short) (0x1)
#define FIL_GROUP (unsigned short) (0x2)
#define FIL_BRDCST (unsigned short) (0x4)
#define FIL_ALL (unsigned short) (0x8)
#define SET_RX_EARLY_THRESH (unsigned short) (0x11<<11)
#define SET_TX_AVAIL_THRESH (unsigned short) (0x12<<11)
#define SET_TX_START_THRESH (unsigned short) (0x13<<11)
#define STATS_ENABLE (unsigned short) (0x15<<11)
#define STATS_DISABLE (unsigned short) (0x16<<11)
#define STOP_TRANSCEIVER (unsigned short) (0x17<<11)
/*
* The following C_* acknowledge the various interrupts. Some of them don't
* do anything. See the manual.
*/
#define ACK_INTR (unsigned short) (0x6800)
#define C_INTR_LATCH (unsigned short) (ACK_INTR|0x1)
#define C_CARD_FAILURE (unsigned short) (ACK_INTR|0x2)
#define C_TX_COMPLETE (unsigned short) (ACK_INTR|0x4)
#define C_TX_AVAIL (unsigned short) (ACK_INTR|0x8)
#define C_RX_COMPLETE (unsigned short) (ACK_INTR|0x10)
#define C_RX_EARLY (unsigned short) (ACK_INTR|0x20)
#define C_INT_RQD (unsigned short) (ACK_INTR|0x40)
#define C_UPD_STATS (unsigned short) (ACK_INTR|0x80)
/*
* Status register. All windows.
*
* 15-13: Window number(0-7).
* 12: Command_in_progress.
* 11: reserved.
* 10: reserved.
* 9: reserved.
* 8: reserved.
* 7: Update Statistics.
* 6: Interrupt Requested.
* 5: RX Early.
* 4: RX Complete.
* 3: TX Available.
* 2: TX Complete.
* 1: Adapter Failure.
* 0: Interrupt Latch.
*/
#define S_INTR_LATCH (unsigned short) (0x1)
#define S_CARD_FAILURE (unsigned short) (0x2)
#define S_TX_COMPLETE (unsigned short) (0x4)
#define S_TX_AVAIL (unsigned short) (0x8)
#define S_RX_COMPLETE (unsigned short) (0x10)
#define S_RX_EARLY (unsigned short) (0x20)
#define S_INT_RQD (unsigned short) (0x40)
#define S_UPD_STATS (unsigned short) (0x80)
#define S_5_INTS (S_CARD_FAILURE|S_TX_COMPLETE|\
S_TX_AVAIL|S_RX_COMPLETE|S_RX_EARLY)
#define S_COMMAND_IN_PROGRESS (unsigned short) (0x1000)
/*
* FIFO Registers.
* RX Status. Window 1/Port 08
*
* 15: Incomplete or FIFO empty.
* 14: 1: Error in RX Packet 0: Incomplete or no error.
* 13-11: Type of error.
* 1000 = Overrun.
* 1011 = Run Packet Error.
* 1100 = Alignment Error.
* 1101 = CRC Error.
* 1001 = Oversize Packet Error (>1514 bytes)
* 0010 = Dribble Bits.
* (all other error codes, no errors.)
*
* 10-0: RX Bytes (0-1514)
*/
#define ERR_RX_INCOMPLETE (unsigned short) (0x1<<15)
#define ERR_RX (unsigned short) (0x1<<14)
#define ERR_RX_OVERRUN (unsigned short) (0x8<<11)
#define ERR_RX_RUN_PKT (unsigned short) (0xb<<11)
#define ERR_RX_ALIGN (unsigned short) (0xc<<11)
#define ERR_RX_CRC (unsigned short) (0xd<<11)
#define ERR_RX_OVERSIZE (unsigned short) (0x9<<11)
#define ERR_RX_DRIBBLE (unsigned short) (0x2<<11)
/*
* FIFO Registers.
* TX Status. Window 1/Port 0B
*
* Reports the transmit status of a completed transmission. Writing this
* register pops the transmit completion stack.
*
* Window 1/Port 0x0b.
*
* 7: Complete
* 6: Interrupt on successful transmission requested.
* 5: Jabber Error (TP Only, TX Reset required. )
* 4: Underrun (TX Reset required. )
* 3: Maximum Collisions.
* 2: TX Status Overflow.
* 1-0: Undefined.
*
*/
#define TXS_COMPLETE 0x80
#define TXS_SUCCES_INTR_REQ 0x40
#define TXS_JABBER 0x20
#define TXS_UNDERRUN 0x10
#define TXS_MAX_COLLISION 0x8
#define TXS_STATUS_OVERFLOW 0x4
/*
* Configuration control register.
* Window 0/Port 04
*/
/* Read */
#define IS_AUI (1<<13)
#define IS_BNC (1<<12)
#define IS_UTP (1<<9)
/* Write */
#define ENABLE_DRQ_IRQ 0x0001
#define W0_P4_CMD_RESET_ADAPTER 0x4
#define W0_P4_CMD_ENABLE_ADAPTER 0x1
/*
* Media type and status.
* Window 4/Port 0A
*/
#define ENABLE_UTP 0xc0
#define DISABLE_UTP 0x0
/*
* Resource control register
*/
#define SET_IRQ(i) ( ((i)<<12) | 0xF00) /* set IRQ i */
/*
* Receive status register
*/
#define RX_BYTES_MASK (unsigned short) (0x07ff)
#define RX_ERROR 0x4000
#define RX_INCOMPLETE 0x8000
/*
* Misc defines for various things.
*/
#define ACTIVATE_ADAPTER_TO_CONFIG 0xff /* to the id_port */
#define MFG_ID 0x6d50 /* in EEPROM and W0 ADDR_CONFIG */
#define PROD_ID 0x9150
#define AUI 0x1
#define BNC 0x2
#define UTP 0x4
#define RX_BYTES_MASK (unsigned short) (0x07ff)
/* EISA support */
#define EP_EISA_START 0x1000
#define EP_EISA_W0 0x0c80
#ifdef INCLUDE_3C529
/* MCA support */
#define MCA_MOTHERBOARD_SETUP_REG 0x94
#define MCA_ADAPTER_SETUP_REG 0x96
#define MCA_MAX_SLOT_NR 8
#define MCA_POS_REG(n) (0x100+(n))
#endif
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+503
View File
@@ -0,0 +1,503 @@
/*
* 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
*
* Copyright (C) 2000 Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
* All rights reserved.
* Mar. 14, 2000
*
* This software may be used, modified, copied, distributed, and sold, in
* both source and binary form provided that the above copyright and these
* terms are retained. Under no circumstances are the authors responsible for
* the proper functioning of this software, nor do the authors assume any
* responsibility for damages incurred with its use.
*
* This code is based on Martin Renters' etherboot-4.4.3 3c509.c and
* Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver.
*
* Copyright (C) 1993-1994, David Greenman, Martin Renters.
* Copyright (C) 1993-1995, Andres Vega Garcia.
* Copyright (C) 1995, Serge Babkin.
*
* Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
*
*/
/* #define EDEBUG */
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "3c595.h"
#include "timer.h"
static unsigned short eth_nic_base, eth_asic_base;
static unsigned short vx_connector, vx_connectors;
static struct connector_entry {
int bit;
char *name;
} conn_tab[VX_CONNECTORS] = {
#define CONNECTOR_UTP 0
{ 0x08, "utp"},
#define CONNECTOR_AUI 1
{ 0x20, "aui"},
/* dummy */
{ 0, "???"},
#define CONNECTOR_BNC 3
{ 0x10, "bnc"},
#define CONNECTOR_TX 4
{ 0x02, "tx"},
#define CONNECTOR_FX 5
{ 0x04, "fx"},
#define CONNECTOR_MII 6
{ 0x40, "mii"},
{ 0, "???"}
};
static void vxgetlink(void);
static void vxsetlink(void);
#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000)
/**************************************************************************
ETH_RESET - Reset adapter
***************************************************************************/
static void t595_reset(struct nic *nic)
{
int i, j;
/***********************************************************
Reset 3Com 595 card
*************************************************************/
/* stop card */
outw(RX_DISABLE, BASE + VX_COMMAND);
outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
VX_BUSY_WAIT;
outw(TX_DISABLE, BASE + VX_COMMAND);
outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
udelay(8000);
outw(RX_RESET, BASE + VX_COMMAND);
VX_BUSY_WAIT;
outw(TX_RESET, BASE + VX_COMMAND);
VX_BUSY_WAIT;
outw(C_INTR_LATCH, BASE + VX_COMMAND);
outw(SET_RD_0_MASK, BASE + VX_COMMAND);
outw(SET_INTR_MASK, BASE + VX_COMMAND);
outw(SET_RX_FILTER, BASE + VX_COMMAND);
/*
* initialize card
*/
VX_BUSY_WAIT;
GO_WINDOW(0);
/* Disable the card */
/* outw(0, BASE + VX_W0_CONFIG_CTRL); */
/* Configure IRQ to none */
/* outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
/* Enable the card */
/* outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
GO_WINDOW(2);
/* Reload the ether_addr. */
for (i = 0; i < ETH_ALEN; i++)
outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
outw(RX_RESET, BASE + VX_COMMAND);
VX_BUSY_WAIT;
outw(TX_RESET, BASE + VX_COMMAND);
VX_BUSY_WAIT;
/* Window 1 is operating window */
GO_WINDOW(1);
for (i = 0; i < 31; i++)
inb(BASE + VX_W1_TX_STATUS);
outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
/*
* Attempt to get rid of any stray interrupts that occured during
* configuration. On the i386 this isn't possible because one may
* already be queued. However, a single stray interrupt is
* unimportant.
*/
outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
outw(SET_RX_FILTER | FIL_INDIVIDUAL |
FIL_BRDCST, BASE + VX_COMMAND);
vxsetlink();
/*{
int i,j;
i = CONNECTOR_TX;
GO_WINDOW(3);
j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
GO_WINDOW(4);
outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
GO_WINDOW(1);
}*/
/* start tranciever and receiver */
outw(RX_ENABLE, BASE + VX_COMMAND);
outw(TX_ENABLE, BASE + VX_COMMAND);
}
/**************************************************************************
ETH_TRANSMIT - Transmit a frame
***************************************************************************/
static char padmap[] = {
0, 3, 2, 1};
static void t595_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
register int len;
int pad;
int status;
#ifdef EDEBUG
printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
#endif
/* swap bytes of type */
t= htons(t);
len=s+ETH_HLEN; /* actual length of packet */
pad = padmap[len & 3];
/*
* The 3c595 automatically pads short packets to minimum ethernet length,
* but we drop packets that are too large. Perhaps we should truncate
* them instead?
*/
if (len + pad > ETH_FRAME_LEN) {
return;
}
/* drop acknowledgements */
while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
outw(TX_RESET, BASE + VX_COMMAND);
outw(TX_ENABLE, BASE + VX_COMMAND);
}
outb(0x0, BASE + VX_W1_TX_STATUS);
}
while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
/* no room in FIFO */
}
outw(len, BASE + VX_W1_TX_PIO_WR_1);
outw(0x0, BASE + VX_W1_TX_PIO_WR_1); /* Second dword meaningless */
/* write packet */
outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
outw(t, BASE + VX_W1_TX_PIO_WR_1);
outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
if (s & 1)
outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
while (pad--)
outb(0, BASE + VX_W1_TX_PIO_WR_1); /* Padding */
/* wait for Tx complete */
while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
;
}
/**************************************************************************
ETH_POLL - Wait for a frame
***************************************************************************/
static int t595_poll(struct nic *nic)
{
/* common variables */
unsigned short type = 0; /* used by EDEBUG */
/* variables for 3C595 */
short status, cst;
register short rx_fifo;
cst=inw(BASE + VX_STATUS);
#ifdef EDEBUG
if(cst & 0x1FFF)
printf("-%hX-",cst);
#endif
if( (cst & S_RX_COMPLETE)==0 ) {
/* acknowledge everything */
outw(ACK_INTR | cst, BASE + VX_COMMAND);
outw(C_INTR_LATCH, BASE + VX_COMMAND);
return 0;
}
status = inw(BASE + VX_W1_RX_STATUS);
#ifdef EDEBUG
printf("*%hX*",status);
#endif
if (status & ERR_RX) {
outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
return 0;
}
rx_fifo = status & RX_BYTES_MASK;
if (rx_fifo==0)
return 0;
/* read packet */
#ifdef EDEBUG
printf("[l=%d",rx_fifo);
#endif
insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
if(rx_fifo & 1)
nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
nic->packetlen=rx_fifo;
while(1) {
status = inw(BASE + VX_W1_RX_STATUS);
#ifdef EDEBUG
printf("*%hX*",status);
#endif
rx_fifo = status & RX_BYTES_MASK;
if(rx_fifo>0) {
insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
if(rx_fifo & 1)
nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
nic->packetlen+=rx_fifo;
#ifdef EDEBUG
printf("+%d",rx_fifo);
#endif
}
if(( status & RX_INCOMPLETE )==0) {
#ifdef EDEBUG
printf("=%d",nic->packetlen);
#endif
break;
}
udelay(1000);
}
/* acknowledge reception of packet */
outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
#ifdef EDEBUG
type = (nic->packet[12]<<8) | nic->packet[13];
if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
nic->packet[5] == 0xFF*ETH_ALEN)
printf(",t=%hX,b]",type);
else
printf(",t=%hX]",type);
#endif
return 1;
}
/*************************************************************************
3Com 595 - specific routines
**************************************************************************/
static int
eeprom_rdy()
{
int i;
for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
udelay(1000);
if (i >= MAX_EEPROMBUSY) {
/* printf("3c595: eeprom failed to come ready.\n"); */
printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */
return (0);
}
return (1);
}
/*
* get_e: gets a 16 bits word from the EEPROM. we must have set the window
* before
*/
static int
get_e(offset)
int offset;
{
if (!eeprom_rdy())
return (0xffff);
outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
if (!eeprom_rdy())
return (0xffff);
return (inw(BASE + VX_W0_EEPROM_DATA));
}
static void
vxgetlink(void)
{
int n, k;
GO_WINDOW(3);
vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
if (vx_connectors & conn_tab[k].bit) {
if (n > 0) {
printf("/");
}
printf(conn_tab[k].name);
n++;
}
}
if (vx_connectors == 0) {
printf("no connectors!");
return;
}
GO_WINDOW(3);
vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG)
& INTERNAL_CONNECTOR_MASK)
>> INTERNAL_CONNECTOR_BITS;
if (vx_connector & 0x10) {
vx_connector &= 0x0f;
printf("[*%s*]", conn_tab[vx_connector].name);
printf(": disable 'auto select' with DOS util!");
} else {
printf("[*%s*]", conn_tab[vx_connector].name);
}
}
static void
vxsetlink(void)
{
int i, j, k;
char *reason, *warning;
static short prev_flags;
static char prev_conn = -1;
if (prev_conn == -1) {
prev_conn = vx_connector;
}
i = vx_connector; /* default in EEPROM */
reason = "default";
warning = 0;
if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
warning = "strange connector type in EEPROM.";
reason = "forced";
i = CONNECTOR_UTP;
}
if (warning != 0) {
printf("warning: %s\n", warning);
}
printf("selected %s. (%s)\n", conn_tab[i].name, reason);
/* Set the selected connector. */
GO_WINDOW(3);
j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
/* First, disable all. */
outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
udelay(8000);
GO_WINDOW(4);
outw(0, BASE + VX_W4_MEDIA_TYPE);
/* Second, enable the selected one. */
switch(i) {
case CONNECTOR_UTP:
GO_WINDOW(4);
outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
break;
case CONNECTOR_BNC:
outw(START_TRANSCEIVER,BASE + VX_COMMAND);
udelay(8000);
break;
case CONNECTOR_TX:
case CONNECTOR_FX:
GO_WINDOW(4);
outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
break;
default: /* AUI and MII fall here */
break;
}
GO_WINDOW(1);
}
static void t595_disable(struct nic *nic)
{
outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
udelay(8000);
GO_WINDOW(4);
outw(0, BASE + VX_W4_MEDIA_TYPE);
GO_WINDOW(1);
}
/**************************************************************************
ETH_PROBE - Look for an adapter
***************************************************************************/
struct nic *t595_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci)
{
int i;
unsigned short *p;
if (probeaddrs == 0 || probeaddrs[0] == 0)
return 0;
/* eth_nic_base = probeaddrs[0] & ~3; */
eth_nic_base = pci->ioaddr;
GO_WINDOW(0);
outw(GLOBAL_RESET, BASE + VX_COMMAND);
VX_BUSY_WAIT;
vxgetlink();
/*
printf("\nEEPROM:");
for (i = 0; i < (EEPROMSIZE/2); i++) {
printf("%hX:", get_e(i));
}
printf("\n");
*/
/*
* Read the station address from the eeprom
*/
p = (unsigned short *) nic->node_addr;
for (i = 0; i < 3; i++) {
GO_WINDOW(0);
p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
GO_WINDOW(2);
outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
}
printf("Ethernet address: %!\n", nic->node_addr);
t595_reset(nic);
nic->reset = t595_reset;
nic->poll = t595_poll;
nic->transmit = t595_transmit;
nic->disable = t595_disable;
return nic;
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+435
View File
@@ -0,0 +1,435 @@
/*
* Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. 2. The name
* of the author may not be used to endorse or promote products derived from
* this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
October 2, 1994
Modified by: Andres Vega Garcia
INRIA - Sophia Antipolis, France
e-mail: avega@sophia.inria.fr
finger: avega@pax.inria.fr
*/
/*
* Created from if_epreg.h by Fred Gray (fgray@rice.edu) to support the
* 3c590 family.
*/
/*
* Modified by Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
* for etherboot
* Mar. 14, 2000
*/
/*
* Ethernet software status per interface.
*/
/*
* Some global constants
*/
#define TX_INIT_RATE 16
#define TX_INIT_MAX_RATE 64
#define RX_INIT_LATENCY 64
#define RX_INIT_EARLY_THRESH 64
#define MIN_RX_EARLY_THRESHF 16 /* not less than ether_header */
#define MIN_RX_EARLY_THRESHL 4
#define EEPROMSIZE 0x40
#define MAX_EEPROMBUSY 1000
#define VX_LAST_TAG 0xd7
#define VX_MAX_BOARDS 16
#define VX_ID_PORT 0x100
/*
* some macros to acces long named fields
*/
#define BASE (eth_nic_base)
/*
* Commands to read/write EEPROM trough EEPROM command register (Window 0,
* Offset 0xa)
*/
#define EEPROM_CMD_RD 0x0080 /* Read: Address required (5 bits) */
#define EEPROM_CMD_WR 0x0040 /* Write: Address required (5 bits) */
#define EEPROM_CMD_ERASE 0x00c0 /* Erase: Address required (5 bits) */
#define EEPROM_CMD_EWEN 0x0030 /* Erase/Write Enable: No data required */
#define EEPROM_BUSY (1<<15)
/*
* Some short functions, worth to let them be a macro
*/
/**************************************************************************
* *
* These define the EEPROM data structure. They are used in the probe
* function to verify the existence of the adapter after having sent
* the ID_Sequence.
*
* There are others but only the ones we use are defined here.
*
**************************************************************************/
#define EEPROM_NODE_ADDR_0 0x0 /* Word */
#define EEPROM_NODE_ADDR_1 0x1 /* Word */
#define EEPROM_NODE_ADDR_2 0x2 /* Word */
#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */
#define EEPROM_MFG_ID 0x7 /* 0x6d50 */
#define EEPROM_ADDR_CFG 0x8 /* Base addr */
#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */
#define EEPROM_OEM_ADDR_0 0xa /* Word */
#define EEPROM_OEM_ADDR_1 0xb /* Word */
#define EEPROM_OEM_ADDR_2 0xc /* Word */
#define EEPROM_SOFT_INFO_2 0xf /* Software information 2 */
#define NO_RX_OVN_ANOMALY (1<<5)
/**************************************************************************
* *
* These are the registers for the 3Com 3c509 and their bit patterns when *
* applicable. They have been taken out the the "EtherLink III Parallel *
* Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual *
* from 3com. *
* *
**************************************************************************/
#define VX_COMMAND 0x0e /* Write. BASE+0x0e is always a
* command reg. */
#define VX_STATUS 0x0e /* Read. BASE+0x0e is always status
* reg. */
#define VX_WINDOW 0x0f /* Read. BASE+0x0f is always window
* reg. */
/*
* Window 0 registers. Setup.
*/
/* Write */
#define VX_W0_EEPROM_DATA 0x0c
#define VX_W0_EEPROM_COMMAND 0x0a
#define VX_W0_RESOURCE_CFG 0x08
#define VX_W0_ADDRESS_CFG 0x06
#define VX_W0_CONFIG_CTRL 0x04
/* Read */
#define VX_W0_PRODUCT_ID 0x02
#define VX_W0_MFG_ID 0x00
/*
* Window 1 registers. Operating Set.
*/
/* Write */
#define VX_W1_TX_PIO_WR_2 0x02
#define VX_W1_TX_PIO_WR_1 0x00
/* Read */
#define VX_W1_FREE_TX 0x0c
#define VX_W1_TX_STATUS 0x0b /* byte */
#define VX_W1_TIMER 0x0a /* byte */
#define VX_W1_RX_STATUS 0x08
#define VX_W1_RX_PIO_RD_2 0x02
#define VX_W1_RX_PIO_RD_1 0x00
/*
* Window 2 registers. Station Address Setup/Read
*/
/* Read/Write */
#define VX_W2_ADDR_5 0x05
#define VX_W2_ADDR_4 0x04
#define VX_W2_ADDR_3 0x03
#define VX_W2_ADDR_2 0x02
#define VX_W2_ADDR_1 0x01
#define VX_W2_ADDR_0 0x00
/*
* Window 3 registers. FIFO Management.
*/
/* Read */
#define VX_W3_INTERNAL_CFG 0x00
#define VX_W3_RESET_OPT 0x08
#define VX_W3_FREE_TX 0x0c
#define VX_W3_FREE_RX 0x0a
/*
* Window 4 registers. Diagnostics.
*/
/* Read/Write */
#define VX_W4_MEDIA_TYPE 0x0a
#define VX_W4_CTRLR_STATUS 0x08
#define VX_W4_NET_DIAG 0x06
#define VX_W4_FIFO_DIAG 0x04
#define VX_W4_HOST_DIAG 0x02
#define VX_W4_TX_DIAG 0x00
/*
* Window 5 Registers. Results and Internal status.
*/
/* Read */
#define VX_W5_READ_0_MASK 0x0c
#define VX_W5_INTR_MASK 0x0a
#define VX_W5_RX_FILTER 0x08
#define VX_W5_RX_EARLY_THRESH 0x06
#define VX_W5_TX_AVAIL_THRESH 0x02
#define VX_W5_TX_START_THRESH 0x00
/*
* Window 6 registers. Statistics.
*/
/* Read/Write */
#define TX_TOTAL_OK 0x0c
#define RX_TOTAL_OK 0x0a
#define TX_DEFERRALS 0x08
#define RX_FRAMES_OK 0x07
#define TX_FRAMES_OK 0x06
#define RX_OVERRUNS 0x05
#define TX_COLLISIONS 0x04
#define TX_AFTER_1_COLLISION 0x03
#define TX_AFTER_X_COLLISIONS 0x02
#define TX_NO_SQE 0x01
#define TX_CD_LOST 0x00
/****************************************
*
* Register definitions.
*
****************************************/
/*
* Command register. All windows.
*
* 16 bit register.
* 15-11: 5-bit code for command to be executed.
* 10-0: 11-bit arg if any. For commands with no args;
* this can be set to anything.
*/
#define GLOBAL_RESET (unsigned short) 0x0000 /* Wait at least 1ms
* after issuing */
#define WINDOW_SELECT (unsigned short) (0x1<<11)
#define START_TRANSCEIVER (unsigned short) (0x2<<11) /* Read ADDR_CFG reg to
* determine whether
* this is needed. If
* so; wait 800 uSec
* before using trans-
* ceiver. */
#define RX_DISABLE (unsigned short) (0x3<<11) /* state disabled on
* power-up */
#define RX_ENABLE (unsigned short) (0x4<<11)
#define RX_RESET (unsigned short) (0x5<<11)
#define RX_DISCARD_TOP_PACK (unsigned short) (0x8<<11)
#define TX_ENABLE (unsigned short) (0x9<<11)
#define TX_DISABLE (unsigned short) (0xa<<11)
#define TX_RESET (unsigned short) (0xb<<11)
#define REQ_INTR (unsigned short) (0xc<<11)
/*
* The following C_* acknowledge the various interrupts. Some of them don't
* do anything. See the manual.
*/
#define ACK_INTR (unsigned short) (0x6800)
# define C_INTR_LATCH (unsigned short) (ACK_INTR|0x1)
# define C_CARD_FAILURE (unsigned short) (ACK_INTR|0x2)
# define C_TX_COMPLETE (unsigned short) (ACK_INTR|0x4)
# define C_TX_AVAIL (unsigned short) (ACK_INTR|0x8)
# define C_RX_COMPLETE (unsigned short) (ACK_INTR|0x10)
# define C_RX_EARLY (unsigned short) (ACK_INTR|0x20)
# define C_INT_RQD (unsigned short) (ACK_INTR|0x40)
# define C_UPD_STATS (unsigned short) (ACK_INTR|0x80)
#define SET_INTR_MASK (unsigned short) (0xe<<11)
#define SET_RD_0_MASK (unsigned short) (0xf<<11)
#define SET_RX_FILTER (unsigned short) (0x10<<11)
# define FIL_INDIVIDUAL (unsigned short) (0x1)
# define FIL_MULTICAST (unsigned short) (0x02)
# define FIL_BRDCST (unsigned short) (0x04)
# define FIL_PROMISC (unsigned short) (0x08)
#define SET_RX_EARLY_THRESH (unsigned short) (0x11<<11)
#define SET_TX_AVAIL_THRESH (unsigned short) (0x12<<11)
#define SET_TX_START_THRESH (unsigned short) (0x13<<11)
#define STATS_ENABLE (unsigned short) (0x15<<11)
#define STATS_DISABLE (unsigned short) (0x16<<11)
#define STOP_TRANSCEIVER (unsigned short) (0x17<<11)
/*
* Status register. All windows.
*
* 15-13: Window number(0-7).
* 12: Command_in_progress.
* 11: reserved.
* 10: reserved.
* 9: reserved.
* 8: reserved.
* 7: Update Statistics.
* 6: Interrupt Requested.
* 5: RX Early.
* 4: RX Complete.
* 3: TX Available.
* 2: TX Complete.
* 1: Adapter Failure.
* 0: Interrupt Latch.
*/
#define S_INTR_LATCH (unsigned short) (0x1)
#define S_CARD_FAILURE (unsigned short) (0x2)
#define S_TX_COMPLETE (unsigned short) (0x4)
#define S_TX_AVAIL (unsigned short) (0x8)
#define S_RX_COMPLETE (unsigned short) (0x10)
#define S_RX_EARLY (unsigned short) (0x20)
#define S_INT_RQD (unsigned short) (0x40)
#define S_UPD_STATS (unsigned short) (0x80)
#define S_COMMAND_IN_PROGRESS (unsigned short) (0x1000)
#define VX_BUSY_WAIT while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS)
/* Address Config. Register.
* Window 0/Port 06
*/
#define ACF_CONNECTOR_BITS 14
#define ACF_CONNECTOR_UTP 0
#define ACF_CONNECTOR_AUI 1
#define ACF_CONNECTOR_BNC 3
#define INTERNAL_CONNECTOR_BITS 20
#define INTERNAL_CONNECTOR_MASK 0x01700000
/*
* FIFO Registers. RX Status.
*
* 15: Incomplete or FIFO empty.
* 14: 1: Error in RX Packet 0: Incomplete or no error.
* 13-11: Type of error.
* 1000 = Overrun.
* 1011 = Run Packet Error.
* 1100 = Alignment Error.
* 1101 = CRC Error.
* 1001 = Oversize Packet Error (>1514 bytes)
* 0010 = Dribble Bits.
* (all other error codes, no errors.)
*
* 10-0: RX Bytes (0-1514)
*/
#define ERR_INCOMPLETE (unsigned short) (0x8000)
#define ERR_RX (unsigned short) (0x4000)
#define ERR_MASK (unsigned short) (0x7800)
#define ERR_OVERRUN (unsigned short) (0x4000)
#define ERR_RUNT (unsigned short) (0x5800)
#define ERR_ALIGNMENT (unsigned short) (0x6000)
#define ERR_CRC (unsigned short) (0x6800)
#define ERR_OVERSIZE (unsigned short) (0x4800)
#define ERR_DRIBBLE (unsigned short) (0x1000)
/*
* TX Status.
*
* Reports the transmit status of a completed transmission. Writing this
* register pops the transmit completion stack.
*
* Window 1/Port 0x0b.
*
* 7: Complete
* 6: Interrupt on successful transmission requested.
* 5: Jabber Error (TP Only, TX Reset required. )
* 4: Underrun (TX Reset required. )
* 3: Maximum Collisions.
* 2: TX Status Overflow.
* 1-0: Undefined.
*
*/
#define TXS_COMPLETE 0x80
#define TXS_INTR_REQ 0x40
#define TXS_JABBER 0x20
#define TXS_UNDERRUN 0x10
#define TXS_MAX_COLLISION 0x8
#define TXS_STATUS_OVERFLOW 0x4
#define RS_AUI (1<<5)
#define RS_BNC (1<<4)
#define RS_UTP (1<<3)
#define RS_T4 (1<<0)
#define RS_TX (1<<1)
#define RS_FX (1<<2)
#define RS_MII (1<<6)
/*
* FIFO Status (Window 4)
*
* Supports FIFO diagnostics
*
* Window 4/Port 0x04.1
*
* 15: 1=RX receiving (RO). Set when a packet is being received
* into the RX FIFO.
* 14: Reserved
* 13: 1=RX underrun (RO). Generates Adapter Failure interrupt.
* Requires RX Reset or Global Reset command to recover.
* It is generated when you read past the end of a packet -
* reading past what has been received so far will give bad
* data.
* 12: 1=RX status overrun (RO). Set when there are already 8
* packets in the RX FIFO. While this bit is set, no additional
* packets are received. Requires no action on the part of
* the host. The condition is cleared once a packet has been
* read out of the RX FIFO.
* 11: 1=RX overrun (RO). Set when the RX FIFO is full (there
* may not be an overrun packet yet). While this bit is set,
* no additional packets will be received (some additional
* bytes can still be pending between the wire and the RX
* FIFO). Requires no action on the part of the host. The
* condition is cleared once a few bytes have been read out
* from the RX FIFO.
* 10: 1=TX overrun (RO). Generates adapter failure interrupt.
* Requires TX Reset or Global Reset command to recover.
* Disables Transmitter.
* 9-8: Unassigned.
* 7-0: Built in self test bits for the RX and TX FIFO's.
*/
#define FIFOS_RX_RECEIVING (unsigned short) 0x8000
#define FIFOS_RX_UNDERRUN (unsigned short) 0x2000
#define FIFOS_RX_STATUS_OVERRUN (unsigned short) 0x1000
#define FIFOS_RX_OVERRUN (unsigned short) 0x0800
#define FIFOS_TX_OVERRUN (unsigned short) 0x0400
/*
* Misc defines for various things.
*/
#define TAG_ADAPTER 0xd0
#define ACTIVATE_ADAPTER_TO_CONFIG 0xff
#define ENABLE_DRQ_IRQ 0x0001
#define MFG_ID 0x506d /* `TCM' */
#define PROD_ID 0x5090
#define GO_WINDOW(x) outw(WINDOW_SELECT|(x),BASE+VX_COMMAND)
#define JABBER_GUARD_ENABLE 0x40
#define LINKBEAT_ENABLE 0x80
#define ENABLE_UTP (JABBER_GUARD_ENABLE | LINKBEAT_ENABLE)
#define DISABLE_UTP 0x0
#define RX_BYTES_MASK (unsigned short) (0x07ff)
#define RX_ERROR 0x4000
#define RX_INCOMPLETE 0x8000
#define TX_INDICATE 1<<15
#define is_eeprom_busy(b) (inw((b)+VX_W0_EEPROM_COMMAND)&EEPROM_BUSY)
#define VX_IOSIZE 0x20
#define VX_CONNECTORS 8
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+929
View File
@@ -0,0 +1,929 @@
/*
* 3c90x.c -- This file implements the 3c90x driver for etherboot. Written
* by Greg Beeley, Greg.Beeley@LightSys.org. Modified by Steve Smith,
* Steve.Smith@Juno.Com
*
* This program Copyright (C) 1999 LightSys Technology Services, Inc.
* Portions Copyright (C) 1999 Steve Smith
*
* This program may be re-distributed in source or binary form, modified,
* sold, or copied for any purpose, provided that the above copyright message
* and this text are included with all source copies or derivative works, and
* provided that the above copyright message and this text are included in the
* documentation of any binary-only distributions. This program is distributed
* WITHOUT ANY WARRANTY, without even the warranty of FITNESS FOR A PARTICULAR
* PURPOSE or MERCHANTABILITY. Please read the associated documentation
* "3c90x.txt" before compiling and using this driver.
*
* --------
*
* Program written with the assistance of the 3com documentation for
* the 3c905B-TX card, as well as with some assistance from the 3c59x
* driver Donald Becker wrote for the Linux kernel, and with some assistance
* from the remainder of the Etherboot distribution.
*
* REVISION HISTORY:
*
* v0.10 1-26-1998 GRB Initial implementation.
* v0.90 1-27-1998 GRB System works.
* v1.00pre1 2-11-1998 GRB Got prom boot issue fixed.
* v2.0 9-24-1999 SCS Modified for 3c905 (from 3c905b code)
* Re-wrote poll and transmit for
* better error recovery and heavy
* network traffic operation
*
*/
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "cards.h"
#include "timer.h"
#define XCVR_MAGIC (0x5A00)
/** any single transmission fails after 16 collisions or other errors
** this is the number of times to retry the transmission -- this should
** be plenty
**/
#define XMIT_RETRIES 250
#undef virt_to_bus
#define virt_to_bus(x) ((unsigned long)x)
/*** Register definitions for the 3c905 ***/
enum Registers
{
regPowerMgmtCtrl_w = 0x7c, /** 905B Revision Only **/
regUpMaxBurst_w = 0x7a, /** 905B Revision Only **/
regDnMaxBurst_w = 0x78, /** 905B Revision Only **/
regDebugControl_w = 0x74, /** 905B Revision Only **/
regDebugData_l = 0x70, /** 905B Revision Only **/
regRealTimeCnt_l = 0x40, /** Universal **/
regUpBurstThresh_b = 0x3e, /** 905B Revision Only **/
regUpPoll_b = 0x3d, /** 905B Revision Only **/
regUpPriorityThresh_b = 0x3c, /** 905B Revision Only **/
regUpListPtr_l = 0x38, /** Universal **/
regCountdown_w = 0x36, /** Universal **/
regFreeTimer_w = 0x34, /** Universal **/
regUpPktStatus_l = 0x30, /** Universal with Exception, pg 130 **/
regTxFreeThresh_b = 0x2f, /** 90X Revision Only **/
regDnPoll_b = 0x2d, /** 905B Revision Only **/
regDnPriorityThresh_b = 0x2c, /** 905B Revision Only **/
regDnBurstThresh_b = 0x2a, /** 905B Revision Only **/
regDnListPtr_l = 0x24, /** Universal with Exception, pg 107 **/
regDmaCtrl_l = 0x20, /** Universal with Exception, pg 106 **/
/** **/
regIntStatusAuto_w = 0x1e, /** 905B Revision Only **/
regTxStatus_b = 0x1b, /** Universal with Exception, pg 113 **/
regTimer_b = 0x1a, /** Universal **/
regTxPktId_b = 0x18, /** 905B Revision Only **/
regCommandIntStatus_w = 0x0e, /** Universal (Command Variations) **/
};
/** following are windowed registers **/
enum Registers7
{
regPowerMgmtEvent_7_w = 0x0c, /** 905B Revision Only **/
regVlanEtherType_7_w = 0x04, /** 905B Revision Only **/
regVlanMask_7_w = 0x00, /** 905B Revision Only **/
};
enum Registers6
{
regBytesXmittedOk_6_w = 0x0c, /** Universal **/
regBytesRcvdOk_6_w = 0x0a, /** Universal **/
regUpperFramesOk_6_b = 0x09, /** Universal **/
regFramesDeferred_6_b = 0x08, /** Universal **/
regFramesRecdOk_6_b = 0x07, /** Universal with Exceptions, pg 142 **/
regFramesXmittedOk_6_b = 0x06, /** Universal **/
regRxOverruns_6_b = 0x05, /** Universal **/
regLateCollisions_6_b = 0x04, /** Universal **/
regSingleCollisions_6_b = 0x03, /** Universal **/
regMultipleCollisions_6_b = 0x02, /** Universal **/
regSqeErrors_6_b = 0x01, /** Universal **/
regCarrierLost_6_b = 0x00, /** Universal **/
};
enum Registers5
{
regIndicationEnable_5_w = 0x0c, /** Universal **/
regInterruptEnable_5_w = 0x0a, /** Universal **/
regTxReclaimThresh_5_b = 0x09, /** 905B Revision Only **/
regRxFilter_5_b = 0x08, /** Universal **/
regRxEarlyThresh_5_w = 0x06, /** Universal **/
regTxStartThresh_5_w = 0x00, /** Universal **/
};
enum Registers4
{
regUpperBytesOk_4_b = 0x0d, /** Universal **/
regBadSSD_4_b = 0x0c, /** Universal **/
regMediaStatus_4_w = 0x0a, /** Universal with Exceptions, pg 201 **/
regPhysicalMgmt_4_w = 0x08, /** Universal **/
regNetworkDiagnostic_4_w = 0x06, /** Universal with Exceptions, pg 203 **/
regFifoDiagnostic_4_w = 0x04, /** Universal with Exceptions, pg 196 **/
regVcoDiagnostic_4_w = 0x02, /** Undocumented? **/
};
enum Registers3
{
regTxFree_3_w = 0x0c, /** Universal **/
regRxFree_3_w = 0x0a, /** Universal with Exceptions, pg 125 **/
regResetMediaOptions_3_w = 0x08, /** Media Options on B Revision, **/
/** Reset Options on Non-B Revision **/
regMacControl_3_w = 0x06, /** Universal with Exceptions, pg 199 **/
regMaxPktSize_3_w = 0x04, /** 905B Revision Only **/
regInternalConfig_3_l = 0x00, /** Universal, different bit **/
/** definitions, pg 59 **/
};
enum Registers2
{
regResetOptions_2_w = 0x0c, /** 905B Revision Only **/
regStationMask_2_3w = 0x06, /** Universal with Exceptions, pg 127 **/
regStationAddress_2_3w = 0x00, /** Universal with Exceptions, pg 127 **/
};
enum Registers1
{
regRxStatus_1_w = 0x0a, /** 90X Revision Only, Pg 126 **/
};
enum Registers0
{
regEepromData_0_w = 0x0c, /** Universal **/
regEepromCommand_0_w = 0x0a, /** Universal **/
regBiosRomData_0_b = 0x08, /** 905B Revision Only **/
regBiosRomAddr_0_l = 0x04, /** 905B Revision Only **/
};
/*** The names for the eight register windows ***/
enum Windows
{
winPowerVlan7 = 0x07,
winStatistics6 = 0x06,
winTxRxControl5 = 0x05,
winDiagnostics4 = 0x04,
winTxRxOptions3 = 0x03,
winAddressing2 = 0x02,
winUnused1 = 0x01,
winEepromBios0 = 0x00,
};
/*** Command definitions for the 3c90X ***/
enum Commands
{
cmdGlobalReset = 0x00, /** Universal with Exceptions, pg 151 **/
cmdSelectRegisterWindow = 0x01, /** Universal **/
cmdEnableDcConverter = 0x02, /** **/
cmdRxDisable = 0x03, /** **/
cmdRxEnable = 0x04, /** Universal **/
cmdRxReset = 0x05, /** Universal **/
cmdStallCtl = 0x06, /** Universal **/
cmdTxEnable = 0x09, /** Universal **/
cmdTxDisable = 0x0A, /** **/
cmdTxReset = 0x0B, /** Universal **/
cmdRequestInterrupt = 0x0C, /** **/
cmdAcknowledgeInterrupt = 0x0D, /** Universal **/
cmdSetInterruptEnable = 0x0E, /** Universal **/
cmdSetIndicationEnable = 0x0F, /** Universal **/
cmdSetRxFilter = 0x10, /** Universal **/
cmdSetRxEarlyThresh = 0x11, /** **/
cmdSetTxStartThresh = 0x13, /** **/
cmdStatisticsEnable = 0x15, /** **/
cmdStatisticsDisable = 0x16, /** **/
cmdDisableDcConverter = 0x17, /** **/
cmdSetTxReclaimThresh = 0x18, /** **/
cmdSetHashFilterBit = 0x19, /** **/
};
/*** Values for int status register bitmask **/
#define INT_INTERRUPTLATCH (1<<0)
#define INT_HOSTERROR (1<<1)
#define INT_TXCOMPLETE (1<<2)
#define INT_RXCOMPLETE (1<<4)
#define INT_RXEARLY (1<<5)
#define INT_INTREQUESTED (1<<6)
#define INT_UPDATESTATS (1<<7)
#define INT_LINKEVENT (1<<8)
#define INT_DNCOMPLETE (1<<9)
#define INT_UPCOMPLETE (1<<10)
#define INT_CMDINPROGRESS (1<<12)
#define INT_WINDOWNUMBER (7<<13)
/*** TX descriptor ***/
typedef struct
{
unsigned int DnNextPtr;
unsigned int FrameStartHeader;
unsigned int HdrAddr;
unsigned int HdrLength;
unsigned int DataAddr;
unsigned int DataLength;
}
TXD;
/*** RX descriptor ***/
typedef struct
{
unsigned int UpNextPtr;
unsigned int UpPktStatus;
unsigned int DataAddr;
unsigned int DataLength;
}
RXD;
/*** Global variables ***/
static struct
{
unsigned char isBrev;
unsigned char CurrentWindow;
unsigned int IOAddr;
unsigned char HWAddr[ETH_ALEN];
TXD TransmitDPD;
RXD ReceiveUPD;
}
INF_3C90X;
/*** a3c90x_internal_IssueCommand: sends a command to the 3c90x card
***/
static int
a3c90x_internal_IssueCommand(int ioaddr, int cmd, int param)
{
unsigned int val;
/** Build the cmd. **/
val = cmd;
val <<= 11;
val |= param;
/** Send the cmd to the cmd register **/
outw(val, ioaddr + regCommandIntStatus_w);
/** Wait for the cmd to complete, if necessary **/
while (inw(ioaddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
return 0;
}
/*** a3c90x_internal_SetWindow: selects a register window set.
***/
static int
a3c90x_internal_SetWindow(int ioaddr, int window)
{
/** Window already as set? **/
if (INF_3C90X.CurrentWindow == window) return 0;
/** Issue the window command. **/
a3c90x_internal_IssueCommand(ioaddr, cmdSelectRegisterWindow, window);
INF_3C90X.CurrentWindow = window;
return 0;
}
/*** a3c90x_internal_ReadEeprom - read data from the serial eeprom.
***/
static unsigned short
a3c90x_internal_ReadEeprom(int ioaddr, int address)
{
unsigned short val;
/** Select correct window **/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winEepromBios0);
/** Make sure the eeprom isn't busy **/
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
/** Read the value. **/
outw(address + ((0x02)<<6), ioaddr + regEepromCommand_0_w);
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
val = inw(ioaddr + regEepromData_0_w);
return val;
}
/*** a3c90x_internal_WriteEepromWord - write a physical word of
*** data to the onboard serial eeprom (not the BIOS prom, but the
*** nvram in the card that stores, among other things, the MAC
*** address).
***/
static int
a3c90x_internal_WriteEepromWord(int ioaddr, int address, unsigned short value)
{
/** Select register window **/
a3c90x_internal_SetWindow(ioaddr, winEepromBios0);
/** Verify Eeprom not busy **/
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
/** Issue WriteEnable, and wait for completion. **/
outw(0x30, ioaddr + regEepromCommand_0_w);
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
/** Issue EraseRegister, and wait for completion. **/
outw(address + ((0x03)<<6), ioaddr + regEepromCommand_0_w);
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
/** Send the new data to the eeprom, and wait for completion. **/
outw(value, ioaddr + regEepromData_0_w);
outw(0x30, ioaddr + regEepromCommand_0_w);
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
/** Burn the new data into the eeprom, and wait for completion. **/
outw(address + ((0x01)<<6), ioaddr + regEepromCommand_0_w);
while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
return 0;
}
/*** a3c90x_internal_WriteEeprom - write data to the serial eeprom,
*** and re-compute the eeprom checksum.
***/
static int
a3c90x_internal_WriteEeprom(int ioaddr, int address, unsigned short value)
{
int cksum = 0,v;
int i;
int maxAddress, cksumAddress;
if (INF_3C90X.isBrev)
{
maxAddress=0x1f;
cksumAddress=0x20;
}
else
{
maxAddress=0x16;
cksumAddress=0x17;
}
/** Write the value. **/
if (a3c90x_internal_WriteEepromWord(ioaddr, address, value) == -1)
return -1;
/** Recompute the checksum. **/
for(i=0;i<=maxAddress;i++)
{
v = a3c90x_internal_ReadEeprom(ioaddr, i);
cksum ^= (v & 0xFF);
cksum ^= ((v>>8) & 0xFF);
}
/** Write the checksum to the location in the eeprom **/
if (a3c90x_internal_WriteEepromWord(ioaddr, cksumAddress, cksum) == -1)
return -1;
return 0;
}
/*** a3c90x_reset: exported function that resets the card to its default
*** state. This is so the Linux driver can re-set the card up the way
*** it wants to. If CFG_3C90X_PRESERVE_XCVR is defined, then the reset will
*** not alter the selected transceiver that we used to download the boot
*** image.
***/
static void
a3c90x_reset(struct nic *nic)
{
int cfg;
#ifdef CFG_3C90X_PRESERVE_XCVR
/** Read the current InternalConfig value. **/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
cfg = inl(INF_3C90X.IOAddr + regInternalConfig_3_l);
#endif
/** Send the reset command to the card **/
printf("Issuing RESET:\n");
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdGlobalReset, 0);
/** wait for reset command to complete **/
while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
/** global reset command resets station mask, non-B revision cards
** require explicit reset of values
**/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2);
outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+0);
outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+2);
outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+4);
#ifdef CFG_3C90X_PRESERVE_XCVR
/** Re-set the original InternalConfig value from before reset **/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
outl(cfg, INF_3C90X.IOAddr + regInternalConfig_3_l);
/** enable DC converter for 10-Base-T **/
if ((cfg&0x0300) == 0x0300)
{
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdEnableDcConverter, 0);
}
#endif
/** Issue transmit reset, wait for command completion **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxReset, 0);
while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS)
;
if (! INF_3C90X.isBrev)
outb(0x01, INF_3C90X.IOAddr + regTxFreeThresh_b);
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
/**
** reset of the receiver on B-revision cards re-negotiates the link
** takes several seconds (a computer eternity)
**/
if (INF_3C90X.isBrev)
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x04);
else
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x00);
while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
;
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxEnable, 0);
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
cmdSetInterruptEnable, 0);
/** enable rxComplete and txComplete **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
cmdSetIndicationEnable, 0x0014);
/** acknowledge any pending status flags **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
cmdAcknowledgeInterrupt, 0x661);
return;
}
/*** a3c90x_transmit: exported function that transmits a packet. Does not
*** return any particular status. Parameters are:
*** d[6] - destination address, ethernet;
*** t - protocol type (ARP, IP, etc);
*** s - size of the non-header part of the packet that needs transmitted;
*** p - the pointer to the packet data itself.
***/
static void
a3c90x_transmit(struct nic *nic, const char *d, unsigned int t,
unsigned int s, const char *p)
{
struct eth_hdr
{
unsigned char dst_addr[ETH_ALEN];
unsigned char src_addr[ETH_ALEN];
unsigned short type;
} hdr;
unsigned char status;
unsigned i, retries;
for (retries=0; retries < XMIT_RETRIES ; retries++)
{
/** Stall the download engine **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdStallCtl, 2);
/** Make sure the card is not waiting on us **/
inw(INF_3C90X.IOAddr + regCommandIntStatus_w);
inw(INF_3C90X.IOAddr + regCommandIntStatus_w);
while (inw(INF_3C90X.IOAddr+regCommandIntStatus_w) &
INT_CMDINPROGRESS)
;
/** Set the ethernet packet type **/
hdr.type = htons(t);
/** Copy the destination address **/
memcpy(hdr.dst_addr, d, ETH_ALEN);
/** Copy our MAC address **/
memcpy(hdr.src_addr, INF_3C90X.HWAddr, ETH_ALEN);
/** Setup the DPD (download descriptor) **/
INF_3C90X.TransmitDPD.DnNextPtr = 0;
/** set notification for transmission completion (bit 15) **/
INF_3C90X.TransmitDPD.FrameStartHeader = (s + sizeof(hdr)) | 0x8000;
INF_3C90X.TransmitDPD.HdrAddr = virt_to_bus(&hdr);
INF_3C90X.TransmitDPD.HdrLength = sizeof(hdr);
INF_3C90X.TransmitDPD.DataAddr = virt_to_bus(p);
INF_3C90X.TransmitDPD.DataLength = s + (1<<31);
/** Send the packet **/
outl(virt_to_bus(&(INF_3C90X.TransmitDPD)),
INF_3C90X.IOAddr + regDnListPtr_l);
/** End Stall and Wait for upload to complete. **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdStallCtl, 3);
while(inl(INF_3C90X.IOAddr + regDnListPtr_l) != 0)
;
/** Wait for NIC Transmit to Complete **/
load_timer2(10*TICKS_PER_MS); /* Give it 10 ms */
while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) &&
timer2_running())
;
if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004))
{
printf("3C90X: Tx Timeout\n");
continue;
}
status = inb(INF_3C90X.IOAddr + regTxStatus_b);
/** acknowledge transmit interrupt by writing status **/
outb(0x00, INF_3C90X.IOAddr + regTxStatus_b);
/** successful completion (sans "interrupt Requested" bit) **/
if ((status & 0xbf) == 0x80)
return;
printf("3C90X: Status (%hhX)\n", status);
/** check error codes **/
if (status & 0x02)
{
printf("3C90X: Tx Reclaim Error (%hhX)\n", status);
a3c90x_reset(NULL);
}
else if (status & 0x04)
{
printf("3C90X: Tx Status Overflow (%hhX)\n", status);
for (i=0; i<32; i++)
outb(0x00, INF_3C90X.IOAddr + regTxStatus_b);
/** must re-enable after max collisions before re-issuing tx **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
}
else if (status & 0x08)
{
printf("3C90X: Tx Max Collisions (%hhX)\n", status);
/** must re-enable after max collisions before re-issuing tx **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
}
else if (status & 0x10)
{
printf("3C90X: Tx Underrun (%hhX)\n", status);
a3c90x_reset(NULL);
}
else if (status & 0x20)
{
printf("3C90X: Tx Jabber (%hhX)\n", status);
a3c90x_reset(NULL);
}
else if ((status & 0x80) != 0x80)
{
printf("3C90X: Internal Error - Incomplete Transmission (%hhX)\n",
status);
a3c90x_reset(NULL);
}
}
/** failed after RETRY attempts **/
printf("Failed to send after %d retries\n", retries);
return;
}
/*** a3c90x_poll: exported routine that waits for a certain length of time
*** for a packet, and if it sees none, returns 0. This routine should
*** copy the packet to nic->packet if it gets a packet and set the size
*** in nic->packetlen. Return 1 if a packet was found.
***/
static int
a3c90x_poll(struct nic *nic)
{
int i, errcode;
if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0010))
{
return 0;
}
/** we don't need to acknowledge rxComplete -- the upload engine
** does it for us.
**/
/** Build the up-load descriptor **/
INF_3C90X.ReceiveUPD.UpNextPtr = 0;
INF_3C90X.ReceiveUPD.UpPktStatus = 0;
INF_3C90X.ReceiveUPD.DataAddr = virt_to_bus(nic->packet);
INF_3C90X.ReceiveUPD.DataLength = 1536 + (1<<31);
/** Submit the upload descriptor to the NIC **/
outl(virt_to_bus(&(INF_3C90X.ReceiveUPD)),
INF_3C90X.IOAddr + regUpListPtr_l);
/** Wait for upload completion (upComplete(15) or upError (14)) **/
for(i=0;i<40000;i++);
while((INF_3C90X.ReceiveUPD.UpPktStatus & ((1<<14) | (1<<15))) == 0)
for(i=0;i<40000;i++);
/** Check for Error (else we have good packet) **/
if (INF_3C90X.ReceiveUPD.UpPktStatus & (1<<14))
{
errcode = INF_3C90X.ReceiveUPD.UpPktStatus;
if (errcode & (1<<16))
printf("3C90X: Rx Overrun (%hX)\n",errcode>>16);
else if (errcode & (1<<17))
printf("3C90X: Runt Frame (%hX)\n",errcode>>16);
else if (errcode & (1<<18))
printf("3C90X: Alignment Error (%hX)\n",errcode>>16);
else if (errcode & (1<<19))
printf("3C90X: CRC Error (%hX)\n",errcode>>16);
else if (errcode & (1<<20))
printf("3C90X: Oversized Frame (%hX)\n",errcode>>16);
else
printf("3C90X: Packet error (%hX)\n",errcode>>16);
return 0;
}
/** Ok, got packet. Set length in nic->packetlen. **/
nic->packetlen = (INF_3C90X.ReceiveUPD.UpPktStatus & 0x1FFF);
return 1;
}
/*** a3c90x_disable: exported routine to disable the card. What's this for?
*** the eepro100.c driver didn't have one, so I just left this one empty too.
*** Ideas anyone?
*** Must turn off receiver at least so stray packets will not corrupt memory
*** [Ken]
***/
static void
a3c90x_disable(struct nic *nic)
{
/* Disable the receiver and transmitter. */
outw(cmdRxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w);
outw(cmdTxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w);
}
/*** a3c90x_probe: exported routine to probe for the 3c905 card and perform
*** initialization. If this routine is called, the pci functions did find the
*** card. We just have to init it here.
***/
struct nic*
a3c90x_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci)
{
int i, c;
unsigned short eeprom[0x21];
unsigned int cfg;
unsigned int mopt;
unsigned short linktype;
if (probeaddrs == 0 || probeaddrs[0] == 0)
return 0;
adjust_pci_device(pci);
INF_3C90X.IOAddr = probeaddrs[0] & ~3;
INF_3C90X.CurrentWindow = 255;
switch (a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, 0x03))
{
case 0x9000: /** 10 Base TPO **/
case 0x9001: /** 10/100 T4 **/
case 0x9050: /** 10/100 TPO **/
case 0x9051: /** 10 Base Combo **/
INF_3C90X.isBrev = 0;
break;
case 0x9004: /** 10 Base TPO **/
case 0x9005: /** 10 Base Combo **/
case 0x9006: /** 10 Base TPO and Base2 **/
case 0x900A: /** 10 Base FL **/
case 0x9055: /** 10/100 TPO **/
case 0x9056: /** 10/100 T4 **/
case 0x905A: /** 10 Base FX **/
default:
INF_3C90X.isBrev = 1;
break;
}
/** Load the EEPROM contents **/
if (INF_3C90X.isBrev)
{
for(i=0;i<=0x20;i++)
{
eeprom[i] = a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, i);
}
#ifdef CFG_3C90X_BOOTROM_FIX
/** Set xcvrSelect in InternalConfig in eeprom. **/
/* only necessary for 3c905b revision cards with boot PROM bug!!! */
a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x13, 0x0160);
#endif
#ifdef CFG_3C90X_XCVR
if (CFG_3C90X_XCVR == 255)
{
/** Clear the LanWorks register **/
a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x16, 0);
}
else
{
/** Set the selected permanent-xcvrSelect in the
** LanWorks register
**/
a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x16,
XCVR_MAGIC + ((CFG_3C90X_XCVR) & 0x000F));
}
#endif
}
else
{
for(i=0;i<=0x17;i++)
{
eeprom[i] = a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, i);
}
}
/** Print identification message **/
printf("\n\n3C90X Driver 2.00 "
"Copyright 1999 LightSys Technology Services, Inc.\n"
"Portions Copyright 1999 Steve Smith\n");
printf("Provided with ABSOLUTELY NO WARRANTY.\n");
printf("-------------------------------------------------------"
"------------------------\n");
/** Retrieve the Hardware address and print it on the screen. **/
INF_3C90X.HWAddr[0] = eeprom[0]>>8;
INF_3C90X.HWAddr[1] = eeprom[0]&0xFF;
INF_3C90X.HWAddr[2] = eeprom[1]>>8;
INF_3C90X.HWAddr[3] = eeprom[1]&0xFF;
INF_3C90X.HWAddr[4] = eeprom[2]>>8;
INF_3C90X.HWAddr[5] = eeprom[2]&0xFF;
printf("MAC Address = %!\n", INF_3C90X.HWAddr);
/** Program the MAC address into the station address registers **/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2);
outw(htons(eeprom[0]), INF_3C90X.IOAddr + regStationAddress_2_3w);
outw(htons(eeprom[1]), INF_3C90X.IOAddr + regStationAddress_2_3w+2);
outw(htons(eeprom[2]), INF_3C90X.IOAddr + regStationAddress_2_3w+4);
outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+0);
outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+2);
outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+4);
/** Fill in our entry in the etherboot arp table **/
for(i=0;i<ETH_ALEN;i++)
nic->node_addr[i] = (eeprom[i/2] >> (8*((i&1)^1))) & 0xff;
/** Read the media options register, print a message and set default
** xcvr.
**
** Uses Media Option command on B revision, Reset Option on non-B
** revision cards -- same register address
**/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
mopt = inw(INF_3C90X.IOAddr + regResetMediaOptions_3_w);
/** mask out VCO bit that is defined as 10baseFL bit on B-rev cards **/
if (! INF_3C90X.isBrev)
{
mopt &= 0x7F;
}
printf("Connectors present: ");
c = 0;
linktype = 0x0008;
if (mopt & 0x01)
{
printf("%s100Base-T4",(c++)?", ":"");
linktype = 0x0006;
}
if (mopt & 0x04)
{
printf("%s100Base-FX",(c++)?", ":"");
linktype = 0x0005;
}
if (mopt & 0x10)
{
printf("%s10Base-2",(c++)?", ":"");
linktype = 0x0003;
}
if (mopt & 0x20)
{
printf("%sAUI",(c++)?", ":"");
linktype = 0x0001;
}
if (mopt & 0x40)
{
printf("%sMII",(c++)?", ":"");
linktype = 0x0006;
}
if ((mopt & 0xA) == 0xA)
{
printf("%s10Base-T / 100Base-TX",(c++)?", ":"");
linktype = 0x0008;
}
else if ((mopt & 0xA) == 0x2)
{
printf("%s100Base-TX",(c++)?", ":"");
linktype = 0x0008;
}
else if ((mopt & 0xA) == 0x8)
{
printf("%s10Base-T",(c++)?", ":"");
linktype = 0x0008;
}
printf(".\n");
/** Determine transceiver type to use, depending on value stored in
** eeprom 0x16
**/
if (INF_3C90X.isBrev)
{
if ((eeprom[0x16] & 0xFF00) == XCVR_MAGIC)
{
/** User-defined **/
linktype = eeprom[0x16] & 0x000F;
}
}
else
{
#ifdef CFG_3C90X_XCVR
if (CFG_3C90X_XCVR != 255)
linktype = CFG_3C90X_XCVR;
#endif /* CFG_3C90X_XCVR */
/** I don't know what MII MAC only mode is!!! **/
if (linktype == 0x0009)
{
if (INF_3C90X.isBrev)
printf("WARNING: MII External MAC Mode only supported on B-revision "
"cards!!!!\nFalling Back to MII Mode\n");
linktype = 0x0006;
}
}
/** enable DC converter for 10-Base-T **/
if (linktype == 0x0003)
{
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdEnableDcConverter, 0);
}
/** Set the link to the type we just determined. **/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
cfg = inl(INF_3C90X.IOAddr + regInternalConfig_3_l);
cfg &= ~(0xF<<20);
cfg |= (linktype<<20);
outl(cfg, INF_3C90X.IOAddr + regInternalConfig_3_l);
/** Now that we set the xcvr type, reset the Tx and Rx, re-enable. **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxReset, 0x00);
while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS)
;
if (!INF_3C90X.isBrev)
outb(0x01, INF_3C90X.IOAddr + regTxFreeThresh_b);
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
/**
** reset of the receiver on B-revision cards re-negotiates the link
** takes several seconds (a computer eternity)
**/
if (INF_3C90X.isBrev)
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x04);
else
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x00);
while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS)
;
/** Set the RX filter = receive only individual pkts & bcast. **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdSetRxFilter, 0x01 + 0x04);
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxEnable, 0);
/**
** set Indication and Interrupt flags , acknowledge any IRQ's
**/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdSetInterruptEnable, 0);
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
cmdSetIndicationEnable, 0x0014);
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
cmdAcknowledgeInterrupt, 0x661);
/** Set our exported functions **/
nic->reset = a3c90x_reset;
nic->poll = a3c90x_poll;
nic->transmit = a3c90x_transmit;
nic->disable = a3c90x_disable;
return nic;
}
+307
View File
@@ -0,0 +1,307 @@
Instructions for use of the 3C90X driver for EtherBoot
Original 3C905B support by:
Greg Beeley (Greg.Beeley@LightSys.org),
LightSys Technology Services, Inc.
February 11, 1999
Updates for 3C90X family by:
Steve Smith (steve.smith@juno.com)
October 1, 1999
Minor documentation updates by
Greg Beeley (Greg.Beeley@LightSys.org)
March 29, 2000
-------------------------------------------------------------------------------
I OVERVIEW
The 3c90X series ethernet cards are a group of high-performance busmaster
DMA cards from 3Com. This particular driver supports both the 3c90x and
the 3c90xB revision cards. 3C90xC family support has been tested to some
degree but not extensively.
Here's the licensing information:
This program Copyright (C) 1999 LightSys Technology Services, Inc.
Portions Copyright (C) 1999 Steve Smith.
This program may be re-distributed in source or binary form, modified,
sold, or copied for any purpose, provided that the above copyright message
and this text are included with all source copies or derivative works, and
provided that the above copyright message and this text are included in the
documentation of any binary-only distributions. This program is
distributed WITHOUT ANY WARRANTY, without even the warranty of FITNESS FOR
A PARTICULAR PURPOSE or MERCHANTABILITY. Please read the associated
documentation "3c90x.txt" before compiling and using this driver.
II FLASH PROMS
The 3c90xB cards, according to the 3Com documentation, only accept the
following flash memory chips:
Atmel AT29C512 (64 kilobyte)
Atmel AT29C010 (128 kilobyte)
The 3c90x cards, according to the 3Com documentation, accept the
following flash memory chips capacities:
64 kb (8 kB)
128 kb (16 kB)
256 kb (32 kB) and
512 kb (64 kB)
Atmel AT29C512 (64 kilobyte) chips are specifically listed for both
adapters, but flashing on the 3c905b cards would only be supported
through the Atmel parts. Any device, of the supported size, should
be supported when programmed by a dedicated PROM programmer (e.g.
not the card).
To use this driver in such a PROM, visit Atmel's web site and download
their .PDF file containing a list of their distributors. Contact the
distributors for pricing information. The prices are quite reasonable
(about $3 US each for the 64 kB part), and are comparable to what one would
expect for similarly sized standard EPROMs. And, the flash chips are much
easier to work with, as they don't need to be UV-erased to be reprogrammed.
The 3C905B card actually provides a method to program the flash memory
while it is resident on board the card itself; if someone would like to
write a small DOS program to do the programming, I can provide the
information about the registers and so forth.
A utility program, 3c90xutil, is provided with Etherboot in the 'contrib'
directory that allows for the on-board flashing of the ROM while Linux
is running. The program has been successfully used under Linux, but I
have heard problem reports of its use under FreeBSD. Anyone willing to
make it work under FreeBSD is more than welcome to do so!
You also have the option of using EPROM chips - the 3C905B-TX-NM has been
successfully tested with 27C256 (32kB) and 27C512 (64kB) chips with a
specified access time of 100ns and faster.
III GENERAL USE
Normally, the basic procedure for using this driver is as follows:
1. Run the 3c90xcfg program on the driver diskette to enable the
boot PROM and set it to 64k or 128k, as appropriate.
2. Build the appropriate 3c90x.fd0 or 3c90x.fd0 floppy image with
possibly the value CFG_3C90X_XCVR defined to the transceiver type that
you want to use (i.e., 10/100 rj45, AUI, coax, MII).
3. Run the floppy image on the PC to be network booted, to get
it configured, and to verify that it will boot properly.
4. Build the 3c90x.rom or 3c90x.lzrom PROM image and program
it into the flash or EPROM memory chip.
5. Put the PROM in the ethernet card, boot and enable 'boot from
network first' in the system BIOS, save and reboot.
Here are some issues to be aware of:
1. If you experience crashes or different behaviour when using the
boot PROM, add the setting CFG_3C90X_BOOTROM_FIX and go through the
steps 2-5 above. This works around a bug in some 3c905B cards (see
below), but has some side-effects which may not be desirable.
Please note that you have to boot off a floppy (not PROM!) once for
this fix to take effect.
2. The possible need to manually set the CFG_3C90X_XCVR value to
configure the transceiver type. Values are listed below.
3. The possible need to define CFG_3C90X_PRESERVE_XCVR for use in
operating systems that don't intelligently determine the
transceiver type.
Some things that are on the 'To-Do' list, perhaps for me, but perhaps
for any other volunteers out there:
1. Extend the driver to fully implement the auto-select
algorithm if the card has multiple media ports.
2. Fix any bugs in the code <grin>....
3. Extend the driver to support the 3c905c revision cards
"officially". Right now, the support has been primarily empirical
and not based on 3c905C documentation.
Now for the details....
This driver has been tested on roughly 300 systems. The main two
configuration issues to contend with are:
1. Ensure that PCI Busmastering is enabled for the adapter (configured
in the CMOS setup)
2. Some systems don't work properly with the adapter when plug and
play OS is enabled; I always set it to "No" or "Disabled" -- this makes
it easier and really doesn't adversely affect anything.
Roughly 95% of the systems worked when configured properly. A few
have issues with booting locally once the boot PROM has been installed
(this number has been less than 2%). Other configuration issues that
to check:
1. Newer BIOS's actually work correctly with the network boot order.
Set the network adapter first. Most older BIOS's automatically go to
the network boot PROM first.
2. For systems where the adapter was already installed and is just
having the PROM installed, try setting the "reset configuration data"
to yes in the CMOS setup if the BIOS isn't seen at first. If your BIOS
doesn't have this option, remove the card, start the system, shut down,
install the card and restart (or switch to a different PCI slot).
3. Make sure the CMOS security settings aren't preventing a boot.
The 3c905B cards have a significant 'bug' that relates to the flash prom:
unless the card is set internally to the MII transceiver, it will only
read the first 8k of the PROM image. Don't ask why -- it seems really
obscure, but it has to do with the way they mux'd the address lines
from the PCI bus to the ROM. Unfortunately, most of us are not using
MII transceivers, and even the .lzrom image ends up being just a little
bit larger than 8k. Note that the workaround for this is disabled by
default, because the Windows NT 4.0 driver does not like it (no packets
are transmitted).
So, the solution that I've used is to internally set the card's nvram
configuration to use MII when it boots. The 3c905b driver does this
automatically. This way, the 16k prom image can be loaded into memory,
and then the 3c905b driver can set the temporary configuration of the
card to an appropriate value, either configurable by the user or chosen
by the driver.
To enable the 3c905B bugfix, which is necessary for these cards when
booting from the Flash ROM, define -DCFG_3C90X_BOOTROM_FIX when building,
create a floppy image and boot it once.
Thereafter, the card should accept the larger prom image.
The driver should choose an appropriate transceiver on the card. However,
if it doesn't on your card or if you need to, for instance, set your
card to 10mbps when connected to an unmanaged 10/100 hub, you can specify
which transceiver you want to use. To do this, build the 3c905b.fd0
image with -DCFG_3C90X_XCVR=x, where 'x' is one of the following
values:
0 10Base-T
1 10mbps AUI
3 10Base-2 (thinnet/coax)
4 100Base-TX
5 100Base-FX
6 MII
8 Auto-negotiation 10Base-T / 100Base-TX (usually the default)
9 MII External MAC Mode
255 Allow driver to choose an 'appropriate' media port.
Then proceed from step 2 in the above 'general use' instructions. The
.rom image can be built with CFG_3C90X_XCVR set to a value, but you
normally don't want to do this, since it is easier to change the
transceiver type by rebuilding a new floppy, changing the BIOS to floppy
boot, booting, and then changing the BIOS back to network boot. If
CFG_3C90X_XCVR is not set in a particular build, it just uses the
current configuration (either its 'best guess' or whatever the stored
CFG_3C90X_XCVR value was from the last time it was set).
[[ Note for the more technically inclined: The CFG_3C90X_XCVR value is
programmed into a register in the card's NVRAM that was reserved for
LanWorks PROM images to use. When the driver boots, the card comes
up in MII mode, and the driver checks the LanWorks register to find
out if the user specified a transceiver type. If it finds that
information, it uses that, otherwise it picks a transceiver that the
card has based on the 3c905b's MediaOptions register. This driver isn't
quite smart enough to always determine which media port is actually
_connected_; maybe someone else would like to take on that task (it
actually involves sending a self-directed packet and seeing if it
comes back. IF it does, that port is connected). ]]
Another issue to keep in mind is that it is possible that some OS'es
might not be happy with the way I've handled the PROM-image hack with
setting MII mode on bootup. Linux 2.0.35 does not have this problem.
Behavior of other systems may vary. The 3com documentation specifically
says that, at least with the card that I have, the device driver in the
OS should auto-select the media port, so other drivers should work fine
with this 'hack'. However, if yours doesn't seem to, you can try defining
CFG_3C90X_PRESERVE_XCVR when building to cause Etherboot to keep the
working setting (that allowed the bootp/tftp process) across the eth_reset
operation.
IV FOR DEVELOPERS....
If you would like to fix/extend/etc. this driver, feel free to do so; just
be sure you can test the modified version on the 3c905B-TX cards that the
driver was originally designed for. This section of this document gives
some information that might be relevant to a programmer.
A. Main Entry Point
a3c90x_probe is the main entry point for this driver. It is referred
to in an array in 'config.c'.
B. Other Important Functions
The functions a3c90x_transmit, a3c90x_poll, a3c90x_reset, and
a3c90x_disable are static functions that EtherBoot finds out about
as a result of a3c90x_probe setting entries in the nic structure
for them. The EtherBoot framework does not use interrupts. It is
polled. All transmit and receive operations are initiated by the
etherboot framework, not by an interrupt or by the driver.
C. Internal Functions
The following functions are internal to the driver:
a3c90x_internal_IssueCommand - sends a command to the 3c905b card.
a3c90x_internal_SetWindow - shifts between one of eight register
windows onboard the 3c90x. The bottom 16 bytes of the card's
I/O space are multiplexed among 128 bytes, only 16 of which are
visible at any one time. This SetWindow function selects one of
the eight sets.
a3c90x_internal_ReadEeprom - reads a word (16 bits) from the
card's onboard nvram. This is NOT the BIOS boot rom. This is
where the card stores such things as its hardware address.
a3c90x_internal_WriteEeprom - writes a word (16 bits) to the
card's nvram, and recomputes the eeprom checksum.
a3c90x_internal_WriteEepromWord - writes a word (16 bits) to the
card's nvram. Used by the above routine.
a3c90x_internal_WriteEepromWord - writes a word (16 bits) to the
card's nvram. Used by the above routine.
D. Globals
All global variables are inside a global structure named INF_3C90X.
So, wherever you see that structure referenced, you know the variable
is a global. Just keeps things a little neater.
E. Enumerations
There are quite a few enumerated type definitions for registers and
so forth, many for registers that I didn't even touch in the driver.
Register types start with 'reg', window numbers (for SetWindow)
start with 'win', and commands (for IssueCommand) start with 'cmd'.
Register offsets also include an indication in the name as to the
size of the register (_b = byte, _w = word, _l = long), and which
window the register is in, if it is windowed (0-7).
F. Why the 'a3c90x' name?
I had to come up with a letter at the beginning of all of the
identifiers, since 3com so conveniently had their name start with a
number. Another driver used 't' (for 'three'?); I chose 'a' for
no reason at all.
Addendum by Jorge L. deLyra <delyra@latt.if.usp.br>, 22Nov2000 re
working around the 3C905 hardware bug mentioned above:
Use this floppy to fix any 3COM model 3C905B PCI 10/100 Ethernet cards
that fail to load and run the boot program the first time around. If
they have a "Lucent" rather than a "Broadcom" chipset these cards have
a configuration bug that causes a hang when trying to load the boot
program from the PROM, if you try to use them right out of the box.
The boot program in this floppy is the file named 3c905b-tpo100.rom
from Etherboot version 4.6.10, compiled with the bugfix parameter
CFG_3C90X_BOOTROM_FIX
You have to take the chip off the card and boot the system once using
this floppy. Once loaded from the floppy, the boot program will access
the card and change some setting in it, correcting the problem. After
that you may use either this boot program or the normal one, compiled
without this bugfix parameter, to boot the machine from the PROM chip.
[Any recent Etherboot version should do, not just 4.6.10 - Ed.]
+219
View File
@@ -0,0 +1,219 @@
# For <shared.h> and <stage1.h>.
INCLUDES = -I$(top_srcdir)/stage2 -I$(top_srcdir)/stage1
# Don't build the netboot support by default.
if NETBOOT_SUPPORT
LIBDRIVERS = libdrivers.a
else
LIBDRIVERS =
endif
noinst_LIBRARIES = $(LIBDRIVERS)
libdrivers_a_SOURCES = cards.h config.c etherboot.h \
fsys_tftp.c linux-asm-io.h linux-asm-string.h \
main.c misc.c nic.h osdep.h pci.c pci.h timer.c timer.h
EXTRA_libdrivers_a_SOURCES = 3c509.c 3c509.h 3c595.c 3c595.h 3c90x.c \
cs89x0.c cs89x0.h davicom.c depca.c eepro.c eepro100.c \
epic100.c epic100.h fa311.c i82586.c lance.c natsemi.c \
ni5010.c ns8390.c ns8390.h otulip.c otulip.h rtl8139.c \
sis900.c sis900.h sk_g16.c sk_g16.h smc9000.c smc9000.h \
tiara.c tlan.c tulip.c via-rhine.c w89c840.c
libdrivers_a_CFLAGS = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
-DFSYS_TFTP=1 $(NET_CFLAGS) $(NET_EXTRAFLAGS)
# Filled by configure.
libdrivers_a_LIBADD = @NETBOOT_DRIVERS@
libdrivers_a_DEPENDENCIES = $(libdrivers_a_LIBADD)
EXTRA_DIST = README.netboot 3c90x.txt cs89x0.txt sis900.txt tulip.txt
# These below are several special rules for the device drivers.
# We cannot use a simple rule for them...
# What objects are derived from a driver?
3c509_drivers = 3c509.o 3c529.o
3c595_drivers = 3c595.o
3c90x_drivers = 3c90x.o
cs89x0_drivers = cs89x0.o
davicom_drivers = davicom.o
depca_drivers = depca.o
eepro_drivers = eepro.o
eepro100_drivers = eepro100.o
epic100_drivers = epic100.o
#fa311_drivers = fa311.o
i82586_drivers = 3c507.o exos205.o ni5210.o
lance_drivers = lance.o ne2100.o ni6510.o
natsemi_drivers = natsemi.o
ni5010_drivers = ni5010.o
ns8390_drivers = 3c503.o ne.o ns8390.o wd.o
otulip_drivers = otulip.o
rtl8139_drivers = rtl8139.o
sis900_drivers = sis900.o
sk_g16_drivers = sk_g16.o
smc9000_drivers = smc9000.o
tiara_drivers = tiara.o
#tlan_drivers = tlan.o
tulip_drivers = tulip.o
via_rhine_drivers = via_rhine.o
w89c840_drivers = w89c840.o
# Is it really necessary to specify dependecies explicitly?
$(3c509_drivers): 3c509.c 3c509.h
$(3c509_drivers): %.o: 3c509.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(3c595_drivers): 3c595.c 3c595.h
$(3c595_drivers): %.o: 3c595.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(3c90x_drivers): 3c90x.c
$(3c90x_drivers): %.o: 3c90x.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(cs89x0_drivers): cs89x0.c cs89x0.h
$(cs89x0_drivers): %.o: cs89x0.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(davicom_drivers): davicom.c
$(davicom_drivers): %.o: davicom.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(depca_drivers): depca.c
$(depca_drivers): %.o: depca.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(eepro_drivers): eepro.c
$(eepro_drivers): %.o: eepro.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(eepro100_drivers): eepro100.c
$(eepro100_drivers): %.o: eepro100.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(epic100_drivers): epic100.c epic100.h
$(epic100_drivers): %.o: epic100.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
#$(fa311_drivers): fa311.c
#$(fa311_drivers): %.o: fa311.c
# $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
# $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(i82586_drivers): i82586.c
$(i82586_drivers): %.o: i82586.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(lance_drivers): lance.c
$(lance_drivers): %.o: lance.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(natsemi_drivers): natsemi.c
$(natsemi_drivers): %.o: natsemi.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(ni5010_drivers): ni5010.c
$(ni5010_drivers): %.o: ni5010.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(ns8390_drivers): ns8390.c ns8390.h
$(ns8390_drivers): %.o: ns8390.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(otulip_drivers): otulip.c otulip.h
$(otulip_drivers): %.o: otulip.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(rtl8139_drivers): rtl8139.c
$(rtl8139_drivers): %.o: rtl8139.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(sis900_drivers): sis900.c
$(sis900_drivers): %.o: sis900.c sis900.h
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(sk_g16_drivers): sk_g16.c sk_g16.h
$(sk_g16_drivers): %.o: sk_g16.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(smc9000_drivers): smc9000.c smc9000.h
$(smc9000_drivers): %.o: smc9000.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(tiara_drivers): tiara.c
$(tiara_drivers): %.o: tiara.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
#$(tlan_drivers): tlan.c
#$(tlan_drivers): %.o: tlan.c
# $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
# $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(tulip_drivers): tulip.c
$(tulip_drivers): %.o: tulip.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(via_rhine_drivers): via-rhine.c
$(via_rhine_drivers): %.o: via-rhine.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
$(w89c840_drivers): w89c840.c
$(w89c840_drivers): %.o: w89c840.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
# Per-object flags.
3c509_o_CFLAGS = -DINCLUDE_3C509=1
3c529_o_CFLAGS = -DINCLUDE_3C529=1
3c595_o_CFLAGS = -DINCLUDE_3C595=1
3c90x_o_CFLAGS = -DINCLUDE_3C90X=1
cs89x0_o_CFLAGS = -DINCLUDE_CS89X0=1
davicom_o_CFLAGS = -DINCLUDE_DAVICOM=1
depca_o_CFLAGS = -DINCLUDE_DEPCA=1
eepro_o_CFLAGS = -DINCLUDE_EEPRO=1
eepro100_o_CFLAGS = -DINCLUDE_EEPRO100=1
epic100_o_CFLAGS = -DINCLUDE_EPIC100=1
#fa311_o_CFLAGS = -DINCLUDE_FA311=1
3c507_o_CFLAGS = -DINCLUDE_3C507=1
exos205_o_CFLAGS = -DINCLUDE_EXOS205=1
ni5210_o_CFLAGS = -DINCLUDE_NI5210=1
lance_o_CFLAGS = -DINCLUDE_LANCE=1
ne2100_o_CFLAGS = -DINCLUDE_NE2100=1
ni6510_o_CFLAGS = -DINCLUDE_NI6510=1
natsemi_o_CFLAGS = -DINCLUDE_NATSEMI=1
ni5010_o_CFLAGS = -DINCLUDE_NI5010=1
3c503_o_CFLAGS = -DINCLUDE_3C503=1
ne_o_CFLAGS = -DINCLUDE_NE=1
ns8390_o_CFLAGS = -DINCLUDE_NS8390=1
wd_o_CFLAGS = -DINCLUDE_WD=1
otulip_o_CFLAGS = -DINCLUDE_OTULIP=1
rtl8139_o_CFLAGS = -DINCLUDE_RTL8139=1
sis900_o_CFLAGS = -DINCLUDE_SIS900=1
sk_g16_o_CFLAGS = -DINCLUDE_SK_G16=1
smc9000_o_CFLAGS = -DINCLUDE_SMC9000=1
tiara_o_CFLAGS = -DINCLUDE_TIARA=1
#tlan_o_CFLAGS = -DINCLUDE_TLAN=1
tulip_o_CFLAGS = -DINCLUDE_TULIP=1
via_rhine_o_CFLAGS = -DINCLUDE_VIA_RHINE=1
w89c840_o_CFLAGS = -DINCLUDE_W89C840=1
+168
View File
@@ -0,0 +1,168 @@
You can use the netboot support to download OS images from a network.
Nearly all the device drivers are coming from the network-based boot
loader, Etherboot. Please visit its web page. They have rich
documentations so you will be able to get useful information from there.
The URL is <http://etherboot.sourceforge.net/>.
These below are common options for configure. Perhaps you may not need
to specify them.
--disable-packet-retransmission
Turns off packet retransmission. Use it on an empty network, where
no packet collision can happen.
--enable-pci-direct
Define this for PCI BIOSes that do not implement BIOS32 or not
correctly.
--enable-diskless
Enable the diskless support. If specified, you will get two optional
images, called "nbgrub" and "pxegrub". The former is the ``Net Boot
Image Proposal'' format, which is used by Etherboot and Netboot, while
the latter is the ``Preboot Execution Environment" format, which is
used by a PXE ROM. You may buy a PXE ROM from some companies.
Here is the information about the device drivers. They are all disabled
by default, so you must specify configure options to enable drivers you
want to use. Some drivers have extra per-driver options, so the extra
options are also described below.
Caution: You should enable them as you need. Don't enable any
unnecessary driver, because GRUB might crash if you include too many
drivers at the same time.
3Com509, ISA/EISA
--enable-3c509
3Com529 == MCA 3c509
--enable-3c529
3Com59x and 3Com900
--enable-3c595
3Com90x
--enable-3c90x
Crystal Semiconductor CS89x0
--enable-cs89x0
--enable-cs-scan=LIST
Probe for CS89x0 base address using LIST of comma separated hex
addresses; increasing the address by one (0x300 -> 0x301) will force
a more aggressive probing algorithm. This might be neccessary after
a soft-reset of the NIC.
Davicom DM9102 and 9009
--enable-davicom
Digital DE100 and DE200
--enable-depca
Intel Etherexpress Pro/10 (ISA card)
--enable-eepro
Intel Etherexpress Pro/100
--enable-eepro100
SMC 83c170 EPIC/100
--enable-epic100
3Com507
--enable-3c507
EXOS205
--enable-exos205
Racal-Interlan NI5210
--enable-ni5210
Lance PCI PCNet/32
AMD HomePNA
--enable-lance
Novell NE2100 and NE1500
--enable-ne2100
Racal-Interlan NI6510
--enable-ni6510
National Semiconductor DP8381x (Netgear FA311 and FA312)
--enable-natsemi
Racal-Interlan NI5010
--enable-ni5010
3Com503, aka Etherlink II, also /16 model
--enable-3c503
--enable-3c503-shmem
Use 3c503 shared memory mode.
--enable-3c503-aui
Use AUI by default on 3c503 cards.
NE1000/2000 and clones (ISA)
--enable-ne
--enable-ne-scan=LIST (0x280,0x300,0x320,0x340)
Probe for NE base address using LIST of comma separated hex
addresses.
NE2000 PCI clone (RTL8029)
Winbond 86C940
Compex RL2000
KTI ET32P2
NetVin 5000SC
Holtek 80232
--enable-ns8390
--enable-compex-rl2000-fix
If you have a Compex RL2000 PCI 32-bit (11F6:1401), and the probe
hangs in "Probing...[NE*000/PCI]", try enabling this fix... it
worked for me :).
WD8003/8013, SMC8216/8416
--enable-wd
--enable-wd-default-mem=MEM (0xCC000)
Default memory location for WD/SMC cards.
Old base driver for Tulip clones
--enable-otulip
Realtek 8139
SMC 1211
D-Link DFE530TX+ and DFE538TX
--enable-rtl8139
SIS 900 and SIS 7016
--enable-sis900
Schneider and Koch G16
--enable-sk-g16
SMC9000
--enable-smc9000
--enable-smc9000-scan=LIST
List of I/O addresses to probe.
Tiara, Fujitsu Lancard
--enable-tiara
Linksys LNE100TX and other NICs using this Tulip clone chip
Netgear FA310TX and other NICs using this Tulip clone chip
Tulip clones based on the ADMtek Centaur-P
Tulip clones based on the Macronix 987x5
Tulip-Fast
Tulip+
Tulip 21142
ASIX AX88140
Intel Tulip
Compex RL100-TX
--enable-tulip
Rhine-I, e.g. D-Link DFE-530TX
Rhine-II
--enable-via-rhine
Winbond W89c840
Compex RL100-ATX
--enable-w89c840
The description about how to use the support can be found in the GRUB
manual. Run "info grub" in the shell prompt.
+183
View File
@@ -0,0 +1,183 @@
#ifndef CARDS_H
#define CARDS_H
/*
* 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, or (at
* your option) any later version.
*/
#include "nic.h"
/* OK, this is how the PCI support hack works: if pci.h is included before
* this file is included, assume that the driver supports PCI. This means that
* this file is usually included last. */
#ifdef PCI_H
#define PCI_ARG(x) ,x
#else
#define PCI_ARG(x)
#endif
#ifdef INCLUDE_WD
extern struct nic *wd_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C503
extern struct nic *t503_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_VIA_RHINE
extern struct nic *rhine_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NE
extern struct nic *ne_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NS8390
extern struct nic *nepci_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C509
extern struct nic *t509_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C529
extern struct nic *t529_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C595
extern struct nic *t595_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C90X
extern struct nic *a3c90x_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_EEPRO
extern struct nic *eepro_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_EEPRO100
extern struct nic *eepro100_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_EPIC100
extern struct nic *epic100_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_OTULIP
extern struct nic *otulip_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_TULIP
extern struct nic *tulip_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_DAVICOM
extern struct nic *davicom_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_CS89X0
extern struct nic *cs89x0_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_LANCE
extern struct nic *lancepci_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NE2100
extern struct nic *ne2100_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NI6510
extern struct nic *ni6510_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_SK_G16
extern struct nic *SK_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_3C507
extern struct nic *t507_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NI5010
extern struct nic *ni5010_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NI5210
extern struct nic *ni5210_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_EXOS205
extern struct nic *exos205_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_SMC9000
extern struct nic *smc9000_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_TIARA
extern struct nic *tiara_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_DEPCA
extern struct nic *depca_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_RTL8139
extern struct nic *rtl8139_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_W89C840
extern struct nic *w89c840_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_SIS900
extern struct nic *sis900_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_NATSEMI
extern struct nic *natsemi_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#ifdef INCLUDE_TLAN
extern struct nic *tlan_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
#endif /* CARDS_H */
+598
View File
@@ -0,0 +1,598 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2001,2002 Free Software Foundation, Inc.
*
* 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.
*/
/* Based on "src/config.c" in etherboot-5.0.5. */
/*
* 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, or (at
* your option) any later version.
*/
#define GRUB 1
#include <etherboot.h>
#include <nic.h>
#undef INCLUDE_PCI
#if defined(INCLUDE_NS8390) || defined(INCLUDE_EEPRO100) || defined(INCLUDE_LANCE) || defined(INCLUDE_EPIC100) || defined(INCLUDE_TULIP) || defined(INCLUDE_OTULIP) || defined(INCLUDE_3C90X) || defined(INCLUDE_3C595) || defined(INCLUDE_RTL8139) || defined(INCLUDE_VIA_RHINE) || defined(INCLUDE_W89C840) || defined(INCLUDE_DAVICOM) || defined(INCLUDE_SIS900) || defined(INCLUDE_NATSEMI) || defined(INCLUDE_TLAN)
/* || others later */
# define INCLUDE_PCI
# include <pci.h>
static unsigned short pci_ioaddrs[16];
static struct pci_device pci_nic_list[] =
{
#ifdef INCLUDE_NS8390
{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029,
"Realtek 8029", 0, 0, 0, 0},
{ PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940,
"Winbond NE2000-PCI", 0, 0, 0, 0},
{ PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000,
"Compex ReadyLink 2000", 0, 0, 0, 0},
{ PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2,
"KTI ET32P2", 0, 0, 0, 0},
{ PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC,
"NetVin NV5000SC", 0, 0, 0, 0},
{ PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_HT80232,
"Holtek HT80232", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_3C90X
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO,
"3Com900-TPO", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900COMBO,
"3Com900-Combo", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905TX,
"3Com905-TX", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905T4,
"3Com905-T4", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9004,
"3Com900B-TPO", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9005,
"3Com900B-Combo", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9006,
"3Com900B-2/T", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x900A,
"3Com900B-FL", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905B_TX,
"3Com905B-TX", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9056,
"3Com905B-T4", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x905A,
"3Com905B-FL", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905C_TXM,
"3Com905C-TXM", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9800,
"3Com980-Cyclone", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9805,
"3Com9805", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x7646,
"3CSOHO100-TX", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_3C595
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C590,
"3Com590", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595,
"3Com595", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_1,
"3Com595", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_2,
"3Com595", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO,
"3Com900-TPO", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900COMBO,
"3Com900-Combo", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9004,
"3Com900B-TPO", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9005,
"3Com900B-Combo", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9006,
"3Com900B-2/T", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x900A,
"3Com900B-FL", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9800,
"3Com980-Cyclone", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x9805,
"3Com9805", 0, 0, 0, 0},
{ PCI_VENDOR_ID_3COM, 0x7646,
"3CSOHO100-TX", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_EEPRO100
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
"Intel EtherExpressPro100", 0, 0, 0, 0},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
"Intel EtherExpressPro100 82559ER", 0, 0, 0, 0},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029,
"Intel EtherExpressPro100 ID1029", 0, 0, 0, 0},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030,
"Intel Corporation 82559 InBusiness 10/100", 0, 0, 0, 0},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562,
"Intel EtherExpressPro100 82562EM", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_EPIC100
{ PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_EPIC100,
"SMC EtherPowerII", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_LANCE
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
"AMD Lance/PCI", 0, 0, 0, 0},
{ PCI_VENDOR_ID_AMD_HOMEPNA, PCI_DEVICE_ID_AMD_HOMEPNA,
"AMD Lance/HomePNA", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_RTL8139
{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
"Realtek 8139", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DFE530TXP,
"DFE530TX+/DFE538TX", 0, 0, 0, 0},
{ PCI_VENDOR_ID_SMC_1211, PCI_DEVICE_ID_SMC_1211,
"SMC EZ10/100", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_OTULIP
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
"Digital Tulip", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
"Digital Tulip Fast", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
"Digital Tulip+", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142,
"Digital Tulip 21142", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_TULIP
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
"Digital Tulip", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
"Digital Tulip Fast", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
"Digital Tulip+", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142,
"Digital Tulip 21142", 0, 0, 0, 0},
{ PCI_VENDOR_ID_MACRONIX, PCI_DEVICE_ID_MX987x5,
"Macronix MX987x5", 0, 0, 0, 0},
{ PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LC82C115,
"LinkSys LNE100TX", 0, 0, 0, 0},
{ PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_DEC_TULIP,
"Netgear FA310TX", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9102,
"Davicom 9102", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9009,
"Davicom 9009", 0, 0, 0, 0},
{ PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_0985,
"ADMtek Centaur-P", 0, 0, 0, 0},
{ PCI_VENDOR_ID_ADMTEK, 0x0981,
"ADMtek AN981 Comet", 0, 0, 0, 0},
{ 0x125B, 0x1400,
"ASIX AX88140", 0, 0, 0, 0 },
{ 0x11F6, 0x9881,
"Compex RL100-TX", 0, 0, 0, 0 },
#endif
#ifdef INCLUDE_DAVICOM
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9102,
"Davicom 9102", 0, 0, 0, 0},
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9009,
"Davicom 9009", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_VIA_RHINE
{ PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_VT6102,
"VIA 6102", 0, 0, 0, 0},
{ PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_RHINE_I,
"VIA 3043", 0, 0, 0, 0},
{ PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_86C100A,
"VIA 86C100A", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_W89C840
{ PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C840,
"Winbond W89C840F", 0, 0, 0, 0},
{ PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL100ATX,
"Compex RL100ATX", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_SIS900
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
"SIS900", 0, 0, 0, 0},
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
"SIS7016", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_NATSEMI
{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_DP83815,
"DP83815", 0, 0, 0, 0},
#endif
#ifdef INCLUDE_TLAN
{ PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326,
"OC2326", 0, 0, 0, 0},
#endif
/* other PCI NICs go here */
{0, 0, NULL, 0, 0, 0, 0}
};
#endif /* INCLUDE_*PCI */
#include <cards.h>
#ifdef INCLUDE_PCI
struct pci_dispatch_table
{
unsigned short vendor;
unsigned short dev_id;
struct nic *(*eth_probe) (struct nic *, unsigned short *,
struct pci_device *);
};
static struct pci_dispatch_table PCI_NIC[] =
{
# ifdef INCLUDE_NS8390
{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, nepci_probe },
{ PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940, nepci_probe },
{ PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000, nepci_probe },
{ PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, nepci_probe },
{ PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, nepci_probe },
{ PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_HT80232, nepci_probe },
# endif /* INCLUDE_NS8390 */
# ifdef INCLUDE_3C90X
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900COMBO, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905TX, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905T4, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x9004, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x9005, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x9006, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x900A, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905B_TX, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x9056, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x905A, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C905C_TXM, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x9800, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x9805, a3c90x_probe },
{ PCI_VENDOR_ID_3COM, 0x7646, a3c90x_probe },
# endif /* INCLUDE_3C90X */
# ifdef INCLUDE_3C595
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C590, t595_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595, t595_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_1, t595_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C595_2, t595_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900TPO, t595_probe },
{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C900COMBO, t595_probe },
{ PCI_VENDOR_ID_3COM, 0x9004, t595_probe },
{ PCI_VENDOR_ID_3COM, 0x9005, t595_probe },
{ PCI_VENDOR_ID_3COM, 0x9006, t595_probe },
{ PCI_VENDOR_ID_3COM, 0x900A, t595_probe },
{ PCI_VENDOR_ID_3COM, 0x9800, t595_probe },
{ PCI_VENDOR_ID_3COM, 0x9805, t595_probe },
{ PCI_VENDOR_ID_3COM, 0x7646, t595_probe },
# endif /* INCLUDE_3C595 */
# ifdef INCLUDE_EEPRO100
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, eepro100_probe },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER, eepro100_probe },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029, eepro100_probe },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, eepro100_probe },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562, eepro100_probe },
# endif /* INCLUDE_EEPRO100 */
# ifdef INCLUDE_EPIC100
{ PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_EPIC100, epic100_probe },
# endif /* INCLUDE_EPIC100 */
# ifdef INCLUDE_LANCE
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, lancepci_probe },
{ PCI_VENDOR_ID_AMD_HOMEPNA, PCI_DEVICE_ID_AMD_HOMEPNA, lancepci_probe },
# endif /* INCLUDE_LANCE */
# ifdef INCLUDE_RTL8139
{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139, rtl8139_probe },
{ PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DFE530TXP, rtl8139_probe },
{ PCI_VENDOR_ID_SMC_1211, PCI_DEVICE_ID_SMC_1211, rtl8139_probe },
# endif /* INCLUDE_RTL8139 */
# ifdef INCLUDE_OTULIP
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, otulip_probe },
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, otulip_probe },
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, otulip_probe },
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, otulip_probe },
# endif /* INCLUDE_OTULIP */
# ifdef INCLUDE_TULIP
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, tulip_probe },
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, tulip_probe },
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, tulip_probe },
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, tulip_probe },
{ PCI_VENDOR_ID_MACRONIX, PCI_DEVICE_ID_MX987x5, tulip_probe },
{ PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LC82C115, tulip_probe },
{ PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_DEC_TULIP, tulip_probe },
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9102, tulip_probe },
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9009, tulip_probe },
{ PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_0985, tulip_probe },
{ PCI_VENDOR_ID_ADMTEK, 0x0981, tulip_probe },
{ 0x125B, 0x1400, tulip_probe },
{ 0x11F6, 0x9881, tulip_probe },
# endif /* INCLUDE_TULIP */
# ifdef INCLUDE_DAVICOM
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9102, davicom_probe },
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DM9009, davicom_probe },
# endif /* INCLUDE_DAVICOM */
# ifdef INCLUDE_VIA_RHINE
{ PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_VT6102, rhine_probe },
{ PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_RHINE_I, rhine_probe },
{ PCI_VENDOR_ID_VIATEC, PCI_DEVICE_ID_VIA_86C100A, rhine_probe },
# endif /* INCLUDE_VIA_RHINE */
# ifdef INCLUDE_W89C840
{ PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C840, w89c840_probe },
{ PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL100ATX, w89c840_probe },
# endif /* INCLUDE_W89C840 */
# ifdef INCLUDE_SIS900
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900, sis900_probe },
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016, sis900_probe },
# endif /* INCLUDE_SIS900 */
# ifdef INCLUDE_NATSEMI
{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_DP83815, natsemi_probe },
# endif /* INCLUDE_NATSEMI */
# ifdef INCLUDE_TLAN
{ PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326, tlan_probe },
# endif /* INCLUDE_TLAN */
{ 0, 0, 0 }
};
#endif /* GRUB && INCLUDE_PCI */
struct dispatch_table
{
const char *nic_name;
#ifdef INCLUDE_PCI
struct nic *(*eth_probe) (struct nic *, unsigned short *,
struct pci_device *);
#else
struct nic *(*eth_probe) (struct nic *, unsigned short *);
#endif /* INCLUDE_PCI */
unsigned short *probe_ioaddrs; /* for probe overrides */
};
/*
* NIC probing is in order of appearance in this table.
* If for some reason you want to change the order,
* just rearrange the entries (bracketed by the #ifdef/#endif)
*/
static struct dispatch_table NIC[] =
{
#ifdef INCLUDE_RTL8139
{ "RTL8139", rtl8139_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_SIS900
{ "SIS900", sis900_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_NATSEMI
{ "NATSEMI", natsemi_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_WD
{ "WD", wd_probe, 0 },
#endif
#ifdef INCLUDE_3C503
{ "3C503", t503_probe, 0 },
#endif
#ifdef INCLUDE_NE
{ "NE*000", ne_probe, 0 },
#endif
#ifdef INCLUDE_3C509
{ "3C5x9", t509_probe, 0 },
#endif
#ifdef INCLUDE_3C529
{ "3C5x9", t529_probe, 0 },
#endif
#ifdef INCLUDE_3C595
{ "3C595", t595_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_3C90X
{ "3C90X", a3c90x_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_EEPRO
{ "EEPRO", eepro_probe, 0 },
#endif
#ifdef INCLUDE_EEPRO100
{ "EEPRO100", eepro100_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_EPIC100
{ "EPIC100", epic100_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_OTULIP
{ "OTulip", otulip_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_TULIP
{ "Tulip", tulip_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_DAVICOM
{ "DAVICOM", davicom_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_CS89X0
{ "CS89x0", cs89x0_probe, 0 },
#endif
#ifdef INCLUDE_NE2100
{ "NE2100", ne2100_probe, 0 },
#endif
#ifdef INCLUDE_NI6510
{ "NI6510", ni6510_probe, 0 },
#endif
#ifdef INCLUDE_SK_G16
{ "SK_G16", SK_probe, 0 },
#endif
#ifdef INCLUDE_3C507
{ "3C507", t507_probe, 0 },
#endif
#ifdef INCLUDE_NI5010
{ "NI5010", ni5010_probe, 0 },
#endif
#ifdef INCLUDE_NI5210
{ "NI5210", ni5210_probe, 0 },
#endif
#ifdef INCLUDE_EXOS205
{ "EXOS205", exos205_probe, 0 },
#endif
#ifdef INCLUDE_SMC9000
{ "SMC9000", smc9000_probe, 0 },
#endif
#ifdef INCLUDE_TIARA
{ "TIARA", tiara_probe, 0 },
#endif
#ifdef INCLUDE_DEPCA
{ "DEPCA", depca_probe, 0 },
#endif
#ifdef INCLUDE_NS8390
{ "NE2000/PCI", nepci_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_LANCE
{ "LANCE/PCI", lancepci_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_VIA_RHINE
{ "VIA 86C100", rhine_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_W89C840
{ "W89C840F", w89c840_probe, pci_ioaddrs },
#endif
#ifdef INCLUDE_TLAN
{ "Olicom 2326", tlan_probe, pci_ioaddrs },
#endif
/* this entry must always be last to mark the end of list */
{ 0, 0, 0 }
};
#define NIC_TABLE_SIZE (sizeof (NIC) / sizeof (NIC[0]))
static int
eth_dummy (struct nic *dummy)
{
return 0;
}
static char packet[ETH_FRAME_LEN];
struct nic nic =
{
(void (*) (struct nic *)) eth_dummy, /* reset */
eth_dummy, /* poll */
(void (*) (struct nic *, const char *,
unsigned int, unsigned int,
const char *)) eth_dummy, /* transmit */
(void (*) (struct nic *)) eth_dummy, /* disable */
#ifdef T503_AUI
1, /* aui */
#else
0, /* no aui */
#endif
&rom, /* rom_info */
arptable[ARP_CLIENT].node, /* node_addr */
packet, /* packet */
0, /* packetlen */
0, /* priv_data */
};
void
eth_reset (void)
{
(*nic.reset) (&nic);
}
int
eth_probe (void)
{
struct pci_device *p;
const struct dispatch_table *t;
static int probed = 0;
/* If already probed, don't try to probe it any longer. */
if (probed)
return 1;
/* Clear the ready flag. */
network_ready = 0;
/* Clear the ARP table. */
grub_memset ((char *) arptable, 0,
MAX_ARP * sizeof (struct arptable_t));
p = 0;
#ifdef INCLUDE_PCI
/* In GRUB, the ROM info is initialized here. */
rom = *((struct rom_info *) ROM_INFO_LOCATION);
eth_pci_init(pci_nic_list);
pci_ioaddrs[0] = 0;
pci_ioaddrs[1] = 0;
/* at this point we have a list of possible PCI candidates
we just pick the first one with a non-zero ioaddr */
for (p = pci_nic_list; p->vendor != 0; ++p)
{
if (p->ioaddr != 0)
{
pci_ioaddrs[0] = p->ioaddr;
break;
}
}
#endif
etherboot_printf("Probing...");
#ifdef INCLUDE_PCI
if (p->vendor)
{
struct pci_dispatch_table *pt;
for (pt = PCI_NIC; pt->eth_probe != 0; pt++)
if (p->vendor == pt->vendor && p->dev_id == pt->dev_id)
{
etherboot_printf ("[%s]", p->name);
if ((pt->eth_probe) (&nic, pci_ioaddrs, p))
{
probed = 1;
return 1;
}
}
}
#endif /* INCLUDE_PCI */
for (t = NIC; t->nic_name != 0; ++t)
{
etherboot_printf("[%s]", t->nic_name);
#ifdef INCLUDE_PCI
if ((*t->eth_probe) (&nic, t->probe_ioaddrs, p))
{
probed = 1;
return 1;
}
#else
if ((*t->eth_probe) (&nic, t->probe_ioaddrs))
{
probed = 1;
return 1;
}
#endif /* INCLUDE_PCI */
}
return 0;
}
int
eth_poll (void)
{
return ((*nic.poll) (&nic));
}
void
eth_transmit (const char *d, unsigned int t, unsigned int s, const void *p)
{
(*nic.transmit) (&nic, d, t, s, p);
if (t == IP)
twiddle ();
}
void
eth_disable (void)
{
(*nic.disable) (&nic);
}
+677
View File
@@ -0,0 +1,677 @@
/**
Per an email message from Russ Nelson <nelson@crynwr.com> on
18 March 2008 this file is now licensed under GPL Version 2.
From: Russ Nelson <nelson@crynwr.com>
Date: Tue, 18 Mar 2008 12:42:00 -0400
Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
-- quote from email
As copyright holder, if I say it doesn't conflict with the GPL,
then it doesn't conflict with the GPL.
However, there's no point in causing people's brains to overheat,
so yes, I grant permission for the code to be relicensed under the
GPLv2. Please make sure that this change in licensing makes its
way upstream. -russ
-- quote from email
**/
/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */
/*
Permission is granted to distribute the enclosed cs89x0.[ch] driver
only in conjunction with the Etherboot package. The code is
ordinarily distributed under the GPL.
Russ Nelson, January 2000
ChangeLog:
Thu Dec 6 22:40:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
* disabled all "advanced" features; this should make the code more reliable
* reorganized the reset function
* always reset the address port, so that autoprobing will continue working
* some cosmetic changes
* 2.5
Thu Dec 5 21:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
* tested the code against a CS8900 card
* lots of minor bug fixes and adjustments
* this is the first release, that actually works! it still requires some
changes in order to be more tolerant to different environments
* 4
Fri Nov 22 23:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
* read the manuals for the CS89x0 chipsets and took note of all the
changes that will be neccessary in order to adapt Russel Nelson's code
to the requirements of a BOOT-Prom
* 6
Thu Nov 19 22:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
* Synched with Russel Nelson's current code (v1.00)
* 2
Thu Nov 12 18:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
* Cleaned up some of the code and tried to optimize the code size.
* 1.5
Sun Nov 10 16:30:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de>
* First experimental release. This code compiles fine, but I
have no way of testing whether it actually works.
* I did not (yet) bother to make the code 16bit aware, so for
the time being, it will only work for Etherboot/32.
* 12
*/
#include "etherboot.h"
#include "nic.h"
#include "cards.h"
#include "cs89x0.h"
static unsigned short eth_nic_base;
static unsigned long eth_mem_start;
static unsigned short eth_irq;
static unsigned short eth_cs_type; /* one of: CS8900, CS8920, CS8920M */
static unsigned short eth_auto_neg_cnf;
static unsigned short eth_adapter_cnf;
static unsigned short eth_linectl;
/*************************************************************************
CS89x0 - specific routines
**************************************************************************/
static inline int readreg(int portno)
{
outw(portno, eth_nic_base + ADD_PORT);
return inw(eth_nic_base + DATA_PORT);
}
static inline void writereg(int portno, int value)
{
outw(portno, eth_nic_base + ADD_PORT);
outw(value, eth_nic_base + DATA_PORT);
return;
}
/*************************************************************************
EEPROM access
**************************************************************************/
static int wait_eeprom_ready(void)
{
unsigned long tmo = currticks() + 4*TICKS_PER_SEC;
/* check to see if the EEPROM is ready, a timeout is used -
just in case EEPROM is ready when SI_BUSY in the
PP_SelfST is clear */
while(readreg(PP_SelfST) & SI_BUSY) {
if (currticks() >= tmo)
return -1; }
return 0;
}
static int get_eeprom_data(int off, int len, unsigned short *buffer)
{
int i;
#ifdef EDEBUG
printf("\ncs: EEPROM data from %hX for %hX:",off,len);
#endif
for (i = 0; i < len; i++) {
if (wait_eeprom_ready() < 0)
return -1;
/* Now send the EEPROM read command and EEPROM location
to read */
writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD);
if (wait_eeprom_ready() < 0)
return -1;
buffer[i] = readreg(PP_EEData);
#ifdef EDEBUG
if (!(i%10))
printf("\ncs: ");
printf("%hX ", buffer[i]);
#endif
}
#ifdef EDEBUG
putchar('\n');
#endif
return(0);
}
static int get_eeprom_chksum(int off, int len, unsigned short *buffer)
{
int i, cksum;
cksum = 0;
for (i = 0; i < len; i++)
cksum += buffer[i];
cksum &= 0xffff;
if (cksum == 0)
return 0;
return -1;
}
/*************************************************************************
Activate all of the available media and probe for network
**************************************************************************/
static void clrline(void)
{
int i;
putchar('\r');
for (i = 79; i--; ) putchar(' ');
printf("\rcs: ");
return;
}
static void control_dc_dc(int on_not_off)
{
unsigned int selfcontrol;
unsigned long tmo = currticks() + TICKS_PER_SEC;
/* control the DC to DC convertor in the SelfControl register. */
selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
selfcontrol |= HCB1;
else
selfcontrol &= ~HCB1;
writereg(PP_SelfCTL, selfcontrol);
/* Wait for the DC/DC converter to power up - 1000ms */
while (currticks() < tmo);
return;
}
static int detect_tp(void)
{
unsigned long tmo;
/* Turn on the chip auto detection of 10BT/ AUI */
clrline(); printf("attempting %s:","TP");
/* If connected to another full duplex capable 10-Base-T card
the link pulses seem to be lost when the auto detect bit in
the LineCTL is set. To overcome this the auto detect bit
will be cleared whilst testing the 10-Base-T interface.
This would not be necessary for the sparrow chip but is
simpler to do it anyway. */
writereg(PP_LineCTL, eth_linectl &~ AUI_ONLY);
control_dc_dc(0);
/* Delay for the hardware to work out if the TP cable is
present - 150ms */
for (tmo = currticks() + 4; currticks() < tmo; );
if ((readreg(PP_LineST) & LINK_OK) == 0)
return 0;
if (eth_cs_type != CS8900) {
writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK);
if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
printf(" negotiating duplex... ");
while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) {
if (currticks() - tmo > 40*TICKS_PER_SEC) {
printf("time out ");
break;
}
}
}
if (readreg(PP_AutoNegST) & FDX_ACTIVE)
printf("using full duplex");
else
printf("using half duplex");
}
return A_CNF_MEDIA_10B_T;
}
/* send a test packet - return true if carrier bits are ok */
static int send_test_pkt(struct nic *nic)
{
static unsigned char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
0, 46, /*A 46 in network order */
0, 0, /*DSAP=0 & SSAP=0 fields */
0xf3,0 /*Control (Test Req+P bit set)*/ };
unsigned long tmo;
writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON);
memcpy(testpacket, nic->node_addr, ETH_ALEN);
memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN);
outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT);
/* Test to see if the chip has allocated memory for the packet */
for (tmo = currticks() + 2;
(readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; )
if (currticks() >= tmo)
return(0);
/* Write the contents of the packet */
outsw(eth_nic_base + TX_FRAME_PORT, testpacket,
(ETH_ZLEN+1)>>1);
printf(" sending test packet ");
/* wait a couple of timer ticks for packet to be received */
for (tmo = currticks() + 2; currticks() < tmo; );
if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
printf("succeeded");
return 1;
}
printf("failed");
return 0;
}
static int detect_aui(struct nic *nic)
{
clrline(); printf("attempting %s:","AUI");
control_dc_dc(0);
writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
if (send_test_pkt(nic)) {
return A_CNF_MEDIA_AUI; }
else
return 0;
}
static int detect_bnc(struct nic *nic)
{
clrline(); printf("attempting %s:","BNC");
control_dc_dc(1);
writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
if (send_test_pkt(nic)) {
return A_CNF_MEDIA_10B_2; }
else
return 0;
}
/**************************************************************************
ETH_RESET - Reset adapter
***************************************************************************/
static void cs89x0_reset(struct nic *nic)
{
int i;
unsigned long reset_tmo;
writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET);
/* wait for two ticks; that is 2*55ms */
for (reset_tmo = currticks() + 2; currticks() < reset_tmo; );
if (eth_cs_type != CS8900) {
/* Hardware problem requires PNP registers to be reconfigured
after a reset */
if (eth_irq != 0xFFFF) {
outw(PP_CS8920_ISAINT, eth_nic_base + ADD_PORT);
outb(eth_irq, eth_nic_base + DATA_PORT);
outb(0, eth_nic_base + DATA_PORT + 1); }
if (eth_mem_start) {
outw(PP_CS8920_ISAMemB, eth_nic_base + ADD_PORT);
outb((eth_mem_start >> 8) & 0xff, eth_nic_base + DATA_PORT);
outb((eth_mem_start >> 24) & 0xff, eth_nic_base + DATA_PORT + 1); } }
/* Wait until the chip is reset */
for (reset_tmo = currticks() + 2;
(readreg(PP_SelfST) & INIT_DONE) == 0 &&
currticks() < reset_tmo; );
/* disable interrupts and memory accesses */
writereg(PP_BusCTL, 0);
/* set the ethernet address */
for (i=0; i < ETH_ALEN/2; i++)
writereg(PP_IA+i*2,
nic->node_addr[i*2] |
(nic->node_addr[i*2+1] << 8));
/* receive only error free packets addressed to this card */
writereg(PP_RxCTL, DEF_RX_ACCEPT);
/* do not generate any interrupts on receive operations */
writereg(PP_RxCFG, 0);
/* do not generate any interrupts on transmit operations */
writereg(PP_TxCFG, 0);
/* do not generate any interrupts on buffer operations */
writereg(PP_BufCFG, 0);
/* reset address port, so that autoprobing will keep working */
outw(PP_ChipID, eth_nic_base + ADD_PORT);
return;
}
/**************************************************************************
ETH_TRANSMIT - Transmit a frame
***************************************************************************/
static void cs89x0_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
unsigned long tmo;
int sr;
/* does this size have to be rounded??? please,
somebody have a look in the specs */
if ((sr = ((s + ETH_HLEN + 1)&~1)) < ETH_ZLEN)
sr = ETH_ZLEN;
retry:
/* initiate a transmit sequence */
outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
outw(sr, eth_nic_base + TX_LEN_PORT);
/* Test to see if the chip has allocated memory for the packet */
if ((readreg(PP_BusST) & READY_FOR_TX_NOW) == 0) {
/* Oops... this should not happen! */
printf("cs: unable to send packet; retrying...\n");
for (tmo = currticks() + 5*TICKS_PER_SEC; currticks() < tmo; );
cs89x0_reset(nic);
goto retry; }
/* Write the contents of the packet */
outsw(eth_nic_base + TX_FRAME_PORT, d, ETH_ALEN/2);
outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr,
ETH_ALEN/2);
outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0;
outw(0, eth_nic_base + TX_FRAME_PORT));
/* wait for transfer to succeed */
for (tmo = currticks()+5*TICKS_PER_SEC;
(s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() < tmo;)
/* nothing */ ;
if ((s & TX_SEND_OK_BITS) != TX_OK) {
printf("\ntransmission error %#hX\n", s);
}
return;
}
/**************************************************************************
ETH_POLL - Wait for a frame
***************************************************************************/
static int cs89x0_poll(struct nic *nic)
{
int status;
status = readreg(PP_RxEvent);
if ((status & RX_OK) == 0)
return(0);
status = inw(eth_nic_base + RX_FRAME_PORT);
nic->packetlen = inw(eth_nic_base + RX_FRAME_PORT);
insw(eth_nic_base + RX_FRAME_PORT, nic->packet, nic->packetlen >> 1);
if (nic->packetlen & 1)
nic->packet[nic->packetlen-1] = inw(eth_nic_base + RX_FRAME_PORT);
return 1;
}
static void cs89x0_disable(struct nic *nic)
{
cs89x0_reset(nic);
}
/**************************************************************************
ETH_PROBE - Look for an adapter
***************************************************************************/
struct nic *cs89x0_probe(struct nic *nic, unsigned short *probe_addrs)
{
static const unsigned int netcard_portlist[] = {
#ifdef CS_SCAN
CS_SCAN,
#else /* use "conservative" default values for autoprobing */
0x300,0x320,0x340,0x200,0x220,0x240,
0x260,0x280,0x2a0,0x2c0,0x2e0,
/* if that did not work, then be more aggressive */
0x301,0x321,0x341,0x201,0x221,0x241,
0x261,0x281,0x2a1,0x2c1,0x2e1,
#endif
0};
int i, result = -1;
unsigned rev_type = 0, ioaddr, ioidx, isa_cnf, cs_revision;
unsigned short eeprom_buff[CHKSUM_LEN];
for (ioidx = 0; (ioaddr=netcard_portlist[ioidx++]) != 0; ) {
/* if they give us an odd I/O address, then do ONE write to
the address port, to get it back to address zero, where we
expect to find the EISA signature word. */
if (ioaddr & 1) {
ioaddr &= ~1;
if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
continue;
outw(PP_ChipID, ioaddr + ADD_PORT);
}
if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
continue;
eth_nic_base = ioaddr;
/* get the chip type */
rev_type = readreg(PRODUCT_ID_ADD);
eth_cs_type = rev_type &~ REVISON_BITS;
cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
printf("\ncs: cs89%c0%s rev %c, base %#hX",
eth_cs_type==CS8900?'0':'2',
eth_cs_type==CS8920M?"M":"",
cs_revision,
eth_nic_base);
/* First check to see if an EEPROM is attached*/
if ((readreg(PP_SelfST) & EEPROM_PRESENT) == 0) {
printf("\ncs: no EEPROM...\n");
outw(PP_ChipID, eth_nic_base + ADD_PORT);
continue; }
else if (get_eeprom_data(START_EEPROM_DATA,CHKSUM_LEN,
eeprom_buff) < 0) {
printf("\ncs: EEPROM read failed...\n");
outw(PP_ChipID, eth_nic_base + ADD_PORT);
continue; }
else if (get_eeprom_chksum(START_EEPROM_DATA,CHKSUM_LEN,
eeprom_buff) < 0) {
printf("\ncs: EEPROM checksum bad...\n");
outw(PP_ChipID, eth_nic_base + ADD_PORT);
continue; }
/* get transmission control word but keep the
autonegotiation bits */
eth_auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
/* Store adapter configuration */
eth_adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
/* Store ISA configuration */
isa_cnf = eeprom_buff[ISA_CNF_OFFSET/2];
/* store the initial memory base address */
eth_mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
printf("%s%s%s, addr ",
(eth_adapter_cnf & A_CNF_10B_T)?", RJ-45":"",
(eth_adapter_cnf & A_CNF_AUI)?", AUI":"",
(eth_adapter_cnf & A_CNF_10B_2)?", BNC":"");
/* If this is a CS8900 then no pnp soft */
if (eth_cs_type != CS8900 &&
/* Check if the ISA IRQ has been set */
(i = readreg(PP_CS8920_ISAINT) & 0xff,
(i != 0 && i < CS8920_NO_INTS)))
eth_irq = i;
else {
i = isa_cnf & INT_NO_MASK;
if (eth_cs_type == CS8900) {
/* the table that follows is dependent
upon how you wired up your cs8900
in your system. The table is the
same as the cs8900 engineering demo
board. irq_map also depends on the
contents of the table. Also see
write_irq, which is the reverse
mapping of the table below. */
if (i < 4) i = "\012\013\014\005"[i];
else printf("\ncs: BUG: isa_config is %d\n", i); }
eth_irq = i; }
/* Retrieve and print the ethernet address. */
for (i=0; i<ETH_ALEN; i++) {
nic->node_addr[i] = ((unsigned char *)eeprom_buff)[i];
}
printf("%!\n", nic->node_addr);
/* Set the LineCTL quintuplet based on adapter
configuration read from EEPROM */
if ((eth_adapter_cnf & A_CNF_EXTND_10B_2) &&
(eth_adapter_cnf & A_CNF_LOW_RX_SQUELCH))
eth_linectl = LOW_RX_SQUELCH;
else
eth_linectl = 0;
/* check to make sure that they have the "right"
hardware available */
switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
case A_CNF_MEDIA_10B_T: result = eth_adapter_cnf & A_CNF_10B_T;
break;
case A_CNF_MEDIA_AUI: result = eth_adapter_cnf & A_CNF_AUI;
break;
case A_CNF_MEDIA_10B_2: result = eth_adapter_cnf & A_CNF_10B_2;
break;
default: result = eth_adapter_cnf & (A_CNF_10B_T | A_CNF_AUI |
A_CNF_10B_2);
}
if (!result) {
printf("cs: EEPROM is configured for unavailable media\n");
error:
writereg(PP_LineCTL, readreg(PP_LineCTL) &
~(SERIAL_TX_ON | SERIAL_RX_ON));
outw(PP_ChipID, eth_nic_base + ADD_PORT);
continue;
}
/* Initialize the card for probing of the attached media */
cs89x0_reset(nic);
/* set the hardware to the configured choice */
switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
case A_CNF_MEDIA_10B_T:
result = detect_tp();
if (!result) {
clrline();
printf("10Base-T (RJ-45%s",
") has no cable\n"); }
/* check "ignore missing media" bit */
if (eth_auto_neg_cnf & IMM_BIT)
/* Yes! I don't care if I see a link pulse */
result = A_CNF_MEDIA_10B_T;
break;
case A_CNF_MEDIA_AUI:
result = detect_aui(nic);
if (!result) {
clrline();
printf("10Base-5 (AUI%s",
") has no cable\n"); }
/* check "ignore missing media" bit */
if (eth_auto_neg_cnf & IMM_BIT)
/* Yes! I don't care if I see a carrrier */
result = A_CNF_MEDIA_AUI;
break;
case A_CNF_MEDIA_10B_2:
result = detect_bnc(nic);
if (!result) {
clrline();
printf("10Base-2 (BNC%s",
") has no cable\n"); }
/* check "ignore missing media" bit */
if (eth_auto_neg_cnf & IMM_BIT)
/* Yes! I don't care if I can xmit a packet */
result = A_CNF_MEDIA_10B_2;
break;
case A_CNF_MEDIA_AUTO:
writereg(PP_LineCTL, eth_linectl | AUTO_AUI_10BASET);
if (eth_adapter_cnf & A_CNF_10B_T)
if ((result = detect_tp()) != 0)
break;
if (eth_adapter_cnf & A_CNF_AUI)
if ((result = detect_aui(nic)) != 0)
break;
if (eth_adapter_cnf & A_CNF_10B_2)
if ((result = detect_bnc(nic)) != 0)
break;
clrline(); printf("no media detected\n");
goto error;
}
clrline();
switch(result) {
case 0: printf("no network cable attached to configured media\n");
goto error;
case A_CNF_MEDIA_10B_T: printf("using 10Base-T (RJ-45)\n");
break;
case A_CNF_MEDIA_AUI: printf("using 10Base-5 (AUI)\n");
break;
case A_CNF_MEDIA_10B_2: printf("using 10Base-2 (BNC)\n");
break;
}
/* Turn on both receive and transmit operations */
writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON |
SERIAL_TX_ON);
break;
}
if (ioaddr == 0)
return (0);
nic->reset = cs89x0_reset;
nic->poll = cs89x0_poll;
nic->transmit = cs89x0_transmit;
nic->disable = cs89x0_disable;
return (nic);
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+479
View File
@@ -0,0 +1,479 @@
/**
Per an email message from Russ Nelson <nelson@crynwr.com> on
18 March 2008 this file is now licensed under GPL Version 2.
From: Russ Nelson <nelson@crynwr.com>
Date: Tue, 18 Mar 2008 12:42:00 -0400
Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
-- quote from email
As copyright holder, if I say it doesn't conflict with the GPL,
then it doesn't conflict with the GPL.
However, there's no point in causing people's brains to overheat,
so yes, I grant permission for the code to be relicensed under the
GPLv2. Please make sure that this change in licensing makes its
way upstream. -russ
-- quote from email
**/
/* Copyright, 1988-1992, Russell Nelson, Crynwr Software
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, version 1.
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. */
#define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */
/* offset 2h -> Model/Product Number */
/* offset 3h -> Chip Revision Number */
#define PP_ISAIOB 0x0020 /* IO base address */
#define PP_CS8900_ISAINT 0x0022 /* ISA interrupt select */
#define PP_CS8920_ISAINT 0x0370 /* ISA interrupt select */
#define PP_CS8900_ISADMA 0x0024 /* ISA Rec DMA channel */
#define PP_CS8920_ISADMA 0x0374 /* ISA Rec DMA channel */
#define PP_ISASOF 0x0026 /* ISA DMA offset */
#define PP_DmaFrameCnt 0x0028 /* ISA DMA Frame count */
#define PP_DmaByteCnt 0x002A /* ISA DMA Byte count */
#define PP_CS8900_ISAMemB 0x002C /* Memory base */
#define PP_CS8920_ISAMemB 0x0348 /* */
#define PP_ISABootBase 0x0030 /* Boot Prom base */
#define PP_ISABootMask 0x0034 /* Boot Prom Mask */
/* EEPROM data and command registers */
#define PP_EECMD 0x0040 /* NVR Interface Command register */
#define PP_EEData 0x0042 /* NVR Interface Data Register */
#define PP_DebugReg 0x0044 /* Debug Register */
#define PP_RxCFG 0x0102 /* Rx Bus config */
#define PP_RxCTL 0x0104 /* Receive Control Register */
#define PP_TxCFG 0x0106 /* Transmit Config Register */
#define PP_TxCMD 0x0108 /* Transmit Command Register */
#define PP_BufCFG 0x010A /* Bus configuration Register */
#define PP_LineCTL 0x0112 /* Line Config Register */
#define PP_SelfCTL 0x0114 /* Self Command Register */
#define PP_BusCTL 0x0116 /* ISA bus control Register */
#define PP_TestCTL 0x0118 /* Test Register */
#define PP_AutoNegCTL 0x011C /* Auto Negotiation Ctrl */
#define PP_ISQ 0x0120 /* Interrupt Status */
#define PP_RxEvent 0x0124 /* Rx Event Register */
#define PP_TxEvent 0x0128 /* Tx Event Register */
#define PP_BufEvent 0x012C /* Bus Event Register */
#define PP_RxMiss 0x0130 /* Receive Miss Count */
#define PP_TxCol 0x0132 /* Transmit Collision Count */
#define PP_LineST 0x0134 /* Line State Register */
#define PP_SelfST 0x0136 /* Self State register */
#define PP_BusST 0x0138 /* Bus Status */
#define PP_TDR 0x013C /* Time Domain Reflectometry */
#define PP_AutoNegST 0x013E /* Auto Neg Status */
#define PP_TxCommand 0x0144 /* Tx Command */
#define PP_TxLength 0x0146 /* Tx Length */
#define PP_LAF 0x0150 /* Hash Table */
#define PP_IA 0x0158 /* Physical Address Register */
#define PP_RxStatus 0x0400 /* Receive start of frame */
#define PP_RxLength 0x0402 /* Receive Length of frame */
#define PP_RxFrame 0x0404 /* Receive frame pointer */
#define PP_TxFrame 0x0A00 /* Transmit frame pointer */
/* Primary I/O Base Address. If no I/O base is supplied by the user, then this */
/* can be used as the default I/O base to access the PacketPage Area. */
#define DEFAULTIOBASE 0x0300
#define FIRST_IO 0x020C /* First I/O port to check */
#define LAST_IO 0x037C /* Last I/O port to check (+10h) */
#define ADD_MASK 0x3000 /* Mask it use of the ADD_PORT register */
#define ADD_SIG 0x3000 /* Expected ID signature */
#define CHIP_EISA_ID_SIG 0x630E /* Product ID Code for Crystal Chip (CS8900 spec 4.3) */
#ifdef IBMEIPKT
#define EISA_ID_SIG 0x4D24 /* IBM */
#define PART_NO_SIG 0x1010 /* IBM */
#define MONGOOSE_BIT 0x0000 /* IBM */
#else
#define EISA_ID_SIG 0x630E /* PnP Vendor ID (same as chip id for Crystal board) */
#define PART_NO_SIG 0x4000 /* ID code CS8920 board (PnP Vendor Product code) */
#define MONGOOSE_BIT 0x2000 /* PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */
#endif
#define PRODUCT_ID_ADD 0x0002 /* Address of product ID */
/* Mask to find out the types of registers */
#define REG_TYPE_MASK 0x001F
/* Eeprom Commands */
#define ERSE_WR_ENBL 0x00F0
#define ERSE_WR_DISABLE 0x0000
/* Defines Control/Config register quintuplet numbers */
#define RX_BUF_CFG 0x0003
#define RX_CONTROL 0x0005
#define TX_CFG 0x0007
#define TX_COMMAND 0x0009
#define BUF_CFG 0x000B
#define LINE_CONTROL 0x0013
#define SELF_CONTROL 0x0015
#define BUS_CONTROL 0x0017
#define TEST_CONTROL 0x0019
/* Defines Status/Count registers quintuplet numbers */
#define RX_EVENT 0x0004
#define TX_EVENT 0x0008
#define BUF_EVENT 0x000C
#define RX_MISS_COUNT 0x0010
#define TX_COL_COUNT 0x0012
#define LINE_STATUS 0x0014
#define SELF_STATUS 0x0016
#define BUS_STATUS 0x0018
#define TDR 0x001C
/* PP_RxCFG - Receive Configuration and Interrupt Mask bit definition - Read/write */
#define SKIP_1 0x0040
#define RX_STREAM_ENBL 0x0080
#define RX_OK_ENBL 0x0100
#define RX_DMA_ONLY 0x0200
#define AUTO_RX_DMA 0x0400
#define BUFFER_CRC 0x0800
#define RX_CRC_ERROR_ENBL 0x1000
#define RX_RUNT_ENBL 0x2000
#define RX_EXTRA_DATA_ENBL 0x4000
/* PP_RxCTL - Receive Control bit definition - Read/write */
#define RX_IA_HASH_ACCEPT 0x0040
#define RX_PROM_ACCEPT 0x0080
#define RX_OK_ACCEPT 0x0100
#define RX_MULTCAST_ACCEPT 0x0200
#define RX_IA_ACCEPT 0x0400
#define RX_BROADCAST_ACCEPT 0x0800
#define RX_BAD_CRC_ACCEPT 0x1000
#define RX_RUNT_ACCEPT 0x2000
#define RX_EXTRA_DATA_ACCEPT 0x4000
#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT)
/* Default receive mode - individually addressed, broadcast, and error free */
#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT)
/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */
#define TX_LOST_CRS_ENBL 0x0040
#define TX_SQE_ERROR_ENBL 0x0080
#define TX_OK_ENBL 0x0100
#define TX_LATE_COL_ENBL 0x0200
#define TX_JBR_ENBL 0x0400
#define TX_ANY_COL_ENBL 0x0800
#define TX_16_COL_ENBL 0x8000
/* PP_TxCMD - Transmit Command bit definition - Read-only */
#define TX_START_4_BYTES 0x0000
#define TX_START_64_BYTES 0x0040
#define TX_START_128_BYTES 0x0080
#define TX_START_ALL_BYTES 0x00C0
#define TX_FORCE 0x0100
#define TX_ONE_COL 0x0200
#define TX_TWO_PART_DEFF_DISABLE 0x0400
#define TX_NO_CRC 0x1000
#define TX_RUNT 0x2000
/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */
#define GENERATE_SW_INTERRUPT 0x0040
#define RX_DMA_ENBL 0x0080
#define READY_FOR_TX_ENBL 0x0100
#define TX_UNDERRUN_ENBL 0x0200
#define RX_MISS_ENBL 0x0400
#define RX_128_BYTE_ENBL 0x0800
#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000
#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000
#define RX_DEST_MATCH_ENBL 0x8000
/* PP_LineCTL - Line Control bit definition - Read/write */
#define SERIAL_RX_ON 0x0040
#define SERIAL_TX_ON 0x0080
#define AUI_ONLY 0x0100
#define AUTO_AUI_10BASET 0x0200
#define MODIFIED_BACKOFF 0x0800
#define NO_AUTO_POLARITY 0x1000
#define TWO_PART_DEFDIS 0x2000
#define LOW_RX_SQUELCH 0x4000
/* PP_SelfCTL - Software Self Control bit definition - Read/write */
#define POWER_ON_RESET 0x0040
#define SW_STOP 0x0100
#define SLEEP_ON 0x0200
#define AUTO_WAKEUP 0x0400
#define HCB0_ENBL 0x1000
#define HCB1_ENBL 0x2000
#define HCB0 0x4000
#define HCB1 0x8000
/* PP_BusCTL - ISA Bus Control bit definition - Read/write */
#define RESET_RX_DMA 0x0040
#define MEMORY_ON 0x0400
#define DMA_BURST_MODE 0x0800
#define IO_CHANNEL_READY_ON 0x1000
#define RX_DMA_SIZE_64K 0x2000
#define ENABLE_IRQ 0x8000
/* PP_TestCTL - Test Control bit definition - Read/write */
#define LINK_OFF 0x0080
#define ENDEC_LOOPBACK 0x0200
#define AUI_LOOPBACK 0x0400
#define BACKOFF_OFF 0x0800
#define FAST_TEST 0x8000
/* PP_RxEvent - Receive Event Bit definition - Read-only */
#define RX_IA_HASHED 0x0040
#define RX_DRIBBLE 0x0080
#define RX_OK 0x0100
#define RX_HASHED 0x0200
#define RX_IA 0x0400
#define RX_BROADCAST 0x0800
#define RX_CRC_ERROR 0x1000
#define RX_RUNT 0x2000
#define RX_EXTRA_DATA 0x4000
#define HASH_INDEX_MASK 0x0FC00
/* PP_TxEvent - Transmit Event Bit definition - Read-only */
#define TX_LOST_CRS 0x0040
#define TX_SQE_ERROR 0x0080
#define TX_OK 0x0100
#define TX_LATE_COL 0x0200
#define TX_JBR 0x0400
#define TX_16_COL 0x8000
#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS)
#define TX_COL_COUNT_MASK 0x7800
/* PP_BufEvent - Buffer Event Bit definition - Read-only */
#define SW_INTERRUPT 0x0040
#define RX_DMA 0x0080
#define READY_FOR_TX 0x0100
#define TX_UNDERRUN 0x0200
#define RX_MISS 0x0400
#define RX_128_BYTE 0x0800
#define TX_COL_OVRFLW 0x1000
#define RX_MISS_OVRFLW 0x2000
#define RX_DEST_MATCH 0x8000
/* PP_LineST - Ethernet Line Status bit definition - Read-only */
#define LINK_OK 0x0080
#define AUI_ON 0x0100
#define TENBASET_ON 0x0200
#define POLARITY_OK 0x1000
#define CRS_OK 0x4000
/* PP_SelfST - Chip Software Status bit definition */
#define ACTIVE_33V 0x0040
#define INIT_DONE 0x0080
#define SI_BUSY 0x0100
#define EEPROM_PRESENT 0x0200
#define EEPROM_OK 0x0400
#define EL_PRESENT 0x0800
#define EE_SIZE_64 0x1000
/* PP_BusST - ISA Bus Status bit definition */
#define TX_BID_ERROR 0x0080
#define READY_FOR_TX_NOW 0x0100
/* PP_AutoNegCTL - Auto Negotiation Control bit definition */
#define RE_NEG_NOW 0x0040
#define ALLOW_FDX 0x0080
#define AUTO_NEG_ENABLE 0x0100
#define NLP_ENABLE 0x0200
#define FORCE_FDX 0x8000
#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE)
#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW)
/* PP_AutoNegST - Auto Negotiation Status bit definition */
#define AUTO_NEG_BUSY 0x0080
#define FLP_LINK 0x0100
#define FLP_LINK_GOOD 0x0800
#define LINK_FAULT 0x1000
#define HDX_ACTIVE 0x4000
#define FDX_ACTIVE 0x8000
/* The following block defines the ISQ event types */
#define ISQ_RECEIVER_EVENT 0x04
#define ISQ_TRANSMITTER_EVENT 0x08
#define ISQ_BUFFER_EVENT 0x0c
#define ISQ_RX_MISS_EVENT 0x10
#define ISQ_TX_COL_EVENT 0x12
#define ISQ_EVENT_MASK 0x003F /* ISQ mask to find out type of event */
#define ISQ_HIST 16 /* small history buffer */
#define AUTOINCREMENT 0x8000 /* Bit mask to set bit-15 for autoincrement */
#define TXRXBUFSIZE 0x0600
#define RXDMABUFSIZE 0x8000
#define RXDMASIZE 0x4000
#define TXRX_LENGTH_MASK 0x07FF
/* rx options bits */
#define RCV_WITH_RXON 1 /* Set SerRx ON */
#define RCV_COUNTS 2 /* Use Framecnt1 */
#define RCV_PONG 4 /* Pong respondent */
#define RCV_DONG 8 /* Dong operation */
#define RCV_POLLING 0x10 /* Poll RxEvent */
#define RCV_ISQ 0x20 /* Use ISQ, int */
#define RCV_AUTO_DMA 0x100 /* Set AutoRxDMAE */
#define RCV_DMA 0x200 /* Set RxDMA only */
#define RCV_DMA_ALL 0x400 /* Copy all DMA'ed */
#define RCV_FIXED_DATA 0x800 /* Every frame same */
#define RCV_IO 0x1000 /* Use ISA IO only */
#define RCV_MEMORY 0x2000 /* Use ISA Memory */
#define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */
#define PKT_START PP_TxFrame /* Start of packet RAM */
#define RX_FRAME_PORT 0x0000
#define TX_FRAME_PORT RX_FRAME_PORT
#define TX_CMD_PORT 0x0004
#define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */
#define TX_AFTER_381 0x0020 /* Tx packet after 381 bytes copied */
#define TX_AFTER_ALL 0x0060 /* Tx packet after all bytes copied */
#define TX_LEN_PORT 0x0006
#define ISQ_PORT 0x0008
#define ADD_PORT 0x000A
#define DATA_PORT 0x000C
#define EEPROM_WRITE_EN 0x00F0
#define EEPROM_WRITE_DIS 0x0000
#define EEPROM_WRITE_CMD 0x0100
#define EEPROM_READ_CMD 0x0200
/* Receive Header */
/* Description of header of each packet in receive area of memory */
#define RBUF_EVENT_LOW 0 /* Low byte of RxEvent - status of received frame */
#define RBUF_EVENT_HIGH 1 /* High byte of RxEvent - status of received frame */
#define RBUF_LEN_LOW 2 /* Length of received data - low byte */
#define RBUF_LEN_HI 3 /* Length of received data - high byte */
#define RBUF_HEAD_LEN 4 /* Length of this header */
#define CHIP_READ 0x1 /* Used to mark state of the repins code (chip or dma) */
#define DMA_READ 0x2 /* Used to mark state of the repins code (chip or dma) */
/* for bios scan */
/* */
#ifdef CSDEBUG
/* use these values for debugging bios scan */
#define BIOS_START_SEG 0x00000
#define BIOS_OFFSET_INC 0x0010
#else
#define BIOS_START_SEG 0x0c000
#define BIOS_OFFSET_INC 0x0200
#endif
#define BIOS_LAST_OFFSET 0x0fc00
/* Byte offsets into the EEPROM configuration buffer */
#define ISA_CNF_OFFSET 0x6
#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8) /* 8900 eeprom */
#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8) /* 8920 eeprom */
/* the assumption here is that the bits in the eeprom are generally */
/* in the same position as those in the autonegctl register. */
/* Of course the IMM bit is not in that register so it must be */
/* masked out */
#define EE_FORCE_FDX 0x8000
#define EE_NLP_ENABLE 0x0200
#define EE_AUTO_NEG_ENABLE 0x0100
#define EE_ALLOW_FDX 0x0080
#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX)
#define IMM_BIT 0x0040 /* ignore missing media */
#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2)
#define A_CNF_10B_T 0x0001
#define A_CNF_AUI 0x0002
#define A_CNF_10B_2 0x0004
#define A_CNF_MEDIA_TYPE 0x0060
#define A_CNF_MEDIA_AUTO 0x0000
#define A_CNF_MEDIA_10B_T 0x0020
#define A_CNF_MEDIA_AUI 0x0040
#define A_CNF_MEDIA_10B_2 0x0060
#define A_CNF_DC_DC_POLARITY 0x0080
#define A_CNF_NO_AUTO_POLARITY 0x2000
#define A_CNF_LOW_RX_SQUELCH 0x4000
#define A_CNF_EXTND_10B_2 0x8000
#define PACKET_PAGE_OFFSET 0x8
/* Bit definitions for the ISA configuration word from the EEPROM */
#define INT_NO_MASK 0x000F
#define DMA_NO_MASK 0x0070
#define ISA_DMA_SIZE 0x0200
#define ISA_AUTO_RxDMA 0x0400
#define ISA_RxDMA 0x0800
#define DMA_BURST 0x1000
#define STREAM_TRANSFER 0x2000
#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA)
/* DMA controller registers */
#define DMA_BASE 0x00 /* DMA controller base */
#define DMA_BASE_2 0x0C0 /* DMA controller base */
#define DMA_STAT 0x0D0 /* DMA controller status register */
#define DMA_MASK 0x0D4 /* DMA controller mask register */
#define DMA_MODE 0x0D6 /* DMA controller mode register */
#define DMA_RESETFF 0x0D8 /* DMA controller first/last flip flop */
/* DMA data */
#define DMA_DISABLE 0x04 /* Disable channel n */
#define DMA_ENABLE 0x00 /* Enable channel n */
/* Demand transfers, incr. address, auto init, writes, ch. n */
#define DMA_RX_MODE 0x14
/* Demand transfers, incr. address, auto init, reads, ch. n */
#define DMA_TX_MODE 0x18
#define DMA_SIZE (16*1024) /* Size of dma buffer - 16k */
#define CS8900 0x0000
#define CS8920 0x4000
#define CS8920M 0x6000
#define REVISON_BITS 0x1F00
#define EEVER_NUMBER 0x12
#define CHKSUM_LEN 0x14
#define CHKSUM_VAL 0x0000
#define START_EEPROM_DATA 0x001c /* Offset into eeprom for start of data */
#define IRQ_MAP_EEPROM_DATA 0x0046 /* Offset into eeprom for the IRQ map */
#define IRQ_MAP_LEN 0x0004 /* No of bytes to read for the IRQ map */
#define PNP_IRQ_FRMT 0x0022 /* PNP small item IRQ format */
#define CS8900_IRQ_MAP 0x1c20 /* This IRQ map is fixed */
#define CS8920_NO_INTS 0x0F /* Max CS8920 interrupt select # */
#define PNP_ADD_PORT 0x0279
#define PNP_WRITE_PORT 0x0A79
#define GET_PNP_ISA_STRUCT 0x40
#define PNP_ISA_STRUCT_LEN 0x06
#define PNP_CSN_CNT_OFF 0x01
#define PNP_RD_PORT_OFF 0x02
#define PNP_FUNCTION_OK 0x00
#define PNP_WAKE 0x03
#define PNP_RSRC_DATA 0x04
#define PNP_RSRC_READY 0x01
#define PNP_STATUS 0x05
#define PNP_ACTIVATE 0x30
#define PNP_CNF_IO_H 0x60
#define PNP_CNF_IO_L 0x61
#define PNP_CNF_INT 0x70
#define PNP_CNF_DMA 0x74
#define PNP_CNF_MEM 0x48
#define BIT0 1
#define BIT15 0x8000
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+26
View File
@@ -0,0 +1,26 @@
Permission is granted to distribute the enclosed cs89x0.[ch] driver
only in conjunction with the Etherboot package. The code is
ordinarily distributed under the GPL.
Russ Nelson, January 2000
CREDITS
I want to thank
Mike Cruse <mcruse@cti-ltd.com>
for providing an evaluation NIC and for sponsoring the
development of this driver.
Randall Sears <sears@crystal.cirrus.com>
Deva Bodas <bodas@crystal.cirrus.com>
Andreas Kraemer <akraemer@crystal.cirrus.com>
Wolfgang Krause <100303.2673@compuserve.com>
for excellent technical support and for providing the required
programming information. I appreciate Crystal Semiconductor's
commitment towards free software.
Russell Nelson <nelson@crynwr.com>
for writing the Linux device driver for the CS89x0
chipset. Russel's code is very well designed and simplified my
job a lot.
+692
View File
@@ -0,0 +1,692 @@
/*
DAVICOM DM9009/DM9102/DM9102A Etherboot Driver V1.00
This driver was ported from Marty Conner's Tulip Etherboot driver.
Thanks Marty Connor (mdc@thinguin.org)
You can get Tulip driver source file from this URL:
"http://etherboot.sourceforge..net/#Distribution"
This davicom etherboot driver supports DM9009/DM9102/DM9102A/
DM9102A+DM9801/DM9102A+DM9802 NICs.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
*/
/*********************************************************************/
/* Revision History */
/*********************************************************************/
/*
19 OCT 2000 Sten 1.00
Different half and full duplex mode
Do the different programming for DM9801/DM9802
12 OCT 2000 Sten 0.90
This driver was ported from tulip driver and it
has the following difference.
Changed symbol tulip/TULIP to davicom/DAVICOM
Deleted some code that did not use in this driver.
Used chain-strcture to replace ring structure
for both TX/RX descriptor.
Allocated two tx descriptor.
According current media mode to set operating
register(CR6)
*/
/*********************************************************************/
/* Declarations */
/*********************************************************************/
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "cards.h"
#undef DAVICOM_DEBUG
#undef DAVICOM_DEBUG_WHERE
#define TX_TIME_OUT 2*TICKS_PER_SEC
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
/* Register offsets for davicom device */
enum davicom_offsets {
CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0
};
/* EEPROM Address width definitions */
#define EEPROM_ADDRLEN 6
#define EEPROM_SIZE 32 /* 1 << EEPROM_ADDRLEN */
/* Used to be 128, but we only need to read enough to get the MAC
address at bytes 20..25 */
/* Data Read from the EEPROM */
static unsigned char ee_data[EEPROM_SIZE];
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << addr_len)
#define EE_READ_CMD (6 << addr_len)
#define EE_ERASE_CMD (7 << addr_len)
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
#define EE_CS 0x01 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
#define EE_WRITE_0 0x01
#define EE_WRITE_1 0x05
#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
#define EE_ENB (0x4800 | EE_CS)
/* Sten 10/11 for phyxcer */
#define PHY_DATA_0 0x0
#define PHY_DATA_1 0x20000
#define MDCLKH 0x10000
/* Delay between EEPROM clock transitions. Even at 33Mhz current PCI
implementations don't overrun the EEPROM clock. We add a bus
turn-around to insure that this remains true. */
#define eeprom_delay() inl(ee_addr)
/* helpful macro if on a big_endian machine for changing byte order.
not strictly needed on Intel */
#define le16_to_cpu(val) (val)
/* transmit and receive descriptor format */
struct txdesc {
volatile unsigned long status; /* owner, status */
unsigned long buf1sz:11, /* size of buffer 1 */
buf2sz:11, /* size of buffer 2 */
control:10; /* control bits */
const unsigned char *buf1addr; /* buffer 1 address */
const unsigned char *buf2addr; /* buffer 2 address */
};
struct rxdesc {
volatile unsigned long status; /* owner, status */
unsigned long buf1sz:11, /* size of buffer 1 */
buf2sz:11, /* size of buffer 2 */
control:10; /* control bits */
unsigned char *buf1addr; /* buffer 1 address */
unsigned char *buf2addr; /* buffer 2 address */
};
/* Size of transmit and receive buffers */
#define BUFLEN 1536
/*********************************************************************/
/* Global Storage */
/*********************************************************************/
/* PCI Bus parameters */
static unsigned short vendor, dev_id;
static unsigned long ioaddr;
/* Note: transmit and receive buffers must be longword aligned and
longword divisable */
/* transmit descriptor and buffer */
#define NTXD 2
static struct txdesc txd[NTXD] __attribute__ ((aligned(4)));
#ifdef USE_LOWMEM_BUFFER
#define txb ((char *)0x10000 - BUFLEN)
#else
static unsigned char txb[BUFLEN] __attribute__ ((aligned(4)));
#endif
/* receive descriptor(s) and buffer(s) */
#define NRXD 4
static struct rxdesc rxd[NRXD] __attribute__ ((aligned(4)));
#ifdef USE_LOWMEM_BUFFER
#define rxb ((char *)0x10000 - NRXD * BUFLEN - BUFLEN)
#else
static unsigned char rxb[NRXD * BUFLEN] __attribute__ ((aligned(4)));
#endif
static int rxd_tail;
static int TxPtr;
/*********************************************************************/
/* Function Prototypes */
/*********************************************************************/
static void whereami(const char *str);
static int read_eeprom(unsigned long ioaddr, int location, int addr_len);
struct nic *davicom_probe(struct nic *nic, unsigned short *io_addrs,
struct pci_device *pci);
static void davicom_init_chain(struct nic *nic); /* Sten 10/9 */
static void davicom_reset(struct nic *nic);
static void davicom_transmit(struct nic *nic, const char *d, unsigned int t,
unsigned int s, const char *p);
static int davicom_poll(struct nic *nic);
static void davicom_disable(struct nic *nic);
static void whereami (const char *str);
#ifdef DAVICOM_DEBUG
static void davicom_more(void);
#endif /* DAVICOM_DEBUG */
static void davicom_wait(unsigned int nticks);
static int phy_read(int);
static void phy_write(int, u16);
static void phy_write_1bit(u32, u32);
static int phy_read_1bit(u32);
static void davicom_media_chk(struct nic *);
/*********************************************************************/
/* Utility Routines */
/*********************************************************************/
static inline void whereami (const char *str)
{
#ifdef DAVICOM_DEBUG_WHERE
printf("%s\n", str);
/* sleep(2); */
#endif
}
#ifdef DAVICOM_DEBUG
static void davicom_more()
{
printf("\n\n-- more --");
while (!iskey())
/* wait */;
getchar();
printf("\n\n");
}
#endif /* DAVICOM_DEBUG */
static void davicom_wait(unsigned int nticks)
{
unsigned int to = currticks() + nticks;
while (currticks() < to)
/* wait */ ;
}
/*********************************************************************/
/* For DAVICOM phyxcer register by MII interface */
/*********************************************************************/
/*
Read a word data from phy register
*/
static int phy_read(int location)
{
int i, phy_addr=1;
u16 phy_data;
u32 io_dcr9;
whereami("phy_read\n");
io_dcr9 = ioaddr + CSR9;
/* Send 33 synchronization clock to Phy controller */
for (i=0; i<34; i++)
phy_write_1bit(io_dcr9, PHY_DATA_1);
/* Send start command(01) to Phy */
phy_write_1bit(io_dcr9, PHY_DATA_0);
phy_write_1bit(io_dcr9, PHY_DATA_1);
/* Send read command(10) to Phy */
phy_write_1bit(io_dcr9, PHY_DATA_1);
phy_write_1bit(io_dcr9, PHY_DATA_0);
/* Send Phy addres */
for (i=0x10; i>0; i=i>>1)
phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
/* Send register addres */
for (i=0x10; i>0; i=i>>1)
phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0);
/* Skip transition state */
phy_read_1bit(io_dcr9);
/* read 16bit data */
for (phy_data=0, i=0; i<16; i++) {
phy_data<<=1;
phy_data|=phy_read_1bit(io_dcr9);
}
return phy_data;
}
/*
Write a word to Phy register
*/
static void phy_write(int location, u16 phy_data)
{
u16 i, phy_addr=1;
u32 io_dcr9;
whereami("phy_write\n");
io_dcr9 = ioaddr + CSR9;
/* Send 33 synchronization clock to Phy controller */
for (i=0; i<34; i++)
phy_write_1bit(io_dcr9, PHY_DATA_1);
/* Send start command(01) to Phy */
phy_write_1bit(io_dcr9, PHY_DATA_0);
phy_write_1bit(io_dcr9, PHY_DATA_1);
/* Send write command(01) to Phy */
phy_write_1bit(io_dcr9, PHY_DATA_0);
phy_write_1bit(io_dcr9, PHY_DATA_1);
/* Send Phy addres */
for (i=0x10; i>0; i=i>>1)
phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
/* Send register addres */
for (i=0x10; i>0; i=i>>1)
phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0);
/* written trasnition */
phy_write_1bit(io_dcr9, PHY_DATA_1);
phy_write_1bit(io_dcr9, PHY_DATA_0);
/* Write a word data to PHY controller */
for (i=0x8000; i>0; i>>=1)
phy_write_1bit(io_dcr9, phy_data&i ? PHY_DATA_1: PHY_DATA_0);
}
/*
Write one bit data to Phy Controller
*/
static void phy_write_1bit(u32 ee_addr, u32 phy_data)
{
whereami("phy_write_1bit\n");
outl(phy_data, ee_addr); /* MII Clock Low */
eeprom_delay();
outl(phy_data|MDCLKH, ee_addr); /* MII Clock High */
eeprom_delay();
outl(phy_data, ee_addr); /* MII Clock Low */
eeprom_delay();
}
/*
Read one bit phy data from PHY controller
*/
static int phy_read_1bit(u32 ee_addr)
{
int phy_data;
whereami("phy_read_1bit\n");
outl(0x50000, ee_addr);
eeprom_delay();
phy_data=(inl(ee_addr)>>19) & 0x1;
outl(0x40000, ee_addr);
eeprom_delay();
return phy_data;
}
/*
DM9801/DM9802 present check and program
*/
static void HPNA_process(void)
{
if ( (phy_read(3) & 0xfff0) == 0xb900 ) {
if ( phy_read(31) == 0x4404 ) {
/* DM9801 present */
if (phy_read(3) == 0xb901)
phy_write(16, 0x5); /* DM9801 E4 */
else
phy_write(16, 0x1005); /* DM9801 E3 and others */
phy_write(25, ((phy_read(24) + 3) & 0xff) | 0xf000);
} else {
/* DM9802 present */
phy_write(16, 0x5);
phy_write(25, (phy_read(25) & 0xff00) + 2);
}
}
}
/*
Sense media mode and set CR6
*/
static void davicom_media_chk(struct nic * nic)
{
unsigned long to, csr6;
csr6 = 0x00200000; /* SF */
outl(csr6, ioaddr + CSR6);
if (vendor == PCI_VENDOR_ID_DAVICOM && dev_id == PCI_DEVICE_ID_DM9009) {
/* Set to 10BaseT mode for DM9009 */
phy_write(0, 0);
} else {
/* For DM9102/DM9102A */
to = currticks() + 2 * TICKS_PER_SEC;
while ( ((phy_read(1) & 0x24)!=0x24) && (currticks() < to))
/* wait */ ;
if ( (phy_read(1) & 0x24) == 0x24 ) {
if (phy_read(17) & 0xa000)
csr6 |= 0x00000200; /* Full Duplex mode */
} else
csr6 |= 0x00040000; /* Select DM9801/DM9802 when Ethernet link failed */
}
/* set the chip's operating mode */
outl(csr6, ioaddr + CSR6);
/* DM9801/DM9802 present check & program */
if (csr6 & 0x40000)
HPNA_process();
}
/*********************************************************************/
/* EEPROM Reading Code */
/*********************************************************************/
/* EEPROM routines adapted from the Linux Tulip Code */
/* Reading a serial EEPROM is a "bit" grungy, but we work our way
through:->.
*/
static int read_eeprom(unsigned long ioaddr, int location, int addr_len)
{
int i;
unsigned short retval = 0;
long ee_addr = ioaddr + CSR9;
int read_cmd = location | EE_READ_CMD;
whereami("read_eeprom\n");
outl(EE_ENB & ~EE_CS, ee_addr);
outl(EE_ENB, ee_addr);
/* Shift the read command bits out. */
for (i = 4 + addr_len; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outl(EE_ENB | dataval, ee_addr);
eeprom_delay();
outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
}
outl(EE_ENB, ee_addr);
for (i = 16; i > 0; i--) {
outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
outl(EE_ENB, ee_addr);
eeprom_delay();
}
/* Terminate the EEPROM access. */
outl(EE_ENB & ~EE_CS, ee_addr);
return retval;
}
/*********************************************************************/
/* davicom_init_chain - setup the tx and rx descriptors */
/* Sten 10/9 */
/*********************************************************************/
static void davicom_init_chain(struct nic *nic)
{
int i;
/* setup the transmit descriptor */
/* Sten: Set 2 TX descriptor but use one TX buffer because
it transmit a packet and wait complete every time. */
for (i=0; i<NTXD; i++) {
txd[i].buf1addr = &txb[0]; /* Used same TX buffer */
txd[i].buf2addr = (unsigned char *)&txd[i+1]; /* Point to Next TX desc */
txd[i].buf1sz = 0;
txd[i].buf2sz = 0;
txd[i].control = 0x184; /* Begin/End/Chain */
txd[i].status = 0x00000000; /* give ownership to Host */
}
/* construct perfect filter frame with mac address as first match
and broadcast address for all others */
for (i=0; i<192; i++) txb[i] = 0xFF;
txb[0] = nic->node_addr[0];
txb[1] = nic->node_addr[1];
txb[4] = nic->node_addr[2];
txb[5] = nic->node_addr[3];
txb[8] = nic->node_addr[4];
txb[9] = nic->node_addr[5];
/* setup receive descriptor */
for (i=0; i<NRXD; i++) {
rxd[i].buf1addr = &rxb[i * BUFLEN];
rxd[i].buf2addr = (unsigned char *)&rxd[i+1]; /* Point to Next RX desc */
rxd[i].buf1sz = BUFLEN;
rxd[i].buf2sz = 0; /* not used */
rxd[i].control = 0x4; /* Chain Structure */
rxd[i].status = 0x80000000; /* give ownership to device */
}
/* Chain the last descriptor to first */
txd[NTXD - 1].buf2addr = (unsigned char *)&txd[0];
rxd[NRXD - 1].buf2addr = (unsigned char *)&rxd[0];
TxPtr = 0;
rxd_tail = 0;
}
/*********************************************************************/
/* davicom_reset - Reset adapter */
/*********************************************************************/
static void davicom_reset(struct nic *nic)
{
unsigned long to;
u32 addr_low, addr_high;
whereami("davicom_reset\n");
/* Stop Tx and RX */
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
outl(0x00000001, ioaddr + CSR0);
davicom_wait(TICKS_PER_SEC);
/* TX/RX descriptor burst */
outl(0x0C00000, ioaddr + CSR0); /* Sten 10/9 */
/* set up transmit and receive descriptors */
davicom_init_chain(nic); /* Sten 10/9 */
/* Point to receive descriptor */
outl((unsigned long)&rxd[0], ioaddr + CSR3);
outl((unsigned long)&txd[0], ioaddr + CSR4); /* Sten 10/9 */
/* According phyxcer media mode to set CR6,
DM9102/A phyxcer can auto-detect media mode */
davicom_media_chk(nic);
/* Prepare Setup Frame Sten 10/9 */
txd[TxPtr].buf1sz = 192;
txd[TxPtr].control = 0x024; /* SF/CE */
txd[TxPtr].status = 0x80000000; /* Give ownership to device */
/* Start Tx */
outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6);
/* immediate transmit demand */
outl(0, ioaddr + CSR1);
to = currticks() + TX_TIME_OUT;
while ((txd[TxPtr].status & 0x80000000) && (currticks() < to)) /* Sten 10/9 */
/* wait */ ;
if (currticks() >= to) {
printf ("TX Setup Timeout!\n");
}
/* Point to next TX descriptor */
TxPtr = (++TxPtr >= NTXD) ? 0:TxPtr; /* Sten 10/9 */
#ifdef DAVICOM_DEBUG
printf("txd.status = %X\n", txd.status);
printf("ticks = %d\n", currticks() - (to - TX_TIME_OUT));
davicom_more();
#endif
/* enable RX */
outl(inl(ioaddr + CSR6) | 0x00000002, ioaddr + CSR6);
/* immediate poll demand */
outl(0, ioaddr + CSR2);
}
/*********************************************************************/
/* eth_transmit - Transmit a frame */
/*********************************************************************/
static void davicom_transmit(struct nic *nic, const char *d, unsigned int t,
unsigned int s, const char *p)
{
unsigned long to;
whereami("davicom_transmit\n");
/* Stop Tx */
/* outl(inl(ioaddr + CSR6) & ~0x00002000, ioaddr + CSR6); */
/* setup ethernet header */
memcpy(&txb[0], d, ETH_ALEN); /* DA 6byte */
memcpy(&txb[ETH_ALEN], nic->node_addr, ETH_ALEN); /* SA 6byte*/
txb[ETH_ALEN*2] = (t >> 8) & 0xFF; /* Frame type: 2byte */
txb[ETH_ALEN*2+1] = t & 0xFF;
memcpy(&txb[ETH_HLEN], p, s); /* Frame data */
/* setup the transmit descriptor */
txd[TxPtr].buf1sz = ETH_HLEN+s;
txd[TxPtr].control = 0x00000184; /* LS+FS+CE */
txd[TxPtr].status = 0x80000000; /* give ownership to device */
/* immediate transmit demand */
outl(0, ioaddr + CSR1);
to = currticks() + TX_TIME_OUT;
while ((txd[TxPtr].status & 0x80000000) && (currticks() < to))
/* wait */ ;
if (currticks() >= to) {
printf ("TX Timeout!\n");
}
/* Point to next TX descriptor */
TxPtr = (++TxPtr >= NTXD) ? 0:TxPtr; /* Sten 10/9 */
}
/*********************************************************************/
/* eth_poll - Wait for a frame */
/*********************************************************************/
static int davicom_poll(struct nic *nic)
{
whereami("davicom_poll\n");
if (rxd[rxd_tail].status & 0x80000000)
return 0;
whereami("davicom_poll got one\n");
nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16;
if( rxd[rxd_tail].status & 0x00008000){
rxd[rxd_tail].status = 0x80000000;
rxd_tail++;
if (rxd_tail == NRXD) rxd_tail = 0;
return 0;
}
/* copy packet to working buffer */
/* XXX - this copy could be avoided with a little more work
but for now we are content with it because the optimised
memcpy is quite fast */
memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen);
/* return the descriptor and buffer to receive ring */
rxd[rxd_tail].status = 0x80000000;
rxd_tail++;
if (rxd_tail == NRXD) rxd_tail = 0;
return 1;
}
/*********************************************************************/
/* eth_disable - Disable the interface */
/*********************************************************************/
static void davicom_disable(struct nic *nic)
{
whereami("davicom_disable\n");
/* disable interrupts */
outl(0x00000000, ioaddr + CSR7);
/* Stop the chip's Tx and Rx processes. */
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
(volatile unsigned long)inl(ioaddr + CSR8);
}
/*********************************************************************/
/* eth_probe - Look for an adapter */
/*********************************************************************/
struct nic *davicom_probe(struct nic *nic, unsigned short *io_addrs,
struct pci_device *pci)
{
unsigned int i;
u32 l1, l2;
whereami("davicom_probe\n");
if (io_addrs == 0 || *io_addrs == 0)
return 0;
vendor = pci->vendor;
dev_id = pci->dev_id;
ioaddr = *io_addrs;
/* wakeup chip */
pcibios_write_config_dword(pci->bus, pci->devfn, 0x40, 0x00000000);
/* Stop the chip's Tx and Rx processes. */
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
(volatile unsigned long)inl(ioaddr + CSR8);
/* Get MAC Address */
/* read EEPROM data */
for (i = 0; i < sizeof(ee_data)/2; i++)
((unsigned short *)ee_data)[i] =
le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));
/* extract MAC address from EEPROM buffer */
for (i=0; i<ETH_ALEN; i++)
nic->node_addr[i] = ee_data[20+i];
printf("Davicom %! at ioaddr %#hX\n", nic->node_addr, ioaddr);
/* initialize device */
davicom_reset(nic);
nic->reset = davicom_reset;
nic->poll = davicom_poll;
nic->transmit = davicom_transmit;
nic->disable = davicom_disable;
return nic;
}
+752
View File
@@ -0,0 +1,752 @@
/* Etherboot: depca.h merged, comments from Linux driver retained */
/* depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux.
Written 1994, 1995 by David C. Davies.
Copyright 1994 David C. Davies
and
United States Government
(as represented by the Director, National Security Agency).
Copyright 1995 Digital Equipment Corporation.
This software may be used and distributed according to the terms of
the GNU Public License, incorporated herein by reference.
This driver is written for the Digital Equipment Corporation series
of DEPCA and EtherWORKS ethernet cards:
DEPCA (the original)
DE100
DE101
DE200 Turbo
DE201 Turbo
DE202 Turbo (TP BNC)
DE210
DE422 (EISA)
The driver has been tested on DE100, DE200 and DE202 cards in a
relatively busy network. The DE422 has been tested a little.
This driver will NOT work for the DE203, DE204 and DE205 series of
cards, since they have a new custom ASIC in place of the AMD LANCE
chip. See the 'ewrk3.c' driver in the Linux source tree for running
those cards.
I have benchmarked the driver with a DE100 at 595kB/s to (542kB/s from)
a DECstation 5000/200.
The author may be reached at davies@maniac.ultranet.com
=========================================================================
The driver was originally based on the 'lance.c' driver from Donald
Becker which is included with the standard driver distribution for
linux. V0.4 is a complete re-write with only the kernel interface
remaining from the original code.
1) Lance.c code in /linux/drivers/net/
2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
AMD, 1992 [(800) 222-9323].
3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
AMD, Pub. #17881, May 1993.
4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
AMD, Pub. #16907, May 1992
5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
Digital Equipment Corporation, 1989
8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
driver.
The original DEPCA card requires that the ethernet ROM address counter
be enabled to count and has an 8 bit NICSR. The ROM counter enabling is
only done when a 0x08 is read as the first address octet (to minimise
the chances of writing over some other hardware's I/O register). The
NICSR accesses have been changed to byte accesses for all the cards
supported by this driver, since there is only one useful bit in the MSB
(remote boot timeout) and it is not used. Also, there is a maximum of
only 48kB network RAM for this card. My thanks to Torbjorn Lindh for
help debugging all this (and holding my feet to the fire until I got it
right).
The DE200 series boards have on-board 64kB RAM for use as a shared
memory network buffer. Only the DE100 cards make use of a 2kB buffer
mode which has not been implemented in this driver (only the 32kB and
64kB modes are supported [16kB/48kB for the original DEPCA]).
At the most only 2 DEPCA cards can be supported on the ISA bus because
there is only provision for two I/O base addresses on each card (0x300
and 0x200). The I/O address is detected by searching for a byte sequence
in the Ethernet station address PROM at the expected I/O address for the
Ethernet PROM. The shared memory base address is 'autoprobed' by
looking for the self test PROM and detecting the card name. When a
second DEPCA is detected, information is placed in the base_addr
variable of the next device structure (which is created if necessary),
thus enabling ethif_probe initialization for the device. More than 2
EISA cards can be supported, but care will be needed assigning the
shared memory to ensure that each slot has the correct IRQ, I/O address
and shared memory address assigned.
************************************************************************
NOTE: If you are using two ISA DEPCAs, it is important that you assign
the base memory addresses correctly. The driver autoprobes I/O 0x300
then 0x200. The base memory address for the first device must be less
than that of the second so that the auto probe will correctly assign the
I/O and memory addresses on the same card. I can't think of a way to do
this unambiguously at the moment, since there is nothing on the cards to
tie I/O and memory information together.
I am unable to test 2 cards together for now, so this code is
unchecked. All reports, good or bad, are welcome.
************************************************************************
The board IRQ setting must be at an unused IRQ which is auto-probed
using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are
{2,3,4,5,7}, whereas the DE200 is at {5,9,10,11,15}. Note that IRQ2 is
really IRQ9 in machines with 16 IRQ lines.
No 16MB memory limitation should exist with this driver as DMA is not
used and the common memory area is in low memory on the network card (my
current system has 20MB and I've not had problems yet).
The ability to load this driver as a loadable module has been added. To
utilise this ability, you have to do <8 things:
0) have a copy of the loadable modules code installed on your system.
1) copy depca.c from the /linux/drivers/net directory to your favourite
temporary directory.
2) if you wish, edit the source code near line 1530 to reflect the I/O
address and IRQ you're using (see also 5).
3) compile depca.c, but include -DMODULE in the command line to ensure
that the correct bits are compiled (see end of source code).
4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
kernel with the depca configuration turned off and reboot.
5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100]
[Alan Cox: Changed the code to allow command line irq/io assignments]
[Dave Davies: Changed the code to allow command line mem/name
assignments]
6) run the net startup bits for your eth?? interface manually
(usually /etc/rc.inet[12] at boot time).
7) enjoy!
Note that autoprobing is not allowed in loadable modules - the system is
already up and running and you're messing with interrupts.
To unload a module, turn off the associated interface
'ifconfig eth?? down' then 'rmmod depca'.
To assign a base memory address for the shared memory when running as a
loadable module, see 5 above. To include the adapter name (if you have
no PROM but know the card name) also see 5 above. Note that this last
option will not work with kernel built-in depca's.
The shared memory assignment for a loadable module makes sense to avoid
the 'memory autoprobe' picking the wrong shared memory (for the case of
2 depca's in a PC).
************************************************************************
Support for MCA EtherWORKS cards added 11-3-98.
Verified to work with up to 2 DE212 cards in a system (although not
fully stress-tested).
Currently known bugs/limitations:
Note: with the MCA stuff as a module, it trusts the MCA configuration,
not the command line for IRQ and memory address. You can
specify them if you want, but it will throw your values out.
You still have to pass the IO address it was configured as
though.
************************************************************************
TO DO:
------
Revision History
----------------
Version Date Description
0.1 25-jan-94 Initial writing.
0.2 27-jan-94 Added LANCE TX hardware buffer chaining.
0.3 1-feb-94 Added multiple DEPCA support.
0.31 4-feb-94 Added DE202 recognition.
0.32 19-feb-94 Tidy up. Improve multi-DEPCA support.
0.33 25-feb-94 Fix DEPCA ethernet ROM counter enable.
Add jabber packet fix from murf@perftech.com
and becker@super.org
0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access.
0.35 8-mar-94 Added DE201 recognition. Tidied up.
0.351 30-apr-94 Added EISA support. Added DE422 recognition.
0.36 16-may-94 DE422 fix released.
0.37 22-jul-94 Added MODULE support
0.38 15-aug-94 Added DBR ROM switch in depca_close().
Multi DEPCA bug fix.
0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0.
0.381 12-dec-94 Added DE101 recognition, fix multicast bug.
0.382 9-feb-95 Fix recognition bug reported by <bkm@star.rl.ac.uk>.
0.383 22-feb-95 Fix for conflict with VESA SCSI reported by
<stromain@alf.dec.com>
0.384 17-mar-95 Fix a ring full bug reported by <bkm@star.rl.ac.uk>
0.385 3-apr-95 Fix a recognition bug reported by
<ryan.niemi@lastfrontier.com>
0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility
0.40 25-May-95 Rewrite for portability & updated.
ALPHA support from <jestabro@amt.tay1.dec.com>
0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from
suggestion by <heiko@colossus.escape.de>
0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable
modules.
Add 'adapter_name' for loadable modules when no PROM.
Both above from a suggestion by
<pchen@woodruffs121.residence.gatech.edu>.
Add new multicasting code.
0.421 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi>
0.422 29-Apr-96 Fix depca_hw_init() bug <jari@markkus2.fimr.fi>
0.423 7-Jun-96 Fix module load bug <kmg@barco.be>
0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
0.44 1-Sep-97 Fix *_probe() to test check_region() first - bug
reported by <mmogilvi@elbert.uccs.edu>
0.45 3-Nov-98 Added support for MCA EtherWORKS (DE210/DE212) cards
by <tymm@computer.org>
0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
0.5 14-Nov-98 Re-spin for 2.1.x kernels.
0.51 27-Jun-99 Correct received packet length for CRC from
report by <worm@dkik.dk>
=========================================================================
*/
#include "etherboot.h"
#include "nic.h"
#include "cards.h"
/*
** I/O addresses. Note that the 2k buffer option is not supported in
** this driver.
*/
#define DEPCA_NICSR ioaddr+0x00 /* Network interface CSR */
#define DEPCA_RBI ioaddr+0x02 /* RAM buffer index (2k buffer mode) */
#define DEPCA_DATA ioaddr+0x04 /* LANCE registers' data port */
#define DEPCA_ADDR ioaddr+0x06 /* LANCE registers' address port */
#define DEPCA_HBASE ioaddr+0x08 /* EISA high memory base address reg. */
#define DEPCA_PROM ioaddr+0x0c /* Ethernet address ROM data port */
#define DEPCA_CNFG ioaddr+0x0c /* EISA Configuration port */
#define DEPCA_RBSA ioaddr+0x0e /* RAM buffer starting address (2k buff.) */
/*
** These are LANCE registers addressable through DEPCA_ADDR
*/
#define CSR0 0
#define CSR1 1
#define CSR2 2
#define CSR3 3
/*
** NETWORK INTERFACE CSR (NI_CSR) bit definitions
*/
#define TO 0x0100 /* Time Out for remote boot */
#define SHE 0x0080 /* SHadow memory Enable */
#define BS 0x0040 /* Bank Select */
#define BUF 0x0020 /* BUFfer size (1->32k, 0->64k) */
#define RBE 0x0010 /* Remote Boot Enable (1->net boot) */
#define AAC 0x0008 /* Address ROM Address Counter (1->enable) */
#define _128KB 0x0008 /* 128kB Network RAM (1->enable) */
#define IM 0x0004 /* Interrupt Mask (1->mask) */
#define IEN 0x0002 /* Interrupt tristate ENable (1->enable) */
#define LED 0x0001 /* LED control */
/*
** Control and Status Register 0 (CSR0) bit definitions
*/
#define ERR 0x8000 /* Error summary */
#define BABL 0x4000 /* Babble transmitter timeout error */
#define CERR 0x2000 /* Collision Error */
#define MISS 0x1000 /* Missed packet */
#define MERR 0x0800 /* Memory Error */
#define RINT 0x0400 /* Receiver Interrupt */
#define TINT 0x0200 /* Transmit Interrupt */
#define IDON 0x0100 /* Initialization Done */
#define INTR 0x0080 /* Interrupt Flag */
#define INEA 0x0040 /* Interrupt Enable */
#define RXON 0x0020 /* Receiver on */
#define TXON 0x0010 /* Transmitter on */
#define TDMD 0x0008 /* Transmit Demand */
#define STOP 0x0004 /* Stop */
#define STRT 0x0002 /* Start */
#define INIT 0x0001 /* Initialize */
#define INTM 0xff00 /* Interrupt Mask */
#define INTE 0xfff0 /* Interrupt Enable */
/*
** CONTROL AND STATUS REGISTER 3 (CSR3)
*/
#define BSWP 0x0004 /* Byte SWaP */
#define ACON 0x0002 /* ALE control */
#define BCON 0x0001 /* Byte CONtrol */
/*
** Initialization Block Mode Register
*/
#define PROM 0x8000 /* Promiscuous Mode */
#define EMBA 0x0080 /* Enable Modified Back-off Algorithm */
#define INTL 0x0040 /* Internal Loopback */
#define DRTY 0x0020 /* Disable Retry */
#define COLL 0x0010 /* Force Collision */
#define DTCR 0x0008 /* Disable Transmit CRC */
#define LOOP 0x0004 /* Loopback */
#define DTX 0x0002 /* Disable the Transmitter */
#define DRX 0x0001 /* Disable the Receiver */
/*
** Receive Message Descriptor 1 (RMD1) bit definitions.
*/
#define R_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
#define R_ERR 0x4000 /* Error Summary */
#define R_FRAM 0x2000 /* Framing Error */
#define R_OFLO 0x1000 /* Overflow Error */
#define R_CRC 0x0800 /* CRC Error */
#define R_BUFF 0x0400 /* Buffer Error */
#define R_STP 0x0200 /* Start of Packet */
#define R_ENP 0x0100 /* End of Packet */
/*
** Transmit Message Descriptor 1 (TMD1) bit definitions.
*/
#define T_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
#define T_ERR 0x4000 /* Error Summary */
#define T_ADD_FCS 0x2000 /* More the 1 retry needed to Xmit */
#define T_MORE 0x1000 /* >1 retry to transmit packet */
#define T_ONE 0x0800 /* 1 try needed to transmit the packet */
#define T_DEF 0x0400 /* Deferred */
#define T_STP 0x02000000 /* Start of Packet */
#define T_ENP 0x01000000 /* End of Packet */
#define T_FLAGS 0xff000000 /* TX Flags Field */
/*
** Transmit Message Descriptor 3 (TMD3) bit definitions.
*/
#define TMD3_BUFF 0x8000 /* BUFFer error */
#define TMD3_UFLO 0x4000 /* UnderFLOw error */
#define TMD3_RES 0x2000 /* REServed */
#define TMD3_LCOL 0x1000 /* Late COLlision */
#define TMD3_LCAR 0x0800 /* Loss of CARrier */
#define TMD3_RTRY 0x0400 /* ReTRY error */
/*
** Ethernet PROM defines
*/
#define PROBE_LENGTH 32
/*
** Set the number of Tx and Rx buffers. Ensure that the memory requested
** here is <= to the amount of shared memory set up by the board switches.
** The number of descriptors MUST BE A POWER OF 2.
**
** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
*/
#define NUM_RX_DESC 2 /* Number of RX descriptors */
#define NUM_TX_DESC 2 /* Number of TX descriptors */
#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */
#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */
/*
** ISA Bus defines
*/
#define DEPCA_IO_PORTS {0x300, 0x200, 0}
#ifndef DEPCA_MODEL
#define DEPCA_MODEL DEPCA
#endif
static enum {
DEPCA, DE100, DE101, DE200, DE201, DE202, DE210, DE212, DE422, unknown
} adapter = DEPCA_MODEL;
/*
** Name <-> Adapter mapping
*/
static char *adapter_name[] = {
"DEPCA",
"DE100","DE101",
"DE200","DE201","DE202",
"DE210","DE212",
"DE422",
""
};
#ifndef DEPCA_RAM_BASE
#define DEPCA_RAM_BASE 0xd0000
#endif
/*
** Memory Alignment. Each descriptor is 4 longwords long. To force a
** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
** DESC_ALIGN. ALIGN aligns the start address of the private memory area
** and hence the RX descriptor ring's first entry.
*/
#define ALIGN4 ((u32)4 - 1) /* 1 longword align */
#define ALIGN8 ((u32)8 - 1) /* 2 longword (quadword) align */
#define ALIGN ALIGN8 /* Keep the LANCE happy... */
typedef long s32;
typedef unsigned long u32;
typedef short s16;
typedef unsigned short u16;
typedef char s8;
typedef unsigned char u8;
/*
** The DEPCA Rx and Tx ring descriptors.
*/
struct depca_rx_desc {
volatile s32 base;
s16 buf_length; /* This length is negative 2's complement! */
s16 msg_length; /* This length is "normal". */
};
struct depca_tx_desc {
volatile s32 base;
s16 length; /* This length is negative 2's complement! */
s16 misc; /* Errors and TDR info */
};
#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM
to LANCE memory address space */
/*
** The Lance initialization block, described in databook, in common memory.
*/
struct depca_init {
u16 mode; /* Mode register */
u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */
u8 mcast_table[8]; /* Multicast Hash Table. */
u32 rx_ring; /* Rx ring base pointer & ring length */
u32 tx_ring; /* Tx ring base pointer & ring length */
};
struct depca_private {
struct depca_rx_desc *rx_ring;
struct depca_tx_desc *tx_ring;
struct depca_init init_block; /* Shadow init block */
char *rx_memcpy[NUM_RX_DESC];
char *tx_memcpy[NUM_TX_DESC];
u32 bus_offset; /* ISA bus address offset */
u32 sh_mem; /* address of shared mem */
u32 dma_buffs; /* Rx & Tx buffer start */
int rx_cur, tx_cur; /* Next free ring entry */
int txRingMask, rxRingMask;
s32 rx_rlen, tx_rlen;
/* log2([rt]xRingMask+1) for the descriptors */
};
static Address mem_start = DEPCA_RAM_BASE;
static Address mem_len, offset;
static unsigned short ioaddr = 0;
static struct depca_private lp;
/*
** Miscellaneous defines...
*/
#define STOP_DEPCA \
outw(CSR0, DEPCA_ADDR);\
outw(STOP, DEPCA_DATA)
/* Initialize the lance Rx and Tx descriptor rings. */
static void depca_init_ring(struct nic *nic)
{
int i;
u32 p;
lp.rx_cur = lp.tx_cur = 0;
/* Initialize the base addresses and length of each buffer in the ring */
for (i = 0; i <= lp.rxRingMask; i++) {
writel((p = lp.dma_buffs + i * RX_BUFF_SZ) | R_OWN, &lp.rx_ring[i].base);
writew(-RX_BUFF_SZ, &lp.rx_ring[i].buf_length);
lp.rx_memcpy[i] = (char *) (p + lp.bus_offset);
}
for (i = 0; i <= lp.txRingMask; i++) {
writel((p = lp.dma_buffs + (i + lp.txRingMask + 1) * TX_BUFF_SZ) & 0x00ffffff, &lp.tx_ring[i].base);
lp.tx_memcpy[i] = (char *) (p + lp.bus_offset);
}
/* Set up the initialization block */
lp.init_block.rx_ring = ((u32) ((u32) lp.rx_ring) & LA_MASK) | lp.rx_rlen;
lp.init_block.tx_ring = ((u32) ((u32) lp.tx_ring) & LA_MASK) | lp.tx_rlen;
for (i = 0; i < ETH_ALEN; i++)
lp.init_block.phys_addr[i] = nic->node_addr[i];
lp.init_block.mode = 0x0000; /* Enable the Tx and Rx */
memset(lp.init_block.mcast_table, 0, sizeof(lp.init_block.mcast_table));
}
static void LoadCSRs(void)
{
outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */
outw((u16) (lp.sh_mem & LA_MASK), DEPCA_DATA);
outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */
outw((u16) ((lp.sh_mem & LA_MASK) >> 16), DEPCA_DATA);
outw(CSR3, DEPCA_ADDR); /* ALE control */
outw(ACON, DEPCA_DATA);
outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */
}
static int InitRestartDepca(void)
{
int i;
/* Copy the shadow init_block to shared memory */
memcpy_toio((char *)lp.sh_mem, &lp.init_block, sizeof(struct depca_init));
outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
outw(INIT, DEPCA_DATA); /* initialise DEPCA */
for (i = 0; i < 100 && !(inw(DEPCA_DATA) & IDON); i++)
;
if (i < 100) {
/* clear IDON by writing a 1, and start LANCE */
outw(IDON | STRT, DEPCA_DATA);
} else {
printf("DEPCA not initialised\n");
return (1);
}
return (0);
}
/**************************************************************************
RESET - Reset adapter
***************************************************************************/
static void depca_reset(struct nic *nic)
{
s16 nicsr;
int i, j;
STOP_DEPCA;
nicsr = inb(DEPCA_NICSR);
nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
outb(nicsr, DEPCA_NICSR);
if (inw(DEPCA_DATA) != STOP)
{
printf("depca: Cannot stop NIC\n");
return;
}
/* Initialisation block */
lp.sh_mem = mem_start;
mem_start += sizeof(struct depca_init);
/* Tx & Rx descriptors (aligned to a quadword boundary) */
mem_start = (mem_start + ALIGN) & ~ALIGN;
lp.rx_ring = (struct depca_rx_desc *) mem_start;
mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
lp.tx_ring = (struct depca_tx_desc *) mem_start;
mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
lp.bus_offset = mem_start & 0x00ff0000;
/* LANCE re-mapped start address */
lp.dma_buffs = mem_start & LA_MASK;
/* Finish initialising the ring information. */
lp.rxRingMask = NUM_RX_DESC - 1;
lp.txRingMask = NUM_TX_DESC - 1;
/* Calculate Tx/Rx RLEN size for the descriptors. */
for (i = 0, j = lp.rxRingMask; j > 0; i++) {
j >>= 1;
}
lp.rx_rlen = (s32) (i << 29);
for (i = 0, j = lp.txRingMask; j > 0; i++) {
j >>= 1;
}
lp.tx_rlen = (s32) (i << 29);
/* Load the initialisation block */
depca_init_ring(nic);
LoadCSRs();
InitRestartDepca();
}
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
static int depca_poll(struct nic *nic)
{
int entry;
u32 status;
entry = lp.rx_cur;
if ((status = readl(&lp.rx_ring[entry].base) & R_OWN))
return (0);
memcpy(nic->packet, lp.rx_memcpy[entry], nic->packetlen = lp.rx_ring[entry].msg_length);
lp.rx_ring[entry].base |= R_OWN;
lp.rx_cur = (++lp.rx_cur) & lp.rxRingMask;
return (1);
}
/**************************************************************************
TRANSMIT - Transmit a frame
***************************************************************************/
static void depca_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
int entry, len;
char *mem;
/* send the packet to destination */
/*
** Caution: the right order is important here... dont
** setup the ownership rights until all the other
** information is in place
*/
mem = lp.tx_memcpy[entry = lp.tx_cur];
memcpy_toio(mem, d, ETH_ALEN);
memcpy_toio(mem + ETH_ALEN, nic->node_addr, ETH_ALEN);
mem[ETH_ALEN * 2] = t >> 8;
mem[ETH_ALEN * 2 + 1] = t;
memcpy_toio(mem + ETH_HLEN, p, s);
s += ETH_HLEN;
len = (s < ETH_ZLEN ? ETH_ZLEN : s);
/* clean out flags */
writel(readl(&lp.tx_ring[entry].base) & ~T_FLAGS, &lp.tx_ring[entry].base);
/* clears other error flags */
writew(0x0000, &lp.tx_ring[entry].misc);
/* packet length in buffer */
writew(-len, &lp.tx_ring[entry].length);
/* start and end of packet, ownership */
writel(readl(&lp.tx_ring[entry].base) | (T_STP|T_ENP|T_OWN), &lp.tx_ring[entry].base);
/* update current pointers */
lp.tx_cur = (++lp.tx_cur) & lp.txRingMask;
}
/**************************************************************************
DISABLE - Turn off ethernet interface
***************************************************************************/
static void depca_disable(struct nic *nic)
{
STOP_DEPCA;
}
/*
** Look for a special sequence in the Ethernet station address PROM that
** is common across all DEPCA products. Note that the original DEPCA needs
** its ROM address counter to be initialized and enabled. Only enable
** if the first address octet is a 0x08 - this minimises the chances of
** messing around with some other hardware, but it assumes that this DEPCA
** card initialized itself correctly.
**
** Search the Ethernet address ROM for the signature. Since the ROM address
** counter can start at an arbitrary point, the search must include the entire
** probe sequence length plus the (length_of_the_signature - 1).
** Stop the search IMMEDIATELY after the signature is found so that the
** PROM address counter is correctly positioned at the start of the
** ethernet address for later read out.
*/
static int depca_probe1(struct nic *nic)
{
u8 data, nicsr;
/* This is only correct for little endian machines, but then
Etherboot doesn't work on anything but a PC */
u8 sig[] = { 0xFF, 0x00, 0x55, 0xAA, 0xFF, 0x00, 0x55, 0xAA };
int i, j;
long sum, chksum;
data = inb(DEPCA_PROM); /* clear counter on DEPCA */
data = inb(DEPCA_PROM); /* read data */
if (data == 0x8) {
nicsr = inb(DEPCA_NICSR);
nicsr |= AAC;
outb(nicsr, DEPCA_NICSR);
}
for (i = 0, j = 0; j < (int)sizeof(sig) && i < PROBE_LENGTH+((int)sizeof(sig))-1; ++i) {
data = inb(DEPCA_PROM);
if (data == sig[j]) /* track signature */
++j;
else
j = (data == sig[0]) ? 1 : 0;
}
if (j != sizeof(sig))
return (0);
/* put the card in its initial state */
STOP_DEPCA;
nicsr = ((inb(DEPCA_NICSR) & ~SHE & ~RBE & ~IEN) | IM);
outb(nicsr, DEPCA_NICSR);
if (inw(DEPCA_DATA) != STOP)
return (0);
memcpy((char *)mem_start, sig, sizeof(sig));
if (memcmp((char *)mem_start, sig, sizeof(sig)) != 0)
return (0);
for (i = 0, j = 0, sum = 0; j < 3; j++) {
sum <<= 1;
if (sum > 0xFFFF)
sum -= 0xFFFF;
sum += (u8)(nic->node_addr[i++] = inb(DEPCA_PROM));
sum += (u16)((nic->node_addr[i++] = inb(DEPCA_PROM)) << 8);
if (sum > 0xFFFF)
sum -= 0xFFFF;
}
if (sum == 0xFFFF)
sum = 0;
chksum = (u8)inb(DEPCA_PROM);
chksum |= (u16)(inb(DEPCA_PROM) << 8);
mem_len = (adapter == DEPCA) ? (48 << 10) : (64 << 10);
offset = 0;
if (nicsr & BUF) {
offset = 0x8000;
nicsr &= ~BS;
mem_len -= (32 << 10);
}
if (adapter != DEPCA) /* enable shadow RAM */
outb(nicsr |= SHE, DEPCA_NICSR);
printf("%s base %#hX, memory [%#hX-%#hX], addr %!",
adapter_name[adapter], ioaddr, mem_start, mem_start + mem_len,
nic->node_addr);
if (sum != chksum)
printf(" (bad checksum)");
putchar('\n');
return (1);
}
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
struct nic *depca_probe(struct nic *nic, unsigned short *probe_addrs)
{
static unsigned short base[] = DEPCA_IO_PORTS;
int i;
if (probe_addrs == 0 || probe_addrs[0] == 0)
probe_addrs = base; /* Use defaults */
for (i = 0; (ioaddr = base[i]) != 0; ++i) {
if (depca_probe1(nic))
break;
}
if (ioaddr == 0)
return (0);
depca_reset(nic);
/* point to NIC specific routines */
nic->reset = depca_reset;
nic->poll = depca_poll;
nic->transmit = depca_transmit;
nic->disable = depca_disable;
return (nic);
}
+586
View File
@@ -0,0 +1,586 @@
/**************************************************************************
Etherboot - BOOTP/TFTP Bootstrap Program
Intel EEPRO/10 NIC driver for Etherboot
Adapted from Linux eepro.c from kernel 2.2.17
This board accepts a 32 pin EEPROM (29C256), however a test with a
27C010 shows that this EPROM also works in the socket, but it's not clear
how repeatably. The two top address pins appear to be held low, thus
the bottom 32kB of the 27C010 is visible in the CPU's address space.
To be sure you could put 4 copies of the code in the 27C010, then
it doesn't matter whether the extra lines are held low or high, just
hopefully not floating as CMOS chips don't like floating inputs.
Be careful with seating the EPROM as the socket on my board actually
has 34 pins, the top row of 2 are not used.
***************************************************************************/
/*
* 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, or (at
* your option) any later version.
*/
/* to get some global routines like printf */
#include "etherboot.h"
/* to get the interface to the body of the program */
#include "nic.h"
/* to get our own prototype */
#include "cards.h"
/* we use timer2 for microsecond waits */
#include "timer.h"
#undef DEBUG /* only after include files */
/* Different 82595 chips */
#define LAN595 0
#define LAN595TX 1
#define LAN595FX 2
#define LAN595FX_10ISA 3
#define SLOW_DOWN inb(0x80);
/* The station (ethernet) address prefix, used for IDing the board. */
#define SA_ADDR0 0x00 /* Etherexpress Pro/10 */
#define SA_ADDR1 0xaa
#define SA_ADDR2 0x00
#define GetBit(x,y) ((x & (1<<y))>>y)
/* EEPROM Word 0: */
#define ee_PnP 0 /* Plug 'n Play enable bit */
#define ee_Word1 1 /* Word 1? */
#define ee_BusWidth 2 /* 8/16 bit */
#define ee_FlashAddr 3 /* Flash Address */
#define ee_FlashMask 0x7 /* Mask */
#define ee_AutoIO 6 /* */
#define ee_reserved0 7 /* =0! */
#define ee_Flash 8 /* Flash there? */
#define ee_AutoNeg 9 /* Auto Negotiation enabled? */
#define ee_IO0 10 /* IO Address LSB */
#define ee_IO0Mask 0x /*...*/
#define ee_IO1 15 /* IO MSB */
/* EEPROM Word 1: */
#define ee_IntSel 0 /* Interrupt */
#define ee_IntMask 0x7
#define ee_LI 3 /* Link Integrity 0= enabled */
#define ee_PC 4 /* Polarity Correction 0= enabled */
#define ee_TPE_AUI 5 /* PortSelection 1=TPE */
#define ee_Jabber 6 /* Jabber prevention 0= enabled */
#define ee_AutoPort 7 /* Auto Port Selection 1= Disabled */
#define ee_SMOUT 8 /* SMout Pin Control 0= Input */
#define ee_PROM 9 /* Flash EPROM / PROM 0=Flash */
#define ee_reserved1 10 /* .. 12 =0! */
#define ee_AltReady 13 /* Alternate Ready, 0=normal */
#define ee_reserved2 14 /* =0! */
#define ee_Duplex 15
/* Word2,3,4: */
#define ee_IA5 0 /*bit start for individual Addr Byte 5 */
#define ee_IA4 8 /*bit start for individual Addr Byte 5 */
#define ee_IA3 0 /*bit start for individual Addr Byte 5 */
#define ee_IA2 8 /*bit start for individual Addr Byte 5 */
#define ee_IA1 0 /*bit start for individual Addr Byte 5 */
#define ee_IA0 8 /*bit start for individual Addr Byte 5 */
/* Word 5: */
#define ee_BNC_TPE 0 /* 0=TPE */
#define ee_BootType 1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */
#define ee_BootTypeMask 0x3
#define ee_NumConn 3 /* Number of Connections 0= One or Two */
#define ee_FlashSock 4 /* Presence of Flash Socket 0= Present */
#define ee_PortTPE 5
#define ee_PortBNC 6
#define ee_PortAUI 7
#define ee_PowerMgt 10 /* 0= disabled */
#define ee_CP 13 /* Concurrent Processing */
#define ee_CPMask 0x7
/* Word 6: */
#define ee_Stepping 0 /* Stepping info */
#define ee_StepMask 0x0F
#define ee_BoardID 4 /* Manucaturer Board ID, reserved */
#define ee_BoardMask 0x0FFF
/* Word 7: */
#define ee_INT_TO_IRQ 0 /* int to IRQ Mapping = 0x1EB8 for Pro/10+ */
#define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */
/*..*/
#define ee_SIZE 0x40 /* total EEprom Size */
#define ee_Checksum 0xBABA /* initial and final value for adding checksum */
/* Card identification via EEprom: */
#define ee_addr_vendor 0x10 /* Word offset for EISA Vendor ID */
#define ee_addr_id 0x11 /* Word offset for Card ID */
#define ee_addr_SN 0x12 /* Serial Number */
#define ee_addr_CRC_8 0x14 /* CRC over last thee Bytes */
#define ee_vendor_intel0 0x25 /* Vendor ID Intel */
#define ee_vendor_intel1 0xD4
#define ee_id_eepro10p0 0x10 /* ID for eepro/10+ */
#define ee_id_eepro10p1 0x31
/* now this section could be used by both boards: the oldies and the ee10:
* ee10 uses tx buffer before of rx buffer and the oldies the inverse.
* (aris)
*/
#define RAM_SIZE 0x8000
#define RCV_HEADER 8
#define RCV_DEFAULT_RAM 0x6000
#define RCV_RAM rcv_ram
static unsigned rcv_ram = RCV_DEFAULT_RAM;
#define XMT_HEADER 8
#define XMT_RAM (RAM_SIZE - RCV_RAM)
#define XMT_START ((rcv_start + RCV_RAM) % RAM_SIZE)
#define RCV_LOWER_LIMIT (rcv_start >> 8)
#define RCV_UPPER_LIMIT (((rcv_start + RCV_RAM) - 2) >> 8)
#define XMT_LOWER_LIMIT (XMT_START >> 8)
#define XMT_UPPER_LIMIT (((XMT_START + XMT_RAM) - 2) >> 8)
#define RCV_START_PRO 0x00
#define RCV_START_10 XMT_RAM
/* by default the old driver */
static unsigned rcv_start = RCV_START_PRO;
#define RCV_DONE 0x0008
#define RX_OK 0x2000
#define RX_ERROR 0x0d81
#define TX_DONE_BIT 0x0080
#define CHAIN_BIT 0x8000
#define XMT_STATUS 0x02
#define XMT_CHAIN 0x04
#define XMT_COUNT 0x06
#define BANK0_SELECT 0x00
#define BANK1_SELECT 0x40
#define BANK2_SELECT 0x80
/* Bank 0 registers */
#define COMMAND_REG 0x00 /* Register 0 */
#define MC_SETUP 0x03
#define XMT_CMD 0x04
#define DIAGNOSE_CMD 0x07
#define RCV_ENABLE_CMD 0x08
#define RCV_DISABLE_CMD 0x0a
#define STOP_RCV_CMD 0x0b
#define RESET_CMD 0x0e
#define POWER_DOWN_CMD 0x18
#define RESUME_XMT_CMD 0x1c
#define SEL_RESET_CMD 0x1e
#define STATUS_REG 0x01 /* Register 1 */
#define RX_INT 0x02
#define TX_INT 0x04
#define EXEC_STATUS 0x30
#define ID_REG 0x02 /* Register 2 */
#define R_ROBIN_BITS 0xc0 /* round robin counter */
#define ID_REG_MASK 0x2c
#define ID_REG_SIG 0x24
#define AUTO_ENABLE 0x10
#define INT_MASK_REG 0x03 /* Register 3 */
#define RX_STOP_MASK 0x01
#define RX_MASK 0x02
#define TX_MASK 0x04
#define EXEC_MASK 0x08
#define ALL_MASK 0x0f
#define IO_32_BIT 0x10
#define RCV_BAR 0x04 /* The following are word (16-bit) registers */
#define RCV_STOP 0x06
#define XMT_BAR_PRO 0x0a
#define XMT_BAR_10 0x0b
static unsigned xmt_bar = XMT_BAR_PRO;
#define HOST_ADDRESS_REG 0x0c
#define IO_PORT 0x0e
#define IO_PORT_32_BIT 0x0c
/* Bank 1 registers */
#define REG1 0x01
#define WORD_WIDTH 0x02
#define INT_ENABLE 0x80
#define INT_NO_REG 0x02
#define RCV_LOWER_LIMIT_REG 0x08
#define RCV_UPPER_LIMIT_REG 0x09
#define XMT_LOWER_LIMIT_REG_PRO 0x0a
#define XMT_UPPER_LIMIT_REG_PRO 0x0b
#define XMT_LOWER_LIMIT_REG_10 0x0b
#define XMT_UPPER_LIMIT_REG_10 0x0a
static unsigned xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO;
static unsigned xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO;
/* Bank 2 registers */
#define XMT_Chain_Int 0x20 /* Interrupt at the end of the transmit chain */
#define XMT_Chain_ErrStop 0x40 /* Interrupt at the end of the chain even if there are errors */
#define RCV_Discard_BadFrame 0x80 /* Throw bad frames away, and continue to receive others */
#define REG2 0x02
#define PRMSC_Mode 0x01
#define Multi_IA 0x20
#define REG3 0x03
#define TPE_BIT 0x04
#define BNC_BIT 0x20
#define REG13 0x0d
#define FDX 0x00
#define A_N_ENABLE 0x02
#define I_ADD_REG0 0x04
#define I_ADD_REG1 0x05
#define I_ADD_REG2 0x06
#define I_ADD_REG3 0x07
#define I_ADD_REG4 0x08
#define I_ADD_REG5 0x09
#define EEPROM_REG_PRO 0x0a
#define EEPROM_REG_10 0x0b
static unsigned eeprom_reg = EEPROM_REG_PRO;
#define EESK 0x01
#define EECS 0x02
#define EEDI 0x04
#define EEDO 0x08
/* The horrible routine to read a word from the serial EEPROM. */
/* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */
/* The delay between EEPROM clock transitions. */
#define eeprom_delay() { udelay(40); }
#define EE_READ_CMD (6 << 6)
/* do a full reset */
#define eepro_full_reset(ioaddr) outb(RESET_CMD, ioaddr); udelay(40);
/* do a nice reset */
#define eepro_sel_reset(ioaddr) { \
outb(SEL_RESET_CMD, ioaddr); \
SLOW_DOWN; \
SLOW_DOWN; \
}
/* clear all interrupts */
#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
/* enable rx */
#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
/* disable rx */
#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
/* switch bank */
#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
static unsigned int rx_start, tx_start;
static int tx_last;
static unsigned tx_end;
static int eepro = 0;
static unsigned short ioaddr = 0;
static unsigned int mem_start, mem_end = RCV_DEFAULT_RAM / 1024;
#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000)
/**************************************************************************
RESET - Reset adapter
***************************************************************************/
static void eepro_reset(struct nic *nic)
{
int temp_reg, i;
/* put the card in its initial state */
eepro_sw2bank2(ioaddr); /* be careful, bank2 now */
temp_reg = inb(ioaddr + eeprom_reg);
#ifdef DEBUG
printf("Stepping %d\n", temp_reg >> 5);
#endif
if (temp_reg & 0x10) /* check the TurnOff Enable bit */
outb(temp_reg & 0xEF, ioaddr + eeprom_reg);
for (i = 0; i < ETH_ALEN; i++) /* fill the MAC address */
outb(nic->node_addr[i], ioaddr + I_ADD_REG0 + i);
temp_reg = inb(ioaddr + REG1);
/* setup Transmit Chaining and discard bad RCV frames */
outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop
| RCV_Discard_BadFrame, ioaddr + REG1);
temp_reg = inb(ioaddr + REG2); /* match broadcast */
outb(temp_reg | 0x14, ioaddr + REG2);
temp_reg = inb(ioaddr + REG3);
outb(temp_reg & 0x3F, ioaddr + REG3); /* clear test mode */
/* set the receiving mode */
eepro_sw2bank1(ioaddr); /* be careful, bank1 now */
/* initialise the RCV and XMT upper and lower limits */
outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG);
outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG);
outb(XMT_LOWER_LIMIT, ioaddr + xmt_lower_limit_reg);
outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg);
eepro_sw2bank0(ioaddr); /* Switch back to bank 0 */
eepro_clear_int(ioaddr);
/* Initialise RCV */
outw(rx_start = (RCV_LOWER_LIMIT << 8), ioaddr + RCV_BAR);
outw(((RCV_UPPER_LIMIT << 8) | 0xFE), ioaddr + RCV_STOP);
/* Intialise XMT */
outw((XMT_LOWER_LIMIT << 8), ioaddr + xmt_bar);
eepro_sel_reset(ioaddr);
tx_start = tx_end = (XMT_LOWER_LIMIT << 8);
tx_last = 0;
eepro_en_rx(ioaddr);
}
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
static int eepro_poll(struct nic *nic)
{
int i;
unsigned int rcv_car = rx_start;
unsigned int rcv_event, rcv_status, rcv_next_frame, rcv_size;
/* return true if there's an ethernet packet ready to read */
/* nic->packet should contain data on return */
/* nic->packetlen should contain length of data */
#if 0
if ((inb(ioaddr + STATUS_REG) & 0x40) == 0)
return (0);
outb(0x40, ioaddr + STATUS_REG);
#endif
outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
rcv_event = inw(ioaddr + IO_PORT);
if (rcv_event != RCV_DONE)
return (0);
rcv_status = inw(ioaddr + IO_PORT);
rcv_next_frame = inw(ioaddr + IO_PORT);
rcv_size = inw(ioaddr + IO_PORT);
#if 0
printf("%hX %hX %d %hhX\n", rcv_status, rcv_next_frame, rcv_size,
inb(ioaddr + STATUS_REG));
#endif
if ((rcv_status & (RX_OK|RX_ERROR)) != RX_OK) {
printf("Receive error %hX\n", rcv_status);
return (0);
}
rcv_size &= 0x3FFF;
insw(ioaddr + IO_PORT, nic->packet, ((rcv_size + 3) >> 1));
#if 0
for (i = 0; i < 48; i++) {
printf("%hhX", nic->packet[i]);
putchar(i % 16 == 15 ? '\n' : ' ');
}
#endif
nic->packetlen = rcv_size;
rcv_car = rx_start + RCV_HEADER + rcv_size;
rx_start = rcv_next_frame;
if (rcv_car == 0)
rcv_car = ((RCV_UPPER_LIMIT << 8) | 0xff);
outw(rcv_car - 1, ioaddr + RCV_STOP);
return (1);
}
/**************************************************************************
TRANSMIT - Transmit a frame
***************************************************************************/
static void eepro_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
unsigned int status, tx_available, last, end, length;
unsigned short type;
int boguscount = 20;
length = s + ETH_HLEN;
if (tx_end > tx_start)
tx_available = XMT_RAM - (tx_end - tx_start);
else if (tx_end < tx_start)
tx_available = tx_start - tx_end;
else
tx_available = XMT_RAM;
last = tx_end;
end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
if (end >= (XMT_UPPER_LIMIT << 8)) {
last = (XMT_LOWER_LIMIT << 8);
end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
}
outw(last, ioaddr + HOST_ADDRESS_REG);
outw(XMT_CMD, ioaddr + IO_PORT);
outw(0, ioaddr + IO_PORT);
outw(end, ioaddr + IO_PORT);
outw(length, ioaddr + IO_PORT);
outsw(ioaddr + IO_PORT, d, ETH_ALEN / 2);
outsw(ioaddr + IO_PORT, nic->node_addr, ETH_ALEN / 2);
type = htons(t);
outsw(ioaddr + IO_PORT, &type, sizeof(type) / 2);
outsw(ioaddr + IO_PORT, p, (s + 3) >> 1);
/* A dummy read to flush the DRAM write pipeline */
status = inw(ioaddr + IO_PORT);
outw(last, ioaddr + xmt_bar);
outb(XMT_CMD, ioaddr);
tx_start = last;
tx_last = last;
tx_end = end;
#if 0
printf("%d %d\n", tx_start, tx_end);
#endif
while (boguscount > 0) {
if (((status = inw(ioaddr + IO_PORT)) & TX_DONE_BIT) == 0) {
udelay(40);
boguscount--;
continue;
}
#if DEBUG
if ((status & 0x2000) == 0)
printf("Transmit status %hX\n", status);
#endif
}
}
/**************************************************************************
DISABLE - Turn off ethernet interface
***************************************************************************/
static void eepro_disable(struct nic *nic)
{
eepro_sw2bank0(ioaddr); /* Switch to bank 0 */
/* Flush the Tx and disable Rx */
outb(STOP_RCV_CMD, ioaddr);
tx_start = tx_end = (XMT_LOWER_LIMIT << 8);
tx_last = 0;
/* Reset the 82595 */
eepro_full_reset(ioaddr);
}
static int read_eeprom(int location)
{
int i;
unsigned short retval = 0;
int ee_addr = ioaddr + eeprom_reg;
int read_cmd = location | EE_READ_CMD;
int ctrl_val = EECS;
if (eepro == LAN595FX_10ISA) {
eepro_sw2bank1(ioaddr);
outb(0x00, ioaddr + STATUS_REG);
}
eepro_sw2bank2(ioaddr);
outb(ctrl_val, ee_addr);
/* shift the read command bits out */
for (i = 8; i >= 0; i--) {
short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val;
outb(outval, ee_addr);
outb(outval | EESK, ee_addr); /* EEPROM clock tick */
eeprom_delay();
outb(outval, ee_addr); /* finish EEPROM clock tick */
eeprom_delay();
}
outb(ctrl_val, ee_addr);
for (i = 16; i > 0; i--) {
outb(ctrl_val | EESK, ee_addr);
eeprom_delay();
retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
outb(ctrl_val, ee_addr);
eeprom_delay();
}
/* terminate the EEPROM access */
ctrl_val &= ~EECS;
outb(ctrl_val | EESK, ee_addr);
eeprom_delay();
outb(ctrl_val, ee_addr);
eeprom_delay();
eepro_sw2bank0(ioaddr);
return (retval);
}
static int eepro_probe1(struct nic *nic)
{
int i, id, counter, l_eepro = 0;
union {
unsigned char caddr[ETH_ALEN];
unsigned short saddr[ETH_ALEN/2];
} station_addr;
char *name;
id = inb(ioaddr + ID_REG);
if ((id & ID_REG_MASK) != ID_REG_SIG)
return (0);
counter = id & R_ROBIN_BITS;
if (((id = inb(ioaddr + ID_REG)) & R_ROBIN_BITS) != (counter + 0x40))
return (0);
/* yes the 82595 has been found */
station_addr.saddr[2] = read_eeprom(2);
if (station_addr.saddr[2] == 0x0000 || station_addr.saddr[2] == 0xFFFF) {
l_eepro = 3;
eepro = LAN595FX_10ISA;
eeprom_reg= EEPROM_REG_10;
rcv_start = RCV_START_10;
xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
station_addr.saddr[2] = read_eeprom(2);
}
station_addr.saddr[1] = read_eeprom(3);
station_addr.saddr[0] = read_eeprom(4);
if (l_eepro)
name = "Intel EtherExpress 10 ISA";
else if (read_eeprom(7) == ee_FX_INT2IRQ) {
name = "Intel EtherExpress Pro/10+ ISA";
l_eepro = 2;
} else if (station_addr.saddr[0] == SA_ADDR1) {
name = "Intel EtherExpress Pro/10 ISA";
l_eepro = 1;
} else {
l_eepro = 0;
name = "Intel 82595-based LAN card";
}
station_addr.saddr[0] = swap16(station_addr.saddr[0]);
station_addr.saddr[1] = swap16(station_addr.saddr[1]);
station_addr.saddr[2] = swap16(station_addr.saddr[2]);
for (i = 0; i < ETH_ALEN; i++) {
nic->node_addr[i] = station_addr.caddr[i];
}
printf("\n%s ioaddr %#hX, addr %!", name, ioaddr, nic->node_addr);
mem_start = RCV_LOWER_LIMIT << 8;
if ((mem_end & 0x3F) < 3 || (mem_end & 0x3F) > 29)
mem_end = RCV_UPPER_LIMIT << 8;
else {
mem_end = mem_end * 1024 + (RCV_LOWER_LIMIT << 8);
rcv_ram = mem_end - (RCV_LOWER_LIMIT << 8);
}
printf(", Rx mem %dK, if %s\n", (mem_end - mem_start) >> 10,
GetBit(read_eeprom(5), ee_BNC_TPE) ? "BNC" : "TP");
return (1);
}
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
struct nic *eepro_probe(struct nic *nic, unsigned short *probe_addrs)
{
unsigned short *p;
/* same probe list as the Linux driver */
static unsigned short ioaddrs[] = {
0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
if (probe_addrs == 0 || probe_addrs[0] == 0)
probe_addrs = ioaddrs;
for (p = probe_addrs; (ioaddr = *p) != 0; p++) {
if (eepro_probe1(nic))
break;
}
if (*p == 0)
return (0);
eepro_reset(nic);
/* point to NIC specific routines */
nic->reset = eepro_reset;
nic->poll = eepro_poll;
nic->transmit = eepro_transmit;
nic->disable = eepro_disable;
return (nic);
}
+654
View File
@@ -0,0 +1,654 @@
/*
* eepro100.c -- This file implements the eepro100 driver for etherboot.
*
*
* Copyright (C) AW Computer Systems.
* written by R.E.Wolff -- R.E.Wolff@BitWizard.nl
*
*
* AW Computer Systems is contributing to the free software community
* by paying for this driver and then putting the result under GPL.
*
* If you need a Linux device driver, please contact BitWizard for a
* quote.
*
*
* 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, 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.
*
*
* date version by what
* Written: May 29 1997 V0.10 REW Initial revision.
* changes: May 31 1997 V0.90 REW Works!
* Jun 1 1997 V0.91 REW Cleanup
* Jun 2 1997 V0.92 REW Add some code documentation
* Jul 25 1997 V1.00 REW Tested by AW to work in a PROM
* Cleanup for publication
*
* This is the etherboot intel etherexpress Pro/100B driver.
*
* It was written from scratch, with Donald Beckers eepro100.c kernel
* driver as a guideline. Mostly the 82557 related definitions and the
* lower level routines have been cut-and-pasted into this source.
*
* The driver was finished before Intel got the NDA out of the closet.
* I still don't have the docs.
* */
/* Philosophy of this driver.
*
* Probing:
*
* Using the pci.c functions of the Etherboot code, the 82557 chip is detected.
* It is verified that the BIOS initialized everything properly and if
* something is missing it is done now.
*
*
* Initialization:
*
*
* The chip is then initialized to "know" its ethernet address, and to
* start recieving packets. The Linux driver has a whole transmit and
* recieve ring of buffers. This is neat if you need high performance:
* you can write the buffers asynchronously to the chip reading the
* buffers and transmitting them over the network. Performance is NOT
* an issue here. We can boot a 400k kernel in about two
* seconds. (Theory: 0.4 seconds). Booting a system is going to take
* about half a minute anyway, so getting 10 times closer to the
* theoretical limit is going to make a difference of a few percent.
*
*
* Transmitting and recieving.
*
* We have only one transmit descriptor. It has two buffer descriptors:
* one for the header, and the other for the data.
* We have only one receive buffer. The chip is told to recieve packets,
* and suspend itself once it got one. The recieve (poll) routine simply
* looks at the recieve buffer to see if there is already a packet there.
* if there is, the buffer is copied, and the reciever is restarted.
*
* Caveats:
*
* The etherboot framework moves the code to the 32k segment from
* 0x98000 to 0xa0000. There is just a little room between the end of
* this driver and the 0xa0000 address. If you compile in too many
* features, this will overflow.
* The number under "hex" in the output of size that scrolls by while
* compiling should be less than 8000. Maybe even the stack is up there,
* so that you need even more headroom.
*/
/* The etherboot authors seem to dislike the argument ordering in
* outb macros that Linux uses. I disklike the confusion that this
* has caused even more.... This file uses the Linux argument ordering. */
/* Sorry not us. It's inherted code from FreeBSD. [The authors] */
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "cards.h"
#include "timer.h"
#undef virt_to_bus
#define virt_to_bus(x) ((unsigned long)x)
static int ioaddr;
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
enum speedo_offsets {
SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */
SCBPointer = 4, /* General purpose pointer. */
SCBPort = 8, /* Misc. commands and operands. */
SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
SCBCtrlMDI = 16, /* MDI interface control. */
SCBEarlyRx = 20, /* Early receive byte count. */
};
static int do_eeprom_cmd(int cmd, int cmd_len);
void hd(void *where, int n);
/***********************************************************************/
/* I82557 related defines */
/***********************************************************************/
/* Serial EEPROM section.
A "bit" grungy, but we work our way through bit-by-bit :->. */
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
#define EE_CS 0x02 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
#define EE_WRITE_0 0x4802
#define EE_WRITE_1 0x4806
#define EE_ENB (0x4800 | EE_CS)
#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_READ_CMD 6
/* The SCB accepts the following controls for the Tx and Rx units: */
#define CU_START 0x0010
#define CU_RESUME 0x0020
#define CU_STATSADDR 0x0040
#define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */
#define CU_CMD_BASE 0x0060 /* Base address to add to add CU commands. */
#define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */
#define RX_START 0x0001
#define RX_RESUME 0x0002
#define RX_ABORT 0x0004
#define RX_ADDR_LOAD 0x0006
#define RX_RESUMENR 0x0007
#define INT_MASK 0x0100
#define DRVR_INT 0x0200 /* Driver generated interrupt. */
enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
S80C24, PhyUndefined, DP83840A=10, };
/* Commands that can be put in a command list entry. */
enum commands {
CmdNOp = 0,
CmdIASetup = 1,
CmdConfigure = 2,
CmdMulticastList = 3,
CmdTx = 4,
CmdTDR = 5,
CmdDump = 6,
CmdDiagnose = 7,
/* And some extra flags: */
CmdSuspend = 0x4000, /* Suspend after completion. */
CmdIntr = 0x2000, /* Interrupt after completion. */
CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */
};
/* How to wait for the command unit to accept a command.
Typically this takes 0 ticks. */
static inline void wait_for_cmd_done(int cmd_ioaddr)
{
short wait = 100;
do ;
while(inb(cmd_ioaddr) && --wait >= 0);
}
/* Elements of the dump_statistics block. This block must be lword aligned. */
static struct speedo_stats {
u32 tx_good_frames;
u32 tx_coll16_errs;
u32 tx_late_colls;
u32 tx_underruns;
u32 tx_lost_carrier;
u32 tx_deferred;
u32 tx_one_colls;
u32 tx_multi_colls;
u32 tx_total_colls;
u32 rx_good_frames;
u32 rx_crc_errs;
u32 rx_align_errs;
u32 rx_resource_errs;
u32 rx_overrun_errs;
u32 rx_colls_errs;
u32 rx_runt_errs;
u32 done_marker;
} lstats;
/* A speedo3 TX buffer descriptor with two buffers... */
static struct TxFD {
volatile s16 status;
s16 command;
u32 link; /* void * */
u32 tx_desc_addr; /* (almost) Always points to the tx_buf_addr element. */
s32 count; /* # of TBD (=2), Tx start thresh., etc. */
/* This constitutes two "TBD" entries: hdr and data */
u32 tx_buf_addr0; /* void *, header of frame to be transmitted. */
s32 tx_buf_size0; /* Length of Tx hdr. */
u32 tx_buf_addr1; /* void *, data to be transmitted. */
s32 tx_buf_size1; /* Length of Tx data. */
} txfd;
struct RxFD { /* Receive frame descriptor. */
volatile s16 status;
s16 command;
u32 link; /* struct RxFD * */
u32 rx_buf_addr; /* void * */
u16 count;
u16 size;
char packet[1518];
};
#ifdef USE_LOWMEM_BUFFER
#define rxfd ((struct RxFD *)(0x10000 - sizeof(struct RxFD)))
#define ACCESS(x) x->
#else
static struct RxFD rxfd;
#define ACCESS(x) x.
#endif
static int congenb = 0; /* Enable congestion control in the DP83840. */
static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
static int txdmacount = 0; /* Tx DMA burst length, 0-127, default 0. */
static int rxdmacount = 0; /* Rx DMA length, 0 means no preemption. */
/* I don't understand a byte in this structure. It was copied from the
* Linux kernel initialization for the eepro100. -- REW */
static struct ConfCmd {
s16 status;
s16 command;
u32 link;
unsigned char data[22];
} confcmd = {
0, CmdConfigure,
(u32) & txfd,
{22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
0, 0x2E, 0, 0x60, 0,
0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
0x3f, 0x05, }
};
/***********************************************************************/
/* Locally used functions */
/***********************************************************************/
/* Support function: mdio_write
*
* This probably writes to the "physical media interface chip".
* -- REW
*/
static int mdio_write(int phy_id, int location, int value)
{
int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */
outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
ioaddr + SCBCtrlMDI);
do {
udelay(16);
val = inl(ioaddr + SCBCtrlMDI);
if (--boguscnt < 0) {
printf(" mdio_write() timed out with val = %X.\n", val);
}
} while (! (val & 0x10000000));
return val & 0xffff;
}
/* Support function: mdio_read
*
* This probably reads a register in the "physical media interface chip".
* -- REW
*/
static int mdio_read(int phy_id, int location)
{
int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */
outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
do {
udelay(16);
val = inl(ioaddr + SCBCtrlMDI);
if (--boguscnt < 0) {
printf( " mdio_read() timed out with val = %X.\n", val);
}
} while (! (val & 0x10000000));
return val & 0xffff;
}
/* The fixes for the code were kindly provided by Dragan Stancevic
<visitor@valinux.com> to strictly follow Intel specifications of EEPROM
access timing.
The publicly available sheet 64486302 (sec. 3.1) specifies 1us access
interval for serial EEPROM. However, it looks like that there is an
additional requirement dictating larger udelay's in the code below.
2000/05/24 SAW */
static int do_eeprom_cmd(int cmd, int cmd_len)
{
unsigned retval = 0;
long ee_addr = ioaddr + SCBeeprom;
outw(EE_ENB, ee_addr); udelay(2);
outw(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2);
/* Shift the command bits out. */
do {
short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
outw(dataval, ee_addr); udelay(2);
outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2);
retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
} while (--cmd_len >= 0);
outw(EE_ENB, ee_addr); udelay(2);
/* Terminate the EEPROM access. */
outw(EE_ENB & ~EE_CS, ee_addr);
return retval;
}
static inline void whereami (const char *str)
{
#if 0
printf ("%s\n", str);
sleep (2);
#endif
}
/* function: eepro100_reset
* resets the card. This is used to allow Etherboot to probe the card again
* from a "virginal" state....
* Arguments: none
*
* returns: void.
*/
static void eepro100_reset(struct nic *nic)
{
outl(0, ioaddr + SCBPort);
}
/* function: eepro100_transmit
* This transmits a packet.
*
* Arguments: char d[6]: destination ethernet address.
* unsigned short t: ethernet protocol type.
* unsigned short s: size of the data-part of the packet.
* char *p: the data for the packet.
* returns: void.
*/
static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
{
struct eth_hdr {
unsigned char dst_addr[ETH_ALEN];
unsigned char src_addr[ETH_ALEN];
unsigned short type;
} hdr;
unsigned short status;
int to;
int s1, s2;
status = inw(ioaddr + SCBStatus);
/* Acknowledge all of the current interrupt sources ASAP. */
outw(status & 0xfc00, ioaddr + SCBStatus);
#ifdef DEBUG
printf ("transmitting type %hX packet (%d bytes). status = %hX, cmd=%hX\n",
t, s, status, inw (ioaddr + SCBCmd));
#endif
memcpy (&hdr.dst_addr, d, ETH_ALEN);
memcpy (&hdr.src_addr, nic->node_addr, ETH_ALEN);
hdr.type = htons (t);
txfd.status = 0;
txfd.command = CmdSuspend | CmdTx | CmdTxFlex;
txfd.link = virt_to_bus (&txfd);
txfd.count = 0x02208000;
txfd.tx_desc_addr = (u32)&txfd.tx_buf_addr0;
txfd.tx_buf_addr0 = virt_to_bus (&hdr);
txfd.tx_buf_size0 = sizeof (hdr);
txfd.tx_buf_addr1 = virt_to_bus (p);
txfd.tx_buf_size1 = s;
#ifdef DEBUG
printf ("txfd: \n");
hd (&txfd, sizeof (txfd));
#endif
outl(virt_to_bus(&txfd), ioaddr + SCBPointer);
outw(INT_MASK | CU_START, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
s1 = inw (ioaddr + SCBStatus);
load_timer2(10*TICKS_PER_MS); /* timeout 10 ms for transmit */
while (!txfd.status && timer2_running())
/* Wait */;
s2 = inw (ioaddr + SCBStatus);
#ifdef DEBUG
printf ("s1 = %hX, s2 = %hX.\n", s1, s2);
#endif
}
/* function: eepro100_poll / eth_poll
* This recieves a packet from the network.
*
* Arguments: none
*
* returns: 1 if a packet was recieved.
* 0 if no pacet was recieved.
* side effects:
* returns the packet in the array nic->packet.
* returns the length of the packet in nic->packetlen.
*/
static int eepro100_poll(struct nic *nic)
{
if (!ACCESS(rxfd)status)
return 0;
/* Ok. We got a packet. Now restart the reciever.... */
ACCESS(rxfd)status = 0;
ACCESS(rxfd)command = 0xc000;
outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer);
outw(INT_MASK | RX_START, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
#ifdef DEBUG
printf ("Got a packet: Len = %d.\n", ACCESS(rxfd)count & 0x3fff);
#endif
nic->packetlen = ACCESS(rxfd)count & 0x3fff;
memcpy (nic->packet, ACCESS(rxfd)packet, nic->packetlen);
#ifdef DEBUG
hd (nic->packet, 0x30);
#endif
return 1;
}
static void eepro100_disable(struct nic *nic)
{
/* See if this PartialReset solves the problem with interfering with
kernel operation after Etherboot hands over. - Ken 20001102 */
outl(2, ioaddr + SCBPort);
}
/* exported function: eepro100_probe / eth_probe
* initializes a card
*
* side effects:
* leaves the ioaddress of the 82557 chip in the variable ioaddr.
* leaves the 82557 initialized, and ready to recieve packets.
*/
struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *p)
{
unsigned short sum = 0;
int i;
int read_cmd, ee_size;
unsigned short value;
int options;
int promisc;
/* we cache only the first few words of the EEPROM data
be careful not to access beyond this array */
unsigned short eeprom[16];
if (probeaddrs == 0 || probeaddrs[0] == 0)
return 0;
ioaddr = probeaddrs[0] & ~3; /* Mask the bit that says "this is an io addr" */
adjust_pci_device(p);
if ((do_eeprom_cmd(EE_READ_CMD << 24, 27) & 0xffe0000)
== 0xffe0000) {
ee_size = 0x100;
read_cmd = EE_READ_CMD << 24;
} else {
ee_size = 0x40;
read_cmd = EE_READ_CMD << 22;
}
for (i = 0, sum = 0; i < ee_size; i++) {
unsigned short value = do_eeprom_cmd(read_cmd | (i << 16), 27);
if (i < (int)(sizeof(eeprom)/sizeof(eeprom[0])))
eeprom[i] = value;
sum += value;
}
for (i=0;i<ETH_ALEN;i++) {
nic->node_addr[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff;
}
printf ("Ethernet addr: %!\n", nic->node_addr);
if (sum != 0xBABA)
printf("eepro100: Invalid EEPROM checksum %#hX, "
"check settings before activating this device!\n", sum);
outl(0, ioaddr + SCBPort);
udelay (10000);
whereami ("Got eeprom.");
outl(virt_to_bus(&lstats), ioaddr + SCBPointer);
outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
whereami ("set stats addr.");
/* INIT RX stuff. */
/* Base = 0 */
outl(0, ioaddr + SCBPointer);
outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
whereami ("set rx base addr.");
ACCESS(rxfd)status = 0x0001;
ACCESS(rxfd)command = 0x0000;
ACCESS(rxfd)link = virt_to_bus(&(ACCESS(rxfd)status));
ACCESS(rxfd)rx_buf_addr = (int) &nic->packet;
ACCESS(rxfd)count = 0;
ACCESS(rxfd)size = 1528;
outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer);
outw(INT_MASK | RX_START, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
whereami ("started RX process.");
/* Start the reciever.... */
ACCESS(rxfd)status = 0;
ACCESS(rxfd)command = 0xc000;
outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer);
outw(INT_MASK | RX_START, ioaddr + SCBCmd);
/* INIT TX stuff. */
/* Base = 0 */
outl(0, ioaddr + SCBPointer);
outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
whereami ("set TX base addr.");
txfd.command = (CmdIASetup);
txfd.status = 0x0000;
txfd.link = virt_to_bus (&confcmd);
{
char *t = (char *)&txfd.tx_desc_addr;
for (i=0;i<ETH_ALEN;i++)
t[i] = nic->node_addr[i];
}
#ifdef DEBUG
printf ("Setup_eaddr:\n");
hd (&txfd, 0x20);
#endif
/* options = 0x40; */ /* 10mbps half duplex... */
options = 0x00; /* Autosense */
promisc = 0;
if ( ((eeprom[6]>>8) & 0x3f) == DP83840
|| ((eeprom[6]>>8) & 0x3f) == DP83840A) {
int mdi_reg23 = mdio_read(eeprom[6] & 0x1f, 23) | 0x0422;
if (congenb)
mdi_reg23 |= 0x0100;
printf(" DP83840 specific setup, setting register 23 to %hX.\n",
mdi_reg23);
mdio_write(eeprom[6] & 0x1f, 23, mdi_reg23);
}
whereami ("Done DP8340 special setup.");
if (options != 0) {
mdio_write(eeprom[6] & 0x1f, 0,
((options & 0x20) ? 0x2000 : 0) | /* 100mbps? */
((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */
whereami ("set mdio_register.");
}
confcmd.command = CmdSuspend | CmdConfigure;
confcmd.status = 0x0000;
confcmd.link = virt_to_bus (&txfd);
confcmd.data[1] = (txfifo << 4) | rxfifo;
confcmd.data[4] = rxdmacount;
confcmd.data[5] = txdmacount + 0x80;
confcmd.data[15] = promisc ? 0x49: 0x48;
confcmd.data[19] = (options & 0x10) ? 0xC0 : 0x80;
confcmd.data[21] = promisc ? 0x0D: 0x05;
outl(virt_to_bus(&txfd), ioaddr + SCBPointer);
outw(INT_MASK | CU_START, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
whereami ("started TX thingy (config, iasetup).");
load_timer2(10*TICKS_PER_MS);
while (!txfd.status && timer2_running())
/* Wait */;
nic->reset = eepro100_reset;
nic->poll = eepro100_poll;
nic->transmit = eepro100_transmit;
nic->disable = eepro100_disable;
return nic;
}
/*********************************************************************/
#ifdef DEBUG
/* Hexdump a number of bytes from memory... */
void hd (void *where, int n)
{
int i;
while (n > 0) {
printf ("%X ", where);
for (i=0;i < ( (n>16)?16:n);i++)
printf (" %hhX", ((char *)where)[i]);
printf ("\n");
n -= 16;
where += 16;
}
}
#endif
+481
View File
@@ -0,0 +1,481 @@
/* epic100.c: A SMC 83c170 EPIC/100 fast ethernet driver for Etherboot */
#define LINUX_OUT_MACROS
#include "etherboot.h"
#include "nic.h"
#include "cards.h"
#include "timer.h"
#include "epic100.h"
#undef virt_to_bus
#define virt_to_bus(x) ((unsigned long)x)
#define TX_RING_SIZE 2 /* use at least 2 buffers for TX */
#define RX_RING_SIZE 2
#define PKT_BUF_SZ 1536 /* Size of each temporary Tx/Rx buffer.*/
/*
#define DEBUG_RX
#define DEBUG_TX
#define DEBUG_EEPROM
*/
#define EPIC_DEBUG 0 /* debug level */
/* The EPIC100 Rx and Tx buffer descriptors. */
struct epic_rx_desc {
unsigned short status;
unsigned short rxlength;
unsigned long bufaddr;
unsigned short buflength;
unsigned short control;
unsigned long next;
};
/* description of the tx descriptors control bits commonly used */
#define TD_STDFLAGS TD_LASTDESC
struct epic_tx_desc {
unsigned short status;
unsigned short txlength;
unsigned long bufaddr;
unsigned short buflength;
unsigned short control;
unsigned long next;
};
#define delay(nanosec) do { int _i = 3; while (--_i > 0) \
{ __SLOW_DOWN_IO; }} while (0)
static void epic100_open(void);
static void epic100_init_ring(void);
static void epic100_disable(struct nic *nic);
static int epic100_poll(struct nic *nic);
static void epic100_transmit(struct nic *nic, const char *destaddr,
unsigned int type, unsigned int len, const char *data);
static int read_eeprom(int location);
static int mii_read(int phy_id, int location);
static int ioaddr;
static int command;
static int intstat;
static int intmask;
static int genctl ;
static int eectl ;
static int test ;
static int mmctl ;
static int mmdata ;
static int lan0 ;
static int rxcon ;
static int txcon ;
static int prcdar ;
static int ptcdar ;
static int eththr ;
static unsigned int cur_rx, cur_tx; /* The next free ring entry */
#ifdef DEBUG_EEPROM
static unsigned short eeprom[64];
#endif
static signed char phys[4]; /* MII device addresses. */
static struct epic_rx_desc rx_ring[RX_RING_SIZE];
static struct epic_tx_desc tx_ring[TX_RING_SIZE];
#ifdef USE_LOWMEM_BUFFER
#define rx_packet ((char *)0x10000 - PKT_BUF_SZ * RX_RING_SIZE)
#define tx_packet ((char *)0x10000 - PKT_BUF_SZ * RX_RING_SIZE - PKT_BUF_SZ * TX_RING_SIZE)
#else
static char rx_packet[PKT_BUF_SZ * RX_RING_SIZE];
static char tx_packet[PKT_BUF_SZ * TX_RING_SIZE];
#endif
/***********************************************************************/
/* Externally visible functions */
/***********************************************************************/
static void
epic100_reset(struct nic *nic)
{
/* Soft reset the chip. */
outl(GC_SOFT_RESET, genctl);
}
struct nic*
epic100_probe(struct nic *nic, unsigned short *probeaddrs)
{
unsigned short sum = 0;
unsigned short value;
int i;
unsigned short* ap;
unsigned int phy, phy_idx;
if (probeaddrs == 0 || probeaddrs[0] == 0)
return 0;
/* Ideally we would detect all network cards in slot order. That would
be best done a central PCI probe dispatch, which wouldn't work
well with the current structure. So instead we detect just the
Epic cards in slot order. */
ioaddr = probeaddrs[0] & ~3; /* Mask the bit that says "this is an io addr" */
/* compute all used static epic100 registers address */
command = ioaddr + COMMAND; /* Control Register */
intstat = ioaddr + INTSTAT; /* Interrupt Status */
intmask = ioaddr + INTMASK; /* Interrupt Mask */
genctl = ioaddr + GENCTL; /* General Control */
eectl = ioaddr + EECTL; /* EEPROM Control */
test = ioaddr + TEST; /* Test register (clocks) */
mmctl = ioaddr + MMCTL; /* MII Management Interface Control */
mmdata = ioaddr + MMDATA; /* MII Management Interface Data */
lan0 = ioaddr + LAN0; /* MAC address. (0x40-0x48) */
rxcon = ioaddr + RXCON; /* Receive Control */
txcon = ioaddr + TXCON; /* Transmit Control */
prcdar = ioaddr + PRCDAR; /* PCI Receive Current Descr Address */
ptcdar = ioaddr + PTCDAR; /* PCI Transmit Current Descr Address */
eththr = ioaddr + ETHTHR; /* Early Transmit Threshold */
/* Reset the chip & bring it out of low-power mode. */
outl(GC_SOFT_RESET, genctl);
/* Disable ALL interrupts by setting the interrupt mask. */
outl(INTR_DISABLE, intmask);
/*
* set the internal clocks:
* Application Note 7.15 says:
* In order to set the CLOCK TEST bit in the TEST register,
* perform the following:
*
* Write 0x0008 to the test register at least sixteen
* consecutive times.
*
* The CLOCK TEST bit is Write-Only. Writing it several times
* consecutively insures a successful write to the bit...
*/
for (i = 0; i < 16; i++) {
outl(0x00000008, test);
}
#ifdef DEBUG_EEPROM
for (i = 0; i < 64; i++) {
value = read_eeprom(i);
eeprom[i] = value;
sum += value;
}
#if (EPIC_DEBUG > 1)
printf("EEPROM contents\n");
for (i = 0; i < 64; i++) {
printf(" %hhX%s", eeprom[i], i % 16 == 15 ? "\n" : "");
}
#endif
#endif
/* This could also be read from the EEPROM. */
ap = (unsigned short*)nic->node_addr;
for (i = 0; i < 3; i++)
*ap++ = inw(lan0 + i*4);
printf(" I/O %#hX %! ", ioaddr, nic->node_addr);
/* Find the connected MII xcvrs. */
for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(phys); phy++) {
int mii_status = mii_read(phy, 0);
if (mii_status != 0xffff && mii_status != 0x0000) {
phys[phy_idx++] = phy;
#if (EPIC_DEBUG > 1)
printf("MII transceiver found at address %d.\n", phy);
#endif
}
}
if (phy_idx == 0) {
#if (EPIC_DEBUG > 1)
printf("***WARNING***: No MII transceiver found!\n");
#endif
/* Use the known PHY address of the EPII. */
phys[0] = 3;
}
epic100_open();
nic->reset = epic100_reset;
nic->poll = epic100_poll;
nic->transmit = epic100_transmit;
nic->disable = epic100_disable;
return nic;
}
static void
epic100_open(void)
{
int mii_reg5;
int full_duplex = 0;
unsigned long tmp;
epic100_init_ring();
/* Pull the chip out of low-power mode, and set for PCI read multiple. */
outl(GC_RX_FIFO_THR_64 | GC_MRC_READ_MULT | GC_ONE_COPY, genctl);
outl(TX_FIFO_THRESH, eththr);
tmp = TC_EARLY_TX_ENABLE | TX_SLOT_TIME;
mii_reg5 = mii_read(phys[0], 5);
if (mii_reg5 != 0xffff && (mii_reg5 & 0x0100)) {
full_duplex = 1;
printf(" full-duplex mode");
tmp |= TC_LM_FULL_DPX;
} else
tmp |= TC_LM_NORMAL;
outl(tmp, txcon);
/* Give adress of RX and TX ring to the chip */
outl(virt_to_bus(&rx_ring), prcdar);
outl(virt_to_bus(&tx_ring), ptcdar);
/* Start the chip's Rx process: receive unicast and broadcast */
outl(0x04, rxcon);
outl(CR_START_RX | CR_QUEUE_RX, command);
putchar('\n');
}
/* Initialize the Rx and Tx rings. */
static void
epic100_init_ring(void)
{
int i;
char* p;
cur_rx = cur_tx = 0;
p = &rx_packet[0];
for (i = 0; i < RX_RING_SIZE; i++) {
rx_ring[i].status = RRING_OWN; /* Owned by Epic chip */
rx_ring[i].buflength = PKT_BUF_SZ;
rx_ring[i].bufaddr = virt_to_bus(p + (PKT_BUF_SZ * i));
rx_ring[i].control = 0;
rx_ring[i].next = virt_to_bus(&(rx_ring[i + 1]) );
}
/* Mark the last entry as wrapping the ring. */
rx_ring[i-1].next = virt_to_bus(&rx_ring[0]);
/*
*The Tx buffer descriptor is filled in as needed,
* but we do need to clear the ownership bit.
*/
p = &tx_packet[0];
for (i = 0; i < TX_RING_SIZE; i++) {
tx_ring[i].status = 0; /* Owned by CPU */
tx_ring[i].bufaddr = virt_to_bus(p + (PKT_BUF_SZ * i));
tx_ring[i].control = TD_STDFLAGS;
tx_ring[i].next = virt_to_bus(&(tx_ring[i + 1]) );
}
tx_ring[i-1].next = virt_to_bus(&tx_ring[0]);
}
/* function: epic100_transmit
* This transmits a packet.
*
* Arguments: char d[6]: destination ethernet address.
* unsigned short t: ethernet protocol type.
* unsigned short s: size of the data-part of the packet.
* char *p: the data for the packet.
* returns: void.
*/
static void
epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
unsigned int len, const char *data)
{
unsigned short nstype;
char* txp;
int entry;
/* Calculate the next Tx descriptor entry. */
entry = cur_tx % TX_RING_SIZE;
if ((tx_ring[entry].status & TRING_OWN) == TRING_OWN) {
printf("eth_transmit: Unable to transmit. status=%hX. Resetting...\n",
tx_ring[entry].status);
epic100_open();
return;
}
txp = (char*)tx_ring[entry].bufaddr;
memcpy(txp, destaddr, ETH_ALEN);
memcpy(txp + ETH_ALEN, nic->node_addr, ETH_ALEN);
nstype = htons(type);
memcpy(txp + 12, (char*)&nstype, 2);
memcpy(txp + ETH_HLEN, data, len);
len += ETH_HLEN;
/*
* Caution: the write order is important here,
* set the base address with the "ownership"
* bits last.
*/
tx_ring[entry].txlength = (len >= 60 ? len : 60);
tx_ring[entry].buflength = len;
tx_ring[entry].status = TRING_OWN; /* Pass ownership to the chip. */
cur_tx++;
/* Trigger an immediate transmit demand. */
outl(CR_QUEUE_TX, command);
load_timer2(10*TICKS_PER_MS); /* timeout 10 ms for transmit */
while ((tx_ring[entry].status & TRING_OWN) && timer2_running())
/* Wait */;
if ((tx_ring[entry].status & TRING_OWN) != 0)
printf("Oops, transmitter timeout, status=%hX\n",
tx_ring[entry].status);
}
/* function: epic100_poll / eth_poll
* This receives a packet from the network.
*
* Arguments: none
*
* returns: 1 if a packet was received.
* 0 if no pacet was received.
* side effects:
* returns the packet in the array nic->packet.
* returns the length of the packet in nic->packetlen.
*/
static int
epic100_poll(struct nic *nic)
{
int entry;
int status;
int retcode;
entry = cur_rx % RX_RING_SIZE;
if ((status = rx_ring[entry].status & RRING_OWN) == RRING_OWN)
return (0);
/* We own the next entry, it's a new packet. Send it up. */
#if (EPIC_DEBUG > 4)
printf("epic_poll: entry %d status %hX\n", entry, status);
#endif
cur_rx++;
if (status & 0x2000) {
printf("epic_poll: Giant packet\n");
retcode = 0;
} else if (status & 0x0006) {
/* Rx Frame errors are counted in hardware. */
printf("epic_poll: Frame received with errors\n");
retcode = 0;
} else {
/* Omit the four octet CRC from the length. */
nic->packetlen = rx_ring[entry].rxlength - 4;
memcpy(nic->packet, (char*)rx_ring[entry].bufaddr, nic->packetlen);
retcode = 1;
}
/* Clear all error sources. */
outl(status & INTR_CLEARERRS, intstat);
/* Give the descriptor back to the chip */
rx_ring[entry].status = RRING_OWN;
/* Restart Receiver */
outl(CR_START_RX | CR_QUEUE_RX, command);
return retcode;
}
static void
epic100_disable(struct nic *nic)
{
}
#ifdef DEBUG_EEPROM
/* Serial EEPROM section. */
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
#define EE_CS 0x02 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x08 /* EEPROM chip data in. */
#define EE_WRITE_0 0x01
#define EE_WRITE_1 0x09
#define EE_DATA_READ 0x10 /* EEPROM chip data out. */
#define EE_ENB (0x0001 | EE_CS)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
#define EE_READ_CMD (6 << 6)
#define EE_ERASE_CMD (7 << 6)
#define eeprom_delay(n) delay(n)
static int
read_eeprom(int location)
{
int i;
int retval = 0;
int read_cmd = location | EE_READ_CMD;
outl(EE_ENB & ~EE_CS, eectl);
outl(EE_ENB, eectl);
/* Shift the read command bits out. */
for (i = 10; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outl(EE_ENB | dataval, eectl);
eeprom_delay(100);
outl(EE_ENB | dataval | EE_SHIFT_CLK, eectl);
eeprom_delay(150);
outl(EE_ENB | dataval, eectl); /* Finish EEPROM a clock tick. */
eeprom_delay(250);
}
outl(EE_ENB, eectl);
for (i = 16; i > 0; i--) {
outl(EE_ENB | EE_SHIFT_CLK, eectl);
eeprom_delay(100);
retval = (retval << 1) | ((inl(eectl) & EE_DATA_READ) ? 1 : 0);
outl(EE_ENB, eectl);
eeprom_delay(100);
}
/* Terminate the EEPROM access. */
outl(EE_ENB & ~EE_CS, eectl);
return retval;
}
#endif
#define MII_READOP 1
#define MII_WRITEOP 2
static int
mii_read(int phy_id, int location)
{
int i;
outl((phy_id << 9) | (location << 4) | MII_READOP, mmctl);
/* Typical operation takes < 50 ticks. */
for (i = 4000; i > 0; i--)
if ((inl(mmctl) & MII_READOP) == 0)
break;
return inw(mmdata);
}
+188
View File
@@ -0,0 +1,188 @@
#ifndef _EPIC100_H_
# define _EPIC100_H_
#ifndef PCI_VENDOR_SMC
# define PCI_VENDOR_SMC 0x10B8
#endif
#ifndef PCI_DEVICE_SMC_EPIC100
# define PCI_DEVICE_SMC_EPIC100 0x0005
#endif
#define PCI_DEVICE_ID_NONE 0xFFFF
/* Offsets to registers (using SMC names). */
enum epic100_registers {
COMMAND= 0, /* Control Register */
INTSTAT= 4, /* Interrupt Status */
INTMASK= 8, /* Interrupt Mask */
GENCTL = 0x0C, /* General Control */
NVCTL = 0x10, /* Non Volatile Control */
EECTL = 0x14, /* EEPROM Control */
TEST = 0x1C, /* Test register: marked as reserved (see in source code) */
CRCCNT = 0x20, /* CRC Error Counter */
ALICNT = 0x24, /* Frame Alignment Error Counter */
MPCNT = 0x28, /* Missed Packet Counter */
MMCTL = 0x30, /* MII Management Interface Control */
MMDATA = 0x34, /* MII Management Interface Data */
MIICFG = 0x38, /* MII Configuration */
IPG = 0x3C, /* InterPacket Gap */
LAN0 = 0x40, /* MAC address. (0x40-0x48) */
IDCHK = 0x4C, /* BoardID/ Checksum */
MC0 = 0x50, /* Multicast filter table. (0x50-0x5c) */
RXCON = 0x60, /* Receive Control */
TXCON = 0x70, /* Transmit Control */
TXSTAT = 0x74, /* Transmit Status */
PRCDAR = 0x84, /* PCI Receive Current Descriptor Address */
PRSTAT = 0xA4, /* PCI Receive DMA Status */
PRCPTHR= 0xB0, /* PCI Receive Copy Threshold */
PTCDAR = 0xC4, /* PCI Transmit Current Descriptor Address */
ETHTHR = 0xDC /* Early Transmit Threshold */
};
/* Command register (CR_) bits */
#define CR_STOP_RX (0x00000001)
#define CR_START_RX (0x00000002)
#define CR_QUEUE_TX (0x00000004)
#define CR_QUEUE_RX (0x00000008)
#define CR_NEXTFRAME (0x00000010)
#define CR_STOP_TX_DMA (0x00000020)
#define CR_STOP_RX_DMA (0x00000040)
#define CR_TX_UGO (0x00000080)
/* Interrupt register bits. NI means No Interrupt generated */
#define INTR_RX_THR_STA (0x00400000) /* rx copy threshold status NI */
#define INTR_RX_BUFF_EMPTY (0x00200000) /* rx buffers empty. NI */
#define INTR_TX_IN_PROG (0x00100000) /* tx copy in progess. NI */
#define INTR_RX_IN_PROG (0x00080000) /* rx copy in progress. NI */
#define INTR_TXIDLE (0x00040000) /* tx idle. NI */
#define INTR_RXIDLE (0x00020000) /* rx idle. NI */
#define INTR_INTR_ACTIVE (0x00010000) /* Interrupt active. NI */
#define INTR_RX_STATUS_OK (0x00008000) /* rx status valid. NI */
#define INTR_PCI_TGT_ABT (0x00004000) /* PCI Target abort */
#define INTR_PCI_MASTER_ABT (0x00002000) /* PCI Master abort */
#define INTR_PCI_PARITY_ERR (0x00001000) /* PCI adress parity error */
#define INTR_PCI_DATA_ERR (0x00000800) /* PCI data parity error */
#define INTR_RX_THR_CROSSED (0x00000400) /* rx copy threshold crossed */
#define INTR_CNTFULL (0x00000200) /* Counter overflow */
#define INTR_TXUNDERRUN (0x00000100) /* tx underrun. */
#define INTR_TXEMPTY (0x00000080) /* tx queue empty */
#define INTR_TX_CH_COMPLETE (0x00000040) /* tx chain complete */
#define INTR_TXDONE (0x00000020) /* tx complete (w or w/o err) */
#define INTR_RXERROR (0x00000010) /* rx error (CRC) */
#define INTR_RXOVERFLOW (0x00000008) /* rx buffer overflow */
#define INTR_RX_QUEUE_EMPTY (0x00000004) /* rx queue empty. */
#define INTR_RXHEADER (0x00000002) /* header copy complete */
#define INTR_RXDONE (0x00000001) /* Receive copy complete */
#define INTR_CLEARINTR (0x00007FFF)
#define INTR_VALIDBITS (0x007FFFFF)
#define INTR_DISABLE (0x00000000)
#define INTR_CLEARERRS (0x00007F18)
#define INTR_ABNINTR (INTR_CNTFULL | INTR_TXUNDERRUN | INTR_RXOVERFLOW)
/* General Control (GC_) bits */
#define GC_SOFT_RESET (0x00000001)
#define GC_INTR_ENABLE (0x00000002)
#define GC_SOFT_INTR (0x00000004)
#define GC_POWER_DOWN (0x00000008)
#define GC_ONE_COPY (0x00000010)
#define GC_BIG_ENDIAN (0x00000020)
#define GC_RX_PREEMPT_TX (0x00000040)
#define GC_TX_PREEMPT_RX (0x00000080)
/*
* Receive FIFO Threshold values
* Control the level at which the PCI burst state machine
* begins to empty the receive FIFO. Possible values: 0-3
*
* 0 => 32, 1 => 64, 2 => 96 3 => 128 bytes.
*/
#define GC_RX_FIFO_THR_32 (0x00000000)
#define GC_RX_FIFO_THR_64 (0x00000100)
#define GC_RX_FIFO_THR_96 (0x00000200)
#define GC_RX_FIFO_THR_128 (0x00000300)
/* Memory Read Control (MRC_) values */
#define GC_MRC_MEM_READ (0x00000000)
#define GC_MRC_READ_MULT (0x00000400)
#define GC_MRC_READ_LINE (0x00000800)
#define GC_SOFTBIT0 (0x00001000)
#define GC_SOFTBIT1 (0x00002000)
#define GC_RESET_PHY (0x00004000)
/* Definitions of the Receive Control (RC_) register bits */
#define RC_SAVE_ERRORED_PKT (0x00000001)
#define RC_SAVE_RUNT_FRAMES (0x00000002)
#define RC_RCV_BROADCAST (0x00000004)
#define RC_RCV_MULTICAST (0x00000008)
#define RC_RCV_INVERSE_PKT (0x00000010)
#define RC_PROMISCUOUS_MODE (0x00000020)
#define RC_MONITOR_MODE (0x00000040)
#define RC_EARLY_RCV_ENABLE (0x00000080)
/* description of the rx descriptors control bits */
#define RD_FRAGLIST (0x0001) /* Desc points to a fragment list */
#define RD_LLFORM (0x0002) /* Frag list format */
#define RD_HDR_CPY (0x0004) /* Desc used for header copy */
/* Definition of the Transmit CONTROL (TC) register bits */
#define TC_EARLY_TX_ENABLE (0x00000001)
/* Loopback Mode (LM_) Select valuesbits */
#define TC_LM_NORMAL (0x00000000)
#define TC_LM_INTERNAL (0x00000002)
#define TC_LM_EXTERNAL (0x00000004)
#define TC_LM_FULL_DPX (0x00000006)
#define TX_SLOT_TIME (0x00000078)
/* Bytes transferred to chip before transmission starts. */
#define TX_FIFO_THRESH 128 /* Rounded down to 4 byte units. */
/* description of rx descriptors status bits */
#define RRING_PKT_INTACT (0x0001)
#define RRING_ALIGN_ERR (0x0002)
#define RRING_CRC_ERR (0x0004)
#define RRING_MISSED_PKT (0x0008)
#define RRING_MULTICAST (0x0010)
#define RRING_BROADCAST (0x0020)
#define RRING_RECEIVER_DISABLE (0x0040)
#define RRING_STATUS_VALID (0x1000)
#define RRING_FRAGLIST_ERR (0x2000)
#define RRING_HDR_COPIED (0x4000)
#define RRING_OWN (0x8000)
/* error summary */
#define RRING_ERROR (RRING_ALIGN_ERR|RRING_CRC_ERR)
/* description of tx descriptors status bits */
#define TRING_PKT_INTACT (0x0001) /* pkt transmitted. */
#define TRING_PKT_NONDEFER (0x0002) /* pkt xmitted w/o deferring */
#define TRING_COLL (0x0004) /* pkt xmitted w collisions */
#define TRING_CARR (0x0008) /* carrier sense lost */
#define TRING_UNDERRUN (0x0010) /* DMA underrun */
#define TRING_HB_COLL (0x0020) /* Collision detect Heartbeat */
#define TRING_WIN_COLL (0x0040) /* out of window collision */
#define TRING_DEFERRED (0x0080) /* Deferring */
#define TRING_COLL_COUNT (0x0F00) /* collision counter (mask) */
#define TRING_COLL_EXCESS (0x1000) /* tx aborted: excessive colls */
#define TRING_OWN (0x8000) /* desc ownership bit */
/* error summary */
#define TRING_ABORT (TRING_COLL_EXCESS|TRING_WIN_COLL|TRING_UNDERRUN)
#define TRING_ERROR (TRING_DEFERRED|TRING_WIN_COLL|TRING_UNDERRUN|TRING_CARR/*|TRING_COLL*/ )
/* description of the tx descriptors control bits */
#define TD_FRAGLIST (0x0001) /* Desc points to a fragment list */
#define TD_LLFORM (0x0002) /* Frag list format */
#define TD_IAF (0x0004) /* Generate Interrupt after tx */
#define TD_NOCRC (0x0008) /* No CRC generated */
#define TD_LASTDESC (0x0010) /* Last desc for this frame */
#endif /* _EPIC100_H_ */
+544
View File
@@ -0,0 +1,544 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
*
* 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.
*/
/* RULE: You must define the macro ``GRUB'' when including this header
file in GRUB code. */
/* Based on "src/etherboot.h" in etherboot-5.0.5. */
/**************************************************************************
ETHERBOOT - BOOTP/TFTP Bootstrap Program
Author: Martin Renters
Date: Dec/93
**************************************************************************/
/* Include GRUB-specific macros and prototypes here. */
#include <shared.h>
/* FIXME: For now, enable the DHCP support. Perhaps I should segregate
the DHCP support from the BOOTP support, and permit both to
co-exist. */
#undef NO_DHCP_SUPPORT
/* In GRUB, the relocated address in Etherboot doesn't have any sense.
Just define it as a bogus value. */
#define RELOC 0
/* FIXME: Should be an option. */
#define BACKOFF_LIMIT 7
#include <osdep.h>
#define CTRL_C 3
#ifndef MAX_TFTP_RETRIES
# define MAX_TFTP_RETRIES 20
#endif
#ifndef MAX_BOOTP_RETRIES
# define MAX_BOOTP_RETRIES 20
#endif
#define MAX_BOOTP_EXTLEN (ETH_FRAME_LEN - ETH_HLEN - \
sizeof (struct bootp_t))
#ifndef MAX_ARP_RETRIES
# define MAX_ARP_RETRIES 20
#endif
#ifndef MAX_RPC_RETRIES
# define MAX_RPC_RETRIES 20
#endif
#define TICKS_PER_SEC 18
/* Inter-packet retry in ticks */
#define TIMEOUT (10 * TICKS_PER_SEC)
/* These settings have sense only if compiled with -DCONGESTED */
/* total retransmission timeout in ticks */
#define TFTP_TIMEOUT (30 * TICKS_PER_SEC)
/* packet retransmission timeout in ticks */
#define TFTP_REXMT (3 * TICKS_PER_SEC)
#ifndef NULL
# define NULL ((void *) 0)
#endif
/*
I'm moving towards the defined names in linux/if_ether.h for clarity.
The confusion between 60/64 and 1514/1518 arose because the NS8390
counts the 4 byte frame checksum in the incoming packet, but not
in the outgoing packet. 60/1514 are the correct numbers for most
if not all of the other NIC controllers. I will be retiring the
64/1518 defines in the lead-up to 5.0.
*/
#define ETH_ALEN 6 /* Size of Ethernet address */
#define ETH_HLEN 14 /* Size of ethernet header */
#define ETH_ZLEN 60 /* Minimum packet */
/*#define ETH_MIN_PACKET 64*/
#define ETH_FRAME_LEN 1514 /* Maximum packet */
/*#define ETH_MAX_PACKET 1518*/
/* Because some DHCP/BOOTP servers don't treat the maximum length the same
as Etherboot, subtract the size of an IP header and that of an UDP
header. */
#define ETH_MAX_MTU (ETH_FRAME_LEN - ETH_HLEN \
- sizeof (struct iphdr) \
- sizeof (struct udphdr))
#define ARP_CLIENT 0
#define ARP_SERVER 1
#define ARP_GATEWAY 2
#define ARP_ROOTSERVER 3
#define ARP_SWAPSERVER 4
#define MAX_ARP ARP_SWAPSERVER+1
#define RARP_REQUEST 3
#define RARP_REPLY 4
#define IP 0x0800
#define ARP 0x0806
#define RARP 0x8035
#define BOOTP_SERVER 67
#define BOOTP_CLIENT 68
#define TFTP_PORT 69
#define SUNRPC_PORT 111
#define IP_UDP 17
/* Same after going through htonl */
#define IP_BROADCAST 0xFFFFFFFF
#define ARP_REQUEST 1
#define ARP_REPLY 2
#define BOOTP_REQUEST 1
#define BOOTP_REPLY 2
#define TAG_LEN(p) (*((p) + 1))
#define RFC1533_COOKIE 99, 130, 83, 99
#define RFC1533_PAD 0
#define RFC1533_NETMASK 1
#define RFC1533_TIMEOFFSET 2
#define RFC1533_GATEWAY 3
#define RFC1533_TIMESERVER 4
#define RFC1533_IEN116NS 5
#define RFC1533_DNS 6
#define RFC1533_LOGSERVER 7
#define RFC1533_COOKIESERVER 8
#define RFC1533_LPRSERVER 9
#define RFC1533_IMPRESSSERVER 10
#define RFC1533_RESOURCESERVER 11
#define RFC1533_HOSTNAME 12
#define RFC1533_BOOTFILESIZE 13
#define RFC1533_MERITDUMPFILE 14
#define RFC1533_DOMAINNAME 15
#define RFC1533_SWAPSERVER 16
#define RFC1533_ROOTPATH 17
#define RFC1533_EXTENSIONPATH 18
#define RFC1533_IPFORWARDING 19
#define RFC1533_IPSOURCEROUTING 20
#define RFC1533_IPPOLICYFILTER 21
#define RFC1533_IPMAXREASSEMBLY 22
#define RFC1533_IPTTL 23
#define RFC1533_IPMTU 24
#define RFC1533_IPMTUPLATEAU 25
#define RFC1533_INTMTU 26
#define RFC1533_INTLOCALSUBNETS 27
#define RFC1533_INTBROADCAST 28
#define RFC1533_INTICMPDISCOVER 29
#define RFC1533_INTICMPRESPOND 30
#define RFC1533_INTROUTEDISCOVER 31
#define RFC1533_INTROUTESOLICIT 32
#define RFC1533_INTSTATICROUTES 33
#define RFC1533_LLTRAILERENCAP 34
#define RFC1533_LLARPCACHETMO 35
#define RFC1533_LLETHERNETENCAP 36
#define RFC1533_TCPTTL 37
#define RFC1533_TCPKEEPALIVETMO 38
#define RFC1533_TCPKEEPALIVEGB 39
#define RFC1533_NISDOMAIN 40
#define RFC1533_NISSERVER 41
#define RFC1533_NTPSERVER 42
#define RFC1533_VENDOR 43
#define RFC1533_NBNS 44
#define RFC1533_NBDD 45
#define RFC1533_NBNT 46
#define RFC1533_NBSCOPE 47
#define RFC1533_XFS 48
#define RFC1533_XDM 49
#ifndef NO_DHCP_SUPPORT
#define RFC2132_REQ_ADDR 50
#define RFC2132_MSG_TYPE 53
#define RFC2132_SRV_ID 54
#define RFC2132_PARAM_LIST 55
#define RFC2132_MAX_SIZE 57
#define RFC2132_VENDOR_CLASS_ID 60
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPACK 5
#endif /* NO_DHCP_SUPPORT */
#define RFC1533_VENDOR_MAJOR 0
#define RFC1533_VENDOR_MINOR 0
#define RFC1533_VENDOR_MAGIC 128
#define RFC1533_VENDOR_ADDPARM 129
#define RFC1533_VENDOR_MNUOPTS 160
#define RFC1533_VENDOR_SELECTION 176
#define RFC1533_VENDOR_MOTD 184
#define RFC1533_VENDOR_NUMOFMOTD 8
#define RFC1533_VENDOR_IMG 192
#define RFC1533_VENDOR_NUMOFIMG 16
#define RFC1533_VENDOR_CONFIGFILE 150
#define RFC1533_END 255
#define BOOTP_VENDOR_LEN 64
#ifndef NO_DHCP_SUPPORT
#define DHCP_OPT_LEN 312
#endif /* NO_DHCP_SUPPORT */
#define TFTP_DEFAULTSIZE_PACKET 512
#define TFTP_MAX_PACKET 1432 /* 512 */
#define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
#define TFTP_OACK 6
#define TFTP_CODE_EOF 1
#define TFTP_CODE_MORE 2
#define TFTP_CODE_ERROR 3
#define TFTP_CODE_BOOT 4
#define TFTP_CODE_CFG 5
#define AWAIT_ARP 0
#define AWAIT_BOOTP 1
#define AWAIT_TFTP 2
#define AWAIT_RARP 3
#define AWAIT_RPC 4
#define AWAIT_QDRAIN 5 /* drain queue, process ARP requests */
typedef struct
{
unsigned long s_addr;
}
in_addr;
struct arptable_t
{
in_addr ipaddr;
unsigned char node[6];
};
/*
* A pity sipaddr and tipaddr are not longword aligned or we could use
* in_addr. No, I don't want to use #pragma packed.
*/
struct arprequest
{
unsigned short hwtype;
unsigned short protocol;
char hwlen;
char protolen;
unsigned short opcode;
char shwaddr[6];
char sipaddr[4];
char thwaddr[6];
char tipaddr[4];
};
struct iphdr
{
char verhdrlen;
char service;
unsigned short len;
unsigned short ident;
unsigned short frags;
char ttl;
char protocol;
unsigned short chksum;
in_addr src;
in_addr dest;
};
struct udphdr
{
unsigned short src;
unsigned short dest;
unsigned short len;
unsigned short chksum;
};
/* Format of a bootp packet. */
struct bootp_t
{
char bp_op;
char bp_htype;
char bp_hlen;
char bp_hops;
unsigned long bp_xid;
unsigned short bp_secs;
unsigned short unused;
in_addr bp_ciaddr;
in_addr bp_yiaddr;
in_addr bp_siaddr;
in_addr bp_giaddr;
char bp_hwaddr[16];
char bp_sname[64];
char bp_file[128];
#ifdef NO_DHCP_SUPPORT
char bp_vend[BOOTP_VENDOR_LEN];
#else
char bp_vend[DHCP_OPT_LEN];
#endif /* NO_DHCP_SUPPORT */
};
/* Format of a bootp IP packet. */
struct bootpip_t
{
struct iphdr ip;
struct udphdr udp;
struct bootp_t bp;
};
/* Format of bootp packet with extensions. */
struct bootpd_t
{
struct bootp_t bootp_reply;
unsigned char bootp_extension[MAX_BOOTP_EXTLEN];
};
struct tftp_t
{
struct iphdr ip;
struct udphdr udp;
unsigned short opcode;
union
{
char rrq[TFTP_DEFAULTSIZE_PACKET];
struct
{
unsigned short block;
char download[TFTP_MAX_PACKET];
}
data;
struct
{
unsigned short block;
}
ack;
struct
{
unsigned short errcode;
char errmsg[TFTP_DEFAULTSIZE_PACKET];
}
err;
struct
{
char data[TFTP_DEFAULTSIZE_PACKET+2];
}
oack;
}
u;
};
/* Define a smaller tftp packet solely for making requests to conserve stack
512 bytes should be enough. */
struct tftpreq_t
{
struct iphdr ip;
struct udphdr udp;
unsigned short opcode;
union
{
char rrq[512];
struct
{
unsigned short block;
}
ack;
struct
{
unsigned short errcode;
char errmsg[512-2];
}
err;
}
u;
};
#define TFTP_MIN_PACKET (sizeof(struct iphdr) + sizeof(struct udphdr) + 4)
struct rpc_t
{
struct iphdr ip;
struct udphdr udp;
union
{
char data[300]; /* longest RPC call must fit!!!! */
struct
{
long id;
long type;
long rpcvers;
long prog;
long vers;
long proc;
long data[1];
}
call;
struct
{
long id;
long type;
long rstatus;
long verifier;
long v2;
long astatus;
long data[1];
}
reply;
}
u;
};
#define PROG_PORTMAP 100000
#define PROG_NFS 100003
#define PROG_MOUNT 100005
#define MSG_CALL 0
#define MSG_REPLY 1
#define PORTMAP_GETPORT 3
#define MOUNT_ADDENTRY 1
#define MOUNT_UMOUNTALL 4
#define NFS_LOOKUP 4
#define NFS_READ 6
#define NFS_FHSIZE 32
#define NFSERR_PERM 1
#define NFSERR_NOENT 2
#define NFSERR_ACCES 13
/* Block size used for NFS read accesses. A RPC reply packet (including all
* headers) must fit within a single Ethernet frame to avoid fragmentation.
* Chosen to be a power of two, as most NFS servers are optimized for this. */
#define NFS_READ_SIZE 1024
#define FLOPPY_BOOT_LOCATION 0x7c00
/* Must match offsets in loader.S */
#define ROM_SEGMENT 0x1fa
#define ROM_LENGTH 0x1fc
#define ROM_INFO_LOCATION (FLOPPY_BOOT_LOCATION + ROM_SEGMENT)
/* at end of floppy boot block */
struct rom_info
{
unsigned short rom_segment;
unsigned short rom_length;
};
static inline int
rom_address_ok (struct rom_info *rom, int assigned_rom_segment)
{
return (assigned_rom_segment < 0xC000
|| assigned_rom_segment == rom->rom_segment);
}
/* Define a type for passing info to a loaded program. */
struct ebinfo
{
unsigned char major, minor; /* Version */
unsigned short flags; /* Bit flags */
};
/***************************************************************************
External prototypes
***************************************************************************/
/* main.c */
extern void print_network_configuration (void);
extern int ifconfig (char *ip, char *sm, char *gw, char *svr);
extern int udp_transmit (unsigned long destip, unsigned int srcsock,
unsigned int destsock, int len, const void *buf);
extern int await_reply (int type, int ival, void *ptr, int timeout);
extern int decode_rfc1533 (unsigned char *, int, int, int);
extern long rfc2131_sleep_interval (int base, int exp);
extern void cleanup (void);
extern int rarp (void);
extern int bootp (void);
extern void cleanup_net (void);
/* config.c */
extern void print_config (void);
extern void eth_reset (void);
extern int eth_probe (void);
extern int eth_poll (void);
extern void eth_transmit (const char *d, unsigned int t,
unsigned int s, const void *p);
extern void eth_disable (void);
/* misc.c */
extern void twiddle (void);
extern void sleep (int secs);
extern int getdec (char **s);
extern void etherboot_printf (const char *, ...);
extern int etherboot_sprintf (char *, const char *, ...);
extern int inet_aton (char *p, in_addr *i);
/***************************************************************************
External variables
***************************************************************************/
/* main.c */
extern int ip_abort;
extern int network_ready;
extern struct rom_info rom;
extern struct arptable_t arptable[MAX_ARP];
/* config.c */
extern struct nic nic;
/* Local hack - define some macros to use etherboot source files "as is". */
#ifndef GRUB
# undef printf
# define printf etherboot_printf
# undef sprintf
# define sprintf etherboot_sprintf
#endif /* GRUB */
+421
View File
@@ -0,0 +1,421 @@
/*
Driver for the National Semiconductor DP83810 Ethernet controller.
Portions Copyright (C) 2001 Inprimis Technologies, Inc.
http://www.inprimis.com/
This driver is based (heavily) on the Linux driver for this chip
which is copyright 1999-2001 by Donald Becker.
This software has no warranties expressed or implied for any
purpose.
This software may be used and distributed according to the terms of
the GNU General Public License (GPL), incorporated herein by reference.
Drivers based on or derived from this code fall under the GPL and must
retain the authorship, copyright and license notice. This file is not
a complete program and may only be used when the entire operating
system is licensed under the GPL. License for under other terms may be
available. Contact the original author for details.
The original author may be reached as becker@scyld.com, or at
Scyld Computing Corporation
410 Severn Ave., Suite 210
Annapolis MD 21403
*/
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#undef virt_to_bus
#define virt_to_bus(x) ((unsigned long)x)
#define cpu_to_le32(val) (val)
#define le32_to_cpu(val) (val)
#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
#define TX_RING_SIZE 1
#define RX_RING_SIZE 4
#define TIME_OUT 1000000
#define PKT_BUF_SZ 1536
/* Offsets to the device registers. */
enum register_offsets {
ChipCmd=0x00, ChipConfig=0x04, EECtrl=0x08, PCIBusCfg=0x0C,
IntrStatus=0x10, IntrMask=0x14, IntrEnable=0x18,
TxRingPtr=0x20, TxConfig=0x24,
RxRingPtr=0x30, RxConfig=0x34,
WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C,
BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60,
RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64,
};
/* Bit in ChipCmd. */
enum ChipCmdBits {
ChipReset=0x100, RxReset=0x20, TxReset=0x10, RxOff=0x08, RxOn=0x04,
TxOff=0x02, TxOn=0x01,
};
/* Bits in the interrupt status/mask registers. */
enum intr_status_bits {
IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008,
IntrRxIdle=0x0010, IntrRxOverrun=0x0020,
IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100,
IntrTxIdle=0x0200, IntrTxUnderrun=0x0400,
StatsMax=0x0800, LinkChange=0x4000, WOLPkt=0x2000,
RxResetDone=0x1000000, TxResetDone=0x2000000,
IntrPCIErr=0x00f00000, IntrNormalSummary=0x0251, IntrAbnormalSummary=0xED20,
};
/* Bits in the RxMode register. */
enum rx_mode_bits {
AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0xC0000000,
AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000,
AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000,
};
/* Bits in network_desc.status */
enum desc_status_bits {
DescOwn=0x80000000, DescMore=0x40000000, DescIntr=0x20000000,
DescNoCRC=0x10000000,
DescPktOK=0x08000000, RxTooLong=0x00400000,
};
/* The Rx and Tx buffer descriptors. */
struct netdev_desc {
u32 next_desc;
s32 cmd_status;
u32 addr;
};
static struct FA311_DEV {
unsigned int ioaddr;
unsigned short vendor;
unsigned short device;
unsigned int cur_rx;
unsigned int cur_tx;
unsigned int rx_buf_sz;
volatile struct netdev_desc *rx_head_desc;
volatile struct netdev_desc rx_ring[RX_RING_SIZE] __attribute__ ((aligned (4)));
volatile struct netdev_desc tx_ring[TX_RING_SIZE] __attribute__ ((aligned (4)));
} fa311_dev;
static int eeprom_read(long ioaddr, int location);
static void init_ring(struct FA311_DEV *dev);
static void fa311_reset(struct nic *nic);
static int fa311_poll(struct nic *nic);
static void fa311_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);
static void fa311_disable(struct nic *nic);
static char rx_packet[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned (4)));
static char tx_packet[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned (4)));
struct nic * fa311_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
{
int prev_eedata;
int i;
int duplex;
int tx_config;
int rx_config;
unsigned char macaddr[6];
unsigned char mactest;
unsigned char pci_bus = 0;
struct FA311_DEV* dev = &fa311_dev;
if (io_addrs == 0 || *io_addrs == 0)
return (0);
memset(dev, 0, sizeof(*dev));
dev->vendor = pci->vendor;
dev->device = pci->dev_id;
dev->ioaddr = pci->membase;
/* Work around the dropped serial bit. */
prev_eedata = eeprom_read(dev->ioaddr, 6);
for (i = 0; i < 3; i++) {
int eedata = eeprom_read(dev->ioaddr, i + 7);
macaddr[i*2] = (eedata << 1) + (prev_eedata >> 15);
macaddr[i*2+1] = eedata >> 7;
prev_eedata = eedata;
}
mactest = 0;
for (i = 0; i < 6; i++)
mactest |= macaddr[i];
if (mactest == 0)
return (0);
for (i = 0; i < 6; i++)
nic->node_addr[i] = macaddr[i];
printf("%! ", nic->node_addr);
adjust_pci_device(pci);
fa311_reset(nic);
nic->reset = fa311_reset;
nic->disable = fa311_disable;
nic->poll = fa311_poll;
nic->transmit = fa311_transmit;
init_ring(dev);
writel(virt_to_bus(dev->rx_ring), dev->ioaddr + RxRingPtr);
writel(virt_to_bus(dev->tx_ring), dev->ioaddr + TxRingPtr);
for (i = 0; i < 6; i += 2)
{
writel(i, dev->ioaddr + RxFilterAddr);
writew(macaddr[i] + (macaddr[i+1] << 8),
dev->ioaddr + RxFilterData);
}
/* Initialize other registers. */
/* Configure for standard, in-spec Ethernet. */
if (readl(dev->ioaddr + ChipConfig) & 0x20000000)
{ /* Full duplex */
tx_config = 0xD0801002;
rx_config = 0x10000020;
}
else
{
tx_config = 0x10801002;
rx_config = 0x0020;
}
writel(tx_config, dev->ioaddr + TxConfig);
writel(rx_config, dev->ioaddr + RxConfig);
duplex = readl(dev->ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;
if (duplex) {
rx_config |= 0x10000000;
tx_config |= 0xC0000000;
} else {
rx_config &= ~0x10000000;
tx_config &= ~0xC0000000;
}
writew(tx_config, dev->ioaddr + TxConfig);
writew(rx_config, dev->ioaddr + RxConfig);
writel(AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys,
dev->ioaddr + RxFilterAddr);
writel(RxOn | TxOn, dev->ioaddr + ChipCmd);
writel(4, dev->ioaddr + StatsCtrl); /* Clear Stats */
return nic;
}
static void fa311_reset(struct nic *nic)
{
u32 chip_config;
struct FA311_DEV* dev = &fa311_dev;
/* Reset the chip to erase previous misconfiguration. */
outl(ChipReset, dev->ioaddr + ChipCmd);
if ((readl(dev->ioaddr + ChipConfig) & 0xe000) != 0xe000)
{
chip_config = readl(dev->ioaddr + ChipConfig);
}
}
static int fa311_poll(struct nic *nic)
{
s32 desc_status;
int to;
int entry;
int retcode;
struct FA311_DEV* dev = &fa311_dev;
retcode = 0;
entry = dev->cur_rx;
to = TIME_OUT;
while (to != 0)
{
desc_status = dev->rx_ring[entry].cmd_status;
if ((desc_status & DescOwn) != 0)
break;
else
--to;
}
if (to != 0)
{
readl(dev->ioaddr + IntrStatus); /* clear interrrupt bits */
/* driver owns the next entry it's a new packet. Send it up. */
if ((desc_status & (DescMore|DescPktOK|RxTooLong)) == DescPktOK)
{
nic->packetlen = (desc_status & 0x0fff) - 4; /* Omit CRC size. */
memcpy(nic->packet, (char*)(dev->rx_ring[entry].addr), nic->packetlen);
retcode = 1;
}
/* Give the descriptor back to the chip */
dev->rx_ring[entry].cmd_status = cpu_to_le32(dev->rx_buf_sz);
dev->cur_rx++;
if (dev->cur_rx >= RX_RING_SIZE)
dev->cur_rx = 0;
dev->rx_head_desc = &dev->rx_ring[dev->cur_rx];
}
/* Restart Rx engine if stopped. */
writel(RxOn, dev->ioaddr + ChipCmd);
return retcode;
}
static void fa311_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned int len, const char *data)
{
unsigned short nstype;
s32 desc_status;
int to;
int entry;
char* txp;
unsigned char* s;
struct FA311_DEV* dev = &fa311_dev;
/* Calculate the next Tx descriptor entry. */
entry = dev->cur_tx;
txp = (char*)(dev->tx_ring[entry].addr);
memcpy(txp, destaddr, ETH_ALEN);
memcpy(txp + ETH_ALEN, nic->node_addr, ETH_ALEN);
nstype = htons(type);
memcpy(txp + 12, (char*)&nstype, 2);
memcpy(txp + ETH_HLEN, data, len);
len += ETH_HLEN;
/* pad frame */
if (len < ETH_ZLEN)
{
s = (unsigned char*)(txp+len);
while (s < (unsigned char*)(txp+ETH_ZLEN))
*s++ = 0;
len = ETH_ZLEN;
}
dev->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | len);
dev->cur_tx++;
if (dev->cur_tx >= TX_RING_SIZE)
dev->cur_tx = 0;
/* Wake the potentially-idle transmit channel. */
writel(TxOn, dev->ioaddr + ChipCmd);
/* wait for tranmission to complete */
to = TIME_OUT;
while (to != 0)
{
desc_status = dev->tx_ring[entry].cmd_status;
if ((desc_status & DescOwn) == 0)
break;
else
--to;
}
readl(dev->ioaddr + IntrStatus); /* clear interrrupt bits */
return;
}
static void fa311_disable(struct nic *nic)
{
struct FA311_DEV* dev = &fa311_dev;
/* Stop the chip's Tx and Rx processes. */
writel(RxOff | TxOff, dev->ioaddr + ChipCmd);
}
/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses. */
/* Delay between EEPROM clock transitions.
No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that
made udelay() unreliable.
The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
depricated.
*/
#define eeprom_delay(ee_addr) inl(ee_addr)
enum EEPROM_Ctrl_Bits {
EE_ShiftClk=0x04, EE_DataIn=0x01, EE_ChipSelect=0x08, EE_DataOut=0x02,
};
#define EE_Write0 (EE_ChipSelect)
#define EE_Write1 (EE_ChipSelect | EE_DataIn)
/* The EEPROM commands include the alway-set leading bit. */
enum EEPROM_Cmds {
EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
};
static int eeprom_read(long addr, int location)
{
int i;
int retval = 0;
int ee_addr = addr + EECtrl;
int read_cmd = location | EE_ReadCmd;
writel(EE_Write0, ee_addr);
/* Shift the read command bits out. */
for (i = 10; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
writel(dataval, ee_addr);
eeprom_delay(ee_addr);
writel(dataval | EE_ShiftClk, ee_addr);
eeprom_delay(ee_addr);
}
writel(EE_ChipSelect, ee_addr);
eeprom_delay(ee_addr);
for (i = 0; i < 16; i++) {
writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
eeprom_delay(ee_addr);
retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 0;
writel(EE_ChipSelect, ee_addr);
eeprom_delay(ee_addr);
}
/* Terminate the EEPROM access. */
writel(EE_Write0, ee_addr);
writel(0, ee_addr);
return retval;
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void init_ring(struct FA311_DEV *dev)
{
int i;
dev->cur_rx = 0;
dev->cur_tx = 0;
dev->rx_buf_sz = PKT_BUF_SZ;
dev->rx_head_desc = &dev->rx_ring[0];
/* Initialize all Rx descriptors. */
for (i = 0; i < RX_RING_SIZE; i++) {
dev->rx_ring[i].next_desc = virt_to_le32desc(&dev->rx_ring[i+1]);
dev->rx_ring[i].cmd_status = DescOwn;
}
/* Mark the last entry as wrapping the ring. */
dev->rx_ring[i-1].next_desc = virt_to_le32desc(&dev->rx_ring[0]);
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
dev->rx_ring[i].addr = (u32)(&rx_packet[PKT_BUF_SZ * i]);
dev->rx_ring[i].cmd_status = cpu_to_le32(dev->rx_buf_sz);
}
for (i = 0; i < TX_RING_SIZE; i++) {
dev->tx_ring[i].next_desc = virt_to_le32desc(&dev->tx_ring[i+1]);
dev->tx_ring[i].cmd_status = 0;
}
dev->tx_ring[i-1].next_desc = virt_to_le32desc(&dev->tx_ring[0]);
for (i = 0; i < TX_RING_SIZE; i++)
dev->tx_ring[i].addr = (u32)(&tx_packet[PKT_BUF_SZ * i]);
return;
}
+497
View File
@@ -0,0 +1,497 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2004 Free Software Foundation, Inc.
*
* 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.
*/
/* Based on "src/main.c" in etherboot-4.5.8. */
/**************************************************************************
ETHERBOOT - BOOTP/TFTP Bootstrap Program
Author: Martin Renters
Date: Dec/93
**************************************************************************/
/* #define TFTP_DEBUG 1 */
#include <filesys.h>
#define GRUB 1
#include <etherboot.h>
#include <nic.h>
static int retry;
static unsigned short iport = 2000;
static unsigned short oport;
static unsigned short block, prevblock;
static int bcounter;
static struct tftp_t tp, saved_tp;
static int packetsize;
static int buf_eof, buf_read;
static int saved_filepos;
static unsigned short len, saved_len;
static char *buf;
/* Fill the buffer by receiving the data via the TFTP protocol. */
static int
buf_fill (int abort)
{
#ifdef TFTP_DEBUG
grub_printf ("buf_fill (%d)\n", abort);
#endif
while (! buf_eof && (buf_read + packetsize <= FSYS_BUFLEN))
{
struct tftp_t *tr;
long timeout;
#ifdef CONGESTED
timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);
#else
timeout = rfc2131_sleep_interval (TIMEOUT, retry);
#endif
if (! await_reply (AWAIT_TFTP, iport, NULL, timeout))
{
if (ip_abort)
return 0;
if (! block && retry++ < MAX_TFTP_RETRIES)
{
/* Maybe initial request was lost. */
#ifdef TFTP_DEBUG
grub_printf ("Maybe initial request was lost.\n");
#endif
if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
++iport, TFTP_PORT, len, &tp))
return 0;
continue;
}
#ifdef CONGESTED
if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
{
/* We resend our last ack. */
# ifdef TFTP_DEBUG
grub_printf ("<REXMT>\n");
# endif
udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
iport, oport,
TFTP_MIN_PACKET, &tp);
continue;
}
#endif
/* Timeout. */
return 0;
}
tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
if (tr->opcode == ntohs (TFTP_ERROR))
{
grub_printf ("TFTP error %d (%s)\n",
ntohs (tr->u.err.errcode),
tr->u.err.errmsg);
return 0;
}
if (tr->opcode == ntohs (TFTP_OACK))
{
char *p = tr->u.oack.data, *e;
#ifdef TFTP_DEBUG
grub_printf ("OACK ");
#endif
/* Shouldn't happen. */
if (prevblock)
{
/* Ignore it. */
grub_printf ("%s:%d: warning: PREVBLOCK != 0 (0x%x)\n",
__FILE__, __LINE__, prevblock);
continue;
}
len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2;
if (len > TFTP_MAX_PACKET)
goto noak;
e = p + len;
while (*p != '\000' && p < e)
{
if (! grub_strcmp ("blksize", p))
{
p += 8;
if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET)
goto noak;
#ifdef TFTP_DEBUG
grub_printf ("blksize = %d\n", packetsize);
#endif
}
else if (! grub_strcmp ("tsize", p))
{
p += 6;
if ((filemax = getdec (&p)) < 0)
{
filemax = -1;
goto noak;
}
#ifdef TFTP_DEBUG
grub_printf ("tsize = %d\n", filemax);
#endif
}
else
{
noak:
#ifdef TFTP_DEBUG
grub_printf ("NOAK\n");
#endif
tp.opcode = htons (TFTP_ERROR);
tp.u.err.errcode = 8;
len = (grub_sprintf ((char *) tp.u.err.errmsg,
"RFC1782 error")
+ sizeof (tp.ip) + sizeof (tp.udp)
+ sizeof (tp.opcode) + sizeof (tp.u.err.errcode)
+ 1);
udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
iport, ntohs (tr->udp.src),
len, &tp);
return 0;
}
while (p < e && *p)
p++;
if (p < e)
p++;
}
if (p > e)
goto noak;
/* This ensures that the packet does not get processed as
data! */
block = tp.u.ack.block = 0;
}
else if (tr->opcode == ntohs (TFTP_DATA))
{
#ifdef TFTP_DEBUG
grub_printf ("DATA ");
#endif
len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4;
/* Shouldn't happen. */
if (len > packetsize)
{
/* Ignore it. */
grub_printf ("%s:%d: warning: LEN > PACKETSIZE (0x%x > 0x%x)\n",
__FILE__, __LINE__, len, packetsize);
continue;
}
block = ntohs (tp.u.ack.block = tr->u.data.block);
}
else
/* Neither TFTP_OACK nor TFTP_DATA. */
break;
if ((block || bcounter) && (block != prevblock + (unsigned short) 1))
/* Block order should be continuous */
tp.u.ack.block = htons (block = prevblock);
/* Should be continuous. */
tp.opcode = abort ? htons (TFTP_ERROR) : htons (TFTP_ACK);
oport = ntohs (tr->udp.src);
#ifdef TFTP_DEBUG
grub_printf ("ACK\n");
#endif
/* Ack. */
udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport,
oport, TFTP_MIN_PACKET, &tp);
if (abort)
{
buf_eof = 1;
break;
}
/* Retransmission or OACK. */
if ((unsigned short) (block - prevblock) != 1)
/* Don't process. */
continue;
prevblock = block;
/* Is it the right place to zero the timer? */
retry = 0;
/* In GRUB, this variable doesn't play any important role at all,
but use it for consistency with Etherboot. */
bcounter++;
/* Copy the downloaded data to the buffer. */
grub_memmove (buf + buf_read, tr->u.data.download, len);
buf_read += len;
/* End of data. */
if (len < packetsize)
buf_eof = 1;
}
return 1;
}
/* Send the RRQ whose length is LEN. */
static int
send_rrq (void)
{
/* Initialize some variables. */
retry = 0;
block = 0;
prevblock = 0;
packetsize = TFTP_DEFAULTSIZE_PACKET;
bcounter = 0;
buf = (char *) FSYS_BUF;
buf_eof = 0;
buf_read = 0;
saved_filepos = 0;
/* Clear out the Rx queue first. It contains nothing of interest,
* except possibly ARP requests from the DHCP/TFTP server. We use
* polling throughout Etherboot, so some time may have passed since we
* last polled the receive queue, which may now be filled with
* broadcast packets. This will cause the reply to the packets we are
* about to send to be lost immediately. Not very clever. */
await_reply (AWAIT_QDRAIN, 0, NULL, 0);
#ifdef TFTP_DEBUG
grub_printf ("send_rrq ()\n");
{
int i;
char *p;
for (i = 0, p = (char *) &tp; i < len; i++)
if (p[i] >= ' ' && p[i] <= '~')
grub_putchar (p[i]);
else
grub_printf ("\\%x", (unsigned) p[i]);
grub_putchar ('\n');
}
#endif
/* Send the packet. */
return udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
TFTP_PORT, len, &tp);
}
/* Mount the network drive. If the drive is ready, return one, otherwise
return zero. */
int
tftp_mount (void)
{
/* Check if the current drive is the network drive. */
if (current_drive != NETWORK_DRIVE)
return 0;
/* If the drive is not initialized yet, abort. */
if (! network_ready)
return 0;
return 1;
}
/* Read up to SIZE bytes, returned in ADDR. */
int
tftp_read (char *addr, int size)
{
/* How many bytes is read? */
int ret = 0;
#ifdef TFTP_DEBUG
grub_printf ("tftp_read (0x%x, %d)\n", (int) addr, size);
#endif
if (filepos < saved_filepos)
{
/* Uggh.. FILEPOS has been moved backwards. So reopen the file. */
buf_read = 0;
buf_fill (1);
grub_memmove ((char *) &tp, (char *) &saved_tp, saved_len);
len = saved_len;
#ifdef TFTP_DEBUG
{
int i;
grub_printf ("opcode = 0x%x, rrq = ", (unsigned long) tp.opcode);
for (i = 0; i < TFTP_DEFAULTSIZE_PACKET; i++)
{
if (tp.u.rrq[i] >= ' ' && tp.u.rrq[i] <= '~')
grub_putchar (tp.u.rrq[i]);
else
grub_putchar ('*');
}
grub_putchar ('\n');
}
#endif
if (! send_rrq ())
{
errnum = ERR_WRITE;
return 0;
}
}
while (size > 0)
{
int amt = buf_read + saved_filepos - filepos;
/* If the length that can be copied from the buffer is over the
requested size, cut it down. */
if (amt > size)
amt = size;
if (amt > 0)
{
/* Copy the buffer to the supplied memory space. */
grub_memmove (addr, buf + filepos - saved_filepos, amt);
size -= amt;
addr += amt;
filepos += amt;
ret += amt;
/* If the size of the empty space becomes small, move the unused
data forwards. */
if (filepos - saved_filepos > FSYS_BUFLEN / 2)
{
grub_memmove (buf, buf + FSYS_BUFLEN / 2, FSYS_BUFLEN / 2);
buf_read -= FSYS_BUFLEN / 2;
saved_filepos += FSYS_BUFLEN / 2;
}
}
else
{
/* Skip the whole buffer. */
saved_filepos += buf_read;
buf_read = 0;
}
/* Read the data. */
if (size > 0 && ! buf_fill (0))
{
errnum = ERR_READ;
return 0;
}
/* Sanity check. */
if (size > 0 && buf_read == 0)
{
errnum = ERR_READ;
return 0;
}
}
return ret;
}
/* Check if the file DIRNAME really exists. Get the size and save it in
FILEMAX. */
int
tftp_dir (char *dirname)
{
int ch;
#ifdef TFTP_DEBUG
grub_printf ("tftp_dir (%s)\n", dirname);
#endif
/* In TFTP, there is no way to know what files exist. */
if (print_possibilities)
return 1;
/* Don't know the size yet. */
filemax = -1;
reopen:
/* Construct the TFTP request packet. */
tp.opcode = htons (TFTP_RRQ);
/* Terminate the filename. */
ch = nul_terminate (dirname);
/* Make the request string (octet, blksize and tsize). */
len = (grub_sprintf ((char *) tp.u.rrq,
"%s%coctet%cblksize%c%d%ctsize%c0",
dirname, 0, 0, 0, TFTP_MAX_PACKET, 0, 0)
+ sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1);
/* Restore the original DIRNAME. */
dirname[grub_strlen (dirname)] = ch;
/* Save the TFTP packet so that we can reopen the file later. */
grub_memmove ((char *) &saved_tp, (char *) &tp, len);
saved_len = len;
if (! send_rrq ())
{
errnum = ERR_WRITE;
return 0;
}
/* Read the data. */
if (! buf_fill (0))
{
errnum = ERR_FILE_NOT_FOUND;
return 0;
}
if (filemax == -1)
{
/* The server doesn't support the "tsize" option, so we must read
the file twice... */
/* Zero the size of the file. */
filemax = 0;
do
{
/* Add the length of the downloaded data. */
filemax += buf_read;
/* Reset the offset. Just discard the contents of the buffer. */
buf_read = 0;
/* Read the data. */
if (! buf_fill (0))
{
errnum = ERR_READ;
return 0;
}
}
while (! buf_eof);
/* Maybe a few amounts of data remains. */
filemax += buf_read;
/* Retry the open instruction. */
goto reopen;
}
return 1;
}
/* Close the file. */
void
tftp_close (void)
{
#ifdef TFTP_DEBUG
grub_printf ("tftp_close ()\n");
#endif
buf_read = 0;
buf_fill (1);
}
+825
View File
@@ -0,0 +1,825 @@
/**************************************************************************
Etherboot - BOOTP/TFTP Bootstrap Program
i82586 NIC driver for Etherboot
Ken Yap, January 1998
***************************************************************************/
/*
* 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, or (at
* your option) any later version.
*/
#include "etherboot.h"
#include "nic.h"
#include "cards.h"
#include "timer.h"
#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000)
/* Sources of information:
Donald Becker's excellent 3c507 driver in Linux
Intel 82596 data sheet (yes, 82596; it has a 586 compatibility mode)
*/
/* Code below mostly stolen wholesale from 3c507.c driver in Linux */
/*
Details of the i82586.
You'll really need the databook to understand the details of this part,
but the outline is that the i82586 has two separate processing units.
Both are started from a list of three configuration tables, of which only
the last, the System Control Block (SCB), is used after reset-time. The SCB
has the following fields:
Status word
Command word
Tx/Command block addr.
Rx block addr.
The command word accepts the following controls for the Tx and Rx units:
*/
#define CUC_START 0x0100
#define CUC_RESUME 0x0200
#define CUC_SUSPEND 0x0300
#define RX_START 0x0010
#define RX_RESUME 0x0020
#define RX_SUSPEND 0x0030
/* The Rx unit uses a list of frame descriptors and a list of data buffer
descriptors. We use full-sized (1518 byte) data buffers, so there is
a one-to-one pairing of frame descriptors to buffer descriptors.
The Tx ("command") unit executes a list of commands that look like:
Status word Written by the 82586 when the command is done.
Command word Command in lower 3 bits, post-command action in upper 3
Link word The address of the next command.
Parameters (as needed).
Some definitions related to the Command Word are:
*/
#define CMD_EOL 0x8000 /* The last command of the list, stop. */
#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
enum commands {
CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
/*
Details of the EtherLink16 Implementation
The 3c507 and NI5210 are generic shared-memory i82586 implementations.
3c507: The host can map 16K, 32K, 48K, or 64K of the 64K memory into
0x0[CD][08]0000, or all 64K into 0xF[02468]0000.
NI5210: The host can map 8k or 16k at 0x[CDE][048C]000 but we
assume 8k because to have 16k you cannot put a ROM on the NIC.
*/
/* Offsets from the base I/O address. */
#ifdef INCLUDE_3C507
#define SA_DATA 0 /* Station address data, or 3Com signature. */
#define MISC_CTRL 6 /* Switch the SA_DATA banks, and bus config bits. */
#define RESET_IRQ 10 /* Reset the latched IRQ line. */
#define I82586_ATTN 11 /* Frob the 82586 Channel Attention line. */
#define ROM_CONFIG 13
#define MEM_CONFIG 14
#define IRQ_CONFIG 15
#define EL16_IO_EXTENT 16
/* The ID port is used at boot-time to locate the ethercard. */
#define ID_PORT 0x100
#endif
#ifdef INCLUDE_NI5210
#define NI52_RESET 0 /* writing to this address, resets the i82586 */
#define I82586_ATTN 1 /* channel attention, kick the 586 */
#endif
#ifdef INCLUDE_EXOS205
#define EXOS205_RESET 0 /* writing to this address, resets the i82586 */
#define I82586_ATTN 1 /* channel attention, kick the 586 */
#endif
/* Offsets to registers in the mailbox (SCB). */
#define iSCB_STATUS 0x8
#define iSCB_CMD 0xA
#define iSCB_CBL 0xC /* Command BLock offset. */
#define iSCB_RFA 0xE /* Rx Frame Area offset. */
/* Since the 3c507 maps the shared memory window so that the last byte is
at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
48K corresponding to window sizes of 64K, 48K, 32K and 16K respectively.
We can account for this be setting the 'SBC Base' entry in the ISCP table
below for all the 16 bit offset addresses, and also adding the 'SCB Base'
value to all 24 bit physical addresses (in the SCP table and the TX and RX
Buffer Descriptors).
-Mark
*/
/*
What follows in 'init_words[]' is the "program" that is downloaded to the
82586 memory. It's mostly tables and command blocks, and starts at the
reset address 0xfffff6. This is designed to be similar to the EtherExpress,
thus the unusual location of the SCB at 0x0008.
Even with the additional "don't care" values, doing it this way takes less
program space than initializing the individual tables, and I feel it's much
cleaner.
The databook is particularly useless for the first two structures, I had
to use the Crynwr driver as an example.
The memory setup is as follows:
*/
#define CONFIG_CMD 0x18
#define SET_SA_CMD 0x24
#define SA_OFFSET 0x2A
#define IDLELOOP 0x30
#define TDR_CMD 0x38
#define TDR_TIME 0x3C
#define DUMP_CMD 0x40
#define DIAG_CMD 0x48
#define SET_MC_CMD 0x4E
#define DUMP_DATA 0x56 /* A 170 byte buffer for dump and Set-MC into. */
#define TX_BUF_START 0x0100
#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */
#define RX_BUF_START 0x1000
#define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */
#define RX_BUF_END (mem_end - mem_start - 20)
/*
That's it: only 86 bytes to set up the beast, including every extra
command available. The 170 byte buffer at DUMP_DATA is shared between the
Dump command (called only by the diagnostic program) and the SetMulticastList
command.
To complete the memory setup you only have to write the station address at
SA_OFFSET and create the Tx & Rx buffer lists.
The Tx command chain and buffer list is setup as follows:
A Tx command table, with the data buffer pointing to...
A Tx data buffer descriptor. The packet is in a single buffer, rather than
chaining together several smaller buffers.
A NoOp command, which initially points to itself,
And the packet data.
A transmit is done by filling in the Tx command table and data buffer,
re-writing the NoOp command, and finally changing the offset of the last
command to point to the current Tx command. When the Tx command is finished,
it jumps to the NoOp, when it loops until the next Tx command changes the
"link offset" in the NoOp. This way the 82586 never has to go through the
slow restart sequence.
The Rx buffer list is set up in the obvious ring structure. We have enough
memory (and low enough interrupt latency) that we can avoid the complicated
Rx buffer linked lists by alway associating a full-size Rx data buffer with
each Rx data frame.
I currently use one transmit buffer starting at TX_BUF_START (0x0100), and
use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
*/
static unsigned short init_words[] = {
/* System Configuration Pointer (SCP). */
#if defined(INCLUDE_3C507)
0x0000, /* Set bus size to 16 bits. */
#else
0x0001, /* Set bus size to 8 bits */
#endif
0,0, /* pad words. */
0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */
/* Intermediate System Configuration Pointer (ISCP). */
0x0001, /* Status word that's cleared when init is done. */
0x0008,0,0, /* SCB offset, (skip, skip) */
/* System Control Block (SCB). */
0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */
CONFIG_CMD, /* Command list pointer, points to Configure. */
RX_BUF_START, /* Rx block list. */
0,0,0,0, /* Error count: CRC, align, buffer, overrun. */
/* 0x0018: Configure command. Change to put MAC data with packet. */
0, CmdConfigure, /* Status, command. */
SET_SA_CMD, /* Next command is Set Station Addr. */
0x0804, /* "4" bytes of config data, 8 byte FIFO. */
0x2e40, /* Magic values, including MAC data location. */
0, /* Unused pad word. */
/* 0x0024: Setup station address command. */
0, CmdSASetup,
SET_MC_CMD, /* Next command. */
0xaa00,0xb000,0x0bad, /* Station address (to be filled in) */
/* 0x0030: NOP, looping back to itself. Point to first Tx buffer to Tx. */
0, CmdNOp, IDLELOOP, 0 /* pad */,
/* 0x0038: A unused Time-Domain Reflectometer command. */
0, CmdTDR, IDLELOOP, 0,
/* 0x0040: An unused Dump State command. */
0, CmdDump, IDLELOOP, DUMP_DATA,
/* 0x0048: An unused Diagnose command. */
0, CmdDiagnose, IDLELOOP,
/* 0x004E: An empty set-multicast-list command. */
0, CmdMulticastList, IDLELOOP, 0,
};
/* NIC specific static variables go here */
static unsigned short ioaddr, irq, scb_base;
static Address mem_start, mem_end;
static unsigned short rx_head, rx_tail;
#define read_mem(m,s) fmemcpy((char *)s, m, sizeof(s))
static void setup_rx_buffers(struct nic *nic)
{
Address write_ptr;
unsigned short cur_rx_buf;
static unsigned short rx_cmd[16] = {
0x0000, /* Rx status */
0x0000, /* Rx command, only and last */
RX_BUF_START, /* Link (will be adjusted) */
RX_BUF_START + 22, /* Buffer offset (will be adjusted) */
0x0000, 0x0000, 0x0000, /* Pad for dest addr */
0x0000, 0x0000, 0x0000, /* Pad for source addr */
0x0000, /* Pad for protocol */
0x0000, /* Buffer: Actual count */
-1, /* Buffer: Next (none) */
RX_BUF_START + 0x20, /* Buffer: Address low (+ scb_base) (will be adjusted) */
0x0000, /* Buffer: Address high */
0x8000 | (RX_BUF_SIZE - 0x20)
};
cur_rx_buf = rx_head = RX_BUF_START;
do { /* While there is room for one more buffer */
write_ptr = mem_start + cur_rx_buf;
/* adjust some contents */
rx_cmd[1] = 0x0000;
rx_cmd[2] = cur_rx_buf + RX_BUF_SIZE;
rx_cmd[3] = cur_rx_buf + 22;
rx_cmd[13] = cur_rx_buf + 0x20 + scb_base;
memcpy((char *)write_ptr, (char *)rx_cmd, sizeof(rx_cmd));
rx_tail = cur_rx_buf;
cur_rx_buf += RX_BUF_SIZE;
} while (cur_rx_buf <= RX_BUF_END - RX_BUF_SIZE);
/* Terminate the list by setting the EOL bit and wrap ther pointer
to make the list a ring. */
write_ptr = mem_start + rx_tail;
rx_cmd[1] = 0xC000;
rx_cmd[2] = rx_head;
memcpy((char *)write_ptr, (char *)rx_cmd, sizeof(unsigned short) * 3);
}
static void ack_status(void)
{
unsigned short cmd, status;
unsigned short *shmem = (short *)mem_start;
cmd = (status = shmem[iSCB_STATUS>>1]) & 0xf000;
if (status & 0x100) /* CU suspended? */
cmd |= CUC_RESUME;
if ((status & 0x200) == 0) /* CU not active? */
cmd |= CUC_START;
if (status & 0x010) /* RU suspended? */
cmd |= RX_RESUME;
else if ((status & 0x040) == 0) /* RU not active? */
cmd |= RX_START;
if (cmd == 0) /* Nothing to do */
return;
shmem[iSCB_CMD>>1] = cmd;
#if defined(DEBUG)
printf("Status %hX Command %hX\n", status, cmd);
#endif
outb(0, ioaddr + I82586_ATTN);
}
/**************************************************************************
RESET - Reset adapter
***************************************************************************/
static void i82586_reset(struct nic *nic)
{
unsigned long time;
unsigned short *shmem = (short *)mem_start;
/* put the card in its initial state */
#ifdef INCLUDE_3C507
/* Enable loopback to protect the wire while starting up,
and hold the 586 in reset during the memory initialisation. */
outb(0x20, ioaddr + MISC_CTRL);
#endif
/* Fix the ISCP address and base. */
init_words[3] = scb_base;
init_words[7] = scb_base;
/* Write the words at 0xfff6. */
/* Write the words at 0x0000. */
/* Fill in the station address. */
memcpy((char *)(mem_end - 10), (char *)init_words, 10);
memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
memcpy((char *)mem_start + SA_OFFSET, nic->node_addr, ETH_ALEN);
setup_rx_buffers(nic);
#ifdef INCLUDE_3C507
/* Start the 586 by releasing the reset line, but leave loopback. */
outb(0xA0, ioaddr + MISC_CTRL);
#endif
/* This was time consuming to track down; you need to give two channel
attention signals to reliably start up the i82586. */
outb(0, ioaddr + I82586_ATTN);
time = currticks() + TICKS_PER_SEC; /* allow 1 second to init */
while (
shmem[iSCB_STATUS>>1] == 0)
{
if (currticks() > time)
{
printf("i82586 initialisation timed out with status %hX, cmd %hX\n",
shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
break;
}
}
/* Issue channel-attn -- the 82586 won't start. */
outb(0, ioaddr + I82586_ATTN);
#ifdef INCLUDE_3C507
/* Disable loopback. */
outb(0x80, ioaddr + MISC_CTRL);
#endif
#if defined(DEBUG)
printf("i82586 status %hX, cmd %hX\n",
shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
#endif
}
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
static int i82586_poll(struct nic *nic)
{
int status;
unsigned short rfd_cmd, next_rx_frame, data_buffer_addr,
frame_status, pkt_len;
unsigned short *shmem = (short *)mem_start + rx_head;
/* return true if there's an ethernet packet ready to read */
if (
((frame_status = shmem[0]) & 0x8000) == 0)
return (0); /* nope */
rfd_cmd = shmem[1];
next_rx_frame = shmem[2];
data_buffer_addr = shmem[3];
pkt_len = shmem[11];
status = 0;
if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22
|| (pkt_len & 0xC000) != 0xC000)
printf("\nRx frame corrupt, discarded");
else if ((frame_status & 0x2000) == 0)
printf("\nRx frame had error");
else
{
/* We have a frame, copy it to our buffer */
pkt_len &= 0x3FFF;
memcpy(nic->packet, (char *)mem_start + rx_head + 0x20, pkt_len);
/* Only packets not from ourself */
if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) != 0)
{
nic->packetlen = pkt_len;
status = 1;
}
}
/* Clear the status word and set EOL on Rx frame */
shmem[0] = 0;
shmem[1] = 0xC000;
*(short *)(mem_start + rx_tail + 2) = 0;
rx_tail = rx_head;
rx_head = next_rx_frame;
ack_status();
return (status);
}
/**************************************************************************
TRANSMIT - Transmit a frame
***************************************************************************/
static void i82586_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
Address bptr;
unsigned short type, z;
static unsigned short tx_cmd[11] = {
0x0, /* Tx status */
CmdTx, /* Tx command */
TX_BUF_START+16, /* Next command is a NoOp */
TX_BUF_START+8, /* Data Buffer offset */
0x8000, /* | with size */
0xffff, /* No next data buffer */
TX_BUF_START+22, /* + scb_base */
0x0, /* Buffer address high bits (always zero) */
0x0, /* Nop status */
CmdNOp, /* Nop command */
TX_BUF_START+16 /* Next is myself */
};
unsigned short *shmem = (short *)mem_start + TX_BUF_START;
/* send the packet to destination */
/* adjust some contents */
type = htons(t);
if (s < ETH_ZLEN)
s = ETH_ZLEN;
tx_cmd[4] = (s + ETH_HLEN) | 0x8000;
tx_cmd[6] = TX_BUF_START + 22 + scb_base;
bptr = mem_start + TX_BUF_START;
memcpy((char *)bptr, (char *)tx_cmd, sizeof(tx_cmd));
bptr += sizeof(tx_cmd);
memcpy((char *)bptr, d, ETH_ALEN);
bptr += ETH_ALEN;
memcpy((char *)bptr, nic->node_addr, ETH_ALEN);
bptr += ETH_ALEN;
memcpy((char *)bptr, (char *)&type, sizeof(type));
bptr += sizeof(type);
memcpy((char *)bptr, p, s);
/* Change the offset in the IDLELOOP */
*(unsigned short *)(mem_start + IDLELOOP + 4) = TX_BUF_START;
/* Wait for transmit completion */
while (
(shmem[0] & 0x2000) == 0)
;
/* Change the offset in the IDLELOOP back and
change the final loop to point here */
*(unsigned short *)(mem_start + IDLELOOP + 4) = IDLELOOP;
*(unsigned short *)(mem_start + TX_BUF_START + 20) = IDLELOOP;
ack_status();
}
/**************************************************************************
DISABLE - Turn off ethernet interface
***************************************************************************/
static void i82586_disable(struct nic *nic)
{
unsigned short *shmem = (short *)mem_start;
#if 0
/* Flush the Tx and disable Rx. */
shmem[iSCB_CMD>>1] = RX_SUSPEND | CUC_SUSPEND;
outb(0, ioaddr + I82586_ATTN);
#ifdef INCLUDE_NI5210
outb(0, ioaddr + NI52_RESET);
#endif
#endif /* 0 */
}
#ifdef INCLUDE_3C507
static int t507_probe1(struct nic *nic, unsigned short ioaddr)
{
int i;
Address size;
char mem_config;
char if_port;
if (inb(ioaddr) != '*' || inb(ioaddr+1) != '3'
|| inb(ioaddr+2) != 'C' || inb(ioaddr+3) != 'O')
return (0);
irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
mem_config = inb(ioaddr + MEM_CONFIG);
if (mem_config & 0x20)
{
size = 65536L;
mem_start = 0xf00000L + (mem_config & 0x08 ? 0x080000L
: (((Address)mem_config & 0x3) << 17));
}
else
{
size = ((((Address)mem_config & 0x3) + 1) << 14);
mem_start = 0x0c0000L + (((Address)mem_config & 0x18) << 12);
}
mem_end = mem_start + size;
scb_base = 65536L - size;
if_port = inb(ioaddr + ROM_CONFIG) & 0x80;
/* Get station address */
outb(0x01, ioaddr + MISC_CTRL);
for (i = 0; i < ETH_ALEN; ++i)
{
nic->node_addr[i] = inb(ioaddr+i);
}
printf("\n3c507 ioaddr %#hX, IRQ %d, mem [%#X-%#X], %sternal xcvr, addr %!\n",
ioaddr, irq, mem_start, mem_end, if_port ? "in" : "ex", nic->node_addr);
return (1);
}
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
struct nic *t507_probe(struct nic *nic, unsigned short *probe_addrs)
{
static unsigned char init_ID_done = 0;
unsigned short lrs_state = 0xff;
static unsigned short io_addrs[] = { 0x300, 0x320, 0x340, 0x280, 0 };
unsigned short *p;
int i;
if (init_ID_done == 0)
{
/* Send the ID sequence to the ID_PORT to enable the board */
outb(0x00, ID_PORT);
for (i = 0; i < 255; ++i)
{
outb(lrs_state, ID_PORT);
lrs_state <<= 1;
if (lrs_state & 0x100)
lrs_state ^= 0xe7;
}
outb(0x00, ID_PORT);
init_ID_done = 1;
}
/* if probe_addrs is 0, then routine can use a hardwired default */
if (probe_addrs == 0)
probe_addrs = io_addrs;
for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
if (t507_probe1(nic, ioaddr))
break;
if (ioaddr != 0)
{
/* point to NIC specific routines */
i82586_reset(nic);
nic->reset = i82586_reset;
nic->poll = i82586_poll;
nic->transmit = i82586_transmit;
nic->disable = i82586_disable;
return nic;
}
/* else */
{
return 0;
}
}
#endif
#ifdef INCLUDE_NI5210
static int ni5210_probe2(void)
{
unsigned short i;
unsigned short shmem[10];
/* Fix the ISCP address and base. */
init_words[3] = scb_base;
init_words[7] = scb_base;
/* Write the words at 0xfff6. */
/* Write the words at 0x0000. */
memcpy((char *)(mem_end - 10), (char *)init_words, 10);
memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
if (*(unsigned short *)mem_start != 1)
return (0);
outb(0, ioaddr + NI52_RESET);
outb(0, ioaddr + I82586_ATTN);
udelay(32);
i = 50;
while (
shmem[iSCB_STATUS>>1] == 0)
{
if (--i == 0)
{
printf("i82586 initialisation timed out with status %hX, cmd %hX\n",
shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
break;
}
}
/* Issue channel-attn -- the 82586 won't start. */
outb(0, ioaddr + I82586_ATTN);
if (*(unsigned short *)mem_start != 0)
return (0);
return (1);
}
static int ni5210_probe1(struct nic *nic)
{
int i;
static Address mem_addrs[] = {
0xc0000, 0xc4000, 0xc8000, 0xcc000,
0xd0000, 0xd4000, 0xd8000, 0xdc000,
0xe0000, 0xe4000, 0xe8000, 0xec000,
0 };
Address *p;
if (inb(ioaddr + 6) != 0x0 || inb(ioaddr + 7) != 0x55)
return (0);
scb_base = -8192; /* assume 8k memory */
for (p = mem_addrs; (mem_start = *p) != 0; ++p)
if (mem_end = mem_start + 8192, ni5210_probe2())
break;
if (mem_start == 0)
return (0);
/* Get station address */
for (i = 0; i < ETH_ALEN; ++i)
{
nic->node_addr[i] = inb(ioaddr+i);
}
printf("\nNI5210 ioaddr %#hX, mem [%#X-%#X], addr %!\n",
ioaddr, mem_start, mem_end, nic->node_addr);
return (1);
}
struct nic *ni5210_probe(struct nic *nic, unsigned short *probe_addrs)
{
/* missing entries are addresses usually already used */
static unsigned short io_addrs[] = {
0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230, 0x238,
0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270, /*Par*/
0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0, 0x2B8,
0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0, /*Ser*/
0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330, 0x338,
0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370, /*Par*/
0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, /*Vid,Par*/
0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, /*Ser*/
0x0
};
unsigned short *p;
int i;
/* if probe_addrs is 0, then routine can use a hardwired default */
if (probe_addrs == 0)
probe_addrs = io_addrs;
for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
if (ni5210_probe1(nic))
break;
if (ioaddr != 0)
{
/* point to NIC specific routines */
i82586_reset(nic);
nic->reset = i82586_reset;
nic->poll = i82586_poll;
nic->transmit = i82586_transmit;
nic->disable = i82586_disable;
return nic;
}
/* else */
{
return 0;
}
}
#endif
#ifdef INCLUDE_EXOS205
/*
* Code to download to I186 in EXOS205
*/
static unsigned char exos_i186_init[] =
{
0x08,0x00,0x14,0x00,0x00,0x00,0xaa,0xfa,0x33,0xc0,0xba,0xfe,0xff,0xef,0xb8,0xf8,
0xff,0xe7,0xa0,0xb8,0x7c,0x00,0xe7,0xa4,0xb8,0xbc,0x80,0xe7,0xa8,0x8c,0xc8,0x8e,
0xd8,0xbb,0x2f,0x0e,0xc6,0x07,0xa5,0x33,0xc9,0xeb,0x00,0xeb,0x00,0xeb,0x00,0xe2,
0xf8,0xbe,0x2c,0x0e,0xba,0x02,0x05,0x33,0xdb,0xb9,0x03,0x00,0xec,0x24,0x0f,0x8a,
0xe0,0x02,0xd8,0x42,0x42,0xec,0x02,0xd8,0xd0,0xe0,0xd0,0xe0,0xd0,0xe0,0xd0,0xe0,
0x0a,0xc4,0x88,0x04,0x42,0x42,0x46,0xe2,0xe3,0x8a,0xe3,0xd0,0xec,0xd0,0xec,0xd0,
0xec,0xd0,0xec,0x80,0xe3,0x0f,0x02,0xe3,0x80,0xf4,0x05,0xec,0x3a,0xe0,0x74,0x05,
0xc6,0x04,0x5a,0xeb,0xfe,0xc6,0x04,0x55,0x33,0xc0,0x8e,0xd8,0xbe,0x38,0x00,0xc7,
0x04,0xce,0x0e,0x46,0x46,0xc7,0x04,0x00,0xff,0xfb,0xba,0x3c,0x00,0xb8,0x03,0x00,
0xef,0x33,0xdb,0x33,0xc9,0xbd,0x04,0x0f,0x90,0x90,0x90,0x90,0xe2,0xfa,0x43,0x2e,
0x89,0x5e,0x00,0xeb,0xf3,0x52,0xba,0x00,0x06,0xef,0x50,0x53,0x55,0xbd,0xf8,0x0e,
0x2e,0x8b,0x5e,0x00,0x43,0x2e,0x89,0x5e,0x00,0xba,0x22,0x00,0xb8,0x00,0x80,0xef,
0x5d,0x5b,0x58,0x5a,0xcf,0x49,0x4e,0x54,0x52,0x20,0x63,0x6e,0x74,0x2d,0x3e,0x00,
0x00,0x4c,0x4f,0x4f,0x50,0x20,0x63,0x6e,0x74,0x2d,0x3e,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x30,0x0e,0x00,0xff,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,00
};
/* These offsets are from the end of the i186 download code */
#define OFFSET_SEMA 0x1D1
#define OFFSET_ADDR 0x1D7
static int exos205_probe2(void)
{
unsigned short i;
unsigned short shmem[10];
/* Fix the ISCP address and base. */
init_words[3] = scb_base;
init_words[7] = scb_base;
/* Write the words at 0xfff6. */
/* Write the words at 0x0000. */
memcpy((char *)(mem_end - 10), (char *)init_words, 10);
memcpy((char *)mem_start, (char *)&init_words[5], sizeof(init_words) - 10);
if (*(unsigned short *)mem_start != 1)
return (0);
outb(0, ioaddr + EXOS205_RESET);
outb(0, ioaddr + I82586_ATTN);
i = 50;
while (
shmem[iSCB_STATUS>>1] == 0)
{
if (--i == 0)
{
printf("i82586 initialisation timed out with status %hX, cmd %hX\n",
shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]);
break;
}
}
/* Issue channel-attn -- the 82586 won't start. */
outb(0, ioaddr + I82586_ATTN);
if (*(unsigned short *)mem_start != 0)
return (0);
return (1);
}
static int exos205_probe1(struct nic *nic)
{
int i;
/* If you know the other addresses please let me know */
static Address mem_addrs[] = {
0xcc000, 0 };
Address *p;
scb_base = -16384; /* assume 8k memory */
for (p = mem_addrs; (mem_start = *p) != 0; ++p)
if (mem_end = mem_start + 16384, exos205_probe2())
break;
if (mem_start == 0)
return (0);
/* Get station address */
for (i = 0; i < ETH_ALEN; ++i)
{
nic->node_addr[i] = inb(ioaddr+i);
}
printf("\nEXOS205 ioaddr %#hX, mem [%#X-%#X], addr %!\n",
ioaddr, mem_start, mem_end, nic->node_addr);
return (1);
}
struct nic *exos205_probe(struct nic *nic, unsigned short *probe_addrs)
{
/* If you know the other addresses, please let me know */
static unsigned short io_addrs[] = {
0x310, 0x0
};
unsigned short *p;
int i;
/* if probe_addrs is 0, then routine can use a hardwired default */
if (probe_addrs == 0)
probe_addrs = io_addrs;
for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
if (exos205_probe1(nic))
break;
if (ioaddr != 0)
{
/* point to NIC specific routines */
i82586_reset(nic);
nic->reset = i82586_reset;
nic->poll = i82586_poll;
nic->transmit = i82586_transmit;
nic->disable = i82586_disable;
return nic;
}
/* else */
{
return 0;
}
}
#endif
+564
View File
@@ -0,0 +1,564 @@
/**************************************************************************
Etherboot - BOOTP/TFTP Bootstrap Program
LANCE NIC driver for Etherboot
Large portions borrowed from the Linux LANCE driver by Donald Becker
Ken Yap, July 1997
***************************************************************************/
/*
* 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, or (at
* your option) any later version.
*/
/* to get some global routines like printf */
#include "etherboot.h"
/* to get the interface to the body of the program */
#include "nic.h"
#ifdef INCLUDE_LANCE
#include "pci.h"
#endif
#include "cards.h"
/* Offsets from base I/O address */
#if defined(INCLUDE_NE2100) || defined(INCLUDE_LANCE)
#define LANCE_ETH_ADDR 0x0
#define LANCE_DATA 0x10
#define LANCE_ADDR 0x12
#define LANCE_RESET 0x14
#define LANCE_BUS_IF 0x16
#define LANCE_TOTAL_SIZE 0x18
#endif
#ifdef INCLUDE_NI6510
#define LANCE_ETH_ADDR 0x8
#define LANCE_DATA 0x0
#define LANCE_ADDR 0x2
#define LANCE_RESET 0x4
#define LANCE_BUS_IF 0x6
#define LANCE_TOTAL_SIZE 0x10
#endif
/* lance_poll() now can use multiple Rx buffers to prevent packet loss. Set
* Set LANCE_LOG_RX_BUFFERS to 0..7 for 1, 2, 4, 8, 16, 32, 64 or 128 Rx
* buffers. Usually 4 (=16 Rx buffers) is a good value. (Andreas Neuhaus)
* Decreased to 2 (=4 Rx buffers) (Ken Yap, 20010305) */
#define LANCE_LOG_RX_BUFFERS 2 /* Use 2^2=4 Rx buffers */
#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
struct lance_init_block
{
unsigned short mode;
unsigned char phys_addr[ETH_ALEN];
unsigned long filter[2];
Address rx_ring;
Address tx_ring;
};
struct lance_rx_head
{
union {
Address base;
unsigned char addr[4];
} u;
short buf_length; /* 2s complement */
short msg_length;
};
struct lance_tx_head
{
union {
Address base;
unsigned char addr[4];
} u;
short buf_length; /* 2s complement */
short misc;
};
struct lance_interface
{
struct lance_init_block init_block;
struct lance_rx_head rx_ring[RX_RING_SIZE];
struct lance_tx_head tx_ring;
unsigned char rbuf[RX_RING_SIZE][ETH_FRAME_LEN+4];
unsigned char tbuf[ETH_FRAME_LEN];
/*
* Do not alter the order of the struct members above;
* the hardware depends on the correct alignment.
*/
int rx_idx;
};
#define LANCE_MUST_PAD 0x00000001
#define LANCE_ENABLE_AUTOSELECT 0x00000002
#define LANCE_SELECT_PHONELINE 0x00000004
#define LANCE_MUST_UNRESET 0x00000008
/* A mapping from the chip ID number to the part number and features.
These are from the datasheets -- in real life the '970 version
reportedly has the same ID as the '965. */
static const struct lance_chip_type
{
int id_number;
const char *name;
int flags;
} chip_table[] = {
{0x0000, "LANCE 7990", /* Ancient lance chip. */
LANCE_MUST_PAD + LANCE_MUST_UNRESET},
{0x0003, "PCnet/ISA 79C960", /* 79C960 PCnet/ISA. */
LANCE_ENABLE_AUTOSELECT},
{0x2260, "PCnet/ISA+ 79C961", /* 79C961 PCnet/ISA+, Plug-n-Play. */
LANCE_ENABLE_AUTOSELECT},
{0x2420, "PCnet/PCI 79C970", /* 79C970 or 79C974 PCnet-SCSI, PCI. */
LANCE_ENABLE_AUTOSELECT},
/* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call
it the PCnet32. */
{0x2430, "PCnet32", /* 79C965 PCnet for VL bus. */
LANCE_ENABLE_AUTOSELECT},
{0x2621, "PCnet/PCI-II 79C970A", /* 79C970A PCInetPCI II. */
LANCE_ENABLE_AUTOSELECT},
{0x2625, "PCnet-FAST III 79C973", /* 79C973 PCInet-FAST III. */
LANCE_ENABLE_AUTOSELECT},
{0x2626, "PCnet/HomePNA 79C978",
LANCE_ENABLE_AUTOSELECT|LANCE_SELECT_PHONELINE},
{0x0, "PCnet (unknown)",
LANCE_ENABLE_AUTOSELECT},
};
/* Define a macro for converting program addresses to real addresses */
#undef virt_to_bus
#define virt_to_bus(x) ((unsigned long)x)
static int chip_version;
static int lance_version;
static unsigned short ioaddr;
#ifndef INCLUDE_LANCE
static int dma;
#endif
static struct lance_interface *lp;
/* additional 8 bytes for 8-byte alignment space */
#ifdef USE_LOWMEM_BUFFER
#define lance ((char *)0x10000 - (sizeof(struct lance_interface)+8))
#else
static char lance[sizeof(struct lance_interface)+8];
#endif
#ifndef INCLUDE_LANCE
/* DMA defines and helper routines */
/* DMA controller registers */
#define DMA1_CMD_REG 0x08 /* command register (w) */
#define DMA1_STAT_REG 0x08 /* status register (r) */
#define DMA1_REQ_REG 0x09 /* request register (w) */
#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
#define DMA1_MODE_REG 0x0B /* mode register (w) */
#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
#define DMA2_CMD_REG 0xD0 /* command register (w) */
#define DMA2_STAT_REG 0xD0 /* status register (r) */
#define DMA2_REQ_REG 0xD2 /* request register (w) */
#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
#define DMA2_MODE_REG 0xD6 /* mode register (w) */
#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
/* enable/disable a specific DMA channel */
static void enable_dma(unsigned int dmanr)
{
if (dmanr <= 3)
outb_p(dmanr, DMA1_MASK_REG);
else
outb_p(dmanr & 3, DMA2_MASK_REG);
}
static void disable_dma(unsigned int dmanr)
{
if (dmanr <= 3)
outb_p(dmanr | 4, DMA1_MASK_REG);
else
outb_p((dmanr & 3) | 4, DMA2_MASK_REG);
}
/* set mode (above) for a specific DMA channel */
static void set_dma_mode(unsigned int dmanr, char mode)
{
if (dmanr <= 3)
outb_p(mode | dmanr, DMA1_MODE_REG);
else
outb_p(mode | (dmanr&3), DMA2_MODE_REG);
}
#endif /* !INCLUDE_LANCE */
/**************************************************************************
RESET - Reset adapter
***************************************************************************/
static void lance_reset(struct nic *nic)
{
int i;
Address l;
/* Reset the LANCE */
(void)inw(ioaddr+LANCE_RESET);
/* Un-Reset the LANCE, needed only for the NE2100 */
if (chip_table[lance_version].flags & LANCE_MUST_UNRESET)
outw(0, ioaddr+LANCE_RESET);
if (chip_table[lance_version].flags & LANCE_ENABLE_AUTOSELECT)
{
/* This is 79C960 specific; Turn on auto-select of media
(AUI, BNC). */
outw(0x2, ioaddr+LANCE_ADDR);
/* Don't touch 10base2 power bit. */
outw(inw(ioaddr+LANCE_BUS_IF) | 0x2, ioaddr+LANCE_BUS_IF);
}
/* HomePNA cards need to explicitly pick the phoneline interface.
* Some of these cards have ethernet interfaces as well, this
* code might require some modification for those.
*/
if (chip_table[lance_version].flags & LANCE_SELECT_PHONELINE) {
short media, check ;
/* this is specific to HomePNA cards... */
outw(49, ioaddr+0x12) ;
media = inw(ioaddr+0x16) ;
#ifdef DEBUG
printf("media was %d\n", media) ;
#endif
media &= ~3 ;
media |= 1 ;
#ifdef DEBUG
printf("media changed to %d\n", media) ;
#endif
media &= ~3 ;
media |= 1 ;
outw(49, ioaddr+0x12) ;
outw(media, ioaddr+0x16) ;
outw(49, ioaddr+0x12) ;
check = inw(ioaddr+0x16) ;
#ifdef DEBUG
printf("check %s, media was set properly\n",
check == media ? "passed" : "FAILED" ) ;
#endif
}
/* Re-initialise the LANCE, and start it when done. */
/* Set station address */
for (i = 0; i < ETH_ALEN; ++i)
lp->init_block.phys_addr[i] = nic->node_addr[i];
/* Preset the receive ring headers */
for (i=0; i<RX_RING_SIZE; i++) {
lp->rx_ring[i].buf_length = -ETH_FRAME_LEN-4;
/* OWN */
lp->rx_ring[i].u.base = virt_to_bus(lp->rbuf[i]) & 0xffffff;
/* we set the top byte as the very last thing */
lp->rx_ring[i].u.addr[3] = 0x80;
}
lp->rx_idx = 0;
lp->init_block.mode = 0x0; /* enable Rx and Tx */
l = (Address)virt_to_bus(&lp->init_block);
outw(0x1, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
outw((short)l, ioaddr+LANCE_DATA);
outw(0x2, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
outw((short)(l >> 16), ioaddr+LANCE_DATA);
outw(0x4, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
outw(0x915, ioaddr+LANCE_DATA);
outw(0x0, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
outw(0x4, ioaddr+LANCE_DATA); /* stop */
outw(0x1, ioaddr+LANCE_DATA); /* init */
for (i = 10000; i > 0; --i)
if (inw(ioaddr+LANCE_DATA) & 0x100)
break;
#ifdef DEBUG
if (i <= 0)
printf("Init timed out\n");
#endif
/* Apparently clearing the InitDone bit here triggers a bug
in the '974. (Mark Stockton) */
outw(0x2, ioaddr+LANCE_DATA); /* start */
}
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
static int lance_poll(struct nic *nic)
{
int status;
status = lp->rx_ring[lp->rx_idx].u.base >> 24;
if (status & 0x80)
return (0);
#ifdef DEBUG
printf("LANCE packet received rx_ring.u.base %X mcnt %hX csr0 %hX\n",
lp->rx_ring[lp->rx_idx].u.base, lp->rx_ring[lp->rx_idx].msg_length,
inw(ioaddr+LANCE_DATA));
#endif
if (status == 0x3)
memcpy(nic->packet, lp->rbuf[lp->rx_idx], nic->packetlen = lp->rx_ring[lp->rx_idx].msg_length);
/* Andrew Boyd of QNX reports that some revs of the 79C765
clear the buffer length */
lp->rx_ring[lp->rx_idx].buf_length = -ETH_FRAME_LEN-4;
lp->rx_ring[lp->rx_idx].u.addr[3] |= 0x80; /* prime for next receive */
/* I'm not sure if the following is still ok with multiple Rx buffers, but it works */
outw(0x0, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
outw(0x500, ioaddr+LANCE_DATA); /* clear receive + InitDone */
/* Switch to the next Rx ring buffer */
lp->rx_idx = (lp->rx_idx + 1) & RX_RING_MOD_MASK;
return (status == 0x3);
}
/**************************************************************************
TRANSMIT - Transmit a frame
***************************************************************************/
static void lance_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
unsigned long time;
/* copy the packet to ring buffer */
memcpy(lp->tbuf, d, ETH_ALEN); /* dst */
memcpy(&lp->tbuf[ETH_ALEN], nic->node_addr, ETH_ALEN); /* src */
lp->tbuf[ETH_ALEN+ETH_ALEN] = t >> 8; /* type */
lp->tbuf[ETH_ALEN+ETH_ALEN+1] = t; /* type */
memcpy(&lp->tbuf[ETH_HLEN], p, s);
s += ETH_HLEN;
if (chip_table[chip_version].flags & LANCE_MUST_PAD)
while (s < ETH_ZLEN) /* pad to min length */
lp->tbuf[s++] = 0;
lp->tx_ring.buf_length = -s;
lp->tx_ring.misc = 0x0;
/* OWN, STP, ENP */
lp->tx_ring.u.base = virt_to_bus(lp->tbuf) & 0xffffff;
/* we set the top byte as the very last thing */
lp->tx_ring.u.addr[3] = 0x83;
/* Trigger an immediate send poll */
outw(0x0, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR); /* as in the datasheets... */
/* Klaus Espenlaub: the value below was 0x48, but that enabled the
* interrupt line, causing a hang if for some reasone the interrupt
* controller had the LANCE interrupt enabled. I have no idea why
* nobody ran into this before... */
outw(0x08, ioaddr+LANCE_DATA);
/* wait for transmit complete */
time = currticks() + TICKS_PER_SEC; /* wait one second */
while (currticks() < time && (lp->tx_ring.u.base & 0x80000000) != 0)
;
if ((lp->tx_ring.u.base & 0x80000000) != 0)
printf("LANCE timed out on transmit\n");
(void)inw(ioaddr+LANCE_ADDR);
outw(0x200, ioaddr+LANCE_DATA); /* clear transmit + InitDone */
#ifdef DEBUG
printf("tx_ring.u.base %X tx_ring.buf_length %hX tx_ring.misc %hX csr0 %hX\n",
lp->tx_ring.u.base, lp->tx_ring.buf_length, lp->tx_ring.misc,
inw(ioaddr+LANCE_DATA));
#endif
}
static void lance_disable(struct nic *nic)
{
(void)inw(ioaddr+LANCE_RESET);
if (chip_table[lance_version].flags & LANCE_MUST_UNRESET)
outw(0, ioaddr+LANCE_RESET);
outw(0, ioaddr+LANCE_ADDR);
outw(0x0004, ioaddr+LANCE_DATA); /* stop the LANCE */
#ifndef INCLUDE_LANCE
disable_dma(dma);
#endif
}
#ifdef INCLUDE_LANCE
static int lance_probe1(struct nic *nic, struct pci_device *pci)
#else
static int lance_probe1(struct nic *nic)
#endif
{
int reset_val ;
unsigned int i;
Address l;
short dma_channels;
#ifndef INCLUDE_LANCE
static const char dmas[] = { 5, 6, 7, 3 };
#endif
reset_val = inw(ioaddr+LANCE_RESET);
outw(reset_val, ioaddr+LANCE_RESET);
#if 1 /* Klaus Espenlaub -- was #ifdef INCLUDE_NE2100*/
outw(0x0, ioaddr+LANCE_ADDR); /* Switch to window 0 */
if (inw(ioaddr+LANCE_DATA) != 0x4)
return (-1);
#endif
outw(88, ioaddr+LANCE_ADDR); /* Get the version of the chip */
if (inw(ioaddr+LANCE_ADDR) != 88)
lance_version = 0;
else
{
chip_version = inw(ioaddr+LANCE_DATA);
outw(89, ioaddr+LANCE_ADDR);
chip_version |= inw(ioaddr+LANCE_DATA) << 16;
if ((chip_version & 0xfff) != 0x3)
return (-1);
chip_version = (chip_version >> 12) & 0xffff;
for (lance_version = 1; chip_table[lance_version].id_number != 0; ++lance_version)
if (chip_table[lance_version].id_number == chip_version)
break;
}
/* make sure data structure is 8-byte aligned */
l = ((Address)lance + 7) & ~7;
lp = (struct lance_interface *)l;
lp->init_block.mode = 0x3; /* disable Rx and Tx */
lp->init_block.filter[0] = lp->init_block.filter[1] = 0x0;
/* using multiple Rx buffer and a single Tx buffer */
lp->init_block.rx_ring = (virt_to_bus(&lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS;
lp->init_block.tx_ring = virt_to_bus(&lp->tx_ring) & 0xffffff;
l = virt_to_bus(&lp->init_block);
outw(0x1, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
outw((unsigned short)l, ioaddr+LANCE_DATA);
outw(0x2, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
outw((unsigned short)(l >> 16), ioaddr+LANCE_DATA);
outw(0x4, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
outw(0x915, ioaddr+LANCE_DATA);
outw(0x0, ioaddr+LANCE_ADDR);
(void)inw(ioaddr+LANCE_ADDR);
/* Get station address */
for (i = 0; i < ETH_ALEN; ++i) {
nic->node_addr[i] = inb(ioaddr+LANCE_ETH_ADDR+i);
}
#ifndef INCLUDE_LANCE
/* now probe for DMA channel */
dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0xf) |
(inb(DMA2_STAT_REG) & 0xf0);
/* need to fix when PCI provides DMA info */
for (i = 0; i < (sizeof(dmas)/sizeof(dmas[0])); ++i)
{
int j;
dma = dmas[i];
/* Don't enable a permanently busy DMA channel,
or the machine will hang */
if (dma_channels & (1 << dma))
continue;
outw(0x7f04, ioaddr+LANCE_DATA); /* clear memory error bits */
set_dma_mode(dma, DMA_MODE_CASCADE);
enable_dma(dma);
outw(0x1, ioaddr+LANCE_DATA); /* init */
for (j = 100; j > 0; --j)
if (inw(ioaddr+LANCE_DATA) & 0x900)
break;
if (inw(ioaddr+LANCE_DATA) & 0x100)
break;
else
disable_dma(dma);
}
if (i >= (sizeof(dmas)/sizeof(dmas[0])))
dma = 0;
printf("\n%s base %#X, DMA %d, addr %!\n",
chip_table[lance_version].name, ioaddr, dma, nic->node_addr);
#else
printf(" %s base %#hX, addr %!\n", chip_table[lance_version].name, ioaddr, nic->node_addr);
#endif
if (chip_table[chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
/* Turn on auto-select of media (10baseT or BNC) so that the
* user watch the LEDs. */
outw(0x0002, ioaddr+LANCE_ADDR);
/* Don't touch 10base2 power bit. */
outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
}
return (lance_version);
}
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
#ifdef INCLUDE_LANCE
struct nic *lancepci_probe(struct nic *nic, unsigned short *probe_addrs, struct pci_device *pci)
#endif
#ifdef INCLUDE_NE2100
struct nic *ne2100_probe(struct nic *nic, unsigned short *probe_addrs)
#endif
#ifdef INCLUDE_NI6510
struct nic *ni6510_probe(struct nic *nic, unsigned short *probe_addrs)
#endif
{
unsigned short *p;
#ifndef INCLUDE_LANCE
static unsigned short io_addrs[] = { 0x300, 0x320, 0x340, 0x360, 0 };
#endif
/* if probe_addrs is 0, then routine can use a hardwired default */
if (probe_addrs == 0) {
#ifdef INCLUDE_LANCE
return 0;
#else
probe_addrs = io_addrs;
#endif
}
for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
{
char offset15, offset14 = inb(ioaddr + 14);
unsigned short pci_cmd;
#ifdef INCLUDE_NE2100
if ((offset14 == 0x52 || offset14 == 0x57) &&
((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
if (lance_probe1(nic) >= 0)
break;
#endif
#ifdef INCLUDE_NI6510
if ((offset14 == 0x00 || offset14 == 0x52) &&
((offset15 = inb(ioaddr + 15)) == 0x55 || offset15 == 0x44))
if (lance_probe1(nic) >= 0)
break;
#endif
#ifdef INCLUDE_LANCE
adjust_pci_device(pci);
if (lance_probe1(nic, pci) >= 0)
break;
#endif
}
/* if board found */
if (ioaddr != 0)
{
/* point to NIC specific routines */
lance_reset(nic);
nic->reset = lance_reset;
nic->poll = lance_poll;
nic->transmit = lance_transmit;
nic->disable = lance_disable;
return nic;
}
/* no board found */
return 0;
}
+187
View File
@@ -0,0 +1,187 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H
/*
* This file contains the definitions for the x86 IO instructions
* inb/inw/inl/outb/outw/outl and the "string versions" of the same
* (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
* versions of the single-IO instructions (inb_p/inw_p/..).
*
* This file is not meant to be obfuscating: it's just complicated
* to (a) handle it all in a way that makes gcc able to optimize it
* as well as possible and (b) trying to avoid writing the same thing
* over and over again with slight variations and possibly making a
* mistake somewhere.
*/
/*
* Thanks to James van Artsdalen for a better timing-fix than
* the two short jumps: using outb's to a nonexistent port seems
* to guarantee better timings even on fast machines.
*
* On the other hand, I'd like to be sure of a non-existent port:
* I feel a bit unsafe about using 0x80 (should be safe, though)
*
* Linus
*/
#ifdef SLOW_IO_BY_JUMPING
#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
#else
#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
#endif
#ifdef REALLY_SLOW_IO
#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
#else
#define SLOW_DOWN_IO __SLOW_DOWN_IO
#endif
/*
* readX/writeX() are used to access memory mapped devices. On some
* architectures the memory mapped IO stuff needs to be accessed
* differently. On the x86 architecture, we just read/write the
* memory location directly.
*/
#define readb(addr) (*(volatile unsigned char *) (addr))
#define readw(addr) (*(volatile unsigned short *) (addr))
#define readl(addr) (*(volatile unsigned int *) (addr))
#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
/*
* Again, i386 does not require mem IO specific function.
*/
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
/*
* Talk about misusing macros..
*/
#define __OUT1(s,x) \
extern void __out##s(unsigned x value, unsigned short port); \
extern inline void __out##s(unsigned x value, unsigned short port) {
#define __OUT2(s,s1,s2) \
__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
#define __OUT(s,s1,x) \
__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
#define __IN1(s,x) \
extern unsigned x __in##s(unsigned short port); \
extern inline unsigned x __in##s(unsigned short port) { unsigned x _v;
#define __IN2(s,s1,s2) \
__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
#define __IN(s,s1,x,i...) \
__IN1(s,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
__IN1(s##c,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
__IN1(s##_p,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
__IN1(s##c_p,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
#define __INS(s) \
extern void ins##s(unsigned short port, void * addr, unsigned long count); \
extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
#define __OUTS(s) \
extern void outs##s(unsigned short port, const void * addr, unsigned long count); \
extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
__IN(b,"", char)
__IN(w,"",short)
__IN(l,"", long)
__OUT(b,"b",char)
__OUT(w,"w",short)
__OUT(l,,int)
__INS(b)
__INS(w)
__INS(l)
__OUTS(b)
__OUTS(w)
__OUTS(l)
/*
* Note that due to the way __builtin_constant_p() works, you
* - can't use it inside a inline function (it will never be true)
* - you don't have to worry about side effects within the __builtin..
*/
#define outb(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outbc((val),(port)) : \
__outb((val),(port)))
#define inb(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inbc(port) : \
__inb(port))
#define outb_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outbc_p((val),(port)) : \
__outb_p((val),(port)))
#define inb_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inbc_p(port) : \
__inb_p(port))
#define outw(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outwc((val),(port)) : \
__outw((val),(port)))
#define inw(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inwc(port) : \
__inw(port))
#define outw_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outwc_p((val),(port)) : \
__outw_p((val),(port)))
#define inw_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inwc_p(port) : \
__inw_p(port))
#define outl(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outlc((val),(port)) : \
__outl((val),(port)))
#define inl(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inlc(port) : \
__inl(port))
#define outl_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__outlc_p((val),(port)) : \
__outl_p((val),(port)))
#define inl_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
__inlc_p(port) : \
__inl_p(port))
#endif
+291
View File
@@ -0,0 +1,291 @@
/*
* Taken from Linux /usr/include/asm/string.h
* All except memcpy, memmove, memset and memcmp removed.
*/
#ifndef _I386_STRING_H_
#define _I386_STRING_H_
/*
* This string-include defines all string functions as inline
* functions. Use gcc. It also assumes ds=es=data space, this should be
* normal. Most of the string-functions are rather heavily hand-optimized,
* see especially strtok,strstr,str[c]spn. They should work, but are not
* very easy to understand. Everything is done entirely within the register
* set, making the functions fast and clean. String instructions have been
* used through-out, making for "slightly" unclear code :-)
*
* NO Copyright (C) 1991, 1992 Linus Torvalds,
* consider these trivial functions to be PD.
*/
typedef int size_t;
extern void *__memcpy(void * to, const void * from, size_t n);
extern void *__constant_memcpy(void * to, const void * from, size_t n);
extern void *memmove(void * dest,const void * src, size_t n);
extern void *__memset_generic(void * s, char c,size_t count);
extern void *__constant_c_memset(void * s, unsigned long c, size_t count);
extern void *__constant_c_and_count_memset(void * s, unsigned long pattern, size_t count);
extern inline void * __memcpy(void * to, const void * from, size_t n)
{
int d0, d1, d2;
__asm__ __volatile__(
"cld\n\t"
"rep ; movsl\n\t"
"testb $2,%b4\n\t"
"je 1f\n\t"
"movsw\n"
"1:\ttestb $1,%b4\n\t"
"je 2f\n\t"
"movsb\n"
"2:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
: "memory");
return (to);
}
/*
* This looks horribly ugly, but the compiler can optimize it totally,
* as the count is constant.
*/
extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
{
switch (n) {
case 0:
return to;
case 1:
*(unsigned char *)to = *(const unsigned char *)from;
return to;
case 2:
*(unsigned short *)to = *(const unsigned short *)from;
return to;
case 3:
*(unsigned short *)to = *(const unsigned short *)from;
*(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
return to;
case 4:
*(unsigned long *)to = *(const unsigned long *)from;
return to;
case 6: /* for Ethernet addresses */
*(unsigned long *)to = *(const unsigned long *)from;
*(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
return to;
case 8:
*(unsigned long *)to = *(const unsigned long *)from;
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
return to;
case 12:
*(unsigned long *)to = *(const unsigned long *)from;
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
return to;
case 16:
*(unsigned long *)to = *(const unsigned long *)from;
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
return to;
case 20:
*(unsigned long *)to = *(const unsigned long *)from;
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
*(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
return to;
}
#define COMMON(x) \
__asm__ __volatile__( \
"cld\n\t" \
"rep ; movsl" \
x \
: "=&c" (d0), "=&D" (d1), "=&S" (d2) \
: "0" (n/4),"1" ((long) to),"2" ((long) from) \
: "memory");
{
int d0, d1, d2;
switch (n % 4) {
case 0: COMMON(""); return to;
case 1: COMMON("\n\tmovsb"); return to;
case 2: COMMON("\n\tmovsw"); return to;
default: COMMON("\n\tmovsw\n\tmovsb"); return to;
}
}
#undef COMMON
}
#define __HAVE_ARCH_MEMCPY
#define memcpy(t, f, n) \
(__builtin_constant_p(n) ? \
__constant_memcpy((t),(f),(n)) : \
__memcpy((t),(f),(n)))
#define __HAVE_ARCH_MEMMOVE
extern inline void * memmove(void * dest,const void * src, size_t n)
{
int d0, d1, d2;
if (dest<src)
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"movsb"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),"1" (src),"2" (dest)
: "memory");
else
__asm__ __volatile__(
"std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),
"1" (n-1+(const char *)src),
"2" (n-1+(char *)dest)
:"memory");
return dest;
}
#define memcmp __builtin_memcmp
extern inline void * __memset_generic(void * s, char c,size_t count)
{
int d0, d1;
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"stosb"
: "=&c" (d0), "=&D" (d1)
:"a" (c),"1" (s),"0" (count)
:"memory");
return s;
}
/* we might want to write optimized versions of these later */
#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
/*
* memset(x,0,y) is a reasonably common thing to do, so we want to fill
* things 32 bits at a time even when we don't know the size of the
* area at compile-time..
*/
extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
{
int d0, d1;
__asm__ __volatile__(
"cld\n\t"
"rep ; stosl\n\t"
"testb $2,%b3\n\t"
"je 1f\n\t"
"stosw\n"
"1:\ttestb $1,%b3\n\t"
"je 2f\n\t"
"stosb\n"
"2:"
: "=&c" (d0), "=&D" (d1)
:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
:"memory");
return (s);
}
/*
* This looks horribly ugly, but the compiler can optimize it totally,
* as we by now know that both pattern and count is constant..
*/
extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
{
switch (count) {
case 0:
return s;
case 1:
*(unsigned char *)s = pattern;
return s;
case 2:
*(unsigned short *)s = pattern;
return s;
case 3:
*(unsigned short *)s = pattern;
*(2+(unsigned char *)s) = pattern;
return s;
case 4:
*(unsigned long *)s = pattern;
return s;
}
#define COMMON(x) \
__asm__ __volatile__("cld\n\t" \
"rep ; stosl" \
x \
: "=&c" (d0), "=&D" (d1) \
: "a" (pattern),"0" (count/4),"1" ((long) s) \
: "memory")
{
int d0, d1;
switch (count % 4) {
case 0: COMMON(""); return s;
case 1: COMMON("\n\tstosb"); return s;
case 2: COMMON("\n\tstosw"); return s;
default: COMMON("\n\tstosw\n\tstosb"); return s;
}
}
#undef COMMON
}
#define __constant_c_x_memset(s, c, count) \
(__builtin_constant_p(count) ? \
__constant_c_and_count_memset((s),(c),(count)) : \
__constant_c_memset((s),(c),(count)))
#define __memset(s, c, count) \
(__builtin_constant_p(count) ? \
__constant_count_memset((s),(c),(count)) : \
__memset_generic((s),(c),(count)))
#define __HAVE_ARCH_MEMSET
#define memset(s, c, count) \
(__builtin_constant_p(c) ? \
__constant_c_x_memset((s),(c),(count)) : \
__memset((s),(c),(count)))
#define __HAVE_ARCH_STRNCMP
static inline int strncmp(const char * cs,const char * ct,size_t count)
{
register int __res;
int d0, d1, d2;
__asm__ __volatile__(
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
"3:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"4:"
:"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
:"1" (cs),"2" (ct),"3" (count));
return __res;
}
#define __HAVE_ARCH_STRLEN
static inline size_t strlen(const char * s)
{
int d0;
register int __res;
__asm__ __volatile__(
"repne\n\t"
"scasb\n\t"
"notl %0\n\t"
"decl %0"
:"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
return __res;
}
#endif
+1171
View File
File diff suppressed because it is too large. Load diff
+266
View File
@@ -0,0 +1,266 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
*
* 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.
*/
/* Based on "src/misc.c" in etherboot-5.0.5. */
#define GRUB 1
#include <etherboot.h>
void
sleep (int secs)
{
unsigned long tmo = currticks () + secs;
while (currticks () < tmo)
;
}
void
twiddle (void)
{
static unsigned long lastticks = 0;
static int count = 0;
static const char tiddles[]="-\\|/";
unsigned long ticks;
if (debug)
{
if ((ticks = currticks ()) == lastticks)
return;
lastticks = ticks;
grub_putchar (tiddles[(count++) & 3]);
grub_putchar ('\b');
}
}
/* Because Etherboot uses its own formats for the printf family,
define separate definitions from GRUB. */
/**************************************************************************
PRINTF and friends
Formats:
%[#]x - 4 bytes long (8 hex digits, lower case)
%[#]X - 4 bytes long (8 hex digits, upper case)
%[#]hx - 2 bytes int (4 hex digits, lower case)
%[#]hX - 2 bytes int (4 hex digits, upper case)
%[#]hhx - 1 byte int (2 hex digits, lower case)
%[#]hhX - 1 byte int (2 hex digits, upper case)
- optional # prefixes 0x or 0X
%d - decimal int
%c - char
%s - string
%@ - Internet address in ddd.ddd.ddd.ddd notation
%! - Ethernet address in xx:xx:xx:xx:xx:xx notation
Note: width specification not supported
**************************************************************************/
static int
etherboot_vsprintf (char *buf, const char *fmt, const int *dp)
{
char *p, *s;
s = buf;
for ( ; *fmt != '\0'; ++fmt)
{
if (*fmt != '%')
{
buf ? *s++ = *fmt : grub_putchar (*fmt);
continue;
}
if (*++fmt == 's')
{
for (p = (char *) *dp++; *p != '\0'; p++)
buf ? *s++ = *p : grub_putchar (*p);
}
else
{
/* Length of item is bounded */
char tmp[20], *q = tmp;
int alt = 0;
int shift = 28;
if (*fmt == '#')
{
alt = 1;
fmt++;
}
if (*fmt == 'h')
{
shift = 12;
fmt++;
}
if (*fmt == 'h')
{
shift = 4;
fmt++;
}
/*
* Before each format q points to tmp buffer
* After each format q points past end of item
*/
if ((*fmt | 0x20) == 'x')
{
/* With x86 gcc, sizeof(long) == sizeof(int) */
const long *lp = (const long *) dp;
long h = *lp++;
int ncase = (*fmt & 0x20);
dp = (const int *) lp;
if (alt)
{
*q++ = '0';
*q++ = 'X' | ncase;
}
for (; shift >= 0; shift -= 4)
*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
}
else if (*fmt == 'd')
{
int i = *dp++;
char *r;
if (i < 0)
{
*q++ = '-';
i = -i;
}
p = q; /* save beginning of digits */
do
{
*q++ = '0' + (i % 10);
i /= 10;
}
while (i);
/* reverse digits, stop in middle */
r = q; /* don't alter q */
while (--r > p)
{
i = *r;
*r = *p;
*p++ = i;
}
}
else if (*fmt == '@')
{
unsigned char *r;
union
{
long l;
unsigned char c[4];
}
u;
const long *lp = (const long *) dp;
u.l = *lp++;
dp = (const int *) lp;
for (r = &u.c[0]; r < &u.c[4]; ++r)
q += etherboot_sprintf (q, "%d.", *r);
--q;
}
else if (*fmt == '!')
{
char *r;
p = (char *) *dp++;
for (r = p + ETH_ALEN; p < r; ++p)
q += etherboot_sprintf (q, "%hhX:", *p);
--q;
}
else if (*fmt == 'c')
*q++ = *dp++;
else
*q++ = *fmt;
/* now output the saved string */
for (p = tmp; p < q; ++p)
buf ? *s++ = *p : grub_putchar (*p);
}
}
if (buf)
*s = '\0';
return (s - buf);
}
int
etherboot_sprintf (char *buf, const char *fmt, ...)
{
return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1);
}
void
etherboot_printf (const char *fmt, ...)
{
(void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1);
}
int
inet_aton (char *p, in_addr *addr)
{
unsigned long ip = 0;
int val;
int i;
for (i = 0; i < 4; i++)
{
val = getdec (&p);
if (val < 0 || val > 255)
return 0;
if (i != 3 && *p++ != '.')
return 0;
ip = (ip << 8) | val;
}
addr->s_addr = htonl (ip);
return 1;
}
int
getdec (char **ptr)
{
char *p = *ptr;
int ret = 0;
if (*p < '0' || *p > '9')
return -1;
while (*p >= '0' && *p <= '9')
{
ret = ret * 10 + (*p - '0');
p++;
}
*ptr = p;
return ret;
}
+739
View File
@@ -0,0 +1,739 @@
/* -*- Mode:C; c-basic-offset:4; -*- */
/*
natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
Copyright (C) 2001 Entity Cyber, Inc.
This development of this Etherboot driver was funded by
Sicom Systems: http://www.sicompos.com/
Author: Marty Connor (mdc@thinguin.org)
Adapted from a Linux driver which was written by Donald Becker
This software may be used and distributed according to the terms
of the GNU Public License (GPL), incorporated herein by reference.
Original Copyright Notice:
Written/copyright 1999-2001 by Donald Becker.
This software may be used and distributed according to the terms of
the GNU General Public License (GPL), incorporated herein by reference.
Drivers based on or derived from this code fall under the GPL and must
retain the authorship, copyright and license notice. This file is not
a complete program and may only be used when the entire operating
system is licensed under the GPL. License for under other terms may be
available. Contact the original author for details.
The original author may be reached as becker@scyld.com, or at
Scyld Computing Corporation
410 Severn Ave., Suite 210
Annapolis MD 21403
Support information and updates available at
http://www.scyld.com/network/netsemi.html
References:
http://www.scyld.com/expert/100mbps.html
http://www.scyld.com/expert/NWay.html
Datasheet is available from:
http://www.national.com/pf/DP/DP83815.html
*/
/* Revision History */
/*
29 May 2001 mdc 1.0
Initial Release. Tested with Netgear FA311 and FA312 boards
*/
/* Includes */
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "cards.h"
/* defines */
#define OWN 0x80000000
#define DSIZE 0x00000FFF
#define CRC_SIZE 4
/* Time in ticks before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*TICKS_PER_SEC)
#define TX_BUF_SIZE 1536
#define RX_BUF_SIZE 1536
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
/* helpful macroes if on a big_endian machine for changing byte order.
not strictly needed on Intel */
#define le16_to_cpu(val) (val)
#define cpu_to_le32(val) (val)
#define get_unaligned(ptr) (*(ptr))
#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
#define get_u16(ptr) (*(u16 *)(ptr))
#define virt_to_bus(x) ((unsigned long)x)
#define virt_to_le32desc(addr) virt_to_bus(addr)
enum pcistuff {
PCI_USES_IO = 0x01,
PCI_USES_MEM = 0x02,
PCI_USES_MASTER = 0x04,
PCI_ADDR0 = 0x08,
PCI_ADDR1 = 0x10,
};
/* MMIO operations required */
#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
/* Offsets to the device registers.
Unlike software-only systems, device drivers interact with complex hardware.
It's not useful to define symbolic names for every register bit in the
device.
*/
enum register_offsets {
ChipCmd = 0x00,
ChipConfig = 0x04,
EECtrl = 0x08,
PCIBusCfg = 0x0C,
IntrStatus = 0x10,
IntrMask = 0x14,
IntrEnable = 0x18,
TxRingPtr = 0x20,
TxConfig = 0x24,
RxRingPtr = 0x30,
RxConfig = 0x34,
ClkRun = 0x3C,
WOLCmd = 0x40,
PauseCmd = 0x44,
RxFilterAddr = 0x48,
RxFilterData = 0x4C,
BootRomAddr = 0x50,
BootRomData = 0x54,
SiliconRev = 0x58,
StatsCtrl = 0x5C,
StatsData = 0x60,
RxPktErrs = 0x60,
RxMissed = 0x68,
RxCRCErrs = 0x64,
PCIPM = 0x44,
PhyStatus = 0xC0,
MIntrCtrl = 0xC4,
MIntrStatus = 0xC8,
/* These are from the spec, around page 78... on a separate table. */
PGSEL = 0xCC,
PMDCSR = 0xE4,
TSTDAT = 0xFC,
DSPCFG = 0xF4,
SDCFG = 0x8C
};
/* Bit in ChipCmd. */
enum ChipCmdBits {
ChipReset = 0x100,
RxReset = 0x20,
TxReset = 0x10,
RxOff = 0x08,
RxOn = 0x04,
TxOff = 0x02,
TxOn = 0x01
};
/* Bits in the RxMode register. */
enum rx_mode_bits {
AcceptErr = 0x20,
AcceptRunt = 0x10,
AcceptBroadcast = 0xC0000000,
AcceptMulticast = 0x00200000,
AcceptAllMulticast = 0x20000000,
AcceptAllPhys = 0x10000000,
AcceptMyPhys = 0x08000000
};
typedef struct _BufferDesc {
u32 link;
volatile u32 cmdsts;
u32 bufptr;
u32 software_use;
} BufferDesc;
/* Bits in network_desc.status */
enum desc_status_bits {
DescOwn = 0x80000000,
DescMore = 0x40000000,
DescIntr = 0x20000000,
DescNoCRC = 0x10000000,
DescPktOK = 0x08000000,
RxTooLong = 0x00400000
};
/* Globals */
static int natsemi_debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
const char *nic_name;
static u32 SavedClkRun;
static unsigned short vendor, dev_id;
static unsigned long ioaddr;
static unsigned int cur_rx;
static unsigned int advertising;
static unsigned int rx_config;
static unsigned int tx_config;
/* Note: transmit and receive buffers and descriptors must be
longword aligned
*/
static BufferDesc txd __attribute__ ((aligned(4)));
static BufferDesc rxd[NUM_RX_DESC] __attribute__ ((aligned(4)));
#ifdef USE_LOWMEM_BUFFER
#define txb ((char *)0x10000 - TX_BUF_SIZE)
#define rxb ((char *)0x10000 - NUM_RX_DESC*RX_BUF_SIZE - TX_BUF_SIZE)
#else
static unsigned char txb[TX_BUF_SIZE] __attribute__ ((aligned(4)));
static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE] __attribute__ ((aligned(4)));
#endif
/* Function Prototypes */
struct nic *natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci);
static int eeprom_read(long addr, int location);
static int mdio_read(int phy_id, int location);
static void natsemi_init(struct nic *nic);
static void natsemi_reset(struct nic *nic);
static void natsemi_init_rxfilter(struct nic *nic);
static void natsemi_init_txd(struct nic *nic);
static void natsemi_init_rxd(struct nic *nic);
static void natsemi_set_rx_mode(struct nic *nic);
static void natsemi_check_duplex(struct nic *nic);
static void natsemi_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p);
static int natsemi_poll(struct nic *nic);
static void natsemi_disable(struct nic *nic);
/*
* Function: natsemi_probe
*
* Description: Retrieves the MAC address of the card, and sets up some
* globals required by other routines, and initializes the NIC, making it
* ready to send and receive packets.
*
* Side effects:
* leaves the ioaddress of the natsemi chip in the variable ioaddr.
* leaves the natsemi initialized, and ready to recieve packets.
*
* Returns: struct nic *: pointer to NIC data structure
*/
struct nic *
natsemi_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
{
int i;
int prev_eedata;
u32 tmp;
if (io_addrs == 0 || *io_addrs == 0)
return NULL;
/* initialize some commonly used globals */
ioaddr = *io_addrs & ~3;
vendor = pci->vendor;
dev_id = pci->dev_id;
nic_name = pci->name;
adjust_pci_device(pci);
/* natsemi has a non-standard PM control register
* in PCI config space. Some boards apparently need
* to be brought to D0 in this manner.
*/
pcibios_read_config_dword(pci->bus, pci->devfn, PCIPM, &tmp);
if (tmp & (0x03|0x100)) {
/* D0 state, disable PME assertion */
u32 newtmp = tmp & ~(0x03|0x100);
pcibios_write_config_dword(pci->bus, pci->devfn, PCIPM, newtmp);
}
/* get MAC address */
prev_eedata = eeprom_read(ioaddr, 6);
for (i = 0; i < 3; i++) {
int eedata = eeprom_read(ioaddr, i + 7);
nic->node_addr[i*2] = (eedata << 1) + (prev_eedata >> 15);
nic->node_addr[i*2+1] = eedata >> 7;
prev_eedata = eedata;
}
printf("\nnatsemi_probe: MAC addr %! at ioaddr %#hX\n",
nic->node_addr, ioaddr);
printf("natsemi_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id);
/* Reset the chip to erase any previous misconfiguration. */
outl(ChipReset, ioaddr + ChipCmd);
advertising = mdio_read(1, 4);
{
u32 chip_config = inl(ioaddr + ChipConfig);
printf("%s: Transceiver default autoneg. %s "
"10%s %s duplex.\n",
nic_name,
chip_config & 0x2000 ? "enabled, advertise" : "disabled, force",
chip_config & 0x4000 ? "0" : "",
chip_config & 0x8000 ? "full" : "half");
}
printf("%s: Transceiver status %hX advertising %hX\n",
nic_name, (int)inl(ioaddr + 0x84), advertising);
/* Disable PME:
* The PME bit is initialized from the EEPROM contents.
* PCI cards probably have PME disabled, but motherboard
* implementations may have PME set to enable WakeOnLan.
* With PME set the chip will scan incoming packets but
* nothing will be written to memory. */
SavedClkRun = inl(ioaddr + ClkRun);
outl(SavedClkRun & ~0x100, ioaddr + ClkRun);
/* initialize device */
natsemi_init(nic);
nic->reset = natsemi_init;
nic->poll = natsemi_poll;
nic->transmit = natsemi_transmit;
nic->disable = natsemi_disable;
return nic;
}
/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.
The EEPROM code is for the common 93c06/46 EEPROMs with 6 bit addresses.
*/
/* Delay between EEPROM clock transitions.
No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
a delay. */
#define eeprom_delay(ee_addr) inl(ee_addr)
enum EEPROM_Ctrl_Bits {
EE_ShiftClk = 0x04,
EE_DataIn = 0x01,
EE_ChipSelect = 0x08,
EE_DataOut = 0x02
};
#define EE_Write0 (EE_ChipSelect)
#define EE_Write1 (EE_ChipSelect | EE_DataIn)
/* The EEPROM commands include the alway-set leading bit. */
enum EEPROM_Cmds {
EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
};
static int eeprom_read(long addr, int location)
{
int i;
int retval = 0;
int ee_addr = addr + EECtrl;
int read_cmd = location | EE_ReadCmd;
outl(EE_Write0, ee_addr);
/* Shift the read command bits out. */
for (i = 10; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
outl(dataval, ee_addr);
eeprom_delay(ee_addr);
outl(dataval | EE_ShiftClk, ee_addr);
eeprom_delay(ee_addr);
}
outl(EE_ChipSelect, ee_addr);
eeprom_delay(ee_addr);
for (i = 0; i < 16; i++) {
outl(EE_ChipSelect | EE_ShiftClk, ee_addr);
eeprom_delay(ee_addr);
retval |= (inl(ee_addr) & EE_DataOut) ? 1 << i : 0;
outl(EE_ChipSelect, ee_addr);
eeprom_delay(ee_addr);
}
/* Terminate the EEPROM access. */
outl(EE_Write0, ee_addr);
outl(0, ee_addr);
return retval;
}
/* MII transceiver control section.
The 83815 series has an internal transceiver, and we present the
management registers as if they were MII connected. */
static int mdio_read(int phy_id, int location)
{
if (phy_id == 1 && location < 32)
return inl(ioaddr + 0x80 + (location<<2)) & 0xffff;
else
return 0xffff;
}
/* Function: natsemi_init
*
* Description: resets the ethernet controller chip and configures
* registers and data structures required for sending and receiving packets.
*
* Arguments: struct nic *nic: NIC data structure
*
* returns: void.
*/
static void
natsemi_init(struct nic *nic)
{
natsemi_reset(nic);
/* Disable PME:
* The PME bit is initialized from the EEPROM contents.
* PCI cards probably have PME disabled, but motherboard
* implementations may have PME set to enable WakeOnLan.
* With PME set the chip will scan incoming packets but
* nothing will be written to memory. */
outl(SavedClkRun & ~0x100, ioaddr + ClkRun);
natsemi_init_rxfilter(nic);
natsemi_init_txd(nic);
natsemi_init_rxd(nic);
/* Initialize other registers. */
/* Configure the PCI bus bursts and FIFO thresholds. */
/* Configure for standard, in-spec Ethernet. */
if (inl(ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */
tx_config = 0xD0801002;
rx_config = 0x10000020;
} else {
tx_config = 0x10801002;
rx_config = 0x0020;
}
outl(tx_config, ioaddr + TxConfig);
outl(rx_config, ioaddr + RxConfig);
natsemi_check_duplex(nic);
natsemi_set_rx_mode(nic);
outl(RxOn, ioaddr + ChipCmd);
}
/*
* Function: natsemi_reset
*
* Description: soft resets the controller chip
*
* Arguments: struct nic *nic: NIC data structure
*
* Returns: void.
*/
static void
natsemi_reset(struct nic *nic)
{
outl(ChipReset, ioaddr + ChipCmd);
/* On page 78 of the spec, they recommend some settings for "optimum
performance" to be done in sequence. These settings optimize some
of the 100Mbit autodetection circuitry. Also, we only want to do
this for rev C of the chip.
*/
if (inl(ioaddr + SiliconRev) == 0x302) {
outw(0x0001, ioaddr + PGSEL);
outw(0x189C, ioaddr + PMDCSR);
outw(0x0000, ioaddr + TSTDAT);
outw(0x5040, ioaddr + DSPCFG);
outw(0x008C, ioaddr + SDCFG);
}
/* Disable interrupts using the mask. */
outl(0, ioaddr + IntrMask);
outl(0, ioaddr + IntrEnable);
}
/* Function: natsemi_init_rxfilter
*
* Description: sets receive filter address to our MAC address
*
* Arguments: struct nic *nic: NIC data structure
*
* returns: void.
*/
static void
natsemi_init_rxfilter(struct nic *nic)
{
int i;
for (i = 0; i < ETH_ALEN; i += 2) {
outl(i, ioaddr + RxFilterAddr);
outw(nic->node_addr[i] + (nic->node_addr[i+1] << 8), ioaddr + RxFilterData);
}
}
/*
* Function: natsemi_init_txd
*
* Description: initializes the Tx descriptor
*
* Arguments: struct nic *nic: NIC data structure
*
* returns: void.
*/
static void
natsemi_init_txd(struct nic *nic)
{
txd.link = (u32) 0;
txd.cmdsts = (u32) 0;
txd.bufptr = (u32) &txb[0];
/* load Transmit Descriptor Register */
outl((u32) &txd, ioaddr + TxRingPtr);
if (natsemi_debug > 1)
printf("natsemi_init_txd: TX descriptor register loaded with: %X\n",
inl(ioaddr + TxRingPtr));
}
/* Function: natsemi_init_rxd
*
* Description: initializes the Rx descriptor ring
*
* Arguments: struct nic *nic: NIC data structure
*
* Returns: void.
*/
static void
natsemi_init_rxd(struct nic *nic)
{
int i;
cur_rx = 0;
/* init RX descriptor */
for (i = 0; i < NUM_RX_DESC; i++) {
rxd[i].link = (i+1 < NUM_RX_DESC) ? (u32) &rxd[i+1] : (u32) &rxd[0];
rxd[i].cmdsts = (u32) RX_BUF_SIZE;
rxd[i].bufptr = (u32) &rxb[i*RX_BUF_SIZE];
if (natsemi_debug > 1)
printf("natsemi_init_rxd: rxd[%d]=%X link=%X cmdsts=%X bufptr=%X\n",
i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr);
}
/* load Receive Descriptor Register */
outl((u32) &rxd[0], ioaddr + RxRingPtr);
if (natsemi_debug > 1)
printf("natsemi_init_rxd: RX descriptor register loaded with: %X\n",
inl(ioaddr + RxRingPtr));
}
/* Function: natsemi_set_rx_mode
*
* Description:
* sets the receive mode to accept all broadcast packets and packets
* with our MAC address, and reject all multicast packets.
*
* Arguments: struct nic *nic: NIC data structure
*
* Returns: void.
*/
static void natsemi_set_rx_mode(struct nic *nic)
{
u32 rx_mode = AcceptBroadcast | AcceptMyPhys;
outl(rx_mode, ioaddr + RxFilterAddr);
}
static void natsemi_check_duplex(struct nic *nic)
{
int duplex = inl(ioaddr + ChipConfig) & 0x20000000 ? 1 : 0;
if (natsemi_debug)
printf("%s: Setting %s-duplex based on negotiated link"
" capability.\n", nic_name,
duplex ? "full" : "half");
if (duplex) {
rx_config |= 0x10000000;
tx_config |= 0xC0000000;
} else {
rx_config &= ~0x10000000;
tx_config &= ~0xC0000000;
}
outl(tx_config, ioaddr + TxConfig);
outl(rx_config, ioaddr + RxConfig);
}
/* Function: natsemi_transmit
*
* Description: transmits a packet and waits for completion or timeout.
*
* Arguments: char d[6]: destination ethernet address.
* unsigned short t: ethernet protocol type.
* unsigned short s: size of the data-part of the packet.
* char *p: the data for the packet.
*
* Returns: void.
*/
static void
natsemi_transmit(struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
u32 status, to, nstype;
volatile u32 tx_status;
/* Stop the transmitter */
outl(TxOff, ioaddr + ChipCmd);
/* load Transmit Descriptor Register */
outl((u32) &txd, ioaddr + TxRingPtr);
if (natsemi_debug > 1)
printf("natsemi_transmit: TX descriptor register loaded with: %X\n",
inl(ioaddr + TxRingPtr));
memcpy(txb, d, ETH_ALEN);
memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
nstype = htons(t);
memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
memcpy(txb + ETH_HLEN, p, s);
s += ETH_HLEN;
s &= DSIZE;
if (natsemi_debug > 1)
printf("natsemi_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
/* pad to minimum packet size */
while (s < ETH_ZLEN)
txb[s++] = '\0';
/* set the transmit buffer descriptor and enable Transmit State Machine */
txd.bufptr = (u32) &txb[0];
txd.cmdsts = (u32) OWN | s;
/* restart the transmitter */
outl(TxOn, ioaddr + ChipCmd);
if (natsemi_debug > 1)
printf("natsemi_transmit: Queued Tx packet size %d.\n", (int) s);
to = currticks() + TX_TIMEOUT;
while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
/* wait */ ;
if (currticks() >= to) {
printf("natsemi_transmit: TX Timeout! Tx status %X.\n", tx_status);
}
if (!(tx_status & 0x08000000)) {
printf("natsemi_transmit: Transmit error, Tx status %X.\n", tx_status);
}
}
/* Function: natsemi_poll
*
* Description: checks for a received packet and returns it if found.
*
* Arguments: struct nic *nic: NIC data structure
*
* Returns: 1 if packet was received.
* 0 if no packet was received.
*
* Side effects:
* Returns (copies) the packet to the array nic->packet.
* Returns the length of the packet in nic->packetlen.
*/
static int
natsemi_poll(struct nic *nic)
{
u32 rx_status = rxd[cur_rx].cmdsts;
int retstat = 0;
if (natsemi_debug > 2)
printf("natsemi_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status);
if (!(rx_status & OWN))
return retstat;
if (natsemi_debug > 1)
printf("natsemi_poll: got a packet: cur_rx:%d, status:%X\n",
cur_rx, rx_status);
nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
if ((rx_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) {
/* corrupted packet received */
printf("natsemi_poll: Corrupted packet received, buffer status = %X\n",
rx_status);
retstat = 0;
} else {
/* give packet to higher level routine */
memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
retstat = 1;
}
/* return the descriptor and buffer to receive ring */
rxd[cur_rx].cmdsts = RX_BUF_SIZE;
rxd[cur_rx].bufptr = (u32) &rxb[cur_rx*RX_BUF_SIZE];
if (++cur_rx == NUM_RX_DESC)
cur_rx = 0;
/* re-enable the potentially idle receive state machine */
outl(RxOn, ioaddr + ChipCmd);
return retstat;
}
/* Function: natsemi_disable
*
* Description: Turns off interrupts and stops Tx and Rx engines
*
* Arguments: struct nic *nic: NIC data structure
*
* Returns: void.
*/
static void
natsemi_disable(struct nic *nic)
{
/* Disable interrupts using the mask. */
outl(0, ioaddr + IntrMask);
outl(0, ioaddr + IntrEnable);
/* Stop the chip's Tx and Rx processes. */
outl(RxOff | TxOff, ioaddr + ChipCmd);
/* Restore PME enable bit */
outl(SavedClkRun, ioaddr + ClkRun);
}
+371
View File
@@ -0,0 +1,371 @@
/**************************************************************************
Etherboot - BOOTP/TFTP Bootstrap Program
Driver for NI5010.
Code freely taken from Jan-Pascal van Best and Andreas Mohr's
Linux NI5010 driver.
***************************************************************************/
/*
* 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, or (at
* your option) any later version.
*/
/* to get some global routines like printf */
#include "etherboot.h"
/* to get the interface to the body of the program */
#include "nic.h"
/* to get our own prototype */
#include "cards.h"
/* ni5010.h file included verbatim */
/*
* Racal-Interlan ni5010 Ethernet definitions
*
* This is an extension to the Linux operating system, and is covered by the
* same Gnu Public License that covers that work.
*
* copyrights (c) 1996 by Jan-Pascal van Best (jvbest@wi.leidenuniv.nl)
*
* I have done a look in the following sources:
* crynwr-packet-driver by Russ Nelson
*/
#define NI5010_BUFSIZE 2048 /* number of bytes in a buffer */
#define NI5010_MAGICVAL0 0x00 /* magic-values for ni5010 card */
#define NI5010_MAGICVAL1 0x55
#define NI5010_MAGICVAL2 0xAA
#define SA_ADDR0 0x02
#define SA_ADDR1 0x07
#define SA_ADDR2 0x01
/* The number of low I/O ports used by the ni5010 ethercard. */
#define NI5010_IO_EXTENT 32
#define PRINTK(x) if (NI5010_DEBUG) printk x
#define PRINTK2(x) if (NI5010_DEBUG>=2) printk x
#define PRINTK3(x) if (NI5010_DEBUG>=3) printk x
/* The various IE command registers */
#define EDLC_XSTAT (ioaddr + 0x00) /* EDLC transmit csr */
#define EDLC_XCLR (ioaddr + 0x00) /* EDLC transmit "Clear IRQ" */
#define EDLC_XMASK (ioaddr + 0x01) /* EDLC transmit "IRQ Masks" */
#define EDLC_RSTAT (ioaddr + 0x02) /* EDLC receive csr */
#define EDLC_RCLR (ioaddr + 0x02) /* EDLC receive "Clear IRQ" */
#define EDLC_RMASK (ioaddr + 0x03) /* EDLC receive "IRQ Masks" */
#define EDLC_XMODE (ioaddr + 0x04) /* EDLC transmit Mode */
#define EDLC_RMODE (ioaddr + 0x05) /* EDLC receive Mode */
#define EDLC_RESET (ioaddr + 0x06) /* EDLC RESET register */
#define EDLC_TDR1 (ioaddr + 0x07) /* "Time Domain Reflectometry" reg1 */
#define EDLC_ADDR (ioaddr + 0x08) /* EDLC station address, 6 bytes */
/* 0x0E doesn't exist for r/w */
#define EDLC_TDR2 (ioaddr + 0x0f) /* "Time Domain Reflectometry" reg2 */
#define IE_GP (ioaddr + 0x10) /* GP pointer (word register) */
/* 0x11 is 2nd byte of GP Pointer */
#define IE_RCNT (ioaddr + 0x10) /* Count of bytes in rcv'd packet */
/* 0x11 is 2nd byte of "Byte Count" */
#define IE_MMODE (ioaddr + 0x12) /* Memory Mode register */
#define IE_DMA_RST (ioaddr + 0x13) /* IE DMA Reset. write only */
#define IE_ISTAT (ioaddr + 0x13) /* IE Interrupt Status. read only */
#define IE_RBUF (ioaddr + 0x14) /* IE Receive Buffer port */
#define IE_XBUF (ioaddr + 0x15) /* IE Transmit Buffer port */
#define IE_SAPROM (ioaddr + 0x16) /* window on station addr prom */
#define IE_RESET (ioaddr + 0x17) /* any write causes Board Reset */
/* bits in EDLC_XSTAT, interrupt clear on write, status when read */
#define XS_TPOK 0x80 /* transmit packet successful */
#define XS_CS 0x40 /* carrier sense */
#define XS_RCVD 0x20 /* transmitted packet received */
#define XS_SHORT 0x10 /* transmission media is shorted */
#define XS_UFLW 0x08 /* underflow. iff failed board */
#define XS_COLL 0x04 /* collision occurred */
#define XS_16COLL 0x02 /* 16th collision occurred */
#define XS_PERR 0x01 /* parity error */
#define XS_CLR_UFLW 0x08 /* clear underflow */
#define XS_CLR_COLL 0x04 /* clear collision */
#define XS_CLR_16COLL 0x02 /* clear 16th collision */
#define XS_CLR_PERR 0x01 /* clear parity error */
/* bits in EDLC_XMASK, mask/enable transmit interrupts. register is r/w */
#define XM_TPOK 0x80 /* =1 to enable Xmt Pkt OK interrupts */
#define XM_RCVD 0x20 /* =1 to enable Xmt Pkt Rcvd ints */
#define XM_UFLW 0x08 /* =1 to enable Xmt Underflow ints */
#define XM_COLL 0x04 /* =1 to enable Xmt Collision ints */
#define XM_COLL16 0x02 /* =1 to enable Xmt 16th Coll ints */
#define XM_PERR 0x01 /* =1 to enable Xmt Parity Error ints */
/* note: always clear this bit */
#define XM_ALL (XM_TPOK | XM_RCVD | XM_UFLW | XM_COLL | XM_COLL16)
/* bits in EDLC_RSTAT, interrupt clear on write, status when read */
#define RS_PKT_OK 0x80 /* received good packet */
#define RS_RST_PKT 0x10 /* RESET packet received */
#define RS_RUNT 0x08 /* Runt Pkt rcvd. Len < 64 Bytes */
#define RS_ALIGN 0x04 /* Alignment error. not 8 bit aligned */
#define RS_CRC_ERR 0x02 /* Bad CRC on rcvd pkt */
#define RS_OFLW 0x01 /* overflow for rcv FIFO */
#define RS_VALID_BITS ( RS_PKT_OK | RS_RST_PKT | RS_RUNT | RS_ALIGN | RS_CRC_ERR | RS_OFLW )
/* all valid RSTAT bits */
#define RS_CLR_PKT_OK 0x80 /* clear rcvd packet interrupt */
#define RS_CLR_RST_PKT 0x10 /* clear RESET packet received */
#define RS_CLR_RUNT 0x08 /* clear Runt Pckt received */
#define RS_CLR_ALIGN 0x04 /* clear Alignment error */
#define RS_CLR_CRC_ERR 0x02 /* clear CRC error */
#define RS_CLR_OFLW 0x01 /* clear rcv FIFO Overflow */
/* bits in EDLC_RMASK, mask/enable receive interrupts. register is r/w */
#define RM_PKT_OK 0x80 /* =1 to enable rcvd good packet ints */
#define RM_RST_PKT 0x10 /* =1 to enable RESET packet ints */
#define RM_RUNT 0x08 /* =1 to enable Runt Pkt rcvd ints */
#define RM_ALIGN 0x04 /* =1 to enable Alignment error ints */
#define RM_CRC_ERR 0x02 /* =1 to enable Bad CRC error ints */
#define RM_OFLW 0x01 /* =1 to enable overflow error ints */
/* bits in EDLC_RMODE, set Receive Packet mode. register is r/w */
#define RMD_TEST 0x80 /* =1 for Chip testing. normally 0 */
#define RMD_ADD_SIZ 0x10 /* =1 5-byte addr match. normally 0 */
#define RMD_EN_RUNT 0x08 /* =1 enable runt rcv. normally 0 */
#define RMD_EN_RST 0x04 /* =1 to rcv RESET pkt. normally 0 */
#define RMD_PROMISC 0x03 /* receive *all* packets. unusual */
#define RMD_MULTICAST 0x02 /* receive multicasts too. unusual */
#define RMD_BROADCAST 0x01 /* receive broadcasts & normal. usual */
#define RMD_NO_PACKETS 0x00 /* don't receive any packets. unusual */
/* bits in EDLC_XMODE, set Transmit Packet mode. register is r/w */
#define XMD_COLL_CNT 0xf0 /* coll's since success. read-only */
#define XMD_IG_PAR 0x08 /* =1 to ignore parity. ALWAYS set */
#define XMD_T_MODE 0x04 /* =1 to power xcvr. ALWAYS set this */
#define XMD_LBC 0x02 /* =1 for loopback. normally set */
#define XMD_DIS_C 0x01 /* =1 disables contention. normally 0 */
/* bits in EDLC_RESET, write only */
#define RS_RESET 0x80 /* =1 to hold EDLC in reset state */
/* bits in IE_MMODE, write only */
#define MM_EN_DMA 0x80 /* =1 begin DMA xfer, Cplt clrs it */
#define MM_EN_RCV 0x40 /* =1 allows Pkt rcv. clr'd by rcv */
#define MM_EN_XMT 0x20 /* =1 begin Xmt pkt. Cplt clrs it */
#define MM_BUS_PAGE 0x18 /* =00 ALWAYS. Used when MUX=1 */
#define MM_NET_PAGE 0x06 /* =00 ALWAYS. Used when MUX=0 */
#define MM_MUX 0x01 /* =1 means Rcv Buff on system bus */
/* =0 means Xmt Buff on system bus */
/* bits in IE_ISTAT, read only */
#define IS_TDIAG 0x80 /* =1 if Diagnostic problem */
#define IS_EN_RCV 0x20 /* =1 until frame is rcv'd cplt */
#define IS_EN_XMT 0x10 /* =1 until frame is xmt'd cplt */
#define IS_EN_DMA 0x08 /* =1 until DMA is cplt or aborted */
#define IS_DMA_INT 0x04 /* =0 iff DMA done interrupt. */
#define IS_R_INT 0x02 /* =0 iff unmasked Rcv interrupt */
#define IS_X_INT 0x01 /* =0 iff unmasked Xmt interrupt */
/* NIC specific static variables go here */
static unsigned short ioaddr = 0;
static unsigned int bufsize_rcv = 0;
#if 0
static void show_registers(void)
{
printf("XSTAT %hhX ", inb(EDLC_XSTAT));
printf("XMASK %hhX ", inb(EDLC_XMASK));
printf("RSTAT %hhX ", inb(EDLC_RSTAT));
printf("RMASK %hhX ", inb(EDLC_RMASK));
printf("RMODE %hhX ", inb(EDLC_RMODE));
printf("XMODE %hhX ", inb(EDLC_XMODE));
printf("ISTAT %hhX\n", inb(IE_ISTAT));
}
#endif
static void reset_receiver(void)
{
outw(0, IE_GP); /* Receive packet at start of buffer */
outb(RS_VALID_BITS, EDLC_RCLR); /* Clear all pending Rcv interrupts */
outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */
}
/**************************************************************************
RESET - Reset adapter
***************************************************************************/
static void ni5010_reset(struct nic *nic)
{
int i;
/* Reset the hardware here. Don't forget to set the station address. */
outb(RS_RESET, EDLC_RESET); /* Hold up EDLC_RESET while configing board */
outb(0, IE_RESET); /* Hardware reset of ni5010 board */
outb(0, EDLC_XMASK); /* Disable all Xmt interrupts */
outb(0, EDLC_RMASK); /* Disable all Rcv interrupt */
outb(0xFF, EDLC_XCLR); /* Clear all pending Xmt interrupts */
outb(0xFF, EDLC_RCLR); /* Clear all pending Rcv interrupts */
outb(XMD_LBC, EDLC_XMODE); /* Only loopback xmits */
/* Set the station address */
for(i = 0; i < ETH_ALEN; i++)
outb(nic->node_addr[i], EDLC_ADDR + i);
outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
/* Normal packet xmit mode */
outb(RMD_BROADCAST, EDLC_RMODE);
/* Receive broadcast and normal packets */
reset_receiver();
outb(0x00, EDLC_RESET); /* Un-reset the ni5010 */
}
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
static int ni5010_poll(struct nic *nic)
{
int rcv_stat;
if (((rcv_stat = inb(EDLC_RSTAT)) & RS_VALID_BITS) != RS_PKT_OK) {
outb(rcv_stat, EDLC_RSTAT); /* Clear the status */
return (0);
}
outb(rcv_stat, EDLC_RCLR); /* Clear the status */
nic->packetlen = inw(IE_RCNT);
/* Read packet into buffer */
outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */
outw(0, IE_GP); /* Seek to beginning of packet */
insb(IE_RBUF, nic->packet, nic->packetlen);
return (1);
}
/**************************************************************************
TRANSMIT - Transmit a frame
***************************************************************************/
static void ni5010_transmit(struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
unsigned int len;
int buf_offs, xmt_stat;
unsigned long time;
len = s + ETH_HLEN;
if (len < ETH_ZLEN)
len = ETH_ZLEN;
buf_offs = NI5010_BUFSIZE - len;
outb(0, EDLC_RMASK); /* Mask all receive interrupts */
outb(0, IE_MMODE); /* Put Xmit buffer on system bus */
outb(0xFF, EDLC_RCLR); /* Clear out pending rcv interrupts */
outw(buf_offs, IE_GP); /* Point GP at start of packet */
outsb(IE_XBUF, d, ETH_ALEN); /* Put dst in buffer */
outsb(IE_XBUF, nic->node_addr, ETH_ALEN);/* Put src in buffer */
outb(t >> 8, IE_XBUF);
outb(t, IE_XBUF);
outsb(IE_XBUF, p, s); /* Put data in buffer */
while (s++ < ETH_ZLEN - ETH_HLEN) /* Pad to min size */
outb(0, IE_XBUF);
outw(buf_offs, IE_GP); /* Rewrite where packet starts */
/* should work without that outb() (Crynwr used it) */
/*outb(MM_MUX, IE_MMODE);*/
/* Xmt buffer to EDLC bus */
outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */
/* wait for transmit complete */
while (((xmt_stat = inb(IE_ISTAT)) & IS_EN_XMT) != 0)
;
reset_receiver(); /* Immediately switch to receive */
}
/**************************************************************************
DISABLE - Turn off ethernet interface
***************************************************************************/
static void ni5010_disable(struct nic *nic)
{
outb(0, IE_MMODE);
outb(RS_RESET, EDLC_RESET);
}
static inline int rd_port(void)
{
inb(IE_RBUF);
return inb(IE_SAPROM);
}
static int ni5010_probe1(struct nic *nic)
{
int i, boguscount = 40, data;
/* The tests are from the Linux NI5010 driver
I don't understand it all, but if it works for them... */
if (inb(ioaddr) == 0xFF)
return (0);
while ((rd_port() & rd_port() & rd_port()
& rd_port() & rd_port() & rd_port()) != 0xFF)
{
if (boguscount-- <= 0)
return (0);
}
for (i = 0; i < 32; i++)
if ((data = rd_port()) != 0xFF)
break;
if (data == 0xFF)
return (0);
if (data == SA_ADDR0 && rd_port() == SA_ADDR1 && rd_port() == SA_ADDR2) {
for (i = 0; i < 4; i++)
rd_port();
if (rd_port() != NI5010_MAGICVAL1 || rd_port() != NI5010_MAGICVAL2)
return (0);
} else
return (0);
for (i = 0; i < ETH_ALEN; i++) {
outw(i, IE_GP);
nic->node_addr[i] = inb(IE_SAPROM);
}
printf("\nNI5010 ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr);
/* get the size of the onboard receive buffer
* higher addresses than bufsize are wrapped into real buffer
* i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer
*/
if (bufsize_rcv == 0) {
outb(1, IE_MMODE); /* Put Rcv buffer on system bus */
outw(0, IE_GP); /* Point GP at start of packet */
outb(0, IE_RBUF); /* set buffer byte 0 to 0 */
for (i = 1; i < 0xFF; i++) {
outw(i << 8, IE_GP); /* Point GP at packet size to be tested */
outb(i, IE_RBUF);
outw(0x0, IE_GP); /* Point GP at start of packet */
data = inb(IE_RBUF);
if (data == i) break;
}
bufsize_rcv = i << 8;
outw(0, IE_GP); /* Point GP at start of packet */
outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */
}
printf("Bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
return (1);
}
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
struct nic *ni5010_probe(struct nic *nic, unsigned short *probe_addrs)
{
static unsigned short io_addrs[] = {
0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 };
unsigned short *p;
/* if probe_addrs is 0, then use list above */
if (probe_addrs == 0 || *probe_addrs == 0)
probe_addrs = io_addrs;
for (p = probe_addrs; (ioaddr = *p) != 0; p++) {
if (ni5010_probe1(nic))
break;
}
if (ioaddr == 0)
return (0);
ni5010_reset(nic);
/* point to NIC specific routines */
nic->reset = ni5010_reset;
nic->poll = ni5010_poll;
nic->transmit = ni5010_transmit;
nic->disable = ni5010_disable;
return (nic);
}
+31
View File
@@ -0,0 +1,31 @@
/*
* 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, or (at
* your option) any later version.
*/
#ifndef NIC_H
#define NIC_H
/*
* Structure returned from eth_probe and passed to other driver
* functions.
*/
struct nic
{
void (*reset)P((struct nic *));
int (*poll)P((struct nic *));
void (*transmit)P((struct nic *, const char *d,
unsigned int t, unsigned int s, const char *p));
void (*disable)P((struct nic *));
int flags; /* driver specific flags */
struct rom_info *rom_info; /* -> rom_info from main */
unsigned char *node_addr;
char *packet;
unsigned int packetlen;
void *priv_data; /* driver can hang private data here */
};
#endif /* NIC_H */
+835
View File
@@ -0,0 +1,835 @@
/**************************************************************************
ETHERBOOT - BOOTP/TFTP Bootstrap Program
Author: Martin Renters
Date: May/94
This code is based heavily on David Greenman's if_ed.c driver
Copyright (C) 1993-1994, David Greenman, Martin Renters.
This software may be used, modified, copied, distributed, and sold, in
both source and binary form provided that the above copyright and these
terms are retained. Under no circumstances are the authors responsible for
the proper functioning of this software, nor do the authors assume any
responsibility for damages incurred with its use.
3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
**************************************************************************/
#include "etherboot.h"
#include "nic.h"
#include "ns8390.h"
#ifdef INCLUDE_NS8390
#include "pci.h"
#endif
#include "cards.h"
static unsigned char eth_vendor, eth_flags, eth_laar;
static unsigned short eth_nic_base, eth_asic_base;
static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
static Address eth_bmem, eth_rmem;
static unsigned char eth_drain_receiver;
#ifdef INCLUDE_WD
static struct wd_board {
const char *name;
char id;
char flags;
char memsize;
} wd_boards[] = {
{"WD8003S", TYPE_WD8003S, 0, MEM_8192},
{"WD8003E", TYPE_WD8003E, 0, MEM_8192},
{"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
{"WD8003W", TYPE_WD8003W, 0, MEM_8192},
{"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
{"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
{"WD8003EP/WD8013EP",
TYPE_WD8013EP, 0, MEM_8192},
{"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
{"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
{"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
{"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
{"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192},
{"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192},
{"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
{NULL, 0, 0, 0}
};
#endif
#ifdef INCLUDE_3C503
static unsigned char t503_output; /* AUI or internal xcvr (Thinnet) */
#endif
#if defined(INCLUDE_WD)
#define eth_probe wd_probe
#if defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
#endif
#endif
#if defined(INCLUDE_3C503)
#define eth_probe t503_probe
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
#endif
#endif
#if defined(INCLUDE_NE)
#define eth_probe ne_probe
#if defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
#endif
#endif
#if defined(INCLUDE_NS8390)
#define eth_probe nepci_probe
#if defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
#endif
#endif
#if defined(INCLUDE_3C503)
#define ASIC_PIO _3COM_RFMSB
#else
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
#define ASIC_PIO NE_DATA
#endif
#endif
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM))
/**************************************************************************
ETH_PIO_READ - Read a frame via Programmed I/O
**************************************************************************/
static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
{
if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; }
outb(D8390_COMMAND_RD2 |
D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
outb(cnt, eth_nic_base + D8390_P0_RBCR0);
outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
outb(src, eth_nic_base + D8390_P0_RSAR0);
outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
outb(D8390_COMMAND_RD0 |
D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
#ifdef INCLUDE_3C503
outb(src & 0xff, eth_asic_base + _3COM_DALSB);
outb(src >> 8, eth_asic_base + _3COM_DAMSB);
outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
#endif
if (eth_flags & FLAG_16BIT)
cnt >>= 1;
while(cnt--) {
#ifdef INCLUDE_3C503
while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
;
#endif
if (eth_flags & FLAG_16BIT) {
*((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
dst += 2;
}
else
*(dst++) = inb(eth_asic_base + ASIC_PIO);
}
#ifdef INCLUDE_3C503
outb(t503_output, eth_asic_base + _3COM_CR);
#endif
}
/**************************************************************************
ETH_PIO_WRITE - Write a frame via Programmed I/O
**************************************************************************/
static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
{
#ifdef COMPEX_RL2000_FIX
unsigned int x;
#endif /* COMPEX_RL2000_FIX */
if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; }
outb(D8390_COMMAND_RD2 |
D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
outb(cnt, eth_nic_base + D8390_P0_RBCR0);
outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
outb(dst, eth_nic_base + D8390_P0_RSAR0);
outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
outb(D8390_COMMAND_RD1 |
D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
#ifdef INCLUDE_3C503
outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
#endif
if (eth_flags & FLAG_16BIT)
cnt >>= 1;
while(cnt--)
{
#ifdef INCLUDE_3C503
while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
;
#endif
if (eth_flags & FLAG_16BIT) {
outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
src += 2;
}
else
outb(*(src++), eth_asic_base + ASIC_PIO);
}
#ifdef INCLUDE_3C503
outb(t503_output, eth_asic_base + _3COM_CR);
#else
#ifdef COMPEX_RL2000_FIX
for (x = 0;
x < COMPEX_RL2000_TRIES &&
(inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
!= D8390_ISR_RDC;
++x);
if (x >= COMPEX_RL2000_TRIES)
printf("Warning: Compex RL2000 aborted wait!\n");
#endif /* COMPEX_RL2000_FIX */
while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
!= D8390_ISR_RDC);
#endif
}
#else
/**************************************************************************
ETH_PIO_READ - Dummy routine when NE2000 not compiled in
**************************************************************************/
static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {}
#endif
/**************************************************************************
NS8390_RESET - Reset adapter
**************************************************************************/
static void ns8390_reset(struct nic *nic)
{
int i;
eth_drain_receiver = 0;
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790)
outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
else
#endif
outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
if (eth_flags & FLAG_16BIT)
outb(0x49, eth_nic_base+D8390_P0_DCR);
else
outb(0x48, eth_nic_base+D8390_P0_DCR);
outb(0, eth_nic_base+D8390_P0_RBCR0);
outb(0, eth_nic_base+D8390_P0_RBCR1);
outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
outb(2, eth_nic_base+D8390_P0_TCR);
outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790) outb(0, eth_nic_base + 0x09);
#endif
outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
outb(0xFF, eth_nic_base+D8390_P0_ISR);
outb(0, eth_nic_base+D8390_P0_IMR);
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790)
outb(D8390_COMMAND_PS1 |
D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
else
#endif
outb(D8390_COMMAND_PS1 |
D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
for (i=0; i<ETH_ALEN; i++)
outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
for (i=0; i<ETH_ALEN; i++)
outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790)
outb(D8390_COMMAND_PS0 |
D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
else
#endif
outb(D8390_COMMAND_PS0 |
D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
outb(0xFF, eth_nic_base+D8390_P0_ISR);
outb(0, eth_nic_base+D8390_P0_TCR);
outb(4, eth_nic_base+D8390_P0_RCR); /* allow broadcast frames */
#ifdef INCLUDE_3C503
/*
* No way to tell whether or not we're supposed to use
* the 3Com's transceiver unless the user tells us.
* 'flags' should have some compile time default value
* which can be changed from the command menu.
*/
t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
outb(t503_output, eth_asic_base + _3COM_CR);
#endif
}
static int ns8390_poll(struct nic *nic);
#ifndef INCLUDE_3C503
/**************************************************************************
ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
**************************************************************************/
static void eth_rx_overrun(struct nic *nic)
{
int start_time;
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790)
outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
else
#endif
outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
/* wait for at least 1.6ms - we wait one timer tick */
start_time = currticks();
while (currticks() - start_time <= 1)
/* Nothing */;
outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */
outb(0, eth_nic_base+D8390_P0_RBCR1);
/*
* Linux driver checks for interrupted TX here. This is not necessary,
* because the transmit routine waits until the frame is sent.
*/
/* enter loopback mode and restart NIC */
outb(2, eth_nic_base+D8390_P0_TCR);
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790)
outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
else
#endif
outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
/* clear the RX ring, acknowledge overrun interrupt */
eth_drain_receiver = 1;
while (ns8390_poll(nic))
/* Nothing */;
eth_drain_receiver = 0;
outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
/* leave loopback mode - no packets to be resent (see Linux driver) */
outb(0, eth_nic_base+D8390_P0_TCR);
}
#endif /* INCLUDE_3C503 */
/**************************************************************************
NS8390_TRANSMIT - Transmit a frame
**************************************************************************/
static void ns8390_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
#ifdef INCLUDE_3C503
if (!(eth_flags & FLAG_PIO)) {
memcpy((char *)eth_bmem, d, ETH_ALEN); /* dst */
memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
*((char *)eth_bmem+12) = t>>8; /* type */
*((char *)eth_bmem+13) = t;
memcpy((char *)eth_bmem+ETH_HLEN, p, s);
s += ETH_HLEN;
while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0;
}
#endif
#ifdef INCLUDE_WD
/* Memory interface */
if (eth_flags & FLAG_16BIT) {
outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
inb(0x84);
}
if (eth_flags & FLAG_790) {
outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
inb(0x84);
}
inb(0x84);
memcpy((char *)eth_bmem, d, ETH_ALEN); /* dst */
memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
*((char *)eth_bmem+12) = t>>8; /* type */
*((char *)eth_bmem+13) = t;
memcpy((char *)eth_bmem+ETH_HLEN, p, s);
s += ETH_HLEN;
while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0;
if (eth_flags & FLAG_790) {
outb(0, eth_asic_base + WD_MSR);
inb(0x84);
}
if (eth_flags & FLAG_16BIT) {
outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
inb(0x84);
}
#endif
#if defined(INCLUDE_3C503)
if (eth_flags & FLAG_PIO) {
#endif
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM))
/* Programmed I/O */
unsigned short type;
type = (t >> 8) | (t << 8);
eth_pio_write(d, eth_tx_start<<8, ETH_ALEN);
eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
/* bcc generates worse code without (const+const) below */
eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s);
s += ETH_HLEN;
if (s < ETH_ZLEN) s = ETH_ZLEN;
#endif
#if defined(INCLUDE_3C503)
}
#endif
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790)
outb(D8390_COMMAND_PS0 |
D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
else
#endif
outb(D8390_COMMAND_PS0 |
D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
outb(s, eth_nic_base+D8390_P0_TBCR0);
outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790)
outb(D8390_COMMAND_PS0 |
D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
else
#endif
outb(D8390_COMMAND_PS0 |
D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
}
/**************************************************************************
NS8390_POLL - Wait for a frame
**************************************************************************/
static int ns8390_poll(struct nic *nic)
{
int ret = 0;
unsigned char rstat, curr, next;
unsigned short len, frag;
unsigned short pktoff;
unsigned char *p;
struct ringbuffer pkthdr;
#ifndef INCLUDE_3C503
/* avoid infinite recursion: see eth_rx_overrun() */
if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
eth_rx_overrun(nic);
return(0);
}
#endif /* INCLUDE_3C503 */
rstat = inb(eth_nic_base+D8390_P0_RSR);
if (!(rstat & D8390_RSTAT_PRX)) return(0);
next = inb(eth_nic_base+D8390_P0_BOUND)+1;
if (next >= eth_memsize) next = eth_rx_start;
outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
curr = inb(eth_nic_base+D8390_P1_CURR);
outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
if (curr >= eth_memsize) curr=eth_rx_start;
if (curr == next) return(0);
#ifdef INCLUDE_WD
if (eth_flags & FLAG_16BIT) {
outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
inb(0x84);
}
if (eth_flags & FLAG_790) {
outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
inb(0x84);
}
inb(0x84);
#endif
pktoff = next << 8;
if (eth_flags & FLAG_PIO)
eth_pio_read(pktoff, (char *)&pkthdr, 4);
else
memcpy(&pkthdr, (char *)eth_rmem + pktoff, 4);
pktoff += sizeof(pkthdr);
/* incoming length includes FCS so must sub 4 */
len = pkthdr.len - 4;
if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
|| len > ETH_FRAME_LEN) {
printf("Bogus packet, ignoring\n");
return (0);
}
else {
p = nic->packet;
nic->packetlen = len; /* available to caller */
frag = (eth_memsize << 8) - pktoff;
if (len > frag) { /* We have a wrap-around */
/* read first part */
if (eth_flags & FLAG_PIO)
eth_pio_read(pktoff, p, frag);
else
memcpy(p, (char *)eth_rmem + pktoff, frag);
pktoff = eth_rx_start << 8;
p += frag;
len -= frag;
}
/* read second part */
if (eth_flags & FLAG_PIO)
eth_pio_read(pktoff, p, len);
else
memcpy(p, (char *)eth_rmem + pktoff, len);
ret = 1;
}
#ifdef INCLUDE_WD
if (eth_flags & FLAG_790) {
outb(0, eth_asic_base + WD_MSR);
inb(0x84);
}
if (eth_flags & FLAG_16BIT) {
outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
inb(0x84);
}
inb(0x84);
#endif
next = pkthdr.next; /* frame number of next packet */
if (next == eth_rx_start)
next = eth_memsize;
outb(next-1, eth_nic_base+D8390_P0_BOUND);
return(ret);
}
/**************************************************************************
NS8390_DISABLE - Turn off adapter
**************************************************************************/
static void ns8390_disable(struct nic *nic)
{
}
/**************************************************************************
ETH_PROBE - Look for an adapter
**************************************************************************/
#ifdef INCLUDE_NS8390
struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs,
struct pci_device *pci)
#else
struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs)
#endif
{
int i;
struct wd_board *brd;
unsigned short chksum;
unsigned char c;
eth_vendor = VENDOR_NONE;
eth_drain_receiver = 0;
#ifdef INCLUDE_WD
/******************************************************************
Search for WD/SMC cards
******************************************************************/
for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
eth_asic_base += 0x20) {
chksum = 0;
for (i=8; i<16; i++)
chksum += inb(eth_asic_base+i);
/* Extra checks to avoid soundcard */
if ((chksum & 0xFF) == 0xFF &&
inb(eth_asic_base+8) != 0xFF &&
inb(eth_asic_base+9) != 0xFF)
break;
}
if (eth_asic_base > WD_HIGH_BASE)
return (0);
/* We've found a board */
eth_vendor = VENDOR_WD;
eth_nic_base = eth_asic_base + WD_NIC_ADDR;
c = inb(eth_asic_base+WD_BID); /* Get board id */
for (brd = wd_boards; brd->name; brd++)
if (brd->id == c) break;
if (!brd->name) {
printf("Unknown WD/SMC NIC type %hhX\n", c);
return (0); /* Unknown type */
}
eth_flags = brd->flags;
eth_memsize = brd->memsize;
eth_tx_start = 0;
eth_rx_start = D8390_TXBUF_SIZE;
if ((c == TYPE_WD8013EP) &&
(inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
eth_flags = FLAG_16BIT;
eth_memsize = MEM_16384;
}
if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
eth_bmem = (0x80000 |
((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
} else
eth_bmem = WD_DEFAULT_MEM;
if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
*((unsigned int *)(eth_bmem + 8192)) = (unsigned int)0;
if (*((unsigned int *)(eth_bmem + 8192))) {
brd += 2;
eth_memsize = brd->memsize;
}
}
outb(0x80, eth_asic_base + WD_MSR); /* Reset */
for (i=0; i<ETH_ALEN; i++) {
nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
}
printf("\n%s base %#hx, memory %#hx, addr %!\n",
brd->name, eth_asic_base, eth_bmem, nic->node_addr);
if (eth_flags & FLAG_790) {
outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
outb((inb(eth_asic_base+0x04) |
0x80), eth_asic_base+0x04);
outb((((unsigned)eth_bmem >> 13) & 0x0F) |
(((unsigned)eth_bmem >> 11) & 0x40) |
(inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
outb((inb(eth_asic_base+0x04) &
~0x80), eth_asic_base+0x04);
} else {
outb((((unsigned)eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
}
if (eth_flags & FLAG_16BIT) {
if (eth_flags & FLAG_790) {
eth_laar = inb(eth_asic_base + WD_LAAR);
outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
} else {
outb((eth_laar =
WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
/*
The previous line used to be
WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
it work for WD8013s. This seems to work for my 8013 boards. I
don't know what is really happening. I wish I had data sheets
or more time to decode the Linux driver. - Ken
*/
}
inb(0x84);
}
#endif
#ifdef INCLUDE_3C503
/******************************************************************
Search for 3Com 3c503 if no WD/SMC cards
******************************************************************/
if (eth_vendor == VENDOR_NONE) {
int idx;
int iobase_reg, membase_reg;
static unsigned short base[] = {
0x300, 0x310, 0x330, 0x350,
0x250, 0x280, 0x2A0, 0x2E0, 0 };
/* Loop through possible addresses checking each one */
for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
/*
* Note that we use the same settings for both 8 and 16 bit cards:
* both have an 8K bank of memory at page 1 while only the 16 bit
* cards have a bank at page 0.
*/
eth_memsize = MEM_16384;
eth_tx_start = 32;
eth_rx_start = 32 + D8390_TXBUF_SIZE;
/* Check our base address. iobase and membase should */
/* both have a maximum of 1 bit set or be 0. */
iobase_reg = inb(eth_asic_base + _3COM_BCFR);
membase_reg = inb(eth_asic_base + _3COM_PCFR);
if ((iobase_reg & (iobase_reg - 1)) ||
(membase_reg & (membase_reg - 1)))
continue; /* nope */
/* Now get the shared memory address */
eth_flags = 0;
switch (membase_reg) {
case _3COM_PCFR_DC000:
eth_bmem = 0xdc000;
break;
case _3COM_PCFR_D8000:
eth_bmem = 0xd8000;
break;
case _3COM_PCFR_CC000:
eth_bmem = 0xcc000;
break;
case _3COM_PCFR_C8000:
eth_bmem = 0xc8000;
break;
case _3COM_PCFR_PIO:
eth_flags |= FLAG_PIO;
eth_bmem = 0;
break;
default:
continue; /* nope */
}
break;
}
if (base[idx] == 0) /* not found */
return (0);
#ifndef T503_SHMEM
eth_flags |= FLAG_PIO; /* force PIO mode */
eth_bmem = 0;
#endif
eth_vendor = VENDOR_3COM;
/* Need this to make ns8390_poll() happy. */
eth_rmem = eth_bmem - 0x2000;
/* Reset NIC and ASIC */
outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
/* Get our ethernet address */
outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
printf("\n3Com 3c503 base %#hx, ", eth_nic_base);
if (eth_flags & FLAG_PIO)
printf("PIO mode");
else
printf("memory %#hx", eth_bmem);
for (i=0; i<ETH_ALEN; i++) {
nic->node_addr[i] = inb(eth_nic_base+i);
}
printf(", %s, addr %!\n", nic->flags ? "AUI" : "internal xcvr",
nic->node_addr);
outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
/*
* Initialize GA configuration register. Set bank and enable shared
* mem. We always use bank 1. Disable interrupts.
*/
outb(_3COM_GACFR_RSEL |
_3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
outb(0xff, eth_asic_base + _3COM_VPTR2);
outb(0xff, eth_asic_base + _3COM_VPTR1);
outb(0x00, eth_asic_base + _3COM_VPTR0);
/*
* Clear memory and verify that it worked (we use only 8K)
*/
if (!(eth_flags & FLAG_PIO)) {
memset((char *)eth_bmem, 0, 0x2000);
for(i = 0; i < 0x2000; ++i)
if (*(((char *)eth_bmem)+i)) {
printf ("Failed to clear 3c503 shared mem.\n");
return (0);
}
}
/*
* Initialize GA page/start/stop registers.
*/
outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
outb(eth_memsize, eth_asic_base + _3COM_PSPR);
}
#endif
#if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
/******************************************************************
Search for NE1000/2000 if no WD/SMC or 3com cards
******************************************************************/
if (eth_vendor == VENDOR_NONE) {
char romdata[16], testbuf[32];
int idx;
static char test[] = "NE*000 memory";
static unsigned short base[] = {
#ifdef NE_SCAN
NE_SCAN,
#endif
0 };
/* if no addresses supplied, fall back on defaults */
if (probe_addrs == 0 || probe_addrs[0] == 0)
probe_addrs = base;
eth_bmem = 0; /* No shared memory */
for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
eth_flags = FLAG_PIO;
eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
eth_memsize = MEM_16384;
eth_tx_start = 32;
eth_rx_start = 32 + D8390_TXBUF_SIZE;
c = inb(eth_asic_base + NE_RESET);
outb(c, eth_asic_base + NE_RESET);
inb(0x84);
outb(D8390_COMMAND_STP |
D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
#ifdef NS8390_FORCE_16BIT
eth_flags |= FLAG_16BIT; /* force 16-bit mode */
#endif
eth_pio_write(test, 8192, sizeof(test));
eth_pio_read(8192, testbuf, sizeof(test));
if (!memcmp(test, testbuf, sizeof(test)))
break;
eth_flags |= FLAG_16BIT;
eth_memsize = MEM_32768;
eth_tx_start = 64;
eth_rx_start = 64 + D8390_TXBUF_SIZE;
outb(D8390_DCR_WTS |
D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
eth_pio_write(test, 16384, sizeof(test));
eth_pio_read(16384, testbuf, sizeof(test));
if (!memcmp(testbuf, test, sizeof(test)))
break;
}
if (eth_nic_base == 0)
return (0);
if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
eth_flags |= FLAG_16BIT;
eth_vendor = VENDOR_NOVELL;
eth_pio_read(0, romdata, sizeof(romdata));
for (i=0; i<ETH_ALEN; i++) {
nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
}
printf("\nNE%c000 base %#hx, addr %!\n",
(eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
nic->node_addr);
}
#endif
if (eth_vendor == VENDOR_NONE)
return(0);
if (eth_vendor != VENDOR_3COM)
eth_rmem = eth_bmem;
ns8390_reset(nic);
nic->reset = ns8390_reset;
nic->poll = ns8390_poll;
nic->transmit = ns8390_transmit;
nic->disable = ns8390_disable;
return(nic);
}
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+238
View File
@@ -0,0 +1,238 @@
/**************************************************************************
ETHERBOOT - BOOTP/TFTP Bootstrap Program
Author: Martin Renters
Date: Jun/94
**************************************************************************/
#define VENDOR_NONE 0
#define VENDOR_WD 1
#define VENDOR_NOVELL 2
#define VENDOR_3COM 3
#define FLAG_PIO 0x01
#define FLAG_16BIT 0x02
#define FLAG_790 0x04
#define MEM_8192 32
#define MEM_16384 64
#define MEM_32768 128
#define ISA_MAX_ADDR 0x400
/**************************************************************************
Western Digital/SMC Board Definitions
**************************************************************************/
#define WD_LOW_BASE 0x200
#define WD_HIGH_BASE 0x3e0
#ifndef WD_DEFAULT_MEM
#define WD_DEFAULT_MEM 0xD0000
#endif
#define WD_NIC_ADDR 0x10
/**************************************************************************
Western Digital/SMC ASIC Addresses
**************************************************************************/
#define WD_MSR 0x00
#define WD_ICR 0x01
#define WD_IAR 0x02
#define WD_BIO 0x03
#define WD_IRR 0x04
#define WD_LAAR 0x05
#define WD_IJR 0x06
#define WD_GP2 0x07
#define WD_LAR 0x08
#define WD_BID 0x0E
#define WD_ICR_16BIT 0x01
#define WD_MSR_MENB 0x40
#define WD_LAAR_L16EN 0x40
#define WD_LAAR_M16EN 0x80
#define WD_SOFTCONFIG 0x20
/**************************************************************************
Western Digital/SMC Board Types
**************************************************************************/
#define TYPE_WD8003S 0x02
#define TYPE_WD8003E 0x03
#define TYPE_WD8013EBT 0x05
#define TYPE_WD8003W 0x24
#define TYPE_WD8003EB 0x25
#define TYPE_WD8013W 0x26
#define TYPE_WD8013EP 0x27
#define TYPE_WD8013WC 0x28
#define TYPE_WD8013EPC 0x29
#define TYPE_SMC8216T 0x2a
#define TYPE_SMC8216C 0x2b
#define TYPE_SMC8416T 0x00 /* Bogus entries: the 8416 generates the */
#define TYPE_SMC8416C 0x00 /* the same codes as the 8216. */
#define TYPE_SMC8013EBP 0x2c
/**************************************************************************
3com 3c503 definitions
**************************************************************************/
#ifndef _3COM_BASE
#define _3COM_BASE 0x300
#endif
#define _3COM_TX_PAGE_OFFSET_8BIT 0x20
#define _3COM_TX_PAGE_OFFSET_16BIT 0x0
#define _3COM_RX_PAGE_OFFSET_16BIT 0x20
#define _3COM_ASIC_OFFSET 0x400
#define _3COM_NIC_OFFSET 0x0
#define _3COM_PSTR 0
#define _3COM_PSPR 1
#define _3COM_BCFR 3
#define _3COM_BCFR_2E0 0x01
#define _3COM_BCFR_2A0 0x02
#define _3COM_BCFR_280 0x04
#define _3COM_BCFR_250 0x08
#define _3COM_BCFR_350 0x10
#define _3COM_BCFR_330 0x20
#define _3COM_BCFR_310 0x40
#define _3COM_BCFR_300 0x80
#define _3COM_PCFR 4
#define _3COM_PCFR_PIO 0
#define _3COM_PCFR_C8000 0x10
#define _3COM_PCFR_CC000 0x20
#define _3COM_PCFR_D8000 0x40
#define _3COM_PCFR_DC000 0x80
#define _3COM_CR 6
#define _3COM_CR_RST 0x01 /* Reset GA and NIC */
#define _3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */
#define _3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */
#define _3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */
#define _3COM_CR_SHARE 0x10 /* select interrupt sharing option */
#define _3COM_CR_DBSEL 0x20 /* Double buffer select */
#define _3COM_CR_DDIR 0x40 /* DMA direction select */
#define _3COM_CR_START 0x80 /* Start DMA controller */
#define _3COM_GACFR 5
#define _3COM_GACFR_MBS0 0x01
#define _3COM_GACFR_MBS1 0x02
#define _3COM_GACFR_MBS2 0x04
#define _3COM_GACFR_RSEL 0x08 /* enable shared memory */
#define _3COM_GACFR_TEST 0x10 /* for GA testing */
#define _3COM_GACFR_OWS 0x20 /* select 0WS access to GA */
#define _3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */
#define _3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */
#define _3COM_STREG 7
#define _3COM_STREG_REV 0x07 /* GA revision */
#define _3COM_STREG_DIP 0x08 /* DMA in progress */
#define _3COM_STREG_DTC 0x10 /* DMA terminal count */
#define _3COM_STREG_OFLW 0x20 /* Overflow */
#define _3COM_STREG_UFLW 0x40 /* Underflow */
#define _3COM_STREG_DPRDY 0x80 /* Data port ready */
#define _3COM_IDCFR 8
#define _3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */
#define _3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */
#define _3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */
#define _3COM_IDCFR_UNUSED 0x08 /* not used */
#define _3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */
#define _3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */
#define _3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */
#define _3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */
#define _3COM_IRQ2 2
#define _3COM_IRQ3 3
#define _3COM_IRQ4 4
#define _3COM_IRQ5 5
#define _3COM_DAMSB 9
#define _3COM_DALSB 0x0a
#define _3COM_VPTR2 0x0b
#define _3COM_VPTR1 0x0c
#define _3COM_VPTR0 0x0d
#define _3COM_RFMSB 0x0e
#define _3COM_RFLSB 0x0f
/**************************************************************************
NE1000/2000 definitions
**************************************************************************/
#define NE_ASIC_OFFSET 0x10
#define NE_RESET 0x0F /* Used to reset card */
#define NE_DATA 0x00 /* Used to read/write NIC mem */
#define COMPEX_RL2000_TRIES 200
/**************************************************************************
8390 Register Definitions
**************************************************************************/
#define D8390_P0_COMMAND 0x00
#define D8390_P0_PSTART 0x01
#define D8390_P0_PSTOP 0x02
#define D8390_P0_BOUND 0x03
#define D8390_P0_TSR 0x04
#define D8390_P0_TPSR 0x04
#define D8390_P0_TBCR0 0x05
#define D8390_P0_TBCR1 0x06
#define D8390_P0_ISR 0x07
#define D8390_P0_RSAR0 0x08
#define D8390_P0_RSAR1 0x09
#define D8390_P0_RBCR0 0x0A
#define D8390_P0_RBCR1 0x0B
#define D8390_P0_RSR 0x0C
#define D8390_P0_RCR 0x0C
#define D8390_P0_TCR 0x0D
#define D8390_P0_DCR 0x0E
#define D8390_P0_IMR 0x0F
#define D8390_P1_COMMAND 0x00
#define D8390_P1_PAR0 0x01
#define D8390_P1_PAR1 0x02
#define D8390_P1_PAR2 0x03
#define D8390_P1_PAR3 0x04
#define D8390_P1_PAR4 0x05
#define D8390_P1_PAR5 0x06
#define D8390_P1_CURR 0x07
#define D8390_P1_MAR0 0x08
#define D8390_COMMAND_PS0 0x0 /* Page 0 select */
#define D8390_COMMAND_PS1 0x40 /* Page 1 select */
#define D8390_COMMAND_PS2 0x80 /* Page 2 select */
#define D8390_COMMAND_RD2 0x20 /* Remote DMA control */
#define D8390_COMMAND_RD1 0x10
#define D8390_COMMAND_RD0 0x08
#define D8390_COMMAND_TXP 0x04 /* transmit packet */
#define D8390_COMMAND_STA 0x02 /* start */
#define D8390_COMMAND_STP 0x01 /* stop */
#define D8390_RCR_MON 0x20 /* monitor mode */
#define D8390_DCR_FT1 0x40
#define D8390_DCR_LS 0x08 /* Loopback select */
#define D8390_DCR_WTS 0x01 /* Word transfer select */
#define D8390_ISR_PRX 0x01 /* successful recv */
#define D8390_ISR_PTX 0x02 /* successful xmit */
#define D8390_ISR_RXE 0x04 /* receive error */
#define D8390_ISR_TXE 0x08 /* transmit error */
#define D8390_ISR_OVW 0x10 /* Overflow */
#define D8390_ISR_CNT 0x20 /* Counter overflow */
#define D8390_ISR_RDC 0x40 /* Remote DMA complete */
#define D8390_ISR_RST 0x80 /* reset */
#define D8390_RSTAT_PRX 0x01 /* successful recv */
#define D8390_RSTAT_CRC 0x02 /* CRC error */
#define D8390_RSTAT_FAE 0x04 /* Frame alignment error */
#define D8390_RSTAT_OVER 0x08 /* FIFO overrun */
#define D8390_TXBUF_SIZE 6
#define D8390_RXBUF_END 32
#define D8390_PAGE_SIZE 256
struct ringbuffer {
unsigned char status;
unsigned char next;
unsigned short len;
};
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+94
View File
@@ -0,0 +1,94 @@
#ifndef __OSDEP_H__
#define __OSDEP_H__
/*
* 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, or (at
* your option) any later version.
*/
#define __LITTLE_ENDIAN /* x86 */
/* Taken from /usr/include/linux/hfs_sysdep.h */
#if defined(__BIG_ENDIAN)
# if !defined(__constant_htonl)
# define __constant_htonl(x) (x)
# endif
# if !defined(__constant_htons)
# define __constant_htons(x) (x)
# endif
#elif defined(__LITTLE_ENDIAN)
# if !defined(__constant_htonl)
# define __constant_htonl(x) \
((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
(((unsigned long int)(x) & 0x0000ff00U) << 8) | \
(((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
(((unsigned long int)(x) & 0xff000000U) >> 24)))
# endif
# if !defined(__constant_htons)
# define __constant_htons(x) \
((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
(((unsigned short int)(x) & 0xff00) >> 8)))
# endif
#else
# error "Don't know if bytes are big- or little-endian!"
#endif
#define ntohl(x) \
(__builtin_constant_p(x) ? \
__constant_htonl((x)) : \
__swap32(x))
#define htonl(x) \
(__builtin_constant_p(x) ? \
__constant_htonl((x)) : \
__swap32(x))
#define ntohs(x) \
(__builtin_constant_p(x) ? \
__constant_htons((x)) : \
__swap16(x))
#define htons(x) \
(__builtin_constant_p(x) ? \
__constant_htons((x)) : \
__swap16(x))
static inline unsigned long int __swap32(unsigned long int x)
{
__asm__("xchgb %b0,%h0\n\t"
"rorl $16,%0\n\t"
"xchgb %b0,%h0"
: "=q" (x)
: "0" (x));
return x;
}
static inline unsigned short int __swap16(unsigned short int x)
{
__asm__("xchgb %b0,%h0"
: "=q" (x)
: "0" (x));
return x;
}
/* Make routines available to all */
#define swap32(x) __swap32(x)
#define swap16(x) __swap16(x)
#include "linux-asm-io.h"
typedef unsigned long Address;
/* ANSI prototyping macro */
#ifdef __STDC__
#define P(x) x
#else
#define P(x) ()
#endif
#endif
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+374
View File
@@ -0,0 +1,374 @@
/*
Etherboot DEC Tulip driver
adapted by Ken Yap from
FreeBSD netboot DEC 21143 driver
Author: David Sharp
date: Nov/98
Known to work on DEC DE500 using 21143-PC chipset.
Even on cards with the same chipset there can be
incompatablity problems with the way media selection
and status LED settings are done. See comments below.
Some code fragments were taken from verious places,
Ken Yap's etherboot, FreeBSD's if_de.c, and various
Linux related files. DEC's manuals for the 21143 and
SROM format were very helpful. The Linux de driver
development page has a number of links to useful
related information. Have a look at:
ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html
*/
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "cards.h"
#include "otulip.h"
static unsigned short vendor, dev_id;
static unsigned short ioaddr;
static unsigned int *membase;
static unsigned char srom[1024];
#define BUFLEN 1536 /* must be longword divisable */
/* buffers must be longword aligned */
/* transmit descriptor and buffer */
static struct txdesc txd;
/* receive descriptor(s) and buffer(s) */
#define NRXD 4
static struct rxdesc rxd[NRXD];
static int rxd_tail = 0;
#ifdef USE_LOWMEM_BUFFER
#define rxb ((char *)0x10000 - NRXD * BUFLEN)
#define txb ((char *)0x10000 - NRXD * BUFLEN - BUFLEN)
#else
static unsigned char rxb[NRXD * BUFLEN];
static unsigned char txb[BUFLEN];
#endif
static unsigned char ehdr[ETH_HLEN]; /* buffer for ethernet header */
enum tulip_offsets {
CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
/***************************************************************************/
/* 21143 specific stuff */
/***************************************************************************/
/* XXX assume 33MHz PCI bus, this is not very accurate and should be
used only with gross over estimations of required delay times unless
you tune UADJUST to your specific processor and I/O subsystem */
#define UADJUST 870
static void udelay(unsigned long usec) {
unsigned long i;
for (i=((usec*UADJUST)/33)+1; i>0; i--) (void) TULIP_CSR_READ(csr_0);
}
/* The following srom related code was taken from FreeBSD's if_de.c */
/* with minor alterations to make it work here. the Linux code is */
/* better but this was easier to use */
static void delay_300ns(void)
{
int idx;
for (idx = (300 / 33) + 1; idx > 0; idx--)
(void) TULIP_CSR_READ(csr_busmode);
}
#define EMIT do { TULIP_CSR_WRITE(csr_srom_mii, csr); delay_300ns(); } while (0)
static void srom_idle(void)
{
unsigned bit, csr;
csr = SROMSEL ; EMIT;
csr = SROMSEL | SROMRD; EMIT;
csr ^= SROMCS; EMIT;
csr ^= SROMCLKON; EMIT;
/*
* Write 25 cycles of 0 which will force the SROM to be idle.
*/
for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
csr ^= SROMCLKON; EMIT; /* clock high; data valid */
}
csr ^= SROMCLKOFF; EMIT;
csr ^= SROMCS; EMIT;
csr = 0; EMIT;
}
static void srom_read(void)
{
unsigned idx;
const unsigned bitwidth = SROM_BITWIDTH;
const unsigned cmdmask = (SROMCMD_RD << bitwidth);
const unsigned msb = 1 << (bitwidth + 3 - 1);
unsigned lastidx = (1 << bitwidth) - 1;
srom_idle();
for (idx = 0; idx <= lastidx; idx++) {
unsigned lastbit, data, bits, bit, csr;
csr = SROMSEL ; EMIT;
csr = SROMSEL | SROMRD; EMIT;
csr ^= SROMCSON; EMIT;
csr ^= SROMCLKON; EMIT;
lastbit = 0;
for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1)
{
const unsigned thisbit = bits & msb;
csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
if (thisbit != lastbit) {
csr ^= SROMDOUT; EMIT; /* clock low; invert data */
} else {
EMIT;
}
csr ^= SROMCLKON; EMIT; /* clock high; data valid */
lastbit = thisbit;
}
csr ^= SROMCLKOFF; EMIT;
for (data = 0, bits = 0; bits < 16; bits++) {
data <<= 1;
csr ^= SROMCLKON; EMIT; /* clock high; data valid */
data |= TULIP_CSR_READ(csr_srom_mii) & SROMDIN ? 1 : 0;
csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
}
srom[idx*2] = data & 0xFF;
srom[idx*2+1] = data >> 8;
csr = SROMSEL | SROMRD; EMIT;
csr = 0; EMIT;
}
srom_idle();
}
/**************************************************************************
ETH_RESET - Reset adapter
***************************************************************************/
static void tulip_reset(struct nic *nic)
{
int x,cnt=2;
outl(0x00000001, ioaddr + CSR0);
udelay(1000);
/* turn off reset and set cache align=16lword, burst=unlimit */
outl(0x01A08000, ioaddr + CSR0);
/* for some reason the media selection does not take
the first time se it is repeated. */
while(cnt--) {
/* stop TX,RX processes */
if (cnt == 1)
outl(0x32404000, ioaddr + CSR6);
else
outl(0x32000040, ioaddr + CSR6);
/* XXX - media selection is vendor specific and hard coded right
here. This should be fixed to use the hints in the SROM and
allow media selection by the user at runtime. MII support
should also be added. Support for chips other than the
21143 should be added here as well */
/* start set to 10Mbps half-duplex */
/* setup SIA */
outl(0x0, ioaddr + CSR13); /* reset SIA */
outl(0x7f3f, ioaddr + CSR14);
outl(0x8000008, ioaddr + CSR15);
outl(0x0, ioaddr + CSR13);
outl(0x1, ioaddr + CSR13);
outl(0x2404000, ioaddr + CSR6);
/* initalize GP */
outl(0x8af0008, ioaddr + CSR15);
outl(0x50008, ioaddr + CSR15);
/* end set to 10Mbps half-duplex */
if (vendor == PCI_VENDOR_ID_MACRONIX && dev_id == PCI_DEVICE_ID_MX987x5) {
/* do stuff for MX98715 */
outl(0x01a80000, ioaddr + CSR6);
outl(0xFFFFFFFF, ioaddr + CSR14);
outl(0x00001000, ioaddr + CSR12);
}
outl(0x0, ioaddr + CSR7); /* disable interrupts */
/* construct setup packet which is used by the 21143 to
program its CAM to recognize interesting MAC addresses */
memset(&txd, 0, sizeof(struct txdesc));
txd.buf1addr = &txb[0];
txd.buf2addr = &txb[0]; /* just in case */
txd.buf1sz = 192; /* setup packet must be 192 bytes */
txd.buf2sz = 0;
txd.control = 0x020; /* setup packet */
txd.status = 0x80000000; /* give ownership to 21143 */
/* construct perfect filter frame */
/* with mac address as first match */
/* and broadcast address for all others */
for(x=0;x<192;x++) txb[x] = 0xff;
txb[0] = nic->node_addr[0];
txb[1] = nic->node_addr[1];
txb[4] = nic->node_addr[2];
txb[5] = nic->node_addr[3];
txb[8] = nic->node_addr[4];
txb[9] = nic->node_addr[5];
outl((unsigned long)&txd, ioaddr + CSR4); /* set xmit buf */
outl(0x2406000, ioaddr + CSR6); /* start transmiter */
udelay(50000); /* wait for the setup packet to be processed */
}
/* setup receive descriptor */
{
int x;
for(x=0;x<NRXD;x++) {
memset(&rxd[x], 0, sizeof(struct rxdesc));
rxd[x].buf1addr = &rxb[x * BUFLEN];
rxd[x].buf2addr = 0; /* not used */
rxd[x].buf1sz = BUFLEN;
rxd[x].buf2sz = 0; /* not used */
rxd[x].control = 0x0;
rxd[x].status = 0x80000000; /* give ownership it to 21143 */
}
rxd[NRXD - 1].control = 0x008; /* Set Receive end of ring on la
st descriptor */
rxd_tail = 0;
}
/* tell DC211XX where to find rx descriptor list */
outl((unsigned long)&rxd[0], ioaddr + CSR3);
/* start the receiver */
outl(0x2406002, ioaddr + CSR6);
}
/**************************************************************************
ETH_TRANSMIT - Transmit a frame
***************************************************************************/
static const char padmap[] = {
0, 3, 2, 1};
static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
{
unsigned long time;
/* setup ethernet header */
memcpy(ehdr, d, ETH_ALEN);
memcpy(&ehdr[ETH_ALEN], nic->node_addr, ETH_ALEN);
ehdr[ETH_ALEN*2] = (t >> 8) & 0xff;
ehdr[ETH_ALEN*2+1] = t & 0xff;
/* setup the transmit descriptor */
memset(&txd, 0, sizeof(struct txdesc));
txd.buf1addr = &ehdr[0]; /* ethernet header */
txd.buf1sz = ETH_HLEN;
txd.buf2addr = p; /* packet to transmit */
txd.buf2sz = s;
txd.control = 0x188; /* LS+FS+TER */
txd.status = 0x80000000; /* give it to 21143 */
outl(inl(ioaddr + CSR6) & ~0x00004000, ioaddr + CSR6);
outl((unsigned long)&txd, ioaddr + CSR4);
outl(inl(ioaddr + CSR6) | 0x00004000, ioaddr + CSR6);
/* Wait for transmit to complete before returning. not well tested.
time = currticks();
while(txd.status & 0x80000000) {
if (currticks() - time > 20) {
printf("transmit timeout.\n");
break;
}
}
*/
}
/**************************************************************************
ETH_POLL - Wait for a frame
***************************************************************************/
static int tulip_poll(struct nic *nic)
{
if (rxd[rxd_tail].status & 0x80000000) return 0;
nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16;
/* copy packet to working buffer */
/* XXX - this copy could be avoided with a little more work
but for now we are content with it because the optimised
memcpy(, , ) is quite fast */
memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen);
/* return the descriptor and buffer to recieve ring */
rxd[rxd_tail].status = 0x80000000;
rxd_tail++;
if (rxd_tail == NRXD) rxd_tail = 0;
return 1;
}
static void tulip_disable(struct nic *nic)
{
/* nothing for the moment */
}
/**************************************************************************
ETH_PROBE - Look for an adapter
***************************************************************************/
struct nic *otulip_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
{
int i;
if (io_addrs == 0 || *io_addrs == 0)
return (0);
vendor = pci->vendor;
dev_id = pci->dev_id;
ioaddr = *io_addrs;
membase = (unsigned int *)pci->membase;
/* wakeup chip */
pcibios_write_config_dword(pci->bus,pci->devfn,0x40,0x00000000);
/* Stop the chip's Tx and Rx processes. */
/* outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); */
/* Clear the missed-packet counter. */
/* (volatile int)inl(ioaddr + CSR8); */
srom_read();
for (i=0; i < ETH_ALEN; i++)
nic->node_addr[i] = srom[20+i];
printf("Tulip %! at ioaddr %#hX\n", nic->node_addr, ioaddr);
tulip_reset(nic);
nic->reset = tulip_reset;
nic->poll = tulip_poll;
nic->transmit = tulip_transmit;
nic->disable = tulip_disable;
return nic;
}
+76
View File
@@ -0,0 +1,76 @@
/* mostly stolen from FreeBSD if_de.c, if_devar.h */
#define TULIP_CSR_READ(csr) (membase[csr*2])
#define CSR_READ(csr) (membase[csr*2])
#define TULIP_CSR_WRITE(csr, val) (membase[csr*2] = val)
#define CSR_WRITE(csr, val) (membase[csr*2] = val)
#define csr_0 0
#define csr_1 1
#define csr_2 2
#define csr_3 3
#define csr_4 4
#define csr_5 5
#define csr_6 6
#define csr_7 7
#define csr_8 8
#define csr_9 9
#define csr_10 10
#define csr_11 11
#define csr_12 12
#define csr_13 13
#define csr_14 14
#define csr_15 15
#define csr_busmode csr_0
#define csr_txpoll csr_1
#define csr_rxpoll csr_2
#define csr_rxlist csr_3
#define csr_txlist csr_4
#define csr_status csr_5
#define csr_command csr_6
#define csr_intr csr_7
#define csr_missed_frames csr_8
#define csr_enetrom csr_9 /* 21040 */
#define csr_reserved csr_10 /* 21040 */
#define csr_full_duplex csr_11 /* 21040 */
#define csr_bootrom csr_10 /* 21041/21140A/?? */
#define csr_gp csr_12 /* 21140* */
#define csr_watchdog csr_15 /* 21140* */
#define csr_gp_timer csr_11 /* 21041/21140* */
#define csr_srom_mii csr_9 /* 21041/21140* */
#define csr_sia_status csr_12 /* 2104x */
#define csr_sia_connectivity csr_13 /* 2104x */
#define csr_sia_tx_rx csr_14 /* 2104x */
#define csr_sia_general csr_15 /* 2104x */
#define SROMSEL 0x0800
#define SROMCS 0x0001
#define SROMCLKON 0x0002
#define SROMCLKOFF 0x0002
#define SROMRD 0x4000
#define SROMWR 0x2000
#define SROM_BITWIDTH 6
#define SROMCMD_RD 6
#define SROMCSON 0x0001
#define SROMDOUT 0x0004
#define SROMDIN 0x0008
struct txdesc {
unsigned long status; /* owner, status */
unsigned long buf1sz:11, /* size of buffer 1 */
buf2sz:11, /* size of buffer 2 */
control:10; /* control bits */
const unsigned char *buf1addr; /* buffer 1 address */
const unsigned char *buf2addr; /* buffer 2 address */
};
struct rxdesc {
unsigned long status; /* owner, status */
unsigned long buf1sz:11, /* size of buffer 1 */
buf2sz:11, /* size of buffer 2 */
control:10; /* control bits */
unsigned char *buf1addr; /* buffer 1 address */
unsigned char *buf2addr; /* buffer 2 address */
};
+501
View File
@@ -0,0 +1,501 @@
/*
** Support for NE2000 PCI clones added David Monro June 1997
** Generalised to other NICs by Ken Yap July 1997
**
** Most of this is taken from:
**
** /usr/src/linux/drivers/pci/pci.c
** /usr/src/linux/include/linux/pci.h
** /usr/src/linux/arch/i386/bios32.c
** /usr/src/linux/include/linux/bios32.h
** /usr/src/linux/drivers/net/ne.c
*/
/*
* 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, or (at
* your option) any later version.
*/
#include "etherboot.h"
#include "pci.h"
/*#define DEBUG 1*/
#define DEBUG 0
#ifdef CONFIG_PCI_DIRECT
#define PCIBIOS_SUCCESSFUL 0x00
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn,
unsigned int where, unsigned char *value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inb(0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
int pcibios_read_config_word (unsigned int bus,
unsigned int device_fn, unsigned int where, unsigned short *value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inw(0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn,
unsigned int where, unsigned int *value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inl(0xCFC);
return PCIBIOS_SUCCESSFUL;
}
int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn,
unsigned int where, unsigned char value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outb(value, 0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
int pcibios_write_config_word (unsigned int bus, unsigned int device_fn,
unsigned int where, unsigned short value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outw(value, 0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value)
{
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outl(value, 0xCFC);
return PCIBIOS_SUCCESSFUL;
}
#undef CONFIG_CMD
#else /* CONFIG_PCI_DIRECT not defined */
static struct {
unsigned long address;
unsigned short segment;
} bios32_indirect = { 0, KERN_CODE_SEG };
static long pcibios_entry;
static struct {
unsigned long address;
unsigned short segment;
} pci_indirect = { 0, KERN_CODE_SEG };
static unsigned long bios32_service(unsigned long service)
{
unsigned char return_code; /* %al */
unsigned long address; /* %ebx */
unsigned long length; /* %ecx */
unsigned long entry; /* %edx */
unsigned long flags;
save_flags(flags);
__asm__(
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%edi)"
#else
"lcall *(%%edi)"
#endif
: "=a" (return_code),
"=b" (address),
"=c" (length),
"=d" (entry)
: "0" (service),
"1" (0),
"D" (&bios32_indirect));
restore_flags(flags);
switch (return_code) {
case 0:
return address + entry;
case 0x80: /* Not present */
printf("bios32_service(%d) : not present\n", service);
return 0;
default: /* Shouldn't happen */
printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n",
service, return_code);
return 0;
}
}
int pcibios_read_config_byte(unsigned int bus,
unsigned int device_fn, unsigned int where, unsigned char *value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
save_flags(flags);
__asm__(
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_BYTE),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
int pcibios_read_config_word(unsigned int bus,
unsigned int device_fn, unsigned int where, unsigned short *value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
save_flags(flags);
__asm__(
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_WORD),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
int pcibios_read_config_dword(unsigned int bus,
unsigned int device_fn, unsigned int where, unsigned int *value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
save_flags(flags);
__asm__(
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_DWORD),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
int pcibios_write_config_byte (unsigned int bus,
unsigned int device_fn, unsigned int where, unsigned char value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
save_flags(flags); cli();
__asm__(
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
int pcibios_write_config_word (unsigned int bus,
unsigned int device_fn, unsigned int where, unsigned short value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
save_flags(flags); cli();
__asm__(
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_WORD),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
int pcibios_write_config_dword (unsigned int bus,
unsigned int device_fn, unsigned int where, unsigned int value)
{
unsigned long ret;
unsigned long bx = (bus << 8) | device_fn;
unsigned long flags;
save_flags(flags); cli();
__asm__(
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
static void check_pcibios(void)
{
unsigned long signature;
unsigned char present_status;
unsigned char major_revision;
unsigned char minor_revision;
unsigned long flags;
int pack;
if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
pci_indirect.address = pcibios_entry;
save_flags(flags);
__asm__(
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%edi)\n\t"
#else
"lcall *(%%edi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:\tshl $8, %%eax\n\t"
"movw %%bx, %%ax"
: "=d" (signature),
"=a" (pack)
: "1" (PCIBIOS_PCI_BIOS_PRESENT),
"D" (&pci_indirect)
: "bx", "cx");
restore_flags(flags);
present_status = (pack >> 16) & 0xff;
major_revision = (pack >> 8) & 0xff;
minor_revision = pack & 0xff;
if (present_status || (signature != PCI_SIGNATURE)) {
printf("ERROR: BIOS32 says PCI BIOS, but no PCI "
"BIOS????\n");
pcibios_entry = 0;
}
#if DEBUG
if (pcibios_entry) {
printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"
" entry at %#X\n", major_revision,
minor_revision, pcibios_entry);
}
#endif
}
}
static void pcibios_init(void)
{
union bios32 *check;
unsigned char sum;
int i, length;
unsigned long bios32_entry = 0;
/*
* Follow the standard procedure for locating the BIOS32 Service
* directory by scanning the permissible address range from
* 0xe0000 through 0xfffff for a valid BIOS32 structure.
*
*/
for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
if (check->fields.signature != BIOS32_SIGNATURE)
continue;
length = check->fields.length * 16;
if (!length)
continue;
sum = 0;
for (i = 0; i < length ; ++i)
sum += check->chars[i];
if (sum != 0)
continue;
if (check->fields.revision != 0) {
printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n",
check->fields.revision, check);
continue;
}
#if DEBUG
printf("pcibios_init : BIOS32 Service Directory "
"structure at %#X\n", check);
#endif
if (!bios32_entry) {
if (check->fields.entry >= 0x100000) {
printf("pcibios_init: entry in high "
"memory, giving up\n");
return;
} else {
bios32_entry = check->fields.entry;
#if DEBUG
printf("pcibios_init : BIOS32 Service Directory"
" entry at %#X\n", bios32_entry);
#endif
bios32_indirect.address = bios32_entry;
}
}
}
if (bios32_entry)
check_pcibios();
}
#endif /* CONFIG_PCI_DIRECT not defined*/
static void scan_bus(struct pci_device *pcidev)
{
unsigned int devfn, l, bus, buses;
unsigned char hdr_type = 0;
unsigned short vendor, device;
unsigned int membase, ioaddr, romaddr;
int i, reg;
unsigned int pci_ioaddr = 0;
/* Scan all PCI buses, until we find our card.
* We could be smart only scan the required busses but that
* is error prone, and tricky.
* By scanning all possible pci busses in order we should find
* our card eventually.
*/
buses=256;
for (bus = 0; bus < buses; ++bus) {
for (devfn = 0; devfn < 0xff; ++devfn) {
if (PCI_FUNC (devfn) == 0)
pcibios_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
else if (!(hdr_type & 0x80)) /* not a multi-function device */
continue;
pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l);
/* some broken boards return 0 if a slot is empty: */
if (l == 0xffffffff || l == 0x00000000) {
hdr_type = 0;
continue;
}
vendor = l & 0xffff;
device = (l >> 16) & 0xffff;
#if DEBUG
printf("bus %hhX, function %hhX, vendor %hX, device %hX\n",
bus, devfn, vendor, device);
#endif
for (i = 0; pcidev[i].vendor != 0; i++) {
if (vendor != pcidev[i].vendor
|| device != pcidev[i].dev_id)
continue;
pcidev[i].devfn = devfn;
pcidev[i].bus = bus;
for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
pcibios_read_config_dword(bus, devfn, reg, &ioaddr);
if ((ioaddr & PCI_BASE_ADDRESS_IO_MASK) == 0 || (ioaddr & PCI_BASE_ADDRESS_SPACE_IO) == 0)
continue;
/* Strip the I/O address out of the returned value */
ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
/* Get the memory base address */
pcibios_read_config_dword(bus, devfn,
PCI_BASE_ADDRESS_1, &membase);
/* Get the ROM base address */
pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
romaddr >>= 10;
printf("Found %s at %#hx, ROM address %#hx\n",
pcidev[i].name, ioaddr, romaddr);
/* Take the first one or the one that matches in boot ROM address */
if (pci_ioaddr == 0 || romaddr == ((unsigned long) rom.rom_segment << 4)) {
pcidev[i].membase = membase;
pcidev[i].ioaddr = ioaddr;
return;
}
}
}
}
}
}
void eth_pci_init(struct pci_device *pcidev)
{
#ifndef CONFIG_PCI_DIRECT
pcibios_init();
if (!pcibios_entry) {
printf("pci_init: no BIOS32 detected\n");
return;
}
#endif
scan_bus(pcidev);
/* return values are in pcidev structures */
}
/*
* Set device to be a busmaster in case BIOS neglected to do so.
* Also adjust PCI latency timer to a reasonable value, 32.
*/
void adjust_pci_device(struct pci_device *p)
{
unsigned short new_command, pci_command;
unsigned char pci_latency;
pcibios_read_config_word(p->bus, p->devfn, PCI_COMMAND, &pci_command);
new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
if (pci_command != new_command) {
printf("The PCI BIOS has not enabled this device!\nUpdating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n",
pci_command, new_command, p->bus, p->devfn);
pcibios_write_config_word(p->bus, p->devfn, PCI_COMMAND, new_command);
}
pcibios_read_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 32) {
printf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency);
pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32);
}
}
+192
View File
@@ -0,0 +1,192 @@
#ifndef PCI_H
#define PCI_H
/*
** Support for NE2000 PCI clones added David Monro June 1997
** Generalised for other PCI NICs by Ken Yap July 1997
**
** Most of this is taken from:
**
** /usr/src/linux/drivers/pci/pci.c
** /usr/src/linux/include/linux/pci.h
** /usr/src/linux/arch/i386/bios32.c
** /usr/src/linux/include/linux/bios32.h
** /usr/src/linux/drivers/net/ne.c
*/
/*
* 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, or (at
* your option) any later version.
*/
#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
#define PCI_COMMAND_MEM 0x2 /* Enable response in mem space */
#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
#define PCIBIOS_PCI_BIOS_PRESENT 0xb101
#define PCIBIOS_FIND_PCI_DEVICE 0xb102
#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
#define PCIBIOS_READ_CONFIG_BYTE 0xb108
#define PCIBIOS_READ_CONFIG_WORD 0xb109
#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
#define PCI_VENDOR_ID 0x00 /* 16 bits */
#define PCI_DEVICE_ID 0x02 /* 16 bits */
#define PCI_COMMAND 0x04 /* 16 bits */
#define PCI_REVISION 0x08 /* 8 bits */
#define PCI_CLASS_CODE 0x0b /* 8 bits */
#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */
#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */
#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
#ifndef PCI_BASE_ADDRESS_IO_MASK
#define PCI_BASE_ADDRESS_IO_MASK (~0x03)
#endif
#define PCI_BASE_ADDRESS_SPACE_IO 0x01
#define PCI_ROM_ADDRESS 0x30 /* 32 bits */
#define PCI_ROM_ADDRESS_ENABLE 0x01 /* Write 1 to enable ROM,
bits 31..11 are address,
10..2 are reserved */
#define PCI_FUNC(devfn) ((devfn) & 0x07)
#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
/* PCI signature: "PCI " */
#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
/* PCI service signature: "$PCI" */
#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
union bios32 {
struct {
unsigned long signature; /* _32_ */
unsigned long entry; /* 32 bit physical address */
unsigned char revision; /* Revision level, 0 */
unsigned char length; /* Length in paragraphs should be 01 */
unsigned char checksum; /* All bytes must add up to zero */
unsigned char reserved[5]; /* Must be zero */
} fields;
char chars[16];
};
#define KERN_CODE_SEG 0x8 /* This _MUST_ match start.S */
/* Stuff for asm */
#define save_flags(x) \
__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
#define cli() __asm__ __volatile__ ("cli": : :"memory")
#define restore_flags(x) \
__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
#define PCI_VENDOR_ID_ADMTEK 0x1317
#define PCI_DEVICE_ID_ADMTEK_0985 0x0985
#define PCI_VENDOR_ID_REALTEK 0x10ec
#define PCI_DEVICE_ID_REALTEK_8029 0x8029
#define PCI_DEVICE_ID_REALTEK_8139 0x8139
#define PCI_VENDOR_ID_WINBOND2 0x1050
#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940
#define PCI_DEVICE_ID_WINBOND2_89C840 0x0840
#define PCI_VENDOR_ID_COMPEX 0x11f6
#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401
#define PCI_DEVICE_ID_COMPEX_RL100ATX 0x2011
#define PCI_VENDOR_ID_KTI 0x8e2e
#define PCI_DEVICE_ID_KTI_ET32P2 0x3000
#define PCI_VENDOR_ID_NETVIN 0x4a14
#define PCI_DEVICE_ID_NETVIN_NV5000SC 0x5000
#define PCI_VENDOR_ID_HOLTEK 0x12c3
#define PCI_DEVICE_ID_HOLTEK_HT80232 0x0058
#define PCI_VENDOR_ID_3COM 0x10b7
#define PCI_DEVICE_ID_3COM_3C590 0x5900
#define PCI_DEVICE_ID_3COM_3C595 0x5950
#define PCI_DEVICE_ID_3COM_3C595_1 0x5951
#define PCI_DEVICE_ID_3COM_3C595_2 0x5952
#define PCI_DEVICE_ID_3COM_3C900TPO 0x9000
#define PCI_DEVICE_ID_3COM_3C900COMBO 0x9001
#define PCI_DEVICE_ID_3COM_3C905TX 0x9050
#define PCI_DEVICE_ID_3COM_3C905T4 0x9051
#define PCI_DEVICE_ID_3COM_3C905B_TX 0x9055
#define PCI_DEVICE_ID_3COM_3C905C_TXM 0x9200
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_82557 0x1229
#define PCI_DEVICE_ID_INTEL_82559ER 0x1209
#define PCI_DEVICE_ID_INTEL_ID1029 0x1029
#define PCI_DEVICE_ID_INTEL_ID1030 0x1030
#define PCI_DEVICE_ID_INTEL_82562 0x2449
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_VENDOR_ID_AMD_HOMEPNA 0x1022
#define PCI_DEVICE_ID_AMD_HOMEPNA 0x2001
#define PCI_VENDOR_ID_SMC_1211 0x1113
#define PCI_DEVICE_ID_SMC_1211 0x1211
#define PCI_VENDOR_ID_DEC 0x1011
#define PCI_DEVICE_ID_DEC_TULIP 0x0002
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
#define PCI_DEVICE_ID_DEC_21142 0x0019
#define PCI_VENDOR_ID_SMC 0x10B8
#ifndef PCI_DEVICE_ID_SMC_EPIC100
# define PCI_DEVICE_ID_SMC_EPIC100 0x0005
#endif
#define PCI_VENDOR_ID_MACRONIX 0x10d9
#define PCI_DEVICE_ID_MX987x5 0x0531
#define PCI_VENDOR_ID_LINKSYS 0x11AD
#define PCI_DEVICE_ID_LC82C115 0xC115
#define PCI_VENDOR_ID_VIATEC 0x1106
#define PCI_DEVICE_ID_VIA_RHINE_I 0x3043
#define PCI_DEVICE_ID_VIA_VT6102 0x3065
#define PCI_DEVICE_ID_VIA_86C100A 0x6100
#define PCI_VENDOR_ID_DAVICOM 0x1282
#define PCI_DEVICE_ID_DM9009 0x9009
#define PCI_DEVICE_ID_DM9102 0x9102
#define PCI_VENDOR_ID_SIS 0x1039
#define PCI_DEVICE_ID_SIS900 0x0900
#define PCI_DEVICE_ID_SIS7016 0x7016
#define PCI_VENDOR_ID_DLINK 0x1186
#define PCI_DEVICE_ID_DFE530TXP 0x1300
#define PCI_VENDOR_ID_NS 0x100B
#define PCI_DEVICE_ID_DP83815 0x0020
#define PCI_VENDOR_ID_OLICOM 0x108d
#define PCI_DEVICE_ID_OLICOM_OC3136 0x0001
#define PCI_DEVICE_ID_OLICOM_OC2315 0x0011
#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012
#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013
#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014
#define PCI_DEVICE_ID_OLICOM_OC6151 0x0021
struct pci_device {
unsigned short vendor, dev_id;
const char *name;
unsigned int membase;
unsigned short ioaddr;
unsigned char devfn;
unsigned char bus;
};
extern void eth_pci_init(struct pci_device *);
extern int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char *value);
extern int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char value);
extern int pcibios_read_config_word(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short *value);
extern int pcibios_write_config_word (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short value);
extern int pcibios_read_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int *value);
extern int pcibios_write_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value);
void adjust_pci_device(struct pci_device *p);
#endif /* PCI_H */
+458
View File
@@ -0,0 +1,458 @@
/* rtl8139.c - etherboot driver for the Realtek 8139 chipset
ported from the linux driver written by Donald Becker
by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
changes to the original driver:
- removed support for interrupts, switching to polling mode (yuck!)
- removed support for the 8129 chip (external MII)
*/
/*********************************************************************/
/* Revision History */
/*********************************************************************/
/*
06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap)
Following email from Hyun-Joon Cha, added a disable routine, otherwise
NIC remains live and can crash the kernel later.
4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub)
Shuffled things around, removed the leftovers from the 8129 support
that was in the Linux driver and added a bit more 8139 definitions.
Moved the 8K receive buffer to a fixed, available address outside the
0x98000-0x9ffff range. This is a bit of a hack, but currently the only
way to make room for the Etherboot features that need substantial amounts
of code like the ANSI console support. Currently the buffer is just below
0x10000, so this even conforms to the tagged boot image specification,
which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My
interpretation of this "reserved" is that Etherboot may do whatever it
likes, as long as its environment is kept intact (like the BIOS
variables). Hopefully fixed rtl_poll() once and for all. The symptoms
were that if Etherboot was left at the boot menu for several minutes, the
first eth_poll failed. Seems like I am the only person who does this.
First of all I fixed the debugging code and then set out for a long bug
hunting session. It took me about a week full time work - poking around
various places in the driver, reading Don Becker's and Jeff Garzik's Linux
driver and even the FreeBSD driver (what a piece of crap!) - and
eventually spotted the nasty thing: the transmit routine was acknowledging
each and every interrupt pending, including the RxOverrun and RxFIFIOver
interrupts. This confused the RTL8139 thoroughly. It destroyed the
Rx ring contents by dumping the 2K FIFO contents right where we wanted to
get the next packet. Oh well, what fun.
18 Jan 2000 mdc@thinguin.org (Marty Connor)
Drastically simplified error handling. Basically, if any error
in transmission or reception occurs, the card is reset.
Also, pointed all transmit descriptors to the same buffer to
save buffer space. This should decrease driver size and avoid
corruption because of exceeding 32K during runtime.
28 Jul 1999 (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de)
rtl_poll was quite broken: it used the RxOK interrupt flag instead
of the RxBufferEmpty flag which often resulted in very bad
transmission performace - below 1kBytes/s.
*/
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "cards.h"
#include "timer.h"
#define RTL_TIMEOUT (1*TICKS_PER_SEC)
/* PCI Tuning Parameters
Threshold is bytes transferred to chip before transmission starts. */
#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
#define TX_DMA_BURST 4 /* Calculate as 16<<val. */
#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */
#define TX_BUF_SIZE ETH_FRAME_LEN /* FCS is added by the chip */
#define RX_BUF_LEN_IDX 0 /* 0, 1, 2 is allowed - 8,16,32K rx buffer */
#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
#undef DEBUG_TX
#undef DEBUG_RX
/* Symbolic offsets to registers. */
enum RTL8139_registers {
MAC0=0, /* Ethernet hardware address. */
MAR0=8, /* Multicast filter. */
TxStatus0=0x10, /* Transmit status (four 32bit registers). */
TxAddr0=0x20, /* Tx descriptors (also four 32bit). */
RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
IntrMask=0x3C, IntrStatus=0x3E,
TxConfig=0x40, RxConfig=0x44,
Timer=0x48, /* general-purpose counter. */
RxMissed=0x4C, /* 24 bits valid, write clears. */
Cfg9346=0x50, Config0=0x51, Config1=0x52,
TimerIntrReg=0x54, /* intr if gp counter reaches this value */
MediaStatus=0x58,
Config3=0x59,
MultiIntr=0x5C,
RevisionID=0x5E, /* revision of the RTL8139 chip */
TxSummary=0x60,
MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
NWayExpansion=0x6A,
DisconnectCnt=0x6C, FalseCarrierCnt=0x6E,
NWayTestReg=0x70,
RxCnt=0x72, /* packet received counter */
CSCR=0x74, /* chip status and configuration register */
PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80, /* undocumented */
/* from 0x84 onwards are a number of power management/wakeup frame
* definitions we will probably never need to know about. */
};
enum ChipCmdBits {
CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
/* Interrupt register bits, using my own meaningful names. */
enum IntrStatusBits {
PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000,
RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
};
enum TxStatusBits {
TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
TxOutOfWindow=0x20000000, TxAborted=0x40000000,
TxCarrierLost=0x80000000,
};
enum RxStatusBits {
RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
RxBadAlign=0x0002, RxStatusOK=0x0001,
};
enum MediaStatusBits {
MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08,
MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01,
};
enum MIIBMCRBits {
BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000,
BMCRRestartNWay=0x0200, BMCRDuplex=0x0100,
};
enum CSCRBits {
CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
CSCR_LinkDownCmd=0x0f3c0,
};
/* Bits in RxConfig. */
enum rx_mode_bits {
RxCfgWrap=0x80,
AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
};
static int ioaddr;
static unsigned int cur_rx,cur_tx;
/* The RTL8139 can only transmit from a contiguous, aligned memory block. */
static unsigned char tx_buffer[TX_BUF_SIZE] __attribute__((aligned(4)));
/* I know that this is a MEGA HACK, but the tagged boot image specification
* states that we can do whatever we want below 0x10000 - so we do! */
/* But we still give the user the choice of using an internal buffer
just in case - Ken */
#ifdef USE_LOWMEM_BUFFER
#define rx_ring ((unsigned char *)(0x10000 - (RX_BUF_LEN + 16)))
#else
static unsigned char rx_ring[RX_BUF_LEN+16] __attribute__((aligned(4)));
#endif
struct nic *rtl8139_probe(struct nic *nic, unsigned short *probeaddrs,
struct pci_device *pci);
static int read_eeprom(int location);
static void rtl_reset(struct nic *nic);
static void rtl_transmit(struct nic *nic, const char *destaddr,
unsigned int type, unsigned int len, const char *data);
static int rtl_poll(struct nic *nic);
static void rtl_disable(struct nic*);
struct nic *rtl8139_probe(struct nic *nic, unsigned short *probeaddrs,
struct pci_device *pci)
{
int i;
int speed10, fullduplex;
/* There are enough "RTL8139" strings on the console already, so
* be brief and concentrate on the interesting pieces of info... */
printf(" - ");
/* Mask the bit that says "this is an io addr" */
ioaddr = probeaddrs[0] & ~3;
adjust_pci_device(pci);
/* Bring the chip out of low-power mode. */
outb(0x00, ioaddr + Config1);
if (read_eeprom(0) != 0xffff) {
unsigned short *ap = (unsigned short*)nic->node_addr;
for (i = 0; i < 3; i++)
*ap++ = read_eeprom(i + 7);
} else {
unsigned char *ap = (unsigned char*)nic->node_addr;
for (i = 0; i < ETH_ALEN; i++)
*ap++ = inb(ioaddr + MAC0 + i);
}
speed10 = inb(ioaddr + MediaStatus) & MSRSpeed10;
fullduplex = inw(ioaddr + MII_BMCR) & BMCRDuplex;
printf("ioaddr %#hX, addr %! %sMbps %s-duplex\n", ioaddr,
nic->node_addr, speed10 ? "10" : "100",
fullduplex ? "full" : "half");
rtl_reset(nic);
nic->reset = rtl_reset;
nic->poll = rtl_poll;
nic->transmit = rtl_transmit;
nic->disable = rtl_disable;
return nic;
}
/* Serial EEPROM section. */
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
#define EE_CS 0x08 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
#define EE_WRITE_0 0x00
#define EE_WRITE_1 0x02
#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
#define EE_ENB (0x80 | EE_CS)
/*
Delay between EEPROM clock transitions.
No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
*/
#define eeprom_delay() inl(ee_addr)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
#define EE_READ_CMD (6 << 6)
#define EE_ERASE_CMD (7 << 6)
static int read_eeprom(int location)
{
int i;
unsigned int retval = 0;
long ee_addr = ioaddr + Cfg9346;
int read_cmd = location | EE_READ_CMD;
outb(EE_ENB & ~EE_CS, ee_addr);
outb(EE_ENB, ee_addr);
/* Shift the read command bits out. */
for (i = 10; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outb(EE_ENB | dataval, ee_addr);
eeprom_delay();
outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
}
outb(EE_ENB, ee_addr);
eeprom_delay();
for (i = 16; i > 0; i--) {
outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
outb(EE_ENB, ee_addr);
eeprom_delay();
}
/* Terminate the EEPROM access. */
outb(~EE_CS, ee_addr);
return retval;
}
static void rtl_reset(struct nic* nic)
{
int i;
outb(CmdReset, ioaddr + ChipCmd);
cur_rx = 0;
cur_tx = 0;
/* Give the chip 10ms to finish the reset. */
load_timer2(10*TICKS_PER_MS);
while ((inb(ioaddr + ChipCmd) & CmdReset) != 0 && timer2_running())
/* wait */;
for (i = 0; i < ETH_ALEN; i++)
outb(nic->node_addr[i], ioaddr + MAC0 + i);
/* Must enable Tx/Rx before setting transfer thresholds! */
outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8),
ioaddr + RxConfig); /* accept no frames yet! */
outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
/* The Linux driver changes Config1 here to use a different LED pattern
* for half duplex or full/autodetect duplex (for full/autodetect, the
* outputs are TX/RX, Link10/100, FULL, while for half duplex it uses
* TX/RX, Link100, Link10). This is messy, because it doesn't match
* the inscription on the mounting bracket. It should not be changed
* from the configuration EEPROM default, because the card manufacturer
* should have set that to match the card. */
#ifdef DEBUG_RX
printf("rx ring address is %X\n",(unsigned long)rx_ring);
#endif
outl((unsigned long)rx_ring, ioaddr + RxBuf);
/* Start the chip's Tx and Rx process. */
outl(0, ioaddr + RxMissed);
/* set_rx_mode */
outb(AcceptBroadcast|AcceptMyPhys, ioaddr + RxConfig);
/* If we add multicast support, the MAR0 register would have to be
* initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot
* only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast. */
outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
/* Disable all known interrupts by setting the interrupt mask. */
outw(0, ioaddr + IntrMask);
}
static void rtl_transmit(struct nic *nic, const char *destaddr,
unsigned int type, unsigned int len, const char *data)
{
unsigned int status, to, nstype;
unsigned long txstatus;
memcpy(tx_buffer, destaddr, ETH_ALEN);
memcpy(tx_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN);
nstype = htons(type);
memcpy(tx_buffer + 2 * ETH_ALEN, (char*)&nstype, 2);
memcpy(tx_buffer + ETH_HLEN, data, len);
len += ETH_HLEN;
#ifdef DEBUG_TX
printf("sending %d bytes ethtype %hX\n", len, type);
#endif
/* Note: RTL8139 doesn't auto-pad, send minimum payload (another 4
* bytes are sent automatically for the FCS, totalling to 64 bytes). */
while (len < ETH_ZLEN) {
tx_buffer[len++] = '\0';
}
outl((unsigned long)tx_buffer, ioaddr + TxAddr0 + cur_tx*4);
outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len,
ioaddr + TxStatus0 + cur_tx*4);
to = currticks() + RTL_TIMEOUT;
do {
status = inw(ioaddr + IntrStatus);
/* Only acknlowledge interrupt sources we can properly handle
* here - the RxOverflow/RxFIFOOver MUST be handled in the
* rtl_poll() function. */
outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus);
if ((status & (TxOK | TxErr | PCIErr)) != 0) break;
} while (currticks() < to);
txstatus = inl(ioaddr+ TxStatus0 + cur_tx*4);
if (status & TxOK) {
cur_tx = (cur_tx + 1) % NUM_TX_DESC;
#ifdef DEBUG_TX
printf("tx done (%d ticks), status %hX txstatus %X\n",
to-currticks(), status, txstatus);
#endif
} else {
#ifdef DEBUG_TX
printf("tx timeout/error (%d ticks), status %hX txstatus %X\n",
currticks()-to, status, txstatus);
#endif
rtl_reset(nic);
}
}
static int rtl_poll(struct nic *nic)
{
unsigned int status;
unsigned int ring_offs;
unsigned int rx_size, rx_status;
if (inb(ioaddr + ChipCmd) & RxBufEmpty) {
return 0;
}
status = inw(ioaddr + IntrStatus);
/* See below for the rest of the interrupt acknowledges. */
outw(status & ~(RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);
#ifdef DEBUG_RX
printf("rtl_poll: int %hX ", status);
#endif
ring_offs = cur_rx % RX_BUF_LEN;
rx_status = *(unsigned int*)(rx_ring + ring_offs);
rx_size = rx_status >> 16;
rx_status &= 0xffff;
if ((rx_status & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) ||
(rx_size < ETH_ZLEN) || (rx_size > ETH_FRAME_LEN + 4)) {
printf("rx error %hX\n", rx_status);
rtl_reset(nic); /* this clears all interrupts still pending */
return 0;
}
/* Received a good packet */
nic->packetlen = rx_size - 4; /* no one cares about the FCS */
if (ring_offs+4+rx_size-4 > RX_BUF_LEN) {
int semi_count = RX_BUF_LEN - ring_offs - 4;
memcpy(nic->packet, rx_ring + ring_offs + 4, semi_count);
memcpy(nic->packet+semi_count, rx_ring, rx_size-4-semi_count);
#ifdef DEBUG_RX
printf("rx packet %d+%d bytes", semi_count,rx_size-4-semi_count);
#endif
} else {
memcpy(nic->packet, rx_ring + ring_offs + 4, nic->packetlen);
#ifdef DEBUG_RX
printf("rx packet %d bytes", rx_size-4);
#endif
}
#ifdef DEBUG_RX
printf(" at %X type %hhX%hhX rxstatus %hX\n",
(unsigned long)(rx_ring+ring_offs+4),
nic->packet[12], nic->packet[13], rx_status);
#endif
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
outw(cur_rx - 16, ioaddr + RxBufPtr);
/* See RTL8139 Programming Guide V0.1 for the official handling of
* Rx overflow situations. The document itself contains basically no
* usable information, except for a few exception handling rules. */
outw(status & (RxFIFOOver | RxOverflow | RxOK), ioaddr + IntrStatus);
return 1;
}
static void rtl_disable(struct nic *nic)
{
/* reset the chip */
outb(CmdReset, ioaddr + ChipCmd);
/* 10 ms timeout */
load_timer2(10*TICKS_PER_MS);
while ((inb(ioaddr + ChipCmd) & CmdReset) != 0 && timer2_running())
/* wait */;
}
+1034
View File
File diff suppressed because it is too large. Load diff
+363
View File
@@ -0,0 +1,363 @@
/* -*- Mode:C; c-basic-offset:4; -*- */
/* Definitions for SiS ethernet controllers including 7014/7016 and 900
* References:
* SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
* preliminary Rev. 1.0 Jan. 14, 1998
* SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
* preliminary Rev. 1.0 Nov. 10, 1998
* SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
* preliminary Rev. 1.0 Jan. 18, 1998
* http://www.sis.com.tw/support/databook.htm
*/
/* MAC operationl registers of SiS 7016 and SiS 900 ethernet controller */
/* The I/O extent, SiS 900 needs 256 bytes of io address */
#define SIS900_TOTAL_SIZE 0x100
/* Symbolic offsets to registers. */
enum sis900_registers {
cr=0x0, /* Command Register */
cfg=0x4, /* Configuration Register */
mear=0x8, /* EEPROM Access Register */
ptscr=0xc, /* PCI Test Control Register */
isr=0x10, /* Interrupt Status Register */
imr=0x14, /* Interrupt Mask Register */
ier=0x18, /* Interrupt Enable Register */
epar=0x18, /* Enhanced PHY Access Register */
txdp=0x20, /* Transmit Descriptor Pointer Register */
txcfg=0x24, /* Transmit Configuration Register */
rxdp=0x30, /* Receive Descriptor Pointer Register */
rxcfg=0x34, /* Receive Configuration Register */
flctrl=0x38, /* Flow Control Register */
rxlen=0x3c, /* Receive Packet Length Register */
rfcr=0x48, /* Receive Filter Control Register */
rfdr=0x4C, /* Receive Filter Data Register */
pmctrl=0xB0, /* Power Management Control Register */
pmer=0xB4 /* Power Management Wake-up Event Register */
};
/* Symbolic names for bits in various registers */
enum sis900_command_register_bits {
RESET = 0x00000100,
SWI = 0x00000080,
RxRESET = 0x00000020,
TxRESET = 0x00000010,
RxDIS = 0x00000008,
RxENA = 0x00000004,
TxDIS = 0x00000002,
TxENA = 0x00000001
};
enum sis900_configuration_register_bits {
DESCRFMT = 0x00000100, /* 7016 specific */
REQALG = 0x00000080,
SB = 0x00000040,
POW = 0x00000020,
EXD = 0x00000010,
PESEL = 0x00000008,
LPM = 0x00000004,
BEM = 0x00000001
};
enum sis900_eeprom_access_reigster_bits {
MDC = 0x00000040,
MDDIR = 0x00000020,
MDIO = 0x00000010, /* 7016 specific */
EECS = 0x00000008,
EECLK = 0x00000004,
EEDO = 0x00000002,
EEDI = 0x00000001
};
enum sis900_interrupt_register_bits {
WKEVT = 0x10000000,
TxPAUSEEND = 0x08000000,
TxPAUSE = 0x04000000,
TxRCMP = 0x02000000,
RxRCMP = 0x01000000,
DPERR = 0x00800000,
SSERR = 0x00400000,
RMABT = 0x00200000,
RTABT = 0x00100000,
RxSOVR = 0x00010000,
HIBERR = 0x00008000,
SWINT = 0x00001000,
MIBINT = 0x00000800,
TxURN = 0x00000400,
TxIDLE = 0x00000200,
TxERR = 0x00000100,
TxDESC = 0x00000080,
TxOK = 0x00000040,
RxORN = 0x00000020,
RxIDLE = 0x00000010,
RxEARLY = 0x00000008,
RxERR = 0x00000004,
RxDESC = 0x00000002,
RxOK = 0x00000001
};
enum sis900_interrupt_enable_reigster_bits {
IE = 0x00000001
};
/* maximum dma burst fro transmission and receive*/
#define MAX_DMA_RANGE 7 /* actually 0 means MAXIMUM !! */
#define TxMXDMA_shift 20
#define RxMXDMA_shift 20
#define TX_DMA_BURST 0
#define RX_DMA_BURST 0
/* transmit FIFO threshholds */
#define TX_FILL_THRESH 16 /* 1/4 FIFO size */
#define TxFILLT_shift 8
#define TxDRNT_shift 0
#define TxDRNT_100 48 /* 3/4 FIFO size */
#define TxDRNT_10 16 /* 1/2 FIFO size */
enum sis900_transmit_config_register_bits {
TxCSI = 0x80000000,
TxHBI = 0x40000000,
TxMLB = 0x20000000,
TxATP = 0x10000000,
TxIFG = 0x0C000000,
TxFILLT = 0x00003F00,
TxDRNT = 0x0000003F
};
/* recevie FIFO thresholds */
#define RxDRNT_shift 1
#define RxDRNT_100 16 /* 1/2 FIFO size */
#define RxDRNT_10 24 /* 3/4 FIFO size */
enum sis900_reveive_config_register_bits {
RxAEP = 0x80000000,
RxARP = 0x40000000,
RxATX = 0x10000000,
RxAJAB = 0x08000000,
RxDRNT = 0x0000007F
};
#define RFAA_shift 28
#define RFADDR_shift 16
enum sis900_receive_filter_control_register_bits {
RFEN = 0x80000000,
RFAAB = 0x40000000,
RFAAM = 0x20000000,
RFAAP = 0x10000000,
RFPromiscuous = (RFAAB|RFAAM|RFAAP)
};
enum sis900_reveive_filter_data_mask {
RFDAT = 0x0000FFFF
};
/* EEPROM Addresses */
enum sis900_eeprom_address {
EEPROMSignature = 0x00,
EEPROMVendorID = 0x02,
EEPROMDeviceID = 0x03,
EEPROMMACAddr = 0x08,
EEPROMChecksum = 0x0b
};
/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
enum sis900_eeprom_command {
EEread = 0x0180,
EEwrite = 0x0140,
EEerase = 0x01C0,
EEwriteEnable = 0x0130,
EEwriteDisable = 0x0100,
EEeraseAll = 0x0120,
EEwriteAll = 0x0110,
EEaddrMask = 0x013F,
};
/* Manamgement Data I/O (mdio) frame */
#define MIIread 0x6000
#define MIIwrite 0x5002
#define MIIpmdShift 7
#define MIIregShift 2
#define MIIcmdLen 16
#define MIIcmdShift 16
/* Buffer Descriptor Status*/
enum sis900_buffer_status {
OWN = 0x80000000,
MORE = 0x40000000,
INTR = 0x20000000,
SUPCRC = 0x10000000,
INCCRC = 0x10000000,
OK = 0x08000000,
DSIZE = 0x00000FFF
};
/* Status for TX Buffers */
enum sis900_tx_buffer_status {
ABORT = 0x04000000,
UNDERRUN = 0x02000000,
NOCARRIER = 0x01000000,
DEFERD = 0x00800000,
EXCDEFER = 0x00400000,
OWCOLL = 0x00200000,
EXCCOLL = 0x00100000,
COLCNT = 0x000F0000
};
enum sis900_rx_bufer_status {
OVERRUN = 0x02000000,
DEST = 0x00800000,
BCAST = 0x01800000,
MCAST = 0x01000000,
UNIMATCH = 0x00800000,
TOOLONG = 0x00400000,
RUNT = 0x00200000,
RXISERR = 0x00100000,
CRCERR = 0x00080000,
FAERR = 0x00040000,
LOOPBK = 0x00020000,
RXCOL = 0x00010000
};
/* MII register offsets */
enum mii_registers {
MII_CONTROL = 0x0000,
MII_STATUS = 0x0001,
MII_PHY_ID0 = 0x0002,
MII_PHY_ID1 = 0x0003,
MII_ANADV = 0x0004,
MII_ANLPAR = 0x0005,
MII_ANEXT = 0x0006
};
/* mii registers specific to SiS 900 */
enum sis_mii_registers {
MII_CONFIG1 = 0x0010,
MII_CONFIG2 = 0x0011,
MII_STSOUT = 0x0012,
MII_MASK = 0x0013
};
/* mii registers specific to AMD 79C901 */
enum amd_mii_registers {
MII_STATUS_SUMMARY = 0x0018
};
/* mii registers specific to ICS 1893 */
enum ics_mii_registers {
MII_EXTCTRL = 0x0010, MII_QPDSTS = 0x0011, MII_10BTOP = 0x0012,
MII_EXTCTRL2 = 0x0013
};
/* MII Control register bit definitions. */
enum mii_control_register_bits {
MII_CNTL_FDX = 0x0100,
MII_CNTL_RST_AUTO = 0x0200,
MII_CNTL_ISOLATE = 0x0400,
MII_CNTL_PWRDWN = 0x0800,
MII_CNTL_AUTO = 0x1000,
MII_CNTL_SPEED = 0x2000,
MII_CNTL_LPBK = 0x4000,
MII_CNTL_RESET = 0x8000
};
/* MII Status register bit */
enum mii_status_register_bits {
MII_STAT_EXT = 0x0001,
MII_STAT_JAB = 0x0002,
MII_STAT_LINK = 0x0004,
MII_STAT_CAN_AUTO = 0x0008,
MII_STAT_FAULT = 0x0010,
MII_STAT_AUTO_DONE = 0x0020,
MII_STAT_CAN_T = 0x0800,
MII_STAT_CAN_T_FDX = 0x1000,
MII_STAT_CAN_TX = 0x2000,
MII_STAT_CAN_TX_FDX = 0x4000,
MII_STAT_CAN_T4 = 0x8000
};
#define MII_ID1_OUI_LO 0xFC00 /* low bits of OUI mask */
#define MII_ID1_MODEL 0x03F0 /* model number */
#define MII_ID1_REV 0x000F /* model number */
/* MII NWAY Register Bits ...
valid for the ANAR (Auto-Negotiation Advertisement) and
ANLPAR (Auto-Negotiation Link Partner) registers */
enum mii_nway_register_bits {
MII_NWAY_NODE_SEL = 0x001f,
MII_NWAY_CSMA_CD = 0x0001,
MII_NWAY_T = 0x0020,
MII_NWAY_T_FDX = 0x0040,
MII_NWAY_TX = 0x0080,
MII_NWAY_TX_FDX = 0x0100,
MII_NWAY_T4 = 0x0200,
MII_NWAY_PAUSE = 0x0400,
MII_NWAY_RF = 0x2000,
MII_NWAY_ACK = 0x4000,
MII_NWAY_NP = 0x8000
};
enum mii_stsout_register_bits {
MII_STSOUT_LINK_FAIL = 0x4000,
MII_STSOUT_SPD = 0x0080,
MII_STSOUT_DPLX = 0x0040
};
enum mii_stsics_register_bits {
MII_STSICS_SPD = 0x8000, MII_STSICS_DPLX = 0x4000,
MII_STSICS_LINKSTS = 0x0001
};
enum mii_stssum_register_bits {
MII_STSSUM_LINK = 0x0008,
MII_STSSUM_DPLX = 0x0004,
MII_STSSUM_AUTO = 0x0002,
MII_STSSUM_SPD = 0x0001
};
enum sis900_revision_id {
SIS630A_900_REV = 0x80, SIS630E_900_REV = 0x81,
SIS630S_900_REV = 0x82, SIS630EA1_900_REV = 0x83
};
enum sis630_revision_id {
SIS630A0 = 0x00, SIS630A1 = 0x01,
SIS630B0 = 0x10, SIS630B1 = 0x11
};
#define FDX_CAPABLE_DUPLEX_UNKNOWN 0
#define FDX_CAPABLE_HALF_SELECTED 1
#define FDX_CAPABLE_FULL_SELECTED 2
#define HW_SPEED_UNCONFIG 0
#define HW_SPEED_HOME 1
#define HW_SPEED_10_MBPS 10
#define HW_SPEED_100_MBPS 100
#define HW_SPEED_DEFAULT (HW_SPEED_100_MBPS)
#define CRC_SIZE 4
#define MAC_HEADER_SIZE 14
#define TX_BUF_SIZE 1536
#define RX_BUF_SIZE 1536
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
/* Time in ticks before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*TICKS_PER_SEC)
typedef struct _BufferDesc {
u32 link;
volatile u32 cmdsts;
u32 bufptr;
} BufferDesc;
+91
View File
@@ -0,0 +1,91 @@
How I added the SIS900 card to Etherboot
Author: Marty Connor (mdc@thinguin.org)
Date: 25 Febrary 2001
Description:
This file is intended to help people who want to write an Etherboot
driver or port another driver to Etherboot. It is a starting point.
Perhaps someday I may write a more detailed description of writing an
Etherboot driver. This text should help get people started, and
studying sis900.[ch] should help show the basic structure and
techniques involved in writing and Etherboot driver.
***********************************************************************
0. Back up all the files I need to modify:
cd etherboot-4.7.20/src
cp Makefile Makefile.orig
cp config.c config.c.orig
cp pci.h pci.h.orig
cp NIC NIC.orig
cp cards.h cards.h.orig
1. Edit src/Makefile to add SIS900FLAGS to defines
SIS900FLAGS= -DINCLUDE_SIS900
2. edit src/pci.h to add PCI signatures for card
#define PCI_VENDOR_ID_SIS 0x1039
#define PCI_DEVICE_ID_SIS900 0x0900
#define PCI_DEVICE_ID_SIS7016 0x7016
3. Edit src/config.c to add the card to the card probe list
#if defined(INCLUDE_NS8390) || defined(INCLUDE_EEPRO100) ||
defined(INCLUDE_LANCE) || defined(INCLUDE_EPIC100) ||
defined(INCLUDE_TULIP) || defined(INCLUDE_OTULIP) ||
defined(INCLUDE_3C90X) || defined(INCLUDE_3C595) ||
defined(INCLUDE_RTL8139) || defined(INCLUDE_VIA_RHINE) ||
defined(INCLUDE_SIS900) || defined(INCLUDE_W89C840)
... and ...
#ifdef INCLUDE_SIS900
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
"SIS900", 0, 0, 0, 0},
{ PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
"SIS7016", 0, 0, 0, 0},
#endif
... and ...
#ifdef INCLUDE_SIS900
{ "SIS900", sis900_probe, pci_ioaddrs },
#endif
4. Edit NIC to add sis900 and sis7016 to NIC list
# SIS 900 and SIS 7016
sis900 sis900 0x1039,0x0900
sis7016 sis900 0x1039,0x7016
5. Edit cards.h to add sis900 probe routine declaration
#ifdef INCLUDE_SIS900
extern struct nic *sis900_probe(struct nic *, unsigned short *
PCI_ARG(struct pci_device *));
#endif
***********************************************************************
At this point, you can begin creating your driver source file. See
the "Writing and Etherboot Driver" section of the Etherboot
documentation for some hints. See the skel.c file for a starting
point. If there is a Linux driver for the card, you may be able to
use that. Copy and learn from existing Etherboot drivers (this is GPL
/ Open Source software!).
Join the etherboot-developers and etherboot-users mailing lists
(information is on etherboot.sourceforge.net) for information and
assistance. We invite more developers to help improve Etherboot.
Visit the http://etherboot.sourceforge.net, http://thinguin.org,
http://rom-o-matic.net, and http://ltsp.org sites for information and
assistance.
Enjoy.
+1160
View File
File diff suppressed because it is too large. Load diff
+168
View File
@@ -0,0 +1,168 @@
/*-
*
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
*
* Module : sk_g16.h
* Version : $Revision$
*
* Author : M.Hipp (mhipp@student.uni-tuebingen.de)
* changes by : Patrick J.D. Weichmann
*
* Date Created : 94/05/25
*
* Description : In here are all necessary definitions of
* the am7990 (LANCE) chip used for writing a
* network device driver which uses this chip
*
* $Log$
* Revision 1.3 2000-07-29 19:22:54 okuji
* update the network support to etherboot-4.6.4.
*
-*/
#ifndef SK_G16_H
#define SK_G16_H
/*
* Control and Status Register 0 (CSR0) bit definitions
*
* (R=Readable) (W=Writeable) (S=Set on write) (C-Clear on write)
*
*/
#define CSR0_ERR 0x8000 /* Error summary (R) */
#define CSR0_BABL 0x4000 /* Babble transmitter timeout error (RC) */
#define CSR0_CERR 0x2000 /* Collision Error (RC) */
#define CSR0_MISS 0x1000 /* Missed packet (RC) */
#define CSR0_MERR 0x0800 /* Memory Error (RC) */
#define CSR0_RINT 0x0400 /* Receiver Interrupt (RC) */
#define CSR0_TINT 0x0200 /* Transmit Interrupt (RC) */
#define CSR0_IDON 0x0100 /* Initialization Done (RC) */
#define CSR0_INTR 0x0080 /* Interrupt Flag (R) */
#define CSR0_INEA 0x0040 /* Interrupt Enable (RW) */
#define CSR0_RXON 0x0020 /* Receiver on (R) */
#define CSR0_TXON 0x0010 /* Transmitter on (R) */
#define CSR0_TDMD 0x0008 /* Transmit Demand (RS) */
#define CSR0_STOP 0x0004 /* Stop (RS) */
#define CSR0_STRT 0x0002 /* Start (RS) */
#define CSR0_INIT 0x0001 /* Initialize (RS) */
#define CSR0_CLRALL 0x7f00 /* mask for all clearable bits */
/*
* Control and Status Register 3 (CSR3) bit definitions
*
*/
#define CSR3_BSWAP 0x0004 /* Byte Swap (RW) */
#define CSR3_ACON 0x0002 /* ALE Control (RW) */
#define CSR3_BCON 0x0001 /* Byte Control (RW) */
/*
* Initialization Block Mode operation Bit Definitions.
*/
#define MODE_PROM 0x8000 /* Promiscuous Mode */
#define MODE_INTL 0x0040 /* Internal Loopback */
#define MODE_DRTY 0x0020 /* Disable Retry */
#define MODE_COLL 0x0010 /* Force Collision */
#define MODE_DTCR 0x0008 /* Disable Transmit CRC) */
#define MODE_LOOP 0x0004 /* Loopback */
#define MODE_DTX 0x0002 /* Disable the Transmitter */
#define MODE_DRX 0x0001 /* Disable the Receiver */
#define MODE_NORMAL 0x0000 /* Normal operation mode */
/*
* Receive message descriptor status bit definitions.
*/
#define RX_OWN 0x80 /* Owner bit 0 = host, 1 = lance */
#define RX_ERR 0x40 /* Error Summary */
#define RX_FRAM 0x20 /* Framing Error */
#define RX_OFLO 0x10 /* Overflow Error */
#define RX_CRC 0x08 /* CRC Error */
#define RX_BUFF 0x04 /* Buffer Error */
#define RX_STP 0x02 /* Start of Packet */
#define RX_ENP 0x01 /* End of Packet */
/*
* Transmit message descriptor status bit definitions.
*/
#define TX_OWN 0x80 /* Owner bit 0 = host, 1 = lance */
#define TX_ERR 0x40 /* Error Summary */
#define TX_MORE 0x10 /* More the 1 retry needed to Xmit */
#define TX_ONE 0x08 /* One retry needed to Xmit */
#define TX_DEF 0x04 /* Deferred */
#define TX_STP 0x02 /* Start of Packet */
#define TX_ENP 0x01 /* End of Packet */
/*
* Transmit status (2) (valid if TX_ERR == 1)
*/
#define TX_BUFF 0x8000 /* Buffering error (no ENP) */
#define TX_UFLO 0x4000 /* Underflow (late memory) */
#define TX_LCOL 0x1000 /* Late collision */
#define TX_LCAR 0x0400 /* Loss of Carrier */
#define TX_RTRY 0x0200 /* Failed after 16 retransmissions */
#define TX_TDR 0x003f /* Time-domain-reflectometer-value */
/*
* Structures used for Communication with the LANCE
*/
/* LANCE Initialize Block */
struct init_block
{
unsigned short mode; /* Mode Register */
unsigned char paddr[6]; /* Physical Address (MAC) */
unsigned char laddr[8]; /* Logical Filter Address (not used) */
unsigned int rdrp; /* Receive Descriptor Ring pointer */
unsigned int tdrp; /* Transmit Descriptor Ring pointer */
};
/* Receive Message Descriptor Entry */
struct rmd
{
union rmd_u
{
unsigned long buffer; /* Address of buffer */
struct rmd_s
{
unsigned char unused[3];
unsigned volatile char status; /* Status Bits */
} s;
} u;
volatile short blen; /* Buffer Length (two's complement) */
unsigned short mlen; /* Message Byte Count */
};
/* Transmit Message Descriptor Entry */
struct tmd
{
union tmd_u
{
unsigned long buffer; /* Address of buffer */
struct tmd_s
{
unsigned char unused[3];
unsigned volatile char status; /* Status Bits */
} s;
} u;
unsigned short blen; /* Buffer Length (two's complement) */
unsigned volatile short status2; /* Error Status Bits */
};
#endif /* End of SK_G16_H */
+522
View File
@@ -0,0 +1,522 @@
/*------------------------------------------------------------------------
* smc9000.c
* This is a Etherboot driver for SMC's 9000 series of Ethernet cards.
*
* Copyright (C) 1998 Daniel Engström <daniel.engstrom@riksnett.no>
* Based on the Linux SMC9000 driver, smc9194.c by Eric Stahlman
* Copyright (C) 1996 by Erik Stahlman <eric@vt.edu>
*
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
*
* "Features" of the SMC chip:
* 4608 byte packet memory. ( for the 91C92/4. Others have more )
* EEPROM for configuration
* AUI/TP selection
*
* Authors
* Erik Stahlman <erik@vt.edu>
* Daniel Engström <daniel.engstrom@riksnett.no>
*
* History
* 98-09-25 Daniel Engström Etherboot driver crated from Eric's
* Linux driver.
*
*---------------------------------------------------------------------------*/
#define LINUX_OUT_MACROS 1
#define SMC9000_VERBOSE 1
#define SMC9000_DEBUG 0
#include "etherboot.h"
#include "nic.h"
#include "cards.h"
#include "smc9000.h"
# define _outb outb
# define _outw outw
static const char smc9000_version[] = "Version 0.99 98-09-30";
static unsigned int smc9000_base=0;
static const char *interfaces[ 2 ] = { "TP", "AUI" };
static const char *chip_ids[ 15 ] = {
NULL, NULL, NULL,
/* 3 */ "SMC91C90/91C92",
/* 4 */ "SMC91C94",
/* 5 */ "SMC91C95",
NULL,
/* 7 */ "SMC91C100",
/* 8 */ "SMC91C100FD",
NULL, NULL, NULL,
NULL, NULL, NULL
};
static const char smc91c96_id[] = "SMC91C96";
/*
* Function: smc_reset( int ioaddr )
* Purpose:
* This sets the SMC91xx chip to its normal state, hopefully from whatever
* mess that any other DOS driver has put it in.
*
* Maybe I should reset more registers to defaults in here? SOFTRESET should
* do that for me.
*
* Method:
* 1. send a SOFT RESET
* 2. wait for it to finish
* 3. reset the memory management unit
* 4. clear all interrupts
*
*/
static void smc_reset(int ioaddr)
{
/* This resets the registers mostly to defaults, but doesn't
* affect EEPROM. That seems unnecessary */
SMC_SELECT_BANK(ioaddr, 0);
_outw( RCR_SOFTRESET, ioaddr + RCR );
/* this should pause enough for the chip to be happy */
SMC_DELAY(ioaddr);
/* Set the transmit and receive configuration registers to
* default values */
_outw(RCR_CLEAR, ioaddr + RCR);
_outw(TCR_CLEAR, ioaddr + TCR);
/* Reset the MMU */
SMC_SELECT_BANK(ioaddr, 2);
_outw( MC_RESET, ioaddr + MMU_CMD );
/* Note: It doesn't seem that waiting for the MMU busy is needed here,
* but this is a place where future chipsets _COULD_ break. Be wary
* of issuing another MMU command right after this */
_outb(0, ioaddr + INT_MASK);
}
/*----------------------------------------------------------------------
* Function: smc_probe( int ioaddr )
*
* Purpose:
* Tests to see if a given ioaddr points to an SMC9xxx chip.
* Returns a 0 on success
*
* Algorithm:
* (1) see if the high byte of BANK_SELECT is 0x33
* (2) compare the ioaddr with the base register's address
* (3) see if I recognize the chip ID in the appropriate register
*
* ---------------------------------------------------------------------
*/
static int smc_probe( int ioaddr )
{
word bank;
word revision_register;
word base_address_register;
/* First, see if the high byte is 0x33 */
bank = inw(ioaddr + BANK_SELECT);
if ((bank & 0xFF00) != 0x3300) {
return -1;
}
/* The above MIGHT indicate a device, but I need to write to further
* test this. */
_outw(0x0, ioaddr + BANK_SELECT);
bank = inw(ioaddr + BANK_SELECT);
if ((bank & 0xFF00) != 0x3300) {
return -1;
}
/* well, we've already written once, so hopefully another time won't
* hurt. This time, I need to switch the bank register to bank 1,
* so I can access the base address register */
SMC_SELECT_BANK(ioaddr, 1);
base_address_register = inw(ioaddr + BASE);
if (ioaddr != (base_address_register >> 3 & 0x3E0)) {
#ifdef SMC9000_VERBOSE
printf("SMC9000: IOADDR %hX doesn't match configuration (%hX)."
"Probably not a SMC chip\n",
ioaddr, base_address_register >> 3 & 0x3E0);
#endif
/* well, the base address register didn't match. Must not have
* been a SMC chip after all. */
return -1;
}
/* check if the revision register is something that I recognize.
* These might need to be added to later, as future revisions
* could be added. */
SMC_SELECT_BANK(ioaddr, 3);
revision_register = inw(ioaddr + REVISION);
if (!chip_ids[(revision_register >> 4) & 0xF]) {
/* I don't recognize this chip, so... */
#ifdef SMC9000_VERBOSE
printf("SMC9000: IO %hX: Unrecognized revision register:"
" %hX, Contact author.\n", ioaddr, revision_register);
#endif
return -1;
}
/* at this point I'll assume that the chip is an SMC9xxx.
* It might be prudent to check a listing of MAC addresses
* against the hardware address, or do some other tests. */
return 0;
}
/**************************************************************************
* ETH_RESET - Reset adapter
***************************************************************************/
static void smc9000_reset(struct nic *nic)
{
smc_reset(smc9000_base);
}
/**************************************************************************
* ETH_TRANSMIT - Transmit a frame
***************************************************************************/
static void smc9000_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
word length; /* real, length incl. header */
word numPages;
unsigned long time_out;
byte packet_no;
word status;
int i;
/* We dont pad here since we can have the hardware doing it for us */
length = (s + ETH_HLEN + 1)&~1;
/* convert to MMU pages */
numPages = length / 256;
if (numPages > 7 ) {
#ifdef SMC9000_VERBOSE
printf("SMC9000: Far too big packet error. \n");
#endif
return;
}
/* dont try more than, say 30 times */
for (i=0;i<30;i++) {
/* now, try to allocate the memory */
SMC_SELECT_BANK(smc9000_base, 2);
_outw(MC_ALLOC | numPages, smc9000_base + MMU_CMD);
status = 0;
/* wait for the memory allocation to finnish */
for (time_out = currticks() + 5*TICKS_PER_SEC; currticks() < time_out; ) {
status = inb(smc9000_base + INTERRUPT);
if ( status & IM_ALLOC_INT ) {
/* acknowledge the interrupt */
_outb(IM_ALLOC_INT, smc9000_base + INTERRUPT);
break;
}
}
if ((status & IM_ALLOC_INT) != 0 ) {
/* We've got the memory */
break;
} else {
printf("SMC9000: Memory allocation timed out, resetting MMU.\n");
_outw(MC_RESET, smc9000_base + MMU_CMD);
}
}
/* If I get here, I _know_ there is a packet slot waiting for me */
packet_no = inb(smc9000_base + PNR_ARR + 1);
if (packet_no & 0x80) {
/* or isn't there? BAD CHIP! */
printf("SMC9000: Memory allocation failed. \n");
return;
}
/* we have a packet address, so tell the card to use it */
_outb(packet_no, smc9000_base + PNR_ARR);
/* point to the beginning of the packet */
_outw(PTR_AUTOINC, smc9000_base + POINTER);
#if SMC9000_DEBUG > 2
printf("Trying to xmit packet of length %hX\n", length );
#endif
/* send the packet length ( +6 for status, length and ctl byte )
* and the status word ( set to zeros ) */
_outw(0, smc9000_base + DATA_1 );
/* send the packet length ( +6 for status words, length, and ctl) */
_outb((length+6) & 0xFF, smc9000_base + DATA_1);
_outb((length+6) >> 8 , smc9000_base + DATA_1);
/* Write the contents of the packet */
/* The ethernet header first... */
outsw(smc9000_base + DATA_1, d, ETH_ALEN >> 1);
outsw(smc9000_base + DATA_1, nic->node_addr, ETH_ALEN >> 1);
_outw(htons(t), smc9000_base + DATA_1);
/* ... the data ... */
outsw(smc9000_base + DATA_1 , p, s >> 1);
/* ... and the last byte, if there is one. */
if ((s & 1) == 0) {
_outw(0, smc9000_base + DATA_1);
} else {
_outb(p[s-1], smc9000_base + DATA_1);
_outb(0x20, smc9000_base + DATA_1);
}
/* and let the chipset deal with it */
_outw(MC_ENQUEUE , smc9000_base + MMU_CMD);
status = 0; time_out = currticks() + 5*TICKS_PER_SEC;
do {
status = inb(smc9000_base + INTERRUPT);
if ((status & IM_TX_INT ) != 0) {
word tx_status;
/* ack interrupt */
_outb(IM_TX_INT, smc9000_base + INTERRUPT);
packet_no = inw(smc9000_base + FIFO_PORTS);
packet_no &= 0x7F;
/* select this as the packet to read from */
_outb( packet_no, smc9000_base + PNR_ARR );
/* read the first word from this packet */
_outw( PTR_AUTOINC | PTR_READ, smc9000_base + POINTER );
tx_status = inw( smc9000_base + DATA_1 );
if (0 == (tx_status & TS_SUCCESS)) {
#ifdef SMC9000_VERBOSE
printf("SMC9000: TX FAIL STATUS: %hX \n", tx_status);
#endif
/* re-enable transmit */
SMC_SELECT_BANK(smc9000_base, 0);
_outw(inw(smc9000_base + TCR ) | TCR_ENABLE, smc9000_base + TCR );
}
/* kill the packet */
SMC_SELECT_BANK(smc9000_base, 2);
_outw(MC_FREEPKT, smc9000_base + MMU_CMD);
return;
}
}while(currticks() < time_out);
printf("SMC9000: Waring TX timed out, resetting board\n");
smc_reset(smc9000_base);
return;
}
/**************************************************************************
* ETH_POLL - Wait for a frame
***************************************************************************/
static int smc9000_poll(struct nic *nic)
{
if(!smc9000_base)
return 0;
SMC_SELECT_BANK(smc9000_base, 2);
if (inw(smc9000_base + FIFO_PORTS) & FP_RXEMPTY)
return 0;
/* start reading from the start of the packet */
_outw(PTR_READ | PTR_RCV | PTR_AUTOINC, smc9000_base + POINTER);
/* First read the status and check that we're ok */
if (!(inw(smc9000_base + DATA_1) & RS_ERRORS)) {
/* Next: read the packet length and mask off the top bits */
nic->packetlen = (inw(smc9000_base + DATA_1) & 0x07ff);
/* the packet length includes the 3 extra words */
nic->packetlen -= 6;
#if SMC9000_DEBUG > 2
printf(" Reading %d words (and %d byte(s))\n",
(nic->packetlen >> 1), nic->packetlen & 1);
#endif
/* read the packet (and the last "extra" word) */
insw(smc9000_base + DATA_1, nic->packet, (nic->packetlen+2) >> 1);
/* is there an odd last byte ? */
if (nic->packet[nic->packetlen+1] & 0x20)
nic->packetlen++;
/* error or good, tell the card to get rid of this packet */
_outw(MC_RELEASE, smc9000_base + MMU_CMD);
return 1;
}
printf("SMC9000: RX error\n");
/* error or good, tell the card to get rid of this packet */
_outw(MC_RELEASE, smc9000_base + MMU_CMD);
return 0;
}
static void smc9000_disable(struct nic *nic)
{
if(!smc9000_base)
return;
/* no more interrupts for me */
SMC_SELECT_BANK(smc9000_base, 2);
_outb( 0, smc9000_base + INT_MASK);
/* and tell the card to stay away from that nasty outside world */
SMC_SELECT_BANK(smc9000_base, 0);
_outb( RCR_CLEAR, smc9000_base + RCR );
_outb( TCR_CLEAR, smc9000_base + TCR );
}
/**************************************************************************
* ETH_PROBE - Look for an adapter
***************************************************************************/
struct nic *smc9000_probe(struct nic *nic, unsigned short *probe_addrs)
{
unsigned short revision;
int memory;
int media;
const char * version_string;
const char * if_string;
int i;
/*
* the SMC9000 can be at any of the following port addresses. To change,
* for a slightly different card, you can add it to the array. Keep in
* mind that the array must end in zero.
*/
static unsigned short portlist[] = {
#ifdef SMC9000_SCAN
SMC9000_SCAN,
#else
0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0,
#endif
0 };
printf("\nSMC9000 %s\n", smc9000_version);
#ifdef SMC9000_VERBOSE
printf("Copyright (C) 1998 Daniel Engstr\x94m\n");
printf("Copyright (C) 1996 Eric Stahlman\n");
#endif
/* if no addresses supplied, fall back on defaults */
if (probe_addrs == 0 || probe_addrs[0] == 0)
probe_addrs = portlist;
/* check every ethernet address */
for (i = 0; probe_addrs[i]; i++) {
/* check this specific address */
if (smc_probe(probe_addrs[i]) == 0)
smc9000_base = probe_addrs[i];
}
/* couldn't find anything */
if(0 == smc9000_base)
goto out;
/*
* Get the MAC address ( bank 1, regs 4 - 9 )
*/
SMC_SELECT_BANK(smc9000_base, 1);
for ( i = 0; i < 6; i += 2 ) {
word address;
address = inw(smc9000_base + ADDR0 + i);
nic->node_addr[i+1] = address >> 8;
nic->node_addr[i] = address & 0xFF;
}
/* get the memory information */
SMC_SELECT_BANK(smc9000_base, 0);
memory = ( inw(smc9000_base + MCR) >> 9 ) & 0x7; /* multiplier */
memory *= 256 * (inw(smc9000_base + MIR) & 0xFF);
/*
* Now, I want to find out more about the chip. This is sort of
* redundant, but it's cleaner to have it in both, rather than having
* one VERY long probe procedure.
*/
SMC_SELECT_BANK(smc9000_base, 3);
revision = inw(smc9000_base + REVISION);
version_string = chip_ids[(revision >> 4) & 0xF];
if (((revision & 0xF0) >> 4 == CHIP_9196) &&
((revision & 0x0F) >= REV_9196)) {
/* This is a 91c96. 'c96 has the same chip id as 'c94 (4) but
* a revision starting at 6 */
version_string = smc91c96_id;
}
if ( !version_string ) {
/* I shouldn't get here because this call was done before.... */
goto out;
}
/* is it using AUI or 10BaseT ? */
SMC_SELECT_BANK(smc9000_base, 1);
if (inw(smc9000_base + CONFIG) & CFG_AUI_SELECT)
media = 2;
else
media = 1;
if_string = interfaces[media - 1];
/* now, reset the chip, and put it into a known state */
smc_reset(smc9000_base);
printf("%s rev:%d I/O port:%hX Interface:%s RAM:%d bytes \n",
version_string, revision & 0xF,
smc9000_base, if_string, memory );
/*
* Print the Ethernet address
*/
printf("Ethernet MAC address: %!\n", nic->node_addr);
SMC_SELECT_BANK(smc9000_base, 0);
/* see the header file for options in TCR/RCR NORMAL*/
_outw(TCR_NORMAL, smc9000_base + TCR);
_outw(RCR_NORMAL, smc9000_base + RCR);
/* Select which interface to use */
SMC_SELECT_BANK(smc9000_base, 1);
if ( media == 1 ) {
_outw( inw( smc9000_base + CONFIG ) & ~CFG_AUI_SELECT,
smc9000_base + CONFIG );
}
else if ( media == 2 ) {
_outw( inw( smc9000_base + CONFIG ) | CFG_AUI_SELECT,
smc9000_base + CONFIG );
}
nic->reset = smc9000_reset;
nic->poll = smc9000_poll;
nic->transmit = smc9000_transmit;
nic->disable = smc9000_disable;
return nic;
out:
#ifdef SMC9000_VERBOSE
printf("No SMC9000 adapters found\n");
#endif
smc9000_base = 0;
return (0);
}
+205
View File
@@ -0,0 +1,205 @@
/*------------------------------------------------------------------------
* smc9000.h
*
* Copyright (C) 1998 by Daniel Engström
* Copyright (C) 1996 by Erik Stahlman
*
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
*
* This file contains register information and access macros for
* the SMC91xxx chipset.
*
* Information contained in this file was obtained from the SMC91C94
* manual from SMC. To get a copy, if you really want one, you can find
* information under www.smsc.com in the components division.
* ( this thanks to advice from Donald Becker ).
*
* Authors
* Daniel Engström <daniel.engstrom@riksnett.no>
* Erik Stahlman <erik@vt.edu>
*
* History
* 96-01-06 Erik Stahlman moved definitions here from main .c
* file
* 96-01-19 Erik Stahlman polished this up some, and added
* better error handling
* 98-09-25 Daniel Engström adjusted for Etherboot
* 98-09-27 Daniel Engström moved some static strings back to the
* main .c file
* --------------------------------------------------------------------------*/
#ifndef _SMC9000_H_
# define _SMC9000_H_
/* I want some simple types */
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long int dword;
/*---------------------------------------------------------------
*
* A description of the SMC registers is probably in order here,
* although for details, the SMC datasheet is invaluable.
*
* Basically, the chip has 4 banks of registers ( 0 to 3 ), which
* are accessed by writing a number into the BANK_SELECT register
* ( I also use a SMC_SELECT_BANK macro for this ).
*
* The banks are configured so that for most purposes, bank 2 is all
* that is needed for simple run time tasks.
* ----------------------------------------------------------------------*/
/*
* Bank Select Register:
*
* yyyy yyyy 0000 00xx
* xx = bank number
* yyyy yyyy = 0x33, for identification purposes.
*/
#define BANK_SELECT 14
/* BANK 0 */
#define TCR 0 /* transmit control register */
#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */
#define TCR_FDUPLX 0x0800 /* receive packets sent out */
#define TCR_STP_SQET 0x1000 /* stop transmitting if Signal quality error */
#define TCR_MON_CNS 0x0400 /* monitors the carrier status */
#define TCR_PAD_ENABLE 0x0080 /* pads short packets to 64 bytes */
#define TCR_CLEAR 0 /* do NOTHING */
/* the normal settings for the TCR register : */
#define TCR_NORMAL (TCR_ENABLE | TCR_PAD_ENABLE)
#define EPH_STATUS 2
#define ES_LINK_OK 0x4000 /* is the link integrity ok ? */
#define RCR 4
#define RCR_SOFTRESET 0x8000 /* resets the chip */
#define RCR_STRIP_CRC 0x200 /* strips CRC */
#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */
#define RCR_ALMUL 0x4 /* receive all multicast packets */
#define RCR_PROMISC 0x2 /* enable promiscuous mode */
/* the normal settings for the RCR register : */
#define RCR_NORMAL (RCR_STRIP_CRC | RCR_ENABLE)
#define RCR_CLEAR 0x0 /* set it to a base state */
#define COUNTER 6
#define MIR 8
#define MCR 10
/* 12 is reserved */
/* BANK 1 */
#define CONFIG 0
#define CFG_AUI_SELECT 0x100
#define BASE 2
#define ADDR0 4
#define ADDR1 6
#define ADDR2 8
#define GENERAL 10
#define CONTROL 12
#define CTL_POWERDOWN 0x2000
#define CTL_LE_ENABLE 0x80
#define CTL_CR_ENABLE 0x40
#define CTL_TE_ENABLE 0x0020
#define CTL_AUTO_RELEASE 0x0800
#define CTL_EPROM_ACCESS 0x0003 /* high if Eprom is being read */
/* BANK 2 */
#define MMU_CMD 0
#define MC_BUSY 1 /* only readable bit in the register */
#define MC_NOP 0
#define MC_ALLOC 0x20 /* or with number of 256 byte packets */
#define MC_RESET 0x40
#define MC_REMOVE 0x60 /* remove the current rx packet */
#define MC_RELEASE 0x80 /* remove and release the current rx packet */
#define MC_FREEPKT 0xA0 /* Release packet in PNR register */
#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */
#define PNR_ARR 2
#define FIFO_PORTS 4
#define FP_RXEMPTY 0x8000
#define FP_TXEMPTY 0x80
#define POINTER 6
#define PTR_READ 0x2000
#define PTR_RCV 0x8000
#define PTR_AUTOINC 0x4000
#define PTR_AUTO_INC 0x0040
#define DATA_1 8
#define DATA_2 10
#define INTERRUPT 12
#define INT_MASK 13
#define IM_RCV_INT 0x1
#define IM_TX_INT 0x2
#define IM_TX_EMPTY_INT 0x4
#define IM_ALLOC_INT 0x8
#define IM_RX_OVRN_INT 0x10
#define IM_EPH_INT 0x20
#define IM_ERCV_INT 0x40 /* not on SMC9192 */
/* BANK 3 */
#define MULTICAST1 0
#define MULTICAST2 2
#define MULTICAST3 4
#define MULTICAST4 6
#define MGMT 8
#define REVISION 10 /* ( hi: chip id low: rev # ) */
/* this is NOT on SMC9192 */
#define ERCV 12
/* Note that 9194 and 9196 have the smame chip id,
* the 9196 will have revisions starting at 6 */
#define CHIP_9190 3
#define CHIP_9194 4
#define CHIP_9195 5
#define CHIP_9196 4
#define CHIP_91100 7
#define CHIP_91100FD 8
#define REV_9196 6
/*
* Transmit status bits
*/
#define TS_SUCCESS 0x0001
#define TS_LOSTCAR 0x0400
#define TS_LATCOL 0x0200
#define TS_16COL 0x0010
/*
* Receive status bits
*/
#define RS_ALGNERR 0x8000
#define RS_BADCRC 0x2000
#define RS_ODDFRAME 0x1000
#define RS_TOOLONG 0x0800
#define RS_TOOSHORT 0x0400
#define RS_MULTICAST 0x0001
#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
/*-------------------------------------------------------------------------
* I define some macros to make it easier to do somewhat common
* or slightly complicated, repeated tasks.
--------------------------------------------------------------------------*/
/* select a register bank, 0 to 3 */
#define SMC_SELECT_BANK(x, y) { _outw( y, x + BANK_SELECT ); }
/* define a small delay for the reset */
#define SMC_DELAY(x) { inw( x + RCR );\
inw( x + RCR );\
inw( x + RCR ); }
#endif /* _SMC_9000_H_ */
+255
View File
@@ -0,0 +1,255 @@
/**************************************************************************
Etherboot - BOOTP/TFTP Bootstrap Program
TIARA (Fujitsu Etherstar) NIC driver for Etherboot
Copyright (c) Ken Yap 1998
Information gleaned from:
TIARA.ASM Packet driver by Brian Fisher, Queens U, Kingston, Ontario
Fujitsu MB86960 spec sheet (different chip but same family)
***************************************************************************/
/*
* 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, or (at
* your option) any later version.
*/
/* to get some global routines like printf */
#include "etherboot.h"
/* to get the interface to the body of the program */
#include "nic.h"
#include "cards.h"
/*
EtherStar I/O Register offsets
*/
/* Offsets of registers */
#define DLCR_XMIT_STAT 0x00
#define DLCR_XMIT_MASK 0x01
#define DLCR_RECV_STAT 0x02
#define DLCR_RECV_MASK 0x03
#define DLCR_XMIT_MODE 0x04
#define DLCR_RECV_MODE 0x05
#define DLCR_ENABLE 0x06
#define DLCR_TDR_LOW 0x07
#define DLCR_NODE_ID 0x08
#define DLCR_TDR_HIGH 0x0F
#define BMPR_MEM_PORT 0x10
#define BMPR_PKT_LEN 0x12
#define BMPR_DMA_ENABLE 0x14
#define PROM_ID 0x18
#define TMST 0x80
#define TMT_OK 0x80
#define TMT_16COLL 0x02
#define BUF_EMPTY 0x40
#define CARD_DISABLE 0x80 /* written to DLCR_ENABLE to disable card */
#define CARD_ENABLE 0 /* written to DLCR_ENABLE to enable card */
#define CLEAR_STATUS 0x0F /* used to clear status info */
/*
00001111B
!!!!!!!!--------
!!!!!!!+--------CLEAR BUS WRITE ERROR
!!!!!!+---------CLEAR 16 COLLISION
!!!!!+----------CLEAR COLLISION
!!!!+-----------CLEAR UNDERFLOW
!!!+------------NC
!!+-------------NC
!+--------------NC
+---------------NC
*/
#define NO_TX_IRQS 0 /* written to clear transmit IRQs */
#define CLR_RCV_STATUS 0xCF /* clears receive status */
#define EN_RCV_IRQS 0x80 /* enable receive interrupts */
/*
10000000B
!!!!!!!!--------
!!!!!!!+--------ENABLE OVERFLOW
!!!!!!+---------ENABLE CRC
!!!!!+----------ENABLE ALIGN
!!!!+-----------ENABLE SHORT PKT
!!!+------------DISABLE REMOTE RESET
!!+-------------RESERVED
!+--------------RESERVED
+---------------ENABLE PKT READY
*/
#define XMIT_MODE 0x02
/*
00000010B
!!!!!!!!---------ENABLE CARRIER DETECT
!!!!!!!+---------DISABLE LOOPBACK
*/
#define RECV_MODE 0x02
/*
00000010B
!!!!!!!!---------ACCEPT ALL PACKETS
!!!!!!!+---------ACCEPT PHYSICAL, MULTICAST, AND
!!!!!!+----------BROADCAST PACKETS
!!!!!+-----------DISABLE REMOTE RESET
!!!!+------------DISABLE SHORT PACKETS
!!!+-------------USE 6 BYTE ADDRESS
!!+--------------NC
!+---------------NC
+----------------DISABLE CRC TEST MODE
*/
/* NIC specific static variables go here */
static unsigned short ioaddr;
/**************************************************************************
RESET - Reset adapter
***************************************************************************/
static void tiara_reset(struct nic *nic)
{
int i;
outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
outb(CLEAR_STATUS, ioaddr + DLCR_XMIT_STAT);
outb(NO_TX_IRQS, ioaddr + DLCR_XMIT_MASK);
outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
outb(XMIT_MODE, ioaddr + DLCR_XMIT_MODE);
outb(RECV_MODE, ioaddr + DLCR_RECV_MODE);
/* Vacuum recv buffer */
while ((inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY) == 0)
inb(ioaddr + BMPR_MEM_PORT);
/* Set node address */
for (i = 0; i < ETH_ALEN; ++i)
outb(nic->node_addr[i], ioaddr + DLCR_NODE_ID + i);
outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
outb(CARD_ENABLE, ioaddr + DLCR_ENABLE);
}
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
static int tiara_poll(struct nic *nic)
{
unsigned int len;
if (inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY)
return (0);
/* Ack packet */
outw(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
len = inw(ioaddr + BMPR_MEM_PORT); /* throw away status */
len = inw(ioaddr + BMPR_MEM_PORT);
/* Drop overlength packets */
if (len > ETH_FRAME_LEN)
return (0); /* should we drain the buffer? */
insw(ioaddr + BMPR_MEM_PORT, nic->packet, len / 2);
/* If it's our own, drop it */
if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) == 0)
return (0);
nic->packetlen = len;
return (1);
}
/**************************************************************************
TRANSMIT - Transmit a frame
***************************************************************************/
static void tiara_transmit(
struct nic *nic,
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
unsigned int len;
unsigned long time;
len = s + ETH_HLEN;
if (len < ETH_ZLEN)
len = ETH_ZLEN;
t = htons(t);
outsw(ioaddr + BMPR_MEM_PORT, d, ETH_ALEN / 2);
outsw(ioaddr + BMPR_MEM_PORT, nic->node_addr, ETH_ALEN / 2);
outw(t, ioaddr + BMPR_MEM_PORT);
outsw(ioaddr + BMPR_MEM_PORT, p, s / 2);
if (s & 1) /* last byte */
outb(p[s-1], ioaddr + BMPR_MEM_PORT);
while (s++ < ETH_ZLEN - ETH_HLEN) /* pad */
outb(0, ioaddr + BMPR_MEM_PORT);
outw(len | (TMST << 8), ioaddr + BMPR_PKT_LEN);
/* wait for transmit complete */
time = currticks() + TICKS_PER_SEC; /* wait one second */
while (currticks() < time && (inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
;
if ((inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
printf("Tiara timed out on transmit\n");
/* Do we need to ack the transmit? */
}
/**************************************************************************
DISABLE - Turn off ethernet interface
***************************************************************************/
static void tiara_disable(struct nic *nic)
{
/* Apparently only a power down can do this properly */
outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
}
static int tiara_probe1(struct nic *nic)
{
/* Hope all the Tiara cards have this vendor prefix */
static char vendor_prefix[] = { 0x08, 0x00, 0x1A };
static char all_ones[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
int i;
for (i = 0; i < ETH_ALEN; ++i)
nic->node_addr[i] = inb(ioaddr + PROM_ID + i);
if (memcmp(nic->node_addr, vendor_prefix, sizeof(vendor_prefix)) != 0)
return (0);
if (memcmp(nic->node_addr, all_ones, sizeof(all_ones)) == 0)
return (0);
printf("\nTiara ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr);
return (1);
}
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
struct nic *tiara_probe(struct nic *nic, unsigned short *probe_addrs)
{
/* missing entries are addresses usually already used */
static unsigned short io_addrs[] = {
0x100, 0x120, 0x140, 0x160,
0x180, 0x1A0, 0x1C0, 0x1E0,
0x200, 0x220, 0x240, /*Par*/
0x280, 0x2A0, 0x2C0, /*Ser*/
0x300, 0x320, 0x340, /*Par*/
0x380, /*Vid,Par*/ 0x3C0, /*Ser*/
0x0
};
unsigned short *p;
/* if probe_addrs is 0, then routine can use a hardwired default */
if (probe_addrs == 0)
probe_addrs = io_addrs;
for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
if (tiara_probe1(nic))
break;
/* if board found */
if (ioaddr != 0)
{
tiara_reset(nic);
/* point to NIC specific routines */
nic->reset = tiara_reset;
nic->poll = tiara_poll;
nic->transmit = tiara_transmit;
nic->disable = tiara_disable;
return nic;
}
else
return (0);
}
+127
View File
@@ -0,0 +1,127 @@
/* A couple of routines to implement a low-overhead timer for drivers */
/*
* 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, or (at
* your option) any later version.
*/
#include "etherboot.h"
#include "timer.h"
void load_timer2(unsigned int ticks)
{
/* Set up the timer gate, turn off the speaker */
outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
outb(ticks & 0xFF, TIMER2_PORT);
outb(ticks >> 8, TIMER2_PORT);
}
#if defined(CONFIG_TSC_CURRTICKS)
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
#define rdtscll(val) \
__asm__ __volatile__ ("rdtsc" : "=A" (val))
#define HZ TICKS_PER_SEC
#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
/* LATCH is used in the interval timer and ftape setup. */
#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
/* ------ Calibrate the TSC -------
* Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
* Too much 64-bit arithmetic here to do this cleanly in C, and for
* accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
* output busy loop as low as possible. We avoid reading the CTC registers
* directly because of the awkward 8-bit access mechanism of the 82C54
* device.
*/
#define CALIBRATE_LATCH (5 * LATCH)
static unsigned long long calibrate_tsc(void)
{
/* Set the Gate high, disable speaker */
outb((inb(0x61) & ~0x02) | 0x01, 0x61);
/*
* Now let's take care of CTC channel 2
*
* Set the Gate high, program CTC channel 2 for mode 0,
* (interrupt on terminal count mode), binary count,
* load 5 * LATCH count, (LSB and MSB) to begin countdown.
*/
outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
{
unsigned long startlow, starthigh;
unsigned long endlow, endhigh;
unsigned long count;
rdtsc(startlow,starthigh);
count = 0;
do {
count++;
} while ((inb(0x61) & 0x20) == 0);
rdtsc(endlow,endhigh);
/* Error: ECTCNEVERSET */
if (count <= 1)
goto bad_ctc;
/* 64-bit subtract - gcc just messes up with long longs */
__asm__("subl %2,%0\n\t"
"sbbl %3,%1"
:"=a" (endlow), "=d" (endhigh)
:"g" (startlow), "g" (starthigh),
"0" (endlow), "1" (endhigh));
/* Error: ECPUTOOFAST */
if (endhigh)
goto bad_ctc;
endlow /= 5;
return endlow;
}
/*
* The CTC wasn't reliable: we got a hit on the very first read,
* or the CPU was so fast/slow that the quotient wouldn't fit in
* 32 bits..
*/
bad_ctc:
printf("bad_ctc\n");
return 0;
}
unsigned long currticks(void)
{
static unsigned long clocks_per_tick;
unsigned long clocks_high, clocks_low;
unsigned long currticks;
if (!clocks_per_tick) {
clocks_per_tick = calibrate_tsc();
printf("clocks_per_tick = %d\n", clocks_per_tick);
}
/* Read the Time Stamp Counter */
rdtsc(clocks_low, clocks_high);
/* currticks = clocks / clocks_per_tick; */
__asm__("divl %1"
:"=a" (currticks)
:"r" (clocks_per_tick), "0" (clocks_low), "d" (clocks_high));
return currticks;
}
#endif /* RTC_CURRTICKS */
+64
View File
@@ -0,0 +1,64 @@
/* Defines for routines to implement a low-overhead timer for drivers */
/*
* 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, or (at
* your option) any later version.
*/
#ifndef TIMER_H
#define TIMER_H
/* Ports for the 8254 timer chip */
#define TIMER2_PORT 0x42
#define TIMER_MODE_PORT 0x43
/* Meaning of the mode bits */
#define TIMER0_SEL 0x00
#define TIMER1_SEL 0x40
#define TIMER2_SEL 0x80
#define READBACK_SEL 0xC0
#define LATCH_COUNT 0x00
#define LOBYTE_ACCESS 0x10
#define HIBYTE_ACCESS 0x20
#define WORD_ACCESS 0x30
#define MODE0 0x00
#define MODE1 0x02
#define MODE2 0x04
#define MODE3 0x06
#define MODE4 0x08
#define MODE5 0x0A
#define BINARY_COUNT 0x00
#define BCD_COUNT 0x01
/* Timers tick over at this rate */
#define TICKS_PER_MS 1193
/* Parallel Peripheral Controller Port B */
#define PPC_PORTB 0x61
/* Meaning of the port bits */
#define PPCB_T2OUT 0x20 /* Bit 5 */
#define PPCB_SPKR 0x02 /* Bit 1 */
#define PPCB_T2GATE 0x01 /* Bit 0 */
/* Ticks must be between 0 and 65535 (0 == 65536)
because it is a 16 bit counter */
extern void load_timer2(unsigned int ticks);
extern inline int timer2_running(void)
{
return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
}
extern inline void waiton_timer2(unsigned int ticks)
{
load_timer2(ticks);
while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0)
;
}
#endif /* TIMER_H */
+3746
View File
File diff suppressed because it is too large. Load diff
+1989
View File
File diff suppressed because it is too large. Load diff
+53
View File
@@ -0,0 +1,53 @@
This software may be used and distributed according to the terms of
the GNU Public License, incorporated herein by reference.
This is a tulip and clone driver for Etherboot. See the revision
history in the tulip.c file for information on changes. This version
of the driver incorporates changes from Bob Edwards and Paul Mackerras
who cantributed changes to support the TRENDnet TE100-PCIA NIC which
uses a genuine Intel 21143-PD chipset. There are also various code
cleanups to make time-based activities more reliable.
Of course you have to have all the usual Etherboot environment
(bootp/dhcp/NFS) set up, and you need a Linux kernel with v0.91g
(7.16.99) or later of the tulip.c driver compiled in to support some
MX98715 based cards. That file is available at:
http://cesdis.gsfc.nasa.gov/linux/drivers/test/tulip.c
NOTES
I've tested this driver with a SOHOware Fast 10/100 Model SDA110A,
a Linksys LNE100TX v2.0, and a Netgear FA310TX card, and it worked at
both 10 and 100 mbits. Other cards based on the tulip family may work as
well.
These cards are about 20$US, are supported by Linux and now Etherboot,
and being PCI, they auto-configure IRQ and IOADDR and auto-negotiate
10/100 half/full duplex. It seems like a pretty good value compared to
some of the pricier cards, and can lower the cost of building/adapting
thin client workstations substantially while giving a considerable
performance increase.
On some PCI tulip clone chipsets (MX987x5, LC82C115, LC82C168) this driver
lets the card choose the fastest speed it can negotiate with the peer
device. On other cards, it chooses 10mbit half-duplex.
I burned an AM27C256 (32KByte) EPROM with mx987x5.lzrom and it worked.
According to the data sheet the MX98715A supports up to 64K (27C512)
EPROMs,
I've liberally commented the code and header files in the hope that it
will help the next person who hacks the code or needs to support some
tulip clone card, or wishes to add functionality.
Anyway, please test this if you can on your tulip based card, and let
me (mdc@thinguin.org) and the netboot list (netboot@baghira.han.de)
know how things go. I also would appreciate code review by people who
program. I'm a strong believer in "another set of eyes".
Regards,
Marty Connor
mdc@thinguin.org
http://www.thinguin.org/
Loaded 100 of 181 files, more files were not shown because too many files have changed in this diff. Show more