patch-2.4.19 linux-2.4.19/drivers/net/wan/8253x/sab8253xds.txt
Next file: linux-2.4.19/drivers/net/wan/8253x/sab8253xfs.txt
Previous file: linux-2.4.19/drivers/net/wan/8253x/ring.h
Back to the patch index
Back to the overall index
- Lines: 4563
- Date:
Fri Aug 2 17:39:44 2002
- Orig file:
linux-2.4.18/drivers/net/wan/8253x/sab8253xds.txt
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.18/drivers/net/wan/8253x/sab8253xds.txt linux-2.4.19/drivers/net/wan/8253x/sab8253xds.txt
@@ -0,0 +1,4562 @@
+*_Design Specification of SAB8253X ASLX Driver for Linux_*
+
+
+
+
+ The effort to design and implement the ASLX SAB8253X Driver for Aurora
+ <http://www.auroratech.com/> hardware with the functionality described
+ in *_Functional Specification of SAB8253X ASLX Driver for Linux
+ <http://www.telfordtools.com/sab8253x/sab8253xfs.html>_* requires
+ solutions to seven separate problems:
+
+
+
+ 1. creating a development environment for maintaining and extending
+ the driver,
+ 2. integrating the driver into the kernel sources,
+ 3. creating a file structure of the driver that aids understanding,
+ 4. crafting a reasonable and easy to use user interface,
+ 5. developing simple tools and example programs for the driver, and
+ 6. designing the driver data structures and
+ 7. designing the driver program logic.
+
+
+
+
+ _Development Environment_
+
+
+
+
+ There are several possible approaches to creating a development
+ environment. The development environments for many drivers seem
+ to have consisted simply of a single machine, and the developer
+ used only /printk()/ in the driver code to debug. I used such an
+ environment to develop a driver for an IOP480 based intelligent
+ adapter card.
+
+
+
+For a driver that provides the functionality described in the Functional
+Specification, a more sophisticated development and debugging
+environment is useful. (One could even occasionally wish for an ICE,
+but that level of resources was not available to me.)
+
+
+
+The development environment consisted of two 686 class machines, on
+which the Linux operating system was installed. One machine ran at 800
+Mhz, the other at 1Ghz. It probably would have been worthwhile to have
+dual processor machine, and one was added to the development environment
+later. The 800 Mhz machine hosted the remote gdb application. It ran
+Redhat Linux 7.0, but because the machine served only as an NFS and
+remote gdb host, the details of the Linux distribution on this machine
+are not particularly important.
+
+
+
+The target machine on which the driver was developed and debugged hosted
+Suse Linux 7.1 and was later upgraded to Suse Linux 7.3. Suse Linux
+seemed to provide the most complete Linux distribution with the least
+hassle in installation. (As the Suse distribution comes on 7 standard
+CDs or 1 DVD, there is a lot of value in having a DVD drive in the
+target machine [and the gdb host if it runs a Suse distribution].)
+
+
+
+The target and remote gdb machines are connected by a 100 Mbps Ethernet
+network and by a serial crossover cable between the Com1 (ttyS0) ports.
+
+
+
+When I started developing the driver, I obtained the Linux 2.4.3 sources
+from The Linux Kernel Archives <http://www.kernel.org/>. Later as later
+distributions became stable, I switched to the Linux 2.4.6
+distribution. The sources were installed first in
+/home/martillo/kernel/linux-2.4.3 and then in
+/home/martillo/kernel/linux-2.4.6 on the remote gdb host machine, which
+was named frolix.
+
+
+
+The sources were imported into CVS on frolix, and the core directory
+into CVS was added manually because the cvs import function ignores
+it. I consider it safer to maintain the CVS repository on the remote
+gdb host machine instead of the target machine because the target
+machine is likely to crash frequently, and its file system may be put
+into bad states.
+
+
+
+I executed the following commands on the remote gdb host machine.
+
+
+
+*ln ^Ös /home/martillo/kernel/linux-2.4.3/include/asm-i386
+/home/martillo/kernel/linux-2.4.3/include/asm*
+
+* *
+
+or
+
+* *
+
+*ln ^Ös /home/martillo/kernel/linux-2.4.6/include/asm-i386
+/home/martillo/kernel/linux-2.4.6/include/asm*
+
+* *
+
+*ln ^Ös / /frolix *
+
+
+
+I edited the /etc/exports file to contain the following.
+
+
+
+/ ylith(rw)
+
+/ fireball(rw)
+
+/ bohun(rw)
+
+/ indefatigable(rw)
+
+
+
+Ylith is the original 1 Ghz target machine. Fireball is a 400 Mhz
+compact PCI target machine. Indefatigable is a dual 1 Ghz target
+machine. Bohun is a Solaris target machine used for another project.
+
+
+
+On the frolix, I started NFS with the following commands (contained in a
+shell script).
+
+
+
+*/etc/rc.d/init.d/nfs start*
+
+*exportfs -va*
+
+
+
+If it had been a Suse Linux machine, I would have used the yast2 control
+center to start NFS service.
+
+
+
+On ylith, I created an empty directory /frolix and executed the
+following command.
+
+
+
+*mount frolix:/ /frolix*
+
+* *
+
+At this point both the remote gdb host (frolix) and the target
+development and debugging machine can refer to the same files by the
+same paths. I could have guaranteed the same paths to the source files
+on both machines if I had simply used /home/martillo as my home
+directory on frolix and exported /home from frolix to all the other
+machines so that there would only be one /home directory for all the
+machines in my network. I was lazy about the network configuration.
+
+
+
+After making sure that the user martillo had read write access
+permissions to all the kernel sources, I built the kernel on the target
+machine from within xemacs with the following sequence of commands.
+
+
+
+From a shell window:
+
+*xemacs ^Öe shell&*
+
+
+
+Inside xemacs:
+
+
+
+*cd /frolix/home/martillo/kernel/linux-2.4.3*
+
+
+
+or
+
+
+
+*cd /frolix/home/martillo/kernel/linux-2.4.6*
+
+
+
+Then make sure that linux-2.4.x/include/asm-i386 is symbolically linked to
+linux-2.4.x/include/asm.
+
+
+
+Execute the following emacs command.
+
+
+
+
+ M-x compile
+
+
+
+This command prompts for targets.
+
+
+
+In the development environment the most useful target string was usually
+/clean xconfig dep bzImage modules./ The target /xconfig /brings up a
+configuration window. In the basic development environment, it was
+generally worthwhile to add SCSI CD ROM, SCSI legacy support, an
+Ethernet driver and DOS file system support
+
+
+
+The target/ dep/ creates the dependencies (note that if the kernel tree
+is ever removed, the .depend and .hdepend files must be regenerated).
+The /bzImage /target builds the kernel. The /modules/ target generates
+all the modules to be dynamically installed in the kernel via the
+*insmod* command.
+
+
+
+After building the kernel, installing the modules in the /lib tree
+requires the execution (as root) of
+
+
+
+make modules_install
+
+
+
+The command *make install* *INSTALL_PATH=/boot* will install the
+compressed kernel image as vmlinuz along with other files in the /boot
+partition. I preferred to use a shell script with commands like the
+following.
+
+
+
+cp /frolix/home/martillo/kernel/linux-2.4.6/arch/i386/boot/bzImage
+/boot/vmlinuz_246
+
+cp /frolix/home/martillo/kernel/linux-2.4.6/System.map
+/boot/System.map-2.4.6
+
+cp /frolix/home/martillo/kernel/linux-2.4.6/.config /boot/vmlinuz_246.config
+
+cp /frolix/home/martillo/kernel/linux-2.4.6/include/linux/autoconf.h
+/boot/vmlinuz_246.autoconf.h
+
+cp /frolix/home/martillo/kernel/linux-2.4.6/include/linux/version.h
+/boot/vmlinuz_246.version.h
+
+
+
+When the kernel comes from a linux-2.4.3 tree, the obvious substitutions
+of 3 for 6 are required.
+
+
+
+Once all the modules and the kernel image are installed, the next step
+in giving the system the ability to boot with the new linux-2.4.3 or
+linux-2.4.6 kernel image is the modification of the lilo.conf file.
+
+
+
+I added the following directives to the lilo.conf file.
+
+
+
+ image = /boot/vmlinuz_243
+
+ label = linux_2.4.3
+
+ root = /dev/hde7
+
+ optional
+
+
+
+ image = /boot/vmlinuz_246
+
+ label = linux_2.4.6
+
+ root = /dev/hde7
+
+ optional
+
+
+
+In this case /dev/hde7 corresponds to the /boot partition, and the
+options linux_2.4.3 and linux_2.4.6 will be added to the boot menu once
+the *lilo* command has been executed. In other system setups the disk
+partition that corresponds to /boot might have a different name like
+/dev/hda7.
+
+
+
+Once the new kernel successfully boots, the next step to creating a
+driver development and debugging environment is patching the kernel for
+remote gdb debugging.
+
+
+
+The necessary patch can be obtained from kgdb: Source level debugging of
+linux kernel <http://kgdb.sourceforge.net/downloads.html>.
+
+
+
+Now the kernel can be built again with the extra step of configuring for
+remote gdb support in the kernel configuration menu.
+
+
+
+The following directives should be added to lilo.conf.
+
+
+
+ image = /boot/vmlinuz_243
+
+ label = debug243
+
+ append = "gdb gdbttyS=0 gdbbaud=115200"
+
+ root = /dev/hde7
+
+ optional
+
+
+
+ image = /boot/vmlinuz_246
+
+ label = debug246
+
+ append = "gdb gdbttyS=0 gdbbaud=115200"
+
+ root = /dev/hde7
+
+ optional
+
+
+
+
+ Then lilo can be executed. On reboot the boot menu will include
+ options for debug243 and debug246.
+
+
+
+To test the patch, select one of the debug options. Then, on the remote
+gdb host machine execute the following command.
+
+
+
+stty 115200 < /dev/ttyS0
+
+
+
+Start up an *xemacs* process. Execute the following commands within
+*xemacs.*
+
+
+
+
+ M-x shell
+
+
+
+Then within the shell window execute the following command.
+
+
+
+cd /frolix/home/martillo/kernel/linux-2.4./X/
+
+/ /
+
+Then invoke the remote debugger.
+
+
+
+
+ M-x gdb
+
+
+
+Reply to the file prompt with *vmlinux.*
+
+* *
+
+In the gdb window, execute the following command.
+
+
+
+target remote /dev/ttyS0
+
+
+
+The gdb window should break in gdbstub.c which will be displayed in the
+gdb source window.
+
+
+
+At this point, all the basic gdb remote debugging capabilities are ready
+to use.
+
+
+
+To access the hardware breakpoint capability of the i386 processor, the
+following commands can be loaded directly or from a file with the
+*script* command.
+
+
+
+#Hardware breakpoints in gdb
+
+#
+
+#Using ia-32 hardware breakpoints.
+
+#
+
+#4 hardware breakpoints are available in ia-32 processors. These breakpoints
+
+#do not need code modification. They are set using debug registers.
+
+#
+
+#Each hardware breakpoint can be of one of the
+
+#three types: execution, write, access.
+
+#1. An Execution breakpoint is triggered when code at the breakpoint
+address is
+
+#executed.
+
+#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
+
+#at the breakpoint address is written.
+
+#3. An access breakpoint is triggered when memory location at the breakpoint
+
+#address is either read or written.
+
+#
+
+#As hardware breakpoints are available in limited number, use software
+
+#breakpoints ( br command in gdb ) instead of execution hardware
+breakpoints.
+
+#
+
+#Length of an access or a write breakpoint defines length of the datatype to
+
+#be watched. Length is 1 for char, 2 short , 3 int.
+
+#
+
+#For placing execution, write and access breakpoints, use commands
+
+#hwebrk, hwwbrk, hwabrk
+
+#To remove a breakpoint use hwrmbrk command.
+
+#
+
+#These commands take following types of arguments. For arguments associated
+
+#with each command, use help command.
+
+#1. breakpointno: 0 to 3
+
+#2. length: 1 to 3
+
+#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
+
+#
+
+#Use the command exinfo to find which hardware breakpoint occured.
+
+
+
+
+
+#hwebrk breakpointno address
+
+define hwebrk
+
+ maintenance packet Y$arg0,0,0,$arg1
+
+end
+
+document hwebrk
+
+ hwebrk breakpointno address
+
+ Places a hardware execution breakpoint
+
+end
+
+
+
+#hwwbrk breakpointno length address
+
+define hwwbrk
+
+ maintenance packet Y$arg0,1,$arg1,$arg2
+
+end
+
+document hwwbrk
+
+ hwwbrk breakpointno length address
+
+ Places a hardware write breakpoint
+
+end
+
+
+
+#hwabrk breakpointno length address
+
+define hwabrk
+
+ maintenance packet Y$arg0,1,$arg1,$arg2
+
+end
+
+document hwabrk
+
+ hwabrk breakpointno length address
+
+ Places a hardware access breakpoint
+
+end
+
+
+
+#hwrmbrk breakpointno
+
+define hwrmbrk
+
+ maintenance packet y$arg0
+
+end
+
+document hwrmbrk
+
+ hwrmbrk breakpointno
+
+ Removes a hardware breakpoint
+
+end
+
+
+
+#exinfo
+
+define exinfo
+
+ maintenance packet qE
+
+end
+
+document exinfo
+
+ exinfo
+
+ Gives information about a breakpoint.
+
+end
+
+
+
+Once the above macros are define, the developer can set hardware
+breakpoints.
+
+
+
+The next step to creating a useful development and debugging environment
+is to provide a shell script to for remote debugging of dynamically
+loaded modules. The following shell script (called *loadmodule.sh*)
+creates a gdb script called *load/ModuleName/* in
+/frolix/home/martillo/kernel/linux-2.4.6 when it is invoked (as root)
+with the following command.
+
+loadmodule.sh modulename
+
+
+
+In order to decrease the probability of confusion, I usually make a link
+in kernel root directory, /frolix/home/martillo/kernel/linux-2.4.6, to
+the location of the module to be debugged in the kernel tree. The above
+command is invoked on the target machine (ylith) in the root directory.
+On the remote debug machine, in the gdb command window, whose working
+directory should be the kernel root directory,
+/frolix/home/martillo/kernel/linux-2.4.6, the command, *script
+load/ModuleName/*, is invoked. Once the script is executed the symbols
+for the module are available for remote symbolic debugging.
+
+
+
+#!/bin/sh
+
+# This script loads a module on a target machine and generates a gdb script.
+
+# source generated gdb script to load the module file at appropriate
+addresses
+
+# in gdb.
+
+#
+
+# Usage:
+
+# Loading the module on target machine and generating gdb script)
+
+# [foo]$ loadmodule.sh <modulename>
+
+#
+
+# Loading the module file into gdb
+
+# (gdb) source <gdbscriptpath>
+
+#
+
+# Modify following variables according to your setup.
+
+# TESTMACHINE - Name of the target machine
+
+# GDBSCRIPTS - The directory where a gdb script will be generated
+
+#
+
+# Author: Amit S. Kale (akale@veritas.com).
+
+#
+
+# If you run into problems, please check files pointed to by following
+
+# variables.
+
+# ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
+
+# MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
+
+# GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
+
+
+
+TESTMACHINE=ylith
+
+GDBSCRIPTS=/frolix/home/martillo/kernel/linux-2.4.6
+
+
+
+if [ $# -lt 1 ] ; then {
+
+ echo Usage: $0 modulefile
+
+ exit
+
+} ; fi
+
+
+
+MODULEFILE=$1
+
+MODULEFILEBASENAME=`basename $1`
+
+
+
+if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
+
+ MODULEFILE=`pwd`/$MODULEFILE
+
+} fi
+
+
+
+ERRFILE=/tmp/$MODULEFILEBASENAME.errs
+
+MAPFILE=/tmp/$MODULEFILEBASENAME.map
+
+GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
+
+
+
+function findaddr() {
+
+ local ADDR=0x$(echo "$SEGMENTS" | \
+
+ grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
+
+ sed 's/[ ]*[^ ]*$//')
+
+ echo $ADDR
+
+}
+
+
+
+function checkerrs() {
+
+ if [ "`cat $ERRFILE`" != "" ] ; then {
+
+ cat $ERRFILE
+
+ } fi
+
+}
+
+
+
+#load the module
+
+#echo Copying $MODULEFILE to $TESTMACHINE
+
+#*rcp $MODULEFILE root@${TESTMACHINE}:
+
+
+
+echo Loading module $MODULEFILE
+
+#rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \
+
+# > $MAPFILE 2> $ERRFILE &
+
+/sbin/insmod -m ./`basename $MODULEFILE` $2 . . > $MAPFILE 2> $ERRFILE &
+
+sleep 5
+
+checkerrs
+
+
+
+NUMLINES=`grep -n '^$' $MAPFILE | sed -e 's/:.*//g'`
+
+SEGMENTS=`head -n $NUMLINES $MAPFILE | tail -n $(eval expr $NUMLINES - 1)`
+
+TEXTADDR=$(findaddr "\\.text[^.]")
+
+LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
+
+SEGADDRS=`echo "$SEGMENTS" | awk '//{
+
+ if ($1 != ".text" && $1 != ".this" &&
+
+ $1 != ".kstrtab" && $1 != ".kmodtab") {
+
+ print " -s " $1 " 0x" $3 " "
+
+ }
+
+}'`
+
+LOADSTRING="$LOADSTRING $SEGADDRS"
+
+echo Generating script $GDBSCRIPT
+
+echo $LOADSTRING > $GDBSCRIPT
+
+
+
+With the addition of the above shell script, the driver development and
+debugging environment is almost complete. Other useful tools for
+developing and debugging this type of serial driver would include a
+Wanalyzer (I used an Interview 7700 and an HP 4952A in developing this
+driver), a breakout box that displays interface signal states and (for
+developing the serial Ethernet-like network driver) several WAN LAN VLAN
+routers as described in *Packet Switching Software and Platforms
+<http://members.aol.com/Telford001/vrouter2g.html>*, *Routing in a
+Bridged Network <http://members.aol.com/Telford001/routetti2.html>, **A
+WAN SUBSYSTEM for a High Performance Packet Switch
+<http://members.aol.com/Keleustes/syncdob.html>* and *A New High
+Performance Architecture for Routers, Bridges and LAN Switches (Software
+Defined Internetworking)
+<http://members.aol.com/Ishtar7713/private/sdi4.html>.*
+
+
+
+
+ _Integration into the Kernel Sources_
+
+
+
+
+The driver has its own directory, {kernel root
+directory}/drivers/net/wan/8253x, in the 2.4.* kernel source tree.
+
+
+
+To facilitate the automatic build of the 8253x driver, the following
+standard kernel files were modified.
+
+
+
+1. {kernel root directory}/drivers/net/wan/Config.in to
+which the line
+
+
+
+tristate ' Aurora Technology, Inc. synchronous asynchronous PCI cards
+V2' CONFIG_ATI_XX20
+
+
+
+
+was added,
+
+2. {kernel root directory}/drivers/net/wan/Makefile to
+which the following lines were added,
+
+
+
+subdir-$(CONFIG_ATI_XX20) += 8253x
+
+
+
+ifeq ($(CONFIG_ATI_XX20),y)
+
+ obj-y += 8253x/ASLX.o
+
+endif
+
+
+
+When the driver is built as a dynamically loaded module, the following
+macro commands in the file 8253xini.c puts the module entry points in
+the special module entry point segment.
+
+
+
+module_init(auraXX20_probe);
+
+module_exit(auraXX20_cleanup);
+
+
+
+The sources are provided to the users in a patch file, tentatively named
+8253x.patch <http://www.telfordtools.com/sab8253x/8253x.patch>.
+
+
+
+To install it the user sets his directory to the top level of the kernel
+sources and executes the following command.
+
+
+
+patch ^Öp1 < /{directory-patch}//8253x.patch
+
+
+
+
+
+ _File Structure of the ASLX Driver Source Code_
+
+
+
+The following files are present in the driver directory.
+
+
+
+8253x.h
+
+8253xdbg.c
+
+8253xmac.c
+
+8253xsyn.c
+
+PciRegs.h
+
+crc32.h
+
+sp502.h
+
+8253xcfg.c
+
+8253xini.c
+
+8253xnet.c
+
+8253xtty.c
+
+Reg9050.h
+
+crc32dcl.h
+
+ring.h
+
+8253xctl.h
+
+8253xioc.h
+
+8253xplx.c
+
+8253xint.c
+
+crc32.c
+
+endian.h
+
+Makefile
+
+Amcc5920.c
+
+8253xmcs.h
+
+8253xmcs.c
+
+8253xchr.c
+
+8253xutl.c
+
+
+
+
+
+
+
+The source code is divided functionally among the files of the ASLX driver.
+
+
+
+8253xcfg.c is the source for a user application that configures 8253x
+control registers to provide clocking. 8253xmac.c is the source for a
+user application that sets a pseudo-MAC address for the network driver.
+
+
+
+8253xini.c contains the initialization/probe logic.
+
+
+
+8253xint.c contains the common interrupt logic.
+
+
+
+8253xtty.c contains the asynchronous TTY logic.
+
+
+
+8253xsyn.c contains the synchronous TTY logic.
+
+
+
+8253xnet.c contains the network driver logic.
+
+
+
+8253xchr.c contains the character driver logic.
+
+
+
+
+8253xdbg.c contains some debugging functions.
+
+
+
+8253xutl.c contains most of the functions that are common among the
+different driver functional subunits.
+
+
+
+8253xplx.c contains some functions specific to the PLX9050 (a PCI bridge
+chip) and specifically to reading and reprogramming the associated
+serial EEPROM.
+
+
+
+amcc5920.c contains some functions specific to the AMCC5920 (a PCI
+bridge chip) and specifically to reading and reprogramming the
+associated serial EEPROM.
+
+
+
+8253xmcs.c contains functions specific to programming the multichannel
+server (mostly G-LINK related logic, programming the sp502 driver chip
+and reading or programming the serial EEPROM associated with the
+interface cards contained within the MCS unit).
+
+
+
+crc32.c contains logic to append a CRC32 to a pseudo MAC frame that is
+generated by the network driver.
+
+
+
+8253x.h contains symbols, structures and macros that relate mostly to
+the 8253x chips and ports.
+
+
+
+8253xctl.h contains symbols, structures and macros that relate mostly to
+the adapter cards.
+
+
+
+8253xmcs.h contains symbols and structures that relate mostly to the
+multichannel server. A lot of this file relates to G-LINK.
+
+
+
+sp502.h contains symbols and structures that relate to the programming
+of the hardware interface line drivers of the 3500 adapter cards of the
+multichannel server.
+
+
+
+8253xioc.h contains symbols and structures that relate to private ioctls.
+
+
+
+PciRegs.h contains symbols and structures that relate to PCI
+configuration space.
+
+
+
+Reg9050.h contains symbols and structures that relate to the PLX9050 PCI
+interface chip and its serial eprom
+
+
+
+crc32.h, crc32dcl.h and .endian.h contain symbols, structures and macros
+that relate to generating a correct CRC32.
+
+
+
+ring.h contains symbols and structures that relate to the network driver
+frame transmission ring and frame reception.
+
+
+
+The Makefile is a standard Linux kernel Makefile whose structure is
+dictated by the current Linux build formalism.
+
+
+
+
+ _Using the ASLX Driver _
+
+
+
+
+
+ The ASLX driver is designed to be a ^Óplug-and-play^Ô driver as far as
+ possible. If it is built as a dynamically loadable module, the user
+ (or relevant system configuration file) invokes /insmod /to load the
+ ASLX.o file.
+
+
+
+The following parameters can be set on the /insmod/ command line.
+
+
+
+MODULE_PARM(xx20_minorstart, "i");/*when statically linked autodected
+otherwise 128 by default*/
+
+MODULE_PARM(sab8253xc_major, "i");/*major dev for character device, by
+default dynamic */
+
+MODULE_PARM(auraXX20n_debug, "i");/*turns on debugging messages, default
+off*/
+
+MODULE_PARM(auraXX20n_name, "s"); /*base network driver name = 8253x000*/
+
+MODULE_PARM(sab8253xn_listsize, "i"); /*transmit ring size default 32*/
+
+MODULE_PARM(sab8253xc_name, "s");/*registered name for char driver =
+sab8253xc*/
+
+MODULE_PARM(sab8253x_default_sp502_mode, "i");
+
+
+
+
+ The asynchronous TTY functionality can immediately be used without
+ extra configuration. [Note that immediate use of the WMS3500 products
+ is possible because the default value of sab8253x_default_sp502_mode
+ is SP502_RS232_MODE (== 1). If a different default mode is needed, it
+ can be set as options in the /etc/modules.conf file. OFF = 0.
+
+RS232 = 1, RS422 = 2, RS485 = 3, RS449 = 4, EIA530 = 5 and V.35 = 6, as
+defined in 8253xioc.h.]
+
+
+
+The MAKETERMS script below parses the /proc/tty/driver/auraserial file
+to make the asynchronous TTY device files in the /dev directory.
+
+
+
+TTYDEV=$1
+
+MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e
+'/[a-zA-Z]/d' | sed -e 's/://'`
+
+
+
+for i in $MDEVS
+
+do
+
+ TTYNAME=/dev/ttyS${TTYDEV}
+
+ mknod $TTYNAME c 4 $i
+
+ TTYDEV=$((${TTYDEV}+1))
+
+done
+
+
+
+The MAKEPROTO script below provides a prototype to modify the
+/etc/inittab file so that an agetty process can be spawned on every
+other /dev/ttyS* at 9600 bps
+
+
+
+TTYDEV=$1
+
+MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e
+'/[a-zA-Z]/d' | sed -e 's/://'`
+
+LEADCHAR=""
+
+
+
+for i in $MDEVS
+
+do
+
+ NAME=S${TTYDEV}
+
+ TTYNAME=ttyS${TTYDEV}
+
+ echo ${LEADCHAR}${NAME}:35:respawn:/sbin/agetty 9600 ${TTYNAME}
+
+ TTYDEV=$((${TTYDEV}+1))
+
+ if [ -z "$LEADCHAR" ]
+
+ then
+
+ LEADCHAR="#"
+
+ else
+
+ LEADCHAR=""
+
+ fi
+
+done
+
+
+
+
+ If loopback cables are connected between successive TTY ports on each
+ Aurora adapter card or unit, the command
+
+
+
+cu ^Öl /dev/ttyS{n} ^Ös 9600
+
+
+
+would connect to the login that was spawned on /dev/ttyS{n-1}.
+
+
+
+The script MAKESTERMS (viz below) creates synchronous TTY dev files for
+all the Aurora serial ports.
+
+
+
+TTYDEV=$1
+
+MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e
+'/[a-zA-Z]/d' | sed -e 's/://'`
+
+
+
+for i in $MDEVS
+
+do
+
+ TTYNAME=/dev/sttyS${TTYDEV}
+
+ mknod $TTYNAME c 5 $i
+
+ TTYDEV=$((${TTYDEV}+1))
+
+done
+
+
+
+The MAKESPROTO script below creates a prototype with which to modify the
+/etc/inittab file to spawn an agetty process on every other
+/dev/sttyS{N} device.
+
+
+
+TTYDEV=$1
+
+MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e
+'/[a-zA-Z]/d' | sed -e 's/://'`
+
+LEADCHAR=""
+
+
+
+for i in $MDEVS
+
+do
+
+ NAME=sS${TTYDEV}
+
+ TTYNAME=sttyS${TTYDEV}
+
+ echo ${LEADCHAR}${NAME}:35:respawn:/sbin/agetty 9600 ${TTYNAME}
+
+ TTYDEV=$((${TTYDEV}+1))
+
+ if [ -z "$LEADCHAR" ]
+
+ then
+
+ LEADCHAR="#"
+
+ else
+
+ LEADCHAR=""
+
+ fi
+
+done
+
+
+
+
+ The simplest way to use these terminals with the agetty process that
+ comes with the Linux distribution is to leave externally clocked (the
+ default) the terminals on which agetty has been spawned.
+
+
+
+The loopback cable can be connected to a port on which agetty is not
+being run. The clockside of the cable is connected to this port. The
+user can run the MAKECLOCKING script below.
+
+
+
+echo 8253xcfg $1 -n 64 158 56 4 192 140 15
+
+8253xcfg $1 -n 64 158 56 4 192 140 15
+
+
+
+The numbers on the 8253xcfg command line are new (decimal) values for
+the channel control, mode and baud rate registers. The file 8253xioc.h
+and sab8253x manuals from Siemens/Infineon can assist in explaining the
+reasoning behind these values. The 8253xcfg sets the mode, channel
+control and baudrate generator registers of the port specified by
+/dev/sttyS{N-1} which is the argument $1 of this script file. 8253xcfg
+is a simple example program that is included with the driver sources.
+It is described in the next section of this document.
+
+
+
+At this point, the user could execute the following command to connect
+synchronously to the peer synchronous TTY port.
+
+
+
+cu ^Öl /dev/sttyS{n} ^Ös 9600
+
+
+
+To turn off internal clocking use the following command.
+
+
+
+8253xcfg /dev/sttyS? ^Ön 64 152 0 4 0 140 15
+
+
+
+To use an ASLX network device the following commands would be used.
+
+
+
+*MAKECLOCKING /dev/sttyS*/{N} [if the interface is to provide clock]/
+
+*stty */{speed} /*< /dev/sttyS*/{N} [if the interface is to provide clock]/
+
+
+
+To set the MAC address, which defaults to 00:00:00:00:00:00 and which
+consequently must be changed, use the following command.
+
+
+
+*ifconfig 8253x*/{mdev} /*hw ether*/ {mac address} [as root]/
+
+
+
+[Note that the 8253x{mdev} interface must not be running when the above
+command is executed.]
+
+
+
+To set the IP address, use the command.
+
+/ /
+
+*ifconfig 8253x*/{mdev} {ipadress} [as root]/
+
+
+
+[Note that the two ifconfig commands can be combined on one line. If
+they are executed separately the MAC address command must be executed
+before the IP address command.]
+
+
+
+After the completion of the above commands, assuming there is an active
+network peer that uses the same serial Ethernet frame structure, it
+should be possible to ping or telnet to the peer networking device.
+
+
+
+{mdev} is the minor device number (in decimal, 3 digits including
+leading 0s required) associated with /dev/sttyS{N}.//
+
+* *
+
+To disable the network interface use the following command.
+
+
+
+*ifconfig 8253x*/{mdev} /*down*/ [as root]/
+
+
+
+If there is a need to disable clocking on a serial port, the
+MAKENONCLOCKING shell script is invoked with the TTY device as an
+argument as follows.
+
+
+
+MAKENONCLOCKING /dev/ttyS{N}
+
+
+
+The shell script contains the following commands.
+
+
+
+echo 8253xcfg $1 -n 64 152 0 4 192 140 255
+
+8253xcfg $1 -n 64 152 0 4 192 140 255
+
+
+
+The numbers on the 8253xcfg command line are new (decimal) values for
+the channel control, mode and baud rate registers. The file 8253xioc.h
+and sab8253x manuals from Siemens/Infineon can assist in explaining the
+reasoning behind these values. The 8253xcfg sets the mode, channel
+control and baudrate generator registers of the port specified by
+/dev/sttyS{N-1} which is the argument $1 of this script file. 8253xcfg
+is a simple example program that is included with the driver sources.
+It is described in the next section of this document.
+
+
+
+
+
+ _Simple Tools and Example Programs_
+
+
+
+The tools and example programs supplied with the SAB8253X ASLX driver
+are the following.
+
+1. eprom9050
+
+2. 8253xcfg
+
+3. 8253xspeed
+
+4. 8253xpeer
+
+5. 8253xmode
+
+
+ eprom9050
+
+
+
+This program performs the bit-banging necessary to read and to program
+the serial eprom of the PLX9050.
+
+
+
+To access the serial eprom on an adapter card the program opens up a TTY
+device on the adapter card, whose serial eprom is to be modified.
+This TTY device can either be synchronous, asynchronous or callout. The
+TTY device is passed as an argument when the program is invoked.
+
+
+
+The program uses the ATIS_IOCGSEP9050 IOCTL to get the current serial
+eprom values and the ATIS_IOCSSEP9050 IOCTL to set the new serial eprom
+values.
+
+
+
+Here is the source code of the program.
+
+
+
+/*
+
+ * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
+
+ *
+
+ * This program is free software; you can redistribute it and/or
+
+ * modify it under the terms of the GNU General Public License
+
+ * as published by the Free Software Foundation; either version
+
+ * 2 of the License, or (at your option) any later version.
+
+ *
+
+ **/
+
+
+
+#include <sys/types.h>
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include "8253xioc.h"
+
+#include "Reg9050.h"
+
+
+
+
+
+ /* This application shows how to load the */
+
+ /* channel control, mode and rx frame
+length */
+
+ /* check registers via an ioctl.*/
+
+
+
+int main(int argc, char **argv)
+
+{
+
+ int fd;
+
+ unsigned short oldeeprom[EPROM9050_SIZE], neweeprom[EPROM9050_SIZE];
+
+ char buffer[200];
+
+ int count;
+
+ int value;
+
+ unsigned short *pointer;
+
+ unsigned short *pointerold;
+
+ int noprompt = 0;
+
+ int epromindex;
+
+
+
+ if(argc < 2)
+
+ {
+
+ fprintf(stderr, "Syntax: %s {portname} [-n] {prom values}.\n", *argv);
+
+ exit(-1);
+
+ }
+
+ fd = open(argv[1], O_RDWR);
+
+ if(fd < 0)
+
+ {
+
+ perror("open failed.");
+
+ exit(-2);
+
+ }
+
+
+
+ if((argc > 2) && !strcmp("-n", argv[2]))
+
+ {
+
+ noprompt = 1;
+
+ }
+
+
+
+ /* get the current values */
+
+ if(ioctl(fd, ATIS_IOCGSEP9050, &oldeeprom) < 0)
+
+ {
+
+ perror("ioctl failed.");
+
+ exit(-3);
+
+ }
+
+ /* set up the existing values as defaults */
+
+ memcpy(neweeprom, oldeeprom, sizeof(oldeeprom));
+
+ /* gather all new values from the
+command line */
+
+ /* or via tty input.*/
+
+ for(count = (2+noprompt), pointer = neweeprom; count < argc; ++count,
+++pointer)
+
+ {
+
+ *pointer = atoi(argv[count]);
+
+ }
+
+ pointer = neweeprom;
+
+ pointerold = oldeeprom;
+
+ for(epromindex = 0; epromindex < EPROM9050_SIZE; ++epromindex)
+
+ {
+
+ fprintf(stderr, "LOCATION %i [%4.4x/%4.4x]: ", epromindex,
+*pointerold, *pointer);
+
+
+
+ if(!noprompt)
+
+ {
+
+ if(count = read(0, buffer, 150), count <= 0)
+
+ {
+
+ exit(0);
+
+ }
+
+ buffer[count] = '\0';
+
+ if(buffer[0] != '\n')
+
+ {
+
+ sscanf(buffer, "%x", &value);
+
+ *pointer = (unsigned short) value;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ fprintf(stderr, "\n");
+
+ }
+
+ ++pointerold;
+
+ ++pointer;
+
+ }
+
+ /* This ioctl does the actual register
+load. */
+
+ if(ioctl(fd, ATIS_IOCSSEP9050, neweeprom) < 0)
+
+ {
+
+ perror("ioctl failed.");
+
+ exit(-3);
+
+ }
+
+
+
+ fflush(stdout);
+
+}
+
+
+
+With the above program it is possible to change PCI vendor and device ID
+values of the adapter card. At that point the card would no longer be
+visible to the driver. To correct the vendor and device IDs use the
+*lspci* Linux command to find out what new values are and recompile the
+driver code after modifying the symbols that correspond to the correct
+vendor and device Ids of the card to the new values. (I should make the
+vendor and device IDs module parameters that can be set from the
+*insmod* command line.) The eprom9050 can be invoked to write the
+device and vendor IDs to the correct values. Of course, then the card
+will no longer be visible to the new version of the driver, and the
+original version of the driver must be used to communicate with this card.
+
+
+
+
+ 8253xcfg
+
+
+
+The 8253xcfg command provides access to images of the channel control,
+mode and baud rate generator registers of the serial port that is
+specified by the minor device number (port number = minor device number
+^Ö minor_start) of the TTY device (either synchronous, asynchronous or
+callout) specified on the command line by which 8253xcfg is invoked.
+The next time the port is initialized (usually on the first open after
+every process that currently has the port open has closed it) these
+registers are set with the values of their images. The 8253xcfg command
+can make a synchronous port clocking or non-clocking. Note that even
+though 8253xcfg operates on a TTY device, the open that finally sets the
+registers with the values from the images can be either a synchronous
+TTY, a network device or a synchronous character device open. The
+program uses the ATIS_IOCGPARAMS IOCTL to get the current values of the
+images of the registers and employs the ATIS_IOCSPARAMS IOCTL to set the
+current values of the images of the registers. Here is the source of
+the 8253xcfg program.
+
+
+
+/*
+
+ * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
+
+ *
+
+ * This program is free software; you can redistribute it and/or
+
+ * modify it under the terms of the GNU General Public License
+
+ * as published by the Free Software Foundation; either version
+
+ * 2 of the License, or (at your option) any later version.
+
+ *
+
+ **/
+
+
+
+#include <sys/types.h>
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include "8253xioc.h"
+
+
+
+char *prompts[] =
+
+ {
+
+ "ccr0",
+
+ "ccr1",
+
+ "ccr2",
+
+ "ccr3",
+
+ "ccr4",
+
+ "mode",
+
+ "rlcr",
+
+ 0
+
+ };
+
+
+
+ /* This application shows how to load the */
+
+ /* channel control, mode and rx frame
+length */
+
+ /* check registers via an ioctl.*/
+
+
+
+int main(int argc, char **argv)
+
+{
+
+ int fd;
+
+ struct channelcontrol ccontrolold, ccontrolnew;
+
+ char buffer[200];
+
+ int count;
+
+ int value;
+
+ unsigned char *pointer;
+
+ unsigned char *pointerold;
+
+ char **promptpointer = prompts;
+
+ int noprompt = 0;
+
+
+
+ if(argc < 2)
+
+ {
+
+ fprintf(stderr, "Syntax: %s {portname} [-n] [ccr0 [ccr1 [ccr2
+[ccr3 [ccr4 [mode [rlcr]]]]]]].\n", *argv);
+
+ exit(-1);
+
+ }
+
+ fd = open(argv[1], O_RDWR);
+
+ if(fd < 0)
+
+ {
+
+ perror("open failed.");
+
+ exit(-2);
+
+ }
+
+
+
+ if((argc > 2) && !strcmp("-n", argv[2]))
+
+ {
+
+ noprompt = 1;
+
+ }
+
+
+
+ /* get the current values */
+
+ if(ioctl(fd, ATIS_IOCGPARAMS, &ccontrolold) < 0)
+
+ {
+
+ perror("ioctl failed.");
+
+ exit(-3);
+
+ }
+
+ /* set up the existing values as defaults */
+
+ ccontrolnew = ccontrolold;
+
+
+
+ /* gather all new values from the
+command line */
+
+ /* or via tty input.*/
+
+ for(count = (2+noprompt), pointer = (unsigned char*) &ccontrolnew;
+count < argc; ++count, ++pointer)
+
+ {
+
+ *pointer = atoi(argv[count]);
+
+ }
+
+ pointer = (unsigned char*) &ccontrolnew;
+
+ pointerold = (unsigned char*) &ccontrolold;
+
+ while(*promptpointer)
+
+ {
+
+ fprintf(stderr, "%s [%2.2x/%2.2x]: ",*promptpointer, *pointerold,
+*pointer);
+
+
+
+ if(!noprompt)
+
+ {
+
+ if(count = read(0, buffer, 150), count <= 0)
+
+ {
+
+ exit(0);
+
+ }
+
+ buffer[count] = '\0';
+
+ if(buffer[0] != '\n')
+
+ {
+
+ sscanf(buffer, "%x", &value);
+
+ *pointer = (unsigned char) value;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ fprintf(stderr, "\n");
+
+ }
+
+ ++pointerold;
+
+ ++pointer;
+
+ ++promptpointer;
+
+ }
+
+ /* This ioctl does the actual register
+load. */
+
+ if(ioctl(fd, ATIS_IOCSPARAMS, &ccontrolnew) < 0)
+
+ {
+
+ perror("ioctl failed.");
+
+ exit(-3);
+
+ }
+
+
+
+ fflush(stdout);
+
+}
+
+
+
+
+
+
+ 8253xspeed
+
+
+
+This program sets the custom baud rate of a serial port. If the custom
+baud rate of a serial port is non-zero, and if the standard baud rate
+has been set to 38,400 bps, the next time the port is initialized, the
+port will run at the custom baud rate. If the custom baud rate were 0,
+the port would run at the standard baud rate. The 8352xpeed program is
+invoked with a TTY device (either asynchronous, synchronous or callout),
+but the effect also applies to the network device and the synchronous
+character device that correspond to the same physical serial port.
+
+
+
+Here is the source code for the 8253xspeed.
+
+
+
+/*
+
+ * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
+
+ *
+
+ * This program is free software; you can redistribute it and/or
+
+ * modify it under the terms of the GNU General Public License
+
+ * as published by the Free Software Foundation; either version
+
+ * 2 of the License, or (at your option) any later version.
+
+ *
+
+ **/
+
+
+
+#include <sys/types.h>
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include "8253xioc.h"
+
+
+
+
+
+int main(int argc, char **argv)
+
+{
+
+ int fd;
+
+ unsigned long oldspeed, newspeed;
+
+ char buffer[200];
+
+ int count;
+
+ long value;
+
+ int noprompt = 0;
+
+ int epromindex;
+
+
+
+ if(argc < 2)
+
+ {
+
+ fprintf(stderr, "Syntax: %s {portname} [-n] {new speed}.\n", *argv);
+
+ exit(-1);
+
+ }
+
+ fd = open(argv[1], O_RDWR);
+
+ if(fd < 0)
+
+ {
+
+ perror("open failed.");
+
+ exit(-2);
+
+ }
+
+
+
+ if((argc > 2) && !strcmp("-n", argv[2]))
+
+ {
+
+ noprompt = 1;
+
+ }
+
+
+
+
+/* get the current values */
+
+ if(ioctl(fd, ATIS_IOCGSPEED, &oldspeed) < 0)
+
+ {
+
+ perror("ioctl failed.");
+
+ exit(-3);
+
+ }
+
+
+/* set up the existing values as defaults */
+
+ newspeed = oldspeed;
+
+
+/* gather all new values from the command line */
+
+
+/* or via tty input.*/
+
+ if(argc == (noprompt + 3))
+
+ {
+
+ newspeed = atoi(argv[count]);
+
+ }
+
+
+
+ fprintf(stderr, "speed [%ld/%ld]: ", oldspeed, newspeed);
+
+
+
+ if(!noprompt)
+
+ {
+
+ if(count = read(0, buffer, 150), count <= 0)
+
+
+{
+
+
+ exit(0);
+
+
+}
+
+ buffer[count] = '\0';
+
+ if(buffer[0] != '\n')
+
+
+{
+
+
+ sscanf(buffer, "%ld", &newspeed);
+
+
+}
+
+ }
+
+ else
+
+ {
+
+ fprintf(stderr, "\n");
+
+ }
+
+
+
+
+/* This ioctl does the actual register load. */
+
+ if(ioctl(fd, ATIS_IOCSSPEED, &newspeed) < 0)
+
+ {
+
+ perror("ioctl failed.");
+
+ exit(-3);
+
+ }
+
+
+
+ fflush(stdout);
+
+}
+
+
+
+The ATIS_IOCGSPEED gets the value the custom baud rate for a serial port
+while ATIS_IOCSSPEED sets the value of the custom baud rate for a serial
+port.
+
+
+
+
+
+
+ 8253xpeer
+
+
+
+The 8253xpeer example program reads and writes packets to the serial
+port in synchronous mode. The synchronous character driver to some
+extent emulates the getmsg/putmsg functionality found in Solaris. This
+driver returns only one packet at a time to read and returns ENOMEM if
+the receive buffer is not large enough to receive the current packet.
+The driver assumes that the data from a write is to be packetized into a
+single packet. The driver can provide asynchronous notification that
+there is no more data queued to be transmitted at the serial port. This
+asynchronous notification informs the application program that a low
+priority packet can now be written to the driver. Such functionality is
+useful to protocols like LAPB that distinguish low priority information
+frames from high priority control frames.
+
+
+
+To try out this program find the major device number associated with the
+8253xc device in the /proc/devices file. Select two ports to loop
+together. Connect them with a synchronous loopback cable. Then execute
+the following command for each of the ports.
+
+
+
+mknod /dev//DevName1/ c /major-dev-num minor-dev-num-1/
+
+/ /
+
+mknod /dev//DevName2/ c /major-dev-num minor-dev-num-2/
+
+
+
+Minor-dev-num-[1/2] correspond to the selected ports.
+
+
+
+Select one of the ports to be clocking (the clocking end of the loopback
+cable should connect to this port) and apply MAKECLOCKING to the
+corresponding TTY. Use stty or 8253xspeed and stty to set the speed on
+the corresponding TTY port.
+
+
+
+Then in one window run *8253xpeer /dev//DevName1/* and in another window
+execute *8253xpeer /dev//DevName2./* It should now be possible to send
+and receive data in each of the windows.
+
+
+
+Here is the program source.
+
+
+
+/*
+
+ * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
+
+ *
+
+ * This program is free software; you can redistribute it and/or
+
+ * modify it under the terms of the GNU General Public License
+
+ * as published by the Free Software Foundation; either version
+
+ * 2 of the License, or (at your option) any later version.
+
+ *
+
+ **/
+
+
+
+#include <sys/types.h>
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include "8253xioc.h"
+
+#include <sys/poll.h>
+
+
+
+struct pollfd pollarray[2];
+
+
+
+
+
+char buffer[8192];
+
+
+
+int main(int argc, char **argv)
+
+{
+
+ int fd;
+
+ int status;
+
+ int prompt = 1;
+
+ int count;
+
+
+
+ if(argc != 2)
+
+ {
+
+ fprintf(stderr, "Syntax: %s {portname}\n", *argv);
+
+ exit(-1);
+
+ }
+
+ fd = open(argv[1], O_RDWR);
+
+ if(fd < 0)
+
+ {
+
+ perror("open failed.");
+
+ exit(-2);
+
+ }
+
+ do
+
+ {
+
+ if(prompt)
+
+ {
+
+ printf("Enter data: ");
+
+ fflush(stdout);
+
+ prompt = 0;
+
+ }
+
+ pollarray[0].fd = 0;
+
+ pollarray[0].events = POLLIN;
+
+ pollarray[0].revents = 0;
+
+ pollarray[1].fd = fd;
+
+ pollarray[1].events = POLLIN|POLLOUT;
+
+ pollarray[1].revents = 0;
+
+ status = poll(pollarray, 2, 10);
+
+ switch(status)
+
+ {
+
+ case 0:
+
+ break;
+
+
+
+ case 1:
+
+ case 2:
+
+ if(pollarray[0].revents == POLLIN)
+
+ {
+
+ if(count = read(0, buffer, 150), count <= 0)
+
+ {
+
+ perror("unable to read stdio.\n");
+
+ exit(0);
+
+ }
+
+ buffer[count] = '\0';
+
+ if(count)
+
+ {
+
+ if(pollarray[1].revents & POLLOUT)
+
+ {
+
+ if(write(pollarray[1].fd, buffer, count) <= 0)
+
+ {
+
+ perror("unable to write protodevice.\n");
+
+ exit(-1);
+
+ }
+
+ }
+
+ else
+
+ {
+
+ printf("Write of protodevice would block.\n");
+
+ fflush(stdout);
+
+ }
+
+ }
+
+ prompt = 1;
+
+ }
+
+ if(pollarray[1].revents & POLLIN)
+
+ {
+
+ if(count = read(pollarray[1].fd, buffer, 8192), count <= 0)
+
+ {
+
+ perror("unable to read protodevice.\n");
+
+ exit(0);
+
+ }
+
+ buffer[count] = '\0';
+
+ printf("\nRead: %s", buffer);
+
+ fflush(stdout);
+
+ prompt = 1;
+
+ }
+
+ break;
+
+
+
+ default:
+
+ break;
+
+ }
+
+ }
+
+ while(status >= 0);
+
+}
+
+
+
+
+
+
+ 8253xmode
+
+
+
+The 8253xmode program sets the signaling mode of port on a multichannel
+server 3500 extension board which has a programmable Sipex sp502
+physical driver chip for each port.
+
+
+
+The command syntax is the following
+
+
+
+*8253xmode* /dev//{dev name} {mode}/
+
+
+
+where mode is one of the following.
+
+ * off
+ * 232
+ * 422
+ * 485
+ * 530
+ * v.35
+
+
+
+Note the minor devices associated with a multiserver increase
+monotonically starting from the first connector on the upper left corner
+if you are facing the connector side of the multiserver. The numbering
+goes from left to right and top to bottom without gaps Thus, the
+numbers on the multiserver itself may not map to the minor device number
+as port number + minor device number of first port if the multiserver is
+not fully populated.
+
+
+
+Here is the source for the 8253xmode program.
+
+
+
+/* -*- linux-c -*- */
+
+/*
+
+ * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
+
+ *
+
+ * This program is free software; you can redistribute it and/or
+
+ * modify it under the terms of the GNU General Public License
+
+ * as published by the Free Software Foundation; either version
+
+ * 2 of the License, or (at your option) any later version.
+
+ *
+
+ **/
+
+
+
+#include <sys/types.h>
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include "8253xioc.h"
+
+
+
+static char *signaling[] =
+
+{
+
+ "OFF",
+
+ "RS232",
+
+ "RS422",
+
+ "RS485",
+
+ "RS449",
+
+ "RS530",
+
+ "V.35"
+
+};
+
+
+
+ /* This application shows how to set sigmode
+
+ * on those devices that support software
+
+ * programmable signaling. */
+
+int main(int argc, char **argv)
+
+{
+
+ int fd;
+
+ unsigned int oldmode, newmode;
+
+
+
+ if(argc != 3)
+
+ {
+
+ fprintf(stderr, "Syntax: %s {portname} {new mode}.\n",
+*argv);
+
+ fprintf(stderr, "{new mode} = off | 232 | 422 | 485 |
+449 | 530 | v.35\n");
+
+ exit(-1);
+
+ }
+
+ fd = open(argv[1], O_RDWR);
+
+ if(fd < 0)
+
+ {
+
+ perror("open failed.");
+
+ exit(-2);
+
+ }
+
+ if(!strcmp("off", argv[2]))
+
+ {
+
+ newmode = SP502_OFF_MODE;
+
+ }
+
+ else if(!strcmp("232", argv[2]))
+
+ {
+
+ newmode = SP502_RS232_MODE;
+
+ }
+
+ else if(!strcmp("422", argv[2]))
+
+ {
+
+ newmode = SP502_RS422_MODE;
+
+ }
+
+ else if(!strcmp("485", argv[2]))
+
+ {
+
+ newmode = SP502_RS485_MODE;
+
+ }
+
+ else if(!strcmp("449", argv[2]))
+
+ {
+
+ newmode = SP502_RS449_MODE;
+
+ }
+
+ else if(!strcmp("530", argv[2]))
+
+ {
+
+ newmode = SP502_EIA530_MODE;
+
+ }
+
+ else if(!strcmp("v.35", argv[2]))
+
+ {
+
+ newmode = SP502_V35_MODE;
+
+ }
+
+ else
+
+ {
+
+ fprintf(stderr, "Unknown mode %s.\n", argv[2]);
+
+ fprintf(stderr, "Syntax: %s {portname} {new mode}.\n",
+*argv);
+
+ fprintf(stderr, "{new mode} = off | 232 | 422 | 485 |
+449 | 530 | v.35\n");
+
+ exit(-1);
+
+ }
+
+
+
+ /* get the current values */
+
+ if(ioctl(fd, ATIS_IOCGSIGMODE, &oldmode) < 0)
+
+ {
+
+ perror("ATIS_IOCGSIGMODE ioctl failed.");
+
+ exit(-3);
+
+ }
+
+ fprintf(stderr, "old mode = %s.\n", signaling[oldmode]);
+
+
+
+ if(ioctl(fd, ATIS_IOCSSIGMODE, &newmode) < 0)
+
+ {
+
+ perror("ATIS_IOCSSIGMODE ioctl failed.");
+
+ exit(-3);
+
+ }
+
+
+
+ /* get the current values */
+
+ if(ioctl(fd, ATIS_IOCGSIGMODE, &oldmode) < 0)
+
+ {
+
+ perror("ATIS_IOCGSIGMODE ioctl failed.");
+
+ exit(-3);
+
+ }
+
+ fprintf(stderr, "new mode = %s.\n", signaling[oldmode]);
+
+ fflush(stdout);
+
+}
+
+
+
+The 8253xmode program uses the ATIS_IOCSSIGMODE ioctl to set the new
+physical signaling mode and employs the ATIS_IOCGSIGMODE ioctl to get
+the original value and to verify the new mode.
+
+
+
+
+ _Logic Structure of the ASLX Driver_
+
+
+
+
+ /Data Structure Summary/
+
+
+
+The key data structures that enable the driver logic are:
+
+
+
+1. SAB_BOARD structure ^Ö driver specific
+
+2. SAB_CHIP structure ^Ö driver specific
+
+3. SAB_PORT structure ^Ö driver specific
+
+4. AURA_CIM structure ^Ö driver specific (actually specific to the
+multichannel server)
+
+5. RING_DESCRIPTOR ^Ö used by all the driver functionalities in the
+transmission of data.
+
+6. DCONTROL2 ^Ö used by all the driver functionalities in managing
+the transmission of data.
+
+7. struct sk_buff_head ^Ö two buffer lists are associated with the
+SAB_PORT structure are used to track all the sk_buffs that are currently
+in use at each port.
+
+8. struct tty_struct ^Ö one per port, standard structure by which
+the TTY driver access low level routines for either asynchronous TTY,
+synchronous TTY and callout functionality. The SAB_PORT serves as the
+private data structure associated with each 8253x TTY, which on a given
+open can instantiate itself as a synchronous TTY, an asynchronous TTY or
+as a call out device.
+
+9. struct net_device ^Ö one per port, standard network device
+structure. The SAB_PORT serves as the private data structure associated
+with each 8253x network interface.
+
+10. struct file_operations ^Ö one per port, standard character device
+structure. The SAB_PORT serves as the private data structure associated
+with each 8253x character interface.
+
+
+
+Thus the fundamental driver functionalities, the TTY device, the network
+interface and the character device, share the port structure; and the
+port structure contains the data is used to arbitrate driver
+functionality access to a given physical port. All the above driver
+specific structures are dynamically allocated at driver initialization.
+They are maintained on lists (in come cases several lists, e.g., global,
+per board, by interrupt+by board type and per chip lists). The global
+port list is used to map minor device numbers sequentially to ports.
+The per chip port list is used in interrupt processing. Likewise the by
+interrupt+by board type board lists are also used in interrupt processing.
+
+
+
+The use and definition of the tty_struct (TTY and callout drivers),
+net_device (network drivers) and file_operations (character drivers)
+structures are found in the Linux.
+
+
+
+
+
+ Quick Overview of Standard Linux TTY, Network and Character Devices
+ and Interaction with the ASLX Driver Design
+
+
+
+The basic design of TTY/callout drivers, network drivers and character
+drivers is specified by the Linux interface.
+
+
+
+The TTY driver uses the standard circular transmit buffer as found in
+serial.c, which handles the PC com ports) while received characters pass
+into a line disciple via the standard flip buffer logic found in serial.c
+
+
+
+The network and character driver parts just follow the design described
+in /Linux Device Drivers/ by Alessandro Rubini.
+
+All the driver functionalities use a circular transmit buffer descriptor
+ring and sk_buffers for receiving and transmitting data. This uniform
+approach to transception simplifies the driver logic immensely.
+
+
+
+There is no use of a transmit done interrupt equivalent (unnecessary for
+a non-dma design). The driver can be compiled to free up transmitted
+sk_buffs in the interrupt handler or in write routines. Investigation
+shows that the driver performs better when transmitted buffers are freed
+outside of the interrupt handlers. The sk_* routines are in general
+fairly performance costly. As a further optimization, when sk_buffs are
+freed in the write routines, if system write gets ahead of the
+transmitter, the program logic will try to avoid releasing transmitted
+buffers (in the TTY driver) but will try to reuse them if possible.
+
+
+
+When data is received, chains of receive buffers are passed back to the
+character device read routine or to a flush-to-line-discipline function
+(defined in the ASLX driver to override the default flush_to_ldisc
+routine defined in tty_io.c) in the case of the TTY driver
+functionalities. The network driver just invokes the /netif_rx()/
+routine at interrupt level to receive packets. Currently, the network
+driver pre-allocates a receive buffer, but such pre-allocation is not
+necessary, and no other driver functionalities make use of
+pre-allocation of buffers.
+
+
+ From Standard Driver Architectures to the ASLX Driver
+
+
+
+The main difficulties to be overcome in the ASLX design fit into two
+categories.
+
+
+
+1. No other Linux driver attempts to combine multiple TTY
+functionalities with network and character driver functionalities.
+
+2. Even though the members of this Aurora product line all use
+basically the same Siemens/Infineon interface chip, the details of
+accessing this chip differ radically over the product line. The adapter
+cards use the PLX 9050 PCI bridge chip while the multichannel servers
+use the AMCC 5920 PCI bridge chip. In the latter case there is a
+somewhat complex G-Link hardware protocol used for communication between
+the host adapter card and the expansion chassis that hosts the extension
+boards where the serial interface chips are located. The adapter cards
+differ in detecting and causing modem signal changes.
+
+
+
+
+ /Creating a Uniform Device Programming Interface/
+
+
+
+The most painful aspect of of creating a multifunction driver for the
+Aurora hardware is the difference of each Aurora adapter card or unit
+from every other Aurora adapter card or unit.
+
+
+
+Signals are handled differently on ESCC2 (SAB82532) versus ESCC8
+(SAB82538) based devices. Interrupt processing is different on ESCC2,
+ESCC8 and multichannel server devices. The multichannel servers use an
+AMCC bridge chip while the other devices use a PLX bridge chip.
+Multichannel servers and all other Aurora adapter cards access device
+registers completely differently.
+
+
+
+There are a set of data structures and macros that simplify access to
+control registers for serial ports and that try to provide uniformity in
+line control signal handling, which is complex because some signals are
+defined in the serial port interface of the 8253X serial interface chip
+while other signals are handled through the general parallel ports of
+the 8253X chip.
+
+
+
+The bitwise definition of the line control signals differ on the
+parallel ports of the 82532 and the 82538 based cards (including
+multichannel server units).
+
+
+
+The macros (courtesy Francois Wautier) below provide a common interface
+for raising and lowering control signals as well as for querying them.
+
+
+
+
+/*
+
+ * Raise a modem signal y on port x, tmpval must exist! */
+
+#define RAISE(xx,y) \
+
+{ \
+
+ unsigned char __tmpval__; \
+
+ __tmpval__= (xx)->readbyte((xx),(xx)->y.reg);\
+
+ if((xx)->y.inverted)\
+
+ __tmpval__ &= ~((xx)->y.mask);\
+
+ else\
+
+ __tmpval__ |= (xx)->y.mask;\
+
+ __tmpval__ |= (xx)->y.cnst;\
+
+ (xx)->y.val=1;\
+
+ (xx)->writebyte((xx),(xx)->y.reg,__tmpval__);\
+
+}
+
+/*
+
+ * Lower a modem signal y on port x, __tmpval__ must exist! */
+
+#define LOWER(xx,y) \
+
+{\
+
+ unsigned char __tmpval__; \
+
+ __tmpval__= (xx)->readbyte((xx),(xx)->y.reg);\
+
+ if((xx)->y.inverted)\
+
+ __tmpval__ |= (xx)->y.mask;\
+
+ else\
+
+ __tmpval__ &= ~((xx)->y.mask);\
+
+ __tmpval__ |= (xx)->y.cnst;\
+
+ (xx)->y.val=0;\
+
+ (xx)->writebyte((xx),(xx)->y.reg,__tmpval__);\
+
+}
+
+
+
+#define ISON(xx,y) \
+
+ ((xx)->y.inverted !=
+(((xx)->readbyte((xx),(xx)->y.reg)&(xx)->y.mask)==(xx)->y.mask))
+
+
+
+The inverted, cnst, and mask fields of the modem signal structure (y)
+are specific to the type of serial communications controller. The
+readbyte and writebyte functions are specific to the different types of
+Aurora hardware.
+
+
+
+To hide the details of accessing control and data registers, the
+SAB_PORT structure has a fields whose values are the functions to read a
+device register, to write a device register,to read a device FIFO and
+to write a device FIFO (as well as to read and to write short words,
+functions that could be used in implementing the readfifo and writefifo
+routines).
+
+
+
+Here is readfifo for non-multichannel server hardware.
+
+
+
+/***************************************************************************
+
+ * aura_readfifo: Function to read the FIFO on a 4X20P, 8X20P or Sun
+serial
+
+ *
+
+ *
+
+ * Parameters :
+
+ * port: The port being accessed
+
+ * buf: The address of a buffer where we should put
+
+ * what we read
+
+ * nbytes: How many chars to read.
+
+ *
+
+ * Return value : none
+
+ *
+
+ * Prerequisite : The port must have been opened
+
+ *
+
+ * Remark :
+
+ *
+
+ * Author : fw
+
+ *
+
+ * Revision : Oct 13 2000, creation
+
+ ***************************************************************************/
+
+void aura_readfifo(struct sab_port *port, unsigned char *buf, unsigned
+int nbytes)
+
+{
+
+ int i;
+
+ unsigned short *wptr = (unsigned short*) buf;
+
+ int nwords = ((nbytes+1)/2);
+
+ for(i = 0; i < nwords; i ++)
+
+ {
+
+ wptr[i] = readw(((unsigned short *)port->regs));
+
+ }
+
+}
+
+
+
+Here is the readfifo function for multichannel servers.
+
+
+
+void wmsaura_readfifo(struct sab_port *port, unsigned char *buf,
+unsigned int nbytes)
+
+{
+
+#ifdef FIFO_DIRECT
+
+ unsigned short fifo[32/2]; /* this array is word aligned
+
+ * buf may not be word aligned*/
+
+ unsigned int nwords;
+
+ int i;
+
+ int wcount;
+
+ unsigned int address;
+
+
+
+ if (nbytes == 0)
+
+ {
+
+ return;
+
+ }
+
+
+
+ wcount = ((nbytes + 1) >> 1);
+
+ /* Read the thing into the local FIFO and copy it out. */
+
+ address = (unsigned int) port->regs;
+
+
+
+ for(i = 0; i < wcount; ++i)
+
+ {
+
+ fifo[i] = readw((unsigned short*)(address + CIMCMD_RDFIFOW));
+
+ }
+
+
+
+ memcpy((unsigned char*) buf, (unsigned char*) &(fifo[0]), (unsigned
+int) nbytes);
+
+
+
+#else /* FIFO_DIRECT */
+
+ unsigned short fifo[32/2];
+
+ int i;
+
+ int wcount;
+
+ SAB_BOARD *bptr;
+
+ unsigned int channel;
+
+
+
+ if (nbytes == 0)
+
+ {
+
+ return;
+
+ }
+
+
+
+ bptr = port->board;
+
+ wcount = ((nbytes + 1) >> 1);
+
+ channel = (((unsigned char*) port->regs) - bptr->CIMCMD_REG); /*
+should be properly shifted */
+
+
+
+ /*
+
+ * Trigger a cache read by writing the nwords - 1 to the
+
+ * magic place.
+
+ */
+
+
+
+ writeb((unsigned char) wcount, bptr->MICCMD_REG + (MICCMD_CACHETRIG +
+channel));
+
+
+
+ /*
+
+ * Now, read out the contents.
+
+ */
+
+
+
+ channel >>= 1;
+
+
+
+ for(i = 0; i < wcount; ++i)
+
+ {
+
+ fifo[i] = readw((unsigned short*)(bptr->FIFOCACHE_REG + (channel +
+(i << 1))));
+
+ }
+
+
+
+ memcpy((unsigned char*) buf, (unsigned char*) &(fifo[0]), (unsigned
+int) nbytes);
+
+#endif /* !FIFO_DIRECT */
+
+}
+
+
+
+
+Except at initialization time the driver code accesses serial
+communications controller device registers only through fields in the
+port structure. The details of accessing the different types of
+hardware are almost completely hidden from the driver program logic.
+
+
+
+The only exception is the interrupt handler, which must understand some
+of the details of the multichannel server. Nevertheless, as is made
+clear in the following section, from the standpoint of processing
+interrupts there are really only two types of Aurora hardware, that
+which is ESCC2 based and that which is ESCC8 based. The details of the
+difference of the two types of hardware is contained solely within the
+8253xint.c file which also contains the logic by which an interrupt from
+a multichannel server can be processed almost exactly like an interrupt
+from an 8520P adapter card.
+
+
+
+
+ /Code Structure Summary/
+
+
+
+
+
+ The SAB8253X driver code has the following logic components
+
+
+
+1. a probe/initialization logic,
+
+a. bridge initialization/EEPROM parsing logic,
+
+b. structure allocation logic,
+
+c. interrupt request logic,
+
+2. the core logic, which handles all the non-interrupt processing
+of the driver functionality,
+
+a. per port startup/shutdown logic,
+
+b. driver arbitration logic,
+
+c. skbuffer management logic,
+
+3. the interrupt handler logic,
+
+a. common interrupt port polling logic,
+
+b. skbuffer management logic,
+
+4. the termination/driver unload logic,
+
+a. interrupt shutdown logic,
+
+b. device shutdown logic,
+
+c. structure deallocation logic.
+
+
+
+
+
+/Probe/Initialization Logic/
+
+
+
+The probe/initialization logic sets up the CRC structures for the
+network driver and then the tty_struct for the synchronous and
+asynchronous TTY drivers. Initializing the tty_struct involves setting
+up pointers to the standard functions that the Linux TTY driver invokes
+as well as some standard data and the /proc/tty/driver/auraserial
+function and data.
+
+
+
+
+The probe/initialization logic identifies all the multiport serial
+adapters, compact PCI adapters and multiserver adapters in the system
+and puts them on a list of board structures. After identifying all the
+boards, initializing the bridge chips and analyzing (possibly rewriting)
+the serial EEPROM, the logic sets up all the chips on the boards and all
+the ports on the chips.
+
+
+
+All chips are linked together in a list. All ports are linked together
+in a list. The port list is linked together so that minor device N
+corresponds to the Nth element of the port list. A board structure
+points to a list of chips on the board as well as a list of all ports on
+the board. Likewise a chip structure points to a list of all ports on
+the chip. Chip structures point back to the board structure associated
+with the board on which the chip resides. Likewise port structures
+point back to the board and to the chip on which they reside. This
+interconnected list structure facilitates access to one type of
+structure when a routine has been passed a pointer to another type of
+structure. All these structures are dynamically allocated via
+/kmalloc()/. When the driver is unloaded, memory is released by walking
+the list.
+
+
+
+After setting up the board, chip and port structures, initialization of
+the tty_struct is completed at this point because the maximum possible
+number of serial TTYs is now known. The, the standard network device
+structure that is associated with each port is allocated and
+initialized. The network devices point to the associated port
+structure. The network devices are chained via a pointer in the
+associated port structure. This chaining facilitates release of the
+network device structure memory when the driver is unloaded.
+
+
+
+Each network device is registered after its network device structure is
+initialized. Network device initialization invokes the network device
+initialization, which installs the standard network functions in the
+network device structure and which sets up the sk_buff transmit ring as
+well as the receive sk_buf. Unlike the Solaris driver, when a complete
+frame is received with no errors, it is immediately passed into the
+network layer. Thus, there is no receive ring of sk_buffs as one might
+find in the driver of a device that could carry out chained DMA (e.g. a
+DEC Tulip or an Hitachi SCA).
+
+
+
+All sk_buffs associated with a network device that are currently in use
+by the network driver are linked together in an sk_buff list (viz core
+logic). This list facilitates release of all sk_buff associated with a
+network device when that network device is shut down. This list may be
+a problem if it becomes possible for a single sk_buff to be used
+simultaneously by multiple network devices. Currently, sk_buff headers
+are not shared among network devices although sk_buff data can be
+shared. Thus, for the nonce this logic works correctly.
+
+
+
+After completing of network device initialization, the
+probe/initialization logic register the character driver. Next, the
+probe/initialization creates three lists of boards for each interrupt
+(0-31). One list contains 82532 based boards at that interrupt level.
+The next list contains 82538 based adapter cards at that interrupt
+level. The third list contains all multichannel server units at that
+interrupt level.
+
+
+
+Next the probe/initialization logic checks the lists associated with
+each interrupt level. If either list is non-null, the
+probe/initialization logic requests that the general interrupt handler
+be installed at this interrupt level and then it turns on PLX9050 or
+AMCC5920 interrupts (as needed) into the Linux host for each card
+associated with that interrupt level. Thus, the interrupt handler polls
+all boards/ports at a given interrupt level when the interrupt occurs.
+This approach is more efficient that installing one interrupt per board
+and avoids some internal Linux limits on the number of interrupt
+handlers that can be installed per interrupt.
+
+
+
+At this point probe/intialization is complete and any serial port may be
+used for asynchronous TTY, synchronous TTY, call out, network device
+service or synchronous character device service.
+
+
+
+
+/Core Logic/
+
+
+
+The main problem of the core logic is arbitration of access to the
+serial port, when and by which part of the driver a port is started and
+when the port is shut down.
+
+
+
+The asynchronous callout, asynchronous TTY, synchronous TTY devices,
+synchronous character device and network device follow the following rules.
+
+
+
+1. If there is an established point-to-point
+connection, only the current process or process group that owns the
+serial port may open the device.
+
+2. If the asynchronous callout is open, opens of a
+single TTY or character device type block until the connection completes.
+
+3. Network device opens never block, and the network
+layer opens a network device only once.
+
+4. If a connection that belongs to a TTY device or
+character device hangs up, eventually all opens of that device will close.
+
+5. Hangup of on a network device does not guarantee a
+close of the device, but a flag bit is set that permits a call out open
+to restore the connection (note that a one-to-one map of TTY devices,
+callout devices, character devices and network devices is implied.)
+
+
+
+The network device open and block_til_ready* functions invoked from TTY
+opens enforce this arbitration.
+
+
+
+The logic works as follows:
+
+
+
+ * The cua device associated with a port may only be opened one.
+ * If a TTY or character device is open, the cua device may not be
+ opened.
+ * If the cua device is open, the network device cannot be opened and
+ the TTY or character device block (multiple opens from the same
+ process or process group are allowed).
+ * If the network device is open, the TTY or character devices cannot
+ be opened while the cua device blocks.
+ * A hangup sends an interrupt to the TTY or character device while
+ the network device shuts down its port and a (network blocked) cua
+ device proceeds.
+ * On the close of the cua device, blocked TTY and character devices
+ proceed and the network device restarts its port.
+
+
+
+When an open completes, the transmit_chars, receive_chars, check_status
+functions and associated data fields are set in the port structure,
+these are used in the interrupt handler that never changes until the
+driver is unloaded.
+
+
+
+When a port is not in use, the asynchronous version of these fields and
+functions are set in the port structure. Some values must be present,
+and the asynchronous ones are probably the least dangerous.
+
+
+
+Besides the arbitration problem, the core logic addresses buffer
+management for the network and character drivers.
+
+
+
+The network layer passes a transmit sk_buff to the network driver. The
+buffer is inserted in the transmit ring or sets a transmit congestion
+flag. In either case, transmit is initialized if not already in
+progress. If the sk_buff is successfully inserted, it is also linked
+into the driver sk_buff list which tracks all sk_buffs used by the
+network driver. On network device close all sk_buffs on the per port
+sk_buff list are released. This sk_buff list mechanism is used to avoid
+memory leaks.
+
+
+
+The TTY and character drivers packetize write data in an sk_buff (each
+write creates a single sk_buff) and inserts it in the transmit ring if
+possible or blocks (returns a failure in the case of TTY drivers).
+Transmit sk_buffs are also linked into the driver sk_buff list. This
+list is a convenience to assist deallocation during driver close.
+
+
+
+The TTY and character drivers also maintains a receive sk_buff list.
+When the user application invokes the read system call, the data from
+one sk_buff is passed up to the user application (or an error if the
+read were not invoked with sufficient buffer space).
+
+
+
+The character driver can be configured via IOCTL to send asynchronous
+user notification when the transmit ring empties (a design choice for
+the standard driver fasync functionality). This character driver design
+emulates the Solaris putmsg/getmsg interface as far as possible and
+makes it possible to implement in a user application protocols like
+LAPB, which require that low priority packets only be queued to the
+driver when the driver currently has no frames in the process of
+transmission or queued for transmission.
+
+
+
+On character device close all sk_buffs on the per port sk_buff and per
+port receive sk_buff list are released. This double sk_buff list
+mechanism is used to avoid memory leaks.
+
+
+
+/Interrupt Handler Logic/
+
+
+
+
+ The following code comprises the combined interrupt and board/port
+ polling logic. The actual handler is /sab8253x_interrupt()/. It
+ walks through the 82532, adapter 82538 adapter and multichannel
+ server lists at the interrupt level that is being processed and
+ invokes inline /sab82532_interrupt()/ and /sab82538_interrupt()/.
+ Note that it temporary modifies multichannel server lists so that
+ it like an 8520P adapter card to the /sab8253x_interrupt()/. This
+ logic works because the granularity of the PCI interrupt
+ associated with the Aurora hardware is basically either a list of
+ ESCC2s (the 4520P and 4520CP adapter cards) or a single ESCC8 (an
+ 8520P or one ESCC8 on a multichannel server remote card after the
+ interrupt status has been queried).
+
+
+
+
+
+ The current interrupt sources are identified and processed. If
+ any characters are available to be received, they are received one
+ fifo at a time into the TTY flip buffer (a structure that is
+ supposed to decrease TTY latency) or into an sk_buf (something
+ like a Solaris mblk/dblk structure( in the case of the network or
+ character driver. Then if there are characters in the TTY
+ circular transmit buffer or in the network or character driver
+ sk_buff, they are loaded into the transmit fifo, one fifo at a
+ time. Finally, modem control status is checked. If a hang up is
+ detected, the serial driver hang up is scheduled at kernel
+ scheduler priority (a slight difference from the standard serial
+ driver which processes hang-ups at interrupt level) in order to
+ avoid certain race conditions in the TTY driver that can occur on
+ fast machines with many serial ports. /do_serial_hangup()/
+ invokes the TTY hangup routines in the case of TTY driver. For a
+ network connection in the event of a line disconnection, carrier
+ is marked as off on the interface and the blocked cua device is
+ woken so that it can proceed after the network port has shut down.
+
+
+
+static void __inline__ sab82532_interrupt(int irq, void *dev_id, struct
+pt_regs *regs)
+
+{
+
+ struct sab_port *port;
+
+ struct sab_chip *chip=NULL;
+
+ struct sab_board *bptr = (struct sab_board*) dev_id;
+
+ union sab8253x_irq_status status;
+
+ unsigned char gis;
+
+
+
+ for(chip = bptr->board_chipbase; chip != NULL; chip =
+chip->next_by_board)
+
+ {
+
+ port= chip->c_portbase;
+
+ gis = READB(port, gis); /* Global! */
+
+ status.stat=0;
+
+
+
+ /* Since the PORT interrupt are global,
+
+ * we do check all the ports for this chip
+
+ */
+
+
+
+ /* A 2 ports chip */
+
+
+
+ if(!(gis & SAB82532_GIS_MASK))
+
+ {
+
+ continue; /* no interrupt on this chip */
+
+ }
+
+
+
+ if (gis & SAB82532_GIS_ISA0)
+
+ {
+
+ status.sreg.isr0 = READB(port, isr0);
+
+ }
+
+ else
+
+ {
+
+ status.sreg.isr0 = 0;
+
+ }
+
+ if (gis & SAB82532_GIS_ISA1)
+
+ {
+
+ status.sreg.isr1 = READB(port, isr1);
+
+ }
+
+ else
+
+ {
+
+ status.sreg.isr1 = 0;
+
+ }
+
+
+
+ if (gis & SAB82532_GIS_PI)
+
+ {
+
+ status.sreg.pis = READB(port, pis);
+
+ }
+
+ else
+
+ {
+
+ status.sreg.pis = 0;
+
+ }
+
+
+
+ if (status.stat)
+
+ {
+
+ if (status.images[ISR0_IDX] & port->receive_test)
+
+ {
+
+ (*port->receive_chars)(port, &status); /* when the fifo
+is full */
+
+ /* no time to schedule
+thread*/
+
+ }
+
+
+
+ if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
+
+ (status.images[port->cts.irq] & port->cts.irqmask) ||
+
+ (status.images[port->dsr.irq] & port->dsr.irqmask) ||
+
+ (status.images[ISR1_IDX] & port->check_status_test))
+
+ {
+
+ (*port->check_status)(port, &status); /* this stuff should
+be */
+
+ /* be moveable to scheduler */
+
+ /* thread*/
+
+ }
+
+
+
+ if (status.images[ISR1_IDX] & port->transmit_test)
+
+ {
+
+ (*port->transmit_chars)(port, &status); /* needs to be
+moved to task */
+
+ }
+
+ }
+
+
+
+ /* Get to next port on chip */
+
+ port = port->next_by_chip;
+
+ /* Port B */
+
+ if (gis & SAB82532_GIS_ISB0)
+
+ {
+
+ status.images[ISR0_IDX] = READB(port, isr0);
+
+ }
+
+ else
+
+ {
+
+ status.images[ISR0_IDX] = 0;
+
+ }
+
+ if (gis & SAB82532_GIS_ISB1)
+
+ {
+
+ status.images[ISR1_IDX] = READB(port,isr1);
+
+ }
+
+ else
+
+ {
+
+ status.images[ISR1_IDX] = 0;
+
+ }
+
+ /* DO NOT SET PIS. IT was reset! */
+
+
+
+
+
+ if (status.stat)
+
+ {
+
+ if (status.images[ISR0_IDX] & port->receive_test)
+
+ {
+
+ (*port->receive_chars)(port, &status);
+
+ }
+
+ if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
+
+ (status.images[port->cts.irq] & port->cts.irqmask) ||
+
+ (status.images[port->dsr.irq] & port->dsr.irqmask) ||
+
+ (status.images[ISR1_IDX] & port->check_status_test))
+
+ {
+
+ (*port->check_status)(port, &status);
+
+ }
+
+ if (status.images[ISR1_IDX] & port->transmit_test)
+
+ {
+
+ (*port->transmit_chars)(port, &status);
+
+ }
+
+ }
+
+ }
+
+}
+
+
+
+static void __inline__ sab82538_interrupt(int irq, void *dev_id, struct
+pt_regs *regs)
+
+{
+
+ struct sab_port *port;
+
+ struct sab_chip *chip=NULL;
+
+ struct sab_board *bptr = (struct sab_board*) dev_id;
+
+ union sab8253x_irq_status status;
+
+ unsigned char gis,i;
+
+
+
+ chip = bptr->board_chipbase;
+
+ port= chip->c_portbase;
+
+
+
+ gis = READB(port, gis); /* Global! */
+
+ status.stat=0;
+
+
+
+ /* Since the PORT interrupt are global,
+
+ * we do check all the ports for this chip
+
+ */
+
+
+
+ /* 8 ports chip */
+
+ if(!(gis & SAB82538_GIS_MASK))
+
+ {
+
+ return;
+
+ }
+
+
+
+ if(gis & SAB82538_GIS_CII)
+
+ { /* A port interrupt! */
+
+ /* Get the port */
+
+ int portindex;
+
+
+
+ portindex = (gis & SAB82538_GIS_CHNL_MASK);
+
+
+
+ port = chip->c_portbase;
+
+
+
+ while(portindex)
+
+ {
+
+ port = port->next_by_chip;
+
+ --portindex;
+
+ }
+
+
+
+ status.images[ISR0_IDX] = READB(port,isr0);
+
+ status.images[ISR1_IDX] = READB(port,isr1);
+
+ if (gis & SAB82538_GIS_PIC)
+
+ {
+
+ status.images[PIS_IDX] =
+
+ (*port->readbyte)(port,
+
+ ((unsigned char *)(port->regs)) +
+
+ SAB82538_REG_PIS_C);
+
+ }
+
+ else
+
+ {
+
+ status.images[PIS_IDX] = 0;
+
+ }
+
+
+
+ if (status.stat)
+
+ {
+
+ if (status.images[ISR0_IDX] & port->receive_test)
+
+ {
+
+ (*port->receive_chars)(port, &status);
+
+ }
+
+ if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
+
+ (status.images[port->cts.irq] & port->cts.irqmask) ||
+
+ (status.images[port->dsr.irq] & port->dsr.irqmask) ||
+
+ (status.images[ISR1_IDX] & port->check_status_test))
+
+ {
+
+ (*port->check_status)(port, &status);
+
+ }
+
+ /*
+
+ * We know that with 8 ports chip, the bit corresponding to
+channel
+
+ * number is used in the parallel port... So we clear it
+
+ * Not too elegant!
+
+ */
+
+ status.images[PIS_IDX] &= ~(1 << (gis&SAB82538_GIS_CHNL_MASK));
+
+ if (status.images[ISR1_IDX] & port->transmit_test)
+
+ {
+
+ (*port->transmit_chars)(port, &status);
+
+ }
+
+ }
+
+ }
+
+
+
+ /*
+
+ * Now we handle the "channel interrupt" case. The chip manual for the
+
+ * 8 ports chip states that "channel" and "port" interrupt are set
+
+ * independently so we still must check the parrallel port
+
+ *
+
+ * We should probably redesign the whole thing to be less AD HOC that we
+
+ * are now... We know that port C is used for DSR so we only check
+that one.
+
+ * PIS for port C was already recorded in status.images[PIS_IDX], so we
+
+ * check the ports that are set
+
+ */
+
+
+
+ if (status.images[PIS_IDX])
+
+ {
+
+ for(i=0, port = chip->c_portbase;
+
+ i < chip->c_nports;
+
+ i++, port=port->next_by_chip)
+
+ {
+
+ if(status.images[PIS_IDX] & (0x1 << i))
+
+ { /* Match */
+
+ /* Checking DSR */
+
+ if(port->dsr.inverted)
+
+ {
+
+ port->dsr.val = (((*port->readbyte)
+
+ (port, port->dsr.reg) &
+
+ port->dsr.mask) ? 0 : 1);
+
+ }
+
+ else
+
+ {
+
+ port->dsr.val = ((*port->readbyte)(port, port->dsr.reg) &
+
+ port->dsr.mask);
+
+ }
+
+
+
+ port->icount.dsr++;
+
+ wake_up_interruptible(&port->delta_msr_wait);
+
+ }
+
+ }
+
+ }
+
+}
+
+
+
+/*
+
+ * This is the serial driver's generic interrupt routine
+
+ */
+
+
+
+void sab8253x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+
+{
+
+ extern SAB_BOARD *AuraBoardESCC2IrqRoot[];
+
+ extern SAB_BOARD *AuraBoardESCC8IrqRoot[];
+
+ extern SAB_BOARD *AuraBoardMCSIrqRoot[];
+
+ AURA_CIM *cim;
+
+ SAB_CHIP *chip;
+
+ SAB_PORT *port;
+
+ register SAB_BOARD *boardptr;
+
+ register unsigned char intrmask;
+
+ unsigned char stat;
+
+ SAB_CHIP *save_chiplist;
+
+ SAB_PORT *save_portlist;
+
+
+
+ if((irq < 0) || (irq >= NUMINTS))
+
+ {
+
+ printk(KERN_ALERT "sab8253x: bad interrupt value %i.\n", irq);
+
+ return;
+
+ }
+
+ /* walk through all the cards on the interrupt that occurred. */
+
+ for(boardptr = AuraBoardESCC2IrqRoot[irq]; boardptr != NULL; boardptr
+= boardptr->next_on_interrupt)
+
+ {
+
+ sab82532_interrupt(irq, boardptr, regs);
+
+ }
+
+
+
+ for(boardptr = AuraBoardESCC8IrqRoot[irq]; boardptr != NULL; boardptr
+= boardptr->next_on_interrupt)
+
+ {
+
+ sab82538_interrupt(irq, boardptr, regs);
+
+ }
+
+
+
+ for(boardptr = AuraBoardMCSIrqRoot[irq]; boardptr != NULL; boardptr =
+boardptr->next_on_interrupt)
+
+ {
+
+
+
+ while(1)
+
+ {
+
+ writeb(0, (unsigned char*)(boardptr->CIMCMD_REG +
+CIMCMD_WRINTDIS)); /* prevent EBs from raising
+
+
+* any more ints through the
+
+
+* host card */
+
+ stat = ~(unsigned char) /* active low !!!!! */
+
+ readw((unsigned short*)
+
+ (((unsigned char*)boardptr->CIMCMD_REG) +
+CIMCMD_RDINT)); /* read out the ints */
+
+ /* write to the MIC csr to reset the PCI
+interrupt */
+
+ writeb(0, (unsigned char*)(boardptr->MICCMD_REG +
+MICCMD_MICCSR)); /* reset the interrupt generation
+
+
+ * hardware on the host card*/
+
+ /* now, write to the CIM interrupt ena
+to re-enable interrupt generation */
+
+ writeb(0, (unsigned char*)(boardptr->CIMCMD_REG +
+CIMCMD_WRINTENA)); /* allow EBs to request ints
+
+
+* through the host card */
+
+ if(!stat)
+
+ {
+
+ break;
+
+ }
+
+ cim = boardptr->b_cimbase; /* cims in reverse order */
+
+ for(intrmask = boardptr->b_intrmask;
+
+ intrmask != 0;
+
+ intrmask <<= 2, stat <<=2)
+
+ {
+
+ if(cim == NULL)
+
+ {
+
+ break; /* no cim no ports */
+
+ }
+
+ if((intrmask & 0xc0) == 0) /* means no cim for these ints */
+
+ { /* cim not on list do not go to next */
+
+ continue;
+
+ }
+
+ save_portlist = boardptr->board_portbase;
+
+ save_chiplist = boardptr->board_chipbase;
+
+ /* the goal is temporarily to make the
+structures
+
+ * look like 8x20 structures -- thus if
+I find
+
+ * a bug related to escc8s I need fix it in
+
+ * only one place. */
+
+ switch(stat & 0xc0) /* possible ints */
+
+ {
+
+ default:
+
+ break;
+
+
+
+ case 0x80: /* esccB */
+
+ chip = cim->ci_chipbase;
+
+ if(!chip)
+
+ {
+
+ printk(KERN_ALERT "aura mcs: missing cim.\n");
+
+ break;
+
+ }
+
+ chip = chip->next_by_cim;
+
+ if(!chip)
+
+ {
+
+ printk(KERN_ALERT "aura mcs: missing 2nd cim.\n");
+
+ break;
+
+ }
+
+ port = chip->c_portbase;
+
+ boardptr->board_portbase = port;
+
+ boardptr->board_chipbase = chip;
+
+ sab82538_interrupt(irq, boardptr, regs);
+
+ break;
+
+
+
+ case 0x40: /* esccA */
+
+ chip = cim->ci_chipbase;
+
+ if(!chip)
+
+ {
+
+ printk(KERN_ALERT "aura mcs: missing cim.\n");
+
+ break;
+
+ }
+
+ port = chip->c_portbase;
+
+ boardptr->board_portbase = port;
+
+ boardptr->board_chipbase = chip;
+
+ sab82538_interrupt(irq, boardptr, regs);
+
+ break;
+
+
+
+ case 0xc0: /* esccB and esccA */
+
+ chip = cim->ci_chipbase;
+
+ if(!chip)
+
+ {
+
+ printk(KERN_ALERT "aura mcs: missing cim.\n");
+
+ break;
+
+ }
+
+ port = chip->c_portbase;
+
+ boardptr->board_portbase = port;
+
+ boardptr->board_chipbase = chip;
+
+ sab82538_interrupt(irq, boardptr, regs);
+
+
+
+ chip = cim->ci_chipbase;
+
+ if(!chip)
+
+ {
+
+ printk(KERN_ALERT "aura mcs: missing cim.\n");
+
+ break;
+
+ }
+
+ chip = chip->next_by_cim;
+
+ if(!chip)
+
+ {
+
+ printk(KERN_ALERT "aura mcs: missing 2nd cim.\n");
+
+ break;
+
+ }
+
+ port = chip->c_portbase;
+
+ boardptr->board_portbase = port;
+
+ boardptr->board_chipbase = chip;
+
+ sab82538_interrupt(irq, boardptr, regs);
+
+ break;
+
+ }
+
+ boardptr->board_portbase = save_portlist;
+
+ boardptr->board_chipbase = save_chiplist;
+
+ cim = cim->next_by_mcs;
+
+ }
+
+ }
+
+ }
+
+}
+
+
+
+Note that if there is no transmit in process when the
+write/hard_start_transmit routine is invoked, transmit is intitiated
+from the core logic as if it took place in the interrupt handler. This
+approach differs from the ASE driver, which used to force an interrupt,
+and then start the transmission. Francois Wautier may have fixed that
+logic to start the transmission either in the STREAMS put or service
+routine.
+
+
+
+/Driver Unload Logic/
+
+
+
+The driver unload logic inverts the probe intialization logic.
+
+
+
+At this point no ports should be in use and in fact every port should
+have been put in the 8253x powered down state when each port underwent
+its last close (or hangup which can actually complete after a close).
+
+
+
+The tty driver is cleaned up, some dynamic TTY data structures are
+deallocated, the bottom half associated with this driver is removed and
+all TTY ports are deregistered.
+
+
+
+The PLX or AMCC interrupts to the Linux host are disabled on each board,
+and all interrupt handlers are freed.
+
+
+
+Next all board and chip structures are deallocated (including physical
+memory to virtual memory mappings associated with PLX9050 or AMCC 5920
+and chip registers). Then all network device structures are
+deallocated. (Note that all lingering sk_buffs were freed during the
+close of the network device, which must have completed before the unload
+of the driver module.) And finally the port structures are
+deallocated. In deallocating the port structures, network driver
+transmit rings and the receive sk_buff descriptor are deallocated if
+they are present. (They were only allocated if the port had ever been
+used for a network device.) At this point the driver has been
+gracefully unloaded.
+
+
+
+ /* cleanup module/free up virtual memory */
+
+ /* space*/
+
+void cleanup_module(void)
+
+{
+
+ SAB_BOARD *boardptr;
+
+ SAB_CHIP *chipptr;
+
+ SAB_PORT *portptr;
+
+ int intr_val;
+
+ extern void sab8253x_cleanup_ttydriver(void);
+
+
+
+ printk(KERN_ALERT "auraXX50n: unloading AURAXX50 driver.\n");
+
+
+
+ sab8253x_cleanup_ttydriver(); /* clean up tty */
+
+
+
+ /* unallocate and turn off ints */
+
+ for(intr_val = 0; intr_val < NUMINTS; ++intr_val)
+
+ {
+
+ if((AuraBoardESCC2IrqRoot[intr_val] != NULL) ||
+(AuraBoardESCC8IrqRoot[intr_val] != NULL))
+
+ {
+
+ for(boardptr = AuraBoardESCC2IrqRoot[intr_val]; boardptr !=
+NULL; boardptr = boardptr->next_on_interrupt)
+
+ {
+
+ writel(PLX_INT_OFF, &(boardptr->b_bridge->intr));
+
+ }
+
+ for(boardptr = AuraBoardESCC8IrqRoot[intr_val]; boardptr !=
+NULL; boardptr = boardptr->next_on_interrupt)
+
+ {
+
+ writel(PLX_INT_OFF, &(boardptr->b_bridge->intr));
+
+ }
+
+
+
+ free_irq(intr_val, &AuraBoardESCC2IrqRoot[intr_val]); /* free
+up board int
+
+ * note
+that if two boards
+
+ * share
+an int, two int
+
+ *
+handlers were registered
+
+ *
+
+ */
+
+ }
+
+ }
+
+
+
+ /* disable chips and free board memory*/
+
+ while(AuraBoardRoot)
+
+ {
+
+ boardptr = AuraBoardRoot;
+
+ for(chipptr = boardptr->board_chipbase; chipptr != NULL; chipptr =
+chipptr->next_by_board)
+
+ {
+
+ (*chipptr->int_disable)(chipptr); /* make sure no ints can
+come int */
+
+ }
+
+ AuraBoardRoot = boardptr->nextboard;
+
+ if(boardptr->virtbaseaddress0)
+
+ {
+
+ DEBUGPRINT((KERN_ALERT
+
+ "auraXX50n: unmapping virtual address %p.\n",
+
+ (void*)boardptr->virtbaseaddress0));
+
+ iounmap((void*)boardptr->virtbaseaddress0);
+
+ boardptr->virtbaseaddress0 = 0;
+
+ }
+
+ if(boardptr->virtbaseaddress2)
+
+ {
+
+ DEBUGPRINT((KERN_ALERT
+
+ "auraXX50n: unmapping virtual address %p.\n",
+
+ (void*)boardptr->virtbaseaddress2));
+
+ iounmap((void*)boardptr->virtbaseaddress2);
+
+ boardptr->virtbaseaddress2 = 0;
+
+ }
+
+ kfree(boardptr);
+
+ }
+
+
+
+ while(AuraChipRoot) /* free chip memory */
+
+ {
+
+ chipptr = AuraChipRoot;
+
+ AuraChipRoot = chipptr->next;
+
+ kfree(chipptr);
+
+ }
+
+
+
+ while(Sab8253xRoot) /* free up network stuff */
+
+ {
+
+ SAB_PORT *priv;
+
+ priv = (SAB_PORT *)Sab8253xRoot->priv;
+
+ unregister_netdev(Sab8253xRoot);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
+
+ kfree(Sab8253xRoot.name);
+
+#endif
+
+ kfree(Sab8253xRoot);
+
+ Sab8253xRoot = priv->next_dev;
+
+ }
+
+
+
+ while(AuraPortRoot) /* free up port memory */
+
+ {
+
+ portptr = AuraPortRoot;
+
+ AuraPortRoot = portptr->next;
+
+ if(portptr->dcontrol2.receive)
+
+ {
+
+ kfree(portptr->dcontrol2.receive);
+
+ }
+
+ if(portptr->dcontrol2.transmit)
+
+ {
+
+ kfree(portptr->dcontrol2.transmit);
+
+ }
+
+ kfree(portptr);
+
+ }
+
+}
+
+
+
+_Design Summary_
+
+
+
+The 10 key data structures are shared by all the logic of the system.
+The logic enforces both exclusive and cooperative access to the physical
+hardware on the basis of certain rules established by the core logic at
+device/port open time. While the driver is mostly self-configuring, the
+data structure sharing simplifies the user interface because an ioctl to
+one driver functionality (e.g., the TTY functionality) configures the
+rest of the driver functionality (e.g., the network and character device
+functionality). In other words, a single serial port acts virtually as
+three arbitrated devices: a TTY device, which may be asynchronous,
+synchronous or call out, a network device or a character device. Yet,
+except at the time of initialization, time of driver unload and very
+early in interrupt processing all hardware details are concealed and the
+driver logic is applied to an abstract, simplified port entity. Thus,
+the user application interfaces to three abstract virtual devices, which
+have a single configuration interface (otherwise it might be possible to
+have an inconsistent configuration) and not to a complex real single
+port in the context of an equally complex adapter card or unit. This
+simplification makes it possible to provide a high degree of serial
+functionality across the family of Aurora synchronous/asynchronous PCI
+hardware through a straightforward uniform application interface.
+
+
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)