Wave OSDR0 Developer Manual
Wave OSDR0 Developer Manual
English Version
1
Wave OS project early developer manual
Index
Foreword ******************************************************************************** 3
2
Wave OS project early developer manual
Foreword
This is a manual for software developers. This manual is an attemp to make easy the
task of learning how this new operating system, codenamed Wave OS, does work,
by explaining its internal architecture, and them exploring each part of it. This manual
its based on existing documentation about Syllable Desktop operating system, wich
is the base system of this project. But it is not a matter of just putting toghether all
that information, as many details are not yet well documented and in the moment this
book is being started, the situation of the original project is not really clear.
As Codename Wave OS evolves, this book will. This is a work in progress, where the
documents rescued does need large improvements and updates, many details of the
system are not even mentioned to them and that is a hard obstable to overcome by
developers, this is what this book wants to change. Heritage documentation was
fount to be confusing, in this book we aim to make things better.
The developer land is yet under construction. Developer Land means all the internet
and local tools and resources wich are used by the developer in order to improve
and develop this operating system. In the moment this document is being wriiten,
July 11, 2010, the developer environment is being set up and whenever it be ready
willl be open to people.
project.Wave OS007@gmail.com
Wave OS project early developer manual
The Wave OS Project aims to produce a new kind of free and opensource operating
system, suitable for everyday usage and easy to understand even for people who
does not know much about computer techonology. This operating system is a large
departure from the old school computing that everyone knows today, as it is foused
in a completely different way that most system softwares does.
The very first advantage is eficiency. This means that this system has to be able to
present a graphic user interface even on small and old computers, but has also to
support the large ones of today. And it has to run well on both.
The second advantage is developer friendlyness. This system has to be the most
easy environment to develop software.
The third advantage is innovation. Codename Wave OS breaks away with classic
and oldschool elements present in most free systems of today, and gets rid of most
problems wich affects those softwares.
However to fully meet our ideal system, much work is needed. Documentation has to
be improved largely, the complete Gnustep system has to be ported to a component
called Appserver, wich performs the role wich X window and X window like does in
most unix like systems, and many system problems has to be resolved.
Documentation is not the best at this point but we want to improve it and make it
student friendly. This book is intended to be regularly upgraded, in order to fix errors
and add features, so please make sure you had download the last version.
You can download, print, copy, host and translate this book by any mean and in any
language, but the meanings of the paragraphs shold be respected as close as the
translation language allows.
Before Developer Release 1, it is possible that when you visit us you end finding a
downloadable CD, this is just for research purposes, they will be pre-developer
builds just for testing our development system. If all goes well, developing tasks
would start on January 2011, by the rest of 2010 things are being prepared.
4
Wave OS project early developer manual
The structure of Codename Wave OS is like any unix-like system, where a kernel
takes charge of the basic hardware and them some ?erversinteract with the user.
One advantage of this system is that apps and drivers uses to be files to be dragged
into a folder, and not code to rebuild the kernel. Well, in deal, Drivers are two files
today, one for the kernel and other for the server, but it is a thing we want to change
by making all the drivers a unique object-oriented kernel module wich begins to work
when placed into the future /drivers folder, without running any assistant.
Appserver: it generates the user interface, not just the windowing system, even it
presents pictures into the video ram.
Media Server: It handles the sound card.
Registrar: Its a component wich plays many roles, wich is not well documented yet.
Wich tools are used to develop software and build packages and /or the whole
operating system?
Since August 30, 2010, Developer Tools began to exist. It's a combination of many
software pieces, many of them has roots in both gnu.org and Syllable.org.
In order to install this environment, all you have to do is to copy the developer-tools
folder in the Developer CD to the desktop, open the terminal and then use this
commands:
cd Desktop
cd Developer-Tools
Warning: if you just drag the setup.sh script from the window to Terminal, it will fail.
This mistake is easy to undo by just following the upper instructions.
It will ask you if you wish to install the packages. This script DELETES old versions
of the packages available in the folder, so please be carefull. If you installed a clean
copy of Wave OS DR0 or Syllable Desktop 0.6.6, wich yet are much the same, then
do not worry about pressing “y”. This script installs all thhe packages by itself.
Depending on the power of your computer, it can take from an hour to about fifteen
minutes. It is important that you have at least 5 gb of disk space in the Wave slice if
you intend to do any software development, the Developer-tools package consumes
about 200 Mb. In order to know wich packages are available, please look in the
folder, the exact content will vary over the time as Wave OS evolves.
Wave OS project early developer manual
System compiling
Warning: The documents below are heritage and we aim to rewrite them soon.
Where you see the word “Syllable” you should read “Wave OS”, as it is a descendant
from Syllable Desktop project. Whenever Wave OS DR1 ( Developer Release 1) this
anomality is flagged for fix.
Please note that the build system is written in the Ruby language,
hence you need to have the Ruby interpreter installed. Refer to the
Ruby package for Syllable for instructions on installing Ruby.
Now for the installation of the build system. You need to install a
version that matches your system. There are different download packages
for Syllable Desktop and Syllable Server. In the case of Builder, there
is not a big difference between them, but they are configured differently.
unzip Builder-0.7.63.i586.resource
6
Wave OS project early developer manual
/syllable/system/apps/utils/Builder/
mv Builder /resources/
su
Then run:
--------------------------------
If you installed manually from the Syllable CVS repository, you should be
aware that the default configuration is for Syllable Desktop. If you
install Builder on Syllable Server from CVS, you must adapt the
configuration accordingly in the file
Builder/settings
There are also other settings options in there that you may want to
change. This file is a plain text file with a structured content. You
can edit it with any text editor, but you should be careful to adhere
to the structure. All files that Builder uses to store its own Builder
specific data have this same basic structure.
You can also use Builder on Linux systems other than Syllable Server (and
probably on other POSIX-like systems, but this has not been tested yet).
An easy way to do so is to install it in your home directory and add the
---------------------------------------------
If you ever want to remove the build system, follow these steps. Again,
you may have to become the super user first:
su
Then you should remove the links to the build system from Syllable.
rm -r /resources/Builder
Keeping the build system up to date is easy if you have an Internetconnection. Just
do:
build update
build log
This requires that you have the CVS program installed. If you have
made your own modifications to files in the build system, you should
always check the log for conflicts and resolve them if there are any.
=======================================
The build system is called with one command: build. To see all
possible uses of this command, run
build help
8
Wave OS project early developer manual
build example/
build ./example
3.3 Logging
-----------
build example
build applications/example
Watch the output to see exactly what operations are performed by the
build system. It will clean the source code, configure it, and then
try to compile it. If you want to see the standard process output as
well, do
If the build procedure was successful, you can optionally run a suite
of tests, if the application has one:
If all is well, you can install the application. You may have to
become the super user to do that:
su
Then run
Building a third-party software package, i.e. software that is not native to Syllable but
was ported to it from other systems, is much like building a native module. Here, the
build system is starting to become useful. It shields you from many differences
between the build procedures of third-party packages. In order to do that, it needs
descriptions of these differences, that are written in the form of something called a
recipe.
10
Wave OS project early developer manual
The build system contains a number of recipes for packages that have
been ported to Syllable, so if you are building one of these
predefined packages, you don't have to worry about recipes. If you
are trying to build a package that is not known by the build system,
it is still possible that the default build procedure is able to
build it. The default procedure is oriented towards commonly used
build steps, and in particular towards the customary build procedures
of packages from the GNU project (http://www.gnu.org). If the default
procedure does not succeed in building a package, you will have to
find a recipe for it, or write one yourself. A common case would be
trying to build a newer version of a package that was ported before.
In that situation, chances are that the recipe for the older version
will work. In any case, refer to the chapter "Developing your own
packages".
3.5.2.1
--------
You could install the source code for a third-party package manually,
in a similar way to how you would put the sources for a native module
have to unpack in the place where you want to build it. However, the
build system can do this job for you. Just drop the source package
/resources/Builder/sources/
When you ask the build system to build a package for which the source
Wave OS project early developer manual
Even better, if the package has a build recipe that defines a download
location, and you have the cURL program installed, the build system
applied to the sources when you allow the build system to unpack the
explicitly tell the build system to apply any patches it has, like
this:
3.5.3 Building it
-----------------
12
Wave OS project early developer manual
contains the source code will typically include the version number of
build example-1.2
To install the package, you may have to become the super user:
su
The installion is done with
Take care that you are not distributing any sensitive data that the
running. If you want to be certain about this, you should build the
running it.
3.6.1
------
module that is built in the context of the source tree for the
Syllable base system. The build system assumes this context when it
path names that you use to designate the modules you want to build
native system modules typically use. It assumes that the source tree
contains the complete Syllable source code, in particular the system
and libraries. Those tend to change when Syllable evolves, which can
Syllable source tree are used. These things can be tricky, and there
Typically, the sources for the Syllable tree and the module to build
the same considerations apply that were described in the section for
14
Wave OS project early developer manual
patch the sources if it can. You are free to modify the tree, as long
3.6.3 Building it
-----------------
The commands for building a system module are no different than those
build example
image example
will install the module in the staging area where a partial directory
there, you can inspect the results of the build and move files into your
3.7.1
------
the build system. This is done by passing a profile name to the build
Wave OS project early developer manual
modules, enter:
build example-profile
sequentially. The logs will contain all the actions on all modules,
/resources/Builder/profiles/
16
Wave OS project early developer manual
A profile is simply a text file that you can write yourself. Please
will contain a list of the modules that failed. This is very handy if
you are building a long list of modules where some of them have
errors. You can use
build failures
will rerun the build procedure on only those packages that weren't
built successfully yet. This will even work if you invoked the build
Another auto-generated profile that you can use is named "last". This
profile always contains the last profile that the build command was
used with.
build dev-pack
(In this case, it's more complicated than that, because the developer
When you are satisfied with single distribution packages. you should
move them to
/resources/Builder/distributions/
Then,
contains all the packages from the profile, and optionally extra
the build system is capable of doing this and evolves over time with
Furthermore, if you try to build from CVS sources, you will most likely
18
Wave OS project early developer manual
encounter build failures that exist along the way to the next Syllable
release.
That said, here is a basic description of how the system is built. For
of them are available as binary packages, but some you may have to build
Source packs
Collection packs
- Shell Essentials
- Network Necessities
- Developer's Delight
Single packages
- CMake
There are several profiles that define a list of all the modules of
the Syllable Desktop base system. The process goes like this:
cd system
image syllable
Wave OS project early developer manual
image base
build log failures
image gui-base
build log failures
image gui
build log failures
image desktop
build log failures
su
image finish-su
build log failures
image finish
build log failures
cd stage/image
build scrub
cd ../..
construct distro SyllableDesktop 1.0 i586
Along the way you will have to fix build failures, using techniques
from this manual. Please have patience, and use at your own risk. Or,
in the words of our enlightened project leader:
Especially for Syllable Desktop, more than the above procedure is needed
to arrive at a complete system. We use extra scripts to set up a build
environment and drive Builder. They are here in Syllable's CVS repository:
/syllable/system/build-tools/scripts/auto-build/
Although these scripts automate the process, they are also a work in
progress, developing together with Syllable. At any point in time, they
are aimed at helping us produce the next Syllable development build.
20
Wave OS project early developer manual
Builder/packages/skeleton.recipe
Developing
Essential tools
There are some essential tools that any developer will require. These include a
compiler, a linker and an editor. All of these tools together are known as the
toolchain.
Syllable uses a combination of the familiar GNU toolchain along with its own
powerful and easy to use editors and applications. The GNU toolchain includes
GCC, BinUtils, GDB, GNU Make and the GNU AutoTools (AutoMake and
AutoConf).
On Syllable these tools are combined to create several packs. The Developer's
Delight pack contains the essential GNU tools, as well as tools such as the
Concurrent Versioning System (CVS), DoxyGen, SPLint and CScope. The
Developer's Delight pack also contains Builder, a Syllable application that can build
and pack software.
Depending on your goals, you may also need to install the other packs. The Perl Pit
pack contains the Perl scripting language and the GNU AutoTools that are necessary
for reconfiguring ported software.
Installing these packs is simple. First, you must log in as the root user. Then unzip
Wave OS project early developer manual
the pack and run the install.sh script which will install the individual packages for you:
[root@machine:~]unzip DevelopersDelight-7.i586.zip
Archive: DevelopersDelight-7.i586.zip
creating: DevelopersDelight/
extracting: DevelopersDelight/Builder-0.6.100.bin.1.zip
inflating: DevelopersDelight/README
extracting: DevelopersDelight/arch-1.3.5.bin.1.zip
extracting: DevelopersDelight/binutils-2.17.bin.2.zip
extracting: DevelopersDelight/bison-2.3.bin.2.zip
extracting: DevelopersDelight/cscope-15.5.bin.2.zip
extracting: DevelopersDelight/cvs-1.12.11.bin.2.zip
extracting: DevelopersDelight/doxygen-1.5.1.bin.1.zip
extracting: DevelopersDelight/flex-2.5.33.bin.2.zip
extracting: DevelopersDelight/gcc-4.1.1.bin.2.zip
extracting: DevelopersDelight/gdb-6.4.bin.2.zip
extracting: DevelopersDelight/indent-2.2.9.bin.3.zip
inflating: DevelopersDelight/install.sh
extracting: DevelopersDelight/m4-1.4.7.bin.1.zip
extracting: DevelopersDelight/make-3.80.bin.2.zip
extracting: DevelopersDelight/nasm-0.98.39.bin.2.zip
extracting: DevelopersDelight/patch-2.5.4.bin.3.zip
extracting: DevelopersDelight/ruby-1.8.5.bin.1.zip
extracting: DevelopersDelight/sindent.bin.1.zip
extracting: DevelopersDelight/splint-3.1.1.bin.3.zip
[root@machine:~]cd DevelopersDelight
[root@machine:~/DevelopersDelight]./install.sh
This will install the packages contained in the developer pack. Previously
installed packages of the same name will be removed first. Do you want
to continue (y/N)?
22
Wave OS project early developer manual
The Perl Pit and other collection packs can be installed in the same way.
[user@machine:~]gcc -v
--prefix=/resources/gcc
--enable-languages=c,c++ --with-arch=i586
--enable-sjlj-exceptions
--enable-shared --enable-threads
--with-system-zlib
--disable-libstdcxx-pch
[user@machine:~]
sIDE
Syllable has its own IDE called sIDE. sIDE includes a programmers editor (Sourcery)
and a GUI editor (Layout Editor).
sIDE keeps your project files organised for you, and comes with various "templates"
for different types of Syllable applications, including GUI and CLI based applications
in C++ and C. sIDE can also create projects that use Layout Editor.
Sourcery has been designed for developers and its features include line numbering,
syntax highlighting, code folding and automatic indenting. Sourcery is the default
editor for use with sIDE, or you can use Sourcery without sIDE if you prefer.
Layout Editor makes it easy to design the GUI for your application. It has a preview
window that shows you what your GUI looks like as you make changes within Layout
Editor, from which it will automatically generate the C++ code that creates and
displays the GUI at run time. Using Layout Editor saves you the hassle of having to
manually layout the GUI and can significantly speed up development time. If you
prefer you can create an sIDE project without using Layout Editor.
AEdit
AEdit is the default text editor that comes with Syllable. It is not a full-featured
Wave OS project early developer manual
programmers editor. If you prefer a simpler editor than Sourcery, AEdit may suit you.
VIM
VIm is a venerable and powerful text editor that comes from Unix. If you already
know VI you'll probably feel comfortable with it. If you're a VIm newbie, the VIm
website contains more information.
Emacs
Although an old version of XEMacs (19.34) was once available for Syllable, it no
longer runs on newer releases. There is no port of EMacs currently available for
Syllable.
Other editors
If none of the above are what you are looking for in an editor, you may find
something else in the Builder recipes.
sIDE
VIm
Other editors
Debugging tools
There are several tools and techniques you can use to debug your software.
GDB
The GNU debugger (GDB) is a well known debugger. If you have developed on other
systems such as Linux or *BSD then you may have already used GDB, or a similiar
Unix debugger.
GDB is a powerful dubugging tool, so unless you are already familiar with it you
should HYPERLINK "http://www.gnu.org/software/gdb/documentation/"read the
GDB manual. GDB is included in the Developer's Delight pack.
Strace
STrace allows you to see what system calls your application is making, as it runs.
This can be very useful for understanding what is happening "under the hood" of
your application, and can also help with profiling. You can trace an application that is
already running, or start an application under the control of STrace.
-o
-f
24
Wave OS project early developer manual
-g Select the syscall groups to include in the trace. The groups are:
mm
proc
device
net
ipc
io
debug
misc
all
More than one group can be passed by separating them with a comma e.g. -g net,io
will select all system calls in the net and io syscall groups.
-e Exclude a given syscall from tracing. The syscall can be given by name, e.g. -e
lock_semaphore will exclude all calls to lock_semaphore() from the trace.
-t
The thread ID (TID) to trace. You can use this to begin tracing an application that is
already running.
Wave OS project early developer manual
-r
Run an application with the supplied tracing arguments. You must specify the full
path to the application you wish to run.
As an example, let's say you wanted to trace thread #41 and see what I/O and
process syscalls it was making:
[user@machine:~]strace -o -g io,proc -t 41
[user@machine:~]
Hello world!
[user@machine:~]
26
Wave OS project early developer manual
As the application is traced the syscall information is printed by the kernel debugger.
You can watch the trace happening by watching the kernel log.
The Syllable kernel includes a simple, but very useful, kernel debugger. While
Syllable is running, the output from the kernel debugger is written to the "kernel log".
The kernel log file is /var/log/kernel.
It is a simple matter of using the tail command to read the kernel log as it is being
written by the kernel debugger:
[user@machine:~]tail -f /var/log/kernel
This will display the kernel log in the terminal. This can be used to watch the output
produced as you use STrace, but the kernel can also provide useful debugging
information of its own. If an application crashes the kernel will produce a "stack
trace" that shows the processor registers, memory area information and a backtrace
of the functions that were called upto the point of the crash.
int *a = (int*)0;
*a = 1;
foo();
return 0;
If we compile and run this application it will crash with a segmentation fault. The
following output is produced in the kernel log:
28
Wave OS project early developer manual
The kernel log can be a very powerful debugging tool once you are familiar with it.
Builder
Builder is a powerful application for Syllable developers that can be used to build
both third-party applications and Syllable itself, from source code. To do this, Builder
uses "recipes" which tell it what steps are required to download, unpack, patch,
configure, build, test, install, register and package the software on Syllable.
Using Builder is incredibly easy. From a Terminal you simply run build <recipe>, and
Builder will do the rest. You can then run build install <recipe> to install the new
software. An example of building GNU Gettext is:
Wave OS project early developer manual
[user@machine:~/]build gettext-0.15
...
[user@machine:~/]su -l
...
...
Builder is intended as a developer tool only and will not attempt to perform any
dependendency management for you, so you should not use it to attempt to upgrade
individual system components. You may also find that many of the packages or
libraries you require are already available as binaries from the Syllable resource
package downloads.
If you are porting software to Syllable, you are strongly encouraged to write a
suitable Builder recipe for it. This makes it much easier to maintain and upgrade the
software. There are a large number of existing recipes already available, and the
skeleton recipe details every option currently available.
main()
omake
Or classic Make:
make
Run it with:
./HelloWorld
30
Wave OS project early developer manual
*/
#include <util/application.h> // Include the definitions of the classes that we will use
#include <gui/window.h>
#include <gui/stringview.h>
// Tell the compiler that we will define classes MyWindow and MyApp later
class MyApp;
class MyWindow;
/*** Define the MyApp class - our customised Application object. ***
Usually the class definition would go in a separate file, myapp.h, but in this case
as it is so simple we include it here.
We declare the members and methods here, but we don't give the code for the
method functions yet. This comes later.
*/
class MyApp : public Application // Declaring class MyApp, derived from
libsyllable class Application
public:
// The destructor
~MyApp();
private:
Wave OS project early developer manual
MyWindow* m_pcWindow;
// *** Define the MyWindow class. This class contains the code for displaying some
content in the window. ***
{
public:
// Destructor
~MyWindow();
private:
StringView* m_pcStringView;
};
// ****** Now we give the code for the class methods ******
// *** First, MyApp ***
32
Wave OS project early developer manual
// The destructor. In this case, we don't need to do anything in the destructor, but we
must include it (or else the app won't link properly).
MyApp::~MyApp()
{}
*/
// This creates the view in memory, but later we need to manually add it to the
window for it to be displayed on screen.
*/
// Add the view to the window. This means it will be displayed in the window.
AddChild( m_pcStringView );
Wave OS project early developer manual
MyWindow::~MyWindow()
{}
// main() : the normal entry point to the program. This is the first thing run when the
program starts
// Create the Application object, which connects to the appserver and creates a
window
pcApp->Run();
return( 0 );
OmakeFile
CXXFLAGS += -O2
LDFLAGS += -lsyllable
APP = HelloWorld
CXXSOURCES[] =
34
Wave OS project early developer manual
$(APP)
open build/C
DefineCommandVars()
.SUBDIRS: .
#! /usr/bin/env rebol
REBOL []
Network drivers
The basics
The Syllable kernel is capable of loading modular device drivers as they are
required. Device drivers are simply ELF Dynamic Shared Objects (DSOs) DSOs are
usually used to implement shared libraries, but because the ELF runtime linker is
built into the kernel, Syllable can also use DSOs for device drivers.
An advantage of using standard ELF DSOs is that the kernel can provide a fixed
Application Binary Interface (ABI) for device drivers. This means that a binary driver
can be used with different kernel versions, without the need to recompile the binary.
Due to the way the compiler, linker (ld) and runtime linker work, the kernel driver API
is exported via. a shared library called "libkernel.so" This is a "stub" library that
contains all of the symbols that form the kernel API that the linker can use when it
Wave OS project early developer manual
builds a driver. If that seems a bit complex, don't worry about it; you do not need to
understand the mechanism. Just remember that "libkernel.so" is a special library that
is used to build device drivers on Syllable.
Like other POSIX systems, applications and libraries communicate with device
drivers through the filesystem. Syllable uses a device filesystem (DevFS) that
dynamically adds and removes device nodes under /dev as hardware is detected
and removed from the system.
Syllable can load drivers on-demand. When an application attempts to open a device
node under /dev that does not exist, the kernel will look for any appropriate drivers
that it has not yet loaded and load them. If any of those drivers successfully detect
hardware they will create device nodes under /dev. Hopefully (for the user) the
device node that the application is attempting to open will be created by one of the
drivers I.e. the driver will be loaded and the application will successfully open the
device node, without ever being aware of the on-demand driver loading.
In order for this on-demand scheme to work, the system organises the device drivers
under /system/drivers/dev in a way that closely matches the layout of the device
nodes under /dev.
As an example, the USB Human Interface Device (HID) driver is found under
/system/drivers/dev/input/. It creates device nodes under /dev/input/. If an application
attempts to open /dev/input/usb_mouse, the kernel can look under
/system/drivers/dev/input and load the usb_hid driver, which in turn will create
/dev/input/usb_mouse if a USB mouse is found on the USB bus. All of this is
transparent to the application.
Anatomy of a driver
In order to even be considered as a driver by the kernel, every driver must export the
following two functions:
device_init() is the entry point for the driver. The kernel will call this function when the
driver is first loaded. The driver will then have the chance to find any supported
hardware and initialise anything it finds. If the driver detects a supported device and
successfully initialises it, this function should return 0. If the driver fails to find any
hardware it can work with, it may return any negative value to indicate failure
(usually, -ENODEV).
device_uninit() is called when the driver is unloaded. The driver may or may not
need to do anything here. Many drivers leave this function empty, as there is no
need to cleanup once the device is removed from the system. We will talk about this
function later.
We'll also need a Makefile at this point. Most driver Makefiles look alike these days,
36
Wave OS project early developer manual
and one is included with the example project. Worth noting are the CFLAGS, which
are declared at the top of the Makefile as:
The important options are -kernel and -fno-PIC. The option -D__ENABLE_DEBUG__
is also very useful. We'll look at debugging later.
Device nodes
Most drivers will need to provide at least one device node in the filesystem so that
the system libraries and applications can communicate with it. A device node is very
simple; just like a normal file, it can be opened, closed, read from, written to,
controlled (via. ioctl()) and select()'d. The system header <atheos/device.h> declares
the following 9 functions for these operations:
typedef status_t dop_open( void* pNode, uint32 nFlags, void **pCookie ); typedef
status_t dop_close( void* pNode, void* pCookie ); typedef status_t dop_ioctl( void*
pNode, void* pCookie, uint32 nCommand, void* pArgs, bool bFromKernel ); typedef
int dop_read( void* pNode, void* pCookie, off_t nPosition, void* pBuffer, size_t
nSize ); typedef int dop_write( void* pNode, void* pCookie, off_t nPosition, const
void* pBuffer, size_t nSize ); typedef int dop_readv( void* pNode, void* pCookie,
off_t nPosition, const struct iovec* psVector, size_t nCount ); typedef int
dop_writev( void* pNode, void* pCookie, off_t nPosition, const struct iovec* psVector,
size_t nCount ); typedef int dop_add_select_req( void* pNode, void* pCookie,
SelectRequest_s* psRequest ); typedef int dop_rem_select_req( void* pNode, void*
pCookie, SelectRequest_s* psRequest );
Note the use of typedef here. This is because the kernel expects the be provided
with pointers to the drivers own version of these functions. The system header
<atheos/device.h> also declares the following structure:
typedef struct { dop_open* open; dop_close* close; dop_ioctl* ioctl; dop_read* read;
dop_write* write; dop_readv* readv; dop_writev* writev; dop_add_select_req*
add_select_req; dop_rem_select_req* rem_select_req; } DeviceOperations_s;
The driver implements the functions and then fills in a DeviceOperations_s structure
with pointers to those functions. A driver can choose to implement whichever device
operations make sense for the hardware and the way that it operates. In practice that
usually means open(), close() and at least one of ioctl(), read() or write(). If read()
and/or write() are implemented, a driver may also implement the readv() or writev()
operations too, but we'll leave those for later.
int create_device_node( int nDeviceID, int nDeviceHandle, const char* pzPath, const
DeviceOperations_s* psOps, void* pCookie );
This creates a device node under /dev and associates the device driver operations
with the device node, so that e.g. an application that calls open() on the device node
will eventually cause the device drivers own open() operation to be called.
/* Device interface */ static status_t example_open( void* pNode, uint32 nFlags, void
**pCookie ) { return 0; } static status_t example_close( void* pNode, void* pCookie )
Wave OS project early developer manual
So our driver will have open(), close(), ioctl(), read()and write() operations. The other
operations are simply NULL pointers: the kernel understands the use of NULL to
mean "No operation" and will handle the unimplemented operations transparently for
us.
Note also that these functions are declared static. There is no need to export these
symbols outside of the DSO as we pass them pointers to them indirectly via. the
DeviceOperations_s structure. Doing it this way allows a driver to export multiple
device nodes e.g. a sound card driver may export different nodes for the DSP and
the mixer.
Note that at this point we only have an empty set of functions and a struct containing
pointers to those functions. We have not called create_device_node() so nothing will
be created in /dev.
Bus managers
Bus managers exist as a way to bring together different host controllers and device
drivers in a moduler fashion. Because many different buses exist (e.g. PCI, USB,
SCSI) there are many different bus managers. At the moment most devices are PCI
devices, so the drivers use the PCI bus manager, but there are a growing number of
USB device drivers, too.
The bus manager abstracts away the bus hardware so that the device driver does
not need to know how the bus controller is implemented. This doesn't mean much for
PCI devices, where the PCI bus interface is well defined, but for e.g. USB buses it
allows the driver to ignore the details of what type of host controller the device is
physically connected too. Bus managers also handle scaning the bus for devices
and hot-plug events (for buses that support such functionality)
Bus managers are really a specialised type of device driver, but their implementation
is outside the scope of this tutorial. All we really need to worry about right now is how
to access the functions of the bus manager.
Every bus is different, and every bus manager provides different bus-specific
functions that a driver may use. The kernel doesn't need to worry about this though,
so we have exactly one function we need to know about:
This generic kernel function can be used to access any of the available bus
managers. However our driver will only need to worry about PCI devices, so:
What we have is another structure that contains a series of function pointers. This
time the PCI_bus_s structure, which contains pointers to the various PCI bus
38
Wave OS project early developer manual
manager functions. Because the functions in the bus manager can change in newer
versions of Syllable, get_busmanager() also accepts a version number which tells
the bus manager which version of the PCI_bus_s structure the driver is expecting. If
an older driver is loaded on a system with a newer PCI bus manager, the bus
manager can still provide a set of functions that will work. This makes the device
driver and bus manager both forward and backward compatible.
Because we'll need to access functions in the PCI bus manager at various points in
the driver we make g_psBus a global variable for convienience.
Device management
Syllable can automatically detect new hardware and drivers, and load them on-
demand. However, it does need a little help from the device drivers so that it knows
which drivers are loaded for what hardware, or if a driver is not required.
There are two functions you will normally need to deal with:
status_t claim_device( int nDeviceID, int nHandle, const char* pzName, enum
device_type eType ); void release_device( int nHandle );
As we know, when the driver is loaded by the kernel the device_init() function. The
driver can then try to find any hardware that it supports. If a supported device is
found the driver can call claim_device() to mark the device as "taken". This stops
another device driver from being able to claim the device. claim_device() is also
used to tell the kernel some additional information about the device, and allows it to
maintain a map of the supported devices on the system. This device map can be
used by utilities such as Syllable Manager to show the user device information.
These functions are more generally used by the bus managers, to tell the kernel
about any devices that are attached to the bus. However they are occasionally used
by device drivers when dealing with devices that are not supported by the bus
managers e.g. ISA devices. In these cases, the device driver first calls
register_device() to tell the kernel about the hardware, and then calls claim_device()
as normal. Unless you are writing a device driver for old or strange hardware, you
can ignore register_device() and unregister_device() for the most part.
There is one more function that is very important to the way device managment
works on Syllable:
disable_device() is a way for a device driver to tell the kernel "I did not find any
hardware. Do not load me again." This is used for devices that do not support hot-
plug, such as PCI devices. In general the configuration of the bus does not change
often; the same devices are usually present on the bus the next time Syllable boots.
So that the kernel does not always need to load every single driver whenever the
system is booted (only for many of them to fail to detect any supported hardware),
disable_device() allows the kernel to know in advance which devices drivers will not
Wave OS project early developer manual
This functionality is less useful for devices that support hot-plug, such as USB
devices. In that case it is impossible to know when hardware will be attached to the
bus, so the kernel must be able to load any of the available device drivers in an
attempt to find a driver which supports the newly attached hardware.
If you're wondering what happens if the user installs a new device but the device
driver that supports it has disabled itself: the PCI bus manager can see when the
configuration has changed and will re-enable all of the previously disabled device
drivers. This gives the drivers a chance to look for supported hardware again.
So far we've ignored the nDeviceID parameter which is passed to device_init() and
device_uninit(), and expected by claim_device(). Although it is named "Device ID" it
is more properly the "Driver ID". Each driver that is loaded by the kernel is given a
unique "Device ID" The ID is used to track which drivers successfully initialise and
which devices are associated with the driver. Other than that you do not need to
worry too much about it, other than to remember to pass it to claim_device().
Debugging
The kernel has a simple debugger built in that can be used by a developer to capture
debugging messages and see what is happening on a system. The debug output
can be seen when Syllable boots, and it is also captured to the kernel log file
/var/log/kernel. The debug output can also be sent over a serial cable to another
machine, which is useful if your driver causes the kernel to crash before it can write
the debug information to the kernel log!
Generating this debug output is very simple. The system header file
<atheos/kdebug.h> contains the function:
which as you might guess, is the kernel equivalent of printf()! printk() will print your
debugging text no matter what. It is generally preferable to have a little more control
over the level of debug information you want to produce, so the macro:
kerndbg(level,format,arg...)
The idea is that you can insert as much debugging information as you need while
you are developing your driver. Once you are satisfied that your driver is working you
can then increase DEBUG_LIMIT to "switch off" this additional debugging
information. Should you ever need to revisit your code to debug any additional
problems, you can once again enable the debugging information by lowering the
value of DEBUG_LIMIT.
40
Wave OS project early developer manual
The kerndbg() macro only works if __ENABLE_DEBUG__ is also defined. You might
remember that it is set in the Makefile CFLAGS with -D__ENABLE_DEBUG__. If you
want to disable debug output totally, you can remove the definition.
The example driver implements a simple driver which registers a new device, claims
it and creates the device node /dev/misc/example. It includes debugging output, so
you can see what happens at various points as the driver is loaded. You can also try
opening, reading, writing and closing the device while you watch the debugging
output in the kernel log (Try " tail -f /var/log/kernel" in a new Terminal).
Once you've got to grips with the example driver, take a look at some of the other
drivers in Syllables CVS repository. Don't worry if they don't make much sense yet,
but you should be able to spot many of the concepts we've already covered. Try
making some changes to the example driver. How would you create a second device
node under /dev? What happens if the driver tries to call claim_device() without
registering a new device with the kernel first?
Next
Part 2: Ethernet drivers and the network stack.
A modular stack
Like the rest of Syllable, the network stack in Syllable is modular. It is comprised of
four parts:
The system libraries (i.e. LibC) which present a BSD sockets API to applications.
The upper part of the network stack, which provided TCP, UDP, IP, ICMP and ARP
functionality.
The interface layer, which handles the generic code appropriate for the type of
network interface in use.
The first two of these layers are a pretty standard network stack. The third layer
allows Syllable to support different types of network connection easily. For ethernet
connections Syllable uses the eth_if interface driver. This handles common tasks,
such as ethernet encapsulation. It then passes these ethernet frames down to the
device driver to send to the hardware. It also recieves ethernet frames from the
device driver and passes the IP packets to the upper layers.
As an example of another interface driver, PPP for Syllable includes a ppp_if driver,
which handles communication between the network stack and pppd, the PPP
deamon.
Just like device drivers, interface drivers are ELF Dynamic Shared Objects (DSOs)
Unlike device drivers, they are always loaded when the kernel boots, rather than on-
demand.
Driver interface
As we know, system libraries and applications communicate with device drivers via.
the device node in /dev. For ethernet drivers this is only part of the full picture.
Ethernet drivers are a special case. Because ethernet frames can and do arrive at
any time and most ethernet controllers only have a small buffer to store these
packets, they must be handled as quickly as possible to avoid overflowing the
incoming packet buffer and losing data.
This means that the interface driver can not simply call read() to retrieve data from
the driver: with a busy network connection, data would be arriving too quickly for the
interface driver to keep up. Instead, the driver "pushes" data to the interface driver as
each frame arrives, which ensures packets are handled as quickly as possible.
Note that the reverse is not true. Because the hardware is generally much quicker
than the network stack, the interface driver can call write() to send data to the driver
without any problems. This leads to one of the most confusing aspects of ethernet
drivers on Syllable: the interface driver will call open(), close(), ioctl() and write() but
not read(). If you are studying an ethernet driver for the first time it may not be
immediatly clear how data arriving from the connection gets to the network stack.
Device nodes
How does the interface driver know which devices are available? When it is loaded
by the kernel, eth_if looks for device nodes under /dev/net/eth/. The drivers create
one node for every interface they have detected, in this directory. For example, on a
machine with a single Intel EEPro 100 network card the device node "
/dev/net/eth/eepro100-0" exists. If the machine had two Intel EEPro network devices,
the driver would also create " /dev/net/eth/eepro100-1"
Packet buffers
Data to be sent and received by the driver are stored in a packet buffer. This is
represented by the PacketBuf_s structure, which is defined in the system header
<net/packet.h>. A single PacketBuf_s structure keeps the packet and its associated
data together all the way through the network stack.
An ethernet driver can treat the PacketBuf_s data as an opaque "blob" of data. All it
must deal with is the raw data inside the packet buffer, which is a complete ethernet
frame.
The system header <net/net.h> provides some functions for dealing with packet
buffers:
These functions do exactly what you would expect. alloc_pkt_buffer() creates a new,
empty packet buffer and free_pkt_buffer() destroys a previously allocated packet
buffer and any packet data that it contains.
Each network interface also has a net queue. The system header <net/packet.h>
42
Wave OS project early developer manual
defines the NetQueue_s structure. A net queue is used to store outgoing and
incoming frames as they are passed between the interface driver and the device
driver. The device driver does not need to do anything with the net queue itself other
than to tell the interface driver which net queue a newly arrived frame should be
placed in. We will cover this in more detail later.
To understand how everything fits together, we'll now look at how data passes
through a typical ethernet driver. First of all we will consider how data is sent to the
network, and then how data arrives from the network.
We can ignore the work that is done by the IP stack and sockets API; from the point
of view of the driver these layers are irrelevant. The only part the driver needs to
know about is the interface layer.
As data works its way down through the layers it will eventually arrive at the interface
layer, where it becomes individual ethernet frames. Each of these frames are stored
in individual packet buffers. For each frame, the interface driver calls write() to pass
the PacketBuf_s structure to the driver. The driver then copies the frame into the
cards internal transmit (Tx) buffer, performs some house keeping tasks such as
updating internal counters, pointers and lists, and then returns. The frame is held in
the cards Tx buffer until the hardware is ready to transmit it.
When a frame arrives from the network, the hardware will store it in an internal
recieve (Rx) buffer and raises an interrupt to signal to the driver that a new frame
has arrived and requires attention. The drivers interrupt handler runs. The driver
creates a new PacketBuf_s structure and copies the new frame into it. It must then
inform the interface layer about the new frame. The system header <net/net.h>
declares the following function:
void enqueue_packet( NetQueue_s* psQueue, PacketBuf_s* psBuf );
This simple function adds the new packet buffer to the net queue, which the interface
layer will process afterwards. The NetQueue_s pointer is provided to the device
driver by the interface layer when the interface is initialised. We will cover this in
more detail in chapter 3.
Once the drivers interupt handler has queue the new frame for the interface layer, it
performs some house keeping tasks such as updating internal counters, pointers
and lists, and then finishes.
This is what any ethernet driver will do 95% of the time. Despite the differences in
the hardware almost every single ethernet driver is structured in a very similiar way,
with the aim of making sending and recieving frames as efficient as possible. Once
you are familiar with how one ethernet driver works you will find it very easy to
understand almost any other ethernet driver.
Video drivers in Syllable are composed of a small kernel driver and a user-space
appserver driver. The appserver driver implements the majority of the actual video
driver functionality. The kernel driver is used only to access PCI hardware,
something that can not be done from user-space. Most video kernel drivers are very
similiar. They iterate the list of PCI hardware looking for a supported card, and
provide a small set of ioctl() commands that can be used by the appserver driver.
Most video drivers inherit from the DisplayDriver class, but some may inherit from
the VesaDriver class. The VesaDriver provides additional VESA mode switching
functions which may be used for certain hardware. For example the Mach64
accelerated driver inherits VesaDriver in order to use the VESA mode switching
functions for some chipsets.
Functionality
For the purposes of this document we'll pretend we have some video hardware
called "Fire" and assume we are writing a display driver for that hardware.
The most basic video driver for any hardware must provide the following functions
and methods.
Fire::Fire( int nFd ); Fire::~Fire( void ); bool Fire::IsInitiated( void ) const; area_id
Fire::Open( void ); int Fire::GetScreenModeCount( void ); bool
Fire::GetScreenModeDesc( int nIndex, os::screen_mode* psMode ); int
Fire::SetScreenMode( os::screen_mode sMode ); extern "C" DisplayDriver*
init_gfx_driver( int nFd );
44
Wave OS project early developer manual
The last function in that list is not a C++ method, but instead a C style function. This
function is called when the display driver is initialised. Most display drivers simply
implement init_gfx_driver() to create a new instance of their display driver class, and
then do the actual hardware detection and initialisation in the class constructor.
init_gfx_driver() is passed a file handle to the kernel driver, which is can use to call
ioctl() and communicate with the kernel driver. The file handle is usually passed to
the constructor.
The constructor and destructor should be fairly obvious. Generally the constructor
will retrieve the hardware configuration information from the kernel driver. If
supported hardware is found then the hardware must be initialised, although this is
an internal function of the display driver and will differ between different video
hardware. What your initialisation code must do however is create and create an
area and remap it to the video framebuffer memory. This area is provided to the
appserver later in the initialisation process and is the only way in which the
DisplayDriver base class can access the video framebuffer.
Unless your hardware has a functional VESA BIOS and you have inherited from the
VesaDriver class, you will have to provide three methods which are used by the
appserver to set the video mode. GetScreenModeCount() should simply return the
total number of valid screenmodes. GetScreenModeDesc() returns a structure which
contains the display mode information for the requested display mode. Finally,
SetScreenMode() is used to actually set the desired video mode.
GetScreenModeCount() & GetScreenModeDesc() are generally implemented in a
similiar maner in any display driver as they are hardware independent.
SetScreenMode() is hardware dependent.
The IsInitiated() method simply returns true if the driver was able to detect and
initialise the video hardware, or false otherwise.
The Open() method is the last peice of the puzzle. It must return the area ID of the
previously created framebuffer area. The appserver can then find the video
framebuffer base address from this area and use it to access the video framebuffer
to perform drawing functions.
Accelerated drawing
An accelerated video driver will also provide methods which override the
DisplayDriver software rendering methods. Their implementation is highly hardware
dependent, but most drivers implement methods to accelerate line drawing,
rectangular fills and bitmap blits. The methods are:
All of these methods receive a pointer to a SrvBitmap class. This class is the internal
bitmap which is being rendered too. SrvBitmaps can either be in video memory or
system memory, depending on wether they are on screen or off screen. Generally,
video hardware cannot perform rendering operations on memory which is not in its
own video framebuffer, so you must first check to ensure that the bitmap you are
rendering to exists in video memory. If it is not, you should pass the rendering
request down to your base class, which will use the software rendering methods in
DisplayDriver .
The DrawLine() and FillRect() methods receive Color information which indicates the
color that the line or fill should be drawn with. You may need to convert the RGBA
information contained in the Color32_s class to information which can be used by
your video hardware, but this is hardware dependent.
The Drawline() and BltBitmap() nMode argument indicates the drawing mode which
should be used to perform the operation. This argument will specify DM_COPY (a
stright drawing operation), DM_OVER (an alpha transparent "stamp" operation
where the transparency is either "On" or "Off") or DM_BLEND (an alpha blending
operation). DM_COPY and DM_OVER operations are the most common, and you
may choose not to support hardware accelerated DM_OVER and DM_BLEND
operations. Generally, passing this drawing operations down to the DisplayDriver
methods does not noticably slow down rendering.
Video overlays
If your hardware supports video overlays you may wish to support this functionality in
your display driver. There are three methods which you must provide in order to
support video overlays correctly. They are:
All of these functions will be highly hardware specific and the functionality is
complex. You should refer to actual driver implementations of these methods if you
wish to understand how they work.
Off-screen bitmaps
Bliting a bitmap from system memory into video memory can be a slow operation, so
it is better to store bitmap data in the hardware video memory where it can be
accessed quickly when it is needed. The DisplayDriver class has four memory
management functions that help the appserver to manage these off-screen bitmaps.
They are:
46
Wave OS project early developer manual
If your driver supports video overlays you will also need to call AllocateMemory() and
FreeMemory() to manage the video memory required by the video overlay. Your
driver should never need to call AllocateBitmap() itself.
LockBitmap() is called by the appserver to ensure that the hardware has completed
any accelerated rendering operations. A basic implementation simply waits for the
hardware to become idle before it returns. Your hardware may or may not require a
more complex method. A simple implementation will not need to implement
UnlockBitmap() , but exactly what you must do depends on how you have
implemented LockBitmap() .
An example driver
/*
* The Syllable appserver
* Example appserver video driver
*/
#include <atheos/areas.h>
#include <atheos/pci.h>
#include <appserver/pci_graphics.h>
/* Initialisation methods */
/*
* Get the device register address and size. The address is usually
taken from one of the PCI base address registers, E.g:
*
* nRegisterBase = sInfo.u.h0.nBase1 & PCI_ADDRESS_MEMORY_32_MASK;
*
* but this is hardware dependent to some degree. Even if your card
does use the PCI base registers, it may not use nBase0
* for the register address; check the documentation!
*
* The size of the device register area is generally fixed, but the
size will be hardware dependent.
*/
uint32 nRegisterBase = /* Physical base address of the device
registers */
size_t nRegisterSize = /* Size of the device registers */
/* Create an area the size of the device registers and remap it to the
device registers */
uint8 * pnRegisterAddr; /* Logical base address of the device
registers, which will be set by remap_area() */
/*
* With the device registers mapped you are now free to perform any
hardware specific initialisation that require device
* register accesses.
*/
/*
* Get the video memory address and size. The address is usually taken
from one of the PCI base address registers, E.g:
*
* nVideoMemoryBase = sInfo.u.h0.nBase0 & PCI_ADDRESS_MEMORY_32_MASK;
*
* but this is hardware dependent to some degree. Even if your card
does use the PCI base registers, it may not use nBase0
* for the framebuffer address; check the documentation!
*
* Obtaining the size of the video memory is hardware dependent.
*/
uint32 nVideoMemoryBase = /* Physical base address of the video
memory */
48
Wave OS project early developer manual
/* Create an area the size of the total available video memory and
remap it to the hardware video memory */
uint8 * pnVideoMemoryAddr; /* Logical base address of the video
memory, which will be set by remap_area() */
/* Note the use of AREA_WRCOMB, which enables MTRR Write Combining for
the video memory */
m_hFrameBufferArea = create_area( "fire_video_memory",
(void**)&pnVideoMemoryAddr, nVideoMemorySize, AREA_FULL_ACCESS |
AREA_WRCOMB, AREA_NO_LOCK );
if( remap_area( m_hFrameBufferArea, (void*)&nVideoMemoryBase ) != EOK )
{
dbprintf( "Error: Failed to remap video memory.\n" );
return;
}
/* pnVideoMemoryAddr now points to the video memory */
/*
* If your driver does not use the VESA BIOS, you must create a list of
available video modes. I would personally recomend
* using and STL std::vector E.g:
*
* std::vector<os::screen_mode>m_cModes;
*
*/
/*
* If your driver supports off-screen bitmaps then you must intialise
the memory allocator.
*/
uint32 nOffScreenOffset = /*
* Calculate the maximum possible memory
that can be used for the framebuffer. This is usually the
* maximum resolution supported by the
device, using:
*
* size = (max_x * max_y) *
max_depth_bytes;
*
* E.g. if your hardware supports a maximum
1024x768 resolution in 32bit colour (4bytes per. pixel) it
* would be:
*
* 3145728 = (1024 * 768) * 4;
*
* Once you know where the framebuffer
ends, you can calculate the start and size of the off-screen
* video memory.
*/
Wave OS project early developer manual
Fire::~Fire( void )
{
/* Delete any areas that this driver has created */
if( m_hFrameBufferArea != -1 )
delete_area( m_hFrameBufferArea );
/* Ensure that you have completed any device register accesse before
deleting the device register area */
if( m_hRegisterArea != -1 )
delete_area( m_hRegisterArea );
}
return m_hFrameBufferArea;
}
*psMode = m_cModes[nIndex];
50
Wave OS project early developer manual
return true;
}
/*
* The hardware FIFO is marked as busy, wait for it to empty. How your
driver does this is hardware dependent.
*/
m_bEngineDirty = false;
return true;
}
return true;
}
return true;
}
return true;
}
52
Wave OS project early developer manual
m_nOverlayOffset = nOverlayOffset;
/* Create a new area for the video overlay data and remap it onto the
video memory at the location given to us by AllocateMemory() */
*phArea = create_area( "fire_video_overlay", NULL,
PAGE_ALIGN( nOverlaySize ), AREA_FULL_ACCESS, AREA_NO_LOCK );
remap_area( *phArea, (void*)( m_nFrameBufferAddr + nOverlayOffset ) );
/*
* Hardware specific code will be required to create the video overlay.
*/
return true;
}
/*
* Hardware specific code will be required to destroy the video
overlay.
*/
{
delete( pcDriver );
pcDriver = NULL;
}
return pcDriver;
}
The example appserver driver shows a skeleton appserver video driver, and there is
also a matching
/*
* The Syllable kernel
* Example kernel graphics driver
* Copyright (C) 2003 Arno Klenke
* Copyright (C) 1999 - 2001 Kurt Skauen
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU Library
* General Public License as published by the Free Software
* Foundation.
*
* 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
*
*/
#include <posix/errno.h>
#include <atheos/kernel.h>
#include <atheos/device.h>
#include <atheos/pci.h>
#include <appserver/pci_graphics.h>
struct gfx_device
{
int nVendorID;
int nDeviceID;
char *zVendorName;
char *zDeviceName;
};
struct gfx_node
{
PCI_Info_s sInfo;
char zName[255];
54
Wave OS project early developer manual
};
switch ( nCommand )
{
case IOCTL_GET_APPSERVER_DRIVER:
{
memcpy_to_user( pArgs, APPSERVER_DRIVER,
strlen( APPSERVER_DRIVER ) );
break;
}
case PCI_GFX_GET_PCI_INFO:
{
memcpy_to_user( pArgs, &psNode->sInfo, sizeof( PCI_Info_s ) );
break;
}
case PCI_GFX_READ_PCI_CONFIG:
{
struct gfx_pci_config sConfig;
PCI_bus_s *psBus = get_busmanager( PCI_BUS_NAME,
PCI_BUS_VERSION );
memcpy_from_user( &sConfig, pArgs, sizeof( struct
gfx_pci_config ) );
Wave OS project early developer manual
case PCI_GFX_WRITE_PCI_CONFIG:
{
struct gfx_pci_config sConfig;
PCI_bus_s *psBus = get_busmanager( PCI_BUS_NAME,
PCI_BUS_VERSION );
memcpy_from_user( &sConfig, pArgs, sizeof( struct
gfx_pci_config ) );
sConfig.m_nValue = nVal;
memcpy_to_user( pArgs, &sConfig, sizeof( struct
gfx_pci_config ) );
}
}
break;
default:
nError = -ENOIOCTLCMD;
}
return nError;
}
DeviceOperations_s g_sOperations = {
gfx_open,
gfx_close,
gfx_ioctl,
NULL,
NULL
};
56
Wave OS project early developer manual
bDevFound = true;
}
}
}
if ( !bDevFound )
{
disable_device( nDeviceID );
return -ENODEV;
}
return 0;
}
These are not complete drivers, but are intended to illustrate some of the points
covered in this article.
Video drivers in Syllable are composed of a small kernel driver and a user-space
appserver driver. The appserver driver implements the majority of the actual video
driver functionality. The kernel driver is used only to access PCI hardware,
something that can not be done from user-space. Most video kernel drivers are very
similiar. They iterate the list of PCI hardware looking for a supported card, and
provide a small set of ioctl() commands that can be used by the appserver driver.
Appserver drivers are written in C++ and provide methods required to open a video
framebuffer, accelerated drawing functions and video overlay controls. The driver
can inherit from one of two possible base classes, DisplayDriver or VesaDriver .
They are structured like this:
58
Wave OS project early developer manual
video memory. The VesaDriver class is a fully functional VESA 2.0 display driver. It is
the default display driver that Syllable will attempt to use if no accelerated display
driver can be found for the installed hardware.
Most video drivers inherit from the DisplayDriver class, but some may inherit from
the VesaDriver class. The VesaDriver provides additional VESA mode switching
functions which may be used for certain hardware. For example the Mach64
accelerated driver inherits VesaDriver in order to use the VESA mode switching
functions for some
chipsets.
Functionality
For the purposes of this document we'll pretend we have some video hardware
called "Fire" and assume we are writing a display driver for that hardware.
The most basic video driver for any hardware must provide the following functions
and methods.
Fire::Fire( int nFd ); Fire::~Fire( void ); bool Fire::IsInitiated( void ) const; area_id
Fire::Open( void ); int Fire::GetScreenModeCount( void ); bool
Fire::GetScreenModeDesc( int nIndex, os::screen_mode* psMode ); int
Fire::SetScreenMode( os::screen_mode sMode ); extern "C" DisplayDriver*
init_gfx_driver( int nFd );
The last function in that list is not a C++ method, but instead a C style function. This
function is called when the display driver is initialised. Most display drivers simply
implement init_gfx_driver() to create a new instance of their display driver class, and
then do the actual hardware detection and initialisation in the class constructor.
init_gfx_driver() is passed a file handle to the kernel driver, which is can use to call
ioctl() and communicate with the kernel driver. The file handle is usually passed to
the constructor.
The constructor and destructor should be fairly obvious. Generally the constructor
will retrieve the hardware configuration information from the kernel driver. If
supported hardware is found then the hardware must be initialised, although this is
an internal function of the display driver and will differ between different video
hardware. What your initialisation code must do however is create and create an
area and remap it to the video framebuffer memory. This area is provided to the
appserver later in the initialisation process and is the only way in which the
DisplayDriver base class can access the video framebuffer.
Unless your hardware has a functional VESA BIOS and you have inherited from the
Wave OS project early developer manual
VesaDriver class, you will have to provide three methods which are used by the
appserver to set the video mode. GetScreenModeCount() should simply return the
total number of valid screenmodes. GetScreenModeDesc() returns a structure which
contains the display mode information for the requested display mode. Finally,
SetScreenMode() is used to actually set the desired video mode.
GetScreenModeCount() & GetScreenModeDesc() are generally implemented in a
similiar maner in any display driver as they are hardware independent.
SetScreenMode() is hardware dependent.
The IsInitiated() method simply returns true if the driver was able to detect and
initialise the video hardware, or false otherwise.
The Open() method is the last peice of the puzzle. It must return the area ID of the
previously created framebuffer area. The appserver can then find the video
framebuffer base address from this area and use it to access the video framebuffer
to perform drawing functions.
Accelerated drawing
An accelerated video driver will also provide methods which override the
DisplayDriver software rendering methods. Their implementation is highly hardware
dependent, but most drivers implement methods to accelerate line drawing,
rectangular fills and bitmap blits. The methods are:
All of these methods receive a pointer to a SrvBitmap class. This class is the internal
bitmap which is being rendered too. SrvBitmaps can either be in video memory or
system memory, depending on wether they are on screen or off screen. Generally,
video hardware cannot perform rendering operations on memory which is not in its
own video framebuffer, so you must first check to ensure that the bitmap you are
rendering to exists in video memory. If it is not, you should pass the rendering
request down to your base class, which will use the software rendering methods in
DisplayDriver .
The DrawLine() and FillRect() methods receive Color information which indicates the
color that the line or fill should be drawn with. You may need to convert the RGBA
information contained in the Color32_s class to information which can be used by
your video hardware, but this is hardware dependent.
The Drawline() and BltBitmap() nMode argument indicates the drawing mode which
should be used to perform the operation. This argument will specify DM_COPY (a
stright drawing operation), DM_OVER (an alpha transparent "stamp" operation
where the transparency is either "On" or "Off") or DM_BLEND (an alpha blending
operation). DM_COPY and DM_OVER operations are the most common, and you
may choose not to support hardware accelerated DM_OVER and DM_BLEND
operations. Generally, passing this drawing operations down to the DisplayDriver
60
Wave OS project early developer manual
Video overlays
If your hardware supports video overlays you may wish to support this functionality in
your display driver. There are three methods which you must provide in order to
support video overlays correctly. They are:
All of these functions will be highly hardware specific and the functionality is
complex. You should refer to actual driver implementations of these methods if you
wish to understand how they work.
Off-screen bitmaps
Bliting a bitmap from system memory into video memory can be a slow operation, so
it is better to store bitmap data in the hardware video memory where it can be
accessed quickly when it is needed. The DisplayDriver class has four memory
management functions that help the appserver to manage these off-screen bitmaps.
They are:
If your driver supports video overlays you will also need to call AllocateMemory() and
FreeMemory() to manage the video memory required by the video overlay. Your
driver should never need to call AllocateBitmap() itself.
LockBitmap() is called by the appserver to ensure that the hardware has completed
any accelerated rendering operations. A basic implementation simply waits for the
hardware to become idle before it returns. Your hardware may or may not require a
more complex method. A simple implementation will not need to implement
UnlockBitmap() , but exactly what you must do depends on how you have
implemented LockBitmap() .
By the end of chapter three we had stubbed out five functions which are called by
tg3_init_one() . They are:
static int tg3_halt(struct tg3 *tp, int kind, int silent); static int tg3_get_invariants(struct
tg3 *tp); static int tg3_get_device_address(struct tg3 *tp); static int
tg3_test_dma(struct tg3 *tp); static PCI_Info_s * tg3_find_peer(struct tg3 *tp);
We skipped them either because they were very large, or because they in turn called
another series of functions. Now we'll have to start porting the code for these
functions. We'll start with the tg3_halt() function. It calls a series of other functions,
namely:
tg3_stop_fw() tg3_write_sig_pre_reset() tg3_abort_hw() tg3_write_sig_legacy()
tg3_write_sig_post_reset() tg3_chip_reset()
There's nothing for it: we'll also have to port each of these functions, too.
Luckily for us, most of these functions are actually fairly simple. They mostly modify
structures we already have, or use functions we have already ported, or rely on
Linux functions which are provided by linux_compat.h In fact, we can pretty much
copy and paste the entire functions into our driver without having to modify anything
other than to change the printk() functions into kerndbg() macros. The only function
that requires much attention is tg3_chip_reset(), where we'll change the Linux style
PCI functions to Syllable style calls to the bus manager.
Once we've completed the six functions called by tg3_halt() , we need to know if
there are any other functions that are called but are not yet ported. That's easy to
work out: we'll try to build the driver and see if it fails:
So we can see that we'll also need to port the following functions:
62
Wave OS project early developer manual
The first two are simple enough. Again, we'll just change the Linux style PCI
functions to Syllable code. Both tg3_disable_ints() and tg3_nvram_lock() are also
very simple and require no changes. While we're here, we'll also go ahead and port
tg3_nvram_unlock() because it's small and we can be fairly certain that we're going
to need it at some point, so we may as well do it now.
That should be enough to satisfy the linker, so lets try compiling the driver again:
So that's tg3_halt() implemented, which was the first function on our original list. You
can see what the driver looks like HYPERLINK
"http://development.syllable.org/documentation/drivers/network/examples/part-2/tg3-
1.c"here .
There are still four more stub functions which we must implement. They can be
ported in the same manner as tg3_halt() , by porting the function and then porting
any functions which is relies upon. There are no shortcuts here, just lots of cutting,
pasting and porting! Still, as long as we stick to one of the stub functions at a time we
shouldn't end up bogged down in the code.
It takes around four hours before we have ported enough code that the driver
compiles and links again. To get an idea of how much work we have done, /*
* tg3.c: Broadcom Tigon3 ethernet driver.
*
* Copyright (C) 2006 Kristian Van Der Vliet (vanders@liqwyd.com)
* Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
* Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
* Copyright (C) 2004 Sun Microsystems Inc.
* Copyright (C) 2005 Broadcom Corporation.
*
* Firmware is:
* Derived from proprietary unpublished source code,
* Copyright (C) 2000-2003 Broadcom Corporation.
*
* Permission is hereby granted for the distribution of this firmware
* data in hexadecimal or equivalent format, provided this copyright
* notice is accompanying it.
*/
#include <atheos/kernel.h>
#include <atheos/kdebug.h>
#include <atheos/types.h>
#include <atheos/device.h>
#include <atheos/pci.h>
#include <atheos/spinlock.h>
#include <atheos/udelay.h>
#include <posix/errno.h>
#include <net/net_device.h>
#include <net/mii.h>
#define NO_DEBUG_STUBS 1
#include <atheos/linux_compat.h>
Wave OS project early developer manual
#include <tg3.h>
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
#define TG3_DEF_TX_MODE 0
/* Do not place this n-ring entries value into the tp struct itself,
* we really want to expose these constants to GCC so that modulo et
* al. operations are done with shifts and masks instead of with
* hw multiply/modulo instructions. Another solution would be to
* replace things like '% foo' with '& (foo - 1)'.
*/
#define TG3_RX_RCB_RING_SIZE(tp) \
((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ? 512 : 1024)
64
Wave OS project early developer manual
66
Wave OS project early developer manual
spin_lock_irqsave(&tp->indirect_lock, flags);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_BASE_ADDR, 4, off);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_DATA, 4, val);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
spin_lock_irqsave(&tp->indirect_lock, flags);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_BASE_ADDR, 4, (uint32)off);
val = g_psBus->read_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_REG_DATA, sizeof(val));
spin_unlock_irqrestore(&tp->indirect_lock, flags);
return val;
}
{
unsigned long flags;
spin_lock_irqsave(&tp->indirect_lock, flags);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_BASE_ADDR, 4, off + 0x5600);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_DATA, 4, val);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
}
spin_lock_irqsave(&tp->indirect_lock, flags);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_BASE_ADDR, 4, (uint32)off + 0x5600);
val = g_psBus->read_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_REG_DATA, sizeof(val));
spin_unlock_irqrestore(&tp->indirect_lock, flags);
return val;
}
68
Wave OS project early developer manual
static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
{
tp->write32_mbox(tp, off, val);
if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) &&
!(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
tp->read32_mbox(tp, off);
}
spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_MEM_WIN_BASE_ADDR, 4, off);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_MEM_WIN_DATA, 4, val);
spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_MEM_WIN_BASE_ADDR, 4, off);
*val = g_psBus->read_pci_config(tp->pdev->nBus, tp->pdev->nDevice,
tp->pdev->nFunction, TG3PCI_MEM_WIN_DATA, 4);
70
Wave OS project early developer manual
orig_clock_ctrl = clock_ctrl;
clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN |
CLOCK_CTRL_CLKRUN_OENABLE |
0x1f);
tp->pci_clock_ctrl = clock_ctrl;
*val = 0x0;
MI_COM_REG_ADDR_MASK);
frame_val |= (MI_COM_CMD_READ | MI_COM_START);
tw32_f(MAC_MI_COM, frame_val);
loops = PHY_BUSY_LOOPS;
while (loops != 0) {
udelay(10);
frame_val = tr32(MAC_MI_COM);
ret = -EBUSY;
if (loops != 0) {
*val = frame_val & MI_COM_DATA_MASK;
ret = 0;
}
return ret;
}
tw32_f(MAC_MI_COM, frame_val);
72
Wave OS project early developer manual
loops = PHY_BUSY_LOOPS;
while (loops != 0) {
udelay(10);
frame_val = tr32(MAC_MI_COM);
if ((frame_val & MI_COM_BUSY) == 0) {
udelay(5);
frame_val = tr32(MAC_MI_COM);
break;
}
loops -= 1;
}
ret = -EBUSY;
if (loops != 0)
ret = 0;
return ret;
}
limit = 5000;
while (limit--) {
Wave OS project early developer manual
return 0;
}
while (limit--) {
u32 tmp32;
return 0;
}
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
74
Wave OS project early developer manual
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
(chan * 0x2000) | 0x0200);
tg3_writephy(tp, 0x16, 0x0082);
if (tg3_wait_macro_done(tp)) {
*resetp = 1;
return -EBUSY;
}
for (i = 0; i < 6; i += 2) {
u32 low, high;
return -EBUSY;
}
}
}
return 0;
}
{
int chan;
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
(chan * 0x2000) | 0x0200);
tg3_writephy(tp, 0x16, 0x0002);
for (i = 0; i < 6; i++)
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
tg3_writephy(tp, 0x16, 0x0202);
if (tg3_wait_macro_done(tp))
return -EBUSY;
}
return 0;
}
retries = 10;
do_phy_reset = 1;
do {
if (do_phy_reset) {
err = tg3_bmcr_reset(tp);
if (err)
return err;
do_phy_reset = 0;
}
reg32 |= 0x3000;
tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
tg3_writephy(tp, MII_TG3_CTRL,
(MII_TG3_CTRL_AS_MASTER |
MII_TG3_CTRL_ENABLE_AS_MASTER));
76
Wave OS project early developer manual
err = tg3_phy_reset_chanpat(tp);
if (err)
return err;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
/* Set Extended packet length bit for jumbo frames */
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4400);
}
else {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
return err;
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
err = tg3_phy_reset_5703_4_5(tp);
if (err)
return err;
goto out;
}
err = tg3_bmcr_reset(tp);
if (err)
return err;
out:
if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0323);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
if (tp->tg3_flags2 & TG3_FLG2_PHY_5704_A0_BUG) {
tg3_writephy(tp, 0x1c, 0x8d68);
tg3_writephy(tp, 0x1c, 0x8d68);
}
if (tp->tg3_flags2 & TG3_FLG2_PHY_BER_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x310b);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x9506);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x401f);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x14e2);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
78
Wave OS project early developer manual
/* Set Extended packet length bit (bit 14) on all chips that */
/* support jumbo frames */
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
/* Cannot do read-modify-write on 5401 */
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
} else if (tp->tg3_flags2 & TG3_FLG2_JUMBO_CAPABLE) {
u32 phy_reg;
tg3_phy_set_wirespeed(tp);
return 0;
}
remote_adv |= LPA_PAUSE_ASYM;
}
if (old_rx_mode != tp->rx_mode) {
tw32_f(MAC_RX_MODE, tp->rx_mode);
}
if (old_tx_mode != tp->tx_mode) {
tw32_f(MAC_TX_MODE, tp->tx_mode);
}
}
80
Wave OS project early developer manual
case MII_TG3_AUX_STAT_10FULL:
*speed = SPEED_10;
*duplex = DUPLEX_FULL;
break;
case MII_TG3_AUX_STAT_100HALF:
*speed = SPEED_100;
*duplex = DUPLEX_HALF;
break;
case MII_TG3_AUX_STAT_100FULL:
*speed = SPEED_100;
*duplex = DUPLEX_FULL;
break;
case MII_TG3_AUX_STAT_1000HALF:
*speed = SPEED_1000;
*duplex = DUPLEX_HALF;
break;
case MII_TG3_AUX_STAT_1000FULL:
*speed = SPEED_1000;
*duplex = DUPLEX_FULL;
break;
default:
*speed = SPEED_INVALID;
*duplex = DUPLEX_INVALID;
break;
};
}
if (tp->link_config.phy_is_low_power) {
/* Entering low power mode. Disable gigabit and
* 100baseT advertisements.
*/
tg3_writephy(tp, MII_TG3_CTRL, 0);
if (tp->link_config.advertising &
(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
new_adv = 0;
if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
(tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0))
new_adv |= (MII_TG3_CTRL_AS_MASTER |
MII_TG3_CTRL_ENABLE_AS_MASTER);
tg3_writephy(tp, MII_TG3_CTRL, new_adv);
} else {
tg3_writephy(tp, MII_TG3_CTRL, 0);
}
} else {
/* Asking for a specific link mode. */
if (tp->link_config.speed == SPEED_1000) {
new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
tg3_writephy(tp, MII_ADVERTISE, new_adv);
if (tp->link_config.duplex == DUPLEX_FULL)
new_adv = MII_TG3_CTRL_ADV_1000_FULL;
else
new_adv = MII_TG3_CTRL_ADV_1000_HALF;
if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
82
Wave OS project early developer manual
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
new_adv |= (MII_TG3_CTRL_AS_MASTER |
MII_TG3_CTRL_ENABLE_AS_MASTER);
tg3_writephy(tp, MII_TG3_CTRL, new_adv);
} else {
tg3_writephy(tp, MII_TG3_CTRL, 0);
tp->link_config.active_speed = tp->link_config.speed;
tp->link_config.active_duplex = tp->link_config.duplex;
bmcr = 0;
switch (tp->link_config.speed) {
default:
case SPEED_10:
break;
case SPEED_100:
bmcr |= BMCR_SPEED100;
break;
case SPEED_1000:
bmcr |= TG3_BMCR_SPEED1000;
break;
};
if (tp->link_config.duplex == DUPLEX_FULL)
bmcr |= BMCR_FULLDPLX;
udelay(10);
if (tg3_readphy(tp, MII_BMSR, &tmp) ||
tg3_readphy(tp, MII_BMSR, &tmp))
continue;
if (!(tmp & BMSR_LSTATUS)) {
udelay(40);
break;
}
}
tg3_writephy(tp, MII_BMCR, bmcr);
udelay(40);
}
} else {
tg3_writephy(tp, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART);
}
}
udelay(40);
return err;
}
84
Wave OS project early developer manual
return 0;
all_mask = (MII_TG3_CTRL_ADV_1000_HALF |
MII_TG3_CTRL_ADV_1000_FULL);
if ((tg3_ctrl & all_mask) != all_mask)
return 0;
}
return 1;
}
tw32(MAC_EVENT, 0);
tw32_f(MAC_STATUS,
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED |
MAC_STATUS_MI_COMPLETION |
MAC_STATUS_LNKSTATE_CHANGED));
udelay(40);
tp->mi_mode = MAC_MI_MODE_BASE;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
force_reset = 1;
}
if (force_reset)
tg3_phy_reset(tp);
86
Wave OS project early developer manual
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
if (tp->led_ctrl == LED_CTRL_MODE_PHY_1)
tg3_writephy(tp, MII_TG3_EXT_CTRL,
MII_TG3_EXT_CTRL_LNK3_LED_MODE);
else
tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
}
current_link_up = 0;
current_speed = SPEED_INVALID;
current_duplex = DUPLEX_INVALID;
bmsr = 0;
for (i = 0; i < 100; i++) {
tg3_readphy(tp, MII_BMSR, &bmsr);
if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
(bmsr & BMSR_LSTATUS))
break;
udelay(40);
}
tg3_aux_stat_to_speed_duplex(tp, aux_stat,
¤t_speed,
¤t_duplex);
bmcr = 0;
for (i = 0; i < 200; i++) {
Wave OS project early developer manual
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
if (bmcr & BMCR_ANENABLE) {
current_link_up = 1;
tp->link_config.active_speed = current_speed;
tp->link_config.active_duplex = current_duplex;
}
if (current_link_up == 1 &&
(tp->link_config.active_duplex == DUPLEX_FULL) &&
(tp->link_config.autoneg == AUTONEG_ENABLE)) {
u32 local_adv, remote_adv;
88
Wave OS project early developer manual
current_link_up = 0;
} else {
tg3_setup_flow_control(tp, local_adv, remote_adv);
}
}
relink:
if (current_link_up == 0 || tp->link_config.phy_is_low_power) {
u32 tmp;
tg3_phy_copper_begin(tp);
tw32_f(MAC_MODE, tp->mac_mode);
Wave OS project early developer manual
udelay(40);
if (current_link_up != netif_carrier_ok(tp->dev)) {
if (current_link_up)
netif_carrier_on(tp->dev);
else
netif_carrier_off(tp->dev);
tg3_link_report(tp);
}
return 0;
}
struct tg3_fiber_aneginfo {
int state;
#define ANEG_STATE_UNKNOWN 0
#define ANEG_STATE_AN_ENABLE 1
#define ANEG_STATE_RESTART_INIT 2
#define ANEG_STATE_RESTART 3
#define ANEG_STATE_DISABLE_LINK_OK 4
#define ANEG_STATE_ABILITY_DETECT_INIT 5
#define ANEG_STATE_ABILITY_DETECT 6
#define ANEG_STATE_ACK_DETECT_INIT 7
#define ANEG_STATE_ACK_DETECT 8
#define ANEG_STATE_COMPLETE_ACK_INIT 9
#define ANEG_STATE_COMPLETE_ACK 10
#define ANEG_STATE_IDLE_DETECT_INIT 11
#define ANEG_STATE_IDLE_DETECT 12
#define ANEG_STATE_LINK_OK 13
90
Wave OS project early developer manual
#define ANEG_STATE_NEXT_PAGE_WAIT_INIT 14
#define ANEG_STATE_NEXT_PAGE_WAIT 15
u32 flags;
#define MR_AN_ENABLE 0x00000001
#define MR_RESTART_AN 0x00000002
#define MR_AN_COMPLETE 0x00000004
#define MR_PAGE_RX 0x00000008
#define MR_NP_LOADED 0x00000010
#define MR_TOGGLE_TX 0x00000020
#define MR_LP_ADV_FULL_DUPLEX 0x00000040
#define MR_LP_ADV_HALF_DUPLEX 0x00000080
#define MR_LP_ADV_SYM_PAUSE 0x00000100
#define MR_LP_ADV_ASYM_PAUSE 0x00000200
#define MR_LP_ADV_REMOTE_FAULT1 0x00000400
#define MR_LP_ADV_REMOTE_FAULT2 0x00000800
#define MR_LP_ADV_NEXT_PAGE 0x00001000
#define MR_TOGGLE_RX 0x00002000
#define MR_NP_RX 0x00004000
u32 ability_match_cfg;
int ability_match_count;
};
#define ANEG_OK 0
#define ANEG_DONE 1
#define ANEG_TIMER_ENAB 2
#define ANEG_FAILED -1
int ret;
if (ap->state == ANEG_STATE_UNKNOWN) {
ap->rxconfig = 0;
ap->link_time = 0;
ap->cur_time = 0;
ap->ability_match_cfg = 0;
ap->ability_match_count = 0;
ap->ability_match = 0;
ap->idle_match = 0;
ap->ack_match = 0;
}
ap->cur_time++;
if (rx_cfg_reg != ap->ability_match_cfg) {
ap->ability_match_cfg = rx_cfg_reg;
ap->ability_match = 0;
ap->ability_match_count = 0;
} else {
if (++ap->ability_match_count > 1) {
ap->ability_match = 1;
ap->ability_match_cfg = rx_cfg_reg;
}
}
if (rx_cfg_reg & ANEG_CFG_ACK)
ap->ack_match = 1;
else
ap->ack_match = 0;
ap->idle_match = 0;
} else {
ap->idle_match = 1;
ap->ability_match_cfg = 0;
ap->ability_match_count = 0;
ap->ability_match = 0;
ap->ack_match = 0;
rx_cfg_reg = 0;
}
ap->rxconfig = rx_cfg_reg;
ret = ANEG_OK;
switch(ap->state) {
case ANEG_STATE_UNKNOWN:
if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
ap->state = ANEG_STATE_AN_ENABLE;
/* fallthru */
92
Wave OS project early developer manual
case ANEG_STATE_AN_ENABLE:
ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
if (ap->flags & MR_AN_ENABLE) {
ap->link_time = 0;
ap->cur_time = 0;
ap->ability_match_cfg = 0;
ap->ability_match_count = 0;
ap->ability_match = 0;
ap->idle_match = 0;
ap->ack_match = 0;
ap->state = ANEG_STATE_RESTART_INIT;
} else {
ap->state = ANEG_STATE_DISABLE_LINK_OK;
}
break;
case ANEG_STATE_RESTART_INIT:
ap->link_time = ap->cur_time;
ap->flags &= ~(MR_NP_LOADED);
ap->txconfig = 0;
tw32(MAC_TX_AUTO_NEG, 0);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
ret = ANEG_TIMER_ENAB;
ap->state = ANEG_STATE_RESTART;
/* fallthru */
case ANEG_STATE_RESTART:
delta = ap->cur_time - ap->link_time;
if (delta > ANEG_STATE_SETTLE_TIME) {
ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
} else {
ret = ANEG_TIMER_ENAB;
}
break;
case ANEG_STATE_DISABLE_LINK_OK:
ret = ANEG_DONE;
break;
case ANEG_STATE_ABILITY_DETECT_INIT:
ap->flags &= ~(MR_TOGGLE_TX);
ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
tw32(MAC_TX_AUTO_NEG, ap->txconfig);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
ap->state = ANEG_STATE_ABILITY_DETECT;
break;
Wave OS project early developer manual
case ANEG_STATE_ABILITY_DETECT:
if (ap->ability_match != 0 && ap->rxconfig != 0) {
ap->state = ANEG_STATE_ACK_DETECT_INIT;
}
break;
case ANEG_STATE_ACK_DETECT_INIT:
ap->txconfig |= ANEG_CFG_ACK;
tw32(MAC_TX_AUTO_NEG, ap->txconfig);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
ap->state = ANEG_STATE_ACK_DETECT;
/* fallthru */
case ANEG_STATE_ACK_DETECT:
if (ap->ack_match != 0) {
if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
(ap->ability_match_cfg & ~ANEG_CFG_ACK)) {
ap->state = ANEG_STATE_COMPLETE_ACK_INIT;
} else {
ap->state = ANEG_STATE_AN_ENABLE;
}
} else if (ap->ability_match != 0 &&
ap->rxconfig == 0) {
ap->state = ANEG_STATE_AN_ENABLE;
}
break;
case ANEG_STATE_COMPLETE_ACK_INIT:
if (ap->rxconfig & ANEG_CFG_INVAL) {
ret = ANEG_FAILED;
break;
}
ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX |
MR_LP_ADV_HALF_DUPLEX |
MR_LP_ADV_SYM_PAUSE |
MR_LP_ADV_ASYM_PAUSE |
MR_LP_ADV_REMOTE_FAULT1 |
MR_LP_ADV_REMOTE_FAULT2 |
MR_LP_ADV_NEXT_PAGE |
MR_TOGGLE_RX |
MR_NP_RX);
if (ap->rxconfig & ANEG_CFG_FD)
ap->flags |= MR_LP_ADV_FULL_DUPLEX;
if (ap->rxconfig & ANEG_CFG_HD)
ap->flags |= MR_LP_ADV_HALF_DUPLEX;
if (ap->rxconfig & ANEG_CFG_PS1)
ap->flags |= MR_LP_ADV_SYM_PAUSE;
if (ap->rxconfig & ANEG_CFG_PS2)
94
Wave OS project early developer manual
ap->flags |= MR_LP_ADV_ASYM_PAUSE;
if (ap->rxconfig & ANEG_CFG_RF1)
ap->flags |= MR_LP_ADV_REMOTE_FAULT1;
if (ap->rxconfig & ANEG_CFG_RF2)
ap->flags |= MR_LP_ADV_REMOTE_FAULT2;
if (ap->rxconfig & ANEG_CFG_NP)
ap->flags |= MR_LP_ADV_NEXT_PAGE;
ap->link_time = ap->cur_time;
ap->flags ^= (MR_TOGGLE_TX);
if (ap->rxconfig & 0x0008)
ap->flags |= MR_TOGGLE_RX;
if (ap->rxconfig & ANEG_CFG_NP)
ap->flags |= MR_NP_RX;
ap->flags |= MR_PAGE_RX;
ap->state = ANEG_STATE_COMPLETE_ACK;
ret = ANEG_TIMER_ENAB;
break;
case ANEG_STATE_COMPLETE_ACK:
if (ap->ability_match != 0 &&
ap->rxconfig == 0) {
ap->state = ANEG_STATE_AN_ENABLE;
break;
}
delta = ap->cur_time - ap->link_time;
if (delta > ANEG_STATE_SETTLE_TIME) {
if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) {
ap->state = ANEG_STATE_IDLE_DETECT_INIT;
} else {
if ((ap->txconfig & ANEG_CFG_NP) == 0 &&
!(ap->flags & MR_NP_RX)) {
ap->state = ANEG_STATE_IDLE_DETECT_INIT;
} else {
ret = ANEG_FAILED;
}
}
}
break;
case ANEG_STATE_IDLE_DETECT_INIT:
ap->link_time = ap->cur_time;
tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
ap->state = ANEG_STATE_IDLE_DETECT;
ret = ANEG_TIMER_ENAB;
break;
case ANEG_STATE_IDLE_DETECT:
Wave OS project early developer manual
if (ap->ability_match != 0 &&
ap->rxconfig == 0) {
ap->state = ANEG_STATE_AN_ENABLE;
break;
}
delta = ap->cur_time - ap->link_time;
if (delta > ANEG_STATE_SETTLE_TIME) {
/* XXX another gem from the Broadcom driver :( */
ap->state = ANEG_STATE_LINK_OK;
}
break;
case ANEG_STATE_LINK_OK:
ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK);
ret = ANEG_DONE;
break;
case ANEG_STATE_NEXT_PAGE_WAIT_INIT:
/* ??? unimplemented */
break;
case ANEG_STATE_NEXT_PAGE_WAIT:
/* ??? unimplemented */
break;
default:
ret = ANEG_FAILED;
break;
};
return ret;
}
tw32_f(MAC_TX_AUTO_NEG, 0);
memset(&aninfo, 0, sizeof(aninfo));
aninfo.flags |= MR_AN_ENABLE;
96
Wave OS project early developer manual
aninfo.state = ANEG_STATE_UNKNOWN;
aninfo.cur_time = 0;
tick = 0;
while (++tick < 195000) {
status = tg3_fiber_aneg_smachine(tp, &aninfo);
if (status == ANEG_DONE || status == ANEG_FAILED)
break;
udelay(1);
}
*flags = aninfo.flags;
return res;
}
/* SW reset */
tg3_writephy(tp, MII_BMCR, BMCR_RESET);
serdes_cfg = 0;
expected_sg_dig_ctrl = 0;
workaround = 0;
port_a = 1;
current_link_up = 0;
sg_dig_ctrl = tr32(SG_DIG_CTRL);
if (tp->link_config.autoneg != AUTONEG_ENABLE) {
if (sg_dig_ctrl & (1 << 31)) {
if (workaround) {
u32 val = serdes_cfg;
98
Wave OS project early developer manual
if (port_a)
val |= 0xc010000;
else
val |= 0x4010000;
tw32_f(MAC_SERDES_CFG, val);
}
tw32_f(SG_DIG_CTRL, 0x01388400);
}
if (mac_status & MAC_STATUS_PCS_SYNCED) {
tg3_setup_flow_control(tp, 0, 0);
current_link_up = 1;
}
goto out;
}
/* Want auto-negotiation. */
expected_sg_dig_ctrl = 0x81388400;
/* Pause capability */
expected_sg_dig_ctrl |= (1 << 11);
/* Asymettric pause */
expected_sg_dig_ctrl |= (1 << 12);
if (sg_dig_ctrl != expected_sg_dig_ctrl) {
if (workaround)
tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
udelay(5);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
} else if (mac_status & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET)) {
int i;
local_adv = ADVERTISE_PAUSE_CAP;
remote_adv = 0;
if (sg_dig_status & (1 << 19))
Wave OS project early developer manual
remote_adv |= LPA_PAUSE_CAP;
if (sg_dig_status & (1 << 20))
remote_adv |= LPA_PAUSE_ASYM;
if (port_a)
val |= 0xc010000;
else
val |= 0x4010000;
tw32_f(MAC_SERDES_CFG, val);
}
tw32_f(SG_DIG_CTRL, 0x01388400);
udelay(40);
out:
return current_link_up;
}
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
100
Wave OS project early developer manual
u32 flags;
int i;
if (fiber_autoneg(tp, &flags)) {
u32 local_adv, remote_adv;
local_adv = ADVERTISE_PAUSE_CAP;
remote_adv = 0;
if (flags & MR_LP_ADV_SYM_PAUSE)
remote_adv |= LPA_PAUSE_CAP;
if (flags & MR_LP_ADV_ASYM_PAUSE)
remote_adv |= LPA_PAUSE_ASYM;
tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
current_link_up = 1;
}
for (i = 0; i < 30; i++) {
udelay(20);
tw32_f(MAC_STATUS,
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED));
udelay(40);
if ((tr32(MAC_STATUS) &
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED)) == 0)
break;
}
mac_status = tr32(MAC_STATUS);
if (current_link_up == 0 &&
(mac_status & MAC_STATUS_PCS_SYNCED) &&
!(mac_status & MAC_STATUS_RCVD_CFG))
current_link_up = 1;
} else {
/* Forcing 1000FD link up. */
current_link_up = 1;
tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
out:
return current_link_up;
}
u32 mac_status;
int current_link_up;
int i;
orig_pause_cfg =
(tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
TG3_FLAG_TX_PAUSE));
orig_active_speed = tp->link_config.active_speed;
orig_active_duplex = tp->link_config.active_duplex;
tw32_f(MAC_TX_AUTO_NEG, 0);
if (tp->phy_id == PHY_ID_BCM8002)
tg3_init_bcm8002(tp);
current_link_up = 0;
mac_status = tr32(MAC_STATUS);
102
Wave OS project early developer manual
tp->hw_status->status =
(SD_STATUS_UPDATED |
(tp->hw_status->status & ~SD_STATUS_LINK_CHG));
mac_status = tr32(MAC_STATUS);
if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
current_link_up = 0;
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
tw32_f(MAC_MODE, (tp->mac_mode |
MAC_MODE_SEND_CONFIGS));
udelay(1);
tw32_f(MAC_MODE, tp->mac_mode);
}
}
if (current_link_up == 1) {
tp->link_config.active_speed = SPEED_1000;
tp->link_config.active_duplex = DUPLEX_FULL;
tw32(MAC_LED_CTRL, (tp->led_ctrl |
LED_CTRL_LNKLED_OVERRIDE |
LED_CTRL_1000MBPS_ON));
} else {
tp->link_config.active_speed = SPEED_INVALID;
tp->link_config.active_duplex = DUPLEX_INVALID;
tw32(MAC_LED_CTRL, (tp->led_ctrl |
LED_CTRL_LNKLED_OVERRIDE |
LED_CTRL_TRAFFIC_OVERRIDE));
}
if (current_link_up != netif_carrier_ok(tp->dev)) {
if (current_link_up)
netif_carrier_on(tp->dev);
else
netif_carrier_off(tp->dev);
tg3_link_report(tp);
} else {
u32 now_pause_cfg =
tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
TG3_FLAG_TX_PAUSE);
if (orig_pause_cfg != now_pause_cfg ||
orig_active_speed != tp->link_config.active_speed ||
orig_active_duplex != tp->link_config.active_duplex)
tg3_link_report(tp);
}
Wave OS project early developer manual
return 0;
}
tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
tw32(MAC_EVENT, 0);
tw32_f(MAC_STATUS,
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED |
MAC_STATUS_MI_COMPLETION |
MAC_STATUS_LNKSTATE_CHANGED));
udelay(40);
if (force_reset)
tg3_phy_reset(tp);
current_link_up = 0;
current_speed = SPEED_INVALID;
current_duplex = DUPLEX_INVALID;
104
Wave OS project early developer manual
ADVERTISE_SLCT);
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
return err;
}
} else {
u32 new_bmcr;
if (tp->link_config.duplex == DUPLEX_FULL)
new_bmcr |= BMCR_FULLDPLX;
if (new_bmcr != bmcr) {
/* BMCR_SPEED1000 is a reserved bit that needs
* to be set on write.
*/
new_bmcr |= BMCR_SPEED1000;
/* Force a linkdown */
if (netif_carrier_ok(tp->dev)) {
u32 adv;
tg3_setup_flow_control(tp, local_adv,
remote_adv);
}
else
current_link_up = 0;
}
}
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
tp->link_config.active_speed = current_speed;
106
Wave OS project early developer manual
tp->link_config.active_duplex = current_duplex;
if (current_link_up != netif_carrier_ok(tp->dev)) {
if (current_link_up)
netif_carrier_on(tp->dev);
else {
netif_carrier_off(tp->dev);
tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
}
tg3_link_report(tp);
}
return err;
}
}
}
}
/* XXXKV: Because we don't use the coalesce code in this driver we're going
to use 0 for all cases for now */
#if 0
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
if (netif_carrier_ok(tp->dev)) {
tw32(HOSTCC_STAT_COAL_TICKS,
tp->coal.stats_block_coalesce_usecs);
} else {
tw32(HOSTCC_STAT_COAL_TICKS, 0);
108
Wave OS project early developer manual
}
}
#else
tw32(HOSTCC_STAT_COAL_TICKS, 0);
#endif
return err;
}
dev_peer = pci_get_drvdata(tp->pdev_peer);
/* remove_one() may have been run on the peer. */
if (!dev_peer)
tp_peer = tp;
else
tp_peer = netdev_priv(dev_peer);
}
#endif
if (tp_peer != tp &&
(tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0)
return;
if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
ASIC_REV_5714) {
grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
grc_local_ctrl, 100);
}
grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 |
GRC_LCLCTRL_GPIO_OE1 |
GRC_LCLCTRL_GPIO_OE2 |
GRC_LCLCTRL_GPIO_OUTPUT1 |
GRC_LCLCTRL_GPIO_OUTPUT2;
if (no_gpio2) {
grc_local_ctrl &= ~(GRC_LCLCTRL_GPIO_OE2 |
GRC_LCLCTRL_GPIO_OUTPUT2);
}
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
grc_local_ctrl, 100);
grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT0;
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
grc_local_ctrl, 100);
if (!no_gpio2) {
grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT2;
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
grc_local_ctrl, 100);
}
}
} else {
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
if (tp_peer != tp &&
(tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0)
return;
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
(GRC_LCLCTRL_GPIO_OE1 |
GRC_LCLCTRL_GPIO_OUTPUT1), 100);
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
GRC_LCLCTRL_GPIO_OE1, 100);
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
(GRC_LCLCTRL_GPIO_OE1 |
GRC_LCLCTRL_GPIO_OUTPUT1), 100);
}
110
Wave OS project early developer manual
}
}
#define RESET_KIND_SHUTDOWN 0
#define RESET_KIND_INIT 1
#define RESET_KIND_SUSPEND 2
return 0;
case PCI_D1:
power_control |= 1;
break;
case PCI_D2:
power_control |= 2;
break;
case PCI_D3hot:
power_control |= 3;
break;
default:
kerndbg( KERN_WARNING, "%s: Invalid power state (%d) requested.\n",
tp->dev->name, state);
return -EINVAL;
};
power_control |= PCI_PM_CTRL_PME_ENABLE;
misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
tw32(TG3PCI_MISC_HOST_CTRL,
misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
if (tp->link_config.phy_is_low_power == 0) {
tp->link_config.phy_is_low_power = 1;
tp->link_config.orig_speed = tp->link_config.speed;
tp->link_config.orig_duplex = tp->link_config.duplex;
tp->link_config.orig_autoneg = tp->link_config.autoneg;
}
112
Wave OS project early developer manual
if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
break;
udelay(100);
}
}
tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE |
WOL_DRV_STATE_SHUTDOWN |
WOL_DRV_WOL | WOL_SET_MAGIC_PKT);
mac_mode = MAC_MODE_PORT_MODE_MII;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
mac_mode |= MAC_MODE_LINK_POLARITY;
} else {
mac_mode = MAC_MODE_PORT_MODE_TBI;
}
tw32_f(MAC_MODE, mac_mode);
udelay(100);
tw32_f(MAC_RX_MODE, RX_MODE_ENABLE);
udelay(10);
}
base_val = tp->pci_clock_ctrl;
base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
CLOCK_CTRL_TXCLK_DISABLE);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
newbits1 = (CLOCK_CTRL_RXCLK_DISABLE |
CLOCK_CTRL_TXCLK_DISABLE |
CLOCK_CTRL_ALTCLK);
newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
} else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
newbits1 = CLOCK_CTRL_625_CORE;
newbits2 = newbits1 | CLOCK_CTRL_ALTCLK;
} else {
newbits1 = CLOCK_CTRL_ALTCLK;
newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
newbits3 = (CLOCK_CTRL_RXCLK_DISABLE |
CLOCK_CTRL_TXCLK_DISABLE |
CLOCK_CTRL_44MHZ_CORE);
} else {
newbits3 = CLOCK_CTRL_44MHZ_CORE;
}
tw32_wait_f(TG3PCI_CLOCK_CTRL,
tp->pci_clock_ctrl | newbits3, 40);
}
}
114
Wave OS project early developer manual
tg3_frob_aux_power(tp);
err = tg3_nvram_lock(tp);
tg3_halt_cpu(tp, RX_CPU_BASE);
if (!err)
tg3_nvram_unlock(tp);
}
}
tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
return 0;
}
/* Device interface */
static status_t tg3_dev_open( void* pNode, uint32 nFlags, void **pCookie )
{
return 0;
}
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
* support TG3_FLG2_HW_TSO_1 or firmware TSO only.
*/
static int tg3_start_xmit_dma_bug(PacketBuf_s *skb, struct net_device *dev)
{
/* Not yet ported */
return 0;
}
116
Wave OS project early developer manual
default:
break;
};
}
val = tr32(ofs);
val &= ~enable_bit;
tw32_f(ofs, val);
return 0;
}
/* tp->lock is held. */
static int tg3_abort_hw(struct tg3 *tp, int silent)
{
Wave OS project early developer manual
int i, err;
tg3_disable_ints(tp);
tw32(FTQ_RESET, 0xffffffff);
tw32(FTQ_RESET, 0x00000000);
118
Wave OS project early developer manual
if (tp->hw_status)
memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
if (tp->hw_stats)
memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
return err;
}
/* tp->lock is held. */
static int tg3_nvram_lock(struct tg3 *tp)
{
if (tp->tg3_flags & TG3_FLAG_NVRAM) {
int i;
if (tp->nvram_lock_cnt == 0) {
tw32(NVRAM_SWARB, SWARB_REQ_SET1);
for (i = 0; i < 8000; i++) {
if (tr32(NVRAM_SWARB) & SWARB_GNT1)
break;
udelay(20);
}
if (i == 8000) {
tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
return -ENODEV;
}
}
tp->nvram_lock_cnt++;
}
return 0;
}
/* tp->lock is held. */
static void tg3_nvram_unlock(struct tg3 *tp)
{
if (tp->tg3_flags & TG3_FLAG_NVRAM) {
if (tp->nvram_lock_cnt > 0)
tp->nvram_lock_cnt--;
if (tp->nvram_lock_cnt == 0)
tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1);
}
}
/* tp->lock is held. */
static void tg3_enable_nvram_access(struct tg3 *tp)
{
if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
!(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
u32 nvaccess = tr32(NVRAM_ACCESS);
/* tp->lock is held. */
static void tg3_disable_nvram_access(struct tg3 *tp)
{
if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
!(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
u32 nvaccess = tr32(NVRAM_ACCESS);
/* tp->lock is held. */
static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
{
tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
case RESET_KIND_SHUTDOWN:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_UNLOAD);
break;
case RESET_KIND_SUSPEND:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_SUSPEND);
break;
default:
break;
};
}
}
/* tp->lock is held. */
static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
{
if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) {
switch (kind) {
case RESET_KIND_INIT:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_START_DONE);
break;
case RESET_KIND_SHUTDOWN:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
120
Wave OS project early developer manual
DRV_STATE_UNLOAD_DONE);
break;
default:
break;
};
}
}
/* tp->lock is held. */
static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
{
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
switch (kind) {
case RESET_KIND_INIT:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_START);
break;
case RESET_KIND_SHUTDOWN:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_UNLOAD);
break;
case RESET_KIND_SUSPEND:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_SUSPEND);
break;
default:
break;
};
}
}
/* tp->lock is held. */
static int tg3_chip_reset(struct tg3 *tp)
{
u32 val;
void (*write_op)(struct tg3 *, u32, u32);
int i;
tg3_nvram_lock(tp);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
Wave OS project early developer manual
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
tw32(GRC_FASTBOOT_PC, 0);
/*
* We must avoid the readl() that normally takes place.
* It locks machines, causes machine checks, and other
* fun things. So, temporarily disable the 5701
* hardware workaround, while we do the reset.
*/
write_op = tp->write32;
if (write_op == tg3_write_flush_reg32)
tp->write32 = tg3_write32;
/* do the reset */
val = GRC_MISC_CFG_CORECLK_RESET;
122
Wave OS project early developer manual
udelay(120);
}
/* Set PCIE max payload size and clear error status. */
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, 0xd8, 4, 0xf5000);
}
pci_restore_state(tp->pdev);
val = tr32(MEMARB_MODE);
tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
} else
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
tg3_stop_fw(tp);
tw32(0x5000, 0x400);
}
tw32(GRC_MODE, tp->grc_mode);
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
u32 val = tr32(0xc4);
124
Wave OS project early developer manual
udelay(40);
return 0;
}
/* tp->lock is held. */
static void tg3_stop_fw(struct tg3 *tp)
{
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
u32 val;
Wave OS project early developer manual
int i;
/* tp->lock is held. */
static int tg3_halt(struct tg3 *tp, int kind, int silent)
{
int err;
tg3_stop_fw(tp);
tg3_write_sig_pre_reset(tp, kind);
tg3_abort_hw(tp, silent);
err = tg3_chip_reset(tp);
tg3_write_sig_legacy(tp, kind);
tg3_write_sig_post_reset(tp, kind);
if (err)
return err;
return 0;
}
/* tp->lock is held. */
static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
{
int i;
if (offset == RX_CPU_BASE) {
for (i = 0; i < 10000; i++) {
tw32(offset + CPU_STATE, 0xffffffff);
tw32(offset + CPU_MODE, CPU_MODE_HALT);
if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
break;
}
126
Wave OS project early developer manual
if (i >= 10000) {
kerndbg( KERN_WARNING, "tg3_reset_cpu timed out for %s, and %s
CPU\n",
tp->dev->name,
(offset == RX_CPU_BASE ? "RX" : "TX"));
return -ENODEV;
}
tp->nvram_size = EEPROM_CHIP_SIZE;
if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
return;
/*
* Size the chip by reading offsets at increasing powers of two.
* When we encounter our validation signature, we know the addressing
* has wrapped around, and thus have our chip size.
*/
cursize = 0x10;
if (val == magic)
break;
cursize <<= 1;
}
tp->nvram_size = cursize;
}
if (tg3_nvram_read_swab(tp, 0, &val) != 0)
return;
/* Selfboot format */
if (val != TG3_EEPROM_MAGIC) {
tg3_get_eeprom_size(tp);
return;
}
nvcfg1 = tr32(NVRAM_CFG1);
if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
tp->tg3_flags2 |= TG3_FLG2_FLASH;
}
else {
nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
tw32(NVRAM_CFG1, nvcfg1);
}
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
128
Wave OS project early developer manual
break;
case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE;
break;
case FLASH_VENDOR_ATMEL_EEPROM:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
break;
case FLASH_VENDOR_ST:
tp->nvram_jedecnum = JEDEC_ST;
tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
break;
case FLASH_VENDOR_SAIFUN:
tp->nvram_jedecnum = JEDEC_SAIFUN;
tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE;
break;
case FLASH_VENDOR_SST_SMALL:
case FLASH_VENDOR_SST_LARGE:
tp->nvram_jedecnum = JEDEC_SST;
tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE;
break;
}
}
else {
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
}
}
nvcfg1 = tr32(NVRAM_CFG1);
break;
case FLASH_5752VENDOR_ST_M45PE10:
case FLASH_5752VENDOR_ST_M45PE20:
case FLASH_5752VENDOR_ST_M45PE40:
tp->nvram_jedecnum = JEDEC_ST;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
tp->tg3_flags2 |= TG3_FLG2_FLASH;
break;
}
nvcfg1 = tr32(NVRAM_CFG1);
130
Wave OS project early developer manual
case FLASH_5755VENDOR_ATMEL_EEPROM_64KHZ:
case FLASH_5755VENDOR_ATMEL_EEPROM_376KHZ:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
nvcfg1 = tr32(NVRAM_CFG1);
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
tp->tg3_flags2 |= TG3_FLG2_FLASH;
tp->nvram_pagesize = 264;
break;
case FLASH_5752VENDOR_ST_M45PE10:
case FLASH_5752VENDOR_ST_M45PE20:
case FLASH_5752VENDOR_ST_M45PE40:
tp->nvram_jedecnum = JEDEC_ST;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
tp->tg3_flags2 |= TG3_FLG2_FLASH;
tp->nvram_pagesize = 256;
break;
}
}
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
static void tg3_nvram_init(struct tg3 *tp)
{
int j;
tw32_f(GRC_EEPROM_ADDR,
(EEPROM_ADDR_FSM_RESET |
(EEPROM_DEFAULT_CLOCK_PERIOD <<
EEPROM_ADDR_CLKPERD_SHIFT)));
if (tg3_nvram_lock(tp)) {
kerndbg( KERN_WARNING, "%s: Cannot get nvarm lock,
tg3_nvram_init failed.\n", tp->dev->name);
return;
}
tg3_enable_nvram_access(tp);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
tg3_get_5752_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tg3_get_5755_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
tg3_get_5787_nvram_info(tp);
else
132
Wave OS project early developer manual
tg3_get_nvram_info(tp);
tg3_get_nvram_size(tp);
tg3_disable_nvram_access(tp);
tg3_nvram_unlock(tp);
} else {
tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
tg3_get_eeprom_size(tp);
}
}
*val = tr32(GRC_EEPROM_DATA);
return 0;
}
tw32(NVRAM_CMD, nvram_cmd);
for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
udelay(10);
if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
udelay(10);
break;
}
}
if (i == NVRAM_CMD_TIMEOUT) {
return -EBUSY;
}
return 0;
}
return addr;
}
return addr;
}
134
Wave OS project early developer manual
ret = tg3_nvram_lock(tp);
if (ret)
return ret;
tg3_enable_nvram_access(tp);
tw32(NVRAM_ADDR, offset);
ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
if (ret == 0)
*val = swab32(tr32(NVRAM_RDDATA));
tg3_disable_nvram_access(tp);
tg3_nvram_unlock(tp);
return ret;
}
struct subsys_tbl_ent {
u16 subsys_vendor, subsys_devid;
u32 phy_id;
};
/* 3com boards. */
Wave OS project early developer manual
/* DELL boards. */
{ PCI_VENDOR_ID_DELL, 0x00d1, PHY_ID_BCM5401 }, /* VIPER */
{ PCI_VENDOR_ID_DELL, 0x0106, PHY_ID_BCM5401 }, /* JAGUAR */
{ PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
{ PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
/* Compaq boards. */
{ PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
{ PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */
{ PCI_VENDOR_ID_COMPAQ, 0x007d, 0 }, /* CHANGELING */
{ PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */
{ PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }, /* NC7780_2 */
/* IBM boards. */
{ PCI_VENDOR_ID_IBM, 0x0281, 0 } /* IBM??? */
};
136
Wave OS project early developer manual
tp->phy_id = PHY_ID_INVALID;
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
tp->phy_id = eeprom_phy_id;
if (eeprom_phy_serdes) {
if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
tp->tg3_flags2 |= TG3_FLG2_MII_SERDES;
else
tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
}
switch (led_cfg) {
default:
case NIC_SRAM_DATA_CFG_LED_MODE_PHY_1:
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
break;
case NIC_SRAM_DATA_CFG_LED_MODE_PHY_2:
tp->led_ctrl = LED_CTRL_MODE_PHY_2;
break;
case NIC_SRAM_DATA_CFG_LED_MODE_MAC:
tp->led_ctrl = LED_CTRL_MODE_MAC;
break;
case SHASTA_EXT_LED_SHARED:
tp->led_ctrl = LED_CTRL_MODE_SHARED;
if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
tp->pci_chip_rev_id != CHIPREV_ID_5750_A1)
tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
LED_CTRL_MODE_PHY_2);
break;
138
Wave OS project early developer manual
case SHASTA_EXT_LED_MAC:
tp->led_ctrl = LED_CTRL_MODE_SHASTA_MAC;
break;
case SHASTA_EXT_LED_COMBO:
tp->led_ctrl = LED_CTRL_MODE_COMBO;
if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0)
tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
LED_CTRL_MODE_PHY_2);
break;
};
tp->phy_id = p->phy_id;
if (!tp->phy_id ||
tp->phy_id == PHY_ID_BCM8002)
tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
}
}
140
Wave OS project early developer manual
err = tg3_phy_reset(tp);
if (err)
return err;
if (!tg3_copper_is_advertising_all(tp)) {
tg3_writephy(tp, MII_ADVERTISE, adv_reg);
tg3_writephy(tp, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART);
}
tg3_phy_set_wirespeed(tp);
skip_phy_reset:
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
err = tg3_init_5401phy_dsp(tp);
if (err)
return err;
}
return err;
}
if (magic == TG3_EEPROM_MAGIC) {
for (i = 0; i < 256; i += 4) {
u32 tmp;
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice,
tp->pdev->nFunction, vpd_cap + PCI_VPD_ADDR, 2, i);
while (j++ < 100) {
tmp16 = g_psBus->read_pci_config(tp->pdev->nBus, tp->pdev-
>nDevice, tp->pdev->nFunction, vpd_cap + PCI_VPD_ADDR, 4);
if (tmp16 & 0x8000)
break;
udelay(100);
}
if (!(tmp16 & 0x8000))
goto out_not_found;
142
Wave OS project early developer manual
tmp = cpu_to_le32(tmp);
memcpy(&vpd_data[i], &tmp, 4);
}
}
if (val != 0x90)
goto out_not_found;
block_end = (i + 3 +
(vpd_data[i + 1] +
(vpd_data[i + 2] << 8)));
i += 3;
while (i < block_end) {
if (vpd_data[i + 0] == 'P' &&
vpd_data[i + 1] == 'N') {
int partno_len = vpd_data[i + 2];
memcpy(tp->board_part_number,
&vpd_data[i + 3],
partno_len);
/* Success. */
return;
}
}
out_not_found:
strcpy(tp->board_part_number, "none");
}
if (tg3_nvram_read_swab(tp, 0, &val))
return;
if (val != TG3_EEPROM_MAGIC)
return;
if (val != 0)
return;
val = cpu_to_le32(val);
memcpy(tp->fw_ver + i, &val, 4);
}
}
}
144
Wave OS project early developer manual
int err;
u32 vendor;
u32 device;
u32 rev;
} ich_chipsets[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_8,
PCI_ANY_ID },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_8,
PCI_ANY_ID },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_11,
0xa },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_6,
PCI_ANY_ID },
{ },
};
struct tg3_dev_id *pci_id = &ich_chipsets[0];
struct pci_dev *bridge = NULL;
tp->tg3_flags2 |= TG3_FLG2_ICH_WORKAROUND;
pci_dev_put(bridge);
break;
}
}
#endif
}
/* The EPB bridge inside 5714, 5715, and 5780 cannot support
* DMA addresses > 40-bit. This bridge may have other additional
* 57xx devices behind it in some 4-port NIC designs for example.
* Any tg3 device found behind the bridge will also need the 40-bit
* DMA workaround.
146
Wave OS project early developer manual
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
tp->tg3_flags2 |= TG3_FLG2_5780_CLASS;
tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG;
tp->msi_cap = g_psBus->get_pci_capability(tp->pdev->nBus, tp->pdev-
>nDevice, tp->pdev->nFunction, PCI_CAP_ID_MSI);
}
else {
do {
bridge = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_EPB,
bridge);
if (bridge && bridge->subordinate &&
(bridge->subordinate->number <=
tp->pdev->nBus->number) &&
(bridge->subordinate->subordinate >=
tp->pdev->nBus->number)) {
tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG;
pci_dev_put(bridge);
break;
}
} while (bridge);
#endif
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
Wave OS project early developer manual
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) ||
(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
148
Wave OS project early developer manual
tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
150
Wave OS project early developer manual
delete_area(tp->reg_area);
tp->regs = NULL;
if (tp->write32 == tg3_write_indirect_reg32 ||
((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX ||
GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_AX)
tp->tg3_flags2 |= TG3_FLG2_PHY_ADC_BUG;
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
tp->coalesce_mode = 0;
if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
152
Wave OS project early developer manual
udelay(80);
tg3_switch_clocks(tp);
if (chiprevid == CHIPREV_ID_5701_A0 ||
chiprevid == CHIPREV_ID_5701_B0 ||
chiprevid == CHIPREV_ID_5701_B2 ||
chiprevid == CHIPREV_ID_5701_B5) {
void *sram_base;
writel(0x00000000, sram_base);
writel(0x00000000, sram_base + 4);
writel(0xffffffff, sram_base + 4);
if (readl(sram_base) != 0x00000000)
tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
}
}
udelay(50);
tg3_nvram_init(tp);
grc_misc_cfg = tr32(GRC_MISC_CFG);
grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS;
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_MISC_HOST_CTRL,
4, tp->misc_host_ctrl);
}
err = tg3_phy_probe(tp);
if (err) {
kerndbg( KERN_WARNING, "(%s) phy probe failed, err %d\n",
tp->dev->name, err);
/* ... but do not return immediately ... */
}
tg3_read_partno(tp);
tg3_read_fw_ver(tp);
154
Wave OS project early developer manual
tp->rx_offset = 2;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
(tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
tp->rx_offset = 0;
tp->rx_std_max_post = TG3_RX_RING_SIZE;
return err;
}
mac_offset = 0x7c;
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
mac_offset = 0xcc;
if (tg3_nvram_lock(tp))
tw32_f(NVRAM_CMD, NVRAM_CMD_RESET);
else
tg3_nvram_unlock(tp);
}
156
Wave OS project early developer manual
if (!is_valid_ether_addr(&dev->dev_addr[0])) {
return -EINVAL;
}
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
return 0;
}
#define BOUNDARY_SINGLE_CACHELINE 1
#define BOUNDARY_MULTI_CACHELINE 2
goal = 0;
if (!goal)
goto out;
case 256:
val |= (DMA_RWCTRL_READ_BNDRY_256_PCIX |
DMA_RWCTRL_WRITE_BNDRY_256_PCIX);
break;
default:
val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
break;
};
} else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
switch (cacheline_size) {
case 16:
case 32:
case 64:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
val |= DMA_RWCTRL_WRITE_BNDRY_64_PCIE;
break;
}
/* fallthrough */
case 128:
default:
val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
break;
};
} else {
switch (cacheline_size) {
case 16:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val |= (DMA_RWCTRL_READ_BNDRY_16 |
DMA_RWCTRL_WRITE_BNDRY_16);
158
Wave OS project early developer manual
break;
}
/* fallthrough */
case 32:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val |= (DMA_RWCTRL_READ_BNDRY_32 |
DMA_RWCTRL_WRITE_BNDRY_32);
break;
}
/* fallthrough */
case 64:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val |= (DMA_RWCTRL_READ_BNDRY_64 |
DMA_RWCTRL_WRITE_BNDRY_64);
break;
}
/* fallthrough */
case 128:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val |= (DMA_RWCTRL_READ_BNDRY_128 |
DMA_RWCTRL_WRITE_BNDRY_128);
break;
}
/* fallthrough */
case 256:
val |= (DMA_RWCTRL_READ_BNDRY_256 |
DMA_RWCTRL_WRITE_BNDRY_256);
break;
case 512:
val |= (DMA_RWCTRL_READ_BNDRY_512 |
DMA_RWCTRL_WRITE_BNDRY_512);
break;
case 1024:
default:
val |= (DMA_RWCTRL_READ_BNDRY_1024 |
DMA_RWCTRL_WRITE_BNDRY_1024);
break;
};
}
out:
return val;
}
sram_dma_descs = NIC_SRAM_DMA_DESC_POOL_BASE;
Wave OS project early developer manual
tw32(FTQ_RCVBD_COMP_FIFO_ENQDEQ, 0);
tw32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ, 0);
tw32(RDMAC_STATUS, 0);
tw32(WDMAC_STATUS, 0);
tw32(BUFMGR_MODE, 0);
tw32(FTQ_RESET, 0);
/*
* HP ZX1 was seeing test failures for 5701 cards running at 33Mhz
* the *second* time the tg3 driver was getting loaded after an
* initial scan.
*
* Broadcom tells me:
* ...the DMA engine is connected to the GRC block and a DMA
* reset may affect the GRC block in some unpredictable way...
* The behavior of resets to individual blocks has not been tested.
*
* Broadcom noted the GRC reset will also reset all sub-components.
*/
if (to_device) {
test_desc.cqid_sqid = (13 << 8) | 2;
tw32_f(RDMAC_MODE, RDMAC_MODE_ENABLE);
udelay(40);
} else {
test_desc.cqid_sqid = (16 << 8) | 7;
tw32_f(WDMAC_MODE, WDMAC_MODE_ENABLE);
udelay(40);
}
test_desc.flags = 0x00000005;
}
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_MEM_WIN_BASE_ADDR, 4, 0);
160
Wave OS project early developer manual
if (to_device) {
tw32(FTQ_DMA_HIGH_READ_FIFO_ENQDEQ, sram_dma_descs);
} else {
tw32(FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ, sram_dma_descs);
}
ret = -ENODEV;
for (i = 0; i < 40; i++) {
u32 val;
if (to_device)
val = tr32(FTQ_RCVBD_COMP_FIFO_ENQDEQ);
else
val = tr32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ);
if ((val & 0xffff) == sram_dma_descs) {
ret = 0;
break;
}
udelay(100);
}
return ret;
}
} else {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
tp->dma_rwctrl &= 0xfffffff0;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
/* Remove this if it causes problems for some boards. */
tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
162
Wave OS project early developer manual
#if 0
/* Unneeded, already done by tg3_get_invariants. */
tg3_switch_clocks(tp);
#endif
ret = 0;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
goto out;
while (1) {
u32 *p = buf, i;
#if 0
/* validate data reached card RAM correctly. */
for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) {
u32 val;
tg3_read_mem(tp, 0x2100 + (i*4), &val);
if (le32_to_cpu(val) != p[i]) {
printk(KERN_ERR " tg3_test_dma() Card buffer corrupted on
write! (%d != %d)\n", val, i);
/* ret = -ENODEV here? */
}
p[i] = 0;
}
#endif
/* Now read it back. */
ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0);
if (ret) {
kerndbg( KERN_WARNING, "tg3_test_dma() Read the buffer failed
%d\n", ret);
break;
}
Wave OS project early developer manual
/* Verify it. */
for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) {
if (p[i] == i)
continue;
if (i == (TEST_BUFFER_SIZE / sizeof(u32))) {
/* Success. */
ret = 0;
break;
}
}
if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
DMA_RWCTRL_WRITE_BNDRY_16) {
static struct pci_device_id dma_wait_state_chipsets[] = {
{ PCI_VENDOR_ID_APPLE,
PCI_DEVICE_ID_APPLE_UNI_N_PCI15 },
{ },
};
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
}
164
Wave OS project early developer manual
out:
pci_free_consistent(tp->pdev, TEST_BUFFER_SIZE, buf, buf_dma);
out_nofree:
return ret;
}
tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780;
tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780;
tp->bufmgr_config.mbuf_high_water_jumbo =
DEFAULT_MB_HIGH_WATER_JUMBO_5780;
} else {
tp->bufmgr_config.mbuf_read_dma_low_water =
DEFAULT_MB_RDMA_LOW_WATER;
tp->bufmgr_config.mbuf_mac_rx_low_water =
DEFAULT_MB_MACRX_LOW_WATER;
tp->bufmgr_config.mbuf_high_water =
DEFAULT_MB_HIGH_WATER;
tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
DEFAULT_MB_RDMA_LOW_WATER_JUMBO;
tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
DEFAULT_MB_MACRX_LOW_WATER_JUMBO;
Wave OS project early developer manual
tp->bufmgr_config.mbuf_high_water_jumbo =
DEFAULT_MB_HIGH_WATER_JUMBO;
}
tp->bufmgr_config.dma_low_water = DEFAULT_DMA_LOW_WATER;
tp->bufmgr_config.dma_high_water = DEFAULT_DMA_HIGH_WATER;
}
strcpy(str, "PCIX:");
if ((clock_ctrl == 7) ||
((tr32(GRC_MISC_CFG) & GRC_MISC_CFG_BOARD_ID_MASK) ==
GRC_MISC_CFG_BOARD_ID_5704CIOBE))
strcat(str, "133MHz");
else if (clock_ctrl == 0)
strcat(str, "33MHz");
else if (clock_ctrl == 2)
strcat(str, "50MHz");
else if (clock_ctrl == 4)
strcat(str, "66MHz");
else if (clock_ctrl == 6)
strcat(str, "100MHz");
166
Wave OS project early developer manual
} else {
strcpy(str, "PCI:");
if (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED)
strcat(str, "66MHz");
else
strcat(str, "33MHz");
}
if (tp->tg3_flags & TG3_FLAG_PCI_32BIT)
strcat(str, ":32-bit");
else
strcat(str, ":64-bit");
return str;
}
/* Enable device */
uint32 nOldCommand, nNewCommand;
tp = netdev_priv(pNetDev);
tp->pdev = pDev;
tp->dev = pNetDev;
tp->pm_cap = pm_cap;
tp->mac_mode = TG3_DEF_MAC_MODE;
tp->rx_mode = TG3_DEF_RX_MODE;
tp->tx_mode = TG3_DEF_TX_MODE;
tp->mi_mode = MAC_MI_MODE_BASE;
168
Wave OS project early developer manual
tg3_init_link_config(tp);
tp->rx_pending = TG3_DEF_RX_RING_PENDING;
tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
tp->tx_pending = TG3_DEF_TX_RING_PENDING;
nError = tg3_get_invariants(tp);
if( nError )
{
kerndbg(KERN_WARNING, "tg3: Problem fetching invariants of chip,
aborting.\n");
goto err_out_iounmap;
}
tg3_init_bufmgr_config(tp);
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714))
tp->pdev_peer = tg3_find_peer(tp);
nError = tg3_get_device_address(tp);
if( nError )
{
kerndbg( KERN_WARNING, "tg3: Could not obtain valid ethernet
address, aborting.\n");
goto err_out_iounmap;
}
/*
* Reset chip in case UNDI or EFI driver did not shutdown
* DMA self test will enable WDMAC and we'll see (spurious)
* pending DMA on the PCI bus at that point.
*/
if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
pci_save_state(tp->pdev);
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
}
nError = tg3_test_dma(tp);
if( nError )
{
Wave OS project early developer manual
/* Now that we have fully setup the chip, save away a snapshot
* of the PCI config space. We need to restore this after
* GRC_MISC_CFG core clock resets and some resume events.
*/
pci_save_state(tp->pdev);
printk( "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %sBaseT Ethernet
",
pNetDev->name,
tp->board_part_number,
tp->pci_chip_rev_id,
tg3_phy_string(tp),
tg3_bus_string(tp, str),
(tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100" :
"10/100/1000");
netif_carrier_off(tp->dev);
return 0;
err_out_iounmap:
if( tp->reg_area )
delete_area( tp->reg_area );
tp->regs = NULL;
170
Wave OS project early developer manual
err_out:
return nError;
}
if( nCardsFound == 0 )
disable_device( nDeviceID );
/* Driver management */
status_t device_init( int nDeviceID )
{
/* Get PCI bus */
g_psBus = get_busmanager( PCI_BUS_NAME, PCI_BUS_VERSION );
if( g_psBus == NULL )
return -ENODEV;
"this is the finished article . We have ported over 4000 lines of additional code: the
driver is now 5623 lines compared to 1351 before we started. We quite literally now
have half a driver: the complete Linux driver is a total of 11831 lines!
One function worth noting is tg3_setup_phy() , which at first glance looks small, but
in the end it required a whole series of other functions which comprised over a
thousand lines of code. However, it is not quite as bad as it may at first look. Many of
the functions we have ported required no modification at all.
The best way to tackle four thousand lines of code is to copy and paste one or two
functions at a time. Then look for any obvious changes that you will need to make.
Then save your changes and attempt to recompile. You may still have link errors, but
you should fix any compiler errors before moving on to the next couple of functions.
What you want to avoid is to copy and paste a huge block of code, only to have to
then work your way through hundreds of compiler errors!
There are still a handful of functions we have chosen to stub out, and also a few
peices of code that are enclosed in #if blocks. You can find these by searching the
code for XXXKV , which I have used to mark out these temporary changes to make
them easier to find later.
172
Wave OS project early developer manual
It would be tempting at this point to install the driver on a machine and see if the
current code works. However we are still not quite there yet; there are a few
functions we need to revisit.
Up to this point we've simply provided empty macros for pci_save_state() and
pci_restore_state() , which are Linux functions which Syllable does not have an
equivalent of. To implement the functionality correctly, we'll need to make a few small
changes and add an extra parameter to both functions. We can then implement a
simple inline function in linux_compat.h . We've also added a new member to the tg3
structure at line 2109 of the file tg3.h .
We'll also add a simple implementation for device_uninit() which attempts to release
resources and clean up when the driver is unloaded. Our current implementation will
only work for one card, but we can fix that later. For now, it is enough. Many drivers
do not implement anything at all for device_uninit() on the basis that the kernel is
shutting down at the point that the function is called, hence there is no need to worry
about freeing resources. However this may not always work for all hardware,
especially hardware that relies on ACPI or loadable firmware, which may require
being cleanly shut-down by the driver before they will function correctly again after a
warm boot. Be careful with your own drivers.
Testing
We're almost ready to test the code that we have ported so far. We'll ensure that all
debugging messages are enabled first, by adding:
At the top of the tg3.c file, just below the #include directives. This will ensure that
every kerndbg() macro will print it's output, which will be useful as we test the driver.
We'll also need a machine to test the driver with. Obviously, it will have to have
access to a device for our driver. It is also a good idea to have two seperate
installations of Syllable on different partitions. You can install your new driver into
one of them. If it crashes, you can boot from the second installation and delete or
change the driver on the first, and then try again. If you only have one installation
and your driver means the system is unable to boot, you'll be stuck. You may also
want to invest in a "null modem" cable, which will allow you to connect a second
computer to your test machine and capture the kernel log.
We'll fix the poorly formatted debug output. But the output shows that the driver was
loaded by the kernel, device_init() was called which detected the hardware (a
BCM5705) and then successfully configured the hardware before creating the device
node /dev/net/eth/tg3-0
This is fortunate for us, but things are not always this simple. If your driver crashes
when you first test it, you will need to inspect the debug messages and stack trace
from the kernel log to try and find the point at which the driver crashes. You may
need to insert additional debugging output into the driver to do this. Like all
Wave OS project early developer manual
debugging, there is no easy way to go about it. If you're stuck, sending the relevant
section of your kernel log and perhaps also a copy of the source code for your driver
to the syllable-kernel or syllable-developer mailing lists may help you find someone
who can help you debug the problem.
Next
By the end of chapter three we had stubbed out five functions which are called by
tg3_init_one() . They are:
static int tg3_halt(struct tg3 *tp, int kind, int silent); static int tg3_get_invariants(struct
tg3 *tp); static int tg3_get_device_address(struct tg3 *tp); static int
tg3_test_dma(struct tg3 *tp); static PCI_Info_s * tg3_find_peer(struct tg3 *tp);
We skipped them either because they were very large, or because they in turn called
another series of functions. Now we'll have to start porting the code for these
functions. We'll start with the tg3_halt() function. It calls a series of other functions,
namely:
There's nothing for it: we'll also have to port each of these functions, too.
Luckily for us, most of these functions are actually fairly simple. They mostly modify
structures we already have, or use functions we have already ported, or rely on
Linux functions which are provided by linux_compat.h In fact, we can pretty much
copy and paste the entire functions into our driver without having to modify anything
other than to change the printk() functions into kerndbg() macros. The only function
that requires much attention is tg3_chip_reset(), where we'll change the Linux style
PCI functions to Syllable style calls to the bus manager.
Once we've completed the six functions called by tg3_halt() , we need to know if
there are any other functions that are called but are not yet ported. That's easy to
work out: we'll try to build the driver and see if it fails:
So we can see that we'll also need to port the following functions:
174
Wave OS project early developer manual
The first two are simple enough. Again, we'll just change the Linux style PCI
functions to Syllable code. Both tg3_disable_ints() and tg3_nvram_lock() are also
very simple and require no changes. While we're here, we'll also go ahead and port
tg3_nvram_unlock() because it's small and we can be fairly certain that we're going
to need it at some point, so we may as well do it now.
That should be enough to satisfy the linker, so lets try compiling the driver again:
There are still four more stub functions which we must implement. They can be
ported in the same manner as tg3_halt() , by porting the function and then porting
any functions which is relies upon. There are no shortcuts here, just lots of cutting,
pasting and porting! Still, as long as we stick to one of the stub functions at a time we
shouldn't end up bogged down in the code.
It takes around four hours before we have ported enough code that the driver
compiles and links again. To get an idea of how much work we have done,
HYPERLINK
"http://development.syllable.org/documentation/drivers/network/examples/part-2/tg3-
2.c"this is the finished article . We have ported over 4000 lines of additional code: the
driver is now 5623 lines compared to 1351 before we started. We quite literally now
have half a driver: the complete Linux driver is a total of 11831 lines!
One function worth noting is tg3_setup_phy() , which at first glance looks small, but
in the end it required a whole series of other functions which comprised over a
thousand lines of code. However, it is not quite as bad as it may at first look. Many of
the functions we have ported required no modification at all.
The best way to tackle four thousand lines of code is to copy and paste one or two
functions at a time. Then look for any obvious changes that you will need to make.
Then save your changes and attempt to recompile. You may still have link errors, but
you should fix any compiler errors before moving on to the next couple of functions.
What you want to avoid is to copy and paste a huge block of code, only to have to
then work your way through hundreds of compiler errors!
There are still a handful of functions we have chosen to stub out, and also a few
peices of code that are enclosed in #if blocks. You can find these by searching the
code for XXXKV , which I have used to mark out these temporary changes to make
them easier to find later.
It would be tempting at this point to install the driver on a machine and see if the
current code works. However we are still not quite there yet; there are a few
functions we need to revisit.
Up to this point we've simply provided empty macros for pci_save_state() and
pci_restore_state() , which are Linux functions which Syllable does not have an
equivalent of. To implement the functionality correctly, we'll need to make a few small
changes and add an extra parameter to both functions. We can then implement a
Wave OS project early developer manual
simple inline function in linux_compat.h . We've also added a new member to the tg3
structure at line 2109 of the file tg3.h .
We'll also add a simple implementation for device_uninit() which attempts to release
resources and clean up when the driver is unloaded. Our current implementation will
only work for one card, but we can fix that later. For now, it is enough. Many drivers
do not implement anything at all for device_uninit() on the basis that the kernel is
shutting down at the point that the function is called, hence there is no need to worry
about freeing resources. However this may not always work for all hardware,
especially hardware that relies on ACPI or loadable firmware, which may require
being cleanly shut-down by the driver before they will function correctly again after a
warm boot. Be careful with your own drivers.
Testing
We're almost ready to test the code that we have ported so far. We'll ensure that all
debugging messages are enabled first, by adding:
At the top of the tg3.c file, just below the #include directives. This will ensure that
every kerndbg() macro will print it's output, which will be useful as we test the driver.
We'll also need a machine to test the driver with. Obviously, it will have to have
access to a device for our driver. It is also a good idea to have two seperate
installations of Syllable on different partitions. You can install your new driver into
one of them. If it crashes, you can boot from the second installation and delete or
change the driver on the first, and then try again. If you only have one installation
and your driver means the system is unable to boot, you'll be stuck. You may also
want to invest in a "null modem" cable, which will allow you to connect a second
computer to your test machine and capture the kernel log.
We'll fix the poorly formatted debug output. But the output shows that the driver was
loaded by the kernel, device_init() was called which detected the hardware (a
BCM5705) and then successfully configured the hardware before creating the device
node /dev/net/eth/tg3-0
This is fortunate for us, but things are not always this simple. If your driver crashes
when you first test it, you will need to inspect the debug messages and stack trace
from the kernel log to try and find the point at which the driver crashes. You may
need to insert additional debugging output into the driver to do this. Like all
debugging, there is no easy way to go about it. If you're stuck, sending the relevant
section of your kernel log and perhaps also a copy of the source code for your driver
to the syllable-kernel or syllable-developer mailing lists may help you find someone
who can help you debug the problem.
176
Wave OS project early developer manual
Next
HYPERLINK "http://development.syllable.org/documentation/drivers/network/part-
3.html"Part 3: We'll continue to add functionality to the driver.
Syllable
HYPERLINK
"http://development.syllable.org/documentation/drivers/index.html"Device drivers -
Contents
HYPERLINK "http://development.syllable.org/documentation/drivers/network/part-
1.html"Part 1 - Porting a real driver
HYPERLINK "http://development.syllable.org/documentation/drivers/network/part-
2.html"Part 2 - Bringing it up
HYPERLINK "http://development.syllable.org/documentation/drivers/network/part-
3.html"Part 3 - Data in, data out
HYPERLINK "http://development.syllable.org/documentation/drivers/network/part-
4.html"Part 4 - Testing and debugging
HYPERLINK "http://development.syllable.org/documentation/drivers/network/part-
5.html"Part 5 - Cleaning up
Device API
Our driver can be loaded by the kernel and successfully initialises the hardware. The
logical next step is to add functionality to the device API in the tg3_dev_open() ,
tg3_dev_close() , tg3_dev_ioctl() and tg3_dev_write() functions. They are quite
simple functions but will lead us onto porting the rest of the driver, including the
interrupt handling code and the transmit and receive code.
The implementation of these functions is almost identical across all of the ethernet
drivers. tg3_dev_write() for example, looks like this:
static int tg3_dev_write( void* pNode, void* pCookie, off_t nPosition, const void*
pBuffer, size_t nSize ) { struct net_device* psNetDev = pNode; PacketBuf_s*
psBuffer = alloc_pkt_buffer( nSize ); if ( psBuffer != NULL ) { memcpy( psBuffer-
>pb_pData, pBuffer, nSize ); psBuffer->pb_nSize = nSize; tg3_start_xmit( psBuffer,
psNetDev ); } return nSize; }
All it does is to copy the raw data from the pBuffer argument into a new PacketBuf_s
structure and call tg3_start_xmit() , which is currently a stub function. tg3_dev_ioctl()
is similarly just as simple, requiring code for just four ioctl commands. It calls two
Wave OS project early developer manual
new functions, tg3_open() and tg3_close() . Do not confuse these with the existing
tg3_dev_open() and tg3_dev_close() functions. We will cover tg3_open() and
tg3_close() later.
One thing to note is the use of the pNode argument in both tg3_dev_ioctl() and
tg3_dev_write() . Both functions have:
at the top of the function. The pNode argument is passed to the driver by the kernel,
and comes from the pData argument we gave the kernel when we called
create_device_node():
The last two functions, tg3_dev_open() and tg3_dev_close() are the simplest of the
four: they don't have to do anything at all! As long as they return successfully,
nothing else has to happen. The real work is done when tg3_open() or tg3_close()
are called in response to the appropriate ioctl commands in tg3_dev_ioctl() .
You can see what the driver looks like now, with stubs for the three functions
tg3_start_xmit() , tg3_open() and tg3_close()
http://development.syllable.org/documentation/drivers/network/examples/part-3/tg3-
1.c here .
Nothing much can happen until the device has been successfully opened, so we'll
start with that.
One section of code that deserves a special mention is the timer code. The Linux
code is:
In Syllable, timers are managed differently so we have changed those four lines to:
The effect is identical: a timer will call the function tg3_timer() after the timer period
expires. We'll provide a stub for tg3_timer() for now.
With a few more tweaks, the driver compiles but we now have a whole new list of
functions that need to be ported:
178
Wave OS project early developer manual
We also still have tg3_timer() , tg3_close() and tg3_xmit() . We'll go ahead and port
the seven in our list above first, though.
NAPI
One place where we run into differences between Syllable and Linux is the use of
the Linux NAPI functions such as netif_rx_schedule() . NAPI is quite different to how
Syllable works, so we will need to change calls to these functions to act in a more
compatible way.
With NAPI the driver calls netif_rx_schedule() to tell the kernel that work is required
and the kernel then calls a poll() function in the driver when it is ready. We can not
easily emulate this scheme in Syllable, so we will have to change it.
If you want more information, the Linux NAPI documentation describes how
netif_rx_schedule() works. For Syllable, we will make the following changes:
We will copy the poll() callback function (In our case, tg3_poll() ) but remove the
budget argument.
Our changes may require some further tweaking when we come to test the driver,
but for now these simple changes should be sufficient.
Once we have all of the functions ported the driver compiles again. We've still got
some code enclosed in #if blocks and some stubs (the timer handling code and the
Rx and Tx functions), but we now have code to open the device and initialise the
hardware and ring buffers, code to handle interrupts and code to close the device
and return it to a sensible state.
We've added just over 2000 lines of code to the driver. You can see how the driver
looks..
Wave OS project early developer manual
/*
* tg3.c: Broadcom Tigon3 ethernet driver.
*
* Copyright (C) 2006 Kristian Van Der Vliet (vanders@liqwyd.com)
* Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
* Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
* Copyright (C) 2004 Sun Microsystems Inc.
* Copyright (C) 2005 Broadcom Corporation.
*
* Firmware is:
* Derived from proprietary unpublished source code,
* Copyright (C) 2000-2003 Broadcom Corporation.
*
* Permission is hereby granted for the distribution of this firmware
* data in hexadecimal or equivalent format, provided this copyright
* notice is accompanying it.
*/
#include <atheos/kernel.h>
#include <atheos/kdebug.h>
#include <atheos/types.h>
#include <atheos/device.h>
#include <atheos/pci.h>
#include <atheos/spinlock.h>
#include <atheos/udelay.h>
#include <atheos/bitops.h>
#include <atheos/seqlock.h>
#include <posix/errno.h>
#include <posix/signal.h>
#include <net/net_device.h>
#include <net/mii.h>
#include <net/sockios.h>
#define NO_DEBUG_STUBS 1
#include <atheos/linux_compat.h>
#include <tg3.h>
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
#define TG3_DEF_TX_MODE 0
180
Wave OS project early developer manual
*/
#define TG3_TX_TIMEOUT (5 * HZ)
/* Do not place this n-ring entries value into the tp struct itself,
* we really want to expose these constants to GCC so that modulo et
* al. operations are done with shifts and masks instead of with
* hw multiply/modulo instructions. Another solution would be to
* replace things like '% foo' with '& (foo - 1)'.
*/
#define TG3_RX_RCB_RING_SIZE(tp) \
((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ? 512 : 1024)
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
182
Wave OS project early developer manual
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ 0, }
};
spin_lock_irqsave(&tp->indirect_lock, flags);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_BASE_ADDR, 4, off);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_DATA, 4, val);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
spin_lock_irqsave(&tp->indirect_lock, flags);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_BASE_ADDR, 4, (uint32)off);
val = g_psBus->read_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_REG_DATA, sizeof(val));
spin_unlock_irqrestore(&tp->indirect_lock, flags);
return val;
}
184
Wave OS project early developer manual
>pdev->nFunction, TG3PCI_STD_RING_PROD_IDX +
TG3_64BIT_REG_LOW, 4, val);
return;
}
spin_lock_irqsave(&tp->indirect_lock, flags);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_BASE_ADDR, 4, off + 0x5600);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_DATA, 4, val);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
}
spin_lock_irqsave(&tp->indirect_lock, flags);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_REG_BASE_ADDR, 4, (uint32)off + 0x5600);
val = g_psBus->read_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_REG_DATA, sizeof(val));
spin_unlock_irqrestore(&tp->indirect_lock, flags);
return val;
}
static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
{
tp->write32_mbox(tp, off, val);
if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) &&
!(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
tp->read32_mbox(tp, off);
}
spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_MEM_WIN_BASE_ADDR, 4, off);
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_MEM_WIN_DATA, 4, val);
186
Wave OS project early developer manual
spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_MEM_WIN_BASE_ADDR, 4, off);
*val = g_psBus->read_pci_config(tp->pdev->nBus, tp->pdev->nDevice,
tp->pdev->nFunction, TG3PCI_MEM_WIN_DATA, 4);
tp->irq_sync = 0;
smp_wmb();
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
(tp->last_tag << 24));
if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
(tp->last_tag << 24));
tg3_cond_int(tp);
}
return work_exists;
}
/* tg3_restart_ints
* similar to tg3_enable_ints, but it accurately determines whether there
* is new work pending and can return without flushing the PIO write
* which reenables interrupts
*/
static void tg3_restart_ints(struct tg3 *tp)
{
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
tp->last_tag << 24);
smp_wmb();
188
Wave OS project early developer manual
orig_clock_ctrl = clock_ctrl;
clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN |
CLOCK_CTRL_CLKRUN_OENABLE |
0x1f);
tp->pci_clock_ctrl = clock_ctrl;
u32 frame_val;
unsigned int loops;
int ret;
*val = 0x0;
tw32_f(MAC_MI_COM, frame_val);
loops = PHY_BUSY_LOOPS;
while (loops != 0) {
udelay(10);
frame_val = tr32(MAC_MI_COM);
ret = -EBUSY;
if (loops != 0) {
*val = frame_val & MI_COM_DATA_MASK;
ret = 0;
}
return ret;
}
190
Wave OS project early developer manual
tw32_f(MAC_MI_COM, frame_val);
loops = PHY_BUSY_LOOPS;
while (loops != 0) {
udelay(10);
frame_val = tr32(MAC_MI_COM);
if ((frame_val & MI_COM_BUSY) == 0) {
udelay(5);
frame_val = tr32(MAC_MI_COM);
break;
}
loops -= 1;
}
ret = -EBUSY;
if (loops != 0)
ret = 0;
return ret;
}
limit = 5000;
while (limit--) {
err = tg3_readphy(tp, MII_BMCR, &phy_control);
if (err != 0)
return -EBUSY;
return 0;
}
while (limit--) {
u32 tmp32;
return 0;
}
192
Wave OS project early developer manual
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
(chan * 0x2000) | 0x0200);
tg3_writephy(tp, 0x16, 0x0002);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
(chan * 0x2000) | 0x0200);
tg3_writephy(tp, 0x16, 0x0082);
if (tg3_wait_macro_done(tp)) {
*resetp = 1;
return -EBUSY;
}
for (i = 0; i < 6; i += 2) {
u32 low, high;
if (low != test_pat[chan][i] ||
high != test_pat[chan][i+1]) {
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005);
return -EBUSY;
}
}
}
return 0;
}
tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
(chan * 0x2000) | 0x0200);
tg3_writephy(tp, 0x16, 0x0002);
for (i = 0; i < 6; i++)
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
tg3_writephy(tp, 0x16, 0x0202);
if (tg3_wait_macro_done(tp))
return -EBUSY;
}
return 0;
}
retries = 10;
do_phy_reset = 1;
do {
if (do_phy_reset) {
err = tg3_bmcr_reset(tp);
if (err)
return err;
do_phy_reset = 0;
}
194
Wave OS project early developer manual
reg32 |= 0x3000;
tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
tg3_writephy(tp, MII_TG3_CTRL,
(MII_TG3_CTRL_AS_MASTER |
MII_TG3_CTRL_ENABLE_AS_MASTER));
err = tg3_phy_reset_chanpat(tp);
if (err)
return err;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
/* Set Extended packet length bit for jumbo frames */
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4400);
}
else {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
err = -EBUSY;
return err;
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
err = tg3_phy_reset_5703_4_5(tp);
if (err)
return err;
goto out;
}
err = tg3_bmcr_reset(tp);
if (err)
return err;
out:
if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0323);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
}
if (tp->tg3_flags2 & TG3_FLG2_PHY_5704_A0_BUG) {
tg3_writephy(tp, 0x1c, 0x8d68);
tg3_writephy(tp, 0x1c, 0x8d68);
}
if (tp->tg3_flags2 & TG3_FLG2_PHY_BER_BUG) {
196
Wave OS project early developer manual
tg3_phy_set_wirespeed(tp);
return 0;
}
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) {
struct net_device *dev_peer;
dev_peer = pci_get_drvdata(tp->pdev_peer);
/* remove_one() may have been run on the peer. */
if (!dev_peer)
tp_peer = tp;
else
tp_peer = netdev_priv(dev_peer);
}
#endif
if (tp_peer != tp &&
(tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0)
return;
grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 |
GRC_LCLCTRL_GPIO_OE1 |
GRC_LCLCTRL_GPIO_OE2 |
GRC_LCLCTRL_GPIO_OUTPUT1 |
GRC_LCLCTRL_GPIO_OUTPUT2;
if (no_gpio2) {
198
Wave OS project early developer manual
grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT0;
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
grc_local_ctrl, 100);
if (!no_gpio2) {
grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT2;
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
grc_local_ctrl, 100);
}
}
} else {
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
if (tp_peer != tp &&
(tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0)
return;
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
(GRC_LCLCTRL_GPIO_OE1 |
GRC_LCLCTRL_GPIO_OUTPUT1), 100);
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
GRC_LCLCTRL_GPIO_OE1, 100);
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
(GRC_LCLCTRL_GPIO_OE1 |
GRC_LCLCTRL_GPIO_OUTPUT1), 100);
}
}
}
#define RESET_KIND_SHUTDOWN 0
#define RESET_KIND_INIT 1
#define RESET_KIND_SUSPEND 2
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
return;
tg3_writephy(tp, MII_BMCR, BMCR_PDOWN);
}
return 0;
case PCI_D1:
power_control |= 1;
break;
case PCI_D2:
power_control |= 2;
break;
case PCI_D3hot:
200
Wave OS project early developer manual
power_control |= 3;
break;
default:
kerndbg( KERN_WARNING, "%s: Invalid power state (%d) requested.\n",
tp->dev->name, state);
return -EINVAL;
};
power_control |= PCI_PM_CTRL_PME_ENABLE;
misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
tw32(TG3PCI_MISC_HOST_CTRL,
misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
if (tp->link_config.phy_is_low_power == 0) {
tp->link_config.phy_is_low_power = 1;
tp->link_config.orig_speed = tp->link_config.speed;
tp->link_config.orig_duplex = tp->link_config.duplex;
tp->link_config.orig_autoneg = tp->link_config.autoneg;
}
mac_mode = MAC_MODE_PORT_MODE_MII;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
mac_mode |= MAC_MODE_LINK_POLARITY;
} else {
mac_mode = MAC_MODE_PORT_MODE_TBI;
}
tw32_f(MAC_MODE, mac_mode);
udelay(100);
tw32_f(MAC_RX_MODE, RX_MODE_ENABLE);
udelay(10);
}
base_val = tp->pci_clock_ctrl;
base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
CLOCK_CTRL_TXCLK_DISABLE);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
newbits1 = (CLOCK_CTRL_RXCLK_DISABLE |
CLOCK_CTRL_TXCLK_DISABLE |
CLOCK_CTRL_ALTCLK);
newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
} else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
newbits1 = CLOCK_CTRL_625_CORE;
newbits2 = newbits1 | CLOCK_CTRL_ALTCLK;
} else {
newbits1 = CLOCK_CTRL_ALTCLK;
202
Wave OS project early developer manual
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
newbits3 = (CLOCK_CTRL_RXCLK_DISABLE |
CLOCK_CTRL_TXCLK_DISABLE |
CLOCK_CTRL_44MHZ_CORE);
} else {
newbits3 = CLOCK_CTRL_44MHZ_CORE;
}
tw32_wait_f(TG3PCI_CLOCK_CTRL,
tp->pci_clock_ctrl | newbits3, 40);
}
}
tg3_frob_aux_power(tp);
err = tg3_nvram_lock(tp);
tg3_halt_cpu(tp, RX_CPU_BASE);
if (!err)
tg3_nvram_unlock(tp);
Wave OS project early developer manual
}
}
tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
return 0;
}
204
Wave OS project early developer manual
if (old_rx_mode != tp->rx_mode) {
tw32_f(MAC_RX_MODE, tp->rx_mode);
}
if (old_tx_mode != tp->tx_mode) {
tw32_f(MAC_TX_MODE, tp->tx_mode);
Wave OS project early developer manual
}
}
case MII_TG3_AUX_STAT_10FULL:
*speed = SPEED_10;
*duplex = DUPLEX_FULL;
break;
case MII_TG3_AUX_STAT_100HALF:
*speed = SPEED_100;
*duplex = DUPLEX_HALF;
break;
case MII_TG3_AUX_STAT_100FULL:
*speed = SPEED_100;
*duplex = DUPLEX_FULL;
break;
case MII_TG3_AUX_STAT_1000HALF:
*speed = SPEED_1000;
*duplex = DUPLEX_HALF;
break;
case MII_TG3_AUX_STAT_1000FULL:
*speed = SPEED_1000;
*duplex = DUPLEX_FULL;
break;
default:
*speed = SPEED_INVALID;
*duplex = DUPLEX_INVALID;
break;
};
}
if (tp->link_config.phy_is_low_power) {
/* Entering low power mode. Disable gigabit and
* 100baseT advertisements.
206
Wave OS project early developer manual
*/
tg3_writephy(tp, MII_TG3_CTRL, 0);
if (tp->link_config.advertising &
(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
new_adv = 0;
if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
(tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0))
new_adv |= (MII_TG3_CTRL_AS_MASTER |
MII_TG3_CTRL_ENABLE_AS_MASTER);
tg3_writephy(tp, MII_TG3_CTRL, new_adv);
} else {
tg3_writephy(tp, MII_TG3_CTRL, 0);
}
} else {
/* Asking for a specific link mode. */
if (tp->link_config.speed == SPEED_1000) {
new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
tg3_writephy(tp, MII_ADVERTISE, new_adv);
Wave OS project early developer manual
if (tp->link_config.duplex == DUPLEX_FULL)
new_adv = MII_TG3_CTRL_ADV_1000_FULL;
else
new_adv = MII_TG3_CTRL_ADV_1000_HALF;
if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
new_adv |= (MII_TG3_CTRL_AS_MASTER |
MII_TG3_CTRL_ENABLE_AS_MASTER);
tg3_writephy(tp, MII_TG3_CTRL, new_adv);
} else {
tg3_writephy(tp, MII_TG3_CTRL, 0);
tp->link_config.active_speed = tp->link_config.speed;
tp->link_config.active_duplex = tp->link_config.duplex;
bmcr = 0;
switch (tp->link_config.speed) {
default:
case SPEED_10:
break;
case SPEED_100:
bmcr |= BMCR_SPEED100;
break;
case SPEED_1000:
bmcr |= TG3_BMCR_SPEED1000;
break;
};
if (tp->link_config.duplex == DUPLEX_FULL)
208
Wave OS project early developer manual
bmcr |= BMCR_FULLDPLX;
udelay(10);
if (tg3_readphy(tp, MII_BMSR, &tmp) ||
tg3_readphy(tp, MII_BMSR, &tmp))
continue;
if (!(tmp & BMSR_LSTATUS)) {
udelay(40);
break;
}
}
tg3_writephy(tp, MII_BMCR, bmcr);
udelay(40);
}
} else {
tg3_writephy(tp, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART);
}
}
udelay(40);
return err;
}
Wave OS project early developer manual
all_mask = (MII_TG3_CTRL_ADV_1000_HALF |
MII_TG3_CTRL_ADV_1000_FULL);
if ((tg3_ctrl & all_mask) != all_mask)
return 0;
}
return 1;
}
tw32(MAC_EVENT, 0);
tw32_f(MAC_STATUS,
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED |
MAC_STATUS_MI_COMPLETION |
MAC_STATUS_LNKSTATE_CHANGED));
udelay(40);
tp->mi_mode = MAC_MI_MODE_BASE;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
210
Wave OS project early developer manual
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
netif_carrier_ok(tp->dev)) {
tg3_readphy(tp, MII_BMSR, &bmsr);
if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
!(bmsr & BMSR_LSTATUS))
force_reset = 1;
}
if (force_reset)
tg3_phy_reset(tp);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
if (tp->led_ctrl == LED_CTRL_MODE_PHY_1)
tg3_writephy(tp, MII_TG3_EXT_CTRL,
MII_TG3_EXT_CTRL_LNK3_LED_MODE);
else
tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
}
current_link_up = 0;
current_speed = SPEED_INVALID;
current_duplex = DUPLEX_INVALID;
bmsr = 0;
for (i = 0; i < 100; i++) {
tg3_readphy(tp, MII_BMSR, &bmsr);
if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
(bmsr & BMSR_LSTATUS))
break;
udelay(40);
}
212
Wave OS project early developer manual
tg3_aux_stat_to_speed_duplex(tp, aux_stat,
¤t_speed,
¤t_duplex);
bmcr = 0;
for (i = 0; i < 200; i++) {
tg3_readphy(tp, MII_BMCR, &bmcr);
if (tg3_readphy(tp, MII_BMCR, &bmcr))
continue;
if (bmcr && bmcr != 0x7fff)
break;
udelay(10);
}
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
if (bmcr & BMCR_ANENABLE) {
current_link_up = 1;
tp->link_config.active_speed = current_speed;
tp->link_config.active_duplex = current_duplex;
}
if (current_link_up == 1 &&
(tp->link_config.active_duplex == DUPLEX_FULL) &&
(tp->link_config.autoneg == AUTONEG_ENABLE)) {
u32 local_adv, remote_adv;
tg3_phy_copper_begin(tp);
214
Wave OS project early developer manual
tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
}
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
if (current_link_up != netif_carrier_ok(tp->dev)) {
if (current_link_up)
netif_carrier_on(tp->dev);
else
netif_carrier_off(tp->dev);
tg3_link_report(tp);
}
return 0;
}
struct tg3_fiber_aneginfo {
int state;
#define ANEG_STATE_UNKNOWN 0
#define ANEG_STATE_AN_ENABLE 1
#define ANEG_STATE_RESTART_INIT 2
#define ANEG_STATE_RESTART 3
#define ANEG_STATE_DISABLE_LINK_OK 4
#define ANEG_STATE_ABILITY_DETECT_INIT 5
#define ANEG_STATE_ABILITY_DETECT 6
#define ANEG_STATE_ACK_DETECT_INIT 7
Wave OS project early developer manual
#define ANEG_STATE_ACK_DETECT 8
#define ANEG_STATE_COMPLETE_ACK_INIT 9
#define ANEG_STATE_COMPLETE_ACK 10
#define ANEG_STATE_IDLE_DETECT_INIT 11
#define ANEG_STATE_IDLE_DETECT 12
#define ANEG_STATE_LINK_OK 13
#define ANEG_STATE_NEXT_PAGE_WAIT_INIT 14
#define ANEG_STATE_NEXT_PAGE_WAIT 15
u32 flags;
#define MR_AN_ENABLE 0x00000001
#define MR_RESTART_AN 0x00000002
#define MR_AN_COMPLETE 0x00000004
#define MR_PAGE_RX 0x00000008
#define MR_NP_LOADED 0x00000010
#define MR_TOGGLE_TX 0x00000020
#define MR_LP_ADV_FULL_DUPLEX 0x00000040
#define MR_LP_ADV_HALF_DUPLEX 0x00000080
#define MR_LP_ADV_SYM_PAUSE 0x00000100
#define MR_LP_ADV_ASYM_PAUSE 0x00000200
#define MR_LP_ADV_REMOTE_FAULT1 0x00000400
#define MR_LP_ADV_REMOTE_FAULT2 0x00000800
#define MR_LP_ADV_NEXT_PAGE 0x00001000
#define MR_TOGGLE_RX 0x00002000
#define MR_NP_RX 0x00004000
u32 ability_match_cfg;
int ability_match_count;
};
#define ANEG_OK 0
#define ANEG_DONE 1
#define ANEG_TIMER_ENAB 2
#define ANEG_FAILED -1
216
Wave OS project early developer manual
if (ap->state == ANEG_STATE_UNKNOWN) {
ap->rxconfig = 0;
ap->link_time = 0;
ap->cur_time = 0;
ap->ability_match_cfg = 0;
ap->ability_match_count = 0;
ap->ability_match = 0;
ap->idle_match = 0;
ap->ack_match = 0;
}
ap->cur_time++;
if (rx_cfg_reg != ap->ability_match_cfg) {
ap->ability_match_cfg = rx_cfg_reg;
ap->ability_match = 0;
ap->ability_match_count = 0;
} else {
if (++ap->ability_match_count > 1) {
ap->ability_match = 1;
ap->ability_match_cfg = rx_cfg_reg;
}
}
if (rx_cfg_reg & ANEG_CFG_ACK)
ap->ack_match = 1;
else
ap->ack_match = 0;
ap->idle_match = 0;
} else {
ap->idle_match = 1;
ap->ability_match_cfg = 0;
ap->ability_match_count = 0;
ap->ability_match = 0;
ap->ack_match = 0;
rx_cfg_reg = 0;
}
ap->rxconfig = rx_cfg_reg;
ret = ANEG_OK;
Wave OS project early developer manual
switch(ap->state) {
case ANEG_STATE_UNKNOWN:
if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
ap->state = ANEG_STATE_AN_ENABLE;
/* fallthru */
case ANEG_STATE_AN_ENABLE:
ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
if (ap->flags & MR_AN_ENABLE) {
ap->link_time = 0;
ap->cur_time = 0;
ap->ability_match_cfg = 0;
ap->ability_match_count = 0;
ap->ability_match = 0;
ap->idle_match = 0;
ap->ack_match = 0;
ap->state = ANEG_STATE_RESTART_INIT;
} else {
ap->state = ANEG_STATE_DISABLE_LINK_OK;
}
break;
case ANEG_STATE_RESTART_INIT:
ap->link_time = ap->cur_time;
ap->flags &= ~(MR_NP_LOADED);
ap->txconfig = 0;
tw32(MAC_TX_AUTO_NEG, 0);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
ret = ANEG_TIMER_ENAB;
ap->state = ANEG_STATE_RESTART;
/* fallthru */
case ANEG_STATE_RESTART:
delta = ap->cur_time - ap->link_time;
if (delta > ANEG_STATE_SETTLE_TIME) {
ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
} else {
ret = ANEG_TIMER_ENAB;
}
break;
case ANEG_STATE_DISABLE_LINK_OK:
ret = ANEG_DONE;
break;
case ANEG_STATE_ABILITY_DETECT_INIT:
ap->flags &= ~(MR_TOGGLE_TX);
ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
218
Wave OS project early developer manual
tw32(MAC_TX_AUTO_NEG, ap->txconfig);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
ap->state = ANEG_STATE_ABILITY_DETECT;
break;
case ANEG_STATE_ABILITY_DETECT:
if (ap->ability_match != 0 && ap->rxconfig != 0) {
ap->state = ANEG_STATE_ACK_DETECT_INIT;
}
break;
case ANEG_STATE_ACK_DETECT_INIT:
ap->txconfig |= ANEG_CFG_ACK;
tw32(MAC_TX_AUTO_NEG, ap->txconfig);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
ap->state = ANEG_STATE_ACK_DETECT;
/* fallthru */
case ANEG_STATE_ACK_DETECT:
if (ap->ack_match != 0) {
if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
(ap->ability_match_cfg & ~ANEG_CFG_ACK)) {
ap->state = ANEG_STATE_COMPLETE_ACK_INIT;
} else {
ap->state = ANEG_STATE_AN_ENABLE;
}
} else if (ap->ability_match != 0 &&
ap->rxconfig == 0) {
ap->state = ANEG_STATE_AN_ENABLE;
}
break;
case ANEG_STATE_COMPLETE_ACK_INIT:
if (ap->rxconfig & ANEG_CFG_INVAL) {
ret = ANEG_FAILED;
break;
}
ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX |
MR_LP_ADV_HALF_DUPLEX |
MR_LP_ADV_SYM_PAUSE |
MR_LP_ADV_ASYM_PAUSE |
MR_LP_ADV_REMOTE_FAULT1 |
MR_LP_ADV_REMOTE_FAULT2 |
MR_LP_ADV_NEXT_PAGE |
MR_TOGGLE_RX |
MR_NP_RX);
if (ap->rxconfig & ANEG_CFG_FD)
Wave OS project early developer manual
ap->flags |= MR_LP_ADV_FULL_DUPLEX;
if (ap->rxconfig & ANEG_CFG_HD)
ap->flags |= MR_LP_ADV_HALF_DUPLEX;
if (ap->rxconfig & ANEG_CFG_PS1)
ap->flags |= MR_LP_ADV_SYM_PAUSE;
if (ap->rxconfig & ANEG_CFG_PS2)
ap->flags |= MR_LP_ADV_ASYM_PAUSE;
if (ap->rxconfig & ANEG_CFG_RF1)
ap->flags |= MR_LP_ADV_REMOTE_FAULT1;
if (ap->rxconfig & ANEG_CFG_RF2)
ap->flags |= MR_LP_ADV_REMOTE_FAULT2;
if (ap->rxconfig & ANEG_CFG_NP)
ap->flags |= MR_LP_ADV_NEXT_PAGE;
ap->link_time = ap->cur_time;
ap->flags ^= (MR_TOGGLE_TX);
if (ap->rxconfig & 0x0008)
ap->flags |= MR_TOGGLE_RX;
if (ap->rxconfig & ANEG_CFG_NP)
ap->flags |= MR_NP_RX;
ap->flags |= MR_PAGE_RX;
ap->state = ANEG_STATE_COMPLETE_ACK;
ret = ANEG_TIMER_ENAB;
break;
case ANEG_STATE_COMPLETE_ACK:
if (ap->ability_match != 0 &&
ap->rxconfig == 0) {
ap->state = ANEG_STATE_AN_ENABLE;
break;
}
delta = ap->cur_time - ap->link_time;
if (delta > ANEG_STATE_SETTLE_TIME) {
if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) {
ap->state = ANEG_STATE_IDLE_DETECT_INIT;
} else {
if ((ap->txconfig & ANEG_CFG_NP) == 0 &&
!(ap->flags & MR_NP_RX)) {
ap->state = ANEG_STATE_IDLE_DETECT_INIT;
} else {
ret = ANEG_FAILED;
}
}
}
break;
case ANEG_STATE_IDLE_DETECT_INIT:
ap->link_time = ap->cur_time;
tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
220
Wave OS project early developer manual
udelay(40);
ap->state = ANEG_STATE_IDLE_DETECT;
ret = ANEG_TIMER_ENAB;
break;
case ANEG_STATE_IDLE_DETECT:
if (ap->ability_match != 0 &&
ap->rxconfig == 0) {
ap->state = ANEG_STATE_AN_ENABLE;
break;
}
delta = ap->cur_time - ap->link_time;
if (delta > ANEG_STATE_SETTLE_TIME) {
/* XXX another gem from the Broadcom driver :( */
ap->state = ANEG_STATE_LINK_OK;
}
break;
case ANEG_STATE_LINK_OK:
ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK);
ret = ANEG_DONE;
break;
case ANEG_STATE_NEXT_PAGE_WAIT_INIT:
/* ??? unimplemented */
break;
case ANEG_STATE_NEXT_PAGE_WAIT:
/* ??? unimplemented */
break;
default:
ret = ANEG_FAILED;
break;
};
return ret;
}
tw32_f(MAC_TX_AUTO_NEG, 0);
memset(&aninfo, 0, sizeof(aninfo));
aninfo.flags |= MR_AN_ENABLE;
aninfo.state = ANEG_STATE_UNKNOWN;
aninfo.cur_time = 0;
tick = 0;
while (++tick < 195000) {
status = tg3_fiber_aneg_smachine(tp, &aninfo);
if (status == ANEG_DONE || status == ANEG_FAILED)
break;
udelay(1);
}
*flags = aninfo.flags;
return res;
}
/* SW reset */
tg3_writephy(tp, MII_BMCR, BMCR_RESET);
222
Wave OS project early developer manual
serdes_cfg = 0;
expected_sg_dig_ctrl = 0;
workaround = 0;
port_a = 1;
current_link_up = 0;
sg_dig_ctrl = tr32(SG_DIG_CTRL);
if (tp->link_config.autoneg != AUTONEG_ENABLE) {
if (sg_dig_ctrl & (1 << 31)) {
if (workaround) {
u32 val = serdes_cfg;
if (port_a)
val |= 0xc010000;
else
val |= 0x4010000;
tw32_f(MAC_SERDES_CFG, val);
}
tw32_f(SG_DIG_CTRL, 0x01388400);
}
if (mac_status & MAC_STATUS_PCS_SYNCED) {
tg3_setup_flow_control(tp, 0, 0);
current_link_up = 1;
}
goto out;
}
/* Want auto-negotiation. */
expected_sg_dig_ctrl = 0x81388400;
/* Pause capability */
expected_sg_dig_ctrl |= (1 << 11);
/* Asymettric pause */
expected_sg_dig_ctrl |= (1 << 12);
if (sg_dig_ctrl != expected_sg_dig_ctrl) {
if (workaround)
tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
udelay(5);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
} else if (mac_status & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET)) {
int i;
224
Wave OS project early developer manual
local_adv = ADVERTISE_PAUSE_CAP;
remote_adv = 0;
if (sg_dig_status & (1 << 19))
remote_adv |= LPA_PAUSE_CAP;
if (sg_dig_status & (1 << 20))
remote_adv |= LPA_PAUSE_ASYM;
if (port_a)
val |= 0xc010000;
else
val |= 0x4010000;
tw32_f(MAC_SERDES_CFG, val);
}
tw32_f(SG_DIG_CTRL, 0x01388400);
udelay(40);
out:
return current_link_up;
}
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
u32 flags;
int i;
if (fiber_autoneg(tp, &flags)) {
u32 local_adv, remote_adv;
local_adv = ADVERTISE_PAUSE_CAP;
remote_adv = 0;
if (flags & MR_LP_ADV_SYM_PAUSE)
remote_adv |= LPA_PAUSE_CAP;
if (flags & MR_LP_ADV_ASYM_PAUSE)
remote_adv |= LPA_PAUSE_ASYM;
tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
current_link_up = 1;
}
for (i = 0; i < 30; i++) {
udelay(20);
tw32_f(MAC_STATUS,
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED));
udelay(40);
if ((tr32(MAC_STATUS) &
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED)) == 0)
break;
}
mac_status = tr32(MAC_STATUS);
if (current_link_up == 0 &&
(mac_status & MAC_STATUS_PCS_SYNCED) &&
!(mac_status & MAC_STATUS_RCVD_CFG))
current_link_up = 1;
} else {
/* Forcing 1000FD link up. */
current_link_up = 1;
tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
out:
return current_link_up;
226
Wave OS project early developer manual
orig_pause_cfg =
(tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
TG3_FLAG_TX_PAUSE));
orig_active_speed = tp->link_config.active_speed;
orig_active_duplex = tp->link_config.active_duplex;
tw32_f(MAC_TX_AUTO_NEG, 0);
if (tp->phy_id == PHY_ID_BCM8002)
tg3_init_bcm8002(tp);
current_link_up = 0;
mac_status = tr32(MAC_STATUS);
tp->hw_status->status =
(SD_STATUS_UPDATED |
(tp->hw_status->status & ~SD_STATUS_LINK_CHG));
mac_status = tr32(MAC_STATUS);
if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
current_link_up = 0;
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
tw32_f(MAC_MODE, (tp->mac_mode |
MAC_MODE_SEND_CONFIGS));
udelay(1);
tw32_f(MAC_MODE, tp->mac_mode);
}
}
if (current_link_up == 1) {
tp->link_config.active_speed = SPEED_1000;
tp->link_config.active_duplex = DUPLEX_FULL;
tw32(MAC_LED_CTRL, (tp->led_ctrl |
LED_CTRL_LNKLED_OVERRIDE |
LED_CTRL_1000MBPS_ON));
} else {
tp->link_config.active_speed = SPEED_INVALID;
tp->link_config.active_duplex = DUPLEX_INVALID;
tw32(MAC_LED_CTRL, (tp->led_ctrl |
LED_CTRL_LNKLED_OVERRIDE |
LED_CTRL_TRAFFIC_OVERRIDE));
}
if (current_link_up != netif_carrier_ok(tp->dev)) {
if (current_link_up)
netif_carrier_on(tp->dev);
else
netif_carrier_off(tp->dev);
tg3_link_report(tp);
} else {
u32 now_pause_cfg =
228
Wave OS project early developer manual
return 0;
}
tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
tw32(MAC_EVENT, 0);
tw32_f(MAC_STATUS,
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED |
MAC_STATUS_MI_COMPLETION |
MAC_STATUS_LNKSTATE_CHANGED));
udelay(40);
if (force_reset)
tg3_phy_reset(tp);
current_link_up = 0;
current_speed = SPEED_INVALID;
current_duplex = DUPLEX_INVALID;
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
return err;
}
} else {
u32 new_bmcr;
if (tp->link_config.duplex == DUPLEX_FULL)
new_bmcr |= BMCR_FULLDPLX;
if (new_bmcr != bmcr) {
/* BMCR_SPEED1000 is a reserved bit that needs
* to be set on write.
*/
new_bmcr |= BMCR_SPEED1000;
/* Force a linkdown */
if (netif_carrier_ok(tp->dev)) {
u32 adv;
230
Wave OS project early developer manual
BMCR_ANRESTART |
BMCR_ANENABLE);
udelay(10);
netif_carrier_off(tp->dev);
}
tg3_writephy(tp, MII_BMCR, new_bmcr);
bmcr = new_bmcr;
err |= tg3_readphy(tp, MII_BMSR, &bmsr);
err |= tg3_readphy(tp, MII_BMSR, &bmsr);
if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
ASIC_REV_5714) {
if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP)
bmsr |= BMSR_LSTATUS;
else
bmsr &= ~BMSR_LSTATUS;
}
tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
}
}
tg3_setup_flow_control(tp, local_adv,
remote_adv);
}
else
current_link_up = 0;
}
}
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
tp->link_config.active_speed = current_speed;
tp->link_config.active_duplex = current_duplex;
if (current_link_up != netif_carrier_ok(tp->dev)) {
if (current_link_up)
netif_carrier_on(tp->dev);
else {
netif_carrier_off(tp->dev);
tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
}
tg3_link_report(tp);
}
return err;
}
232
Wave OS project early developer manual
}
}
}
/* XXXKV: Because we don't use the coalesce code in this driver we're going
to use 0 for all cases for now */
#if 0
Wave OS project early developer manual
return err;
}
src_map = NULL;
switch (opaque_key) {
case RXD_OPAQUE_RING_STD:
dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE;
desc = &tp->rx_std[dest_idx];
map = &tp->rx_std_buffers[dest_idx];
if (src_idx >= 0)
234
Wave OS project early developer manual
src_map = &tp->rx_std_buffers[src_idx];
skb_size = tp->rx_pkt_buf_sz;
break;
case RXD_OPAQUE_RING_JUMBO:
dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE;
desc = &tp->rx_jumbo[dest_idx];
map = &tp->rx_jumbo_buffers[dest_idx];
if (src_idx >= 0)
src_map = &tp->rx_jumbo_buffers[src_idx];
skb_size = RX_JUMBO_PKT_BUF_SZ;
break;
default:
return -EINVAL;
};
map->skb = skb;
if (src_map != NULL)
src_map->skb = NULL;
return skb_size;
}
236
Wave OS project early developer manual
prefetch(tp->hw_status);
Wave OS project early developer manual
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
if (!tg3_irq_sync(tp))
tg3_poll(dev); /* do work */
return 0;
}
prefetch(tp->hw_status);
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
/*
* Writing any value to intr-mbox-0 clears PCI INTA# and
* chip-internal interrupt pending events.
* Writing non-zero to intr-mbox-0 additional tells the
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (!tg3_irq_sync(tp))
tg3_poll(dev); /* do work */
return 1;
}
238
Wave OS project early developer manual
* event coalescing.
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
if (tg3_irq_sync(tp))
goto out;
sblk->status &= ~SD_STATUS_UPDATED;
if (tg3_has_work(tp)) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
tg3_poll(dev); /* do work */
} else {
/* No work, shared interrupt perhaps? re-enable
* interrupts, and flush that PCI write
*/
tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000000);
}
} else { /* shared interrupt */
handled = 0;
}
out:
return handled;
}
240
Wave OS project early developer manual
return err;
}
/* Device interface */
static int tg3_open(struct net_device *dev);
static int tg3_start_xmit(PacketBuf_s *skb, struct net_device *dev);
switch( nCommand )
{
case SIOC_ETH_START:
{
psNetDev->packet_queue = pArgs;
tg3_open( psNetDev );
break;
}
case SIOC_ETH_STOP:
{
tg3_close( psNetDev );
psNetDev->packet_queue = NULL;
break;
}
case SIOCSIFHWADDR:
{
nError = -ENOSYS;
break;
}
case SIOCGIFHWADDR:
{
memcpy( ((struct ifreq*)pArgs)->ifr_hwaddr.sa_data, psNetDev-
>dev_addr, 6 );
break;
}
default:
Wave OS project early developer manual
{
kerndbg( KERN_WARNING, "tg3_dev_ioctl(): Unknown command %d\n",
(int)nCommand );
nError = -ENOSYS;
break;
}
}
return nError;
}
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
* support TG3_FLG2_HW_TSO_1 or firmware TSO only.
*/
static int tg3_start_xmit_dma_bug(PacketBuf_s *skb, struct net_device *dev)
{
/* Not yet ported */
242
Wave OS project early developer manual
return 0;
}
if (rxp->skb == NULL)
continue;
pci_unmap_single(tp->pdev,
pci_unmap_addr(rxp, mapping),
tp->rx_pkt_buf_sz - tp->rx_offset,
PCI_DMA_FROMDEVICE);
free_pkt_buffer(rxp->skb);
rxp->skb = NULL;
}
if (rxp->skb == NULL)
continue;
pci_unmap_single(tp->pdev,
pci_unmap_addr(rxp, mapping),
RX_JUMBO_PKT_BUF_SZ - tp->rx_offset,
PCI_DMA_FROMDEVICE);
free_pkt_buffer(rxp->skb);
rxp->skb = NULL;
}
txp = &tp->tx_buffers[i];
skb = txp->skb;
if (skb == NULL) {
i++;
continue;
}
Wave OS project early developer manual
pci_unmap_single(tp->pdev,
pci_unmap_addr(txp, mapping),
skb_headlen(skb),
PCI_DMA_TODEVICE);
txp->skb = NULL;
i++;
free_pkt_buffer(skb);
}
}
tp->rx_pkt_buf_sz = RX_PKT_BUF_SZ;
if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
(tp->dev->mtu > ETH_DATA_LEN))
tp->rx_pkt_buf_sz = RX_JUMBO_PKT_BUF_SZ;
rxd = &tp->rx_std[i];
rxd->idx_len = (tp->rx_pkt_buf_sz - tp->rx_offset - 64)
<< RXD_LEN_SHIFT;
rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT);
rxd->opaque = (RXD_OPAQUE_RING_STD |
(i << RXD_OPAQUE_INDEX_SHIFT));
}
244
Wave OS project early developer manual
rxd = &tp->rx_jumbo[i];
rxd->idx_len = (RX_JUMBO_PKT_BUF_SZ - tp->rx_offset - 64)
<< RXD_LEN_SHIFT;
rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) |
RXD_FLAG_JUMBO;
rxd->opaque = (RXD_OPAQUE_RING_JUMBO |
(i << RXD_OPAQUE_INDEX_SHIFT));
}
}
/*
* Must not be invoked with interrupt sources disabled and
Wave OS project early developer manual
/*
* Must not be invoked with interrupt sources disabled and
* the hardware shutdown down. Can sleep.
*/
static int tg3_alloc_consistent(struct tg3 *tp)
{
tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) *
(TG3_RX_RING_SIZE +
TG3_RX_JUMBO_RING_SIZE)) +
(sizeof(struct tx_ring_info) *
TG3_TX_RING_SIZE),
MEMF_KERNEL);
if (!tp->rx_std_buffers)
return -ENOMEM;
246
Wave OS project early developer manual
memset(tp->rx_std_buffers, 0,
(sizeof(struct ring_info) *
(TG3_RX_RING_SIZE +
TG3_RX_JUMBO_RING_SIZE)) +
(sizeof(struct tx_ring_info) *
TG3_TX_RING_SIZE));
tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
tp->tx_buffers = (struct tx_ring_info *)
&tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
if (!tp->rx_jumbo)
goto err_out;
tp->hw_status = pci_alloc_consistent(tp->pdev,
TG3_HW_STATUS_SIZE,
&tp->status_mapping);
if (!tp->hw_status)
goto err_out;
tp->hw_stats = pci_alloc_consistent(tp->pdev,
sizeof(struct tg3_hw_stats),
&tp->stats_mapping);
if (!tp->hw_stats)
goto err_out;
memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
return 0;
err_out:
tg3_free_consistent(tp);
return -ENOMEM;
Wave OS project early developer manual
default:
break;
};
}
val = tr32(ofs);
val &= ~enable_bit;
tw32_f(ofs, val);
return 0;
}
/* tp->lock is held. */
248
Wave OS project early developer manual
tg3_disable_ints(tp);
tw32(FTQ_RESET, 0xffffffff);
tw32(FTQ_RESET, 0x00000000);
if (tp->hw_status)
memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
if (tp->hw_stats)
memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
return err;
}
/* tp->lock is held. */
static int tg3_nvram_lock(struct tg3 *tp)
{
if (tp->tg3_flags & TG3_FLAG_NVRAM) {
int i;
if (tp->nvram_lock_cnt == 0) {
tw32(NVRAM_SWARB, SWARB_REQ_SET1);
for (i = 0; i < 8000; i++) {
if (tr32(NVRAM_SWARB) & SWARB_GNT1)
break;
udelay(20);
}
if (i == 8000) {
tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
return -ENODEV;
}
}
tp->nvram_lock_cnt++;
}
return 0;
}
/* tp->lock is held. */
static void tg3_nvram_unlock(struct tg3 *tp)
{
if (tp->tg3_flags & TG3_FLAG_NVRAM) {
if (tp->nvram_lock_cnt > 0)
tp->nvram_lock_cnt--;
if (tp->nvram_lock_cnt == 0)
tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1);
}
}
/* tp->lock is held. */
static void tg3_enable_nvram_access(struct tg3 *tp)
{
if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
!(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
u32 nvaccess = tr32(NVRAM_ACCESS);
250
Wave OS project early developer manual
/* tp->lock is held. */
static void tg3_disable_nvram_access(struct tg3 *tp)
{
if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
!(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
u32 nvaccess = tr32(NVRAM_ACCESS);
/* tp->lock is held. */
static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
{
tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
case RESET_KIND_SHUTDOWN:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_UNLOAD);
break;
case RESET_KIND_SUSPEND:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_SUSPEND);
break;
default:
break;
};
}
}
/* tp->lock is held. */
static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
{
if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) {
switch (kind) {
case RESET_KIND_INIT:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_START_DONE);
break;
case RESET_KIND_SHUTDOWN:
Wave OS project early developer manual
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_UNLOAD_DONE);
break;
default:
break;
};
}
}
/* tp->lock is held. */
static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
{
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
switch (kind) {
case RESET_KIND_INIT:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_START);
break;
case RESET_KIND_SHUTDOWN:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_UNLOAD);
break;
case RESET_KIND_SUSPEND:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_SUSPEND);
break;
default:
break;
};
}
}
/* tp->lock is held. */
static int tg3_chip_reset(struct tg3 *tp)
{
u32 val;
void (*write_op)(struct tg3 *, u32, u32);
int i;
tg3_nvram_lock(tp);
252
Wave OS project early developer manual
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
tw32(GRC_FASTBOOT_PC, 0);
/*
* We must avoid the readl() that normally takes place.
* It locks machines, causes machine checks, and other
* fun things. So, temporarily disable the 5701
* hardware workaround, while we do the reset.
*/
write_op = tp->write32;
if (write_op == tg3_write_flush_reg32)
tp->write32 = tg3_write32;
/* do the reset */
val = GRC_MISC_CFG_CORECLK_RESET;
udelay(120);
}
/* Set PCIE max payload size and clear error status. */
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, 0xd8, 4, 0xf5000);
}
pci_restore_state(tp->pdev, tp->pci_state);
254
Wave OS project early developer manual
u32 val;
val = tr32(MEMARB_MODE);
tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
} else
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
tg3_stop_fw(tp);
tw32(0x5000, 0x400);
}
tw32(GRC_MODE, tp->grc_mode);
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
u32 val = tr32(0xc4);
tw32_f(MAC_MODE, 0);
udelay(40);
return 0;
}
/* tp->lock is held. */
static void tg3_stop_fw(struct tg3 *tp)
{
256
Wave OS project early developer manual
/* tp->lock is held. */
static int tg3_halt(struct tg3 *tp, int kind, int silent)
{
int err;
tg3_stop_fw(tp);
tg3_write_sig_pre_reset(tp, kind);
tg3_abort_hw(tp, silent);
err = tg3_chip_reset(tp);
tg3_write_sig_legacy(tp, kind);
tg3_write_sig_post_reset(tp, kind);
if (err)
return err;
return 0;
}
258
Wave OS project early developer manual
/* tp->lock is held. */
static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
{
int i;
if (offset == RX_CPU_BASE) {
for (i = 0; i < 10000; i++) {
tw32(offset + CPU_STATE, 0xffffffff);
tw32(offset + CPU_MODE, CPU_MODE_HALT);
if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
break;
}
if (i >= 10000) {
kerndbg( KERN_WARNING, "tg3_reset_cpu timed out for %s, and %s
CPU\n",
tp->dev->name,
(offset == RX_CPU_BASE ? "RX" : "TX"));
return -ENODEV;
}
260
Wave OS project early developer manual
struct fw_info {
unsigned int text_base;
unsigned int text_len;
u32 *text_data;
unsigned int rodata_base;
unsigned int rodata_len;
u32 *rodata_data;
unsigned int data_base;
unsigned int data_len;
u32 *data_data;
};
/* tp->lock is held. */
static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32
cpu_scratch_base,
int cpu_scratch_size, struct fw_info *info)
{
int err, lock_err, i;
void (*write_op)(struct tg3 *, u32, u32);
err = 0;
out:
return err;
}
/* tp->lock is held. */
static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
{
struct fw_info info;
int err, i;
info.text_base = TG3_FW_TEXT_ADDR;
info.text_len = TG3_FW_TEXT_LEN;
info.text_data = &tg3FwText[0];
info.rodata_base = TG3_FW_RODATA_ADDR;
info.rodata_len = TG3_FW_RODATA_LEN;
info.rodata_data = &tg3FwRodata[0];
info.data_base = TG3_FW_DATA_ADDR;
info.data_len = TG3_FW_DATA_LEN;
info.data_data = NULL;
262
Wave OS project early developer manual
return 0;
}
/* tp->lock is held. */
static void __tg3_set_mac_addr(struct tg3 *tp)
{
u32 addr_high, addr_low;
int i;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
for (i = 0; i < 12; i++) {
tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
}
}
addr_high = (tp->dev->dev_addr[0] +
tp->dev->dev_addr[1] +
tp->dev->dev_addr[2] +
tp->dev->dev_addr[3] +
tp->dev->dev_addr[4] +
tp->dev->dev_addr[5]) &
TX_BACKOFF_SEED_MASK;
tw32(MAC_TX_BACKOFF_SEED, addr_high);
Wave OS project early developer manual
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
if (!netif_running(dev))
return 0;
return err;
}
/* tp->lock is held. */
static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr,
dma_addr_t mapping, u32 maxlen_flags,
u32 nic_addr)
{
tg3_write_mem(tp,
(bdinfo_addr + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH),
((u64) mapping >> 32));
tg3_write_mem(tp,
(bdinfo_addr + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW),
((u64) mapping & 0xffffffff));
tg3_write_mem(tp,
(bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS),
maxlen_flags);
264
Wave OS project early developer manual
/* tp->lock is held. */
static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
{
u32 val, rdmac_mode;
int i, err, limit;
tg3_disable_ints(tp);
tg3_stop_fw(tp);
tg3_write_sig_pre_reset(tp, RESET_KIND_INIT);
err = tg3_chip_reset(tp);
if (err)
return err;
tg3_write_sig_legacy(tp, RESET_KIND_INIT);
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
/* Enable some hw fixes. */
val = tr32(TG3PCI_MSI_DATA);
val |= (1 << 26) | (1 << 28) | (1 << 29);
Wave OS project early developer manual
tw32(TG3PCI_MSI_DATA, val);
}
tw32(GRC_MODE,
tp->grc_mode |
(GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP));
266
Wave OS project early developer manual
}
#if TG3_TSO_SUPPORT != 0
else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
int fw_len;
fw_len = (TG3_TSO5_FW_TEXT_LEN +
TG3_TSO5_FW_RODATA_LEN +
TG3_TSO5_FW_DATA_LEN +
TG3_TSO5_FW_SBSS_LEN +
TG3_TSO5_FW_BSS_LEN);
fw_len = (fw_len + (0x80 - 1)) & ~(0x80 - 1);
tw32(BUFMGR_MB_POOL_ADDR,
NIC_SRAM_MBUF_POOL_BASE5705 + fw_len);
tw32(BUFMGR_MB_POOL_SIZE,
NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00);
}
#endif
if (val == 0)
val = 1;
else if (val > tp->rx_std_max_post)
val = tp->rx_std_max_post;
tw32(RCVBDI_STD_THRESH, val);
tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
BDINFO_FLAGS_DISABLED);
268
Wave OS project early developer manual
TG3_64BIT_REG_LOW,
((u64) tp->rx_jumbo_mapping & 0xffffffff));
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
NIC_SRAM_RX_JUMBO_BUFFER_DESC);
} else {
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
BDINFO_FLAGS_DISABLED);
}
tp->tx_prod = 0;
tp->tx_cons = 0;
tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
tp->tx_desc_mapping,
(TG3_TX_RING_SIZE <<
BDINFO_FLAGS_MAXLEN_SHIFT),
NIC_SRAM_TX_BUFFER_DESC);
tp->rx_rcb_ptr = 0;
tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0);
tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB,
tp->rx_rcb_mapping,
(TG3_RX_RCB_RING_SIZE(tp) <<
BDINFO_FLAGS_MAXLEN_SHIFT),
Wave OS project early developer manual
0);
tp->rx_std_ptr = tp->rx_pending;
tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
tp->rx_std_ptr);
/* Receive rules. */
tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS);
tw32(RCVLPC_CONFIG, 0x0181);
270
Wave OS project early developer manual
#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
rdmac_mode |= (1 << 27);
#endif
/* Receive/send statistics. */
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
val = tr32(RCVLPC_STATS_ENABLE);
val &= ~RCVLPC_STATSENAB_DACK_FIX;
tw32(RCVLPC_STATS_ENABLE, val);
} else if ((rdmac_mode & RDMAC_MODE_FIFO_SIZE_128) &&
(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
val = tr32(RCVLPC_STATS_ENABLE);
val &= ~RCVLPC_STATSENAB_LNGBRST_RFIX;
tw32(RCVLPC_STATS_ENABLE, val);
} else {
tw32(RCVLPC_STATS_ENABLE, 0xffffff);
}
tw32(RCVLPC_STATSCTRL, RCVLPC_STATSCTRL_ENABLE);
tw32(SNDDATAI_STATSENAB, 0xffffff);
tw32(SNDDATAI_STATSCTRL,
(SNDDATAI_SCTRL_ENABLE |
SNDDATAI_SCTRL_FASTUPD));
tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
((u64) tp->stats_mapping >> 32));
tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
((u64) tp->stats_mapping & 0xffffffff));
tw32(HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK);
tw32(HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK);
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
gpio_mask |= GRC_LCLCTRL_GPIO_OE3 |
GRC_LCLCTRL_GPIO_OUTPUT3;
272
Wave OS project early developer manual
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
gpio_mask |= GRC_LCLCTRL_GPIO_UART_SEL;
tw32_f(WDMAC_MODE, val);
udelay(40);
tw32_f(RDMAC_MODE, rdmac_mode);
udelay(40);
if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
err = tg3_load_5701_a0_firmware_fix(tp);
if (err)
return err;
}
#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
err = tg3_load_tso_firmware(tp);
if (err)
return err;
}
#endif
tp->tx_mode = TX_MODE_ENABLE;
tw32_f(MAC_TX_MODE, tp->tx_mode);
udelay(100);
tp->rx_mode = RX_MODE_ENABLE;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
274
Wave OS project early developer manual
tw32_f(MAC_RX_MODE, tp->rx_mode);
udelay(10);
if (tp->link_config.phy_is_low_power) {
tp->link_config.phy_is_low_power = 0;
tp->link_config.speed = tp->link_config.orig_speed;
tp->link_config.duplex = tp->link_config.orig_duplex;
tp->link_config.autoneg = tp->link_config.orig_autoneg;
}
tp->mi_mode = MAC_MI_MODE_BASE;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
tw32(MAC_LED_CTRL, tp->led_ctrl);
tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
tw32_f(MAC_RX_MODE, RX_MODE_RESET);
udelay(10);
}
tw32_f(MAC_RX_MODE, tp->rx_mode);
udelay(10);
tmp = tr32(SERDES_RX_CTRL);
tw32(SERDES_RX_CTRL, tmp | SERDES_RX_SIG_DETECT);
tp->grc_local_ctrl &= ~GRC_LCLCTRL_USE_EXT_SIG_DETECT;
tp->grc_local_ctrl |= GRC_LCLCTRL_USE_SIG_DETECT;
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
}
__tg3_set_rx_mode(tp->dev);
276
Wave OS project early developer manual
default:
break;
};
tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
return 0;
}
tg3_switch_clocks(tp);
tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
out:
return err;
}
if (!netif_running(dev))
return -ENODEV;
tg3_disable_ints(tp);
release_irq(tp->dev->irq, tp->dev->irq_handle);
tg3_disable_ints(tp);
release_irq(tp->dev->irq, handle);
278
Wave OS project early developer manual
err = tg3_request_irq(tp);
if (err)
return err;
if (int_mbox != 0)
return 0;
return -EIO;
}
/* Returns 0 if MSI test succeeds or MSI test fails and INTx mode is
* successfully restored
*/
static int tg3_test_msi(struct tg3 *tp)
{
struct net_device *dev = tp->dev;
int err;
u16 pci_cmd;
err = tg3_test_interrupt(tp);
if (!err)
return 0;
/* other failures */
if (err != -EIO)
return err;
release_irq(tp->dev->irq, tp->dev->irq_handle);
Wave OS project early developer manual
pci_disable_msi(tp->pdev);
err = tg3_request_irq(tp);
if (err)
return err;
/* Need to reset the chip because the MSI cycle may have terminated
* with Master Abort.
*/
tg3_full_lock(tp, 1);
tg3_full_unlock(tp);
if (err)
release_irq(tp->dev->irq, tp->dev->irq_handle);
return err;
}
tg3_full_lock(tp, 0);
tg3_disable_ints(tp);
tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
tg3_full_unlock(tp);
280
Wave OS project early developer manual
msi_mode = tr32(MSGINT_MODE);
tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
}
}
err = tg3_request_irq(tp);
if (err) {
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
}
tg3_free_consistent(tp);
return err;
}
tg3_full_lock(tp, 0);
tp->timer_counter = tp->timer_multiplier =
(HZ / tp->timer_offset);
tp->asf_counter = tp->asf_multiplier =
((HZ / tp->timer_offset) * 2);
tp->timer = create_timer();
start_timer(tp->timer, (timer_callback *) &tg3_timer, tp, (jiffies
+ tp->timer_offset)*100, true );
}
tg3_full_unlock(tp);
if (err) {
release_irq(tp->dev->irq, tp->dev->irq_handle);
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
pci_disable_msi(tp->pdev);
Wave OS project early developer manual
if (err) {
tg3_full_lock(tp, 0);
tg3_full_unlock(tp);
return err;
}
tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
tg3_enable_ints(tp);
tg3_full_unlock(tp);
netif_start_queue(dev);
return 0;
}
282
Wave OS project early developer manual
netif_stop_queue(dev);
delete_timer(&tp->timer);
tg3_full_lock(tp, 1);
#if 0
tg3_dump_state(tp);
#endif
tg3_disable_ints(tp);
tg3_full_unlock(tp);
release_irq(tp->dev->irq, tp->dev->irq_handle);
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
}
tg3_free_consistent(tp);
tg3_set_power_state(tp, PCI_D3hot);
netif_carrier_off(tp->dev);
return 0;
}
if (rx_mode != tp->rx_mode) {
tp->rx_mode = rx_mode;
tw32_f(MAC_RX_MODE, rx_mode);
udelay(10);
}
}
if (!netif_running(dev))
return;
tg3_full_lock(tp, 0);
284
Wave OS project early developer manual
__tg3_set_rx_mode(dev);
tg3_full_unlock(tp);
}
tp->nvram_size = EEPROM_CHIP_SIZE;
if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
return;
/*
* Size the chip by reading offsets at increasing powers of two.
* When we encounter our validation signature, we know the addressing
* has wrapped around, and thus have our chip size.
*/
cursize = 0x10;
if (val == magic)
break;
cursize <<= 1;
}
tp->nvram_size = cursize;
}
if (tg3_nvram_read_swab(tp, 0, &val) != 0)
return;
/* Selfboot format */
if (val != TG3_EEPROM_MAGIC) {
tg3_get_eeprom_size(tp);
return;
}
Wave OS project early developer manual
nvcfg1 = tr32(NVRAM_CFG1);
if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
tp->tg3_flags2 |= TG3_FLG2_FLASH;
}
else {
nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
tw32(NVRAM_CFG1, nvcfg1);
}
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
break;
case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE;
break;
case FLASH_VENDOR_ATMEL_EEPROM:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
break;
case FLASH_VENDOR_ST:
tp->nvram_jedecnum = JEDEC_ST;
tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
break;
case FLASH_VENDOR_SAIFUN:
tp->nvram_jedecnum = JEDEC_SAIFUN;
tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE;
break;
case FLASH_VENDOR_SST_SMALL:
case FLASH_VENDOR_SST_LARGE:
tp->nvram_jedecnum = JEDEC_SST;
tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE;
286
Wave OS project early developer manual
break;
}
}
else {
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
}
}
nvcfg1 = tr32(NVRAM_CFG1);
break;
case FLASH_5752PAGE_SIZE_4K:
tp->nvram_pagesize = 4096;
break;
case FLASH_5752PAGE_SIZE_264:
tp->nvram_pagesize = 264;
break;
}
}
else {
/* For eeprom, set pagesize to maximum eeprom size */
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
nvcfg1 = tr32(NVRAM_CFG1);
288
Wave OS project early developer manual
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
tp->tg3_flags2 |= TG3_FLG2_FLASH;
tp->nvram_pagesize = 256;
break;
}
}
nvcfg1 = tr32(NVRAM_CFG1);
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
static void tg3_nvram_init(struct tg3 *tp)
{
int j;
tw32_f(GRC_EEPROM_ADDR,
(EEPROM_ADDR_FSM_RESET |
(EEPROM_DEFAULT_CLOCK_PERIOD <<
Wave OS project early developer manual
EEPROM_ADDR_CLKPERD_SHIFT)));
if (tg3_nvram_lock(tp)) {
kerndbg( KERN_WARNING, "%s: Cannot get nvarm lock,
tg3_nvram_init failed.\n", tp->dev->name);
return;
}
tg3_enable_nvram_access(tp);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
tg3_get_5752_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tg3_get_5755_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
tg3_get_5787_nvram_info(tp);
else
tg3_get_nvram_info(tp);
tg3_get_nvram_size(tp);
tg3_disable_nvram_access(tp);
tg3_nvram_unlock(tp);
} else {
tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
tg3_get_eeprom_size(tp);
}
}
290
Wave OS project early developer manual
*val = tr32(GRC_EEPROM_DATA);
return 0;
}
tw32(NVRAM_CMD, nvram_cmd);
for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
udelay(10);
if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
udelay(10);
break;
}
}
if (i == NVRAM_CMD_TIMEOUT) {
return -EBUSY;
}
return 0;
}
ATMEL_AT45DB0X1B_PAGE_POS) +
(addr % tp->nvram_pagesize);
return addr;
}
return addr;
}
ret = tg3_nvram_lock(tp);
if (ret)
return ret;
tg3_enable_nvram_access(tp);
tw32(NVRAM_ADDR, offset);
ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
if (ret == 0)
*val = swab32(tr32(NVRAM_RDDATA));
tg3_disable_nvram_access(tp);
tg3_nvram_unlock(tp);
return ret;
}
292
Wave OS project early developer manual
struct subsys_tbl_ent {
u16 subsys_vendor, subsys_devid;
u32 phy_id;
};
/* 3com boards. */
{ PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */
{ PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */
{ PCI_VENDOR_ID_3COM, 0x1004, 0 }, /* 3C996SX */
{ PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */
{ PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */
/* DELL boards. */
{ PCI_VENDOR_ID_DELL, 0x00d1, PHY_ID_BCM5401 }, /* VIPER */
{ PCI_VENDOR_ID_DELL, 0x0106, PHY_ID_BCM5401 }, /* JAGUAR */
{ PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
{ PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
/* Compaq boards. */
{ PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
{ PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */
{ PCI_VENDOR_ID_COMPAQ, 0x007d, 0 }, /* CHANGELING */
{ PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */
{ PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }, /* NC7780_2 */
/* IBM boards. */
{ PCI_VENDOR_ID_IBM, 0x0281, 0 } /* IBM??? */
};
Wave OS project early developer manual
tp->phy_id = PHY_ID_INVALID;
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
294
Wave OS project early developer manual
tp->phy_id = eeprom_phy_id;
if (eeprom_phy_serdes) {
if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
tp->tg3_flags2 |= TG3_FLG2_MII_SERDES;
else
tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
}
switch (led_cfg) {
default:
case NIC_SRAM_DATA_CFG_LED_MODE_PHY_1:
Wave OS project early developer manual
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
break;
case NIC_SRAM_DATA_CFG_LED_MODE_PHY_2:
tp->led_ctrl = LED_CTRL_MODE_PHY_2;
break;
case NIC_SRAM_DATA_CFG_LED_MODE_MAC:
tp->led_ctrl = LED_CTRL_MODE_MAC;
break;
case SHASTA_EXT_LED_SHARED:
tp->led_ctrl = LED_CTRL_MODE_SHARED;
if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
tp->pci_chip_rev_id != CHIPREV_ID_5750_A1)
tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
LED_CTRL_MODE_PHY_2);
break;
case SHASTA_EXT_LED_MAC:
tp->led_ctrl = LED_CTRL_MODE_SHASTA_MAC;
break;
case SHASTA_EXT_LED_COMBO:
tp->led_ctrl = LED_CTRL_MODE_COMBO;
if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0)
tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
LED_CTRL_MODE_PHY_2);
break;
};
296
Wave OS project early developer manual
tp->phy_id = p->phy_id;
if (!tp->phy_id ||
tp->phy_id == PHY_ID_BCM8002)
tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
}
}
err = tg3_phy_reset(tp);
if (err)
return err;
if (!tg3_copper_is_advertising_all(tp)) {
tg3_writephy(tp, MII_ADVERTISE, adv_reg);
298
Wave OS project early developer manual
tg3_writephy(tp, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART);
}
tg3_phy_set_wirespeed(tp);
skip_phy_reset:
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
err = tg3_init_5401phy_dsp(tp);
if (err)
return err;
}
return err;
}
if (magic == TG3_EEPROM_MAGIC) {
for (i = 0; i < 256; i += 4) {
u32 tmp;
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice,
tp->pdev->nFunction, vpd_cap + PCI_VPD_ADDR, 2, i);
while (j++ < 100) {
tmp16 = g_psBus->read_pci_config(tp->pdev->nBus, tp->pdev-
>nDevice, tp->pdev->nFunction, vpd_cap + PCI_VPD_ADDR, 4);
if (tmp16 & 0x8000)
break;
udelay(100);
}
if (!(tmp16 & 0x8000))
goto out_not_found;
if (val != 0x90)
goto out_not_found;
block_end = (i + 3 +
(vpd_data[i + 1] +
(vpd_data[i + 2] << 8)));
300
Wave OS project early developer manual
i += 3;
while (i < block_end) {
if (vpd_data[i + 0] == 'P' &&
vpd_data[i + 1] == 'N') {
int partno_len = vpd_data[i + 2];
memcpy(tp->board_part_number,
&vpd_data[i + 3],
partno_len);
/* Success. */
return;
}
}
out_not_found:
strcpy(tp->board_part_number, "none");
}
if (tg3_nvram_read_swab(tp, 0, &val))
return;
if (val != TG3_EEPROM_MAGIC)
return;
if (val != 0)
Wave OS project early developer manual
return;
val = cpu_to_le32(val);
memcpy(tp->fw_ver + i, &val, 4);
}
}
}
302
Wave OS project early developer manual
if (!bridge) {
pci_id++;
continue;
}
if (pci_id->rev != PCI_ANY_ID) {
u8 rev;
tp->tg3_flags2 |= TG3_FLG2_ICH_WORKAROUND;
pci_dev_put(bridge);
break;
}
}
#endif
}
/* The EPB bridge inside 5714, 5715, and 5780 cannot support
* DMA addresses > 40-bit. This bridge may have other additional
* 57xx devices behind it in some 4-port NIC designs for example.
* Any tg3 device found behind the bridge will also need the 40-bit
* DMA workaround.
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
tp->tg3_flags2 |= TG3_FLG2_5780_CLASS;
tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG;
tp->msi_cap = g_psBus->get_pci_capability(tp->pdev->nBus, tp->pdev-
>nDevice, tp->pdev->nFunction, PCI_CAP_ID_MSI);
}
else {
do {
bridge = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_EPB,
bridge);
if (bridge && bridge->subordinate &&
(bridge->subordinate->number <=
tp->pdev->nBus->number) &&
(bridge->subordinate->subordinate >=
304
Wave OS project early developer manual
tp->pdev->nBus->number)) {
tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG;
pci_dev_put(bridge);
break;
}
} while (bridge);
#endif
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) ||
(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
306
Wave OS project early developer manual
tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
delete_area(tp->reg_area);
tp->regs = NULL;
if (tp->write32 == tg3_write_indirect_reg32 ||
((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
308
Wave OS project early developer manual
*/
tg3_get_eeprom_hw_cfg(tp);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX ||
GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_AX)
tp->tg3_flags2 |= TG3_FLG2_PHY_ADC_BUG;
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG;
tp->coalesce_mode = 0;
if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
tg3_switch_clocks(tp);
if (chiprevid == CHIPREV_ID_5701_A0 ||
chiprevid == CHIPREV_ID_5701_B0 ||
chiprevid == CHIPREV_ID_5701_B2 ||
chiprevid == CHIPREV_ID_5701_B5) {
310
Wave OS project early developer manual
void *sram_base;
writel(0x00000000, sram_base);
writel(0x00000000, sram_base + 4);
writel(0xffffffff, sram_base + 4);
if (readl(sram_base) != 0x00000000)
tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
}
}
udelay(50);
tg3_nvram_init(tp);
grc_misc_cfg = tr32(GRC_MISC_CFG);
grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS;
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp-
>pdev->nFunction, TG3PCI_MISC_HOST_CTRL,
4, tp->misc_host_ctrl);
}
(tp->pdev->nDeviceID == PCI_DEVICE_ID_TIGON3_5901 ||
tp->pdev->nDeviceID == PCI_DEVICE_ID_TIGON3_5901_2 ||
tp->pdev->nDeviceID == PCI_DEVICE_ID_TIGON3_5705F)) ||
(tp->pdev->nVendorID == PCI_VENDOR_ID_BROADCOM &&
(tp->pdev->nDeviceID == PCI_DEVICE_ID_TIGON3_5751F ||
tp->pdev->nDeviceID == PCI_DEVICE_ID_TIGON3_5753F)))
tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
err = tg3_phy_probe(tp);
if (err) {
kerndbg( KERN_WARNING, "(%s) phy probe failed, err %d\n",
tp->dev->name, err);
/* ... but do not return immediately ... */
}
tg3_read_partno(tp);
tg3_read_fw_ver(tp);
312
Wave OS project early developer manual
tp->rx_offset = 2;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
(tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
tp->rx_offset = 0;
tp->rx_std_max_post = TG3_RX_RING_SIZE;
return err;
}
mac_offset = 0x7c;
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
mac_offset = 0xcc;
if (tg3_nvram_lock(tp))
tw32_f(NVRAM_CMD, NVRAM_CMD_RESET);
else
tg3_nvram_unlock(tp);
}
if (!is_valid_ether_addr(&dev->dev_addr[0])) {
return -EINVAL;
}
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
return 0;
}
#define BOUNDARY_SINGLE_CACHELINE 1
#define BOUNDARY_MULTI_CACHELINE 2
314
Wave OS project early developer manual
int goal;
goal = 0;
if (!goal)
goto out;
case 256:
val |= (DMA_RWCTRL_READ_BNDRY_256_PCIX |
DMA_RWCTRL_WRITE_BNDRY_256_PCIX);
break;
Wave OS project early developer manual
default:
val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
break;
};
} else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
switch (cacheline_size) {
case 16:
case 32:
case 64:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
val |= DMA_RWCTRL_WRITE_BNDRY_64_PCIE;
break;
}
/* fallthrough */
case 128:
default:
val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
break;
};
} else {
switch (cacheline_size) {
case 16:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val |= (DMA_RWCTRL_READ_BNDRY_16 |
DMA_RWCTRL_WRITE_BNDRY_16);
break;
}
/* fallthrough */
case 32:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val |= (DMA_RWCTRL_READ_BNDRY_32 |
DMA_RWCTRL_WRITE_BNDRY_32);
break;
}
/* fallthrough */
case 64:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val |= (DMA_RWCTRL_READ_BNDRY_64 |
DMA_RWCTRL_WRITE_BNDRY_64);
break;
}
/* fallthrough */
case 128:
if (goal == BOUNDARY_SINGLE_CACHELINE) {
val |= (DMA_RWCTRL_READ_BNDRY_128 |
DMA_RWCTRL_WRITE_BNDRY_128);
break;
}
316
Wave OS project early developer manual
/* fallthrough */
case 256:
val |= (DMA_RWCTRL_READ_BNDRY_256 |
DMA_RWCTRL_WRITE_BNDRY_256);
break;
case 512:
val |= (DMA_RWCTRL_READ_BNDRY_512 |
DMA_RWCTRL_WRITE_BNDRY_512);
break;
case 1024:
default:
val |= (DMA_RWCTRL_READ_BNDRY_1024 |
DMA_RWCTRL_WRITE_BNDRY_1024);
break;
};
}
out:
return val;
}
sram_dma_descs = NIC_SRAM_DMA_DESC_POOL_BASE;
tw32(FTQ_RCVBD_COMP_FIFO_ENQDEQ, 0);
tw32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ, 0);
tw32(RDMAC_STATUS, 0);
tw32(WDMAC_STATUS, 0);
tw32(BUFMGR_MODE, 0);
tw32(FTQ_RESET, 0);
/*
* HP ZX1 was seeing test failures for 5701 cards running at 33Mhz
* the *second* time the tg3 driver was getting loaded after an
* initial scan.
*
* Broadcom tells me:
* ...the DMA engine is connected to the GRC block and a DMA
* reset may affect the GRC block in some unpredictable way...
* The behavior of resets to individual blocks has not been tested.
*
Wave OS project early developer manual
* Broadcom noted the GRC reset will also reset all sub-components.
*/
if (to_device) {
test_desc.cqid_sqid = (13 << 8) | 2;
tw32_f(RDMAC_MODE, RDMAC_MODE_ENABLE);
udelay(40);
} else {
test_desc.cqid_sqid = (16 << 8) | 7;
tw32_f(WDMAC_MODE, WDMAC_MODE_ENABLE);
udelay(40);
}
test_desc.flags = 0x00000005;
}
g_psBus->write_pci_config(tp->pdev->nBus, tp->pdev->nDevice, tp->pdev-
>nFunction, TG3PCI_MEM_WIN_BASE_ADDR, 4, 0);
if (to_device) {
tw32(FTQ_DMA_HIGH_READ_FIFO_ENQDEQ, sram_dma_descs);
} else {
tw32(FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ, sram_dma_descs);
}
ret = -ENODEV;
for (i = 0; i < 40; i++) {
u32 val;
if (to_device)
val = tr32(FTQ_RCVBD_COMP_FIFO_ENQDEQ);
else
val = tr32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ);
if ((val & 0xffff) == sram_dma_descs) {
ret = 0;
break;
}
udelay(100);
}
return ret;
318
Wave OS project early developer manual
} else {
tp->dma_rwctrl |= 0x001b000f;
}
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
tp->dma_rwctrl &= 0xfffffff0;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
/* Remove this if it causes problems for some boards. */
tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
#if 0
/* Unneeded, already done by tg3_get_invariants. */
tg3_switch_clocks(tp);
#endif
ret = 0;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
goto out;
while (1) {
u32 *p = buf, i;
320
Wave OS project early developer manual
#if 0
/* validate data reached card RAM correctly. */
for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) {
u32 val;
tg3_read_mem(tp, 0x2100 + (i*4), &val);
if (le32_to_cpu(val) != p[i]) {
printk(KERN_ERR " tg3_test_dma() Card buffer corrupted on
write! (%d != %d)\n", val, i);
/* ret = -ENODEV here? */
}
p[i] = 0;
}
#endif
/* Now read it back. */
ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0);
if (ret) {
kerndbg( KERN_WARNING, "tg3_test_dma() Read the buffer failed
%d\n", ret);
break;
}
/* Verify it. */
for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) {
if (p[i] == i)
continue;
if (i == (TEST_BUFFER_SIZE / sizeof(u32))) {
/* Success. */
ret = 0;
break;
Wave OS project early developer manual
}
}
if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
DMA_RWCTRL_WRITE_BNDRY_16) {
static struct pci_device_id dma_wait_state_chipsets[] = {
{ PCI_VENDOR_ID_APPLE,
PCI_DEVICE_ID_APPLE_UNI_N_PCI15 },
{ },
};
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
}
out:
pci_free_consistent(tp->pdev, TEST_BUFFER_SIZE, buf, buf_dma);
out_nofree:
return ret;
}
322
Wave OS project early developer manual
tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780;
tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780;
tp->bufmgr_config.mbuf_high_water_jumbo =
DEFAULT_MB_HIGH_WATER_JUMBO_5780;
} else {
tp->bufmgr_config.mbuf_read_dma_low_water =
DEFAULT_MB_RDMA_LOW_WATER;
tp->bufmgr_config.mbuf_mac_rx_low_water =
DEFAULT_MB_MACRX_LOW_WATER;
tp->bufmgr_config.mbuf_high_water =
DEFAULT_MB_HIGH_WATER;
tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
DEFAULT_MB_RDMA_LOW_WATER_JUMBO;
tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
DEFAULT_MB_MACRX_LOW_WATER_JUMBO;
tp->bufmgr_config.mbuf_high_water_jumbo =
DEFAULT_MB_HIGH_WATER_JUMBO;
}
tp->bufmgr_config.dma_low_water = DEFAULT_DMA_LOW_WATER;
tp->bufmgr_config.dma_high_water = DEFAULT_DMA_HIGH_WATER;
}
strcpy(str, "PCIX:");
if ((clock_ctrl == 7) ||
((tr32(GRC_MISC_CFG) & GRC_MISC_CFG_BOARD_ID_MASK) ==
GRC_MISC_CFG_BOARD_ID_5704CIOBE))
strcat(str, "133MHz");
else if (clock_ctrl == 0)
strcat(str, "33MHz");
else if (clock_ctrl == 2)
strcat(str, "50MHz");
else if (clock_ctrl == 4)
strcat(str, "66MHz");
else if (clock_ctrl == 6)
strcat(str, "100MHz");
} else {
strcpy(str, "PCI:");
if (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED)
strcat(str, "66MHz");
else
strcat(str, "33MHz");
}
if (tp->tg3_flags & TG3_FLAG_PCI_32BIT)
strcat(str, ":32-bit");
else
strcat(str, ":64-bit");
return str;
}
324
Wave OS project early developer manual
/* Enable device */
uint32 nOldCommand, nNewCommand;
tp = netdev_priv(pNetDev);
tp->pdev = pDev;
tp->dev = pNetDev;
tp->pm_cap = pm_cap;
tp->mac_mode = TG3_DEF_MAC_MODE;
tp->rx_mode = TG3_DEF_RX_MODE;
tp->tx_mode = TG3_DEF_TX_MODE;
tp->mi_mode = MAC_MI_MODE_BASE;
*
* The StrongARM chips on the board (one for tx, one for rx)
* are running in big-endian mode.
*/
tp->grc_mode = (GRC_MODE_WSWAP_DATA | GRC_MODE_BSWAP_DATA |
GRC_MODE_WSWAP_NONFRM_DATA);
spinlock_init(&tp->lock, "tg3");
spinlock_init(&tp->indirect_lock, "tg3_indirect");
tg3_init_link_config(tp);
tp->rx_pending = TG3_DEF_RX_RING_PENDING;
tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
tp->tx_pending = TG3_DEF_TX_RING_PENDING;
nError = tg3_get_invariants(tp);
if( nError )
{
kerndbg(KERN_WARNING, "tg3: Problem fetching invariants of chip,
aborting.\n");
goto err_out_iounmap;
}
tg3_init_bufmgr_config(tp);
326
Wave OS project early developer manual
tp->rx_pending = 63;
}
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714))
tp->pdev_peer = tg3_find_peer(tp);
nError = tg3_get_device_address(tp);
if( nError )
{
kerndbg( KERN_WARNING, "tg3: Could not obtain valid ethernet
address, aborting.\n");
goto err_out_iounmap;
}
/*
* Reset chip in case UNDI or EFI driver did not shutdown
* DMA self test will enable WDMAC and we'll see (spurious)
* pending DMA on the PCI bus at that point.
*/
if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
pci_save_state(tp->pdev, tp->pci_state);
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
}
nError = tg3_test_dma(tp);
if( nError )
{
kerndbg( KERN_WARNING, "tg3: DMA engine test failed, aborting.\n");
goto err_out_iounmap;
}
/* Now that we have fully setup the chip, save away a snapshot
* of the PCI config space. We need to restore this after
* GRC_MISC_CFG core clock resets and some resume events.
*/
pci_save_state(tp->pdev, tp->pci_state);
"10/100/1000");
netif_carrier_off(tp->dev);
return 0;
err_out_iounmap:
if( tp->reg_area )
delete_area( tp->reg_area );
tp->regs = NULL;
err_out:
return nError;
}
328
Wave OS project early developer manual
g_nDeviceHandle = sInfo.nHandle;
set_device_data( g_nDeviceHandle, pNetDev );
if( nCardsFound == 0 )
disable_device( nDeviceID );
/* Driver management */
status_t device_init( int nDeviceID )
{
/* Get PCI bus */
g_psBus = get_busmanager( PCI_BUS_NAME, PCI_BUS_VERSION );
if( g_psBus == NULL )
return -ENODEV;
delete_area( pPrivate->reg_area );
pPrivate->regs = NULL;
kfree( pPrivate );
kfree( pNetDev );
release_device( g_nDeviceHandle );
g_nDeviceHandle = -1;
}
return 0;
}
So we clearly do not yet have enough to be able to test our driver properly, but can
at least try the load it and see what happens when the interface layer attempts to
open the device. This will cause tg3_dev_open() to be called and run much of the
code we have ported since we last tested the driver.
Testing
Again when we test the driver it does not crash, which would seem to indicate that
most of the new code is working as we would expect. We can add some additional
debugging output to check. We'll add some debugging to tg3_open() to see if the
new code paths are being followed.
330
Wave OS project early developer manual
tg3_open() has several places where it may return early, so we'll add debugging
statements at each of those points to find out what the likely problem is:
So tg3_open() returns at the second possible early return point, in this block of code:
err = tg3_request_irq(tp); if (err) { if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
{ pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; }
tg3_free_consistent(tp); kerndbg( KERN_DEBUG_LOW, "%s(): 2\n",
__FUNCTION__ ); return err; }
Apparently, we could not successfully claim the desired IRQ. We can also see from
the kernel output that at least part of tg3_request_irq() worked:
So we'll have to investigate a little further and try to find out what has gone wrong.
static int tg3_request_irq(struct tg3 *tp) { int (*fn)(int, void *, SysCallRegs_s *);
unsigned long flags; struct net_device *dev = tp->dev; if (tp->tg3_flags2 &
TG3_FLG2_USING_MSI) { fn = tg3_msi; if (tp->tg3_flags2 &
TG3_FLG2_1SHOT_MSI) fn = tg3_msi_1shot; } else { fn = tg3_interrupt; if (tp-
>tg3_flags & TG3_FLAG_TAGGED_STATUS) fn = tg3_interrupt_tagged; flags =
SA_SHIRQ; } return (request_irq(tp->dev->irq, fn, NULL, flags, dev->name, dev)); }
The problem is that we have changed the call to request_irq() but not payed
attention the way it is used. On Linux request_irq() returns 0 to indicate success and
a positive value to indicate failure. On Syllable request_irq() returns a positive value
as a handle that is used with other kernel functions, and less than 0 to indicate
failure. This is the opposite of what is expected. So we'll re-write this to fit Syllable:
static int tg3_request_irq(struct tg3 *tp) { int (*fn)(int, void *, SysCallRegs_s *);
unsigned long flags; struct net_device *dev = tp->dev; if (tp->tg3_flags2 &
TG3_FLG2_USING_MSI) { fn = tg3_msi; if (tp->tg3_flags2 &
TG3_FLG2_1SHOT_MSI) fn = tg3_msi_1shot; } else { fn = tg3_interrupt; if (tp-
>tg3_flags & TG3_FLAG_TAGGED_STATUS) fn = tg3_interrupt_tagged; flags =
SA_SHIRQ; } tp->dev->irq_handle = request_irq(tp->dev->irq, fn, NULL, flags, dev-
>name, dev); return ( tp->dev->irq_handle < 0 ? 1 : 0 ); }
We store the handle returned by request_irq() and return 0 to indicate success and 1
Wave OS project early developer manual
if request_irq() failed. This should satisfy any code in the driver that calls
tg3_request_irq() .
At this point there is not much more we can do to test the driver. However, we can at
least be moderately certain that the device initialisation code is now complete.
Next
HYPERLINK "http://development.syllable.org/documentation/drivers/network/part-
4.html"Part 4: We'll port the rest of the code for the Rx and Tx code paths, and test
our driver.
Syllable
HYPERLINK
"http://development.syllable.org/documentation/drivers/index.html"Device drivers -
Contents
Timers
Most of the functionality in the rest of these functions relies on tg3_timer() operating
correctly, so this is the next logical function to port.
The first thing to note is that we must change the function declaration to take a void*
argument instead of unsigned long . This is another difference between timers on
Linux and Syllable. As before, we also have to change the one instance of create
timer from:
To the Syllable-esque:
332
Wave OS project early developer manual
Once we've added the timer handling code, our driver begins to "come alive". When
we test it now, we see additional output:
We can test that the timer code is working by removing the network cable:
So it seems the timer code is working, mostly. We have commented out one line of
code:
schedule_work(&tp->reset_task);
Tx codepath
The next piece of functionality we'll add is code for handling Tx (Transmit). Three of
the functions we already have stubs for, tg3_tx() , tg3_start_xmit() and
tg3_start_xmit_dma_bug() are related to this code path. The best thing to do is start
with tg3_tx() and see where that leads us.
Because we need to make quite a few changes, our first effort is rough, with large
blocks of code commented out and enclosed in #if blocks. You can see how the
tg3_start_xmit() function looks HYPERLINK
"http://development.syllable.org/documentation/drivers/network/examples/part-4/tg3-
tx.c"here .
The biggest change is that we have removed any code that deals with fragments, or
"skb frags". Transmitting fragmented packets is not done by Syllable, so the
PacketBuf_s we are transmitting will always contain a single complete frame. This
makes the Syllable code a little easier, but does require a few changes to the code to
make it behave as if the "last" fragment has been transmitted. Linux also has a few
additional macros and inline functions that are used to extract various pieces of
information from an skb:
len = skb_headlen(skb);
len = skb->pb_nSize;
You can see which members are available in the PacketBuf_s structure by looking at
its definition in the system header file <net/packet.h> .
It is a little hard to test the driver at this point, with only the Tx code implemented. We
can add some additional debugging output to the Tx functions such as
tg3_start_xmit() and ensure that they are being called correctly. The best way to test
the driver is to connect the card to a dedicated network switch, preferably with one
other machine connected to the same switch. We can then configure the network
interface and attempt to ping the other machine: if the Tx code is working, we will be
able to see the data that is being transmitted via the activity light on the network card
and the switch. If this is not an option for you, you'll have to continue to port the Rx
code to the driver and test both the Tx and Rx functions together. This is more
difficult to debug, however.
When we connect our machine to a switch and test it the first time, it doesn't work.
From the debug output it is clear that tg3_start_xmit() is called, but no traffic is seen
on the switch. We clearly need to take a closer look at tg3_start_xmit() and the other
Tx code to see if we have missed anything. Our second attempt can be seen
HYPERLINK
"http://development.syllable.org/documentation/drivers/network/examples/part-4/tg3-
tx.c"here . We've changed the way we call tg3_set_txd() and also ensured that the
line:
tp->tx_prod = entry;
When we test this iteration, the driver appears to work. Traffic can be seen by the
switch, which indicates that frames must be leaving the device.
At this point there is not much more we can do to test the driver. We could connect a
second machine to the switch, set it to promiscuous mode and capture the packets
that our test machine is sending to ensure they are correct, but that's really not
necessary.
Before we finish up, we'd better clean up the code we have. We'll remove the code in
the #if blocks and lines of code that are commented out. We'll also clean up some
unused variables and some unused code, and fix a compiler warning. We'll also
make similar changes to the tg3_start_xmit_dma_bug() function, which is used for
certain cards. The result of this cleanup is seen in HYPERLINK
"http://development.syllable.org/documentation/drivers/network/examples/part-4/tg3-
tx.c"here . The driver as it stands now can be seen HYPERLINK
"http://development.syllable.org/documentation/drivers/network/examples/part-4/tg3-
2.c"here .
Rx codepath
We're almost there. The last piece of code implements the Rx codepath. We'll start
with the function tg3_rx() , which is currently a stub. It isn't a large function and it
relies on only one extra function, tg3_recycle_rx() , which is also small.
One important difference is the way that incoming frames are placed in the net
queue and notified to the interface layer. In the Linux driver you will see the functions
skb_put() and netif_receive_skb() . On Syllable, skb_put() is emulated to some
degree by the system header linux_compat.h . netif_receive_skb() is replaced by
enqueue_packet() .
In general, you use the following code instead of a simple call to skb_put() :
334
Wave OS project early developer manual
The code copies the raw ethernet frame out of the cards Rx buffer ( desc ) to the a
new skb. The following code then pushes the skb to the interface layer:
This code is near universal across all of the network drivers for Syllable.
In theory, we now have a complete driver which can configure the hardware and
transmit and receive packets. Now we can begin to test it properly.
The first thing we'll do is attempt to ping another machine on a network. This will
generate a low volume of transmits and receives; exactly what we want to do at this
point.
When we try the driver, it doesn't work. We know that tg3_start_xmit() is being called
and data appears to be transmitted, but nothing seems to be received by the card.
There could be a number of reasons for this.
After some investigation it turns out that the driver is not receiving any interrupts, and
none of the interrupt handlers are being called. The obvious first thing to do is to
check that the interrupt handling code is correct, and that the driver correctly calls
request_irq() . We can already see from the kernel output that the driver does indeed
request IRQ 11 when it is loaded, so we can be fairly certain that it is correct. None
the less, we'll add some debug output to the interrupt handlers to see if they are
being called.
After some debugging, it becomes apparent that the culprit is this block of code in
the function tg3_reset_hw() :
So maybe it is required after all! We'll merge the functions tg3_init_coal() and
__tg3_set_coalesce() into one function. Once we've done that and test the driver
again, we have more success:
Our test network is configured incorrectly, or the network configuration for the
interface is incorrect.
Frames are being sent to our device, but the hardware is ignoring them.
The frames are being received by the Rx ring buffer has been incorrectly created,
causing the hardware to drop them.
The frames are being received and placed in the Rx ring buffer but the hardware is
not raising an interrupt.
Number 1 can be tested by connecting two other machines to the network and
pinging between themselves. Number 5 can probably be discounted because
interrupts are now being raised for Tx completion events. We have already tested
number 2 by forcing __tg3_set_rx_mode() to place the interface in promiscuous
mode. That leaves only numbers 3 and 4, both of which are going to be hard to
check.
This particular bug doesn't give us a logical starting point, so we're left with little
choice but to examine the code line by line, starting with device_init() and comparing
our version with the original. We'll look for pieces of code that may have been
changed when porting and double check them. We're also looking for places where
we may have made assumptions: remember __tg3_set_coalesce() in the Tx
codepath! We'll also double-check any calculations and ensure default values are
correctly set.
It looks harmless enough, but as it deals directly with configuring the card for Rx, we
give it extra attention. The obvious thing to check here is if tp->dev->mtu has a
sensible value. We can add some debug output to check. When we test the driver,
we find that tp->dev->mtu is 0. This could certainly cause serious problems: the
maximum MTU for ethernet is just over 1500 bytes!
It turns out that the tg3 driver expects the mtu field in the net_device structure to
336
Wave OS project early developer manual
Success! It seems we have found the problem, and now the device is receiving
packets and generating interrupts.
Not only is the card generating interrupts, when we ping a remote machine we also
receive a response: the device is correctly transmitting and receiving frames, and
those frames are being sent correctly to the interface layer. We have a working
driver!
It's time to give the driver a proper test. We'll switch off the debugging output by
commenting out the lines:
at the top of the driver and recompiling. We'll simply test the driver by using our new
network connection just like any other: we'll try connecting to different servers with
various protocols and ensure it works.
Next
http://development.syllable.org/documentation/drivers/network/part-5.html Part 5 :
We'll clean up a little and add some "bells & whistles" in the form of power
management. We'll also take a look back and recap the important points of porting a
network driver to Syllable.
Power management
ACPI power management is still fairly new in Syllable, and few drivers implement
support for it. For most modern hardware it's fairly simple to add support though.
There are two additional functions our driver must export to support power
management. They are defined in the system header file <atheos/device.h> :
It's a fairly simple task to port the tg3_suspend() and tg3_resume() functions to
Syllable. Apart from changing the timer handling to fit Syllable we also have to
change the call to tg3_set_power_state() in device_suspend() from:
Wave OS project early developer manual
to
The effect is the same. It seems we do also need the function tg3_restart_hw() ,
which was previously unused and removed from the driver. Again, it is a simple task
to re-add the function to the driver.
Tasks
We have ignored tasks upto now. The Linux kernel implements the concept of
"tasklets", which are essentially kernel threads that can be scheduled by the driver to
perform a small piece of work that is required. The tg3 driver has one task, which is
performed by the function tg3_reset_task() . That task may be scheduled at two
points in the driver with the following function call:
schedule_work(&tp->reset_task);
Tasklets are not something Syllable implements. If we wanted too, we could always
emulate them with a kernel thread. Instead of calling schedule_work() we would
instead unlock a mutex that the thread was waiting on, causing it to run.
For now we'll adopt a simpler aproach of simply calling tg3_reset_task() directly. This
has the disadvantage that the task is performed from "inside" the interrupt handler,
but it is unlikely to be a problem.
Release vs uninit
When the driver is unloaded by the kernel it will call the device_uninit() function as a
way of informing the driver. Syllable 0.6.2 added a new function:
We can use device_release() to shut down the card and clean up instead of
device_uninit() . If we do that, we no longer need to store the device handle in a
global variable. This means that the driver will able to work with multiple devices in
one machine.
Changing our driver is simple. We take the code from device_uninit() and move it to
our new device_release() function, with a few additional changes to take advantage
of the additional device parameters. The device_release() function looks like this:
338
Wave OS project early developer manual
The device_uninit() function is still required by Syllable but now it has little to do:
Smaller changes
We can also make a few smaller tweaks and changes. We'll clean up the defines for
DEBUG_LIMIT at the top of the file and enclose them in an #if block so that we can
easily "switch on" debugging again should we need to.
We'll also change the name that is passed to claim_device(). Currently the device is
claimed as a "Broadcom Tigon3", but most Broadcom users would probably know
these cards by the name "Broadcom NetExtreme", so that's what we'll use.
It's also probably a good idea if we move the small piece of code we added to set an
MTU value when we were debugging the Rx codepath. We'll move it into tg3_probe()
where some other default values are set in our net_device instance.
Leftovers
There are still a handful of places in the driver where we have been forced to
comment out blocks of code inside #if blocks. Most of this code deals with scanning
the PCI bus using Linux-specific functions. Right now we will not be implementing
any support for this code on Syllable. The downside is that the driver may not work
correctly on certain motherboard chipsets or with certain configurations, but those
are limited. We can revisit these blocks of code at a later date, when we have a
suitable solution that will work with Syllable.
Recap
We've now ported a network driver to Syllable. We've covered some important topics
and shown how to debug your driver in practical terms. Here are some things to
remember as you work on your own code:
You can use the example driver we started with in part 1 as a base for your driver.
Follow the code path in a logical manner. There are several points during
development where the next stage in your port should be obvious.
Work in small chunks, porting no more than one or two functions at a time. If you try
to port 5000 lines in one go you'll quickly sink under the feeling of having bitten off
more than you can chew.
Comment out any code you do not fully understand and comment it to remind
yourself why you commented it out, and to help you find it later.
Refer to this series, existing drivers and the Linux documentation for help on
understanding specific functions.
Test and debug your driver at every available opportunity. You can catch some bugs
and fix them even without porting the entire driver.
Try to change as little of the code as possible. It will make it easier to maintain and
update the driver in the future.
It may be better to add to linux_compat.h instead of changing the code in the driver.
If you make any changes, make sure you submit them back to the Syllable
Wave OS project early developer manual
developers so that it can be merged back into the main source tree.
Work on the core functionality first and ensure that it is working before you add
support for optional extras. Just remember that sometimes a function that looks
optional may be important!
Check your assumptions. What you thought was correct may be wrong.
Debugging is hard work but necessary. Just keep at it, and try everything.
You don't need to port everything. Linux implements functionality that Syllable does
not, such as VLAN support and ethertool. Not having to port the code for these can
mean the Syllable driver can be thousands or hundreds of lines shorter than the
Linux driver.
If you're stuck, ask. There are people who have been there before you and may be
able to help.
Audio Drivers
Some details about Syllable audio drivers
-----------------------------------------
- Like every driver for the media system, the userspace driver has to
implement the init_media_addon() call and return a os::MediaAddon object
(which can then export multiple os::MediaOutput and os::MediaInput objects).
of the stream.
340
Wave OS project early developer manual
If the card uses an ac97 codec you can use the ac97 kernel driver code. Add a
AC97AudioDriver_s structure to your private driver structure and fill the
following parts:
*pDriverData - Set this to your private driver structure. It will be passed to
all called driver functions.
*pfWait - Wait for the codec to become ready.
*pfWrite - Write data to one register of the codec.
*pfRead - Read data from one register of the codec.
Then call ac97_initialize() with a unique id string and the number of codecs
of the card.
There are various other ac97 functions that you can use (see ac97audio.h), the
most important one is probably ac97_set_rate() to set one samplerate register.
To use the ac97 userspace driver your driver needs to implement the
followinging ioctls:
- AC97_CLEAR: Stop the engine and reset the buffer pointer to the start of the
buffer. Call generic_stream_clear() from your implementation if you use the
generic streams code.
The ac97 userspace driver expects that you create a device node for every
hardware stream.
Wave OS project early developer manual
--------------------------------
The easiest way to create a new driver is to take a present one like the i8xx
driver and then replace the hardware specific code, especially if your card
Here is some information about where you can find the necessary information in
the alsa drivers.
The function names are based on the i8xx/vt82xx/hda syllable drivers and it is
assumed that you use the generic streams code.
hw_check_format():
The snd_pcm_hardware and snd_pcm_hw_constraint_list structures should give you
some ideas about the number of supported channels and samplerates. The
xxx_playback_open() or xxx_pcm_open() calls might supply additional
information.
hw_set_format():
Search for xxx_prepare() functions and the functions they call. Do not forget
to call the ac97 functions if you use the ac97 code. Also load the dma buffer
or descriptor table pointer to the hardware.
hw_create_buffers():
Most of this code is not hw specific. Check the maximum buffer and fragment
size of the card.
If your card uses a descriptor table just adjust the entry format
(hw_sgd_table) and fill it correctly.
hw_get_frag_size()/hw_get_frag_number()/hw_get_buffer():
hw_get_current_positition():
See xxx_pcm_pointer(). Make sure you return the position in the current
fragment.
The i8xx/vt82xx cards are examples for having different registers for the
current fragment and the current position inside the fragment, hd-audio cards
are examples for having a register that returns the position in the whole
buffer.
hw_start()/hw_stop():
See xxx_trigger().
hw_clear():
342
Wave OS project early developer manual
This function is a bit difficult to implement. You need to stop the engine and
reset the pointer to the start of the buffer without resetting the format.
This can be difficult if your hardware does not have a direct way to set the
buffer position.
hw_open()/hw_close()/hw_read()/hw_write():
See the i8xx/vt82xx/hda driver for this. No hardware specific code required.
hw_ioctl()
If your card uses ac97 then you can take the code from the i8xx/vt82xx
drivers. Otherwise you have to create your own interface to the userspace
driver.
hw_init_stream():
hw_init():
See xxx_probe() and the called functions. Check the i8xx driver as an example
about how to initialize the parts that are not hardware specific.
hw_uninit():
hw_release():
Headers Reference
This part shows the content of the system headers, in order to make the development tasks a little bit
easier. The headers are shown as they are, and are just the custom headers provided by the legacy
project where this code comes from.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
#ifndef F_CODEVIEW_FORMAT_PERL_H
344
Wave OS project early developer manual
#define F_CODEVIEW_FORMAT_PERL_H
#include "format.h"
namespace cv
{
uint GetStyleCount();
const os::String& GetStyleName( char );
void SetStyle( char, const CodeViewStyle& );
const CodeViewStyle& GetStyle( char );
private:
enum {
F_DEFAULT = 0,
F_COMMENT,
F_STRING,
F_KEYWORD,
CodeViewStyle styles[FORMAT_COUNT];
} /* namespace cv */
#endif /* F_CODEVIEW_FORMAT_PERL_H */
/* libcodeview.so - A programmers editor widget for Atheos
Copyright (c) 2001 Andreas Engh-Halstvedt
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Wave OS project early developer manual
//contexts
#define C_NONE 0x00000000
//for convenience
#define C_COMMENT (C_LINECOMMENT | C_SPANCOMMENT)
#define C_CONST (C_STRINGCONST | C_CHARCONST)
#define C_FLAGS (C_ESCAPE | C_SLASH | C_STAR)
346
Wave OS project early developer manual
"do",
"else",
"elsif",
"end",
"ensure",
"false",
"for",
"if",
"in",
"module",
"next",
"nil",
"not",
"or",
"redo",
"rescue",
"retry",
"return",
"self",
"super",
"then",
"true",
"undef",
"unless",
"until",
"when",
"while",
"yield"
};
#endif
Format_Ruby::Format_Ruby()
{
for( int a = 0; a < FORMAT_COUNT; a++ )
styles[a].sColor = defaultcolors[ a ];
}
uint Format_Ruby::GetStyleCount()
{
return FORMAT_COUNT;
}
return;
end=start+1;
while(end<line.size() && format[end]==F_DEFAULT &&
canContinueIdentifier(line[end]))
++end;
while(start<line.size()){
os::String tmp=line.const_str().substr(start, end-start);
int max=sizeof(keywords)/sizeof(keywords[0]);
int min=0;
int test=max/2;
//binary search
while(max-min>1){
if(!strcmp(keywords[test], tmp.c_str()))
break;
if(tmp<keywords[test])
max=test;
else
min=test;
test=(max+min)/2;
}
if(!strcmp(keywords[test], tmp.c_str())){
for(;start<end;++start)
format[start]=F_KEYWORD;
}
start=end+1;
end=start+1;
while(end<line.size() && format[end]==F_DEFAULT &&
canContinueIdentifier(line[end]))
++end;
}
}
348
Wave OS project early developer manual
format.resize(line.size());
for(uint a=0;a<line.size();++a){
newcntx = oldcntx & ( C_COMMENT | C_CONST );
c = line[a];
switch(line[a]){
//if found '\'' ->
// if context is comment or string: ignore
// if context is charconst and escape: ignore
// if context is charconst and !escape: end charconst
// if context is !charconst and !escape: begin charconst
case '\'':
if(oldcntx & (C_COMMENT | C_STRINGCONST))
break;
newcntx |= C_SLASH;
break;
}
oldcntx = newcntx;
}
if(newcntx&C_ESCAPE)
return newcntx & ( C_COMMENT | C_CONST );
else
return newcntx & ( C_SPANCOMMENT );
}
uint white;
for(white=0;white<line.size();++white)
if(line[white]!=' ' && line[white]!='\t')
break;
350
Wave OS project early developer manual
if(canContinueIdentifier(line[chr])){//in identifier
while(chr>0 && canContinueIdentifier(line[chr]))
--chr;
if(!canContinueIdentifier(line[chr]))
++chr;
}else{//outside identifier
while(chr>0 && !canContinueIdentifier(line[chr]))
--chr;
if(canContinueIdentifier(line[chr]))
++chr;
}
return chr;
}
if(canContinueIdentifier(line[chr])){//in identifier
while(chr<=max && canContinueIdentifier(line[chr]))
++chr;
}else{//outside identifier
while(chr<=max && !canContinueIdentifier(line[chr]))
++chr;
}
return chr;
}
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
#ifndef F_CODEVIEW_FORMAT_RUBY_H
#define F_CODEVIEW_FORMAT_RUBY_H
#include "format.h"
Wave OS project early developer manual
namespace cv
{
class Format_Ruby : public Format {
private:
enum{
F_DEFAULT = 0,
F_COMMENT,
F_STRING,
F_CHAR,
F_KEYWORD,
CodeViewStyle styles[FORMAT_COUNT];
public:
Format_Ruby();
uint GetStyleCount();
const os::String& GetStyleName( char );
void SetStyle( char, const CodeViewStyle& );
const CodeViewStyle& GetStyle( char );
} /* namespace cv */
#endif /* F_CODEVIEW_FORMAT_RUBY_H */
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
352
Wave OS project early developer manual
#ifndef F_CODEVIEW_FORMAT_H
#define F_CODEVIEW_FORMAT_H
#include <gui/gfxtypes.h>
#include <atheos/types.h>
#include <util/string.h>
namespace cv
{
*
* \return The number of styles supported by this format.
*/
virtual uint GetStyleCount() = 0;
354
Wave OS project early developer manual
} /* end of namespace */
#endif /* F_CODEVIEW_FORMAT_H */
/* libcodeview.so - A programmers editor widget for Atheos
Copyright (c) 2001 Andreas Engh-Halstvedt
Copyright (c) 2003 Henrik Isaksson
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
#include "inneredit.h"
#include "codeview.h"
#include <assert.h>
#include <gui/font.h>
#include <gui/scrollbar.h>
#include <util/clipboard.h>
#include <util/application.h>
#define POINTER_WIDTH 7
#define POINTER_HEIGHT 14
static uint8 mouseImg[]=
{
0x02,0x02,0x02,0x00,0x02,0x02,0x02,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x02,0x02,0x02,0x00,0x02,0x02,0x02
};
InnerEdit::InnerEdit(os::Control* c)
: View(os::Rect(), "", os::CF_FOLLOW_ALL, os::WID_WILL_DRAW |
os::WID_FULL_UPDATE_ON_H_RESIZE),
control(c), eventMask(0), eventBuffer(0),
mousePressed(false), IcursorActive(false),
format(0), backBM(0), backView(0),
maxWidth(0), cursorX(0), cursorY(0), old_cursorX(0), old_cursorY(0),
356
Wave OS project early developer manual
tabSize(4), useTab(true),
selectionValid(false),
enabled(true), readOnly(false),
maxUndo(1000), undoCount(0), redoCount(0), undoHead(0), undoTail(0),
undoCurrent(0),
m_pcContextMenu( NULL ), sHighlight(0,0,0,0)
{
SetBgColor(255, 255, 255);
SetFgColor(0, 0, 0);
os::font_properties fp;
os::Font::GetDefaultFont(DEFAULT_FONT_FIXED, &fp);
os::Font *f=new os::Font(fp);
SetFont(f);
f->Release();
buffer.resize(1);
UpdateBackBuffer();
UpdateScrollbars();
m_nMargin = 40;
}
InnerEdit::~InnerEdit()
{
if(backBM)
delete backBM;
if(IcursorActive)
os::Application::GetInstance()->PopCursor();
}
c.green/=2;
c.blue/=2;
return c;
}
uint selTop=selStart.y;
uint selLeft=selStart.x;
uint selBot=selEnd.y;
uint selRight=selEnd.x;
if( selectionValid ) {
if( selTop > selBot ) {
uint tmp=selTop;
selTop=selBot;
selBot=tmp;
tmp=selLeft;
selLeft=selRight;
selRight=tmp;
} else if( selTop == selBot && selLeft > selRight ) {
uint tmp=selLeft;
selLeft=selRight;
selRight=tmp;
}
}
if( m_nMargin ) {
backView->FillRect( os::Rect( xOff, 0, xOff + m_nMargin -
1/*was -4*/, lineHeight ),m_sLineBackColor);
backView->FillRect(os::Rect(m_nMargin-4,0,m_nMargin-
2,lineHeight),os::Color32_s(255,255,255));
backView->FillRect( os::Rect(m_nMargin-2,0,m_nMargin-
1,lineHeight ),m_sLineBackColor);
backView->MovePenTo( xOff, lineBase );
358
Wave OS project early developer manual
backView->SetFgColor( m_sLineNumberFg );
backView->SetBgColor( m_sLineNumberBg );
if( bIsFolded ) {
backView->DrawFrame( os::Rect( xOff, 0, xOff +
m_nMargin - 1, lineHeight),os::FRAME_TRANSPARENT );
backView->DrawString( "+" );
} else {
os::String cLineNo;
cLineNo.Format( "%d", nBufferIndex+1 );
backView->DrawString( cLineNo );
}
}
if(selectionValid){
if( nVisibleLine == selTop ) {
invStart = selLeft;
invEnd = pcLineText.size();
}
if( nVisibleLine == selBot )
invEnd = selRight;
if( nVisibleLine > selTop && nVisibleLine < selBot )
invEnd = pcLineText.size();
os::Color32_s fg=GetFgColor();
os::Color32_s bg=GetBgColor();
backView->SetFgColor(fg);
if(chr=='\t') {
backView->Sync();//need this to get correct pen pos
float tab=spaceWidth*tabSize;
float x = backView->GetPenPosition().x - xOff -
m_nMargin;
x = tab*ceil((x+1)/tab);
++a;
while( a < pcLineText.size() && pcLineText[ a ] ==
'\t' ) {
++a;
x+=tab;
}
if(!(nfg==fg)){
fg=nfg;
backView->SetFgColor(fg);
}
if(!(nbg==bg)){
360
Wave OS project early developer manual
bg=nbg;
backView->SetBgColor(bg);
}
int len=os::utf8_char_length(chr);
backView->DrawString( pcLineText.c_str() + a,
len );
a+=len;
}
if( bIsFolded ) {
backView->SetFgColor( os::Color32_s( 200, 50, 50 ) );
backView->SetBgColor( bg );
backView->DrawString( " (...)" );
}
backView->Sync();
DrawBitmap( backBM, backBM->GetBounds(), os::Rect( -xOff, y,
backBM->GetBounds().Width() - xOff, y + lineHeight - 1 ) );
Sync();
nBufferIndex = _TranslateBufferIndex( ++nVisibleLine );
y += lineHeight;
}
buffer.clear();
vector<os::String> list;
SplitLine(list, s);
buffer.resize(list.size());
for(uint a=0;a<list.size();++a){
buffer[a].text=list[a];
}
UpdateAllWidths();
Reformat(0, buffer.size()-1);
cursorY=0;
cursorX=0;
UpdateScrollbars();
Invalidate();
eventBuffer |= CodeView::EI_CONTENT_CHANGED;
ClearUndo();
}
vector<os::String> list;
SplitLine(list, str);
if(addUndo)
AddUndoNode(UndoNode::ADDED, str, x, y);
if(list.size()==1){
buffer[nBufferIndex].text.str().insert(x, str);
UpdateWidth(y);
//_AdjustFoldedSections( nBufferIndex, 1 );
InvalidateLines(y, y);
}else{
os::String tmp=buffer[ nBufferIndex ].text.str().substr(x);
buffer[nBufferIndex].text.erase(x, ~0);
buffer[nBufferIndex].text+=list[0];
if(nBufferIndex==buffer.size()-1){
for(uint a=1;a<list.size();++a){
buffer.push_back(Line());
buffer.back().text=list[a];
}
}else{
362
Wave OS project early developer manual
buffer_type::iterator iter;
for(uint a=1;a<list.size();++a){
//buffer.insert(&buffer[nBufferIndex+a], Line());
iter = buffer.begin() + nBufferIndex + a;
buffer.insert(iter, Line());
buffer[nBufferIndex+a].text=list[a];
}
}
buffer[nBufferIndex+list.size()-1].text+=tmp;
UpdateAllWidths();
InvalidateLines( y, buffer.size()-1 );
}
UpdateScrollbars();
eventBuffer |= CodeView::EI_CONTENT_CHANGED;
}
*str=buffer[top].text.const_str().substr(left);
*str+='\n';
for(uint a=top+1;a<bot;++a){
*str += buffer[a].text;
*str += '\n';
}
void InnerEdit::RemoveText( uint nLeft, uint nTop, uint nRight, uint nBot,
bool bAddUndo )
{
uint nBfrTop = min( _TranslateBufferIndex( nTop ), buffer.size() -
1 );
uint nBfrBot = min( _TranslateBufferIndex( nBot ), buffer.size() -
1 );
nLeft = min( nLeft, buffer[ nBfrTop ].text.size() );
nRight = min( nRight, buffer[ nBfrBot ].text.size() );
// _AdjustFoldedSections( nBfrTop, -1 );
InvalidateLines( nTop, nTop );
} else {
os::String cUndoStr;
if(bAddUndo)
cUndoStr = buffer[ nBfrTop ].text.str().substr( nLeft ) +
"\n";
364
Wave OS project early developer manual
if(bAddUndo)
AddUndoNode(UndoNode::REMOVED, cUndoStr, nLeft, nTop);
if(cursorY==nTop){
if(nCursorChar>nLeft){
nCursorChar=nLeft;
}
}else if(cursorY==nBot){
cursorY=nTop;
if(nCursorChar>nRight){
nCursorChar+=nLeft-nRight;
}else{
nCursorChar=nLeft;
}
}else if(cursorY>nBot){//after deleted area
cursorY-=nBot-nTop;
}else if(cursorY>nTop){//in deleted area
cursorY=nTop;
nCursorChar=nLeft;
}
UpdateScrollbars();
Invalidate();
}
lineBase=fh.ascender+fh.line_gap;
lineHeight=fh.ascender+fh.line_gap+fh.descender+1;
spaceWidth=f->GetStringWidth(" ");
Wave OS project early developer manual
if(f->GetDirection()!=os::FONT_LEFT_TO_RIGHT){
throw "Cannot use fonts with other directions than left-to-
right!";
}
UpdateBackBuffer();
UpdateScrollbars();
Invalidate();
Flush();
}
list.clear();
while(start<=line.size()){
end=line.const_str().find(splitter, start);
if(end==-1)
end=line.size();
list.push_back(line.const_str().substr(start, end-start));
start=end+1;
}
}
void InnerEdit::Activated(bool b)
{
InvalidateLines(cursorY, cursorY);
Flush();
if(!b){
eventBuffer |= CodeView::EI_FOCUS_LOST;
CommitEvents();
}
}
bool shift=modifiers&os::QUAL_SHIFT;
bool alt=modifiers&os::QUAL_ALT;
bool ctrl=modifiers&os::QUAL_CTRL;
bool dead=modifiers&os::QUAL_DEADKEY;
uint charY=_TranslateBufferIndex( cursorY );
if(strlen(rawstr)==1){
switch(rawstr[0]){
case ' ':
if(ctrl && !alt && !shift) {
if( _LineIsFolded( charY ) ) {
_UnfoldSection( charY );
366
Wave OS project early developer manual
break;
Undo();
ShowCursor();
goto done;
}
if(ctrl && !alt && shift){
if(readOnly)
break;
Redo();
ShowCursor();
goto done;
}
break;
}
}
switch(str[0]){
case 0:
break;
case os::VK_LEFT_ARROW:
if(alt && !ctrl)
ScrollLeft();
else if(!alt && ctrl){
MoveWordLeft(shift);
ShowCursor();
}else if(!alt && !ctrl){
MoveLeft(shift);
ShowCursor();
}
break;
case os::VK_RIGHT_ARROW:
if(alt && !ctrl)
ScrollRight();
else if(!alt && ctrl){
MoveWordRight(shift);
ShowCursor();
}else if(!alt && !ctrl){
MoveRight(shift);
ShowCursor();
}
break;
case os::VK_UP_ARROW:
if(alt)
ScrollUp();
else{
MoveUp(shift);
ShowCursor();
}
break;
case os::VK_DOWN_ARROW:
if(alt)
ScrollDown();
else{
MoveDown(shift);
ShowCursor();
}
break;
case os::VK_HOME:
if(ctrl)
MoveTop(shift);
else
368
Wave OS project early developer manual
MoveLineStart(shift);
ShowCursor();
break;
case os::VK_END:
if(ctrl)
MoveBottom(shift);
else
MoveLineEnd(shift);
ShowCursor();
break;
case os::VK_PAGE_UP:
if(alt)
ScrollPageUp();
else{
MovePageUp(shift);
ShowCursor();
}
break;
case os::VK_PAGE_DOWN:
if(alt)
ScrollPageDown();
else{
MovePageDown(shift);
ShowCursor();
}
break;
case os::VK_TAB:
if(readOnly)
break;
if(selectionValid){
IndentSelection(shift);
}else{
cursorX=min(cursorX, GetW(buffer[charY].text.size(),
charY));
if(useTab)
/***/ InsertText("\t", GetChar(cursorX, charY), cursorY);
else{
os::String tmp;
tmp.resize(tabSize, ' ');
InsertText(tmp, GetChar(cursorX, charY), cursorY);
}
ShowCursor();
}
break;
case os::VK_BACKSPACE:
if(readOnly)
break;
if(alt && !shift && !ctrl)
Undo();
else if(!alt){
if(selectionValid){
Del();
}else if(cursorY!=0 || (GetChar(cursorX, 0)!=0 &&
buffer[0].text.size()!=0)){
MoveLeft(false);
Del();
}
}
ShowCursor();
break;
Wave OS project early developer manual
case os::VK_DELETE:
if(readOnly)
break;
if(shift)
Cut();
else
Del();
ShowCursor();
break;
case os::VK_ENTER:
{
if(readOnly)
break;
if(selectionValid)
Del();
cursorX=min(cursorX, GetW(buffer[charY].text.size(),
charY));
uint chr=GetChar(cursorX, charY);
if(format){
InsertText(os::String("\n")+format-
>GetIndentString( buffer[charY].text.str().substr(0, chr),
useTab, tabSize), chr, cursorY);
}else{
InsertText("\n", chr, cursorY);
}
ShowCursor();
eventBuffer |= CodeView::EI_ENTER_PRESSED;
}
break;
case os::VK_INSERT:
if(shift && !ctrl){
if(readOnly)
break;
Paste();
ShowCursor();
}
if(!shift && ctrl){
Copy();
ShowCursor();
}
break;
case os::VK_ESCAPE:
eventBuffer |= CodeView::EI_ESC_PRESSED;
break;
case os::VK_FUNCTION_KEY:
break;
default:
if(readOnly)
break;
if(selectionValid)
Del();
370
Wave OS project early developer manual
done:
Flush();
CommitEvents();
}
off.y=off.y-3*p.y*lineHeight;
float max=buffer.size()*lineHeight-Height();
if(off.y<-max)
off.y=-max;
if(off.y>0.0f)
off.y=0.0f;
ScrollTo(off);
}
ClearSelection();
InvalidateLines(cursorY, cursorY);
cursorY=line;
cursorX=p.x - m_nMargin;
InvalidateLines(cursorY, cursorY);
ShowCursor();
Flush();
CommitEvents();
}
if(but&1)
mousePressed=false;
Wave OS project early developer manual
Flush();
CommitEvents();
}
}
InvalidateLines(cursorY, cursorY);
cursorY=min(y, buffer.size()-1);
cursorX=GetW(x, _TranslateBufferIndex( cursorY ) );
InvalidateLines(cursorY, cursorY);
ShowCursor();
PostMove(select);
}
372
Wave OS project early developer manual
if( !x ) {
if( cursorY > 0 ) {
--cursorY;
y = _TranslateBufferIndex( cursorY );
cursorX = GetW( buffer[y].text.size(), y );
InvalidateLines(cursorY, cursorY+1);
}
}else{
--x;
while(x>0 && !os::is_first_utf8_byte(buffer[y].text[x]))
--x;
cursorX=GetW(x, y);
InvalidateLines(cursorY, cursorY);
}
PostMove(select);
}
if(x==buffer[y].text.size()){
if(y<buffer.size()-1){
++cursorY;
y = _TranslateBufferIndex( cursorY );
cursorX=0;
InvalidateLines(cursorY-1, cursorY);
}
}else{
int len=os::utf8_char_length(buffer[y].text[x]);
cursorX=GetW(x+len, y);
InvalidateLines(cursorY, cursorY);
}
PostMove(select);
}
if(cursorY>0){
--cursorY;
InvalidateLines(cursorY, cursorY+1);
}
PostMove(select);
}
Wave OS project early developer manual
PostMove(select);
}
cursorX=0;
InvalidateLines(0, cursorY);
cursorY=0;
PostMove(select);
}
InvalidateLines(cursorY, buffer.size());
uint y = buffer.size()-1;
cursorY = _TranslateLineNumber( y );
cursorX=GetW(buffer[y].text.size(), y);
PostMove(select);
}
uint lines=((int)Height())/((int)lineHeight);
InvalidateLines(cursorY, cursorY);
if(lines>cursorY)
cursorY=0;
else
cursorY-=lines;
InvalidateLines(cursorY, cursorY);
PostMove(select);
}
uint lines=((int)Height())/((int)lineHeight);
InvalidateLines(cursorY, cursorY);
cursorY = min( _TranslateLineNumber( buffer.size()-1 ), cursorY +
lines );
374
Wave OS project early developer manual
InvalidateLines(cursorY, cursorY);
PostMove(select);
}
cursorX=0;
InvalidateLines(cursorY, cursorY);
PostMove(select);
}
PostMove(select);
}
if(x==0 || format==NULL)
MoveLeft(select);
else{
PreMove(select);
cursorX=GetW(format->GetPreviousWordLimit(buffer[y].text, x),
y);
InvalidateLines(cursorY, cursorY);
PostMove(select);
}
}
if(x==buffer[y].text.size() || format==NULL)
MoveRight(select);
else{
PreMove(select);
PostMove(select);
}
}
void InnerEdit::SetFormat(Format* f)
{
Wave OS project early developer manual
format=f;
if(format){
Reformat(0, buffer.size()-1);
}else{
for(uint a=0;a<buffer.size();++a)
buffer[a].style.resize(0);
}
}
void InnerEdit::UpdateScrollbars()
{
os::ScrollBar* sb = GetVScrollBar();
if( sb ) {
float h = Height();
uint nBufSize = _TranslateLineNumber( buffer.size() );
sb->SetSteps( lineHeight, h - lineHeight );
sb->SetMinMax( 0, max( 0.0f, lineHeight * nBufSize - h ) );
sb->SetProportion( h / ( lineHeight * nBufSize ) );
}
sb = GetHScrollBar();
if( sb ) {
float w = Width();
sb->SetSteps( spaceWidth, w - spaceWidth );
sb->SetMinMax(0, maxWidth + spaceWidth - w );
sb->SetProportion( w / ( maxWidth + spaceWidth ) );
}
}
void InnerEdit::ShowCursor()
{
const float vOffset = 5;
os::Point cScroll = GetScrollOffset();
os::Point cInitialScroll = cScroll;
float w = Width();
float h = Height();
376
Wave OS project early developer manual
uint dx=0;
/* if(buffer[y].text.size()>x){
dx=x-buffer[y].text.size();
x-=dx;
}
*/
uint first=0, last;
float w=0;
while(first<x){
last=first;
if(line[first]=='\t'){
float tab=spaceWidth*tabSize;
w=tab*ceil((w+1)/tab);
w+=GetStringWidth(line+first, last-first+1);
}
first=last+1;
}
// cout << "GetW:\t\t" << x << "\t" << y << "\t" << w+spaceWidth*dx <<
endl;
return w+spaceWidth*dx;
}
uint c=0;
uint max=buffer[y].text.size();
float x=0;
// cout << "GetChar:\t" << c << "\t" << y << "\t" << targetX << endl;
return c;
}
if(selectionValid){
uint oldy=selStart.y;
selStart.y=y;
selStart.x=x;
if(selectionValid){
uint oldy=selEnd.y;
selEnd.y=y;
selEnd.x=x;
378
Wave OS project early developer manual
selEnd.y=selStart.y=y;
selEnd.x=selStart.x=x;
selectionValid=true;
}
eventBuffer |= CodeView::EI_SELECTION_CHANGED;
}
void InnerEdit::ClearSelection()
{
if(selectionValid){
selectionValid=false;
InvalidateLines(min(selStart.y, selEnd.y), max(selStart.y,
selEnd.y));
}
eventBuffer |= CodeView::EI_SELECTION_CHANGED;
}
void InnerEdit::ScrollLeft()
{
os::Point p=GetScrollOffset();
p.x=min(0.0f, p.x+spaceWidth);
ScrollTo(p);
}
void InnerEdit::ScrollRight()
{
os::Point p=GetScrollOffset();
p.x-=spaceWidth;
ScrollTo(p);
}
void InnerEdit::ScrollUp()
{
os::Point p=GetScrollOffset();
p.y=min(0.0f, p.y+lineHeight);
ScrollTo(p);
}
void InnerEdit::ScrollDown()
{
os::Point p=GetScrollOffset();
p.y=max(-(buffer.size()*lineHeight-Height()), p.y-lineHeight);
if(p.y>0)
p.y=0;
ScrollTo(p);
}
void InnerEdit::ScrollPageUp()
{
os::Point p=GetScrollOffset();
ScrollTo( p );
Wave OS project early developer manual
void InnerEdit::ScrollPageDown()
{
os::Point p = GetScrollOffset();
ScrollTo( p );
}
void InnerEdit::UpdateBackBuffer()
{
if(backBM){
if(backView)
backBM->RemoveChild(backView);
delete backBM;
}
if(!backView)
backView=new os::View(os::Rect(), "");
backView->SetFrame(backBM->GetBounds());
os::Font* f=GetFont();
backView->SetFont(f);
backBM->AddChild(backView);
}
uint32 max=buffer.size()-1;
if(last>max)
last=max;
if(first>last)
first=last;
uint32 line=first;
CodeViewContext oldCookie, newCookie;
do{
oldCookie=buffer[line].cookie;
if(line==0)
newCookie = format->Parse(buffer[line].text,
buffer[line].style, CodeViewContext(0));
else
newCookie = format->Parse(buffer[line].text,
buffer[line].style, buffer[line-1].cookie);
buffer[line].cookie=newCookie;
++line;
}while(line<=max && (!(newCookie==oldCookie) || line<=last) );
380
Wave OS project early developer manual
InvalidateLines(first, line);
Flush();
}
os::Clipboard clip;
clip.Lock();
clip.Clear();
os::String tmp;
GetText(&tmp, selStart, selEnd);
clip.GetData()->AddString("text/plain", tmp);
clip.Commit();
clip.Unlock();
}
void InnerEdit::Paste()
{
os::Clipboard clip;
os::String str;
clip.Lock();
if(clip.GetData()->FindString("text/plain", &str)==0){
if(selectionValid)
Del();
void InnerEdit::Cut()
{
if(!selectionValid)
return;
Copy();
Del();
}
void InnerEdit::Del()
{
if(selectionValid) {
RemoveText(selStart, selEnd);
ClearSelection();
} else {
uint y = _TranslateBufferIndex( cursorY );
uint x = min( GetChar( cursorX, y ), buffer[y].text.size() );
if( x < buffer[y].text.size() ) {
RemoveText( x, cursorY, x +
os::utf8_char_length( buffer[y].text[x] ), cursorY );
}else if(cursorY<buffer.size()-1){
RemoveText( x, cursorY, 0, cursorY+1 );
}
}
}
Wave OS project early developer manual
buffer[y].text=line;
buffer[y].style.resize(0);
UpdateWidth(y);
InvalidateLines(y, y);
Reformat(y, y);
eventBuffer |= CodeView::EI_CONTENT_CHANGED;
}
void InnerEdit::SetTabSize(uint i)
{
uint y = _TranslateBufferIndex( cursorY );
uint chr = GetChar( cursorX, y );
tabSize = i;
cursorX = GetW( chr, y );
UpdateAllWidths();
Invalidate();
}
void InnerEdit::SetEnable(bool b)
{
if(b!=enabled){
enabled=b;
Invalidate();
}
}
void InnerEdit::SetReadOnly(bool b)
{
if(b!=readOnly){
readOnly=b;
Invalidate();
}
}
void InnerEdit::CommitEvents()
{
if(cursorX!=old_cursorX || cursorY!=old_cursorY)
eventBuffer|=CodeView::EI_CURSOR_MOVED;
old_cursorX=cursorX;
old_cursorY=cursorY;
382
Wave OS project early developer manual
size_t InnerEdit::GetLength()
{
size_t tmp=buffer.size();
if(tmp>0)
--tmp;
for(uint a=0;a<buffer.size();++a)
tmp+=buffer[a].text.size();
return tmp;
}
int InnerEdit::GetMaxUndoSize()
{
return maxUndo;
}
if(undoCurrent==NULL){
undoHead=undoTail=undoCurrent=node;
undoCount=1;
redoCount=0;
}else{
if(undoCurrent->next!=NULL){
UndoNode *tmp=undoCurrent->next;
while(tmp->next){
tmp=tmp->next;
delete tmp->previous;
}
delete tmp;
redoCount=0;
}
undoCurrent->next=node;
node->previous=undoCurrent;
undoCurrent=node;
undoTail=undoCurrent;
++undoCount;
}
while(undoCount>maxUndo){
undoHead=undoHead->next;
delete undoHead->previous;
undoHead->previous=NULL;
--undoCount;
}
}
Wave OS project early developer manual
void InnerEdit::ClearUndo()
{
if(!undoHead)
return;
while(undoHead->next){
undoHead=undoHead->next;
delete undoHead->previous;
}
delete undoHead;
undoHead=undoTail=undoCurrent=NULL;
undoCount=redoCount=0;
}
bool InnerEdit::UndoAvailable()
{
return undoCount>0;
}
bool InnerEdit::RedoAvailable()
{
return redoCount>0;
}
bool InnerEdit::Undo()
{
if(undoCurrent==NULL || undoCount==0)
return false;
switch(undoCurrent->mode){
case UndoNode::ADDED:
{
os::String& str=undoCurrent->text;
uint y=undoCurrent->y;
uint x=undoCurrent->x+str.size();
while( x >
buffer[ _TranslateBufferIndex(y) ].text.size() ) {
x -= buffer[ _TranslateBufferIndex(y) ].text.size()
+ 1;
++y;
}
384
Wave OS project early developer manual
if(undoCurrent->previous!=NULL)
undoCurrent=undoCurrent->previous;
--undoCount;
++redoCount;
return true;
}
bool InnerEdit::Redo()
{
if(undoCurrent==NULL || redoCount==0)
return false;
UndoNode* node=undoCurrent;
if(undoCount>0)
node=node->next;
switch(node->mode){
case UndoNode::REMOVED:
{
os::String& str=node->text;
uint y=node->y;
uint x=node->x+str.size();
while( x >
buffer[ _TranslateBufferIndex(y) ].text.size() ) {
x -= buffer[ _TranslateBufferIndex(y) ].text.size()
+ 1;
++y;
}
}
default:
assert(false);
}
if(undoCount>0)
undoCurrent=undoCurrent->next;
++undoCount;
--redoCount;
return true;
}
void InnerEdit::UpdateWidth(uint y)
{
float ow = buffer[y].w + m_nMargin;
float nw = GetW( buffer[y].text.size(), y ) + m_nMargin;
buffer[y].w=nw;
void InnerEdit::UpdateAllWidths()
{
maxWidth = 0;
for(uint a=0;a<buffer.size()-1;++a){
buffer[a].w=GetW(buffer[a].text.size(), a);
if(buffer[a].w>maxWidth)
maxWidth=buffer[a].w;
}
maxWidth += m_nMargin;
UpdateScrollbars();
}
assert(selectionValid);
selectionValid=false;
if(selStart.y>selEnd.y){
bot=selStart.y;
if(selStart.x==0)
--bot;
top=selEnd.y;
}else{
top=selStart.y;
bot=selEnd.y;
if(bot>top && selEnd.x==0)
--bot;
386
Wave OS project early developer manual
for(uint a=top;a<=bot;++a){
if(unindent){
const os::String &line=buffer[a].text;
if(line.size()==0)
continue;
if(line[0]=='\t'){
RemoveText(0, a, 1, a);
}else if(line[0]==' '){
uint len=max(tabSize, line.size());
uint spaces=1;
for(uint b=1;b<len;++b)
if(line[b]==' ')
++spaces;
else
break;
RemoveText(0, a, spaces, a);
}//else ignore
}else{//indent
if(useTab)
InsertText("\t", 0, a);
else{
os::String pad;
pad.resize(tabSize, ' ');
InsertText(pad, 0, a);
}
}
}
selectionValid=true;
selStart.y=top;
selStart.x=0;
selEnd.y=bot;
selEnd.x=buffer[bot].text.size();
float x=GetW(selEnd.x, bot);
if(cursorY!=bot || cursorX!=x)
eventBuffer |= CodeView::EI_CURSOR_MOVED;
cursorY=bot;
cursorX=x;
Reformat(top, bot);
InvalidateLines(top, bot);
eventBuffer |= CodeView::EI_CONTENT_CHANGED;
}
/** Look for foldable parts of code within the specified range and fold
them */
void InnerEdit::FoldSection( uint nFirst, uint nLast )
{
if( format == NULL ) return;
// cout << "FoldSection: " << nFirst << ", " << nLast << endl;
do {
nOldFold = nFoldLevel;
nFoldLevel = format->GetFoldLevel( buffer[ nLine ].text,
nOldFold );
if( nFoldLevel == 1 && nOldFold == 0 ) {
nFoldStart = nLine;
}
if( nFoldLevel == 0 && nOldFold == 1 ) {
// cout << "** _FoldSection: " << nFoldStart << ", " << nLine <<
endl;
if( nLine-1 > nFoldStart )
_FoldSection( nFoldStart, nLine-1 );
}
++nLine;
} while( nLine <= nMax && ( nFoldLevel > 0 || nLine <= nLast ) );
InvalidateLines( 0, buffer.size()-1 );
Flush();
}
return nLineIndex;
}
return nLineIndex;
}
388
Wave OS project early developer manual
return 0;
}
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
#ifndef _INNEREDIT_H_
#define _INNEREDIT_H_
#include <vector>
#include <gui/view.h>
#include <gui/control.h>
#include <gui/bitmap.h>
#include <gui/menu.h>
#include <util/looper.h>
#include <util/message.h>
#include "format.h"
namespace cv
{
class InnerEdit;
/**
* \internal
*/
class Line
{
public:
os::String text; /** Text on this line */
os::String style; /** Style numbers for each
character on this line */
CodeViewContext cookie; /** Used by the formatters */
float w; /** ? */
390
Wave OS project early developer manual
/**
* \internal
*/
class UndoNode
{
public:
enum {
ADDED,
REMOVED,
SET_LINE
};
UndoNode() {
next = 0;
previous = 0;
}
};
/**
* \internal
*/
class Fold
{
public:
uint32 nStart; /** First line in the fold
section */
uint32 nEnd; /** Last hidden line */
/**
* \internal
*/
class InnerEdit : public os::View
{
friend class CodeView;
private:
buffer_type buffer;
mutable list<Fold> cFoldedSections;
/* Line index = visible line number */
/* Buffer index = index in buffer */
uint _TranslateBufferIndex( uint32 nLineIndex ) const;
uint _TranslateLineNumber( uint32 nBufferIndex ) const;
void _FoldSection( uint32 nStart, uint32 nEnd );
void _UnfoldSection( uint32 nStart );
uint _LineIsFolded( uint32 nBufferIndex );
void _AdjustFoldedSections( uint nStart, int nLen );
Wave OS project early developer manual
os::Control* control;
uint32 eventMask;
uint32 eventBuffer;
bool mousePressed;
bool IcursorActive;
Format* format;
os::Bitmap* backBM;
os::View* backView;
void UpdateBackBuffer();
float maxWidth;
float lineHeight;
float lineBase;
float spaceWidth;
bool selectionValid;
os::IPoint selStart,
selEnd;
void UpdateScrollbars();
void UpdateWidth(uint);
void UpdateAllWidths();
void InvalidateLines(int, int);
void PreMove(bool);
void PostMove(bool);
bool enabled;
bool readOnly;
392
Wave OS project early developer manual
os::Menu* m_pcContextMenu;
os::Color32_s sHighlight;
os::Color32_s m_sLineNumberFg;
os::Color32_s m_sLineNumberBg;
os::Color32_s m_sLineBackColor;
public:
InnerEdit(os::Control* c);
~InnerEdit();
void SetTabSize(uint);
uint GetTabSize() const{ return tabSize; }
void SetUseTab(bool b){ useTab=b; }
bool GetUseTab(){ return useTab; }
void ScrollLeft();
Wave OS project early developer manual
void ScrollRight();
void ScrollUp();
void ScrollDown();
void ScrollPageUp();
void ScrollPageDown();
size_t GetLength();
void CommitEvents();
void SetEventMask( uint32 nMask ) { eventMask = nMask; }
uint32 GetEventMask() { return eventMask; }
394
Wave OS project early developer manual
os::Color32_s GetHighlightColor()
{
return sHighlight;
}
os::Color32_s GetLineNumberBgColor()
{
return m_sLineNumberBg;
}
os::Color32_s GetLineNumberFgColor()
{
return m_sLineNumberFg;
}
os::Color32_s GetLineBackColor()
{
return m_sLineBackColor;
}
};
} /* namespace cv */
#endif
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. 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 <sysexits.h>
#include "argp.h"
/* The exit status that argp will use when exiting due to a parsing error.
If not defined or set by the user program, this defaults to EX_USAGE
from
<sysexits.h>. */
error_t argp_err_exit_status = EX_USAGE;
/* Word-wrapping and line-truncating streams
Copyright (C) 1997, 1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
396
Wave OS project early developer manual
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. 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 <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <ctype.h>
#include "argp-fmtstream.h"
#include "argp-namefrob.h"
#ifndef ARGP_FMTSTREAM_USE_LINEWRAP
#ifndef isblank
#define isblank(ch) ((ch)==' ' || (ch)=='\t')
#endif
fs->lmargin = lmargin;
fs->rmargin = rmargin;
fs->wmargin = wmargin;
fs->point_col = 0;
fs->point_offs = 0;
return fs;
}
#ifdef weak_alias
weak_alias (__argp_make_fmtstream, argp_make_fmtstream)
#endif
/* Flush FS to its stream, and free it (but don't close the stream). */
void
__argp_fmtstream_free (argp_fmtstream_t fs)
{
__argp_fmtstream_update (fs);
if (fs->p > fs->buf)
fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
free (fs->buf);
free (fs);
}
#ifdef weak_alias
weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
#endif
398
Wave OS project early developer manual
/* Process FS's buffer so that line wrapping is done from POINT_OFFS to the
end of its buffer. This code is mostly from glibc stdio/linewrap.c. */
void
__argp_fmtstream_update (argp_fmtstream_t fs)
{
char *buf, *nl;
size_t len;
if (fs->point_col < 0)
fs->point_col = 0;
if (!nl)
{
/* The buffer ends in a partial line. */
if (fs->wmargin < 0)
{
/* Truncate the line by overwriting the excess with the
newline and anything after it in the buffer. */
if (nl < fs->p)
{
memmove (buf + (r - fs->point_col), nl, fs->p - nl);
fs->p -= buf + (r - fs->point_col) - nl;
/* Reset point for the next line and start scanning it. */
fs->point_col = 0;
buf += r + 1; /* Skip full line plus \n. */
}
else
{
/* The buffer ends with a partial line that is beyond the
maximum line width. Advance point for the characters
written, and discard those past the max from the buffer. */
fs->point_col += len;
fs->p -= fs->point_col - r;
break;
}
}
else
{
/* Do word wrap. Go to the column just past the maximum line
width and scan back for the beginning of the word there.
Then insert a line break. */
p = buf + (r + 1 - fs->point_col);
while (p >= buf && !isblank (*p))
--p;
nextline = p + 1; /* This will begin the next line. */
400
Wave OS project early developer manual
p = buf + (r + 1 - fs->point_col);
/* Find the end of the long word. */
do
++p;
while (p < nl && !isblank (*p));
if (p == nl)
{
/* It already ends a line. No fussing required. */
fs->point_col = 0;
buf = nl + 1;
continue;
}
/* We will move the newline to replace the first blank. */
nl = p;
/* Swallow separating blanks. */
do
++p;
while (isblank (*p));
/* The next line will start here. */
nextline = p;
}
else
for (i = 0; i < fs->wmargin; ++i)
putc_unlocked (' ', fs->stream);
/* Copy the tail of the original buffer into the current buffer
position. */
if (nl < nextline)
memmove (nl, nextline, buf + len - nextline);
len -= nextline - buf;
/* Reset the counter of what has been output this line. If wmargin
is 0, we want to avoid the lmargin getting added, so we set
point_col to a magic value of -1 in that case. */
fs->point_col = fs->wmargin ? fs->wmargin : -1;
}
}
402
Wave OS project early developer manual
/* Ensure that FS has space for AMOUNT more bytes in its buffer, either by
growing the buffer, or by flushing it. True is returned iff we succeed.
*/
int
__argp_fmtstream_ensure (struct argp_fmtstream *fs, size_t amount)
{
if ((size_t) (fs->end - fs->p) < amount)
{
ssize_t wrote;
if (! new_buf)
{
__set_errno (ENOMEM);
return 0;
}
fs->buf = new_buf;
fs->end = new_buf + new_size;
fs->p = fs->buf;
}
}
return 1;
}
Wave OS project early developer manual
ssize_t
__argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
{
int out;
size_t size_guess = PRINTF_SIZE_GUESS; /* How much space to reserve. */
do
{
va_list args;
fs->p += out;
return out;
}
#ifdef weak_alias
weak_alias (__argp_fmtstream_printf, argp_fmtstream_printf)
#endif
#endif /* !ARGP_FMTSTREAM_USE_LINEWRAP */
/* Word-wrapping and line-truncating streams.
Copyright (C) 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#ifndef _ARGP_FMTSTREAM_H
#define _ARGP_FMTSTREAM_H
404
Wave OS project early developer manual
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef ARGP_FMTSTREAM_USE_LINEWRAP
/* Just be a simple wrapper for line_wrap_stream; the semantics are
*slightly* different, as line_wrap_stream doesn't actually make a new
object, it just modifies the given stream (reversibly) to do
line-wrapping. Since we control who uses this code, it doesn't matter.
*/
#include <linewrap.h>
#else /* !ARGP_FMTSTREAM_USE_LINEWRAP */
/* Guess we have to define our own version. */
#ifndef __const
#define __const const
#endif
Wave OS project early developer manual
struct argp_fmtstream
{
FILE *stream; /* The stream we're outputting to. */
/* Point in buffer to which we've processed for wrapping, but not output.
*/
size_t point_offs;
/* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin.
*/
ssize_t point_col;
/* Flush __FS to its stream, and free it (but don't close the stream). */
extern void __argp_fmtstream_free (argp_fmtstream_t __fs);
extern void argp_fmtstream_free (argp_fmtstream_t __fs);
406
Wave OS project early developer manual
Wave OS project early developer manual
/* Set __FS's left margin to LMARGIN and return the old value. */
extern size_t argp_fmtstream_set_lmargin (argp_fmtstream_t __fs,
size_t __lmargin);
extern size_t __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs,
size_t __lmargin);
/* Set __FS's right margin to __RMARGIN and return the old value. */
extern size_t argp_fmtstream_set_rmargin (argp_fmtstream_t __fs,
size_t __rmargin);
extern size_t __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs,
size_t __rmargin);
/* Set __FS's wrap margin to __WMARGIN and return the old value. */
extern size_t argp_fmtstream_set_wmargin (argp_fmtstream_t __fs,
size_t __wmargin);
extern size_t __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs,
size_t __wmargin);
/* Internal routines. */
extern void _argp_fmtstream_update (argp_fmtstream_t __fs);
extern void __argp_fmtstream_update (argp_fmtstream_t __fs);
extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t
__amount);
408
Wave OS project early developer manual
#ifdef __OPTIMIZE__
/* Inline versions of above routines. */
#if !_LIBC
#define __argp_fmtstream_putc argp_fmtstream_putc
#define __argp_fmtstream_puts argp_fmtstream_puts
#define __argp_fmtstream_write argp_fmtstream_write
#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin
#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin
#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin
#define __argp_fmtstream_point argp_fmtstream_point
#define __argp_fmtstream_update _argp_fmtstream_update
#define __argp_fmtstream_ensure _argp_fmtstream_ensure
#endif
#ifndef ARGP_FS_EI
#define ARGP_FS_EI extern inline
#endif
ARGP_FS_EI size_t
__argp_fmtstream_write (argp_fmtstream_t __fs,
__const char *__str, size_t __len)
{
if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs,
__len))
{
memcpy (__fs->p, __str, __len);
__fs->p += __len;
return __len;
}
else
return 0;
}
ARGP_FS_EI int
__argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str)
{
size_t __len = strlen (__str);
if (__len)
{
size_t __wrote = __argp_fmtstream_write (__fs, __str, __len);
return __wrote == __len ? 0 : -1;
}
else
return 0;
}
ARGP_FS_EI int
__argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch)
{
if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1))
return *__fs->p++ = __ch;
else
return EOF;
}
/* Set __FS's left margin to __LMARGIN and return the old value. */
ARGP_FS_EI size_t
__argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin)
{
size_t __old;
Wave OS project early developer manual
/* Set __FS's right margin to __RMARGIN and return the old value. */
ARGP_FS_EI size_t
__argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin)
{
size_t __old;
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
__argp_fmtstream_update (__fs);
__old = __fs->rmargin;
__fs->rmargin = __rmargin;
return __old;
}
/* Set FS's wrap margin to __WMARGIN and return the old value. */
ARGP_FS_EI size_t
__argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin)
{
size_t __old;
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
__argp_fmtstream_update (__fs);
__old = __fs->wmargin;
__fs->wmargin = __wmargin;
return __old;
}
#if !_LIBC
#undef __argp_fmtstream_putc
#undef __argp_fmtstream_puts
#undef __argp_fmtstream_write
#undef __argp_fmtstream_set_lmargin
#undef __argp_fmtstream_set_rmargin
#undef __argp_fmtstream_set_wmargin
#undef __argp_fmtstream_point
#undef __argp_fmtstream_update
#undef __argp_fmtstream_ensure
#endif
#endif /* __OPTIMIZE__ */
#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */
#endif /* argp-fmtstream.h */
/* Hierarchial argument parsing help output
Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation,
Inc.
This file is part of the GNU C Library.
410
Wave OS project early developer manual
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef alloca
# ifdef __GNUC__
# define alloca __builtin_alloca
# define HAVE_ALLOCA 1
# else
# if defined HAVE_ALLOCA_H || defined _LIBC
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca
char *alloca ();
# endif
# endif
# endif
# endif
#endif
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
#include <malloc.h>
#include <ctype.h>
#ifndef _
/* This is for other GNU distributions with internationalized messages. */
# ifdef HAVE_LIBINTL_H
# include <libintl.h>
# else
# define dgettext(domain, msgid) (msgid)
# endif
#endif
Wave OS project early developer manual
#ifdef USE_IN_LIBIO
# define flockfile(s) _IO_flockfile (s)
# define funlockfile(s) _IO_funlockfile (s)
#endif
#include "argp.h"
#include "argp-fmtstream.h"
#include "argp-namefrob.h"
412
Wave OS project early developer manual
/* Default parameters. */
#define DUP_ARGS 0 /* True if option argument can be duplicated.
*/
#define DUP_ARGS_NOTE 1 /* True to print a note about duplicate args.
*/
#define SHORT_OPT_COL 2 /* column in which short options start */
#define LONG_OPT_COL 6 /* column in which long options start */
#define DOC_OPT_COL 2 /* column in which doc options start */
#define OPT_DOC_COL 29 /* column in which option text starts */
#define HEADER_COL 1 /* column in which group headers are printed
*/
#define USAGE_INDENT 12 /* indentation of wrapped usage lines */
#define RMARGIN 79 /* right margin used for wrapping */
/* This is a global variable, as user options are only ever read once. */
static struct uparams uparams = {
DUP_ARGS, DUP_ARGS_NOTE,
SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL,
USAGE_INDENT, RMARGIN,
0
};
struct uparam_name
{
const char *name; /* User name. */
int is_bool; /* Whether it's `boolean'. */
size_t uparams_offs; /* Location of the (int) field in UPARAMS.
*/
};
if (var)
/* Parse var. */
while (*var)
{
SKIPWS (var);
if (isalpha (*var))
{
size_t var_len;
const struct uparam_name *un;
int unspec = 0, val = 0;
const char *arg = var;
SKIPWS (arg);
if (unspec)
{
414
Wave OS project early developer manual
var = arg;
if (*var == ',')
var++;
}
else if (*var)
{
__argp_failure (state, 0, 0,
dgettext (state->root_argp->argp_domain,
"Garbage in ARGP_HELP_FMT: %s"), var);
break;
}
}
}
Wave OS project early developer manual
416
Wave OS project early developer manual
/*
The help format for a particular option is like:
The struct argp_option array for the above could look like:
{
{"pid", 'p', "PID", 0, "List the process PID"},
{"pgrp", OPT_PGRP, "PGRP", 0, "List processes in the process
group PGRP"},
{"no-parent", 'P', 0, 0, "Include processes without
parents"},
{0, 'x', 0, OPTION_ALIAS},
{"all-fields",'Q', 0, 0, "Don't elide unusable fields
(normally"
" if there's some reason ps can't"
" print a field for any process, it's"
" removed from the output
entirely)" },
{"reverse", 'r', 0, 0, "Reverse the order of any sort"},
{"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS},
{"session", OPT_SESS, "SID", OPTION_ARG_OPTIONAL,
"Add the processes from the
session"
" SID (which defaults to the sid of"
" the current process)" },
Wave OS project early developer manual
{0}
}
*/
418
Wave OS project early developer manual
struct hol_entry
{
/* First option. */
const struct argp_option *opt;
/* Number of options (including aliases). */
unsigned num;
/* Used to order clusters within the same group with the same parent,
according to the order in which they occured in the parent argp's
child
list. */
int index;
/* How to sort this cluster with respect to options and other clusters at
the
same depth (clusters always follow options in the same group). */
int group;
420
Wave OS project early developer manual
them
possible. */
struct hol_cluster *next;
};
assert (hol);
hol->num_entries = 0;
hol->clusters = 0;
if (opts)
{
int cur_group = 0;
do
{
entry->num++;
if (oshort (o) && ! find_char (o->key, hol->short_options, so))
/* O has a valid short option which hasn't already been used.*/
*so++ = o->key;
422
Wave OS project early developer manual
o++;
}
while (! oend (o) && oalias (o));
}
*so = '\0'; /* null terminated so we can find the length */
}
return hol;
}
Wave OS project early developer manual
/* Add a new cluster to HOL, with the given GROUP and HEADER (taken from
the
associated argp child list entry), INDEX, and PARENT, and return a
pointer
to it. ARGP is the argp that this cluster results from. */
static struct hol_cluster *
hol_add_cluster (struct hol *hol, int group, const char *header, int index,
struct hol_cluster *parent, const struct argp *argp)
{
struct hol_cluster *cl = malloc (sizeof (struct hol_cluster));
if (cl)
{
cl->group = group;
cl->header = header;
cl->index = index;
cl->parent = parent;
cl->argp = argp;
cl->depth = parent ? parent->depth + 1 : 0;
cl->next = hol->clusters;
hol->clusters = cl;
}
return cl;
}
424
Wave OS project early developer manual
while (cl)
{
struct hol_cluster *next = cl->next;
free (cl);
cl = next;
}
if (hol->num_entries > 0)
{
free (hol->entries);
free (hol->short_options);
}
free (hol);
}
Wave OS project early developer manual
for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
if (oshort (opt) && *so == opt->key)
{
if (!oalias (opt))
real = opt;
if (ovisible (opt))
val = (*func)(opt, real, domain, cookie);
so++;
}
return val;
}
for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
if (opt->name)
{
if (!oalias (opt))
real = opt;
if (ovisible (opt))
val = (*func)(opt, real, domain, cookie);
}
return val;
}
426
Wave OS project early developer manual
/* Returns the entry in HOL with the long option name NAME, or 0 if there
is
none. */
static struct hol_entry *
hol_find_entry (struct hol *hol, const char *name)
{
struct hol_entry *entry = hol->entries;
unsigned num_entries = hol->num_entries;
entry++;
}
return 0;
}
Wave OS project early developer manual
/* If an entry with the long option NAME occurs in HOL, set it's special
sort position to GROUP. */
static void
hol_set_group (struct hol *hol, const char *name, int group)
{
struct hol_entry *entry = hol_find_entry (hol, name);
if (entry)
entry->group = group;
}
428
Wave OS project early developer manual
/* Compare clusters CL1 & CL2 by the order that they should appear in
output. */
static int
hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster
*cl2)
{
/* If one cluster is deeper than the other, use its ancestor at the same
level, so that finding the common ancestor is straightforward. */
while (cl1->depth < cl2->depth)
cl1 = cl1->parent;
while (cl2->depth < cl1->depth)
cl2 = cl2->parent;
/* Now reduce both clusters to their ancestors at the point where both
have
a common parent; these can be directly compared. */
while (cl1->parent != cl2->parent)
cl1 = cl1->parent, cl2 = cl2->parent;
/* Return the ancestor of CL that's just below the root (i.e., has a parent
of 0). */
static struct hol_cluster *
hol_cluster_base (struct hol_cluster *cl)
{
while (cl->parent)
cl = cl->parent;
return cl;
}
/* Order ENTRY1 & ENTRY2 by the order which they should appear in a help
listing. */
static int
hol_entry_cmp (const struct hol_entry *entry1,
const struct hol_entry *entry2)
{
/* The group numbers by which the entries should be ordered; if either is
in a cluster, then this is just the group within the cluster. */
int group1 = entry1->group, group2 = entry2->group;
if (entry1->cluster != entry2->cluster)
{
/* The entries are not within the same cluster, so we can't compare
them
directly, we have to use the appropiate clustering level too. */
if (! entry1->cluster)
/* ENTRY1 is at the `base level', not in a cluster, so we have to
compare it's group number with that of the base cluster in which
ENTRY2 resides. Note that if they're in the same group, the
clustered option always comes laster. */
return group_cmp (group1, hol_cluster_base (entry2->cluster)->group,
-1);
else if (! entry2->cluster)
/* Likewise, but ENTRY2's not in a cluster. */
return group_cmp (hol_cluster_base (entry1->cluster)->group, group2,
1);
else
/* Both entries are in clusters, we can just compare the clusters.
*/
return hol_cluster_cmp (entry1->cluster, entry2->cluster);
}
else if (group1 == group2)
/* The entries are both in the same cluster and group, so compare them
alphabetically. */
{
int short1 = hol_entry_first_short (entry1);
int short2 = hol_entry_first_short (entry2);
int doc1 = odoc (entry1->opt);
int doc2 = odoc (entry2->opt);
const char *long1 = hol_entry_first_long (entry1);
const char *long2 = hol_entry_first_long (entry2);
430
Wave OS project early developer manual
if (doc1)
doc1 = canon_doc_option (&long1);
if (doc2)
doc2 = canon_doc_option (&long2);
if (doc1 != doc2)
/* `documentation' options always follow normal options (or
documentation options that *look* like normal options). */
return doc1 - doc2;
else if (!short1 && !short2 && long1 && long2)
/* Only long options. */
return __strcasecmp (long1, long2);
else
/* Compare short/short, long/short, short/long, using the first
character of long options. Entries without *any* valid
options (such as options with OPTION_HIDDEN set) will be put
first, but as they're not displayed, it doesn't matter where
they are. */
{
char first1 = short1 ? short1 : long1 ? *long1 : 0;
char first2 = short2 ? short2 : long2 ? *long2 : 0;
#ifdef _tolower
int lower_cmp = _tolower (first1) - _tolower (first2);
#else
int lower_cmp = tolower (first1) - tolower (first2);
#endif
/* Compare ignoring case, except when the options are both the
same letter, in which case lower-case always comes first. */
return lower_cmp ? lower_cmp : first2 - first1;
}
}
else
/* Within the same cluster, but not the same group, so just compare
groups. */
return group_cmp (group1, group2, 0);
}
/* Sort HOL by group and alphabetically by option name (with short options
taking precedence over long). Since the sorting is for display purposes
only, the shadowing of options isn't effected. */
static void
hol_sort (struct hol *hol)
{
if (hol->num_entries > 0)
qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry),
hol_entry_qcmp);
}
Wave OS project early developer manual
/* Merge entries. */
if (more->num_entries > 0)
{
if (hol->num_entries == 0)
{
hol->num_entries = more->num_entries;
hol->entries = more->entries;
hol->short_options = more->short_options;
more->num_entries = 0; /* Mark MORE's fields as invalid. */
}
else
/* Append the entries in MORE to those in HOL, taking care to only
add
non-shadowed SHORT_OPTIONS values. */
{
unsigned left;
char *so, *more_so;
struct hol_entry *e;
unsigned num_entries = hol->num_entries + more->num_entries;
struct hol_entry *entries =
malloc (num_entries * sizeof (struct hol_entry));
unsigned hol_so_len = strlen (hol->short_options);
char *short_options =
malloc (hol_so_len + strlen (more->short_options) + 1);
/* Now add the short options from MORE, fixing up its entries
too. */
so = short_options + hol_so_len;
more_so = more->short_options;
for (left = more->num_entries; left > 0; e++, left--)
{
int opts_left;
const struct argp_option *opt;
e->short_options = so;
432
Wave OS project early developer manual
*so = '\0';
free (hol->entries);
free (hol->short_options);
hol->entries = entries;
hol->num_entries = num_entries;
hol->short_options = short_options;
}
}
hol_free (more);
}
Wave OS project early developer manual
434
Wave OS project early developer manual
/* Some state used while printing a help entry (used to communicate with
helper functions). See the doc for hol_entry_help for more info, as
most
of the fields are copied from its arguments. */
struct pentry_state
{
const struct hol_entry *entry;
argp_fmtstream_t stream;
struct hol_help_state *hhstate;
/* Prints STR as a header line, with the margin lines set appropiately, and
notes the fact that groups should be separated with a blank line. ARGP
is
the argp that should dictate any user doc filtering to take place. Note
that the previous wrap margin isn't restored, but the left margin is
reset
to 0. */
static void
print_header (const char *str, const struct argp *argp,
struct pentry_state *pest)
Wave OS project early developer manual
{
const char *tstr = dgettext (argp->argp_domain, str);
const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest-
>state);
if (fstr)
{
if (*fstr)
{
if (pest->hhstate->prev_entry)
/* Precede with a blank line. */
__argp_fmtstream_putc (pest->stream, '\n');
indent_to (pest->stream, uparams.header_col);
__argp_fmtstream_set_lmargin (pest->stream, uparams.header_col);
__argp_fmtstream_set_wmargin (pest->stream, uparams.header_col);
__argp_fmtstream_puts (pest->stream, fstr);
__argp_fmtstream_set_lmargin (pest->stream, 0);
__argp_fmtstream_putc (pest->stream, '\n');
}
if (fstr != tstr)
free ((char *) fstr);
}
/* Inserts a comma if this isn't the first item on the line, and then makes
sure we're at least to column COL. If this *is* the first item on a
line,
prints any pending whitespace/headers that should precede this line.
Also
clears FIRST. */
static void
comma (unsigned col, struct pentry_state *pest)
{
if (pest->first)
{
const struct hol_entry *pe = pest->hhstate->prev_entry;
const struct hol_cluster *cl = pest->entry->cluster;
pest->first = 0;
}
436
Wave OS project early developer manual
else
__argp_fmtstream_puts (pest->stream, ", ");
if (! odoc (real))
for (opt = real, num = entry->num; num > 0; opt++, num--)
if (opt->name && ovisible (opt))
{
have_long_opt = 1;
break;
}
438
Wave OS project early developer manual
}
}
else
/* A real long option. */
{
int first_long_opt = 1;
if (pest.first)
{
/* Didn't print any switches, what's up? */
if (!oshort (real) && !real->name)
/* This is a group header, print it nicely. */
print_header (real->doc, entry->argp, &pest);
else
/* Just a totally shadowed option or null header; print nothing. */
goto cleanup; /* Just return, after cleaning up. */
}
else
{
const char *tstr = real->doc ? dgettext (state->root_argp-
>argp_domain,
real->doc) : 0;
const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
if (fstr && *fstr)
{
unsigned int col = __argp_fmtstream_point (stream);
hhstate->prev_entry = entry;
cleanup:
__argp_fmtstream_set_lmargin (stream, old_lm);
__argp_fmtstream_set_wmargin (stream, old_wm);
}
440
Wave OS project early developer manual
/* If OPT is a short option without an arg, append its key to the string
pointer pointer to by COOKIE, and advance the pointer. */
static int
add_argless_short_opt (const struct argp_option *opt,
const struct argp_option *real,
const char *domain, void *cookie)
{
char **snao_end = cookie;
if (!(opt->arg || real->arg)
&& !((opt->flags | real->flags) & OPTION_NO_USAGE))
*(*snao_end)++ = opt->key;
return 0;
}
/* If OPT is a short option with an arg, output a usage entry for it to the
stream pointed at by COOKIE. */
static int
usage_argful_short_opt (const struct argp_option *opt,
const struct argp_option *real,
const char *domain, void *cookie)
{
argp_fmtstream_t stream = cookie;
const char *arg = opt->arg;
int flags = opt->flags | real->flags;
if (! arg)
arg = real->arg;
return 0;
}
/* Output a usage entry for the long option opt to the stream pointed at by
COOKIE. */
static int
usage_long_opt (const struct argp_option *opt,
const struct argp_option *real,
const char *domain, void *cookie)
{
argp_fmtstream_t stream = cookie;
const char *arg = opt->arg;
int flags = opt->flags | real->flags;
if (! arg)
442
Wave OS project early developer manual
arg = real->arg;
return 0;
}
Wave OS project early developer manual
444
Wave OS project early developer manual
/* Calculate how many different levels with alternative args strings exist
in
ARGP. */
static size_t
argp_args_levels (const struct argp *argp)
{
size_t levels = 0;
const struct argp_child *child = argp->children;
if (child)
while (child->argp)
levels += argp_args_levels ((child++)->argp);
return levels;
}
/* Print all the non-option args documented in ARGP to STREAM. Any output
is
preceded by a space. LEVELS is a pointer to a byte vector the length
returned by argp_args_levels; it should be initialized to zero, and
updated by this routine for the next call if ADVANCE is true. True is
returned as long as there are more patterns to output. */
static int
argp_args_usage (const struct argp *argp, const struct argp_state *state,
char **levels, int advance, argp_fmtstream_t stream)
{
char *our_level = *levels;
int multiple = 0;
const struct argp_child *child = argp->children;
const char *tdoc = dgettext (argp->argp_domain, argp->args_doc), *nl = 0;
const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp,
state);
if (fdoc)
{
const char *cp = fdoc;
nl = __strchrnul (cp, '\n');
if (*nl != '\0')
/* This is a `multi-level' args doc; advance to the correct position
as determined by our state in LEVELS, and update LEVELS. */
{
int i;
multiple = 1;
for (i = 0; i < *our_level; i++)
cp = nl + 1, nl = __strchrnul (cp, '\n');
(*levels)++;
}
446
Wave OS project early developer manual
if (child)
while (child->argp)
advance = !argp_args_usage ((child++)->argp, state, levels, advance,
stream);
return !advance;
}
Wave OS project early developer manual
if (doc)
{
char *vt = strchr (doc, '\v');
inp_text = post ? (vt ? vt + 1 : 0) : doc;
inp_text_limit = (!post && vt) ? (vt - doc) : 0;
}
else
inp_text = 0;
if (argp->help_filter)
/* We have to filter the doc strings. */
{
if (inp_text_limit)
/* Copy INP_TEXT so that it's nul-terminated. */
inp_text = __strndup (inp_text, inp_text_limit);
input = __argp_input (argp, state);
text =
(*argp->help_filter) (post
? ARGP_KEY_HELP_POST_DOC
: ARGP_KEY_HELP_PRE_DOC,
inp_text, input);
}
else
text = (const char *) inp_text;
if (text)
{
if (pre_blank)
__argp_fmtstream_putc (stream, '\n');
448
Wave OS project early developer manual
anything = 1;
}
if (child)
while (child->argp && !(first_only && anything))
anything |=
argp_doc ((child++)->argp, state,
post, anything || pre_blank, first_only,
stream);
return anything;
}
Wave OS project early developer manual
if (! stream)
return;
flockfile (stream);
if (! uparams.valid)
fill_in_uparams (state);
hol_sort (hol);
}
do
{
int old_lm;
int old_wm = __argp_fmtstream_set_wmargin (fs,
uparams.usage_indent);
char *levels = pattern_levels;
if (first_pattern)
__argp_fmtstream_printf (fs, "%s %s",
dgettext (argp->argp_domain, "Usage:"),
name);
450
Wave OS project early developer manual
else
__argp_fmtstream_printf (fs, "%s %s",
dgettext (argp->argp_domain, " or: "),
name);
first_pattern = 0;
}
while (more_patterns);
}
funlockfile (stream);
if (hol)
hol_free (hol);
__argp_fmtstream_free (fs);
}
452
Wave OS project early developer manual
/* Output a usage message for ARGP to STREAM. FLAGS are from the set
ARGP_HELP_*. NAME is what to use wherever a `program name' is needed.
*/
void __argp_help (const struct argp *argp, FILE *stream,
unsigned flags, char *name)
{
_help (argp, 0, stream, flags, name);
}
#ifdef weak_alias
weak_alias (__argp_help, argp_help)
#endif
/* If appropriate, print the printf string FMT and following args, preceded
by the program name and `:', to stderr, and followed by a `Try ...
--help'
message, then exit (1). */
void
__argp_error (const struct argp_state *state, const char *fmt, ...)
{
if (!state || !(state->flags & ARGP_NO_ERRS))
{
FILE *stream = state ? state->err_stream : stderr;
if (stream)
{
va_list ap;
flockfile (stream);
funlockfile (stream);
}
}
}
#ifdef weak_alias
weak_alias (__argp_error, argp_error)
#endif
454
Wave OS project early developer manual
if (stream)
{
flockfile (stream);
if (fmt)
{
va_list ap;
if (errnum)
{
putc_unlocked (':', stream);
putc_unlocked (' ', stream);
fputs (strerror (errnum), stream);
}
funlockfile (stream);
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#if !_LIBC
/* This code is written for inclusion in gnu-libc, and uses names in the
namespace reserved for libc. If we're not compiling in libc, define
those
names to be the normal ones instead. */
/* argp-parse functions */
#undef __argp_parse
#define __argp_parse argp_parse
#undef __option_is_end
#define __option_is_end _option_is_end
#undef __option_is_short
#define __option_is_short _option_is_short
#undef __argp_input
#define __argp_input _argp_input
/* argp-help functions */
#undef __argp_help
#define __argp_help argp_help
#undef __argp_error
#define __argp_error argp_error
#undef __argp_failure
#define __argp_failure argp_failure
#undef __argp_state_help
#define __argp_state_help argp_state_help
#undef __argp_usage
#define __argp_usage argp_usage
/* argp-fmtstream functions */
#undef __argp_make_fmtstream
#define __argp_make_fmtstream argp_make_fmtstream
#undef __argp_fmtstream_free
#define __argp_fmtstream_free argp_fmtstream_free
#undef __argp_fmtstream_putc
#define __argp_fmtstream_putc argp_fmtstream_putc
#undef __argp_fmtstream_puts
#define __argp_fmtstream_puts argp_fmtstream_puts
#undef __argp_fmtstream_write
#define __argp_fmtstream_write argp_fmtstream_write
#undef __argp_fmtstream_printf
#define __argp_fmtstream_printf argp_fmtstream_printf
#undef __argp_fmtstream_set_lmargin
#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin
#undef __argp_fmtstream_set_rmargin
#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin
456
Wave OS project early developer manual
#undef __argp_fmtstream_set_wmargin
#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin
#undef __argp_fmtstream_point
#define __argp_fmtstream_point argp_fmtstream_point
#undef __argp_fmtstream_update
#define __argp_fmtstream_update _argp_fmtstream_update
#undef __argp_fmtstream_ensure
#define __argp_fmtstream_ensure _argp_fmtstream_ensure
#undef __argp_fmtstream_lmargin
#define __argp_fmtstream_lmargin argp_fmtstream_lmargin
#undef __argp_fmtstream_rmargin
#define __argp_fmtstream_rmargin argp_fmtstream_rmargin
#undef __argp_fmtstream_wmargin
#define __argp_fmtstream_wmargin argp_fmtstream_wmargin
#endif /* !_LIBC */
#ifndef __set_errno
#define __set_errno(e) (errno = (e))
#endif
/* Hierarchial argument parsing, layered over getopt
Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation,
Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. 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 <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <getopt.h>
#ifndef _
/* This is for other GNU distributions with internationalized messages.
Wave OS project early developer manual
#if _LIBC - 0
#include <bits/libc-lock.h>
#else
#ifdef HAVE_CTHREADS_H
#include <cthreads.h>
#endif
#endif /* _LIBC */
#include "argp.h"
#include "argp-namefrob.h"
/* The number of bits we steal in a long-option value for our own use. */
#define GROUP_BITS CHAR_BIT
458
Wave OS project early developer manual
/* Default options. */
/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will
sleep
for one second intervals, decrementing _ARGP_HANG until it's zero. Thus
you can force the program to continue by attaching a debugger and
setting
it to 0 yourself. */
volatile int _argp_hang;
#define OPT_PROGNAME -2
#define OPT_USAGE -3
#define OPT_HANG -4
static error_t
argp_default_parser (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case '?':
__argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP);
break;
case OPT_USAGE:
__argp_state_help (state, state->out_stream,
ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
break;
break;
Wave OS project early developer manual
case OPT_HANG:
_argp_hang = atoi (arg ? arg : "3600");
while (_argp_hang-- > 0)
__sleep (1);
break;
default:
return EBADKEY;
}
return 0;
}
460
Wave OS project early developer manual
static error_t
argp_version_parser (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case 'V':
if (argp_program_version_hook)
(*argp_program_version_hook) (state->out_stream, state);
else if (argp_program_version)
fprintf (state->out_stream, "%s\n", argp_program_version);
else
__argp_error (state, dgettext (state->root_argp->argp_domain,
"(PROGRAM ERROR) No version known!?"));
if (! (state->flags & ARGP_NO_EXIT))
exit (0);
break;
default:
return EBADKEY;
}
return 0;
}
/* Returns the offset into the getopt long options array LONG_OPTIONS of a
long option with called NAME, or -1 if none is found. Passing NULL as
NAME will return the number of options. */
static int
find_long_option (struct option *long_options, const char *name)
{
struct option *l = long_options;
while (l->name != NULL)
if (name != NULL && strcmp (l->name, name) == 0)
return l - long_options;
else
l++;
if (name == NULL)
return l - long_options;
else
return -1;
}
462
Wave OS project early developer manual
#if _LIBC - 0
#else /* !_LIBC */
#ifdef HAVE_CTHREADS_H
#else /* !HAVE_CTHREADS_H */
#endif /* HAVE_CTHREADS_H */
#endif /* _LIBC */
/* This hack to allow programs that know what's going on to call argp
recursively. If someday argp is changed not to use the non-reentrant
getopt interface, we can get rid of this shit. XXX */
void
_argp_unlock_xxx (void)
{
UNLOCK_GETOPT;
}
Wave OS project early developer manual
/* These fields are swapped into and out of the state structure when
calling this group's parser. */
void *input, **child_inputs;
void *hook;
};
/* Call GROUP's parser with KEY and ARG, swapping any group-specific info
from STATE before calling, and back into state afterwards. If GROUP has
no parser, EBADKEY is returned. */
static error_t
group_parse (struct group *group, struct argp_state *state, int key, char
*arg)
{
if (group->parser)
{
error_t err;
state->hook = group->hook;
state->input = group->input;
state->child_inputs = group->child_inputs;
state->arg_num = group->args_processed;
err = (*group->parser)(key, arg, state);
group->hook = state->hook;
return err;
}
else
return EBADKEY;
}
464
Wave OS project early developer manual
struct parser
{
const struct argp *argp;
/* SHORT_OPTS is the getopt short options string for the union of all the
groups of options. */
char *short_opts;
/* LONG_OPTS is the array of getop long option structures for the union
of
all the groups of options. */
struct option *long_opts;
/* The next usable entries in the various parser tables being filled in by
convert_options. */
struct parser_convert_state
{
struct parser *parser;
char *short_end;
struct option *long_end;
void **child_inputs_end;
};
if (real || argp->parser)
{
const struct argp_option *opt;
if (real)
for (opt = real; !__option_is_end (opt); opt++)
{
if (! (opt->flags & OPTION_ALIAS))
/* OPT isn't an alias, so we can use values from it. */
real = opt;
if (opt->name
&& find_long_option (cvt->parser->long_opts, opt->name) <
0)
/* OPT can be used as a long option. */
{
cvt->long_end->name = opt->name;
cvt->long_end->has_arg =
(real->arg
466
Wave OS project early developer manual
group->parser = argp->parser;
group->argp = argp;
group->short_end = cvt->short_end;
group->args_processed = 0;
group->parent = parent;
group->parent_index = parent_index;
group->input = 0;
group->hook = 0;
group->child_inputs = 0;
if (children)
/* Assign GROUP's CHILD_INPUTS field some space from
CVT->child_inputs_end.*/
{
unsigned num_children = 0;
while (children[num_children].argp)
num_children++;
group->child_inputs = cvt->child_inputs_end;
cvt->child_inputs_end += num_children;
}
parent = group++;
}
else
parent = 0;
if (children)
{
unsigned index = 0;
while (children->argp)
group =
convert_options (children++->argp, parent, index++, group, cvt);
}
return group;
}
/* Find the merged set of getopt options, with keys appropiately prefixed.
*/
static void
parser_convert (struct parser *parser, const struct argp *argp, int flags)
Wave OS project early developer manual
{
struct parser_convert_state cvt;
cvt.parser = parser;
cvt.short_end = parser->short_opts;
cvt.long_end = parser->long_opts;
cvt.child_inputs_end = parser->child_inputs;
cvt.long_end->name = NULL;
parser->argp = argp;
if (argp)
parser->egroup = convert_options (argp, 0, 0, parser->groups, &cvt);
else
parser->egroup = parser->groups; /* No parsers at all! */
}
468
Wave OS project early developer manual
/* For ARGP, increments the NUM_GROUPS field in SZS by the total number of
argp structures descended from it, and the SHORT_LEN & LONG_LEN fields by
the maximum lengths of the resulting merged getopt short options string
and
long-options array, respectively. */
static void
calc_sizes (const struct argp *argp, struct parser_sizes *szs)
{
const struct argp_child *child = argp->children;
const struct argp_option *opt = argp->options;
if (opt || argp->parser)
{
szs->num_groups++;
if (opt)
{
int num_opts = 0;
while (!__option_is_end (opt++))
num_opts++;
szs->short_len += num_opts * 3; /* opt + up to 2 `:'s */
szs->long_len += num_opts;
}
}
if (child)
while (child->argp)
{
calc_sizes ((child++)->argp, szs);
szs->num_child_inputs++;
}
}
if (argp)
calc_sizes (argp, &szs);
parser->groups = parser->storage;
parser->child_inputs = parser->storage + GLEN;
parser->long_opts = parser->storage + GLEN + CLEN;
parser->short_opts = parser->storage + GLEN + CLEN + LLEN;
parser->try_getopt = 1;
/* Call each parser for the first time, giving it a chance to propagate
values to child parsers. */
if (parser->groups < parser->egroup)
parser->groups->input = input;
for (group = parser->groups;
group < parser->egroup && (!err || err == EBADKEY);
group++)
{
if (group->parent)
/* If a child parser, get the initial input value from the parent. */
group->input = group->parent->child_inputs[group->parent_index];
if (!group->parser
&& group->argp->children && group->argp->children->argp)
/* For the special case where no parsing function is supplied for an
argp, propagate its input to its first child, if any (this just
makes very simple wrapper argps more convenient). */
group->child_inputs[0] = group->input;
if (err)
return err;
470
Wave OS project early developer manual
return 0;
}
Wave OS project early developer manual
UNLOCK_GETOPT;
if (! err)
{
if (parser->state.next == parser->state.argc)
/* We successfully parsed all arguments! Call all the parsers again,
just a few more times... */
{
for (group = parser->groups;
group < parser->egroup && (!err || err==EBADKEY);
group++)
if (group->args_processed == 0)
err = group_parse (group, &parser->state, ARGP_KEY_NO_ARGS, 0);
for (group = parser->groups;
group < parser->egroup && (!err || err==EBADKEY);
group++)
err = group_parse (group, &parser->state, ARGP_KEY_END, 0);
if (err == EBADKEY)
err = 0; /* Some parser didn't understand. */
/* Okay, we're all done, with either an error or success; call the
parsers
to indicate which one. */
if (err)
{
/* Maybe print an error message. */
if (err == EBADKEY)
472
Wave OS project early developer manual
/* Call parsers once more, to do any final cleanup. Errors are ignored.
*/
for (group = parser->egroup - 1; group >= parser->groups; group--)
group_parse (group, &parser->state, ARGP_KEY_FINI, 0);
if (err == EBADKEY)
err = EINVAL;
free (parser->storage);
return err;
}
Wave OS project early developer manual
/* Call the user parsers to parse the non-option argument VAL, at the
current
position, returning any error. The state NEXT pointer is assumed to
have
been adjusted (by getopt) to point after this argument; this function
will
adjust it correctly to reflect however many args actually end up being
consumed. */
static error_t
parser_parse_arg (struct parser *parser, char *val)
{
/* Save the starting value of NEXT, first adjusting it so that the arg
we're parsing is again the front of the arg vector. */
int index = --parser->state.next;
error_t err = EBADKEY;
struct group *group;
int key = 0; /* Which of ARGP_KEY_ARG[S] we used. */
if (err == EBADKEY)
/* This parser doesn't like ARGP_KEY_ARG; try ARGP_KEY_ARGS instead.
*/
{
parser->state.next--; /* For ARGP_KEY_ARGS, put back the arg. */
key = ARGP_KEY_ARGS;
err = group_parse (group, &parser->state, key, 0);
}
}
if (! err)
{
if (key == ARGP_KEY_ARGS)
/* The default for ARGP_KEY_ARGS is to assume that if NEXT isn't
changed by the user, *all* arguments should be considered
consumed. */
parser->state.next = parser->state.argc;
return err;
}
474
Wave OS project early developer manual
/* Call the user parsers to parse the option OPT, with argument VAL, at the
current position, returning any error. */
static error_t
parser_parse_opt (struct parser *parser, int opt, char *val)
{
/* The group key encoded in the high bits; 0 for short opts or
group_number + 1 for long opts. */
int group_key = opt >> USER_BITS;
error_t err = EBADKEY;
if (group_key == 0)
/* A short option. By comparing OPT's position in SHORT_OPTS to the
various starting positions in each group's SHORT_END field, we can
determine which group OPT came from. */
{
struct group *group;
char *short_index = strchr (parser->short_opts, opt);
if (short_index)
for (group = parser->groups; group < parser->egroup; group++)
if (group->short_end > short_index)
{
err = group_parse (group, &parser->state, opt, optarg);
break;
}
}
else
/* A long option. We use shifts instead of masking for extracting
the user value in order to preserve the sign. */
err =
group_parse (&parser->groups[group_key - 1], &parser->state,
(opt << GROUP_BITS) >> GROUP_BITS, optarg);
if (err == EBADKEY)
/* At least currently, an option not recognized is an error in the
parser, because we pre-compute which parser is supposed to deal
with each option. */
{
static const char bad_key_err[] =
N_("(PROGRAM ERROR) Option should have been recognized!?");
if (group_key == 0)
__argp_error (&parser->state, "-%c: %s", opt,
dgettext (parser->argp->argp_domain, bad_key_err));
else
{
struct option *long_opt = parser->long_opts;
while (long_opt->val != opt && long_opt->name)
long_opt++;
__argp_error (&parser->state, "--%s: %s",
long_opt->name ? long_opt->name : "???",
dgettext (parser->argp->argp_domain, bad_key_err));
}
}
return err;
}
Wave OS project early developer manual
if (opt == KEY_END)
/* Getopt says there are no more options, so stop using
getopt; we'll continue if necessary on our own. */
{
parser->try_getopt = 0;
if (parser->state.next > 1
&& strcmp (parser->state.argv[parser->state.next - 1], QUOTE)
== 0)
/* Not only is this the end of the options, but it's a
`quoted' region, which may have args that *look* like
options, so we definitely shouldn't try to use getopt past
here, whatever happens. */
parser->state.quoted = parser->state.next;
}
else if (opt == KEY_ERR && optopt != KEY_END)
/* KEY_ERR can have the same value as a valid user short
option, but in the case of a real error, getopt sets OPTOPT
to the offending character, which can never be KEY_END. */
{
*arg_ebadkey = 0;
return EBADKEY;
}
}
else
opt = KEY_END;
if (opt == KEY_END)
{
/* We're past what getopt considers the options. */
if (parser->state.next >= parser->state.argc
476
Wave OS project early developer manual
if (opt == KEY_ARG)
/* A non-option argument; try each parser in turn. */
err = parser_parse_arg (parser, optarg);
else
err = parser_parse_opt (parser, opt, optarg);
if (err == EBADKEY)
*arg_ebadkey = (opt == KEY_END || opt == KEY_ARG);
return err;
}
Wave OS project early developer manual
/* Parse the options strings in ARGC & ARGV according to the argp in ARGP.
FLAGS is one of the ARGP_ flags above. If END_INDEX is non-NULL, the
index in ARGV of the first unparsed option is returned in it. If an
unknown option is present, EINVAL is returned; if some parser routine
returned a non-zero value, it is returned; otherwise 0 is returned. */
error_t
__argp_parse (const struct argp *argp, int argc, char **argv, unsigned
flags,
int *end_index, void *input)
{
error_t err;
struct parser parser;
if (argp)
(child++)->argp = argp;
(child++)->argp = &argp_default_argp;
if (argp_program_version || argp_program_version_hook)
(child++)->argp = &argp_version_argp;
child->argp = 0;
argp = top_argp;
}
if (! err)
/* Parse! */
{
while (! err)
err = parser_parse_next (&parser, &arg_ebadkey);
err = parser_finalize (&parser, err, arg_ebadkey, end_index);
}
return err;
}
#ifdef weak_alias
weak_alias (__argp_parse, argp_parse)
#endif
478
Wave OS project early developer manual
/* Return the input field for ARGP in the parser corresponding to STATE;
used
by the help routines. */
void *
__argp_input (const struct argp *argp, const struct argp_state *state)
{
if (state)
{
struct group *group;
struct parser *parser = state->pstate;
return 0;
}
#ifdef weak_alias
weak_alias (__argp_input, _argp_input)
#endif
/* Default definition for ARGP_PROGRAM_VERSION.
Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. 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 "argp.h"
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. 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 <stdlib.h>
#include <time.h>
#include <string.h>
#include <argp.h>
480
Wave OS project early developer manual
{0}
};
static error_t
sub_parse_opt (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case ARGP_KEY_NO_ARGS:
printf ("NO SUB ARGS\n");
break;
case ARGP_KEY_ARG:
printf ("SUB ARG: %s\n", arg);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static char *
sub_help_filter (int key, const char *text, void *input)
{
if (key == ARGP_KEY_HELP_EXTRA)
return strdup ("This is some extra text from the sub parser (note that
it \
is preceded by a blank line).");
else
return (char *)text;
}
#define OPT_PGRP 1
#define OPT_SESS 2
{0}
};
static void
popt (int key, char *arg)
{
char buf[10];
if (isprint (key))
sprintf (buf, "%c", key);
else
sprintf (buf, "%d", key);
if (arg)
printf ("KEY %s: %s\n", buf, arg);
else
printf ("KEY %s\n", buf);
}
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
struct params *params = state->input;
482
Wave OS project early developer manual
switch (key)
{
case ARGP_KEY_NO_ARGS:
printf ("NO ARGS\n");
break;
case ARGP_KEY_ARG:
if (state->arg_num > 0)
return ARGP_ERR_UNKNOWN; /* Leave it for the sub-arg parser. */
printf ("ARG: %s\n", arg);
break;
case 'f':
if (arg)
params->foonly = atoi (arg);
else
params->foonly = params->foonly_default;
popt (key, arg);
break;
case 'p': case 'P': case OPT_PGRP: case 'x': case 'Q':
case 'r': case OPT_SESS: case 'z':
popt (key, arg);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static char *
help_filter (int key, const char *text, void *input)
{
char *new_text;
struct params *params = input;
return new_text;
}
int
main (int argc, char **argv)
{
struct params params;
params.foonly = 0;
params.foonly_default = random ();
argp_parse (&argp, argc, argv, 0, 0, ¶ms);
printf ("After parsing: foonly = %x\n", params.foonly);
return 0;
}
* Real definitions for extern inline functions in argp-fmtstream.h
Copyright (C) 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. 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
#define ARGP_FS_EI
#undef __OPTIMIZE__
#define __OPTIMIZE__
#include "argp-fmtstream.h"
#endif
484
Wave OS project early developer manual
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#ifndef _ARGP_H
#define _ARGP_H
#include <stdio.h>
#include <ctype.h>
#include <getopt.h>
#define __need_error_t
#include <errno.h>
#ifndef __const
# define __const const
#endif
#ifndef __error_t_defined
typedef int error_t;
# define __error_t_defined
#endif
#ifndef __P
# ifdef __cplusplus
# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 7)
# define __P(args) args throw ()
# else
# define __P(args) args
# endif
# define __PMT(args) args
# elif defined __STDC__ && __STDC__ > 0
# define __P(args) args
# define __PMT(args) args
# else
# define __P(args) ()
# define __PMT(args) ()
# endif
#endif
Wave OS project early developer manual
#ifdef __cplusplus
extern "C" {
#endif
/* What key is returned for this option. If > 0 and printable, then it's
also accepted as a short option. */
int key;
/* OPTION_ flags. */
int flags;
/* The doc string for this option. If both NAME and KEY are 0, This
string
will be printed outdented from the normal option column, making it
useful as a group header (it will be the first thing printed in its
group); in this usage, it's conventional to end the string with a `:'.
*/
__const char *doc;
/* The group this option is in. In a long help message, options are
sorted
alphabetically within each group, and the groups presented in the
order
0, 1, 2, ..., n, -m, ..., -2, -1. Every entry in an options array
with
if this field 0 will inherit the group number of the previous entry,
or
zero if it's the first one, unless its a group header (NAME and KEY
both
0), in which case, the previous entry + 1 is the default. Automagic
options such as --help are put into group -1. */
int group;
};
/* This option is an alias for the closest previous non-alias option. This
means that it will be displayed in the same help entry, and will inherit
fields other than NAME and KEY from the aliased option. */
486
Wave OS project early developer manual
/* What to return for unrecognized keys. For special ARGP_KEY_ keys, such
returns will simply be ignored. For user keys, this error will be
turned
into EINVAL (if the call to argp_parse is such that errors are
propagated
back to the user instead of exiting); returning EINVAL itself would
result
in an immediate stop to parsing in *all* cases. */
#define ARGP_ERR_UNKNOWN E2BIG /* Hurd should never need E2BIG. XXX
*/
488
Wave OS project early developer manual
any non-option args, user parsers are called with this key if they
didn't
successfully process any non-option arguments. Called just before
ARGP_KEY_END (where more general validity checks on previously parsed
arguments can take place). */
#define ARGP_KEY_NO_ARGS 0x1000002
/* Passed in before any parsing is done. Afterwards, the values of each
element of the CHILD_INPUT field, if any, in the state structure is
copied to each child's state to be the initial value of the INPUT field.
*/
#define ARGP_KEY_INIT 0x1000003
/* Use after all other keys, including SUCCESS & END. */
#define ARGP_KEY_FINI 0x1000007
/* Passed in when parsing has successfully been completed (even if there
are
still arguments remaining). */
#define ARGP_KEY_SUCCESS 0x1000004
/* Passed in if an error occurs. */
#define ARGP_KEY_ERROR 0x1000005
your
own. */
__const struct argp_child *children;
/* If non-zero the strings used in the argp library are translated using
the domain described by this string. Otherwise the currently
installed
default domain is used. */
const char *argp_domain;
};
490
Wave OS project early developer manual
/* The index in ARGV of the next arg that to be parsed. May be modified.
*/
int next;
492
Wave OS project early developer manual
/* Flags for argp_parse (note that the defaults are those that are
convenient for program command line parsing): */
/* Don't ignore the first element of ARGV. Normally (and always unless
ARGP_NO_ERRS is set) the first element of the argument vector is
skipped for option parsing purposes, as it corresponds to the program
name
in a command line. */
#define ARGP_PARSE_ARGV0 0x01
/* Don't print error messages for unknown options to stderr; unless this
flag
is set, ARGP_PARSE_ARGV0 is ignored, as ARGV[0] is used as the program
name in the error messages. This flag implies ARGP_NO_EXIT (on the
assumption that silent exiting upon errors is bad behaviour). */
#define ARGP_NO_ERRS 0x02
/* Don't parse any non-option args. Normally non-option args are parsed by
calling the parse functions with a key of ARGP_KEY_ARG, and the actual
arg
as the value. Since it's impossible to know which parse function wants
to
handle it, each one is called in turn, until one returns 0 or an error
other than ARGP_ERR_UNKNOWN; if an argument is handled by no one, the
argp_parse returns prematurely (but with a return value of 0). If all
args have been parsed without error, all parsing functions are called
one
last time with a key of ARGP_KEY_END. This flag needn't normally be
set,
as the normal behavior is to stop parsing as soon as some argument can't
be handled. */
#define ARGP_NO_ARGS 0x04
/* Parse options and arguments in the same order they occur on the command
line -- normally they're rearranged so that all options come first. */
#define ARGP_IN_ORDER 0x08
/* Don't provide the standard long option --help, which causes usage and
option help information to be output to stdout, and exit (0) called.
*/
#define ARGP_NO_HELP 0x10
/* Parse the options strings in ARGC & ARGV according to the options in
ARGP.
FLAGS is one of the ARGP_ flags above. If ARG_INDEX is non-NULL, the
index in ARGV of the first unparsed option is returned in it. If an
unknown option is present, ARGP_ERR_UNKNOWN is returned; if some parser
routine returned a non-zero value, it is returned; otherwise 0 is
returned. This function may also call exit unless the ARGP_NO_HELP flag
is set. INPUT is a pointer to a value to be passed in to the parser.
*/
extern error_t argp_parse __P ((__const struct argp *__restrict __argp,
Wave OS project early developer manual
494
Wave OS project early developer manual
/* Global variables. */
/* The exit status that argp will use when exiting due to a parsing error.
If not defined or set by the user program, this defaults to EX_USAGE
from
<sysexits.h>. */
extern error_t argp_err_exit_status;
Wave OS project early developer manual
/* Output a usage message for ARGP to STREAM. FLAGS are from the set
ARGP_HELP_*. */
extern void argp_help __P ((__const struct argp *__restrict __argp,
FILE *__restrict __stream,
unsigned __flags, char *__restrict __name));
extern void __argp_help __P ((__const struct argp *__restrict __argp,
FILE *__restrict __stream, unsigned __flags,
char *__name));
496
Wave OS project early developer manual
/* Possibly output the standard usage message for ARGP to stderr and exit.
*/
extern void argp_usage __P ((__const struct argp_state *__state));
extern void __argp_usage __P ((__const struct argp_state *__state));
/* If appropriate, print the printf string FMT and following args, preceded
by the program name and `:', to stderr, and followed by a `Try ...
--help'
message, then exit (1). */
extern void argp_error __P ((__const struct argp_state *__restrict __state,
__const char *__restrict __fmt, ...))
__attribute__ ((__format__ (__printf__, 2, 3)));
extern void __argp_error __P ((__const struct argp_state *__restrict
__state,
__const char *__restrict __fmt, ...))
__attribute__ ((__format__ (__printf__, 2, 3)));
/* Returns true if the option OPT is in fact the last (unused) entry in an
options array. */
extern int _option_is_end __P ((__const struct argp_option *__opt));
extern int __option_is_end __P ((__const struct argp_option *__opt));
/* Return the input field for ARGP in the parser corresponding to STATE;
used
by the help routines. */
extern void *_argp_input __P ((__const struct argp *__restrict __argp,
__const struct argp_state *__restrict __state));
extern void *__argp_input __P ((__const struct argp *__restrict __argp,
__const struct argp_state *__restrict
__state));
498
Wave OS project early developer manual
#ifdef __USE_EXTERN_INLINES
# if !_LIBC
# define __argp_usage argp_usage
# define __argp_state_help argp_state_help
# define __option_is_short _option_is_short
# define __option_is_end _option_is_end
# endif
# ifndef ARGP_EI
# define ARGP_EI extern __inline__
# endif
ARGP_EI void
__argp_usage (__const struct argp_state *__state) __THROW
{
__argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE);
}
ARGP_EI int
__option_is_short (__const struct argp_option *__opt) __THROW
{
if (__opt->flags & OPTION_DOC)
return 0;
else
{
int __key = __opt->key;
return __key > 0 && isprint (__key);
}
}
ARGP_EI int
__option_is_end (__const struct argp_option *__opt) __THROW
{
return !__opt->key && !__opt->name && !__opt->doc && !__opt->group;
}
# if !_LIBC
# undef __argp_usage
# undef __argp_state_help
# undef __option_is_short
# undef __option_is_end
# endif
#endif /* Use extern inlines. */
#ifdef __cplusplus
}
#endif
#endif /* argp.h */
/* Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation,
Inc.
This file is part of the GNU C Library.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sysdep.h>
#ifdef USE_IN_LIBIO
# include <libio/iolibio.h>
# define fflush(s) _IO_fflush (s)
#endif
#ifdef FATAL_PREPARE_INCLUDE
# include FATAL_PREPARE_INCLUDE
#endif
void
__assert_perror_fail (int errnum,
const char *file, unsigned int line,
const char *function)
{
char errbuf[1024];
#ifdef FATAL_PREPARE
FATAL_PREPARE;
#endif
abort ();
}
/* Copyright (C) 1991, 1994, 1995, 1996, 1998 Free Software Foundation,
Inc.
This file is part of the GNU C Library.
500
Wave OS project early developer manual
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysdep.h>
#ifdef USE_IN_LIBIO
# include <libio/iolibio.h>
# define fflush(s) _IO_fflush (s)
#endif
#ifdef FATAL_PREPARE_INCLUDE
# include FATAL_PREPARE_INCLUDE
#endif
void
__assert_fail (const char *assertion, const char *file, unsigned int line,
const char *function)
{
#ifdef FATAL_PREPARE
FATAL_PREPARE;
#endif
abort ();
}
#ifdef HAVE_GNU_LD
#include <string.h>
static void
set_progname (int argc, char **argv, char **envp)
{
char *p;
Wave OS project early developer manual
#endif
/* Copyright (C) 1991,92,94,95,96,97,98,99 Free Software Foundation, Inc.
This file is part of the GNU C Library.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
/*
* ISO C Standard: 4.2 DIAGNOSTICS <assert.h>
*/
#ifdef _ASSERT_H
# undef _ASSERT_H
# undef assert
# ifdef __USE_GNU
# undef assert_perror
# endif
#endif /* assert.h */
#define _ASSERT_H 1
#include <features.h>
#ifdef NDEBUG
502
Wave OS project early developer manual
# ifdef __USE_GNU
# define assert_perror(errnum) ((void) 0)
# endif
__BEGIN_DECLS
__END_DECLS
# define assert(expr) \
((void) ((expr) ? 0 : \
(__assert_fail (__STRING(expr), \
__FILE__, __LINE__, __ASSERT_FUNCTION), 0)))
# ifdef __USE_GNU
# define assert_perror(errnum) \
((void) (!(errnum) ? 0 : (__assert_perror_fail ((errnum), \
__FILE__, __LINE__, \
__ASSERT_FUNCTION), 0)))
# endif
#endif /* NDEBUG. */
/* Test assert_perror().
*
* This is hairier than you'd think, involving games with
* stdio and signals.
*
*/
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
jmp_buf rec;
char buf[160];
void
sigabrt (int unused)
{
longjmp (rec, 1); /* recover control */
}
#undef NDEBUG
#include <assert.h>
void
assert1 (void)
{
assert_perror (1);
}
void
assert2 (void)
{
assert_perror (0);
}
#define NDEBUG
#include <assert.h>
void
assert3 (void)
{
assert_perror (2);
}
int
main(void)
{
volatile int failed = 1; /* safety in presence of longjmp() */
fclose (stderr);
stderr = tmpfile ();
if (!stderr)
abort ();
504
Wave OS project early developer manual
if (!setjmp (rec))
assert1 ();
else
failed = 0; /* should happen */
if (!setjmp (rec))
assert2 ();
else
failed = 1; /* should not happen */
if (!setjmp (rec))
assert3 ();
else
failed = 1; /* should not happen */
rewind (stderr);
fgets (buf, 160, stderr);
if (!strstr(buf, strerror (1)))
failed = 1;
return failed;
}
/* Test assert().
*
* This is hairier than you'd think, involving games with
* stdio and signals.
*
*/
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
jmp_buf rec;
char buf[160];
void
sigabrt (int unused)
{
longjmp (rec, 1); /* recover control */
}
#undef NDEBUG
#include <assert.h>
void
assert1 (void)
{
assert (1 == 2);
}
void
assert2 (void)
Wave OS project early developer manual
{
assert (1 == 1);
}
#define NDEBUG
#include <assert.h>
void
assert3 (void)
{
assert (2 == 3);
}
int
main (void)
{
fclose (stderr);
stderr = tmpfile ();
if(!stderr)
abort ();
if (!setjmp (rec))
assert1 ();
else
failed = 0; /* should happen */
if (!setjmp (rec))
assert2 ();
else
failed = 1; /* should not happen */
if (!setjmp (rec))
assert3 ();
else
failed = 1; /* should not happen */
rewind (stderr);
fgets (buf, 160, stderr);
if (!strstr (buf, "1 == 2"))
failed = 1;
return failed;
}
/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper, <drepper@gnu.org>.
506
Wave OS project early developer manual
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#include <alloca.h>
#include <errno.h>
#include <nl_types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include "catgetsinfo.h"
if (env_var != NULL)
goto have_env_var;
}
have_env_var:
env_var_len = strlen (env_var) + 1;
nlspath_len = len;
}
else
{
nlspath = NLSPATH;
result->status = closed;
result->cat_name = endp = (char *) (result + 1);
endp = __mempcpy (endp, cat_name, cat_name_len);
__libc_lock_init (result->lock);
if (catalog->status == closed)
__open_catalog (catalog);
if (catalog->status == nonexisting)
{
__set_errno (EBADF);
return (char *) string;
}
508
Wave OS project early developer manual
cnt = 0;
do
{
if (catalog->name_ptr[idx + 0] == (u_int32_t) set
&& catalog->name_ptr[idx + 1] == (u_int32_t) message)
return (char *) &catalog->strings[catalog->name_ptr[idx + 2]];
idx += catalog->plane_size * 3;
}
while (++cnt < catalog->plane_depth);
__set_errno (ENOMSG);
return (char *) string;
}
#ifdef _POSIX_MAPPED_FILES
if (catalog->status == mmapped)
__munmap ((void *) catalog->file_ptr, catalog->file_size);
else
#endif /* _POSIX_MAPPED_FILES */
if (catalog->status == malloced)
free ((void *) catalog->file_ptr);
else if (catalog->status != closed && catalog->status != nonexisting)
{
__set_errno (EBADF);
return -1;
}
return 0;
}
/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#include <sys/types.h>
Wave OS project early developer manual
#include <bits/libc-lock.h>
struct catalog_obj
{
u_int32_t magic;
u_int32_t plane_size;
u_int32_t plane_depth;
/* This is in fact two arrays in one: always a pair of name and
pointer into the data area. */
u_int32_t name_ptr[0];
};
size_t plane_size;
size_t plane_depth;
u_int32_t *name_ptr;
const char *strings;
__libc_lock_define (,lock);
} *__nl_catd;
#include_next <config.h>
#endif
/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
510
Wave OS project early developer manual
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. 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 <argp.h>
#include <ctype.h>
#include <endian.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <locale.h>
#include <libintl.h>
#include <limits.h>
#include <nl_types.h>
#include <obstack.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "version.h"
#include "catgetsinfo.h"
#define SWAPU32(w) \
(((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >>
24))
struct message_list
{
int number;
const char *message;
struct set_list
{
int number;
int deleted;
struct message_list *messages;
Wave OS project early developer manual
int last_message;
struct catalog
{
struct set_list *all_sets;
struct set_list *current_set;
size_t total_messages;
char quote_char;
int last_set;
#define OPT_NEW 1
512
Wave OS project early developer manual
int
main (int argc, char *argv[])
{
struct catalog *result;
int remaining;
exit (EXIT_SUCCESS);
}
static char *
more_help (int key, const char *text, void *input)
{
switch (key)
{
case ARGP_KEY_HELP_EXTRA:
/* We print some extra information. */
return strdup (gettext ("\
Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n"));
default:
break;
}
return (char *) text;
}
514
Wave OS project early developer manual
static void
error_print ()
{
/* We don't want the program name to be printed in messages. Emacs'
compile.el does not like this. */
}
buf = NULL;
len = 0;
line_number = 0;
while (!feof (fp))
{
int continued;
int used;
size_t start_line = line_number + 1;
char *this_line;
do
{
int act_len;
{
--act_len;
continued = buf[act_len - 1] == '\\';
if (continued)
--act_len;
}
else
continued = 0;
used = 0;
if (this_line[0] == '$')
{
if (isspace (this_line[1]))
/* This is a comment line. Do nothing. */;
else if (strncmp (&this_line[1], "set", 3) == 0)
{
int cnt = sizeof ("set");
int set_number;
const char *symbol = NULL;
while (isspace (this_line[cnt]))
++cnt;
if (isdigit (this_line[cnt]))
{
set_number = atol (&this_line[cnt]);
if (cnt == start)
{
/* No correct character found. */
error_at_line (0, 0, fname, start_line,
gettext ("illegal set number"));
set_number = 0;
}
else
{
/* We have found seomthing that looks like a
correct identifier. */
struct set_list *runp;
516
Wave OS project early developer manual
this_line[cnt] = '\0';
used = 1;
symbol = &this_line[start];
if (runp != NULL)
{
/* We cannot allow duplicate identifiers for
message sets. */
error_at_line (0, 0, fname, start_line,
gettext ("duplicate set definition"));
error_at_line (0, 0, runp->fname, runp->line,
gettext ("\
this is the first definition"));
set_number = 0;
}
else
/* Allocate next free message set for identifier. */
set_number = ++current->last_set;
}
}
if (set_number != 0)
{
/* We found a legal set number. */
current->current_set = find_set (current, set_number);
if (symbol != NULL)
used = 1;
current->current_set->symbol = symbol;
current->current_set->fname = fname;
current->current_set->line = start_line;
}
}
else if (strncmp (&this_line[1], "delset", 6) == 0)
{
int cnt = sizeof ("delset");
size_t set_number;
while (isspace (this_line[cnt]))
++cnt;
if (isdigit (this_line[cnt]))
{
size_t set_number = atol (&this_line[cnt]);
struct set_list *set;
if (cnt == start)
{
error_at_line (0, 0, fname, start_line,
gettext ("illegal set number"));
set_number = 0;
}
else
{
const char *symbol;
struct set_list *runp;
this_line[cnt] = '\0';
used = 1;
symbol = &this_line[start];
518
Wave OS project early developer manual
do
++this_line;
while (this_line[0] != '\0' && !isspace (this_line[0]));
any_space = isspace (*this_line);
*this_line++ = '\0'; /* Terminate the identifier. */
if (isdigit (ident[0]))
{
struct message_list *runp;
struct message_list *lastp;
if (message_number != 0
&& message_number > current->current_set->last_message)
current->current_set->last_message = message_number;
}
else if (ident[0] != '\0')
{
struct message_list *runp;
struct message_list *lastp;
Wave OS project early developer manual
if (message_number != 0)
{
struct message_list *newp;
520
Wave OS project early developer manual
if (current->current_set->messages == NULL
|| current->current_set->messages->number > message_number)
{
newp->next = current->current_set->messages;
current->current_set->messages = newp;
}
else
{
struct message_list *runp;
runp = current->current_set->messages;
while (runp->next != NULL)
if (runp->next->number > message_number)
break;
else
runp = runp->next;
newp->next = runp->next;
runp->next = newp;
}
}
++current->total_messages;
}
else
{
size_t cnt;
cnt = 0;
/* See whether we have any non-white space character in this
line. */
while (this_line[cnt] != '\0' && isspace (this_line[cnt]))
++cnt;
if (this_line[cnt] != '\0')
/* Yes, some unknown characters found. */
error_at_line (0, 0, fname, start_line,
gettext ("malformed line ignored"));
}
/* We can save the memory for the line if it was not used. */
if (!used)
obstack_free (¤t->mem_pool, this_line);
}
if (fp != stdin)
fclose (fp);
return current;
}
static void
write_out (struct catalog *catalog, const char *output_name,
const char *header_name)
{
/* Computing the "optimal" size. */
struct set_list *set_run;
size_t best_total, best_size, best_depth;
size_t act_size, act_depth;
struct catalog_obj obj;
struct obstack string_pool;
const char *strings;
size_t strings_size;
u_int32_t *array1, *array2;
size_t cnt;
Wave OS project early developer manual
int fd;
act_depth = 1;
memset (deep, '\0', act_size * sizeof (size_t));
set_run = catalog->all_sets;
while (set_run != NULL)
{
struct message_list *message_run;
message_run = set_run->messages;
while (message_run != NULL)
{
size_t idx = (message_run->number * set_run->number) %
act_size;
++deep[idx];
if (deep[idx] > act_depth)
{
act_depth = deep[idx];
if (act_depth * act_size > best_total)
break;
}
message_run = message_run->next;
}
set_run = set_run->next;
}
++act_size;
}
522
Wave OS project early developer manual
/* OK, now we have the size we will use. Fill in the header, build
the table and the second one with swapped byte order. */
obj.magic = CATGETS_MAGIC;
obj.plane_size = best_size;
obj.plane_depth = best_depth;
set_run = catalog->all_sets;
while (set_run != NULL)
{
struct message_list *message_run;
message_run = set_run->messages;
while (message_run != NULL)
{
size_t idx = (((message_run->number * set_run->number) % best_size)
* 3);
/* Determine collision depth. */
while (array1[idx] != 0)
idx += best_size * 3;
message_run = message_run->next;
}
set_run = set_run->next;
}
strings_size = obstack_object_size (&string_pool);
strings = obstack_finish (&string_pool);
if (fd != STDOUT_FILENO)
close (fd);
524
Wave OS project early developer manual
set_run->fname, set_run->line);
first = 0;
message_run = set_run->messages;
while (message_run != NULL)
{
/* If the current message has a symbolic name write
#define out. But we have to take care for the set
not having a symbolic name. */
if (message_run->symbol != NULL)
{
if (set_run->symbol == NULL)
fprintf (fp, "#define AutomaticSet%d%s %#x\t/* %s:%Zu
*/\n",
set_run->number, message_run->symbol,
message_run->number, message_run->fname,
message_run->line);
else
fprintf (fp, "#define %s%s %#x\t/* %s:%Zu */\n",
set_run->symbol, message_run->symbol,
message_run->number, message_run->fname,
message_run->line);
}
message_run = message_run->next;
}
set_run = set_run->next;
}
if (fp != stdout)
fclose (fp);
}
}
return result;
}
526
Wave OS project early developer manual
{
int number = *rp++ - '0';
while (number <= (255 / 8) && *rp >= '0' && *rp <= '7')
{
number *= 8;
number += *rp++ - '0';
}
*wp++ = (char) number;
}
break;
default:
/* Simply ignore the backslash character. */
break;
}
}
else
*wp++ = *rp++;
/* Terminate string. */
*wp = '\0';
return;
}
static void
read_old (struct catalog *catalog, const char *file_name)
{
struct catalog_info old_cat_obj;
struct set_list *set = NULL;
int last_set = -1;
size_t cnt;
old_cat_obj.status = closed;
old_cat_obj.cat_name = file_name;
old_cat_obj.nlspath = NULL;
__libc_lock_init (old_cat_obj.lock);
/* OK, we have the catalog loaded. Now read all messages and merge
them. When set and message number clash for any message the new
one is used. */
for (cnt = 0; cnt < old_cat_obj.plane_size * old_cat_obj.plane_depth; +
+cnt)
{
struct message_list *message, *last;
Wave OS project early developer manual
if (old_cat_obj.name_ptr[cnt * 3 + 0] == 0)
/* No message in this slot. */
continue;
last = NULL;
message = set->messages;
while (message != NULL)
{
if ((u_int32_t) message->number >= old_cat_obj.name_ptr[cnt * 3 +
1])
break;
last = message;
message = message->next;
}
if (message == NULL
|| (u_int32_t) message->number > old_cat_obj.name_ptr[cnt * 3 + 1])
{
/* We have found a message which is not yet in the catalog.
Insert it at the right position. */
struct message_list *newp;
if (last == NULL)
set->messages = newp;
else
last->next = newp;
++catalog->total_messages;
}
}
}
/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
This file is part of the GNU C Library.
You should have received a copy of the GNU Library General Public
528
Wave OS project early developer manual
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#ifndef _NL_TYPES_H
#define _NL_TYPES_H 1
#include <features.h>
__BEGIN_DECLS
__END_DECLS
#endif /* nl_types.h */
/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper, <drepper@gnu.org>.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#include <byteswap.h>
#include <endian.h>
Wave OS project early developer manual
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef _POSIX_MAPPED_FILES
# include <sys/mman.h>
#endif
#include <sys/stat.h>
#include "catgetsinfo.h"
void
__open_catalog (__nl_catd catalog)
{
int fd = -1;
struct stat st;
int swapping;
size_t cnt;
size_t max_offset;
size_t tab_size;
const char *lastp;
buf = NULL;
bufmax = 0;
530
Wave OS project early developer manual
fd = -1;
while (*run_nlspath != '\0')
{
bufact = 0;
while (*run_nlspath != ':' && *run_nlspath != '\0')
if (*run_nlspath == '%')
{
const char *tmp;
do
{
ENOUGH (1);
buf[bufact++] = *tmp;
}
while (*tmp != '\0');
}
break;
case '%':
ENOUGH (1);
buf[bufact++] = '%';
break;
default:
/* Unknown variable: ignore this path element. */
bufact = 0;
while (*run_nlspath != '\0' && *run_nlspath != ':')
++run_nlspath;
break;
}
}
else
{
ENOUGH (1);
buf[bufact++] = *run_nlspath++;
}
ENOUGH (1);
buf[bufact] = '\0';
if (bufact != 0)
{
fd = __open (buf, O_RDONLY);
if (fd >= 0)
break;
}
++run_nlspath;
}
}
catalog->file_size = st.st_size;
532
Wave OS project early developer manual
#ifdef _POSIX_MAPPED_FILES
# ifndef MAP_COPY
/* Linux seems to lack read-only copy-on-write. */
# define MAP_COPY MAP_PRIVATE
# endif
# ifndef MAP_FILE
/* Some systems do not have this flag; it is superfluous. */
# define MAP_FILE 0
# endif
# ifndef MAP_INHERIT
/* Some systems might lack this; they lose. */
# define MAP_INHERIT 0
# endif
catalog->file_ptr =
(struct catalog_obj *) __mmap (NULL, st.st_size, PROT_READ,
MAP_FILE|MAP_COPY|MAP_INHERIT, fd, 0);
if (catalog->file_ptr != (struct catalog_obj *) MAP_FAILED)
/* Tell the world we managed to mmap the file. */
catalog->status = mmapped;
else
#endif /* _POSIX_MAPPED_FILES */
{
/* mmap failed perhaps because the system call is not
implemented. Try to load the file. */
size_t todo;
catalog->file_ptr = malloc (st.st_size);
if (catalog->file_ptr == NULL)
{
catalog->status = nonexisting;
goto close_unlock_return;
}
todo = st.st_size;
/* Save read, handle partial reads. */
do
{
size_t now = __read (fd, (((char *) &catalog->file_ptr)
+ (st.st_size - todo)), todo);
if (now == 0)
{
free ((void *) catalog->file_ptr);
catalog->status = nonexisting;
goto close_unlock_return;
}
todo -= now;
}
while (todo > 0);
catalog->status = malloced;
}
if (catalog->status == mmapped)
__munmap ((void *) catalog->file_ptr, catalog->file_size);
else
#endif /* _POSIX_MAPPED_FILES */
free (catalog->file_ptr);
catalog->status = nonexisting;
goto close_unlock_return;
}
/* The file contains two versions of the pointer tables. Pick the
right one for the local byte order. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
catalog->name_ptr = &catalog->file_ptr->name_ptr[0];
#elif __BYTE_ORDER == __BIG_ENDIAN
catalog->name_ptr = &catalog->file_ptr->name_ptr[catalog->plane_size
* catalog->plane_depth
* 3];
#else
# error Cannot handle __BYTE_ORDER byte order
#endif
/* The rest of the file contains all the strings. They are
addressed relative to the position of the first string. */
catalog->strings =
(const char *) &catalog->file_ptr->name_ptr[catalog->plane_size
* catalog->plane_depth * 3 * 2];
/* Now we can check whether the file is large enough to contain the
tables it says it contains. */
if (st.st_size <= (sizeof (struct catalog_obj) + 2 * tab_size +
max_offset))
/* The last string is not contained in the file. */
goto invalid_file;
534
Wave OS project early developer manual
__libc_lock_unlock (catalog->lock);
}
/* This file is used by some of the resolver code in inet/ that
comes from BIND 4.9. I have written this file instead of modifying
those things not to use it so that I can later drop in replacement
files from future BIND distributions without change. */
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
/* Some BIND code decides it can omit the definitions of some functions
if BSD is defined to some value. That might make sense when the BIND
code is augmenting or replacing an existing system library, but we can
never omit a function here, since we are defining the system library.
*/
#undef BSD
#undef sun
#define NEED_INETADDR 1
#define NEED_INETATON 1
/* Copyright (C) 1991,92,93,95,96,97,98,99 Free Software Foundation, Inc.
This file is part of the GNU C Library.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
/*
* ISO C Standard 4.3: CHARACTER HANDLING <ctype.h>
*/
#ifndef _CTYPE_H
#define _CTYPE_H 1
#include <features.h>
#include <bits/types.h>
__BEGIN_DECLS
#ifndef _ISbit
/* These are all the characteristics of characters.
Wave OS project early developer manual
# include <endian.h>
# if __BYTE_ORDER == __BIG_ENDIAN
# define _ISbit(bit) (1 << (bit))
# else /* __BYTE_ORDER == __LITTLE_ENDIAN */
# define _ISbit(bit) ((bit) < 8 ? ((1 << (bit)) << 8) : ((1 << (bit)) >>
8))
# endif
enum
{
_ISupper = _ISbit (0), /* UPPERCASE. */
_ISlower = _ISbit (1), /* lowercase. */
_ISalpha = _ISbit (2), /* Alphabetic. */
_ISdigit = _ISbit (3), /* Numeric. */
_ISxdigit = _ISbit (4), /* Hexadecimal numeric. */
_ISspace = _ISbit (5), /* Whitespace. */
_ISprint = _ISbit (6), /* Printing. */
_ISgraph = _ISbit (7), /* Graphical. */
_ISblank = _ISbit (8), /* Blank (usually SPC and TAB). */
_IScntrl = _ISbit (9), /* Control character. */
_ISpunct = _ISbit (10), /* Punctuation. */
_ISalnum = _ISbit (11) /* Alphanumeric. */
};
#endif /* ! _ISbit */
These point into arrays of 384, so they can be indexed by any `unsigned
char' value [0,255]; by EOF (-1); or by any `signed char' value
[-128,-1). ISO C requires that the ctype functions work for `unsigned
char' values and for EOF; we also support negative `signed char' values
for broken old programs. The case conversion arrays are of `int's
rather than `unsigned char's because tolower (EOF) must be EOF, which
doesn't fit into an `unsigned char'. But today more important is that
the arrays are also used for multi-byte character sets. */
extern __const unsigned short int *__ctype_b; /* Characteristics. */
extern __const __int32_t *__ctype_tolower; /* Case conversions. */
extern __const __int32_t *__ctype_toupper; /* Case conversions. */
536
Wave OS project early developer manual
__exctype (isalnum);
__exctype (isalpha);
__exctype (iscntrl);
__exctype (isdigit);
__exctype (islower);
__exctype (isgraph);
__exctype (isprint);
__exctype (ispunct);
__exctype (isspace);
__exctype (isupper);
__exctype (isxdigit);
#ifdef __USE_GNU
__exctype (isblank);
#endif
#ifndef __NO_CTYPE
# define isalnum(c) __isctype((c), _ISalnum)
# define isalpha(c) __isctype((c), _ISalpha)
# define iscntrl(c) __isctype((c), _IScntrl)
# define isdigit(c) __isctype((c), _ISdigit)
# define islower(c) __isctype((c), _ISlower)
# define isgraph(c) __isctype((c), _ISgraph)
# define isprint(c) __isctype((c), _ISprint)
# define ispunct(c) __isctype((c), _ISpunct)
# define isspace(c) __isctype((c), _ISspace)
# define isupper(c) __isctype((c), _ISupper)
# define isxdigit(c) __isctype((c), _ISxdigit)
#ifdef __USE_GNU
# define isblank(c) __isctype((c), _ISblank)
#endif
#ifdef __USE_GNU
/* The concept of one static locale per category is not very well
thought out. Many applications will need to process its data using
information from several different locales. Another application is
the implementation of the internationalization handling in the
upcoming ISO C++ standard library. To support this another set of
the functions using locale data exist which have an additional
argument.
538
Wave OS project early developer manual
/* These definitions are similar to the ones above but all functions
take as an argument a handle for the locale which shall be used. */
# define __isctype_l(c, type, locale) \
((locale)->__ctype_b[(int) (c)] & (unsigned short int) type)
__exctype_l (__isblank_l);
# ifndef __NO_CTYPE
# define __isalnum_l(c,l) __isctype_l((c), _ISalnum, (l))
# define __isalpha_l(c,l) __isctype_l((c), _ISalpha, (l))
# define __iscntrl_l(c,l) __isctype_l((c), _IScntrl, (l))
# define __isdigit_l(c,l) __isctype_l((c), _ISdigit, (l))
# define __islower_l(c,l) __isctype_l((c), _ISlower, (l))
# define __isgraph_l(c,l) __isctype_l((c), _ISgraph, (l))
# define __isprint_l(c,l) __isctype_l((c), _ISprint, (l))
# define __ispunct_l(c,l) __isctype_l((c), _ISpunct, (l))
# define __isspace_l(c,l) __isctype_l((c), _ISspace, (l))
# define __isupper_l(c,l) __isctype_l((c), _ISupper, (l))
# define __isxdigit_l(c,l) __isctype_l((c), _ISxdigit, (l))
__END_DECLS
#endif /* ctype.h */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)btree.h 8.11 (Berkeley) 8/17/94
*/
#include <mpool.h>
#ifdef _LIBC
/* In the GNU C library we must not pollute the namespace because libdb is
needed by libnss_db. */
#define mpool_open __mpool_open
#define mpool_filter __mpool_filter
#define mpool_new __mpool_new
#define mpool_get __mpool_get
#define mpool_put __mpool_put
540
Wave OS project early developer manual
/*
* Page 0 of a btree file contains a copy of the meta-data. This page is
also
* used as an out-of-band page, i.e. page pointers that point to nowhere
point
* to page 0. Page 1 is the root of the btree.
*/
#define P_INVALID 0 /* Invalid tree page number. */
#define P_META 0 /* Tree metadata page number. */
#define P_ROOT 1 /* Tree root page number. */
/*
* There are five page layouts in the btree: btree internal pages
(BINTERNAL),
* btree leaf pages (BLEAF), recno internal pages (RINTERNAL), recno leaf
pages
* (RLEAF) and overflow pages. All five page types have a page header
(PAGE).
* This implementation requires that values within structures NOT be
padded.
* (ANSI C permits random padding.) If your compiler pads randomly you'll
have
* to do some work to get this package to run.
*/
typedef struct _page {
pgno_t pgno; /* this page's page number */
pgno_t prevpg; /* left sibling */
pgno_t nextpg; /* right sibling */
/*
* For pages other than overflow pages, there is an array of offsets into
the
Wave OS project early developer manual
* rest of the page immediately following the page header. Each offset is
to
* an item which is unique to the type of page. The h_lower offset is just
* past the last filled-in index. The h_upper offset is the first item on
the
* page. Offsets are from the beginning of the page.
*
* If an item is too big to store on a single page, a flag is set and the
item
* is a { page, size } pair such that the page is the first page of an
overflow
* chain with size bytes of item. Overflow pages are simply bytes without
any
* external structure.
*
* The page number and size fields in the items are pgno_t-aligned so they
can
* be manipulated without copying. (This presumes that 32 bit items can be
* manipulated on this system.)
*/
#define LALIGN(n) (((n) + sizeof(pgno_t) - 1) & ~(sizeof(pgno_t) -
1))
#define NOVFLSIZE (sizeof(pgno_t) + sizeof(u_int32_t))
/*
* For the btree internal pages, the item is a key. BINTERNALs are {key,
pgno}
* pairs, such that the key compares less than or equal to all of the
records
* on that page. For a tree without duplicate keys, an internal page with
two
* consecutive keys, a and b, will have all records greater than or equal
to a
* and less than b stored on the page associated with a. Duplicate keys
are
* somewhat special and can cause duplicate internal and leaf page records
and
* some minor modifications of the above rule.
*/
typedef struct _binternal {
u_int32_t ksize; /* key size */
pgno_t pgno; /* page number stored on */
#define P_BIGDATA 0x01 /* overflow data */
#define P_BIGKEY 0x02 /* overflow key */
u_char flags;
char bytes[1]; /* data */
} BINTERNAL;
542
Wave OS project early developer manual
p += sizeof(pgno_t); \
*(u_char *)p = flags; \
p += sizeof(u_char); \
}
/*
* For the recno internal pages, the item is a page number with the number
of
* keys found on that page and below.
*/
typedef struct _rinternal {
recno_t nrecs; /* number of records */
pgno_t pgno; /* page number stored below */
} RINTERNAL;
/* For the btree leaf pages, the item is a key and data pair. */
typedef struct _bleaf {
u_int32_t ksize; /* size of key */
u_int32_t dsize; /* size of data */
u_char flags; /* P_BIGDATA, P_BIGKEY */
char bytes[1]; /* data */
} BLEAF;
/*
* A record in the tree is either a pointer to a page and an index in the
page
* or a page number and an index. These structures are used as a cursor,
stack
* entry and search returns as well as to pass records to other routines.
*
* One comment about searches. Internal page searches must find the
largest
* record less than key in the tree so that descents work. Leaf page
searches
* must find the smallest record greater than key so that the returned
index
* is the record's correct position for insertion.
*/
typedef struct _epgno {
pgno_t pgno; /* the page number */
indx_t index; /* the index on the page */
} EPGNO;
/*
* About cursors. The cursor (and the page that contained the key/data
pair
* that it referenced) can be deleted, which makes things a bit tricky. If
* there are no duplicates of the cursor key in the tree (i.e. B_NODUPS is
set
* or there simply aren't any duplicates of the key) we copy the key that
it
544
Wave OS project early developer manual
* referenced when it's deleted, and reacquire a new cursor key if the
cursor
* is used again. If there are duplicates keys, we move to the
next/previous
* key, and set a flag so that we know what happened. NOTE: if duplicate
(to
* the cursor) keys are added to the tree during this process, it is
undefined
* if they will be returned or not in a cursor scan.
*
* The flags determine the possible states of the cursor:
*
* CURS_INIT The cursor references *something*.
* CURS_ACQUIRE The cursor was deleted, and a key has been saved so that
* we can reacquire the right position in the tree.
* CURS_AFTER, CURS_BEFORE
* The cursor was deleted, and now references a key/data pair
* that has not yet been returned, either before or after the
* deleted key/data pair.
* XXX
* This structure is broken out so that we can eventually offer multiple
* cursors as part of the DB interface.
*/
typedef struct _cursor {
EPGNO pg; /* B: Saved tree reference. */
DBT key; /* B: Saved key, or key.data == NULL. */
recno_t rcursor; /* R: recno cursor (1-based) */
/*
* The metadata of the tree. The nrecs field is used only by the RECNO
code.
* This is because the btree doesn't really need it and it requires that
every
* put or delete call modify the metadata.
*/
typedef struct _btmeta {
u_int32_t magic; /* magic number */
u_int32_t version; /* version */
u_int32_t psize; /* page size */
u_int32_t free; /* page number of first free page */
u_int32_t nrecs; /* R: number of records */
#define BT_PUSH(t, p, i) { \
t->bt_sp->pgno = p; \
t->bt_sp->index = i; \
++t->bt_sp; \
}
#define BT_POP(t) (t->bt_sp == t->bt_stack ? NULL : --t->bt_sp)
#define BT_CLR(t) (t->bt_sp = t->bt_stack)
EPGNO bt_stack[50]; /* stack of parent pages */
EPGNO *bt_sp; /* current stack pointer */
/*
* NB:
* B_NODUPS and R_RECNO are stored on disk, and may not be changed.
*/
#define B_INMEM 0x00001 /* in-memory tree */
#define B_METADIRTY 0x00002 /* need to write metadata */
#define B_MODIFIED 0x00004 /* tree modified */
#define B_NEEDSWAP 0x00008 /* if byte order requires
swapping */
#define B_RDONLY 0x00010 /* read-only tree */
546
Wave OS project early developer manual
#include "extern.h"
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)extern.h 8.10 (Berkeley) 7/20/94
*/
#ifdef DEBUG
void __bt_dnpage __P((DB *, pgno_t));
void __bt_dpage __P((PAGE *));
void __bt_dump __P((DB *));
#endif
#ifdef STATISTICS
void __bt_stat __P((DB *));
#endif
/* Values for building 4.4 BSD db routines in the GNU C library. */
#ifndef _compat_h_
#define _compat_h_
#include <fcntl.h>
/*
* If you can't provide lock values in the open(2) call. Note, this
* allows races to happen.
*/
#ifndef O_EXLOCK /* 4.4BSD extension. */
#define O_EXLOCK 0
#endif
#include <errno.h>
#ifndef EFTYPE
#define EFTYPE EINVAL /* POSIX 1003.1 format
errno. */
#endif
#include <unistd.h>
#include <limits.h>
#include <termios.h>
548
Wave OS project early developer manual
#include <sys/param.h>
#endif /* compat.h */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)db.h 8.7 (Berkeley) 6/16/94
*/
#ifndef _DB_H
#define _DB_H 1
#include <sys/types.h>
#include <sys/cdefs.h>
#include <limits.h>
Wave OS project early developer manual
#ifdef __DBINTERFACE_PRIVATE
#include <compat.h>
#endif
#ifndef __BIT_TYPES_DEFINED__
#define __BIT_TYPES_DEFINED__
typedef __signed char int8_t;
typedef unsigned char u_int8_t;
typedef short int16_t;
typedef unsigned short u_int16_t;
typedef int int32_t;
typedef unsigned int u_int32_t;
#ifdef WE_DONT_NEED_QUADS
typedef long long int64_t;
typedef unsigned long long u_int64_t;
#endif
#endif
/* Routine flags. */
#define R_CURSOR 1 /* del, put, seq */
#define __R_UNUSED 2 /* UNUSED */
#define R_FIRST 3 /* seq */
#define R_IAFTER 4 /* put (RECNO) */
#define R_IBEFORE 5 /* put (RECNO) */
#define R_LAST 6 /* seq (BTREE, RECNO) */
#define R_NEXT 7 /* seq */
#define R_NOOVERWRITE 8 /* put */
#define R_PREV 9 /* seq (BTREE, RECNO) */
#define R_SETCURSOR 10 /* put (RECNO) */
#define R_RECNOSYNC 11 /* sync (RECNO) */
/*
* !!!
* The following flags are included in the dbopen(3) call as part of the
* open(2) flags. In order to avoid conflicts with the open flags, start
* at the top of the 16 or 32-bit number space and work our way down. If
* the open flags were significantly expanded in the future, it could be
* a problem. Wish I'd left another flags word in the dbopen call.
*
* !!!
* None of this stuff is implemented yet. The only reason that it's here
* is so that the access methods can skip copying the key/data pair when
550
Wave OS project early developer manual
u_long flags;
u_int cachesize; /* bytes to cache */
u_int psize; /* page size */
int lorder; /* byte order */
size_t reclen; /* record length (fixed-length records)
*/
u_char bval; /* delimiting byte (variable-length records
*/
char *bfname; /* btree file name */
} RECNOINFO;
#ifdef __DBINTERFACE_PRIVATE
/*
* Little endian <==> big endian 32-bit swap macros.
* M_32_SWAP swap a memory location
* P_32_SWAP swap a referenced memory location
* P_32_COPY swap from one location to another
*/
#define M_32_SWAP(a) { \
u_int32_t _tmp = a; \
((char *)&a)[0] = ((char *)&_tmp)[3]; \
((char *)&a)[1] = ((char *)&_tmp)[2]; \
((char *)&a)[2] = ((char *)&_tmp)[1]; \
((char *)&a)[3] = ((char *)&_tmp)[0]; \
}
#define P_32_SWAP(a) { \
u_int32_t _tmp = *(u_int32_t *)a; \
((char *)a)[0] = ((char *)&_tmp)[3]; \
((char *)a)[1] = ((char *)&_tmp)[2]; \
((char *)a)[2] = ((char *)&_tmp)[1]; \
((char *)a)[3] = ((char *)&_tmp)[0]; \
}
#define P_32_COPY(a, b) { \
((char *)&(b))[0] = ((char *)&(a))[3]; \
((char *)&(b))[1] = ((char *)&(a))[2]; \
((char *)&(b))[2] = ((char *)&(a))[1]; \
((char *)&(b))[3] = ((char *)&(a))[0]; \
}
/*
* Little endian <==> big endian 16-bit swap macros.
* M_16_SWAP swap a memory location
* P_16_SWAP swap a referenced memory location
* P_16_COPY swap from one location to another
*/
#define M_16_SWAP(a) { \
u_int16_t _tmp = a; \
((char *)&a)[0] = ((char *)&_tmp)[1]; \
((char *)&a)[1] = ((char *)&_tmp)[0]; \
}
#define P_16_SWAP(a) { \
u_int16_t _tmp = *(u_int16_t *)a; \
((char *)a)[0] = ((char *)&_tmp)[1]; \
((char *)a)[1] = ((char *)&_tmp)[0]; \
}
#define P_16_COPY(a, b) { \
((char *)&(b))[0] = ((char *)&(a))[1]; \
((char *)&(b))[1] = ((char *)&(a))[0]; \
}
#endif
552
Wave OS project early developer manual
__BEGIN_DECLS
DB *__dbopen __P((const char *, int, int, DBTYPE, const void *));
DB *dbopen __P((const char *, int, int, DBTYPE, const void *));
#ifdef __DBINTERFACE_PRIVATE
DB *__bt_open __P((const char *, int, int, const BTREEINFO *, int));
DB *__hash_open __P((const char *, int, int, const HASHINFO *, int));
DB *__rec_open __P((const char *, int, int, const RECNOINFO *, int));
void __dbpanic __P((DB *dbp));
#endif
__END_DECLS
#endif /* db.h */
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)extern.h 8.4 (Berkeley) 6/16/94
*/
#ifdef HASH_STATISTICS
extern int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
#endif
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)hash.h 8.3 (Berkeley) 5/31/94
*/
554
Wave OS project early developer manual
/* Operations */
typedef enum {
HASH_GET, HASH_PUT, HASH_PUTNEW, HASH_DELETE, HASH_FIRST, HASH_NEXT
} ACTION;
struct _bufhead {
BUFHEAD *prev; /* LRU links */
BUFHEAD *next; /* LRU links */
BUFHEAD *ovfl; /* Overflow page buffer header */
u_int32_t addr; /* Address of this page */
char *page; /* Actual page data */
char flags;
#define BUF_MOD 0x0001
#define BUF_DISK 0x0002
#define BUF_BUCKET 0x0004
#define BUF_PIN 0x0008
};
/*
* Constants
*/
#define MAX_BSIZE 65536 /* 2^16 */
#define MIN_BUFFERS 6
#define MINHDRSIZE 512
#define DEF_BUFSIZE 65536 /* 64 K */
#define DEF_BUCKET_SIZE 4096
#define DEF_BUCKET_SHIFT 12 /* log2(BUCKET) */
#define DEF_SEGSIZE 256
#define DEF_SEGSIZE_SHIFT 8 /* log2(SEGSIZE) */
#define DEF_DIRSIZE 256
#define DEF_FFACTOR 65536
#define MIN_FFACTOR 4
#define SPLTMAX 8
#define CHARKEY "%$sniglet^&"
#define NUMKEY 1038583
#define BYTE_SHIFT 3
#define INT_TO_BYTE 2
#define INT_BYTE_SHIFT 5
#define ALL_SET ((u_int32_t)0xFFFFFFFF)
#define ALL_CLEAR 0
#define BITS_PER_MAP 32
/* Given the address of the beginning of a big map, clear/set the nth bit
*/
#define CLRBIT(A, N) ((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))
#define SETBIT(A, N) ((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))
#define ISSET(A, N) ((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))
/* Overflow management */
/*
* Overflow page numbers are allocated per split point. At each doubling
556
Wave OS project early developer manual
of
* the table, we can allocate extra pages. So, an overflow page number has
* the top 5 bits indicate which split point and the lower 11 bits indicate
* which page at that split point is indicated (pages within split points
are
* numberered starting with 1).
*/
#define SPLITSHIFT 11
#define SPLITMASK 0x7FF
#define SPLITNUM(N) (((u_int32_t)(N)) >> SPLITSHIFT)
#define OPAGENUM(N) ((N) & SPLITMASK)
#define OADDR_OF(S,O) ((u_int32_t)((u_int32_t)(S) << SPLITSHIFT) +
(O))
#define BUCKET_TO_PAGE(B) \
(B) + hashp->HDRPAGES + ((B) ? hashp->SPARES[__hash_log2((B)+1)-1] :
0)
#define OADDR_TO_PAGE(B) \
BUCKET_TO_PAGE ( (1 << SPLITNUM((B))) -1 ) + OPAGENUM((B));
/*
* page.h contains a detailed description of the page format.
*
* Normally, keys and data are accessed from offset tables in the top of
* each page which point to the beginning of the key and data. There are
* four flag values which may be stored in these offset tables which
indicate
* the following:
*
*
* OVFLPAGE Rather than a key data pair, this pair contains
* the address of an overflow page. The format of
* the pair is:
* OVERFLOW_PAGE_NUMBER OVFLPAGE
*
* PARTIAL_KEY This must be the first key/data pair on a page
* and implies that page contains only a partial key.
* That is, the key is too big to fit on a single page
* so it starts on this page and continues on the next.
* The format of the page is:
* KEY_OFF PARTIAL_KEY OVFL_PAGENO OVFLPAGE
*
* KEY_OFF -- offset of the beginning of the key
* PARTIAL_KEY -- 1
* OVFL_PAGENO - page number of the next overflow page
* OVFLPAGE -- 0
*
* FULL_KEY This must be the first key/data pair on the page. It
* is used in two cases.
*
* Case 1:
* There is a complete key on the page but no data
* (because it wouldn't fit). The next page contains
* the data.
*
* Page format it:
* KEY_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
*
* KEY_OFF -- offset of the beginning of the key
* FULL_KEY -- 2
* OVFL_PAGENO - page number of the next overflow page
Wave OS project early developer manual
* OVFLPAGE -- 0
*
* Case 2:
* This page contains no key, but part of a large
* data field, which is continued on the next page.
*
* Page format it:
* DATA_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
*
* KEY_OFF -- offset of the beginning of the data on
* this page
* FULL_KEY -- 2
* OVFL_PAGENO - page number of the next overflow page
* OVFLPAGE -- 0
*
* FULL_KEY_DATA
* This must be the first key/data pair on the page.
* There are two cases:
*
* Case 1:
* This page contains a key and the beginning of the
* data field, but the data field is continued on the
* next page.
*
* Page format is:
* KEY_OFF FULL_KEY_DATA OVFL_PAGENO DATA_OFF
*
* KEY_OFF -- offset of the beginning of the key
* FULL_KEY_DATA -- 3
* OVFL_PAGENO - page number of the next overflow page
* DATA_OFF -- offset of the beginning of the data
*
* Case 2:
* This page contains the last page of a big data pair.
* There is no key, only the tail end of the data
* on this page.
*
* Page format is:
* DATA_OFF FULL_KEY_DATA <OVFL_PAGENO> <OVFLPAGE>
*
* DATA_OFF -- offset of the beginning of the data on
* this page
* FULL_KEY_DATA -- 3
* OVFL_PAGENO - page number of the next overflow page
* OVFLPAGE -- 0
*
* OVFL_PAGENO and OVFLPAGE are optional (they are
* not present if there is no next page).
*/
#define OVFLPAGE 0
#define PARTIAL_KEY 1
#define FULL_KEY 2
#define FULL_KEY_DATA 3
#define REAL_KEY 4
558
Wave OS project early developer manual
/*
* Definitions for hashing page file format.
*/
Wave OS project early developer manual
/*
* routines dealing with a data page
*
* page format:
* +------------------------------+
* p | n | keyoff | datoff | keyoff |
* +------------+--------+--------+
* | datoff | free | ptr | --> |
* +--------+---------------------+
* | F R E E A R E A |
* +--------------+---------------+
* | <---- - - - | data |
* +--------+-----+----+----------+
* | key | data | key |
* +--------+----------+----------+
*
* Pointer to the free space is always: p[p[0] + 2]
* Amount of free space on the page is: p[p[0] + 1]
*/
/*
* How many bytes required for this pair?
* 2 shorts in the table at the top of the page + room for the
* key and room for the data
*
* We prohibit entering a pair on a page unless there is also room to
append
* an overflow page. The reason for this it that you can get in a situation
* where a single key/data pair fits on a page, but you can't append an
* overflow page and later you'd have to split the key/data and handle like
* a big pair.
* You might as well do this up front.
*/
typedef struct {
BUFHEAD *newp;
BUFHEAD *oldp;
BUFHEAD *nextp;
u_int16_t next_addr;
} SPLIT_RETURN;
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright
560
Wave OS project early developer manual
#include "../btree/extern.h"
#include "../btree/btree.h"
#include "extern.h"
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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
562
Wave OS project early developer manual
WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mpool.h 8.2 (Berkeley) 7/14/94
*/
#ifndef _MPOOL_H
#define _MPOOL_H 1
#include <sys/queue.h>
/*
* The memory pool scheme is a simple one. Each in-memory page is
referenced
* by a bucket which is threaded in up to two of three ways. All active
pages
* are threaded on a hash chain (hashed by page number) and an lru chain.
* Inactive pages are threaded on a free chain. Each reference to a memory
* pool is handed an opaque MPOOL cookie which stores all of this
information.
*/
#define HASHSIZE 128
#define HASHKEY(pgno) ((pgno - 1) % HASHSIZE)
} MPOOL;
__BEGIN_DECLS
MPOOL *__mpool_open __P((void *, int, pgno_t, pgno_t));
MPOOL *mpool_open __P((void *, int, pgno_t, pgno_t));
void __mpool_filter __P((MPOOL *, void (*)(void *, pgno_t, void *),
void (*)(void *, pgno_t, void *), void *));
void mpool_filter __P((MPOOL *, void (*)(void *, pgno_t, void *),
void (*)(void *, pgno_t, void *), void *));
void *__mpool_new __P((MPOOL *, pgno_t *));
void *mpool_new __P((MPOOL *, pgno_t *));
void *__mpool_get __P((MPOOL *, pgno_t, u_int));
void *mpool_get __P((MPOOL *, pgno_t, u_int));
int __mpool_put __P((MPOOL *, void *, u_int));
int mpool_put __P((MPOOL *, void *, u_int));
int __mpool_sync __P((MPOOL *));
int mpool_sync __P((MPOOL *));
int __mpool_close __P((MPOOL *));
int mpool_close __P((MPOOL *));
#ifdef STATISTICS
void mpool_stat __P((MPOOL *));
#endif
__END_DECLS
#endif /* mpool.h */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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
564
Wave OS project early developer manual
#ifndef _NDBM_H
#define _NDBM_H 1
#include <db.h>
/* Flags to dbm_store(). */
#define DBM_INSERT 0
#define DBM_REPLACE 1
/*
* The db(3) support for ndbm(3) always appends this suffix to the
* file name to avoid overwriting the user's original database.
*/
#define DBM_SUFFIX ".db"
typedef struct {
char *dptr;
int dsize;
} datum;
typedef DB DBM;
#define dbm_pagfno(a) DBM_PAGFNO_NOT_AVAILABLE
__BEGIN_DECLS
void dbm_close __P((DBM *));
int dbm_delete __P((DBM *, datum));
datum dbm_fetch __P((DBM *, datum));
datum dbm_firstkey __P((DBM *));
long dbm_forder __P((DBM *, datum));
datum dbm_nextkey __P((DBM *));
DBM *dbm_open __P((const char *, int, int));
int dbm_store __P((DBM *, datum, datum, int));
int dbm_dirfno __P((DBM *));
int dbm_error __P((DBM *));
int dbm_clearerr __P((DBM *));
__END_DECLS
#endif /* ndbm.h */
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996, 1997, 1998
* Sleepycat Software. All rights reserved.
*
* @(#)txn.h 10.15 (Sleepycat) 4/21/98
*/
#ifndef _TXN_H_
#define _TXN_H_
/*
* The name of the transaction shared memory region is DEFAULT_TXN_FILE and
* the region is always created group RW of the group owning the directory.
*/
Wave OS project early developer manual
/*
* Transaction type declarations.
*/
/*
* Internal data maintained in shared memory for each transaction.
*/
typedef struct __txn_detail {
u_int32_t txnid; /* current transaction id
used to link free list also */
DB_LSN last_lsn; /* last lsn written for this txn */
DB_LSN begin_lsn; /* lsn of begin record */
size_t last_lock; /* offset in lock region of last lock
for this transaction. */
#define TXN_UNALLOC 0
#define TXN_RUNNING 1
#define TXN_ABORTED 2
#define TXN_PREPARED 3
u_int32_t status; /* status of the transaction */
SH_TAILQ_ENTRY links; /* free/active list */
} TXN_DETAIL;
/*
* The transaction manager encapsulates the transaction system. It
contains
* references to the log and lock managers as well as the state that keeps
* track of the shared memory region.
*/
struct __db_txnmgr {
/* These fields need to be protected for multi-threaded support. */
db_mutex_t *mutexp; /* Synchronization. */
/* list of active transactions */
TAILQ_HEAD(_chain, __db_txn) txn_chain;
/*
* Layout of the shared memory region.
* The region consists of a DB_TXNREGION structure followed by a large
* pool of shalloc'd memory which is used to hold TXN_DETAIL structures
* and thread mutexes (which are dynamically allocated).
*/
struct __db_txnregion {
RLAYOUT hdr; /* Shared memory region header. */
u_int32_t magic; /* transaction magic number */
u_int32_t version; /* version number */
u_int32_t maxtxns; /* maximum number of active txns */
566
Wave OS project early developer manual
/*
* Make the region large enough to hold N transaction detail structures
* plus some space to hold thread handles and the beginning of the shalloc
* region.
*/
#define TXN_REGION_SIZE(N) \
(sizeof(DB_TXNREGION) + N * sizeof(TXN_DETAIL) + 1000)
#define LOCK_TXNREGION(tmgrp) \
(void)__db_mutex_lock(&(tmgrp)->region->hdr.lock, (tmgrp)-
>reginfo.fd)
#define UNLOCK_TXNREGION(tmgrp) \
(void)__db_mutex_unlock(&(tmgrp)->region->hdr.lock, (tmgrp)-
>reginfo.fd)
/*
* Log record types.
*/
#define TXN_COMMIT 1
#define TXN_PREPARE 2
#define TXN_CHECKPOINT 3
#include "txn_auto.h"
#include "txn_ext.h"
#endif /* !_TXN_H_ */
/* DO NOT EDIT: automatically built by dist/distrib. */
#ifndef _txn_ext_h_
#define _txn_ext_h_
int __txn_regop_log
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
u_int32_t));
int __txn_regop_print
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __txn_regop_read __P((void *, __txn_regop_args **));
int __txn_ckp_log
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
DB_LSN *, DB_LSN *));
int __txn_ckp_print
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __txn_ckp_read __P((void *, __txn_ckp_args **));
int __txn_init_print __P((DB_ENV *));
Wave OS project early developer manual
#endif
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996, 1997, 1998
* Sleepycat Software. All rights reserved.
*
* @(#)shqueue.h 8.13 (Sleepycat) 4/10/98
*/
#ifndef _SYS_SHQUEUE_H_
#define _SYS_SHQUEUE_H_
/*
* This file defines three types of data structures: lists, tail queues,
and
* circular queues, similarly to the include file <sys/queue.h>.
*
* The difference is that this set of macros can be used for structures
that
* reside in shared memory that may be mapped at different addresses in
each
* process. In most cases, the macros for shared structures exactly mirror
* the normal macros, although the macro calls require an additional type
* parameter, only used by the HEAD and ENTRY macros of the standard
macros.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
/*
* Shared list definitions.
*/
568
Wave OS project early developer manual
#define SH_LIST_HEAD(name) \
struct name { \
ssize_t slh_first; /* first element */ \
}
#define SH_LIST_ENTRY \
struct { \
ssize_t sle_next; /* relative offset next element */ \
ssize_t sle_prev; /* relative offset of prev element */ \
}
/*
* Shared list functions. Since we use relative offsets for pointers,
* 0 is a valid offset. Therefore, we use -1 to indicate end of list.
* The macros ending in "P" return pointers without checking for end
* of list, the others check for end of list and evaluate to either a
* pointer or NULL.
*/
/*
* Take the element's next pointer and calculate what the corresponding
* Prev pointer should be -- basically it is the negation plus the offset
* of the next field in the structure.
*/
#define SH_LIST_NEXT_TO_PREV(elm, field) \
(-(elm)->field.sle_next + SH_PTR_TO_OFF(elm, &(elm)->field.sle_next))
/*
* Shared tail queue definitions.
*/
#define SH_TAILQ_HEAD(name) \
struct name { \
ssize_t stqh_first; /* relative offset of first element */ \
ssize_t stqh_last; /* relative offset of last's next */ \
}
#define SH_TAILQ_ENTRY \
struct { \
ssize_t stqe_next; /* relative offset of next element */ \
ssize_t stqe_prev; /* relative offset of prev's next */ \
}
/*
* Shared tail queue functions.
*/
#define SH_TAILQ_FIRSTP(head, type) \
((struct type *)((u_int8_t *)(head) + (head)->stqh_first))
#define SH_TAILQ_LAST(head) \
((ssize_t *)(((u_int8_t *)(head)) + (head)->stqh_last))
570
Wave OS project early developer manual
>field.stqe_next))
#define SH_TAILQ_INIT(head) { \
(head)->stqh_first = -1; \
(head)->stqh_last = SH_PTR_TO_OFF(head, &(head)->stqh_first); \
}
} else { \
(head)->stqh_last = (elm)->field.stqe_prev + \
SH_PTR_TO_OFF(head, elm); \
*SH_TAILQ_PREVP(elm, field) = -1; \
} \
} while (0)
/*
* Shared circular queue definitions.
*/
#define SH_CIRCLEQ_HEAD(name) \
struct name { \
ssize_t scqh_first; /* first element */ \
ssize_t scqh_last; /* last element */ \
}
#define SH_CIRCLEQ_ENTRY \
struct { \
ssize_t scqe_next; /* next element */ \
ssize_t scqe_prev; /* previous element */ \
}
/*
* Shared circular queue functions.
*/
#define SH_CIRCLEQ_FIRSTP(head, type) \
((struct type *)(((u_int8_t *)(head)) + (head)->scqh_first))
#define SH_CIRCLEQ_INIT(head) { \
(head)->scqh_first = 0; \
(head)->scqh_last = 0; \
}
572
Wave OS project early developer manual
} while (0)
#endif /* !_SYS_SHQUEUE_H_ */
/* BSDI $Id: queue.h,v 1.3 2002/08/19 18:04:51 vanders Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines three types of data structures: lists, tail queues,
* and circular queues.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
574
Wave OS project early developer manual
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#define LIST_INIT(head) { \
(head)->lh_first = NULL; \
}
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
576
Wave OS project early developer manual
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = (void *)(head); \
(head)->cqh_last = (void *)(head); \
} while (0)
} while (0)
578
Wave OS project early developer manual
/*
* Names used by DB to call through the jump table.
*
* The naming scheme goes like this: if the functionality the application
can
* replace is the same as the DB functionality, e.g., malloc, or dirlist,
then
* we use the name __db_XXX, and the application is expected to replace the
* complete functionality, which may or may not map directly to an ANSI C
or
* POSIX 1003.1 interface. If the functionality that the aplication
replaces
* only underlies what the DB os directory exports to other parts of DB,
e.g.,
* read, then the name __os_XXX is used, and the application can only
replace
* the underlying functionality. Under most circumstances, the os
directory
* part of DB is the only code that should use the __os_XXX names, all
other
* parts of DB should be calling __db_XXX functions.
*/
#define __os_close __db_jump.j_close /* __db_close is a wrapper. */
#define __db_dirfree __db_jump.j_dirfree
#define __db_dirlist __db_jump.j_dirlist
#define __db_exists __db_jump.j_exists
#define __db_free __db_jump.j_free
#define __os_fsync __db_jump.j_fsync /* __db_fsync is a wrapper. */
#define __db_ioinfo __db_jump.j_ioinfo
#define __os_open __db_jump.j_open /* __db_open is a wrapper. */
#define __os_read __db_jump.j_read /* __db_read is a wrapper. */
#define __db_seek __db_jump.j_seek
#define __db_sleep __db_jump.j_sleep
#define __os_unlink __db_jump.j_unlink /* __db_unlink is a
wrapper. */
#define __os_write __db_jump.j_write /* __db_write is a wrapper. */
#define __db_yield __db_jump.j_yield
/* DO NOT EDIT: automatically built by dist/distrib. */
#ifndef _os_ext_h_
#define _os_ext_h_
int __db_abspath __P((const char *));
char *__db_strdup __P((const char *));
void *__db_calloc __P((size_t, size_t));
void *__db_malloc __P((size_t));
void *__db_realloc __P((void *, size_t));
int __os_dirlist __P((const char *, char ***, int *));
Wave OS project early developer manual
/*
* We default to 128K (16 8K pages) if the user doesn't specify, and
* require a minimum of 20K.
*/
#ifndef DB_CACHESIZE_DEF
#define DB_CACHESIZE_DEF (128 * 1024)
#endif
#define DB_CACHESIZE_MIN ( 20 * 1024)
580
Wave OS project early developer manual
/*
* There are three ways we do locking in the mpool code:
*
* Locking a handle mutex to provide concurrency for DB_THREAD operations.
* Locking the region mutex to provide mutual exclusion while reading and
* writing structures in the shared region.
* Locking buffer header mutexes during I/O.
*
* The first will not be further described here. We use the shared mpool
* region lock to provide mutual exclusion while reading/modifying all of
* the data structures, including the buffer headers. We use a per-buffer
* header lock to wait on buffer I/O. The order of locking is as follows:
*
* Searching for a buffer:
* Acquire the region lock.
* Find the buffer header.
* Increment the reference count (guarantee the buffer stays).
* While the BH_LOCKED flag is set (I/O is going on) {
* Release the region lock.
* Explicitly yield the processor if it's not the first pass
* through this loop, otherwise, we can simply spin because
* we'll be simply switching between the two locks.
* Request the buffer lock.
* The I/O will complete...
* Acquire the buffer lock.
* Release the buffer lock.
* Acquire the region lock.
* }
* Return the buffer.
*
* Reading/writing a buffer:
* Acquire the region lock.
* Find/create the buffer header.
* If reading, increment the reference count (guarantee the buffer
stays).
* Set the BH_LOCKED flag.
* Acquire the buffer lock (guaranteed not to block).
* Release the region lock.
* Do the I/O and/or initialize the buffer contents.
* Release the buffer lock.
* At this point, the buffer lock is available, but the logical
* operation (flagged by BH_LOCKED) is not yet completed. For
* this reason, among others, threads checking the BH_LOCKED flag
* must loop around their test.
* Acquire the region lock.
* Clear the BH_LOCKED flag.
* Release the region lock.
* Return/discard the buffer.
*
* Pointers to DB_MPOOL, MPOOL, DB_MPOOLFILE and MPOOLFILE structures are
not
* reacquired when a region lock is reacquired because they couldn't have
been
* closed/discarded and because they never move in memory.
*/
#define LOCKINIT(dbmp, mutexp) \
if (F_ISSET(dbmp, MP_LOCKHANDLE | MP_LOCKREGION)) \
(void)__db_mutex_init(mutexp, \
MUTEX_LOCK_OFFSET((dbmp)->reginfo.addr, mutexp))
(void)__db_mutex_lock(mutexp, (dbmp)->reginfo.fd)
#define UNLOCKHANDLE(dbmp, mutexp) \
if (F_ISSET(dbmp, MP_LOCKHANDLE)) \
(void)__db_mutex_unlock(mutexp, (dbmp)->reginfo.fd)
#define LOCKREGION(dbmp) \
if (F_ISSET(dbmp, MP_LOCKREGION)) \
(void)__db_mutex_lock(&((RLAYOUT *)(dbmp)->mp)->lock, \
(dbmp)->reginfo.fd)
#define UNLOCKREGION(dbmp) \
if (F_ISSET(dbmp, MP_LOCKREGION)) \
(void)__db_mutex_unlock(&((RLAYOUT *)(dbmp)->mp)->lock, \
(dbmp)->reginfo.fd)
/*
* DB_MPOOL --
* Per-process memory pool structure.
*/
struct __db_mpool {
/* These fields need to be protected for multi-threaded support. */
db_mutex_t *mutexp; /* Structure lock. */
/* List of DB_MPOOLFILE's. */
TAILQ_HEAD(__db_mpoolfileh, __db_mpoolfile) dbmfq;
/*
* DB_MPREG --
* DB_MPOOL registry of pgin/pgout functions.
*/
struct __db_mpreg {
LIST_ENTRY(__db_mpreg) q; /* Linked list. */
582
Wave OS project early developer manual
/*
* DB_MPOOLFILE --
* Per-process DB_MPOOLFILE information.
*/
struct __db_mpoolfile {
/* These fields need to be protected for multi-threaded support. */
db_mutex_t *mutexp; /* Structure lock. */
/*
* MPOOL --
* Shared memory pool region. One of these is allocated in shared
* memory, and describes the pool.
*/
struct __mpool {
RLAYOUT rlayout; /* General region information. */
/*
* We make the assumption that the early pages of the file are far
* more likely to be retrieved than the later pages, which means
* that the top bits are more interesting for hashing since they're
* less likely to collide. On the other hand, since 512 4K pages
* represents a 2MB file, only the bottom 9 bits of the page number
* are likely to be set. We XOR in the offset in the MPOOL of the
* MPOOLFILE that backs this particular page, since that should also
* be unique for the page.
*/
#define BUCKET(mp, mf_offset, pgno) \
(((pgno) ^ ((mf_offset) << 9)) % (mp)->htab_buckets)
/*
* MPOOLFILE --
* Shared DB_MPOOLFILE information.
*/
struct __mpoolfile {
SH_TAILQ_ENTRY q; /* List of MPOOLFILEs */
/*
* BH --
* Buffer header.
*/
struct __bh {
db_mutex_t mutex; /* Structure lock. */
584
Wave OS project early developer manual
/*
* !!!
* This array must be size_t aligned -- the DB access methods put
PAGE
* and other structures into it, and expect to be able to access them
* directly. (We guarantee size_t alignment in the db_mpool(3)
manual
* page as well.)
*/
u_int8_t buf[1]; /* Variable length data. */
};
#ifndef HAVE_RAISE
int raise __P((int));
#endif
#ifndef HAVE_SNPRINTF
#ifdef __STDC__
int snprintf __P((char *, size_t, const char *, ...));
#else
int snprintf();
#endif
#endif
#ifndef HAVE_STRERROR
char *strerror __P((int));
#endif
#ifndef HAVE_STRSEP
char *strsep __P((char **, const char *));
#endif
#ifndef HAVE_VSNPRINTF
int vsnprintf();
#endif
#endif /* _clib_ext_h_ */
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996, 1997, 1998
* Sleepycat Software. All rights reserved.
*/
/*
* Copyright (c) 1990, 1993, 1994, 1995, 1996
* Keith Bostic. All rights reserved.
*/
/*
* Copyright (c) 1990, 1993, 1994, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
586
Wave OS project early developer manual
/*
* If doing transactions we have to hold the locks associated with a data
item
* from a page for the entire transaction. However, we don't have to hold
the
* locks associated with walking the tree. Distinguish between the two so
that
* we don't tie up the internal pages of the tree longer than necessary.
*/
#define __BT_LPUT(dbp, lock) \
(F_ISSET((dbp), DB_AM_LOCKING) ? \
lock_put((dbp)->dbenv->lk_info, lock) : 0)
#define __BT_TLPUT(dbp, lock) \
(F_ISSET((dbp), DB_AM_LOCKING) && (dbp)->txn == NULL ? \
lock_put((dbp)->dbenv->lk_info, lock) : 0)
/*
* Flags to __bt_search() and __rec_search().
*
* Note, internal page searches must find the largest record less than key
in
Wave OS project early developer manual
* the tree so that descents work. Leaf page searches must find the
smallest
* record greater than key so that the returned index is the record's
correct
* position for insertion.
*
* The flags parameter to the search routines describes three aspects of
the
* search: the type of locking required (including if we're locking a pair
of
* pages), the item to return in the presence of duplicates and whether or
not
* to return deleted entries. To simplify both the mnemonic representation
* and the code that checks for various cases, we construct a set of
bitmasks.
*/
#define S_READ 0x00001 /* Read locks. */
#define S_WRITE 0x00002 /* Write locks. */
/*
* If doing insert search (including keyfirst or keylast operations) or a
* split search on behalf of an insert, it's okay to return the entry one
* past the end of the page.
*/
#define PAST_END_OK(f) \
((f) == S_INSERT || \
(f) == S_KEYFIRST || (f) == S_KEYLAST || (f) == S_WRPAIR)
/*
* Flags to __bam_iitem().
*/
#define BI_DELETED 0x01 /* Key/data pair only placeholder. */
#define BI_DOINCR 0x02 /* Increment the record count. */
#define BI_NEWKEY 0x04 /* New key. */
/*
* Various routines pass around page references. A page reference can be a
* pointer to the page or a page number; for either, an indx can designate
* an item on the page.
*/
struct __epg {
PAGE *page; /* The page. */
db_indx_t indx; /* The index on the page. */
588
Wave OS project early developer manual
/*
* All cursors are queued from the master DB structure. Convert the user's
* DB reference to the master DB reference. We lock the master DB mutex
* so that we can walk the cursor queue. There's no race in accessing the
* cursors, because if we're modifying a page, we have a write lock on it,
* and therefore no other thread than the current one can have a cursor
that
* references the page.
*/
#define CURSOR_SETUP(dbp) { \
(dbp) = (dbp)->master; \
DB_THREAD_LOCK(dbp); \
}
#define CURSOR_TEARDOWN(dbp) \
DB_THREAD_UNLOCK(dbp);
/*
* Btree cursor.
*
* Arguments passed to __bam_ca_replace().
*/
typedef enum {
REPLACE_SETUP,
REPLACE_SUCCESS,
REPLACE_FAILED
} ca_replace_arg;
struct __cursor {
DBC *dbc; /* Enclosing DBC. */
/*
* If a cursor record is deleted, the key/data pair has to remain on
* the page so that subsequent inserts/deletes don't interrupt the
* cursor progression through the file. This results in interesting
* cases when "standard" operations, e.g., dbp->put() are done in the
* context of "deleted" cursors.
*
* C_DELETED -- The item referenced by the cursor has been "deleted"
* but not physically removed from the page.
* C_REPLACE -- The "deleted" item referenced by a cursor has been
* replaced by a dbp->put(), so the cursor is no longer
* responsible for physical removal from the page.
* C_REPLACE_SETUP --
* We are about to overwrite a "deleted" item, flag any
* cursors referencing it for transition to C_REPLACE
* state.
*/
#define C_DELETED 0x0001
#define C_REPLACE 0x0002
Wave OS project early developer manual
/*
* Internal cursor held for DB->get; don't hold locks unless involved
* in a TXN.
*/
#define C_INTERNAL 0x0008
u_int32_t flags;
};
/*
* Recno cursor.
*
* Arguments passed to __ram_ca().
*/
typedef enum {
CA_DELETE,
CA_IAFTER,
CA_IBEFORE
} ca_recno_arg;
struct __rcursor {
DBC *dbc; /* Enclosing DBC. */
/*
* Cursors referencing "deleted" records are positioned between
* two records, and so must be specially adjusted until they are
* moved.
*/
#define CR_DELETED 0x0001 /* Record deleted. */
u_int32_t flags;
};
/*
* We maintain a stack of the pages that we're locking in the tree.
Btree's
* (currently) only save two levels of the tree at a time, so the default
* stack is always large enough. Recno trees have to lock the entire tree
to
* do inserts/deletes, however. Grow the stack as necessary.
*/
#undef BT_STK_CLR
#define BT_STK_CLR(t) \
((t)->bt_csp = (t)->bt_sp)
#undef BT_STK_ENTER
#define BT_STK_ENTER(t, pagep, page_indx, lock, ret) do { \
if ((ret = \
(t)->bt_csp == (t)->bt_esp ? __bam_stkgrow(t) : 0) == 0) { \
(t)->bt_csp->page = pagep; \
(t)->bt_csp->indx = page_indx; \
(t)->bt_csp->lock = lock; \
} \
} while (0)
#undef BT_STK_PUSH
#define BT_STK_PUSH(t, pagep, page_indx, lock, ret) do { \
BT_STK_ENTER(t, pagep, page_indx, lock, ret); \
++(t)->bt_csp; \
} while (0)
590
Wave OS project early developer manual
#undef BT_STK_POP
#define BT_STK_POP(t) \
((t)->bt_csp == (t)->bt_stack ? NULL : --(t)->bt_csp)
/*
* The in-memory recno data structure.
*
* !!!
* These fields are ignored as far as multi-threading is concerned. There
* are no transaction semantics associated with backing files, nor is there
* any thread protection.
*/
#undef RECNO_OOB
#define RECNO_OOB 0 /* Illegal record number. */
struct __recno {
int re_delim; /* Variable-length delimiting byte. */
int re_pad; /* Fixed-length padding byte. */
u_int32_t re_len; /* Length for fixed-length records. */
/*
* The in-memory btree data structure.
*/
struct __btree {
/*
* These fields are per-thread and are initialized when the BTREE structure
* is created.
*/
db_pgno_t bt_lpgno; /* Last insert location. */
/*
* These fields are copied from the original BTREE structure and never
* change.
*/
Wave OS project early developer manual
#include "btree_auto.h"
#include "btree_ext.h"
#include "db_am.h"
#include "common_ext.h"
/* DO NOT EDIT: automatically built by dist/distrib. */
#ifndef _btree_ext_h_
#define _btree_ext_h_
int __bam_close __P((DB *));
int __bam_sync __P((DB *, u_int32_t));
int __bam_cmp __P((DB *, const DBT *, EPG *));
int __bam_defcmp __P((const DBT *, const DBT *));
size_t __bam_defpfx __P((const DBT *, const DBT *));
int __bam_pgin __P((db_pgno_t, void *, DBT *));
int __bam_pgout __P((db_pgno_t, void *, DBT *));
int __bam_mswap __P((PAGE *));
int __bam_cursor __P((DB *, DB_TXN *, DBC **));
int __bam_c_iclose __P((DB *, DBC *));
int __bam_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
int __bam_ovfl_chk __P((DB *, CURSOR *, u_int32_t, int));
int __bam_cprint __P((DB *));
int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, CURSOR *, int));
void __bam_ca_di __P((DB *, db_pgno_t, u_int32_t, int));
void __bam_ca_dup __P((DB *,
db_pgno_t, u_int32_t, u_int32_t, db_pgno_t, u_int32_t));
void __bam_ca_move __P((DB *, db_pgno_t, db_pgno_t));
void __bam_ca_replace
__P((DB *, db_pgno_t, u_int32_t, ca_replace_arg));
void __bam_ca_split __P((DB *,
db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int));
int __bam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
int __ram_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
int __bam_ditem __P((DB *, PAGE *, u_int32_t));
int __bam_adjindx __P((DB *, PAGE *, u_int32_t, u_int32_t, int));
int __bam_dpage __P((DB *, const DBT *));
int __bam_open __P((DB *, DBTYPE, DB_INFO *));
int __bam_bdup __P((DB *, DB *));
int __bam_new __P((DB *, u_int32_t, PAGE **));
int __bam_free __P((DB *, PAGE *));
int __bam_lt __P((DB *));
int __bam_lget __P((DB *, int, db_pgno_t, db_lockmode_t, DB_LOCK *));
int __bam_lput __P((DB *, DB_LOCK));
int __bam_pget __P((DB *, PAGE **, db_pgno_t *, u_int32_t));
int __bam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
int __bam_iitem __P((DB *,
PAGE **, db_indx_t *, DBT *, DBT *, u_int32_t, u_int32_t));
int __bam_ritem __P((DB *, PAGE *, u_int32_t, DBT *));
int __bam_pg_alloc_recover
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_pg_free_recover
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
592
Wave OS project early developer manual
int __bam_split_recover
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_rsplit_recover
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_adj_recover
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_cadjust_recover
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_cdel_recover
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_repl_recover
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __ram_open __P((DB *, DBTYPE, DB_INFO *));
int __ram_cursor __P((DB *, DB_TXN *, DBC **));
int __ram_close __P((DB *));
int __ram_c_iclose __P((DB *, DBC *));
void __ram_ca __P((DB *, db_recno_t, ca_recno_arg));
int __ram_cprint __P((DB *));
int __ram_getno __P((DB *, const DBT *, db_recno_t *, int));
int __ram_snapshot __P((DB *));
int __bam_rsearch __P((DB *, db_recno_t *, u_int32_t, int, int *));
int __bam_adjust __P((DB *, BTREE *, int32_t));
int __bam_nrecs __P((DB *, db_recno_t *));
db_recno_t __bam_total __P((PAGE *));
int __bam_search __P((DB *,
const DBT *, u_int32_t, int, db_recno_t *, int *));
int __bam_stkrel __P((DB *));
int __bam_stkgrow __P((BTREE *));
int __bam_split __P((DB *, void *));
int __bam_broot __P((DB *, PAGE *, PAGE *, PAGE *));
int __ram_root __P((DB *, PAGE *, PAGE *, PAGE *));
int __bam_copy __P((DB *, PAGE *, PAGE *, u_int32_t, u_int32_t));
int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
void __bam_add_mstat __P((DB_BTREE_LSTAT *, DB_BTREE_LSTAT *));
int __bam_pg_alloc_log
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
u_int32_t, DB_LSN *, DB_LSN *, db_pgno_t,
u_int32_t, db_pgno_t));
int __bam_pg_alloc_print
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_pg_alloc_read __P((void *, __bam_pg_alloc_args **));
int __bam_pg_free_log
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
u_int32_t, db_pgno_t, DB_LSN *, const DBT *,
db_pgno_t));
int __bam_pg_free_print
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_pg_free_read __P((void *, __bam_pg_free_args **));
int __bam_split_log
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t,
DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *,
const DBT *));
int __bam_split_print
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
int __bam_split_read __P((void *, __bam_split_args **));
int __bam_rsplit_log
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
u_int32_t, db_pgno_t, const DBT *, db_pgno_t,
const DBT *, DB_LSN *));
int __bam_rsplit_print
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
Wave OS project early developer manual
594
Wave OS project early developer manual
db_pgno_t next;
} __bam_pg_free_args;
int32_t adjust;
int32_t total;
} __bam_cadjust_args;
#endif
/* DO NOT EDIT: automatically built by dist/distrib. */
#ifndef _common_ext_h_
#define _common_ext_h_
int __db_appname __P((DB_ENV *,
APPNAME, const char *, const char *, u_int32_t, int *, char **));
int __db_apprec __P((DB_ENV *, u_int32_t));
int __db_byteorder __P((DB_ENV *, int));
#ifdef __STDC__
void __db_err __P((const DB_ENV *dbenv, const char *fmt, ...));
#else
void __db_err();
#endif
int __db_panic __P((DB *));
int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t));
int __db_fcchk
__P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
int __db_cdelchk __P((const DB *, u_int32_t, int, int));
int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int));
int __db_cputchk __P((const DB *,
const DBT *, DBT *, u_int32_t, int, int));
int __db_delchk __P((const DB *, DBT *, u_int32_t, int));
int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t));
int __db_putchk
__P((const DB *, DBT *, const DBT *, u_int32_t, int, int));
int __db_statchk __P((const DB *, u_int32_t));
596
Wave OS project early developer manual
#ifndef _CXX_INT_H_
#define _CXX_INT_H_
//
// Using FooImp classes will allow the implementation to change in the
// future without any modification to user code or even to header files
// that the user includes. FooImp * is just like void * except that it
// provides a little extra protection, since you cannot randomly assign
// any old pointer to a FooImp* as you can with void *. Currently, a
// pointer to such an opaque class is always just a pointer to the
// appropriate underlying implementation struct. These are converted
// back and forth using the various overloaded wrap()/unwrap() methods.
// This is essentially a use of the "Bridge" Design Pattern.
//
// WRAPPED_CLASS implements the appropriate wrap() and unwrap() methods
// for a wrapper class that has an underlying pointer representation.
//
#define WRAPPED_CLASS(_WRAPPER_CLASS, _IMP_CLASS,
_WRAPPED_TYPE) \
\
class _IMP_CLASS
{}; \
\
inline _WRAPPED_TYPE unwrap(_WRAPPER_CLASS
*val) \
{
\
if (!val) return
0; \
return (_WRAPPED_TYPE)(val-
Wave OS project early developer manual
>imp()); \
}
\
\
inline const _WRAPPED_TYPE unwrapConst(const _WRAPPER_CLASS
*val) \
{
\
if (!val) return
0; \
return (const _WRAPPED_TYPE)(val-
>imp()); \
}
\
\
inline _IMP_CLASS *wrap(_WRAPPED_TYPE
val) \
{
\
return
(_IMP_CLASS*)val; \
}
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// These defines are for tedious flag or field set/get access methods.
//
598
Wave OS project early developer manual
if (onOrOff) \
_flags |= _flag_name; \
else \
_flags &= ~(_flag_name); \
} \
\
int _class::get##_cxx_name() const \
{ \
return (_flags & _flag_name) ? 1 : 0; \
}
#endif /* !_CXX_INT_H_ */
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996, 1997, 1998
* Sleepycat Software. All rights reserved.
*
* @(#)db_am.h 10.9 (Sleepycat) 4/10/98
*/
#ifndef _DB_AM_H
#define _DB_AM_H
/*
* Standard initialization and shutdown macros for all recovery functions.
*
* Requires the following local variables:
*
* DB *file_dbp, *mdbp;
* DB_MPOOLFILE *mpf;
* int ret;
*/
#define REC_INTRO(func) { \
file_dbp = mdbp = NULL; \
if ((ret = func(dbtp->data, &argp)) != 0) \
Wave OS project early developer manual
goto out; \
if ((ret = __db_fileid_to_db(logp, &mdbp, argp->fileid)) != 0) {\
if (ret == DB_DELETED) \
ret = 0; \
goto out; \
} \
if (mdbp == NULL) \
goto out; \
if (F_ISSET(mdbp, DB_AM_THREAD)) { \
if ((ret = __db_gethandle(mdbp, \
mdbp->type == DB_HASH ? __ham_hdup : __bam_bdup, \
&file_dbp)) != 0) \
goto out; \
} else \
file_dbp = mdbp; \
F_SET(file_dbp, DB_AM_RECOVER); \
mpf = file_dbp->mpf; \
}
#define REC_CLOSE { \
if (argp != NULL) \
__db_free(argp); \
if (file_dbp != NULL) { \
F_CLR(file_dbp, DB_AM_RECOVER); \
if (F_ISSET(file_dbp, DB_AM_THREAD)) \
__db_puthandle(file_dbp); \
} \
return (ret); \
}
/*
* No-op versions of the same macros.
*/
#define REC_NOOP_INTRO(func) { \
if ((ret = func(dbtp->data, &argp)) != 0) \
return (ret); \
}
#define REC_NOOP_CLOSE { \
if (argp != NULL) \
__db_free(argp); \
return (ret); \
}
/*
* Standard debugging macro for all recovery functions.
*/
#ifdef DEBUG_RECOVER
#define REC_PRINT(func) \
(void)func(logp, dbtp, lsnp, redo, info);
#else
#define REC_PRINT(func) \
COMPQUIET(info, NULL);
#endif
#include "db_auto.h"
#include "db_ext.h"
#endif
/* Do not edit: automatically built by dist/db_gen.sh. */
#ifndef db_AUTO_H
#define db_AUTO_H
600
Wave OS project early developer manual
#endif
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1997, 1998
* Sleepycat Software. All rights reserved.
*
602
Wave OS project early developer manual
#ifndef _DB_CXX_H_
#define _DB_CXX_H_
//
// C++ assumptions:
//
// To ensure portability to many platforms, both new and old, we make
// few assumptions about the C++ compiler and library. For example,
// we do not expect STL, templates or namespaces to be available. The
// "newest" C++ feature used is exceptions, which are used liberally
// to transmit error information. Even the use of exceptions can be
// disabled at runtime, see setErrorModel().
//
// C++ naming conventions:
//
// - All top level class names start with Db.
// - All class members start with lower case letter.
// - All private data members are suffixed with underscore.
// - Use underscores to divide names into multiple words.
// - Simple data accessors are named with get_ or set_ prefix.
// - All method names are taken from names of functions in the C
// layer of db (usually by dropping a prefix like "db_").
// These methods have the same argument types and order,
// other than dropping the explicit arg that acts as "this".
//
// As a rule, each DbFoo object has exactly one underlying DB_FOO struct
// (defined in db.h) associated with it. In many cases, we inherit
directly
// from the DB_FOO structure to make this relationship explicit. Often,
// the underlying C layer allocates and deallocates these structures, so
// there is no easy way to add any data to the DbFoo class. When you see
// a comment about whether data is permitted to be added, this is what
// is going on. Of course, if we need to add data to such C++ classes
// in the future, we will arrange to have an indirect pointer to the
// DB_FOO struct (as some of the classes already have).
//
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Forward declarations
//
#include "db.h"
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Mechanisms for declaring classes
//
//
// Every class defined in this file has an _exported next to the class
name.
// This is needed for WinTel machines so that the class methods can
// be exported or imported in a DLL as appropriate. Users of the DLL
// use the define DB_USE_DLL. When the DLL is built, DB_CREATE_DLL
// must be defined.
//
#if defined(_MSC_VER)
# if defined(DB_CREATE_DLL)
# define _exported __declspec(dllexport) // creator of dll
# elif defined(DB_USE_DLL)
# define _exported __declspec(dllimport) // user of dll
# else
# define _exported // static lib creator or
user
# endif
#else
# define _exported
#endif
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Turn off inappropriate compiler warnings
//
#ifdef _MSC_VER
604
Wave OS project early developer manual
#endif
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Exception classes
//
private:
char *what_;
int err_; // errno
};
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Lock classes
//
public:
DbLock(u_int);
DbLock();
u_int get_lock_id();
void set_lock_id(u_int);
protected:
// We can add data to this class if needed
// since its contained class is not allocated by db.
// (see comment at top)
DB_LOCK lock_;
};
private:
// We can add data to this class if needed
// since it is implemented via a pointer.
// (see comment at top)
DEFINE_DB_CLASS(DbLockTab);
};
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Log classes
//
606
Wave OS project early developer manual
};
private:
// We can add data to this class if needed
// since it is implemented via a pointer.
// (see comment at top)
// no copying
DbLog(const DbLog &);
operator = (const DbLog &);
DEFINE_DB_CLASS(DbLog);
};
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Memory pool classes
//
int sync();
private:
// We can add data to this class if needed
// since it is implemented via a pointer.
// (see comment at top)
private:
// no copying
DbMpoolFile(const DbMpoolFile &);
operator = (const DbMpoolFile &);
DEFINE_DB_CLASS(DbMpoolFile);
};
private:
// We can add data to this class if needed
// since it is implemented via a pointer.
// (see comment at top)
608
Wave OS project early developer manual
// no copying
DbMpool(const DbMpool &);
DbMpool &operator = (const DbMpool &);
DEFINE_DB_CLASS(DbMpool);
};
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Transaction classes
//
private:
// We can add data to this class if needed
// since it is implemented via a pointer.
// (see comment at top)
// no copying
DbTxnMgr(const DbTxnMgr &);
operator = (const DbTxnMgr &);
DEFINE_DB_CLASS(DbTxnMgr);
};
int prepare();
private:
// We can add data to this class if needed
// since it is implemented via a pointer.
// (see comment at top)
// no copying
DbTxn(const DbTxn &);
operator = (const DbTxn &);
DEFINE_DB_CLASS(DbTxn);
};
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Application classes
//
//
// A set of application options - define how this application uses
// the db library.
//
class _exported DbInfo : protected DB_INFO
{
friend DbEnv;
friend Db;
public:
DbInfo();
~DbInfo();
// Byte order.
int get_lorder() const;
void set_lorder(int);
////////////////////////////////////////////////////////////////
// Btree access method.
610
Wave OS project early developer manual
// Comparison function.
typedef int (*bt_compare_fcn)(const DBT *, const DBT *);
bt_compare_fcn get_bt_compare() const;
void set_bt_compare(bt_compare_fcn);
// Prefix function.
typedef size_t (*bt_prefix_fcn)(const DBT *, const DBT *);
bt_prefix_fcn get_bt_prefix() const;
void set_bt_prefix(bt_prefix_fcn);
////////////////////////////////////////////////////////////////
// Hash access method.
// Fill factor.
u_int32_t get_h_ffactor() const;
void set_h_ffactor(u_int32_t);
// Number of elements.
u_int32_t get_h_nelem() const;
void set_h_nelem(u_int32_t);
// Hash function.
typedef u_int32_t (*h_hash_fcn)(const void *, u_int32_t);
h_hash_fcn get_h_hash() const;
void set_h_hash(h_hash_fcn);
////////////////////////////////////////////////////////////////
// Recno access method.
private:
// We can add data to this class if needed
// since parent class is not allocated by db.
// (see comment at top)
};
//
// Base application class. Provides functions for opening a database.
// User of this library can use this class as a starting point for
// developing a DB application - derive their application class from
// this one, add application control logic.
//
// Note that if you use the default constructor, you must explicitly
// call appinit() before any other db activity (e.g. opening files)
//
class _exported DbEnv : protected DB_ENV
{
friend DbTxnMgr;
friend DbLog;
friend DbLockTab;
friend DbMpool;
friend Db;
public:
~DbEnv();
////////////////////////////////////////////////////////////////
// simple get/set access methods
//
// If you are calling set_ methods, you need to
// use the default constructor along with appinit().
// Byte order.
612
Wave OS project early developer manual
////////////////////////////////////////////////////////////////
// User paths.
// Database home.
char *get_home() const;
void set_home(char *);
////////////////////////////////////////////////////////////////
// Locking.
////////////////////////////////////////////////////////////////
// Logging.
////////////////////////////////////////////////////////////////
// Memory pool.
////////////////////////////////////////////////////////////////
// Transactions.
// Flags.
u_int32_t get_flags() const;
void set_flags(u_int32_t);
////////////////////////////////////////////////////////////////
// The default error model is to throw an exception whenever
// an error occurs. This generally allows for cleaner logic
// for transaction processing, as a try block can surround a
// single transaction. Alternatively, since almost every method
// returns an error code (errno), the error model can be set to
// not throw exceptions, and instead return the appropriate code.
614
Wave OS project early developer manual
//
enum ErrorModel { Exception, ErrorReturn };
void set_error_model(ErrorModel);
ErrorModel get_error_model() const;
// used internally
static int runtime_error(const char *caller, int err, int in_destructor
= 0);
private:
// We can add data to this class if needed
// since parent class is not allocated by db.
// (see comment at top)
// no copying
DbEnv(const DbEnv &);
operator = (const DbEnv &);
ErrorModel error_model_;
static void stream_error_function(const char *, char *);
static ostream *error_stream_;
};
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// Table access classes
//
//
// Represents a database table = a set of keys with associated values.
//
class _exported Db
{
friend DbEnv;
public:
int close(u_int32_t flags);
int cursor(DbTxn *txnid, Dbc **cursorp);
int del(DbTxn *txnid, Dbt *key, u_int32_t flags);
int fd(int *fdp);
int get(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);
int put(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);
int stat(void *sp, void *(*db_malloc)(size_t), u_int32_t flags);
int sync(u_int32_t flags);
private:
// We can add data to this class if needed
// since it is implemented via a pointer.
// (see comment at top)
// no copying
Db(const Db &);
Db &operator = (const Db &);
DEFINE_DB_CLASS(Db);
};
//
// A chunk of data, maybe a key or value.
//
class _exported Dbt : private DBT
{
friend Dbc;
friend Db;
friend DbLog;
friend DbMpoolFile;
friend DbLockTab;
public:
// key/data
void *get_data() const;
void set_data(void *);
// key/data length
u_int32_t get_size() const;
void set_size(u_int32_t);
// flags
u_int32_t get_flags() const;
void set_flags(u_int32_t);
616
Wave OS project early developer manual
private:
// We can add data to this class if needed
// since parent class is not allocated by db.
// (see comment at top)
};
public:
int close();
int del(u_int32_t flags);
int get(Dbt* key, Dbt *data, u_int32_t flags);
int put(Dbt* key, Dbt *data, u_int32_t flags);
private:
// No data is permitted in this class (see comment at top)
// no copying
Dbc(const Dbc &);
Dbc &operator = (const Dbc &);
};
#endif /* !_DB_CXX_H_ */
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 1996, 1997, 1998
* Sleepycat Software. All rights reserved.
*/
/*
* Copyright (c) 1995, 1996
* The President and Fellows of Harvard University. 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS BE LIABLE
Wave OS project early developer manual
#ifndef _DB_DISPATCH_H
#define _DB_DISPATCH_H
/*
* Declarations and typedefs for the list of transaction IDs used during
* recovery.
*/
struct __db_txnhead {
LIST_HEAD(__db_headlink, __db_txnlist) head;
u_int32_t maxid;
int32_t generation;
};
struct __db_txnlist {
LIST_ENTRY(__db_txnlist) links;
u_int32_t txnid;
int32_t generation;
};
#define DB_log_BEGIN 0
#define DB_txn_BEGIN 5
#define DB_ham_BEGIN 20
#define DB_db_BEGIN 40
#define DB_bam_BEGIN 50
#define DB_ram_BEGIN 100
#define DB_user_BEGIN 150
#define TXN_UNDO 0
#define TXN_REDO 1
#define TXN_BACKWARD_ROLL -1
#define TXN_FORWARD_ROLL -2
#define TXN_OPENFILES -3
#endif
/* DO NOT EDIT: automatically built by dist/distrib. */
#ifndef _db_ext_h_
#define _db_ext_h_
int __db_pgerr __P((DB *, db_pgno_t));
int __db_pgfmt __P((DB *, db_pgno_t));
int __db_addrem_log
__P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
u_int32_t, u_int32_t, db_pgno_t, u_int32_t,
size_t, const DBT *, const DBT *, DB_LSN *));
int __db_addrem_print
__P((DB_LOG *, DBT *, DB_LSN *, int, void *));
618
Wave OS project early developer manual
620
Wave OS project early developer manual
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#ifndef _LDSODEFS_H
#define _LDSODEFS_H 1
#include <features.h>
#define __need_size_t
#define __need_NULL
#include <stddef.h>
#include <elf.h>
#include <dlfcn.h>
#include <link.h>
__BEGIN_DECLS
/* For the version handling we need an array with only names and their
hash values. */
struct r_found_version
{
const char *name;
ElfW(Word) hash;
int hidden;
const char *filename;
};
struct r_search_path_elem
{
/* This link is only used in the `all_dirs' member of `r_search_path'.
*/
struct r_search_path_elem *next;
/* Basename for this search path element. The string must end with
a slash character. */
const char *dirname;
size_t dirnamelen;
struct r_strlenpair
Wave OS project early developer manual
{
const char *str;
size_t len;
};
/* Test whether given NAME matches any of the names of the given object.
*/
static __inline int
__attribute__ ((unused))
_dl_name_match_p (const char *__name, struct link_map *__map)
{
int __found = strcmp (__name, __map->l_name) == 0;
struct libname_list *__runp = __map->l_libname;
return __found;
}
622
Wave OS project early developer manual
line. */
extern void _dl_debug_message (int new_line, const char *string, ...);
624
Wave OS project early developer manual
/* Helper function for <dlfcn.h> functions. Runs the OPERATE function via
_dl_catch_error. Returns zero for success, nonzero for failure; and
arranges for `dlerror' to return the error details.
ARGS is passed as argument to OPERATE. */
extern int _dlerror_run (void (*operate) (void *), void *args)
internal_function;
/* Open the shared object NAME, relocate it, and run its initializer if it
hasn't already been run. MODE is as for `dlopen' (see <dlfcn.h>). If
the object is already opened, returns its existing map. */
extern struct link_map *_dl_open (const char *name, int mode,
const void *caller)
internal_function;
/* Look up symbol NAME in MAP's scope and return its run-time address. */
extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name)
internal_function;
626
Wave OS project early developer manual
/* Check the version dependencies for MAP. If VERBOSE print some more
diagnostics. */
extern int _dl_check_map_versions (struct link_map *map, int verbose)
internal_function;
/* Return the address of the next initializer function for SCOPE or one of
its dependencies that has not yet been run. When there are no more
initializers to be run, this returns zero. The functions are returned
in the order they should be called. */
extern ElfW(Addr) _dl_init_next (struct r_scope_elem *scope)
internal_function;
/* The dynamic linker calls this function before and having changing
any shared object mappings. The `r_state' member of `struct r_debug'
says what change is taking place. This function's address is
the value of the `r_brk' member. */
extern void _dl_debug_state (void);
/* Gather the information needed to install the profiling tables and start
the timers. */
extern void _dl_start_profile (struct link_map *map, const char
*output_dir)
internal_function;
calling function. */
extern void _dl_mcount_wrapper (ElfW(Addr) selfpc);
/* Show the members of the auxiliary array passed up from the kernel. */
extern void _dl_show_auxv (void) internal_function;
/* Return all environment variables starting with `LD_', one after the
other. */
extern char *_dl_next_ld_env_entry (char ***position) internal_function;
__END_DECLS
#endif /* ldsodefs.h */
/* Data structure for communication from the run-time dynamic linker for
loaded ELF shared objects.
Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation,
Inc.
This file is part of the GNU C Library.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite
330,
Boston, MA 02111-1307, USA. */
#ifndef _LINK_H
#define _LINK_H 1
#include <features.h>
628
Wave OS project early developer manual
#include <elf.h>
#include <dlfcn.h>
#include <sys/types.h>
struct r_debug
{
int r_version; /* Version number for this protocol. */
/* Forward declaration. */
Wave OS project early developer manual
struct link_map;
struct link_map
{
/* These first few members are part of the protocol with the debugger.
This is the same format used in SVR4. */
630
Wave OS project early developer manual
/* This is an array defining the lookup scope for this link map.
There are at most three different scope lists. */
struct r_scope_elem *l_scope[4];
/* A similar array, this time only with the local scope. This is
used occasionally. */
struct r_scope_elem *l_local_scope[2];
ino_t l_ino;
#endif /* link.h */
632