mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-28 10:10:29 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
125f436763 | ||
|
|
3af093a503 | ||
|
|
9a43953b56 | ||
|
|
8dbf5c8999 | ||
|
|
e8b13ced38 | ||
|
|
f557cee7dc | ||
|
|
53f9ac3175 |
No files matched your search
-30
@@ -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
|
||||
@@ -0,0 +1,9 @@
|
||||
.deps
|
||||
Makefile
|
||||
autom4te.cache
|
||||
config.cache
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
stamp-h
|
||||
stamp-h1
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -1,626 +1,285 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
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
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
@@ -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.
|
||||
+60
@@ -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
@@ -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
|
||||
@@ -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.
|
||||
@@ -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>.
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,3 @@
|
||||
.deps
|
||||
Makefile
|
||||
*.info*
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
+517
@@ -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';
|
||||
}
|
||||
|
||||
$_;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
File renamed without changes.
@@ -0,0 +1,4 @@
|
||||
@set UPDATED 8 May 2005
|
||||
@set UPDATED-MONTH May 2005
|
||||
@set EDITION 0.97
|
||||
@set VERSION 0.97
|
||||
@@ -0,0 +1,4 @@
|
||||
@set UPDATED 8 May 2005
|
||||
@set UPDATED-MONTH May 2005
|
||||
@set EDITION 0.97
|
||||
@set VERSION 0.97
|
||||
@@ -0,0 +1,3 @@
|
||||
.deps
|
||||
Makefile
|
||||
grub
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
+272
@@ -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 ());
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
.deps
|
||||
Makefile
|
||||
@@ -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
@@ -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, §or_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__ */
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
+133
@@ -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
@@ -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 */
|
||||
@@ -0,0 +1,2 @@
|
||||
.deps
|
||||
Makefile
|
||||
+620
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.]
|
||||
@@ -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
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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:
|
||||
*/
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
+266
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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:
|
||||
*/
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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;
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
+1989
File diff suppressed because it is too large.
Load diff
@@ -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
Reference in new issue
Block a user