****************************************************************************
**********************************BEWARE************************************
****************************************************************************

This software is beta software and is distributed as is. It works at
the operating system level and can thus cause the destruction of part
or the whole of your data.

The authors of this software, as well as those who have worked on it
(myself too) do not endorse any responsability as far as the consequences
of the use of this software. The user is the sole responsible of this.
In other words, you are free to use this software or not to use it, but,
if you chose to use it, it's you affair.

****************************************************************************
****************************************************************************
****************************************************************************

I. Introduction

    This is an enhanced version of the Linux driver for DSL modems based
on the Analog chipset Eagle 8051. The Sagem F@st 800 modem as well as
USRobotics DSL modems are based on this chipset. However, only the F@st 800
as been fully tested.
    The latest revision of this driver can be found at the following URL:

http://sl33p3r.free.fr

    You'll find a french newsgroup dedicated to this driver at
the following URL too:

http://www.eagle-usb.fr.st/

    The driver has been partially rewritten and cleaned-up, and has been
modified to be fully GPL compatible by rewriting non free parts, it can
therefore be extended and modified freely now. Several oddities have
been fixed in the file layout and in the source code itself too.
Last, severe bugs were fixed to make the driver usable. The user space
interface has been completely rewritten to check user space requests
error and to prevent crashes.

    The main changes are:
    - pppoa memory leak fix;
    - connection lost in case of high upstream traffic fix;
    - pppoa crashes and packet size control for packets from the
driver interface;
    - race conditions on initialization;
    - add ioctl codes to control the driver safely;
    - fimware sent to the kernel validity check;
    - 2.4.x kernel support enhancement;
    - simplifications and miscellaneous corrections in the module;
    - rewrite of hotplug scripts;
    - install script rewrite;
    - rewrite of adictrl and GPL licensing, with an option to get
help, add error messages.

    This is this what will cause incompatibilities with the original
driver from ADI, the following informations will therefore certainly
be usefull to install this driver.


II. Installation

    The driver needs several kernel functiuns to work seemless. These
functions are:
    - module loading support with version information support
(options "Enable loadable module suppor", "Set version information
on all module symbols" and "Kernel module loader");
    - hotplug support (if we want the driver to be loaded automatically
at boot, option "Support for hot-pluggable devices");
    - network support (normally, every kernel is properly configured
for that);
    - ppp support ((options "PPP (point-to-point protocol) support",
"PPP support for async serial ports", and eventually "PPP support for sync
tty ports" if you want to use the synchronous connection mode of pppd);
    - USB support (options "Support for USB", "Preliminary USB device
filesystem" and support for one of the UHCI controller or for the OHCI
controller). If you have a UHCI USB controller, you may consider using
the alternate driver JE.

    The kernel headers must be in /usr/src/linux, or there should be
a symbolic link there that references the kernel headers.

    The virtual filesystems /proc and /proc/bus/usb must be mounted.
You can add the fillowing lines to your /etc/fstab to mount them at boot:

none            /proc                     proc            defaults   0   0
usbdevfs        /proc/bus/usb             usbdevfs        defaults   0   0

    The pppd 2.4.1 or later daemon must be installed.

    The driver itself can be installed with the following steps:

    1. Driver compilation
    
    make clean
    make

    2. Driver installation
    
    make install
    
    This step requires to be root. You'll be asked your connection
parameters which you ISP has given you, in order to generate
the configuration files /etc/ppp/options, /etc/ppp/pap-secrets and
/etc/ppp/chap-secrets.
    Once the drivers installed, you can connect with the script
/usr/sbin/startadsl and shutdown the connection with the script
/usr/sbin/stopadsl. These scripts must be run as root.

    3. Automatic connection configuration
    
    This version do not install automatic connection scripts because
of the many variants of Linux distributions and because of it's a matter
of taste as far as the manner to do that is concerned.
    However, a sample script is given in the scripts/adsl directory.
This script is adsl.inittab and is writtent to be used directly in
the system configuration file /etc/inittab. To install it, you can
simply copy it to the /usr/sbin directory and add the following line
to your /etc/inittab file:

adsl:2345:respawn:/usr/sbin/adsl.inittab

This will start the connection automatically (and handle reconnections
as well) in the running level 2, 3, 4 and 5.

Note :
    The install script do not handle USRobotics for now. The driver
is given with the BNM files for the DSP code of these modems, and with
the configuration files, as they are given by USRobotics. To use them
you must rebuild the binary DSP code file for you modem with the buildDSP
tool, and place the resulting file and the configuration files in the
/etc/analog directory.


III. Driver removall

    There is no uninstall script in this version. To uninstall
the driver you must do it yourself.
    For your information, the driver installs the following files:
    
    /lib/modules/version/kernel/drivers/usb/adiusbadsl.o
    /usr/sbin/adictrl
    /usr/sbin/startadsl
    /usr/sbin/startmire
    /usr/sbin/stopadsl
    /usr/sbin/showstat
    /etc/analog/adiusbadsl.conf
    /etc/analog/DSPcode.bin
    /etc/hotplug/usb/adiusbfirmware
    /etc/hotplug/usb/adiusbdsp
    /etc/ppp/options.adsl
    /etc/ppp/options.mire

    It modifies the following files too:
    
    /etc/ppp/pap-secrets (add password)
    /etc/ppp/chap-secrets (add password)
    /etc/hotplug/usb.usermap (add modem USB entries to load the firmware
and the DSP code with hotplug).


IV. Use
    
    When modem is plugged-in (at least the first time), it is shown as
a "pre-firmware" mode. Driver detetcts this, and send firmware code to
the modem, which unplugs and replugs itself as "post-firmware" device.

    Once the firmware has been loaded, the modem waits for the DSP code.
This can be loaded with the following command:

adictrl -d [file]

where "file" is the binary file containing the DSP code. This file can
be generated with the tool driver/firmware/buildDSP from the .BNM files.
The default DSP code file is the file /etc/analog/DSPcode.bin.
    The module keeps in memory the DSP code, since the modem can need
it at any time. However, it is not resent automatically when the modem
is plugged in, so the firmware must be reloaded explicitely in this case.

    This command sends the driver options that are stored in the file
/etc/analog/adiusbadsl.conf too. The option file may be loaded separately with
the '-o' option of adictrl. However, the options cannot be changed while
the network interface of the module is up.

    The modem initialize as soon as it receives the DSP code. Once it
has synchronized, you can connect. You can always see the modem state
in the following file:

/proc/driver/adimodem

(pay attention, this file was previously placed directly in /proc).
The showstat command prints this file more conveniently.

    It is possible to wait for the modem to synchronize with the following
command:

atictrl -s [timeout]

This command blocks until the modem passed in the "operational" state

    To connect, you must bring the network interface ethX of the module up
(beware, this interface was previously called "ADIModem"), where X is the
network interface number, which depends of the number of other Ethernet
interface already installed in your system. Generally, this number will
be 0 (no Ethernet card) or 1 (there is another Ethernet card). The network
interface of the module is created with the '-i' option of adictrl:

adictrl -i

This command prints the network interface name used too. It can be called
multiple times, however only one network interface is created, at the first
call. This ensure there is no name conflict with the other network
interfaces installed in the system.

NOTE: it is possible to force the name of the interface to use, by
      specifying it when loading the module, using the eth_name
      variable:
      Exe: insmod adiusbadsl.i eth_name="eth9"

    To bring the network interface of the driver, use ifconfig as usual:

/sbin/ifconfig ethX 192.168.60.30 up

The IP address doesn't import at all, as long as it doesn't conflict with
an existing address. You should use only local network addresses assigned
for private networks.

    Once the network interface us up, the following command starts
the connection:

/usr/sbin/pppd pty "/usr/sbin/pppoa -I ethX" file /etc/ppp/options.adsl

All options and connection parameters should be defined in the configuration
files /etc/ppp/options.adsl, /etc/ppp/pap-secrets or /etc/ppp/chap-secrets
before. You'll find samples for these files in the directory scripts/ppp.
The setup script generate correct scripts if you answer the good things
when it asks for your login and password.

    You can automatically connect and disconnect with the scripts startadsl
and stopadsl. The script startmire connects to France Telecom mire, which
is a particular debug connection used in France (not very usefull for
other user I think). To disconnect from the mire, you must use stopadsl
too.

Note :
    The order of all these operations does matter. The driver code and
adictrl have been modified to prevent the user from doing things in the
wrong order. In particular, it's impossible to reload the driver options
or the DSP code in the modem while the network interface is up.
    Unplugging the modem removes the network interface. The connection
scripts must therefore takes this kind of error into account.


V. How does it work?

    I'll describe shortly in this section the internals of the driver
for potential developpers. It's what I understood of its mechanisms,
and the description is neither precise not strictly exacts.
    The driver is a USB driver that can handle USB DSL modems based
on the chipset Eagle 8051 from Analog. These devices are identified
by a vendor identifier and a product identifier, which are declared
in the AdiUsbAdsl.h file. The identifiers themselves are defined
int AdiUsbAdsl.c to let modprobe find them.
    These devices have two identifiers (which seems to be quite standard
in the USB world), the first references the device without firmware,
whereas the second references the device with its firmware loaded.
When the devices of each type are detected by the system, the adi_probe
function is called to ask the module if it handles them.
    The module handles pre firmware devices simply by sending them
their firmware. Once the firmware loaded, the device disappears from
the USB bus and reappears with its second identifier. This here that
things get serious.
    The module begins with the selection of the right USB configuration
and initialize its data structures (state of the modem, incoming data
buffers). Then it loads the DSP code in the modem and boot it. Once
the modem is ready, the user space scripts can create an Ethernet
network interface through which pppoa or pppoe will send and read
their packets. Note that the removall of the peripheral automatically
destroys the network interface. I ignore what happens in user space
programs in this case. However, unplugging the modem while it's in
use is not a normal way to use it.
    The adictrl configuration tool talks with the module through
special files in the virtual USB filesystem usbdevfs. It looks for
all the devices it can handle in the directories /proc/bus/usb,
which contains a subdirectory for each USB bus. Once the device
is localized, an ioctl command is sent to give or retreive informations
from the module. The ioctl commands avalaible are listed in the file
AdiUsbAdsl.h.
    adictrl can do several operations, as loading the firmware,
loading the driver options and loading the DSP code to the modem.
The driver options tells which encapsulation method should be used
to send and receive packets, as well as the VPI/VCI ATM channel
parameters to contact the ISP. The DSP code is the software that
gives the modem the ability to talk with the ISP equipments and
to talk with the driver on the other hand. The communication with
the DSL terminal is fully done in ATM (Asynchronous Transfer Mode).
    The DSP code is sent as soon as possible to the modem. It seems
that this code is too big to fit in the modem (or to be loaded
in a single step), it is therefore splitted in pages (which are
in turn splitted in "blocks"), which can be loaded to the modem
asynchronously. The loading code must therefore be handled in
the interrupt service request (ISR) that deals with the events
coming from the modem. This ISR is therefore set up just before
the DSP code is send, which is done simply by sending its first
page. This ISR is connected to the modem through an URB
(USB Request Block) on one of the modem interface. This ISR
handles the notifications of the modem state change too.
Its function is the adi_irq function. The modem boot code
is in the BootTheModem (Boor.c) function.
    Once the modem is booted, its state can change while it is
trying to find the DSL line. The state is dealt with in the
Sm.c and Me.c files (State Machine and Management Entity
respectively). The state changes are trapped by the module ISR.
    The state management code has a timer that check regularly
if the modem is still alive. If it's not the case, the modem
is rebooted by the driver, which cause a reload of the DSP.
The module must therefore keep the DSP code in memory permanently
(which takes some 500 Kb).
    An ioctl code is defined to let the user space processes to
synchronize with the modem state. Once the modem is synchronized,
these processes can use the Ethernet interface of the module.
    This is always done in the same manner: a raw socket must
be opened on the interface, that is we must be able to read and
write raw Ethernet packets directly. To do that, the user space
programs must be run as root of course. That's what the pppoa
and pppoe programs do: they take outgoing data from pppd from their
standard input stream and send them to the driver, and read incoming
data from the network interface and write them to their standard
ouput stream. The only difference between the two is the encapsulation
used to send the PPP packets to the ISP (the "peer") and receive
others.
    So, sent packets are encapsulated in a Ethernet frame completed
with other informations. These informations depends of the kind
of encapsulation used. In a word, the pppoa encapsulation is lighter
than the pppoe one. The Ethernet frames are modified by the
network interface in a encapsulation dependant manner too.
The pppoe packets are sent as is to the ATM layer, with the
Ethernet headers. pppoa packets are cleaned up before the ATM
layer receives them and therefore are smaller.
    The module uses a reception buffer that contains several URBs
for data reception. These URBs are connected to the incoming data
interface of the modem and are handled by a callback function called
asynchronously by the USB driver. However, this job is done
synchronously on behalf of the USB driver. This is done in the
Pipes.c file. Thanks to this buffer, URBs can arrive faster
that the module can handled them. As soon as an URB is arrived,
the incoming data function reads the URBs it receives and
send the data to the ATM decapsulation code (function
UniProcessInboundData).
    When data are rebuild in a full packet by the ATM code,
the ReadSendItUp function (Pipes.c) is called. This function
finishes the Ethernet packet reconstruction and send it to
the network layer. For pppoe, this reconstruction
is simply analysing the packet header received from the ATM layer,
and for pppoa, it consists in adding an Ethernet header.
The data is sent to Linux with the netif_rx function. The kernel
routes them then to pppoa or pppoe (which strip the packet from
their encapsulation and send data to the pppd daemon).
    The ATM code of the module has not been analysed. It seems
that this code is a packet splitting code conforming to the AAL5
protocol. It does therefore (another) encapsulation for the data
from the module network interface, and place them in ATM cells.
It's important to note that the AAL5 code is done in several
places: first the encapsulation headers are build in Mpoa.c,
then the splitting in ATM cells is done in the files Uni.c and Sar.c.
Note that the AAL5 encapsulation adds ten more bytes to the Ethernet
frame header for the PPPoE protocol (these bytes must be substracted
from the transfer rate), whereas the PPPoA/VC protocol do not have
any additionnal cost.
    In other words, the PPPoA encapsulation transfer the PPP packets
directly to the ATM code, and just passes through the Ethernet
interface of the module. The PPPoE encapsulation is done in pppoe
itself, and the Ethernet frames are send in their entirety to the
ATM layer. It is therefore something lile "PPPoEoA" (PPP over Ethernet
over ATM). This implies that the MTU (Maximum Transmit Unit) is smaller
at the pppd interface level. If I'm not too wrong, pppoa uses 14 bytes
for the Ethernet header plus 2 encapsulation bytes, which gives a
MTU of 1500-2=1498 (Ethernet packets can take 1514 bytes at most).
pppoe uses 6 bytes for its encapsulation, which gives a MTU of 1494.
To these bytes, we must add two bytes added by PPP itself for both
protocols, which gives now 1496 and 1492 respectively. Moreover,
the PPPoA protocol do not use any encapsulation at the ATM layer,
whereas the PPPoE protocol uses 10 bytes. I therefore advise you to
use the pppoa protocol, because it's the one that uses the less
resources (at the expense of an Ethernet header reconstruction
at the reception, since both protocoles uses such an header
when sending packets). The theoric delta between both protocols
is something like 1.9% (a 1492 bytes packet is transfered as
1514+10=1524 packets with PPPoE, that with a cost of 32 bytes,
whereas PPPoA uses only 4 bytes, which gives an additionnal cost
of 28 bytes for 1492 for PPPoE, but we must correct this by a
1496/1492 factor because of the smaller MTU of the PPPoE protocol).
I have nearly 50% odds to be wrong here...


Hope this will be usefull...

Surf well,

C. Casteyde (casteyde.christian@free.fr) (retired)
Fred Sleeper Ros (sl33p3r@free.fr)

