1*_Design Specification of SAB8253X ASLX Driver for Linux_*
2
3
4
5
6  The effort to design and implement the ASLX SAB8253X Driver for Aurora
7  <http://www.auroratech.com/> hardware with the functionality described
8  in *_Functional Specification of SAB8253X ASLX Driver for Linux
9  <http://www.telfordtools.com/sab8253x/sab8253xfs.html>_* requires
10  solutions to seven separate problems:
11
12
13
14   1. creating a development environment for maintaining and extending
15      the driver,
16   2. integrating the driver into the kernel sources,
17   3. creating a file structure of the driver that aids understanding,
18   4. crafting a reasonable and easy to use user interface,
19   5. developing simple tools and example programs for the driver, and
20   6. designing the driver data structures and
21   7. designing the driver program logic.
22
23
24
25
26  _Development Environment_
27
28
29
30
31      There are several possible approaches to creating a development
32      environment.  The development environments for many drivers seem
33      to have consisted simply of a single machine, and the developer
34      used only /printk()/ in the driver code to debug.  I used such an
35      environment to develop a driver for an IOP480 based intelligent
36      adapter card.
37
38
39
40For a driver that provides the functionality described in the Functional
41Specification, a more sophisticated development and debugging
42environment is useful.  (One could even occasionally wish for an ICE,
43but that level of resources was not available to me.)
44
45
46
47The development environment consisted of two 686 class machines, on
48which the Linux operating system was installed.  One machine ran at 800
49Mhz, the other at 1Ghz.  It probably would have been worthwhile to have
50dual processor machine, and one was added to the development environment
51later.  The 800 Mhz machine hosted the remote gdb application.  It ran
52Redhat Linux 7.0, but because the machine served only as an NFS and
53remote gdb host, the details of the Linux distribution on this machine
54are not particularly important.
55
56
57
58The target machine on which the driver was developed and debugged hosted
59Suse Linux 7.1 and was later upgraded to Suse Linux 7.3.  Suse Linux
60seemed to provide the most complete Linux distribution with the least
61hassle in installation.  (As the Suse distribution comes on 7 standard
62CDs or 1 DVD, there is a lot of value in having a DVD drive in the
63target machine [and the gdb host if it runs a Suse distribution].)
64
65
66
67The target and remote gdb machines are connected by a 100 Mbps Ethernet
68network and by a serial crossover cable between the Com1 (ttyS0) ports.
69
70
71
72When I started developing the driver, I obtained the Linux 2.4.3 sources
73from The Linux Kernel Archives <http://www.kernel.org/>.  Later as later
74distributions became stable, I switched to the Linux 2.4.6
75distribution.  The sources were installed first in
76/home/martillo/kernel/linux-2.4.3 and then in
77/home/martillo/kernel/linux-2.4.6 on the remote gdb host machine, which
78was named frolix.
79
80
81
82The sources were imported into CVS on frolix, and the core directory
83into CVS  was added manually because the cvs import function ignores
84it.  I consider it safer to maintain the CVS repository on the remote
85gdb host machine instead of the target machine because the target
86machine is likely to crash frequently, and its file system may be put
87into bad states.
88
89
90
91I executed the following commands on the remote gdb host machine.
92
93
94
95*ln ^�s /home/martillo/kernel/linux-2.4.3/include/asm-i386
96/home/martillo/kernel/linux-2.4.3/include/asm*
97
98* *
99
100or
101
102* *
103
104*ln ^�s /home/martillo/kernel/linux-2.4.6/include/asm-i386
105/home/martillo/kernel/linux-2.4.6/include/asm*
106
107* *
108
109*ln ^�s / /frolix *
110
111
112
113I edited the /etc/exports file to contain the following.
114
115
116
117/               ylith(rw)
118
119/               fireball(rw)
120
121/               bohun(rw)
122
123/               indefatigable(rw)
124
125
126
127Ylith is the original 1 Ghz target machine.  Fireball is a 400 Mhz
128compact PCI target machine.  Indefatigable is a dual 1 Ghz target
129machine.  Bohun is a Solaris target machine used for another project.
130
131
132
133On the frolix, I started NFS with the following commands (contained in a
134shell script).
135
136
137
138*/etc/rc.d/init.d/nfs start*
139
140*exportfs -va*
141
142
143
144If it had been a Suse Linux machine, I would have used the yast2 control
145center to start NFS service.
146
147
148
149On ylith, I created an empty directory /frolix and executed the
150following command.
151
152
153
154*mount frolix:/ /frolix*
155
156* *
157
158At this point both the remote gdb host (frolix) and the target
159development and debugging machine can refer to the same files by the
160same paths.  I could have guaranteed the same paths to the source files
161on both machines if I had simply used /home/martillo as my home
162directory on frolix and exported /home from frolix to all the other
163machines so that there would only be one /home directory for all the
164machines in my network.  I was lazy about the network configuration.
165
166
167
168After making sure that the user martillo had read write access
169permissions to all the kernel sources, I built the kernel on the target
170machine from within xemacs with the following sequence of commands.
171
172
173
174From a shell window:
175
176*xemacs ^�e shell&*
177
178
179
180Inside xemacs:
181
182
183
184*cd /frolix/home/martillo/kernel/linux-2.4.3*
185
186
187
188or
189
190
191
192*cd /frolix/home/martillo/kernel/linux-2.4.6*
193
194
195
196Then make sure that linux-2.4.x/include/asm-i386 is symbolically linked to
197linux-2.4.x/include/asm.
198
199
200
201Execute the following emacs command.
202
203
204
205
206          M-x compile
207
208
209
210This command prompts for targets.
211
212
213
214In the development environment the most useful target string was usually
215/clean xconfig dep bzImage modules./ The target /xconfig /brings up a
216configuration window.  In the basic development environment, it was
217generally worthwhile to add SCSI CD ROM, SCSI legacy support, an
218Ethernet driver and DOS file system support
219
220
221
222The target/ dep/ creates the dependencies (note that if the kernel tree
223is ever removed, the .depend and .hdepend files must be regenerated).
224The /bzImage /target builds the kernel.  The /modules/ target generates
225all the modules to be dynamically installed in the kernel via the
226*insmod* command.
227
228
229
230After building the kernel, installing the modules in the /lib tree
231requires the execution (as root) of
232
233
234
235make modules_install
236
237
238
239The command *make install* *INSTALL_PATH=/boot* will install the
240compressed kernel image as vmlinuz along with other files in the /boot
241partition.  I preferred to use a shell script with commands like the
242following.
243
244
245
246cp /frolix/home/martillo/kernel/linux-2.4.6/arch/i386/boot/bzImage
247/boot/vmlinuz_246
248
249cp /frolix/home/martillo/kernel/linux-2.4.6/System.map
250/boot/System.map-2.4.6
251
252cp /frolix/home/martillo/kernel/linux-2.4.6/.config /boot/vmlinuz_246.config
253
254cp /frolix/home/martillo/kernel/linux-2.4.6/include/linux/autoconf.h
255/boot/vmlinuz_246.autoconf.h
256
257cp /frolix/home/martillo/kernel/linux-2.4.6/include/linux/version.h
258/boot/vmlinuz_246.version.h
259
260
261
262When the kernel comes from a linux-2.4.3 tree, the obvious substitutions
263of 3 for 6 are required.
264
265
266
267Once all the modules and the kernel image are installed, the next step
268in giving the system the ability to boot with the new linux-2.4.3 or
269linux-2.4.6 kernel image is the modification of the lilo.conf file.
270
271
272
273I added the following directives to the lilo.conf file.
274
275
276
277  image  = /boot/vmlinuz_243
278
279  label  = linux_2.4.3
280
281  root   = /dev/hde7
282
283  optional
284
285
286
287  image  = /boot/vmlinuz_246
288
289  label  = linux_2.4.6
290
291  root   = /dev/hde7
292
293  optional
294
295
296
297In this case /dev/hde7 corresponds to the /boot partition, and the
298options linux_2.4.3 and linux_2.4.6 will be added to the boot menu once
299the *lilo* command has been executed.  In other system setups the disk
300partition that corresponds to /boot might have a different name like
301/dev/hda7.
302
303
304
305Once the new kernel successfully boots, the next step to creating a
306driver development and debugging environment is patching the kernel for
307remote gdb debugging.
308
309
310
311The necessary patch can be obtained from kgdb: Source level debugging of
312linux kernel <http://kgdb.sourceforge.net/downloads.html>.
313
314
315
316Now the kernel can be built again with the extra step of configuring for
317remote gdb support in the kernel configuration menu.
318
319
320
321The following directives should be added to lilo.conf.
322
323
324
325  image  = /boot/vmlinuz_243
326
327  label  = debug243
328
329  append = "gdb gdbttyS=0 gdbbaud=115200"
330
331  root   = /dev/hde7
332
333  optional
334
335
336
337  image  = /boot/vmlinuz_246
338
339  label  = debug246
340
341  append = "gdb gdbttyS=0 gdbbaud=115200"
342
343  root   = /dev/hde7
344
345  optional
346
347
348
349
350      Then lilo can be executed.  On reboot the boot menu will include
351      options for debug243 and debug246.
352
353
354
355To test the patch, select one of the debug options.  Then, on the remote
356gdb host machine execute the following command.
357
358
359
360stty 115200 < /dev/ttyS0
361
362
363
364Start up an *xemacs* process.  Execute the following commands within
365*xemacs.*
366
367
368
369
370          M-x shell
371
372
373
374Then within the shell window execute the following command.
375
376
377
378cd /frolix/home/martillo/kernel/linux-2.4./X/
379
380/ /
381
382Then invoke the remote debugger.
383
384
385
386
387          M-x gdb
388
389
390
391Reply to the file prompt with *vmlinux.*
392
393* *
394
395In the gdb window, execute the following command.
396
397
398
399target remote /dev/ttyS0
400
401
402
403The gdb window should break in gdbstub.c which will be displayed in the
404gdb source window.
405
406
407
408At this point, all the basic gdb remote debugging capabilities are ready
409to use.
410
411
412
413To access the hardware breakpoint capability of the i386 processor, the
414following commands can be loaded directly or from a file with the
415*script* command.
416
417
418
419#Hardware breakpoints in gdb
420
421#
422
423#Using ia-32 hardware breakpoints.
424
425#
426
427#4 hardware breakpoints are available in ia-32 processors. These breakpoints
428
429#do not need code modification. They are set using debug registers.
430
431#
432
433#Each hardware breakpoint can be of one of the
434
435#three types: execution, write, access.
436
437#1. An Execution breakpoint is triggered when code at the breakpoint
438address is
439
440#executed.
441
442#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
443
444#at the breakpoint address is written.
445
446#3. An access breakpoint is triggered when memory location at the breakpoint
447
448#address is either read or written.
449
450#
451
452#As hardware breakpoints are available in limited number, use software
453
454#breakpoints ( br command in gdb ) instead of execution hardware
455breakpoints.
456
457#
458
459#Length of an access or a write breakpoint defines length of the datatype to
460
461#be watched. Length is 1 for char, 2 short , 3 int.
462
463#
464
465#For placing execution, write and access breakpoints, use commands
466
467#hwebrk, hwwbrk, hwabrk
468
469#To remove a breakpoint use hwrmbrk command.
470
471#
472
473#These commands take following types of arguments. For arguments associated
474
475#with each command, use help command.
476
477#1. breakpointno: 0 to 3
478
479#2. length: 1 to 3
480
481#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
482
483#
484
485#Use the command exinfo to find which hardware breakpoint occured.
486
487
488
489
490
491#hwebrk breakpointno address
492
493define hwebrk
494
495        maintenance packet Y$arg0,0,0,$arg1
496
497end
498
499document hwebrk
500
501        hwebrk breakpointno address
502
503        Places a hardware execution breakpoint
504
505end
506
507
508
509#hwwbrk breakpointno length address
510
511define hwwbrk
512
513        maintenance packet Y$arg0,1,$arg1,$arg2
514
515end
516
517document hwwbrk
518
519        hwwbrk breakpointno length address
520
521        Places a hardware write breakpoint
522
523end
524
525
526
527#hwabrk breakpointno length address
528
529define hwabrk
530
531        maintenance packet Y$arg0,1,$arg1,$arg2
532
533end
534
535document hwabrk
536
537        hwabrk breakpointno length address
538
539        Places a hardware access breakpoint
540
541end
542
543
544
545#hwrmbrk breakpointno
546
547define hwrmbrk
548
549        maintenance packet y$arg0
550
551end
552
553document hwrmbrk
554
555        hwrmbrk breakpointno
556
557        Removes a hardware breakpoint
558
559end
560
561
562
563#exinfo
564
565define exinfo
566
567        maintenance packet qE
568
569end
570
571document exinfo
572
573        exinfo
574
575        Gives information about a breakpoint.
576
577end
578
579
580
581Once the above macros are define, the developer can set hardware
582breakpoints.
583
584
585
586The next step to creating a useful development and debugging environment
587is to provide a shell script to for remote debugging of dynamically
588loaded modules.  The following shell script (called *loadmodule.sh*)
589creates a gdb script called *load/ModuleName/* in
590/frolix/home/martillo/kernel/linux-2.4.6 when it is invoked (as root)
591with the following command.
592
593loadmodule.sh modulename
594
595
596
597In order to decrease the probability of confusion, I usually make a link
598in kernel root directory,  /frolix/home/martillo/kernel/linux-2.4.6, to
599the location of the module to be debugged in the kernel tree.  The above
600command is invoked on the target machine (ylith) in the root directory.
601On the remote debug machine, in the gdb command window, whose working
602directory should be the kernel root directory,
603/frolix/home/martillo/kernel/linux-2.4.6, the command, *script
604load/ModuleName/*, is invoked.  Once the script is executed the symbols
605for the module are available for remote symbolic debugging.
606
607
608
609#!/bin/sh
610
611# This script loads a module on a target machine and generates a gdb script.
612
613# source generated gdb script to load the module file at appropriate
614addresses
615
616# in gdb.
617
618#
619
620# Usage:
621
622# Loading the module on target machine and generating gdb script)
623
624#       [foo]$ loadmodule.sh <modulename>
625
626#
627
628# Loading the module file into gdb
629
630#       (gdb) source <gdbscriptpath>
631
632#
633
634# Modify following variables according to your setup.
635
636#       TESTMACHINE - Name of the target machine
637
638#       GDBSCRIPTS - The directory where a gdb script will be generated
639
640#
641
642# Author: Amit S. Kale (akale@veritas.com).
643
644#
645
646# If you run into problems, please check files pointed to by following
647
648# variables.
649
650#       ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
651
652#       MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
653
654#       GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
655
656
657
658TESTMACHINE=ylith
659
660GDBSCRIPTS=/frolix/home/martillo/kernel/linux-2.4.6
661
662
663
664if [ $# -lt 1 ] ; then {
665
666        echo Usage: $0 modulefile
667
668        exit
669
670} ; fi
671
672
673
674MODULEFILE=$1
675
676MODULEFILEBASENAME=`basename $1`
677
678
679
680if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
681
682        MODULEFILE=`pwd`/$MODULEFILE
683
684} fi
685
686
687
688ERRFILE=/tmp/$MODULEFILEBASENAME.errs
689
690MAPFILE=/tmp/$MODULEFILEBASENAME.map
691
692GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
693
694
695
696function findaddr() {
697
698        local ADDR=0x$(echo "$SEGMENTS" | \
699
700                grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
701
702                sed 's/[ ]*[^ ]*$//')
703
704        echo $ADDR
705
706}
707
708
709
710function checkerrs() {
711
712        if [ "`cat $ERRFILE`" != "" ] ; then {
713
714                cat $ERRFILE
715
716        } fi
717
718}
719
720
721
722#load the module
723
724#echo Copying $MODULEFILE to $TESTMACHINE
725
726#*rcp $MODULEFILE root@${TESTMACHINE}:
727
728
729
730echo Loading module $MODULEFILE
731
732#rsh -l root $TESTMACHINE  /sbin/insmod -m ./`basename $MODULEFILE` \
733
734#       > $MAPFILE 2> $ERRFILE &
735
736/sbin/insmod -m ./`basename $MODULEFILE` $2 . .  > $MAPFILE 2> $ERRFILE &
737
738sleep 5
739
740checkerrs
741
742
743
744NUMLINES=`grep -n '^$' $MAPFILE | sed -e 's/:.*//g'`
745
746SEGMENTS=`head -n $NUMLINES $MAPFILE | tail -n $(eval expr $NUMLINES - 1)`
747
748TEXTADDR=$(findaddr "\\.text[^.]")
749
750LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
751
752SEGADDRS=`echo "$SEGMENTS" | awk '//{
753
754        if ($1 != ".text" && $1 != ".this" &&
755
756            $1 != ".kstrtab" && $1 != ".kmodtab") {
757
758                print " -s " $1 " 0x" $3 " "
759
760        }
761
762}'`
763
764LOADSTRING="$LOADSTRING $SEGADDRS"
765
766echo Generating script $GDBSCRIPT
767
768echo $LOADSTRING > $GDBSCRIPT
769
770
771
772With the addition of the above shell script, the driver development and
773debugging environment is almost complete.  Other useful tools for
774developing and debugging this type of serial driver would include a
775Wanalyzer (I used an Interview 7700 and an HP 4952A in developing this
776driver), a breakout box that displays interface signal states and  (for
777developing the serial Ethernet-like network driver) several WAN LAN VLAN
778routers as described in *Packet Switching Software and Platforms
779<http://members.aol.com/Telford001/vrouter2g.html>*, *Routing in a
780Bridged Network <http://members.aol.com/Telford001/routetti2.html>, **A
781WAN SUBSYSTEM for a High Performance Packet Switch
782<http://members.aol.com/Keleustes/syncdob.html>* and *A New High
783Performance Architecture for Routers, Bridges and LAN Switches (Software
784Defined Internetworking)
785<http://members.aol.com/Ishtar7713/private/sdi4.html>.*
786
787
788
789
790  _Integration into the Kernel Sources_
791
792
793
794
795The driver has its own directory, {kernel root
796directory}/drivers/net/wan/8253x, in the 2.4.* kernel source tree.
797
798
799
800To facilitate the automatic build of the 8253x driver, the following
801standard kernel files were modified.
802
803
804
8051.                  {kernel root directory}/drivers/net/wan/Config.in to
806which the line
807
808
809
810tristate '  Aurora Technology, Inc. synchronous asynchronous PCI cards
811V2' CONFIG_ATI_XX20
812
813
814
815
816was added,
817
8182.                  {kernel root directory}/drivers/net/wan/Makefile to
819which the following lines were added,
820
821
822
823subdir-$(CONFIG_ATI_XX20) += 8253x
824
825
826
827ifeq ($(CONFIG_ATI_XX20),y)
828
829  obj-y += 8253x/ASLX.o
830
831endif
832
833
834
835When the driver is built as a dynamically loaded module, the following
836macro commands in the file 8253xini.c puts the module entry points in
837the special module entry point segment.
838
839
840
841module_init(auraXX20_probe);
842
843module_exit(auraXX20_cleanup);
844
845
846
847The sources are provided to the users in a patch file, tentatively named
8488253x.patch <http://www.telfordtools.com/sab8253x/8253x.patch>.
849
850
851
852To install it the user sets his directory to the top level of the kernel
853sources and executes the following command.
854
855
856
857patch ^�p1 < /{directory-patch}//8253x.patch
858
859
860
861
862
863  _File Structure of the ASLX Driver Source Code_
864
865
866
867The following files are present in the driver directory.
868
869
870
8718253x.h
872
8738253xdbg.c
874
8758253xmac.c
876
8778253xsyn.c
878
879PciRegs.h
880
881crc32.h
882
883sp502.h
884
8858253xcfg.c
886
8878253xini.c
888
8898253xnet.c
890
8918253xtty.c
892
893Reg9050.h
894
895crc32dcl.h
896
897ring.h
898
8998253xctl.h
900
9018253xioc.h
902
9038253xplx.c
904
9058253xint.c
906
907crc32.c
908
909endian.h
910
911Makefile
912
913Amcc5920.c
914
9158253xmcs.h
916
9178253xmcs.c
918
9198253xchr.c
920
9218253xutl.c
922
923
924
925
926
927
928
929The source code is divided functionally among the files of the ASLX driver.
930
931
932
9338253xcfg.c is the source for a user application that configures 8253x
934control registers to provide clocking.  8253xmac.c is the source for a
935user application that sets a pseudo-MAC address for the network driver.
936
937
938
9398253xini.c contains the initialization/probe logic.
940
941
942
9438253xint.c contains the common interrupt logic.
944
945
946
9478253xtty.c contains the asynchronous TTY logic.
948
949
950
9518253xsyn.c contains the synchronous TTY logic.
952
953
954
9558253xnet.c contains the network driver logic.
956
957
958
9598253xchr.c contains the character driver logic.
960
961
962
963
9648253xdbg.c contains some debugging functions.
965
966
967
9688253xutl.c contains most of the functions that are common among the
969different driver functional subunits.
970
971
972
9738253xplx.c contains some functions specific to the PLX9050 (a PCI bridge
974chip) and specifically to reading and reprogramming the associated
975serial EEPROM.
976
977
978
979amcc5920.c contains some functions specific to the AMCC5920 (a PCI
980bridge chip) and specifically to reading and reprogramming the
981associated serial EEPROM.
982
983
984
9858253xmcs.c contains functions specific to programming the multichannel
986server (mostly G-LINK related logic, programming the sp502 driver chip
987and reading or programming the serial EEPROM associated with the
988interface cards contained within the MCS unit).
989
990
991
992crc32.c contains logic to append a CRC32 to a pseudo MAC frame that is
993generated by the network driver.
994
995
996
9978253x.h contains symbols, structures and macros that relate mostly to
998the 8253x chips and ports.
999
1000
1001
10028253xctl.h contains symbols, structures and macros that relate mostly to
1003the adapter cards.
1004
1005
1006
10078253xmcs.h contains symbols and structures that relate mostly to the
1008multichannel server.  A lot of this file relates to G-LINK.
1009
1010
1011
1012sp502.h contains symbols and structures that relate to the programming
1013of the hardware interface line drivers of the 3500 adapter cards of the
1014multichannel server.
1015
1016
1017
10188253xioc.h contains symbols and structures that relate to private ioctls.
1019
1020
1021
1022PciRegs.h contains symbols and structures that relate to PCI
1023configuration space.
1024
1025
1026
1027Reg9050.h contains symbols and structures that relate to the PLX9050 PCI
1028interface chip and its serial eprom
1029
1030
1031
1032crc32.h, crc32dcl.h and .endian.h contain symbols, structures and macros
1033that relate to generating a correct CRC32.
1034
1035
1036
1037ring.h contains symbols and structures that relate to the network driver
1038frame transmission ring and frame reception.
1039
1040
1041
1042The Makefile is a standard Linux kernel Makefile whose structure is
1043dictated by the current Linux build formalism.
1044
1045
1046
1047
1048  _Using the ASLX Driver _
1049
1050
1051
1052
1053
1054  The ASLX driver is designed to be a ^�plug-and-play^� driver as far as
1055  possible.  If it is built as a dynamically loadable module, the user
1056  (or relevant system configuration file) invokes /insmod /to load the
1057  ASLX.o file.
1058
1059
1060
1061The following parameters can be set on the /insmod/ command line.
1062
1063
1064
1065MODULE_PARM(xx20_minorstart, "i");/*when statically linked autodected
1066otherwise 128 by default*/
1067
1068MODULE_PARM(sab8253xc_major, "i");/*major dev for character device, by
1069default dynamic */
1070
1071MODULE_PARM(auraXX20n_debug, "i");/*turns on debugging messages, default
1072off*/
1073
1074MODULE_PARM(auraXX20n_name, "s"); /*base network driver name = 8253x000*/
1075
1076MODULE_PARM(sab8253xn_listsize, "i"); /*transmit ring size default 32*/
1077
1078MODULE_PARM(sab8253xc_name, "s");/*registered name for char driver =
1079sab8253xc*/
1080
1081MODULE_PARM(sab8253x_default_sp502_mode, "i");
1082
1083
1084
1085
1086  The asynchronous TTY functionality can immediately be used without
1087  extra configuration.  [Note that immediate use of the WMS3500 products
1088  is possible because the default value of sab8253x_default_sp502_mode
1089  is SP502_RS232_MODE (== 1).  If a different default mode is needed, it
1090  can be set as options in the /etc/modules.conf file.  OFF = 0.
1091
1092RS232 = 1, RS422 = 2, RS485 = 3, RS449 = 4, EIA530 = 5 and V.35 = 6, as
1093defined in 8253xioc.h.]
1094
1095
1096
1097The MAKETERMS script below parses the /proc/tty/driver/auraserial file
1098to make the asynchronous TTY device files in the /dev directory.
1099
1100
1101
1102TTYDEV=$1
1103
1104MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e
1105'/[a-zA-Z]/d' | sed -e 's/://'`
1106
1107
1108
1109for i in $MDEVS
1110
1111do
1112
1113        TTYNAME=/dev/ttyS${TTYDEV}
1114
1115        mknod $TTYNAME c 4 $i
1116
1117        TTYDEV=$((${TTYDEV}+1))
1118
1119done
1120
1121
1122
1123The MAKEPROTO script below provides a prototype to modify the
1124/etc/inittab file so that an agetty process can be spawned on every
1125other /dev/ttyS* at 9600 bps
1126
1127
1128
1129TTYDEV=$1
1130
1131MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e
1132'/[a-zA-Z]/d' | sed -e 's/://'`
1133
1134LEADCHAR=""
1135
1136
1137
1138for i in $MDEVS
1139
1140do
1141
1142        NAME=S${TTYDEV}
1143
1144        TTYNAME=ttyS${TTYDEV}
1145
1146        echo ${LEADCHAR}${NAME}:35:respawn:/sbin/agetty 9600 ${TTYNAME}
1147
1148        TTYDEV=$((${TTYDEV}+1))
1149
1150        if [ -z "$LEADCHAR" ]
1151
1152        then
1153
1154                LEADCHAR="#"
1155
1156        else
1157
1158                LEADCHAR=""
1159
1160        fi
1161
1162done
1163
1164
1165
1166
1167  If loopback cables are connected between successive TTY ports on each
1168  Aurora adapter card or unit, the command
1169
1170
1171
1172cu ^�l /dev/ttyS{n} ^�s 9600
1173
1174
1175
1176would connect to the login that was spawned on /dev/ttyS{n-1}.
1177
1178
1179
1180The script MAKESTERMS (viz below) creates synchronous TTY dev files for
1181all the Aurora serial ports.
1182
1183
1184
1185TTYDEV=$1
1186
1187MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e
1188'/[a-zA-Z]/d' | sed -e 's/://'`
1189
1190
1191
1192for i in $MDEVS
1193
1194do
1195
1196        TTYNAME=/dev/sttyS${TTYDEV}
1197
1198        mknod $TTYNAME c 5 $i
1199
1200        TTYDEV=$((${TTYDEV}+1))
1201
1202done
1203
1204
1205
1206The MAKESPROTO script below creates a prototype with which to modify the
1207/etc/inittab file to spawn an agetty process on every other
1208/dev/sttyS{N} device.
1209
1210
1211
1212TTYDEV=$1
1213
1214MDEVS=`cat /proc/tty/driver/auraserial | gawk '{print $1}' | sed -e
1215'/[a-zA-Z]/d' | sed -e 's/://'`
1216
1217LEADCHAR=""
1218
1219
1220
1221for i in $MDEVS
1222
1223do
1224
1225        NAME=sS${TTYDEV}
1226
1227        TTYNAME=sttyS${TTYDEV}
1228
1229        echo ${LEADCHAR}${NAME}:35:respawn:/sbin/agetty 9600 ${TTYNAME}
1230
1231        TTYDEV=$((${TTYDEV}+1))
1232
1233        if [ -z "$LEADCHAR" ]
1234
1235        then
1236
1237                LEADCHAR="#"
1238
1239        else
1240
1241                LEADCHAR=""
1242
1243        fi
1244
1245done
1246
1247
1248
1249
1250  The simplest way to use these terminals with the agetty process that
1251  comes with the Linux distribution is to leave externally clocked (the
1252  default) the terminals on which agetty has been spawned.
1253
1254
1255
1256The loopback cable can be connected to a port on which agetty is not
1257being run.  The clockside of the cable is connected to this port.  The
1258user can run the MAKECLOCKING script below.
1259
1260
1261
1262echo 8253xcfg $1 -n 64 158 56 4 192 140 15
1263
12648253xcfg $1 -n 64 158 56 4 192 140 15
1265
1266
1267
1268The numbers on the 8253xcfg command line are new (decimal) values for
1269the channel control, mode and baud rate registers.  The file 8253xioc.h
1270and sab8253x manuals from Siemens/Infineon can assist in explaining the
1271reasoning behind these values. The 8253xcfg sets the mode, channel
1272control and baudrate generator registers of the port specified by
1273/dev/sttyS{N-1} which is the argument $1 of this script file.  8253xcfg
1274is a simple example program that is included with the driver sources.
1275It is described in the next section of this document.
1276
1277
1278
1279At this point, the user could execute the following command to connect
1280synchronously to the peer synchronous TTY port.
1281
1282
1283
1284cu ^�l /dev/sttyS{n} ^�s 9600
1285
1286
1287
1288To turn off internal clocking use the following command.
1289
1290
1291
12928253xcfg /dev/sttyS? ^�n 64 152 0 4 0 140 15
1293
1294
1295
1296To use an ASLX network device the following commands would be used.
1297
1298
1299
1300*MAKECLOCKING /dev/sttyS*/{N} [if the interface is to provide clock]/
1301
1302*stty */{speed} /*< /dev/sttyS*/{N} [if the interface is to provide clock]/
1303
1304
1305
1306To set the MAC address, which defaults to 00:00:00:00:00:00 and which
1307consequently must be changed, use the following command.
1308
1309
1310
1311*ifconfig 8253x*/{mdev} /*hw ether*/ {mac address} [as root]/
1312
1313
1314
1315[Note that the 8253x{mdev} interface must not be running when the above
1316command is executed.]
1317
1318
1319
1320To set the IP address, use the command.
1321
1322/ /
1323
1324*ifconfig 8253x*/{mdev} {ipadress} [as root]/
1325
1326
1327
1328[Note that the two ifconfig commands can be combined on one line.  If
1329they are executed separately the MAC address command must be executed
1330before the IP address command.]
1331
1332
1333
1334After the completion of the above commands, assuming there is an active
1335network peer that uses the same serial Ethernet frame structure, it
1336should be possible to ping or telnet to the peer networking device.
1337
1338
1339
1340{mdev} is the minor device number (in decimal, 3 digits including
1341leading 0s required) associated with /dev/sttyS{N}.//
1342
1343* *
1344
1345To disable the network interface use the following command.
1346
1347
1348
1349*ifconfig 8253x*/{mdev} /*down*/ [as root]/
1350
1351
1352
1353If there is a need to disable clocking on a serial port, the
1354MAKENONCLOCKING shell script is invoked with the TTY device as an
1355argument as follows.
1356
1357
1358
1359MAKENONCLOCKING /dev/ttyS{N}
1360
1361
1362
1363The shell script contains the following commands.
1364
1365
1366
1367echo 8253xcfg $1 -n 64 152 0 4 192 140 255
1368
13698253xcfg $1 -n 64 152 0 4 192 140 255
1370
1371
1372
1373The numbers on the 8253xcfg command line are new (decimal) values for
1374the channel control, mode and baud rate registers.  The file 8253xioc.h
1375and sab8253x manuals from Siemens/Infineon can assist in explaining the
1376reasoning behind these values. The 8253xcfg sets the mode, channel
1377control and baudrate generator registers of the port specified by
1378/dev/sttyS{N-1} which is the argument $1 of this script file.  8253xcfg
1379is a simple example program that is included with the driver sources.
1380It is described in the next section of this document.
1381
1382
1383
1384
1385
1386  _Simple Tools and Example Programs_
1387
1388
1389
1390The tools and example programs supplied with the SAB8253X ASLX driver
1391are the following.
1392
13931.      eprom9050
1394
13952.      8253xcfg
1396
13973.      8253xspeed
1398
13994.      8253xpeer
1400
14015.      8253xmode
1402
1403
1404    eprom9050
1405
1406
1407
1408This program performs the bit-banging necessary to read and to program
1409the serial eprom of the PLX9050.
1410
1411
1412
1413To access the serial eprom on an adapter card the program opens up a TTY
1414device on   the adapter card, whose serial eprom is to be modified.
1415This TTY device can either be synchronous, asynchronous or callout.  The
1416TTY device is passed as an argument when the program is invoked.
1417
1418
1419
1420The program uses the ATIS_IOCGSEP9050 IOCTL to get the current serial
1421eprom values and the ATIS_IOCSSEP9050 IOCTL to set the new serial eprom
1422values.
1423
1424
1425
1426Here is the source code of the program.
1427
1428
1429
1430/*
1431
1432 * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
1433
1434 *
1435
1436 * This program is free software; you can redistribute it and/or
1437
1438 * modify it under the terms of the GNU General Public License
1439
1440 * as published by the Free Software Foundation; either version
1441
1442 * 2 of the License, or (at your option) any later version.
1443
1444 *
1445
1446 **/
1447
1448
1449
1450#include <sys/types.h>
1451
1452#include <sys/stat.h>
1453
1454#include <fcntl.h>
1455
1456#include <stdio.h>
1457
1458#include <stdlib.h>
1459
1460#include "8253xioc.h"
1461
1462#include "Reg9050.h"
1463
1464
1465
1466
1467
1468                                /* This application shows how to load the */
1469
1470                                /* channel control, mode and rx frame
1471length */
1472
1473                                /* check registers via an ioctl.*/
1474
1475
1476
1477int main(int argc, char **argv)
1478
1479{
1480
1481  int fd;
1482
1483  unsigned short oldeeprom[EPROM9050_SIZE], neweeprom[EPROM9050_SIZE];
1484
1485  char buffer[200];
1486
1487  int count;
1488
1489  int value;
1490
1491  unsigned short *pointer;
1492
1493  unsigned short *pointerold;
1494
1495  int noprompt = 0;
1496
1497  int epromindex;
1498
1499
1500
1501  if(argc < 2)
1502
1503    {
1504
1505      fprintf(stderr, "Syntax: %s {portname} [-n] {prom values}.\n", *argv);
1506
1507      exit(-1);
1508
1509    }
1510
1511  fd = open(argv[1], O_RDWR);
1512
1513  if(fd < 0)
1514
1515    {
1516
1517      perror("open failed.");
1518
1519      exit(-2);
1520
1521    }
1522
1523
1524
1525  if((argc > 2) && !strcmp("-n", argv[2]))
1526
1527    {
1528
1529      noprompt = 1;
1530
1531    }
1532
1533
1534
1535                                /* get the current values */
1536
1537  if(ioctl(fd, ATIS_IOCGSEP9050, &oldeeprom) < 0)
1538
1539    {
1540
1541      perror("ioctl failed.");
1542
1543      exit(-3);
1544
1545    }
1546
1547                                /* set up the existing values as defaults */
1548
1549  memcpy(neweeprom, oldeeprom, sizeof(oldeeprom));
1550
1551                                /* gather all new values from the
1552command line */
1553
1554                                /* or via tty input.*/
1555
1556  for(count = (2+noprompt), pointer = neweeprom; count < argc; ++count,
1557++pointer)
1558
1559    {
1560
1561      *pointer = atoi(argv[count]);
1562
1563    }
1564
1565  pointer = neweeprom;
1566
1567  pointerold = oldeeprom;
1568
1569  for(epromindex = 0; epromindex < EPROM9050_SIZE; ++epromindex)
1570
1571    {
1572
1573      fprintf(stderr, "LOCATION %i [%4.4x/%4.4x]: ", epromindex,
1574*pointerold, *pointer);
1575
1576
1577
1578      if(!noprompt)
1579
1580        {
1581
1582          if(count = read(0, buffer, 150), count <= 0)
1583
1584            {
1585
1586              exit(0);
1587
1588            }
1589
1590          buffer[count] = '\0';
1591
1592          if(buffer[0] != '\n')
1593
1594            {
1595
1596              sscanf(buffer, "%x", &value);
1597
1598              *pointer = (unsigned short) value;
1599
1600            }
1601
1602        }
1603
1604      else
1605
1606        {
1607
1608          fprintf(stderr, "\n");
1609
1610        }
1611
1612      ++pointerold;
1613
1614      ++pointer;
1615
1616    }
1617
1618                                /* This ioctl does the actual register
1619load. */
1620
1621  if(ioctl(fd, ATIS_IOCSSEP9050, neweeprom) < 0)
1622
1623    {
1624
1625      perror("ioctl failed.");
1626
1627      exit(-3);
1628
1629    }
1630
1631
1632
1633  fflush(stdout);
1634
1635}
1636
1637
1638
1639With the above program it is possible to change PCI vendor and device ID
1640values of the adapter card.  At that point the card would no longer be
1641visible to the driver.  To correct the vendor and device IDs use the
1642*lspci* Linux command to find out what new values are and recompile the
1643driver code after modifying the symbols that correspond to the correct
1644vendor and device Ids of the card to the new values.  (I should make the
1645vendor and device IDs module parameters that can be set from the
1646*insmod* command line.)  The eprom9050 can be invoked to write the
1647device and vendor IDs to the correct values.  Of course, then the card
1648will no longer be visible to the new version of the driver, and the
1649original version of the driver must be used to communicate with this card.
1650
1651
1652
1653
1654    8253xcfg
1655
1656
1657
1658The 8253xcfg command provides access to images of the channel control,
1659mode and baud rate generator registers of the serial port that is
1660specified by the minor device number (port number = minor device number
1661^� minor_start) of the TTY device (either synchronous, asynchronous or
1662callout) specified on the command line by which 8253xcfg is invoked.
1663The next time the port is initialized (usually on the first open after
1664every process that currently has the port open has closed it) these
1665registers are set with the values of their images.  The 8253xcfg command
1666can make a synchronous port clocking or non-clocking.  Note that even
1667though 8253xcfg operates on a TTY device, the open that finally sets the
1668registers with the values from the images can be either a synchronous
1669TTY, a network device or a synchronous character device open.  The
1670program uses the ATIS_IOCGPARAMS IOCTL to get the current values of the
1671images of the registers and employs the ATIS_IOCSPARAMS IOCTL to set the
1672current values of the images of the registers.  Here is the source of
1673the 8253xcfg program.
1674
1675
1676
1677/*
1678
1679 * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
1680
1681 *
1682
1683 * This program is free software; you can redistribute it and/or
1684
1685 * modify it under the terms of the GNU General Public License
1686
1687 * as published by the Free Software Foundation; either version
1688
1689 * 2 of the License, or (at your option) any later version.
1690
1691 *
1692
1693 **/
1694
1695
1696
1697#include <sys/types.h>
1698
1699#include <sys/stat.h>
1700
1701#include <fcntl.h>
1702
1703#include <stdio.h>
1704
1705#include <stdlib.h>
1706
1707#include "8253xioc.h"
1708
1709
1710
1711char *prompts[] =
1712
1713  {
1714
1715    "ccr0",
1716
1717    "ccr1",
1718
1719    "ccr2",
1720
1721    "ccr3",
1722
1723    "ccr4",
1724
1725    "mode",
1726
1727    "rlcr",
1728
1729    0
1730
1731  };
1732
1733
1734
1735                                /* This application shows how to load the */
1736
1737                                /* channel control, mode and rx frame
1738length */
1739
1740                                /* check registers via an ioctl.*/
1741
1742
1743
1744int main(int argc, char **argv)
1745
1746{
1747
1748  int fd;
1749
1750  struct channelcontrol ccontrolold, ccontrolnew;
1751
1752  char buffer[200];
1753
1754  int count;
1755
1756  int value;
1757
1758  unsigned char *pointer;
1759
1760  unsigned char *pointerold;
1761
1762  char **promptpointer = prompts;
1763
1764  int noprompt = 0;
1765
1766
1767
1768  if(argc < 2)
1769
1770    {
1771
1772      fprintf(stderr, "Syntax: %s {portname} [-n] [ccr0 [ccr1 [ccr2
1773[ccr3 [ccr4 [mode [rlcr]]]]]]].\n", *argv);
1774
1775      exit(-1);
1776
1777    }
1778
1779  fd = open(argv[1], O_RDWR);
1780
1781  if(fd < 0)
1782
1783    {
1784
1785      perror("open failed.");
1786
1787      exit(-2);
1788
1789    }
1790
1791
1792
1793  if((argc > 2) && !strcmp("-n", argv[2]))
1794
1795    {
1796
1797      noprompt = 1;
1798
1799    }
1800
1801
1802
1803                                /* get the current values */
1804
1805  if(ioctl(fd, ATIS_IOCGPARAMS, &ccontrolold) < 0)
1806
1807    {
1808
1809      perror("ioctl failed.");
1810
1811      exit(-3);
1812
1813    }
1814
1815                                /* set up the existing values as defaults */
1816
1817  ccontrolnew = ccontrolold;
1818
1819
1820
1821                                /* gather all new values from the
1822command line */
1823
1824                                /* or via tty input.*/
1825
1826  for(count = (2+noprompt), pointer = (unsigned char*) &ccontrolnew;
1827count < argc; ++count, ++pointer)
1828
1829    {
1830
1831      *pointer = atoi(argv[count]);
1832
1833    }
1834
1835  pointer = (unsigned char*) &ccontrolnew;
1836
1837  pointerold = (unsigned char*) &ccontrolold;
1838
1839  while(*promptpointer)
1840
1841    {
1842
1843      fprintf(stderr, "%s [%2.2x/%2.2x]: ",*promptpointer, *pointerold,
1844*pointer);
1845
1846
1847
1848      if(!noprompt)
1849
1850        {
1851
1852          if(count = read(0, buffer, 150), count <= 0)
1853
1854            {
1855
1856              exit(0);
1857
1858            }
1859
1860          buffer[count] = '\0';
1861
1862          if(buffer[0] != '\n')
1863
1864            {
1865
1866              sscanf(buffer, "%x", &value);
1867
1868              *pointer = (unsigned char) value;
1869
1870            }
1871
1872        }
1873
1874      else
1875
1876        {
1877
1878          fprintf(stderr, "\n");
1879
1880        }
1881
1882      ++pointerold;
1883
1884      ++pointer;
1885
1886      ++promptpointer;
1887
1888    }
1889
1890                                /* This ioctl does the actual register
1891load. */
1892
1893  if(ioctl(fd, ATIS_IOCSPARAMS, &ccontrolnew) < 0)
1894
1895    {
1896
1897      perror("ioctl failed.");
1898
1899      exit(-3);
1900
1901    }
1902
1903
1904
1905  fflush(stdout);
1906
1907}
1908
1909
1910
1911
1912
1913
1914    8253xspeed
1915
1916
1917
1918This program sets the custom baud rate of a serial port.  If the custom
1919baud rate of a serial port is non-zero, and if the standard baud rate
1920has been set to 38,400 bps, the next time the port is initialized, the
1921port will run at the custom baud rate.  If the custom baud rate were 0,
1922the port would run at the standard baud rate.   The 8352xpeed program is
1923invoked with a TTY device (either asynchronous, synchronous or callout),
1924but the effect also applies to the network device and the synchronous
1925character device that correspond to the same physical serial port.
1926
1927
1928
1929Here is the source code for the 8253xspeed.
1930
1931
1932
1933/*
1934
1935 * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
1936
1937 *
1938
1939 * This program is free software; you can redistribute it and/or
1940
1941 * modify it under the terms of the GNU General Public License
1942
1943 * as published by the Free Software Foundation; either version
1944
1945 * 2 of the License, or (at your option) any later version.
1946
1947 *
1948
1949 **/
1950
1951
1952
1953#include <sys/types.h>
1954
1955#include <sys/stat.h>
1956
1957#include <fcntl.h>
1958
1959#include <stdio.h>
1960
1961#include <stdlib.h>
1962
1963#include "8253xioc.h"
1964
1965
1966
1967
1968
1969int main(int argc, char **argv)
1970
1971{
1972
1973  int fd;
1974
1975  unsigned long oldspeed, newspeed;
1976
1977  char buffer[200];
1978
1979  int count;
1980
1981  long value;
1982
1983  int noprompt = 0;
1984
1985  int epromindex;
1986
1987
1988
1989  if(argc < 2)
1990
1991    {
1992
1993      fprintf(stderr, "Syntax: %s {portname} [-n] {new speed}.\n", *argv);
1994
1995      exit(-1);
1996
1997    }
1998
1999  fd = open(argv[1], O_RDWR);
2000
2001  if(fd < 0)
2002
2003    {
2004
2005      perror("open failed.");
2006
2007      exit(-2);
2008
2009    }
2010
2011
2012
2013  if((argc > 2) && !strcmp("-n", argv[2]))
2014
2015    {
2016
2017      noprompt = 1;
2018
2019    }
2020
2021
2022
2023
2024/* get the current values */
2025
2026  if(ioctl(fd, ATIS_IOCGSPEED, &oldspeed) < 0)
2027
2028    {
2029
2030      perror("ioctl failed.");
2031
2032      exit(-3);
2033
2034    }
2035
2036
2037/* set up the existing values as defaults */
2038
2039  newspeed = oldspeed;
2040
2041
2042/* gather all new values from the command line */
2043
2044
2045/* or via tty input.*/
2046
2047  if(argc == (noprompt + 3))
2048
2049    {
2050
2051      newspeed = atoi(argv[count]);
2052
2053    }
2054
2055
2056
2057  fprintf(stderr, "speed [%ld/%ld]: ", oldspeed, newspeed);
2058
2059
2060
2061  if(!noprompt)
2062
2063    {
2064
2065      if(count = read(0, buffer, 150), count <= 0)
2066
2067
2068{
2069
2070
2071  exit(0);
2072
2073
2074}
2075
2076      buffer[count] = '\0';
2077
2078      if(buffer[0] != '\n')
2079
2080
2081{
2082
2083
2084  sscanf(buffer, "%ld", &newspeed);
2085
2086
2087}
2088
2089    }
2090
2091  else
2092
2093    {
2094
2095      fprintf(stderr, "\n");
2096
2097    }
2098
2099
2100
2101
2102/* This ioctl does the actual register load. */
2103
2104  if(ioctl(fd, ATIS_IOCSSPEED, &newspeed) < 0)
2105
2106    {
2107
2108      perror("ioctl failed.");
2109
2110      exit(-3);
2111
2112    }
2113
2114
2115
2116  fflush(stdout);
2117
2118}
2119
2120
2121
2122The ATIS_IOCGSPEED gets the value the custom baud rate for a serial port
2123while ATIS_IOCSSPEED sets the value of the custom baud rate for a serial
2124port.
2125
2126
2127
2128
2129
2130
2131    8253xpeer
2132
2133
2134
2135The 8253xpeer example program reads and writes packets to the serial
2136port in synchronous mode.  The synchronous character driver to some
2137extent emulates the getmsg/putmsg functionality found in Solaris.  This
2138driver returns only one packet at a time to read and returns ENOMEM if
2139the receive buffer is not large enough to receive the current packet.
2140The driver assumes that the data from a write is to be packetized into a
2141single packet.  The driver can provide asynchronous notification that
2142there is no more data queued to be transmitted at the serial port.  This
2143asynchronous notification informs the application program that a low
2144priority packet can now be written to the driver.  Such functionality is
2145useful to protocols like LAPB that distinguish low priority information
2146frames from high priority control frames.
2147
2148
2149
2150To try out this program find the major device number associated with the
21518253xc device in the /proc/devices file.  Select two ports to loop
2152together.  Connect them with a synchronous loopback cable.  Then execute
2153the following command for each of the ports.
2154
2155
2156
2157mknod /dev//DevName1/ c /major-dev-num minor-dev-num-1/
2158
2159/ /
2160
2161mknod /dev//DevName2/ c /major-dev-num minor-dev-num-2/
2162
2163
2164
2165Minor-dev-num-[1/2] correspond to the selected ports.
2166
2167
2168
2169Select one of the ports to be clocking (the clocking end of the loopback
2170cable should connect to this port) and apply MAKECLOCKING to the
2171corresponding TTY.  Use stty or 8253xspeed and stty to set the speed on
2172the corresponding TTY port.
2173
2174
2175
2176Then in one window run *8253xpeer /dev//DevName1/* and in another window
2177execute *8253xpeer /dev//DevName2./*  It should now be possible to send
2178and receive data in each of the windows.
2179
2180
2181
2182Here is the program source.
2183
2184
2185
2186/*
2187
2188 * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
2189
2190 *
2191
2192 * This program is free software; you can redistribute it and/or
2193
2194 * modify it under the terms of the GNU General Public License
2195
2196 * as published by the Free Software Foundation; either version
2197
2198 * 2 of the License, or (at your option) any later version.
2199
2200 *
2201
2202 **/
2203
2204
2205
2206#include <sys/types.h>
2207
2208#include <sys/stat.h>
2209
2210#include <fcntl.h>
2211
2212#include <stdio.h>
2213
2214#include <stdlib.h>
2215
2216#include "8253xioc.h"
2217
2218#include <sys/poll.h>
2219
2220
2221
2222struct pollfd pollarray[2];
2223
2224
2225
2226
2227
2228char buffer[8192];
2229
2230
2231
2232int main(int argc, char **argv)
2233
2234{
2235
2236  int fd;
2237
2238  int status;
2239
2240  int prompt = 1;
2241
2242  int count;
2243
2244
2245
2246  if(argc != 2)
2247
2248    {
2249
2250      fprintf(stderr, "Syntax: %s {portname}\n", *argv);
2251
2252      exit(-1);
2253
2254    }
2255
2256  fd = open(argv[1], O_RDWR);
2257
2258  if(fd < 0)
2259
2260    {
2261
2262      perror("open failed.");
2263
2264      exit(-2);
2265
2266    }
2267
2268  do
2269
2270    {
2271
2272      if(prompt)
2273
2274        {
2275
2276          printf("Enter data: ");
2277
2278          fflush(stdout);
2279
2280          prompt = 0;
2281
2282        }
2283
2284      pollarray[0].fd = 0;
2285
2286      pollarray[0].events = POLLIN;
2287
2288      pollarray[0].revents = 0;
2289
2290      pollarray[1].fd = fd;
2291
2292      pollarray[1].events = POLLIN|POLLOUT;
2293
2294      pollarray[1].revents = 0;
2295
2296      status = poll(pollarray, 2, 10);
2297
2298      switch(status)
2299
2300        {
2301
2302        case 0:
2303
2304          break;
2305
2306
2307
2308        case 1:
2309
2310        case 2:
2311
2312          if(pollarray[0].revents == POLLIN)
2313
2314            {
2315
2316              if(count = read(0, buffer, 150), count <= 0)
2317
2318                {
2319
2320                  perror("unable to read stdio.\n");
2321
2322                  exit(0);
2323
2324                }
2325
2326              buffer[count] = '\0';
2327
2328              if(count)
2329
2330                {
2331
2332                  if(pollarray[1].revents & POLLOUT)
2333
2334                    {
2335
2336                      if(write(pollarray[1].fd, buffer, count) <= 0)
2337
2338                        {
2339
2340                          perror("unable to write protodevice.\n");
2341
2342                          exit(-1);
2343
2344                        }
2345
2346                    }
2347
2348                  else
2349
2350                    {
2351
2352                      printf("Write of protodevice would block.\n");
2353
2354                      fflush(stdout);
2355
2356                    }
2357
2358                }
2359
2360              prompt = 1;
2361
2362            }
2363
2364          if(pollarray[1].revents & POLLIN)
2365
2366            {
2367
2368              if(count = read(pollarray[1].fd, buffer, 8192), count <= 0)
2369
2370                {
2371
2372                  perror("unable to read protodevice.\n");
2373
2374                  exit(0);
2375
2376                }
2377
2378              buffer[count] = '\0';
2379
2380              printf("\nRead: %s", buffer);
2381
2382              fflush(stdout);
2383
2384              prompt = 1;
2385
2386            }
2387
2388          break;
2389
2390
2391
2392        default:
2393
2394          break;
2395
2396        }
2397
2398    }
2399
2400  while(status >= 0);
2401
2402}
2403
2404
2405
2406
2407
2408
2409    8253xmode
2410
2411
2412
2413The 8253xmode program sets the signaling mode of port on a multichannel
2414server 3500 extension board which has a programmable Sipex sp502
2415physical driver chip for each port.
2416
2417
2418
2419The command syntax is the following
2420
2421
2422
2423*8253xmode* /dev//{dev name} {mode}/
2424
2425
2426
2427where mode is one of the following.
2428
2429    * off
2430    * 232
2431    * 422
2432    * 485
2433    * 530
2434    * v.35
2435
2436
2437
2438Note the minor devices associated with a multiserver increase
2439monotonically starting from the first connector on the upper left corner
2440if you are facing the connector side of the multiserver.  The numbering
2441goes from left to right and top to bottom without gaps  Thus, the
2442numbers on the multiserver itself may not map to the minor device number
2443as port number + minor device number of first port if the multiserver is
2444not fully populated.
2445
2446
2447
2448Here is the source for the 8253xmode program.
2449
2450
2451
2452/* -*- linux-c -*- */
2453
2454/*
2455
2456 * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
2457
2458 *
2459
2460 * This program is free software; you can redistribute it and/or
2461
2462 * modify it under the terms of the GNU General Public License
2463
2464 * as published by the Free Software Foundation; either version
2465
2466 * 2 of the License, or (at your option) any later version.
2467
2468 *
2469
2470 **/
2471
2472
2473
2474#include <sys/types.h>
2475
2476#include <sys/stat.h>
2477
2478#include <fcntl.h>
2479
2480#include <stdio.h>
2481
2482#include <stdlib.h>
2483
2484#include "8253xioc.h"
2485
2486
2487
2488static char *signaling[] =
2489
2490{
2491
2492        "OFF",
2493
2494        "RS232",
2495
2496        "RS422",
2497
2498        "RS485",
2499
2500        "RS449",
2501
2502        "RS530",
2503
2504        "V.35"
2505
2506};
2507
2508
2509
2510                                /* This application shows how to set sigmode
2511
2512                                 * on those devices that support software
2513
2514                                 * programmable signaling. */
2515
2516int main(int argc, char **argv)
2517
2518{
2519
2520        int fd;
2521
2522        unsigned int oldmode, newmode;
2523
2524
2525
2526        if(argc != 3)
2527
2528        {
2529
2530                fprintf(stderr, "Syntax: %s {portname} {new mode}.\n",
2531*argv);
2532
2533                fprintf(stderr, "{new mode} = off | 232 | 422 | 485 |
2534449 | 530 | v.35\n");
2535
2536                exit(-1);
2537
2538        }
2539
2540        fd = open(argv[1], O_RDWR);
2541
2542        if(fd < 0)
2543
2544        {
2545
2546                perror("open failed.");
2547
2548                exit(-2);
2549
2550        }
2551
2552        if(!strcmp("off", argv[2]))
2553
2554        {
2555
2556                newmode = SP502_OFF_MODE;
2557
2558        }
2559
2560        else if(!strcmp("232", argv[2]))
2561
2562        {
2563
2564                newmode = SP502_RS232_MODE;
2565
2566        }
2567
2568        else if(!strcmp("422", argv[2]))
2569
2570        {
2571
2572                newmode = SP502_RS422_MODE;
2573
2574        }
2575
2576        else if(!strcmp("485", argv[2]))
2577
2578        {
2579
2580                newmode = SP502_RS485_MODE;
2581
2582        }
2583
2584        else if(!strcmp("449", argv[2]))
2585
2586        {
2587
2588                newmode = SP502_RS449_MODE;
2589
2590        }
2591
2592        else if(!strcmp("530", argv[2]))
2593
2594        {
2595
2596                newmode = SP502_EIA530_MODE;
2597
2598        }
2599
2600        else if(!strcmp("v.35", argv[2]))
2601
2602        {
2603
2604                newmode = SP502_V35_MODE;
2605
2606        }
2607
2608        else
2609
2610        {
2611
2612                fprintf(stderr, "Unknown mode %s.\n", argv[2]);
2613
2614                fprintf(stderr, "Syntax: %s {portname} {new mode}.\n",
2615*argv);
2616
2617                fprintf(stderr, "{new mode} = off | 232 | 422 | 485 |
2618449 | 530 | v.35\n");
2619
2620                exit(-1);
2621
2622        }
2623
2624
2625
2626        /* get the current values */
2627
2628        if(ioctl(fd, ATIS_IOCGSIGMODE, &oldmode) < 0)
2629
2630        {
2631
2632                perror("ATIS_IOCGSIGMODE ioctl failed.");
2633
2634                exit(-3);
2635
2636        }
2637
2638        fprintf(stderr, "old mode = %s.\n", signaling[oldmode]);
2639
2640
2641
2642        if(ioctl(fd, ATIS_IOCSSIGMODE, &newmode) < 0)
2643
2644        {
2645
2646                perror("ATIS_IOCSSIGMODE ioctl failed.");
2647
2648                exit(-3);
2649
2650        }
2651
2652
2653
2654        /* get the current values */
2655
2656        if(ioctl(fd, ATIS_IOCGSIGMODE, &oldmode) < 0)
2657
2658        {
2659
2660                perror("ATIS_IOCGSIGMODE ioctl failed.");
2661
2662                exit(-3);
2663
2664        }
2665
2666        fprintf(stderr, "new mode = %s.\n", signaling[oldmode]);
2667
2668        fflush(stdout);
2669
2670}
2671
2672
2673
2674The 8253xmode program uses the ATIS_IOCSSIGMODE ioctl to set the new
2675physical signaling mode and employs the ATIS_IOCGSIGMODE ioctl to get
2676the original value and to verify the new mode.
2677
2678
2679
2680
2681  _Logic Structure of the ASLX Driver_
2682
2683
2684
2685
2686  /Data Structure Summary/
2687
2688
2689
2690The key data structures that enable the driver logic are:
2691
2692
2693
26941.      SAB_BOARD structure ^� driver specific
2695
26962.      SAB_CHIP structure ^� driver specific
2697
26983.      SAB_PORT structure ^� driver specific
2699
27004.      AURA_CIM structure ^� driver specific (actually specific to the
2701multichannel server)
2702
27035.      RING_DESCRIPTOR ^� used by all the driver functionalities in the
2704transmission of data.
2705
27066.      DCONTROL2 ^� used by all the driver functionalities in managing
2707the transmission of data.
2708
27097.      struct sk_buff_head ^� two buffer lists are associated with the
2710SAB_PORT structure are used to track all the sk_buffs that are currently
2711in use at each port.
2712
27138.      struct tty_struct ^� one per port, standard structure by which
2714the TTY driver access low level routines for either asynchronous TTY,
2715synchronous TTY and callout functionality.  The SAB_PORT serves as the
2716private data structure associated with each 8253x TTY, which on a given
2717open can instantiate itself as a synchronous TTY, an asynchronous TTY or
2718as a call out device.
2719
27209.      struct net_device ^� one per port, standard network device
2721structure.  The SAB_PORT serves as the private data structure associated
2722with each 8253x network interface.
2723
272410. struct file_operations ^� one per port, standard character device
2725structure.  The SAB_PORT serves as the private data structure associated
2726with each 8253x character interface.
2727
2728
2729
2730Thus the fundamental driver functionalities, the TTY device, the network
2731interface and the character device, share the port structure; and the
2732port structure contains the data is used to arbitrate driver
2733functionality access to a given physical port.  All the above driver
2734specific structures are dynamically allocated at driver initialization.
2735They are maintained on lists (in come cases several lists, e.g., global,
2736per board, by interrupt+by board type and per chip lists).  The global
2737port list is used to map minor device numbers sequentially to ports.
2738The per chip port list is used in interrupt processing.  Likewise the by
2739interrupt+by board type board lists are also used in interrupt processing.
2740
2741
2742
2743The use and definition of the tty_struct (TTY and callout drivers),
2744net_device (network drivers) and file_operations (character drivers)
2745structures are found in the Linux.
2746
2747
2748
2749
2750
2751    Quick Overview of Standard Linux TTY, Network and Character Devices
2752    and Interaction with the ASLX Driver Design
2753
2754
2755
2756The basic design of TTY/callout drivers, network drivers and character
2757drivers is specified by the Linux interface.
2758
2759
2760
2761The TTY driver uses the standard circular transmit buffer as found in
2762serial.c, which handles the PC com ports) while received characters pass
2763into a line disciple via the standard flip buffer logic found in serial.c
2764
2765
2766
2767The network and character driver parts just follow the design described
2768in /Linux Device Drivers/ by Alessandro Rubini.
2769
2770All the driver functionalities use a circular transmit buffer descriptor
2771ring and sk_buffers for receiving and transmitting data.  This uniform
2772approach to transception simplifies the driver logic immensely.
2773
2774
2775
2776There is no use of a transmit done interrupt equivalent (unnecessary for
2777a non-dma design).  The driver can be compiled to free up transmitted
2778sk_buffs in the interrupt handler or in write routines. Investigation
2779shows that the driver performs better when transmitted buffers are freed
2780outside of the interrupt handlers.  The sk_* routines are in general
2781fairly performance costly.  As a further optimization, when sk_buffs are
2782freed in the write routines, if system write gets ahead of the
2783transmitter, the program logic will try to avoid releasing transmitted
2784buffers (in the TTY driver) but will try to reuse them if possible.
2785
2786
2787
2788When data is received, chains of receive buffers are passed back to the
2789character device read routine or to a flush-to-line-discipline function
2790(defined in the ASLX driver to override the default flush_to_ldisc
2791routine defined in tty_io.c) in the case of the TTY driver
2792functionalities. The network driver just invokes the /netif_rx()/
2793routine at interrupt level to receive packets. Currently, the network
2794driver pre-allocates a receive buffer, but such pre-allocation is not
2795necessary, and no other driver functionalities make use of
2796pre-allocation of buffers.
2797
2798
2799    From Standard Driver Architectures to the ASLX Driver
2800
2801
2802
2803The main difficulties to be overcome in the ASLX design fit into two
2804categories.
2805
2806
2807
28081.      No other Linux driver attempts to combine multiple TTY
2809functionalities with network and character driver functionalities.
2810
28112.      Even though the members of this Aurora product line all use
2812basically the same Siemens/Infineon interface chip, the details of
2813accessing this chip differ radically over the product line.  The adapter
2814cards use the PLX 9050 PCI bridge chip while the multichannel servers
2815use the AMCC 5920 PCI bridge chip.  In the latter case there is a
2816somewhat complex G-Link hardware protocol used for communication between
2817the host adapter card and the expansion chassis that hosts the extension
2818boards where the serial interface chips are located.  The adapter cards
2819differ in detecting and causing modem signal changes.
2820
2821
2822
2823
2824  /Creating a Uniform Device Programming Interface/
2825
2826
2827
2828The most painful aspect of  of creating a multifunction driver for the
2829Aurora hardware is the difference of each Aurora adapter card or unit
2830from every other Aurora adapter card or unit.
2831
2832
2833
2834Signals are handled differently on ESCC2 (SAB82532) versus ESCC8
2835(SAB82538) based devices.  Interrupt processing is different on ESCC2,
2836ESCC8 and multichannel server devices.  The multichannel servers use an
2837AMCC bridge chip while the other devices use a PLX bridge chip.
2838Multichannel servers and all other Aurora adapter cards access device
2839registers completely differently.
2840
2841
2842
2843There are a set of data structures and macros that simplify access to
2844control registers for serial ports and that try to provide uniformity in
2845line control signal handling, which is complex because some signals are
2846defined in the serial port interface of the 8253X serial interface chip
2847while other signals are handled through the general parallel ports of
2848the 8253X chip.
2849
2850
2851
2852The bitwise definition of the line control signals differ on the
2853parallel ports of the 82532 and the 82538 based cards (including
2854multichannel server units).
2855
2856
2857
2858The macros (courtesy Francois Wautier) below provide a common interface
2859for raising and lowering control signals as well as for querying them.
2860
2861
2862
2863
2864/*
2865
2866 * Raise a modem signal y on port x, tmpval must exist! */
2867
2868#define RAISE(xx,y) \
2869
2870{ \
2871
2872          unsigned char __tmpval__; \
2873
2874          __tmpval__= (xx)->readbyte((xx),(xx)->y.reg);\
2875
2876          if((xx)->y.inverted)\
2877
2878            __tmpval__ &= ~((xx)->y.mask);\
2879
2880          else\
2881
2882            __tmpval__ |= (xx)->y.mask;\
2883
2884          __tmpval__ |= (xx)->y.cnst;\
2885
2886          (xx)->y.val=1;\
2887
2888          (xx)->writebyte((xx),(xx)->y.reg,__tmpval__);\
2889
2890}
2891
2892/*
2893
2894 * Lower a modem signal y on port x, __tmpval__ must exist! */
2895
2896#define LOWER(xx,y) \
2897
2898{\
2899
2900          unsigned char __tmpval__; \
2901
2902          __tmpval__= (xx)->readbyte((xx),(xx)->y.reg);\
2903
2904          if((xx)->y.inverted)\
2905
2906            __tmpval__ |= (xx)->y.mask;\
2907
2908          else\
2909
2910            __tmpval__ &= ~((xx)->y.mask);\
2911
2912          __tmpval__ |= (xx)->y.cnst;\
2913
2914          (xx)->y.val=0;\
2915
2916          (xx)->writebyte((xx),(xx)->y.reg,__tmpval__);\
2917
2918}
2919
2920
2921
2922#define ISON(xx,y) \
2923
2924          ((xx)->y.inverted !=
2925(((xx)->readbyte((xx),(xx)->y.reg)&(xx)->y.mask)==(xx)->y.mask))
2926
2927
2928
2929The inverted, cnst, and mask fields of the modem signal structure (y)
2930are specific to the type of serial communications controller.  The
2931readbyte and writebyte functions are specific to the different types of
2932Aurora hardware.
2933
2934
2935
2936To hide the details of accessing control and data registers, the
2937SAB_PORT structure has a fields whose values are the functions to read a
2938device register, to write a device register,to  read a device FIFO and
2939to write a device FIFO (as well as to read and to write short words,
2940functions that could be used in implementing the readfifo and writefifo
2941routines).
2942
2943
2944
2945Here is readfifo for non-multichannel server hardware.
2946
2947
2948
2949/***************************************************************************
2950
2951 * aura_readfifo:    Function to read the FIFO on a 4X20P, 8X20P or Sun
2952serial
2953
2954 *
2955
2956 *
2957
2958 *     Parameters   :
2959
2960 *                   port:  The port being accessed
2961
2962 *                   buf:   The address of a buffer where we should put
2963
2964 *                          what we read
2965
2966 *                  nbytes: How many chars to read.
2967
2968 *
2969
2970 *     Return value : none
2971
2972 *
2973
2974 *     Prerequisite : The port must have been opened
2975
2976 *
2977
2978 *     Remark       :
2979
2980 *
2981
2982 *     Author       : fw
2983
2984 *
2985
2986 *     Revision     : Oct 13 2000, creation
2987
2988 ***************************************************************************/
2989
2990void aura_readfifo(struct sab_port *port, unsigned char *buf, unsigned
2991int nbytes)
2992
2993{
2994
2995  int i;
2996
2997  unsigned short *wptr = (unsigned short*) buf;
2998
2999  int nwords = ((nbytes+1)/2);
3000
3001  for(i = 0; i < nwords; i ++)
3002
3003    {
3004
3005      wptr[i] = readw(((unsigned short *)port->regs));
3006
3007    }
3008
3009}
3010
3011
3012
3013Here is the readfifo function for multichannel servers.
3014
3015
3016
3017void wmsaura_readfifo(struct sab_port *port, unsigned char *buf,
3018unsigned int nbytes)
3019
3020{
3021
3022#ifdef FIFO_DIRECT
3023
3024  unsigned short fifo[32/2];    /* this array is word aligned
3025
3026                                 * buf may not be word aligned*/
3027
3028  unsigned int nwords;
3029
3030  int i;
3031
3032  int wcount;
3033
3034  unsigned int address;
3035
3036
3037
3038  if (nbytes == 0)
3039
3040    {
3041
3042      return;
3043
3044    }
3045
3046
3047
3048  wcount = ((nbytes + 1) >> 1);
3049
3050  /* Read the thing into the local FIFO and copy it out. */
3051
3052  address = (unsigned int) port->regs;
3053
3054
3055
3056  for(i = 0; i < wcount; ++i)
3057
3058    {
3059
3060      fifo[i] = readw((unsigned short*)(address + CIMCMD_RDFIFOW));
3061
3062    }
3063
3064
3065
3066  memcpy((unsigned char*) buf, (unsigned char*) &(fifo[0]), (unsigned
3067int) nbytes);
3068
3069
3070
3071#else           /* FIFO_DIRECT */
3072
3073  unsigned short fifo[32/2];
3074
3075  int i;
3076
3077  int wcount;
3078
3079  SAB_BOARD *bptr;
3080
3081  unsigned int channel;
3082
3083
3084
3085  if (nbytes == 0)
3086
3087    {
3088
3089      return;
3090
3091    }
3092
3093
3094
3095  bptr = port->board;
3096
3097  wcount = ((nbytes + 1) >> 1);
3098
3099  channel = (((unsigned char*) port->regs) - bptr->CIMCMD_REG); /*
3100should be properly shifted */
3101
3102
3103
3104  /*
3105
3106   * Trigger a cache read by writing the nwords - 1 to the
3107
3108   *  magic place.
3109
3110   */
3111
3112
3113
3114  writeb((unsigned char) wcount, bptr->MICCMD_REG + (MICCMD_CACHETRIG +
3115channel));
3116
3117
3118
3119  /*
3120
3121   * Now, read out the contents.
3122
3123   */
3124
3125
3126
3127  channel >>= 1;
3128
3129
3130
3131  for(i = 0; i < wcount; ++i)
3132
3133    {
3134
3135      fifo[i] = readw((unsigned short*)(bptr->FIFOCACHE_REG + (channel +
3136(i << 1))));
3137
3138    }
3139
3140
3141
3142  memcpy((unsigned char*) buf, (unsigned char*) &(fifo[0]), (unsigned
3143int) nbytes);
3144
3145#endif          /* !FIFO_DIRECT */
3146
3147}
3148
3149
3150
3151
3152Except at initialization time the driver code accesses serial
3153communications controller device registers only through fields in the
3154port structure.  The details of accessing the different types of
3155hardware are almost completely hidden from the driver program logic.
3156
3157
3158
3159The only exception is the interrupt handler, which must understand some
3160of the details of the multichannel server.  Nevertheless, as is made
3161clear in the following section, from the standpoint of processing
3162interrupts there are really only two types of Aurora hardware, that
3163which is ESCC2 based and that which is ESCC8 based.  The details of the
3164difference of the two types of hardware is contained solely within the
31658253xint.c file which also contains the logic by which an interrupt from
3166a multichannel server can be processed almost exactly like an interrupt
3167from an 8520P adapter card.
3168
3169
3170
3171
3172  /Code Structure Summary/
3173
3174
3175
3176
3177
3178  The SAB8253X driver code has the following logic components
3179
3180
3181
31821.      a probe/initialization logic,
3183
3184a.      bridge initialization/EEPROM parsing logic,
3185
3186b.      structure allocation logic,
3187
3188c.      interrupt request logic,
3189
31902.      the core logic, which handles all the non-interrupt processing
3191of the driver functionality,
3192
3193a.      per port startup/shutdown logic,
3194
3195b.      driver arbitration logic,
3196
3197c.      skbuffer management logic,
3198
31993.      the interrupt handler logic,
3200
3201a.      common interrupt port polling logic,
3202
3203b.      skbuffer management logic,
3204
32054.      the termination/driver unload logic,
3206
3207a.      interrupt shutdown logic,
3208
3209b.      device shutdown logic,
3210
3211c.      structure deallocation logic.
3212
3213
3214
3215
3216
3217/Probe/Initialization Logic/
3218
3219
3220
3221The probe/initialization logic sets up the CRC structures for the
3222network driver and then the tty_struct for the synchronous and
3223asynchronous TTY drivers.  Initializing the tty_struct involves setting
3224up pointers to the standard functions that the Linux TTY driver invokes
3225as well as some standard data and the /proc/tty/driver/auraserial
3226function and data.
3227
3228
3229
3230
3231The probe/initialization logic identifies all the multiport serial
3232adapters, compact PCI adapters and multiserver adapters in the system
3233and puts them on a list of board structures.  After identifying all the
3234boards, initializing the bridge chips and analyzing (possibly rewriting)
3235the serial EEPROM, the logic sets up all the chips on the boards and all
3236the ports on the chips.
3237
3238
3239
3240All chips are linked together in a list.  All ports are linked together
3241in a list.  The port list is linked together so that minor device N
3242corresponds to the Nth element of the port list.  A board structure
3243points to a list of chips on the board as well as a list of all ports on
3244the board.  Likewise a chip structure points to a list of all ports on
3245the chip.  Chip structures point back to the board structure associated
3246with the board on which the chip resides.  Likewise port structures
3247point back to the board and to the chip on which they reside.  This
3248interconnected list structure facilitates access to one type of
3249structure when a routine has been passed a pointer to another type of
3250structure.  All these structures are dynamically allocated via
3251/kmalloc()/.  When the driver is unloaded, memory is released by walking
3252the list.
3253
3254
3255
3256After setting up the board, chip and port structures, initialization of
3257the tty_struct is completed at this point because the maximum possible
3258number of serial TTYs is now known.  The, the standard network device
3259structure that is associated with each port is allocated and
3260initialized.  The network devices point to the associated port
3261structure.  The network devices are chained via a pointer in the
3262associated port structure.  This chaining facilitates release of the
3263network device structure memory when the driver is unloaded.
3264
3265
3266
3267Each network device is registered after its network device structure is
3268initialized.  Network device initialization invokes the network device
3269initialization, which installs the standard network functions in the
3270network device structure and which sets up the sk_buff transmit ring as
3271well as the receive sk_buf.  Unlike the Solaris driver, when a complete
3272frame is received with no errors, it is immediately passed into the
3273network layer.  Thus, there is no receive ring of sk_buffs as one might
3274find in the driver of a device that could carry out chained DMA (e.g. a
3275DEC Tulip or an Hitachi SCA).
3276
3277
3278
3279All sk_buffs associated with a network device that are currently in use
3280by the network driver are linked together in an sk_buff list (viz core
3281logic).   This list facilitates release of all sk_buff associated with a
3282network device when that network device is shut down.  This list may be
3283a problem if it becomes possible for a single sk_buff to be used
3284simultaneously by multiple network devices.  Currently, sk_buff headers
3285are not shared among network devices although sk_buff data can be
3286shared.  Thus, for the nonce this logic works correctly.
3287
3288
3289
3290After completing of network device initialization, the
3291probe/initialization logic register the character driver.  Next, the
3292probe/initialization creates three lists of boards for each interrupt
3293(0-31).  One list contains 82532 based boards at that interrupt level.
3294The next list contains 82538 based adapter cards at that interrupt
3295level.  The third list contains all multichannel server units at that
3296interrupt level.
3297
3298
3299
3300Next the probe/initialization logic checks the lists associated with
3301each interrupt level.  If either list is non-null, the
3302probe/initialization logic requests that the general interrupt handler
3303be installed at this interrupt level and then it turns on PLX9050 or
3304AMCC5920 interrupts (as needed) into the Linux host for each card
3305associated with that interrupt level.  Thus, the interrupt handler polls
3306all boards/ports at a given interrupt level when the interrupt occurs.
3307This approach is more efficient that installing one interrupt per board
3308and avoids some internal Linux limits on the number of interrupt
3309handlers that can be installed per interrupt.
3310
3311
3312
3313At this point probe/intialization is complete and any serial port may be
3314used for asynchronous TTY, synchronous TTY, call out, network device
3315service or synchronous character device service.
3316
3317
3318
3319
3320/Core Logic/
3321
3322
3323
3324The main problem of the core logic is arbitration of access to the
3325serial port, when and by which part of the driver a port is started and
3326when the port is shut down.
3327
3328
3329
3330The asynchronous callout, asynchronous TTY, synchronous TTY devices,
3331synchronous character device and network device follow the following rules.
3332
3333
3334
33351.                  If there is an established point-to-point
3336connection, only the current process or process group that owns the
3337serial port may open the device.
3338
33392.                  If the asynchronous callout is open, opens of a
3340single TTY or character device type block until the connection completes.
3341
33423.                  Network device opens never block, and the network
3343layer opens a network device only once.
3344
33454.                  If a connection that belongs to a TTY device or
3346character device hangs up, eventually all opens of that device will close.
3347
33485.                  Hangup of on a network device does not guarantee a
3349close of the device, but a flag bit is set that permits a call out open
3350to restore the connection (note that a one-to-one map of TTY devices,
3351callout devices, character devices and network devices is implied.)
3352
3353
3354
3355The network device open and block_til_ready* functions invoked from TTY
3356opens enforce this arbitration.
3357
3358
3359
3360The logic works as follows:
3361
3362
3363
3364    * The cua device associated with a port may only be opened one.
3365    * If a TTY or character device is open, the cua device may not be
3366      opened.
3367    * If the cua device is open, the network device cannot be opened and
3368      the TTY or character device block (multiple opens from the same
3369      process or process group are allowed).
3370    * If the network device is open, the TTY or character devices cannot
3371      be opened while the cua device blocks.
3372    * A hangup sends an interrupt to the TTY or character device while
3373      the network device shuts down its port and a (network blocked) cua
3374      device proceeds.
3375    * On the close of the cua device, blocked TTY and character devices
3376      proceed and the network device restarts its port.
3377
3378
3379
3380When an open completes, the transmit_chars, receive_chars,  check_status
3381functions and associated data fields are set in the port structure,
3382these are used in the interrupt handler that never changes until the
3383driver is unloaded.
3384
3385
3386
3387When a port is not in use, the asynchronous version of these fields and
3388functions are set in the port structure.  Some values must be present,
3389and the asynchronous ones are probably the least dangerous.
3390
3391
3392
3393Besides the arbitration problem, the core logic addresses buffer
3394management for the network and character drivers.
3395
3396
3397
3398The network layer passes a transmit sk_buff to the network driver.   The
3399buffer is inserted in the transmit ring or sets a transmit congestion
3400flag.  In either case, transmit is initialized if not already in
3401progress.  If the sk_buff is successfully inserted, it is also linked
3402into the driver sk_buff list which tracks all sk_buffs used by the
3403network driver.  On network device close all sk_buffs on the per port
3404sk_buff list are released.  This sk_buff list mechanism is used to avoid
3405memory leaks.
3406
3407
3408
3409The TTY and character drivers packetize write data in an sk_buff (each
3410write creates a single sk_buff) and inserts it in the transmit ring if
3411possible or blocks (returns a failure in the case of TTY drivers).
3412Transmit sk_buffs are also linked into the driver sk_buff list.  This
3413list is a convenience to assist deallocation during driver close.
3414
3415
3416
3417The TTY and character drivers also maintains a receive sk_buff list.
3418When the user application invokes the read system call, the data from
3419one sk_buff is passed up to the user application (or an error if the
3420read were not invoked with sufficient buffer space).
3421
3422
3423
3424The character driver can be configured via IOCTL to send asynchronous
3425user notification when the transmit ring empties (a design choice for
3426the standard driver fasync functionality).  This character driver design
3427emulates the Solaris putmsg/getmsg interface as far as possible and
3428makes it possible to implement in a user application protocols like
3429LAPB, which require that low priority packets only be queued to the
3430driver when the driver currently has no frames in the process of
3431transmission or queued for transmission.
3432
3433
3434
3435On character device close all sk_buffs on the per port sk_buff and per
3436port receive sk_buff list are released.  This double sk_buff list
3437mechanism is used to avoid memory leaks.
3438
3439
3440
3441/Interrupt Handler Logic/
3442
3443
3444
3445
3446      The following code comprises the combined interrupt and board/port
3447      polling logic.  The actual handler is /sab8253x_interrupt()/.  It
3448      walks through the 82532, adapter 82538 adapter and multichannel
3449      server lists at the interrupt level that is being processed and
3450      invokes inline /sab82532_interrupt()/ and /sab82538_interrupt()/.
3451      Note that it temporary modifies multichannel server lists so that
3452      it like an 8520P adapter card to the /sab8253x_interrupt()/.  This
3453      logic works because the granularity of the PCI interrupt
3454      associated with the Aurora hardware is basically either a list of
3455      ESCC2s (the 4520P and 4520CP adapter cards) or a single ESCC8 (an
3456      8520P or one ESCC8 on a multichannel server remote card after the
3457      interrupt status has been queried).
3458
3459
3460
3461
3462
3463      The current interrupt sources are identified and processed.  If
3464      any characters are available to be received, they are received one
3465      fifo at a time into the TTY flip buffer (a structure that is
3466      supposed to decrease TTY latency) or into an sk_buf (something
3467      like a Solaris mblk/dblk structure( in the case of the network or
3468      character driver.  Then if there are characters in the TTY
3469      circular transmit buffer or in the network or character driver
3470      sk_buff, they are loaded into the transmit fifo, one fifo at a
3471      time.  Finally, modem control status is checked.  If a hang up is
3472      detected, the serial driver hang up is scheduled at kernel
3473      scheduler priority (a slight difference from the standard serial
3474      driver which processes hang-ups at interrupt level) in order to
3475      avoid certain race conditions in the TTY driver that can occur on
3476      fast machines with many serial ports.  /do_serial_hangup()/
3477      invokes the TTY hangup routines in the case of TTY driver.  For a
3478      network connection in the event of a line disconnection, carrier
3479      is marked as off on the interface and the blocked cua device is
3480      woken so that it can proceed after the network port has shut down.
3481
3482
3483
3484static void __inline__ sab82532_interrupt(int irq, void *dev_id, struct
3485pt_regs *regs)
3486
3487{
3488
3489  struct sab_port *port;
3490
3491  struct sab_chip *chip=NULL;
3492
3493  struct sab_board *bptr = (struct sab_board*) dev_id;
3494
3495  union sab8253x_irq_status status;
3496
3497  unsigned char gis;
3498
3499
3500
3501  for(chip = bptr->board_chipbase; chip != NULL; chip =
3502chip->next_by_board)
3503
3504    {
3505
3506      port= chip->c_portbase;
3507
3508      gis = READB(port, gis); /* Global! */
3509
3510      status.stat=0;
3511
3512
3513
3514            /* Since the PORT interrupt are global,
3515
3516             * we do check all the ports for this chip
3517
3518             */
3519
3520
3521
3522                                /* A 2 ports chip */
3523
3524
3525
3526      if(!(gis & SAB82532_GIS_MASK))
3527
3528        {
3529
3530          continue; /* no interrupt on this chip */
3531
3532        }
3533
3534
3535
3536      if (gis & SAB82532_GIS_ISA0)
3537
3538        {
3539
3540          status.sreg.isr0 = READB(port, isr0);
3541
3542        }
3543
3544      else
3545
3546        {
3547
3548          status.sreg.isr0 = 0;
3549
3550        }
3551
3552      if (gis & SAB82532_GIS_ISA1)
3553
3554        {
3555
3556          status.sreg.isr1 = READB(port, isr1);
3557
3558        }
3559
3560      else
3561
3562        {
3563
3564          status.sreg.isr1 = 0;
3565
3566        }
3567
3568
3569
3570      if (gis & SAB82532_GIS_PI)
3571
3572        {
3573
3574          status.sreg.pis = READB(port, pis);
3575
3576        }
3577
3578      else
3579
3580        {
3581
3582          status.sreg.pis = 0;
3583
3584        }
3585
3586
3587
3588      if (status.stat)
3589
3590        {
3591
3592          if (status.images[ISR0_IDX] & port->receive_test)
3593
3594            {
3595
3596              (*port->receive_chars)(port, &status);    /* when the fifo
3597is full */
3598
3599                                                /* no time to schedule
3600thread*/
3601
3602            }
3603
3604
3605
3606          if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
3607
3608              (status.images[port->cts.irq] & port->cts.irqmask) ||
3609
3610              (status.images[port->dsr.irq] & port->dsr.irqmask) ||
3611
3612              (status.images[ISR1_IDX] & port->check_status_test))
3613
3614            {
3615
3616              (*port->check_status)(port, &status); /* this stuff should
3617be */
3618
3619              /* be moveable to scheduler */
3620
3621              /* thread*/
3622
3623            }
3624
3625
3626
3627          if (status.images[ISR1_IDX] & port->transmit_test)
3628
3629            {
3630
3631              (*port->transmit_chars)(port, &status); /* needs to be
3632moved to task */
3633
3634            }
3635
3636        }
3637
3638
3639
3640                                /* Get to next port on chip */
3641
3642      port = port->next_by_chip;
3643
3644      /* Port B */
3645
3646      if (gis & SAB82532_GIS_ISB0)
3647
3648        {
3649
3650          status.images[ISR0_IDX] = READB(port, isr0);
3651
3652        }
3653
3654      else
3655
3656        {
3657
3658          status.images[ISR0_IDX] = 0;
3659
3660        }
3661
3662      if (gis & SAB82532_GIS_ISB1)
3663
3664        {
3665
3666          status.images[ISR1_IDX] = READB(port,isr1);
3667
3668        }
3669
3670      else
3671
3672        {
3673
3674          status.images[ISR1_IDX] = 0;
3675
3676        }
3677
3678      /* DO NOT SET PIS. IT was reset! */
3679
3680
3681
3682
3683
3684      if (status.stat)
3685
3686        {
3687
3688          if (status.images[ISR0_IDX] & port->receive_test)
3689
3690            {
3691
3692              (*port->receive_chars)(port, &status);
3693
3694            }
3695
3696          if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
3697
3698              (status.images[port->cts.irq] & port->cts.irqmask) ||
3699
3700              (status.images[port->dsr.irq] & port->dsr.irqmask) ||
3701
3702              (status.images[ISR1_IDX] & port->check_status_test))
3703
3704            {
3705
3706              (*port->check_status)(port, &status);
3707
3708            }
3709
3710          if (status.images[ISR1_IDX] & port->transmit_test)
3711
3712            {
3713
3714              (*port->transmit_chars)(port, &status);
3715
3716            }
3717
3718        }
3719
3720    }
3721
3722}
3723
3724
3725
3726static void __inline__ sab82538_interrupt(int irq, void *dev_id, struct
3727pt_regs *regs)
3728
3729{
3730
3731  struct sab_port *port;
3732
3733  struct sab_chip *chip=NULL;
3734
3735  struct sab_board *bptr = (struct sab_board*) dev_id;
3736
3737  union sab8253x_irq_status status;
3738
3739  unsigned char gis,i;
3740
3741
3742
3743  chip = bptr->board_chipbase;
3744
3745  port= chip->c_portbase;
3746
3747
3748
3749  gis = READB(port, gis); /* Global! */
3750
3751  status.stat=0;
3752
3753
3754
3755            /* Since the PORT interrupt are global,
3756
3757             * we do check all the ports for this chip
3758
3759             */
3760
3761
3762
3763  /* 8 ports chip */
3764
3765  if(!(gis & SAB82538_GIS_MASK))
3766
3767    {
3768
3769      return;
3770
3771    }
3772
3773
3774
3775  if(gis & SAB82538_GIS_CII)
3776
3777    { /* A port interrupt! */
3778
3779      /* Get the port */
3780
3781      int portindex;
3782
3783
3784
3785      portindex = (gis & SAB82538_GIS_CHNL_MASK);
3786
3787
3788
3789      port = chip->c_portbase;
3790
3791
3792
3793      while(portindex)
3794
3795        {
3796
3797          port = port->next_by_chip;
3798
3799          --portindex;
3800
3801        }
3802
3803
3804
3805      status.images[ISR0_IDX] = READB(port,isr0);
3806
3807      status.images[ISR1_IDX] = READB(port,isr1);
3808
3809      if (gis & SAB82538_GIS_PIC)
3810
3811        {
3812
3813          status.images[PIS_IDX] =
3814
3815            (*port->readbyte)(port,
3816
3817                              ((unsigned char *)(port->regs)) +
3818
3819                              SAB82538_REG_PIS_C);
3820
3821        }
3822
3823      else
3824
3825        {
3826
3827          status.images[PIS_IDX] = 0;
3828
3829        }
3830
3831
3832
3833      if (status.stat)
3834
3835        {
3836
3837          if (status.images[ISR0_IDX] & port->receive_test)
3838
3839            {
3840
3841              (*port->receive_chars)(port, &status);
3842
3843            }
3844
3845          if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
3846
3847              (status.images[port->cts.irq] & port->cts.irqmask) ||
3848
3849              (status.images[port->dsr.irq] & port->dsr.irqmask) ||
3850
3851              (status.images[ISR1_IDX] & port->check_status_test))
3852
3853            {
3854
3855              (*port->check_status)(port, &status);
3856
3857            }
3858
3859          /*
3860
3861           * We know that with 8 ports chip, the bit corresponding to
3862channel
3863
3864           * number is used in the parallel port... So we clear it
3865
3866           * Not too elegant!
3867
3868           */
3869
3870          status.images[PIS_IDX] &= ~(1 << (gis&SAB82538_GIS_CHNL_MASK));
3871
3872          if (status.images[ISR1_IDX] & port->transmit_test)
3873
3874            {
3875
3876              (*port->transmit_chars)(port, &status);
3877
3878            }
3879
3880        }
3881
3882    }
3883
3884
3885
3886  /*
3887
3888   * Now we handle the "channel interrupt" case. The chip manual for the
3889
3890   * 8 ports chip states that "channel" and "port" interrupt are set
3891
3892   * independently so we still must check the parrallel port
3893
3894   *
3895
3896   * We should probably redesign the whole thing to be less AD HOC that we
3897
3898   * are now... We know that port C is used for DSR so we only check
3899that one.
3900
3901   * PIS for port C was already recorded in  status.images[PIS_IDX], so we
3902
3903   * check the ports that are set
3904
3905   */
3906
3907
3908
3909  if (status.images[PIS_IDX])
3910
3911    {
3912
3913      for(i=0, port = chip->c_portbase;
3914
3915          i < chip->c_nports;
3916
3917          i++, port=port->next_by_chip)
3918
3919        {
3920
3921          if(status.images[PIS_IDX] & (0x1 << i))
3922
3923            { /* Match */
3924
3925              /* Checking DSR */
3926
3927              if(port->dsr.inverted)
3928
3929                {
3930
3931                  port->dsr.val = (((*port->readbyte)
3932
3933                                    (port, port->dsr.reg) &
3934
3935                                    port->dsr.mask) ? 0 : 1);
3936
3937                }
3938
3939              else
3940
3941                {
3942
3943                  port->dsr.val = ((*port->readbyte)(port, port->dsr.reg) &
3944
3945                                   port->dsr.mask);
3946
3947                }
3948
3949
3950
3951              port->icount.dsr++;
3952
3953              wake_up_interruptible(&port->delta_msr_wait);
3954
3955            }
3956
3957        }
3958
3959    }
3960
3961}
3962
3963
3964
3965/*
3966
3967 * This is the serial driver's generic interrupt routine
3968
3969 */
3970
3971
3972
3973void sab8253x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
3974
3975{
3976
3977  extern SAB_BOARD *AuraBoardESCC2IrqRoot[];
3978
3979  extern SAB_BOARD *AuraBoardESCC8IrqRoot[];
3980
3981  extern SAB_BOARD *AuraBoardMCSIrqRoot[];
3982
3983  AURA_CIM *cim;
3984
3985  SAB_CHIP *chip;
3986
3987  SAB_PORT *port;
3988
3989  register SAB_BOARD *boardptr;
3990
3991  register unsigned char intrmask;
3992
3993  unsigned char stat;
3994
3995  SAB_CHIP *save_chiplist;
3996
3997  SAB_PORT *save_portlist;
3998
3999
4000
4001  if((irq < 0) || (irq >= NUMINTS))
4002
4003    {
4004
4005      printk(KERN_ALERT "sab8253x: bad interrupt value %i.\n", irq);
4006
4007      return;
4008
4009    }
4010
4011  /* walk through all the cards on the interrupt that occurred. */
4012
4013  for(boardptr = AuraBoardESCC2IrqRoot[irq]; boardptr != NULL; boardptr
4014= boardptr->next_on_interrupt)
4015
4016    {
4017
4018      sab82532_interrupt(irq, boardptr, regs);
4019
4020    }
4021
4022
4023
4024  for(boardptr = AuraBoardESCC8IrqRoot[irq]; boardptr != NULL; boardptr
4025= boardptr->next_on_interrupt)
4026
4027    {
4028
4029      sab82538_interrupt(irq, boardptr, regs);
4030
4031    }
4032
4033
4034
4035  for(boardptr = AuraBoardMCSIrqRoot[irq]; boardptr != NULL; boardptr =
4036boardptr->next_on_interrupt)
4037
4038    {
4039
4040
4041
4042      while(1)
4043
4044        {
4045
4046          writeb(0, (unsigned char*)(boardptr->CIMCMD_REG +
4047CIMCMD_WRINTDIS)); /* prevent EBs from raising
4048
4049
4050* any more ints through the
4051
4052
4053* host card */
4054
4055          stat = ~(unsigned char) /* active low !!!!! */
4056
4057            readw((unsigned short*)
4058
4059                  (((unsigned char*)boardptr->CIMCMD_REG) +
4060CIMCMD_RDINT)); /* read out the ints */
4061
4062                                /* write to the MIC csr to reset the PCI
4063interrupt */
4064
4065          writeb(0, (unsigned char*)(boardptr->MICCMD_REG +
4066MICCMD_MICCSR)); /* reset the interrupt generation
4067
4068
4069      * hardware on the host card*/
4070
4071                                /* now, write to the CIM interrupt ena
4072to re-enable interrupt generation */
4073
4074          writeb(0, (unsigned char*)(boardptr->CIMCMD_REG +
4075CIMCMD_WRINTENA)); /* allow EBs to request ints
4076
4077
4078* through the host card */
4079
4080          if(!stat)
4081
4082            {
4083
4084              break;
4085
4086            }
4087
4088          cim = boardptr->b_cimbase; /* cims in reverse order */
4089
4090          for(intrmask = boardptr->b_intrmask;
4091
4092              intrmask != 0;
4093
4094              intrmask <<= 2, stat <<=2)
4095
4096            {
4097
4098              if(cim == NULL)
4099
4100                {
4101
4102                  break;        /* no cim no ports */
4103
4104                }
4105
4106              if((intrmask & 0xc0) == 0) /* means no cim for these ints */
4107
4108                {               /* cim not on list do not go to next */
4109
4110                  continue;
4111
4112                }
4113
4114              save_portlist = boardptr->board_portbase;
4115
4116              save_chiplist = boardptr->board_chipbase;
4117
4118                                /* the goal is temporarily to make the
4119structures
4120
4121                                 * look like 8x20 structures -- thus if
4122I find
4123
4124                                 * a bug related to escc8s I need fix it in
4125
4126                                 * only one place. */
4127
4128              switch(stat & 0xc0) /* possible ints */
4129
4130                {
4131
4132                default:
4133
4134                  break;
4135
4136
4137
4138                case 0x80:      /* esccB */
4139
4140                  chip = cim->ci_chipbase;
4141
4142                  if(!chip)
4143
4144                    {
4145
4146                      printk(KERN_ALERT "aura mcs: missing cim.\n");
4147
4148                      break;
4149
4150                    }
4151
4152                  chip = chip->next_by_cim;
4153
4154                  if(!chip)
4155
4156                    {
4157
4158                      printk(KERN_ALERT "aura mcs: missing 2nd cim.\n");
4159
4160                      break;
4161
4162                    }
4163
4164                  port = chip->c_portbase;
4165
4166                  boardptr->board_portbase = port;
4167
4168                  boardptr->board_chipbase = chip;
4169
4170                  sab82538_interrupt(irq, boardptr, regs);
4171
4172                  break;
4173
4174
4175
4176                case 0x40:      /* esccA */
4177
4178                  chip = cim->ci_chipbase;
4179
4180                  if(!chip)
4181
4182                    {
4183
4184                      printk(KERN_ALERT "aura mcs: missing cim.\n");
4185
4186                      break;
4187
4188                    }
4189
4190                  port = chip->c_portbase;
4191
4192                  boardptr->board_portbase = port;
4193
4194                  boardptr->board_chipbase = chip;
4195
4196                  sab82538_interrupt(irq, boardptr, regs);
4197
4198                  break;
4199
4200
4201
4202                case 0xc0:      /* esccB and esccA */
4203
4204                  chip = cim->ci_chipbase;
4205
4206                  if(!chip)
4207
4208                    {
4209
4210                      printk(KERN_ALERT "aura mcs: missing cim.\n");
4211
4212                      break;
4213
4214                    }
4215
4216                  port = chip->c_portbase;
4217
4218                  boardptr->board_portbase = port;
4219
4220                  boardptr->board_chipbase = chip;
4221
4222                  sab82538_interrupt(irq, boardptr, regs);
4223
4224
4225
4226                  chip = cim->ci_chipbase;
4227
4228                  if(!chip)
4229
4230                    {
4231
4232                      printk(KERN_ALERT "aura mcs: missing cim.\n");
4233
4234                      break;
4235
4236                    }
4237
4238                  chip = chip->next_by_cim;
4239
4240                  if(!chip)
4241
4242                    {
4243
4244                      printk(KERN_ALERT "aura mcs: missing 2nd cim.\n");
4245
4246                      break;
4247
4248                    }
4249
4250                  port = chip->c_portbase;
4251
4252                  boardptr->board_portbase = port;
4253
4254                  boardptr->board_chipbase = chip;
4255
4256                  sab82538_interrupt(irq, boardptr, regs);
4257
4258                  break;
4259
4260                }
4261
4262              boardptr->board_portbase = save_portlist;
4263
4264              boardptr->board_chipbase = save_chiplist;
4265
4266              cim = cim->next_by_mcs;
4267
4268            }
4269
4270        }
4271
4272    }
4273
4274}
4275
4276
4277
4278Note that if there is no transmit in process when the
4279write/hard_start_transmit routine is invoked,  transmit is intitiated
4280from the core logic as if it took place in the interrupt handler.  This
4281approach differs from the ASE driver, which used to force an interrupt,
4282and then start the transmission.  Francois Wautier may have fixed that
4283logic to start the transmission either in the STREAMS put or service
4284routine.
4285
4286
4287
4288/Driver Unload Logic/
4289
4290
4291
4292The driver unload logic inverts the probe intialization logic.
4293
4294
4295
4296At this point no ports should be in use and in fact every port should
4297have been put in the 8253x powered down state when each port underwent
4298its last close (or hangup which can actually complete after a close).
4299
4300
4301
4302The tty driver is cleaned up, some dynamic TTY data structures are
4303deallocated, the bottom half associated with this driver is removed and
4304all TTY ports are deregistered.
4305
4306
4307
4308The PLX or AMCC interrupts to the Linux host are disabled on each board,
4309and all interrupt handlers are freed.
4310
4311
4312
4313Next all board and chip structures are deallocated (including physical
4314memory to virtual memory mappings associated with PLX9050 or AMCC 5920
4315and chip registers).  Then all network device structures are
4316deallocated.  (Note that all lingering sk_buffs were freed during the
4317close of the network device, which must have completed before the unload
4318of the driver module.)  And finally the port structures are
4319deallocated.  In deallocating the port structures, network driver
4320transmit rings and the receive sk_buff descriptor are deallocated if
4321they are present.  (They were only allocated if the port had ever been
4322used for a network device.)  At this point the driver has been
4323gracefully unloaded.
4324
4325
4326
4327                                /* cleanup module/free up virtual memory */
4328
4329                                /* space*/
4330
4331void cleanup_module(void)
4332
4333{
4334
4335  SAB_BOARD *boardptr;
4336
4337  SAB_CHIP *chipptr;
4338
4339  SAB_PORT *portptr;
4340
4341  int intr_val;
4342
4343  extern void sab8253x_cleanup_ttydriver(void);
4344
4345
4346
4347  printk(KERN_ALERT "auraXX50n: unloading AURAXX50 driver.\n");
4348
4349
4350
4351  sab8253x_cleanup_ttydriver(); /* clean up tty */
4352
4353
4354
4355                                /* unallocate and turn off ints */
4356
4357  for(intr_val = 0; intr_val < NUMINTS; ++intr_val)
4358
4359    {
4360
4361      if((AuraBoardESCC2IrqRoot[intr_val] != NULL) ||
4362(AuraBoardESCC8IrqRoot[intr_val] != NULL))
4363
4364        {
4365
4366          for(boardptr = AuraBoardESCC2IrqRoot[intr_val]; boardptr !=
4367NULL; boardptr = boardptr->next_on_interrupt)
4368
4369            {
4370
4371              writel(PLX_INT_OFF, &(boardptr->b_bridge->intr));
4372
4373            }
4374
4375          for(boardptr = AuraBoardESCC8IrqRoot[intr_val]; boardptr !=
4376NULL; boardptr = boardptr->next_on_interrupt)
4377
4378            {
4379
4380              writel(PLX_INT_OFF, &(boardptr->b_bridge->intr));
4381
4382            }
4383
4384
4385
4386          free_irq(intr_val, &AuraBoardESCC2IrqRoot[intr_val]); /* free
4387up board int
4388
4389                                                                 * note
4390that if two boards
4391
4392                                                                 * share
4393an int, two int
4394
4395                                                                 *
4396handlers were registered
4397
4398                                                                 *
4399
4400                                                                 */
4401
4402        }
4403
4404    }
4405
4406
4407
4408                                /* disable chips and free board memory*/
4409
4410  while(AuraBoardRoot)
4411
4412    {
4413
4414      boardptr = AuraBoardRoot;
4415
4416      for(chipptr = boardptr->board_chipbase; chipptr != NULL; chipptr =
4417chipptr->next_by_board)
4418
4419        {
4420
4421          (*chipptr->int_disable)(chipptr); /* make sure no ints can
4422come int */
4423
4424        }
4425
4426      AuraBoardRoot = boardptr->nextboard;
4427
4428      if(boardptr->virtbaseaddress0)
4429
4430        {
4431
4432          DEBUGPRINT((KERN_ALERT
4433
4434                      "auraXX50n: unmapping virtual address %p.\n",
4435
4436                      (void*)boardptr->virtbaseaddress0));
4437
4438          iounmap((void*)boardptr->virtbaseaddress0);
4439
4440          boardptr->virtbaseaddress0 = 0;
4441
4442        }
4443
4444      if(boardptr->virtbaseaddress2)
4445
4446        {
4447
4448          DEBUGPRINT((KERN_ALERT
4449
4450                      "auraXX50n: unmapping virtual address %p.\n",
4451
4452                      (void*)boardptr->virtbaseaddress2));
4453
4454          iounmap((void*)boardptr->virtbaseaddress2);
4455
4456          boardptr->virtbaseaddress2 = 0;
4457
4458        }
4459
4460      kfree(boardptr);
4461
4462    }
4463
4464
4465
4466  while(AuraChipRoot)           /* free chip memory */
4467
4468    {
4469
4470      chipptr = AuraChipRoot;
4471
4472      AuraChipRoot = chipptr->next;
4473
4474      kfree(chipptr);
4475
4476    }
4477
4478
4479
4480  while(Sab8253xRoot)           /* free up network stuff */
4481
4482    {
4483
4484      SAB_PORT *priv;
4485
4486      priv = (SAB_PORT *)Sab8253xRoot->priv;
4487
4488      unregister_netdev(Sab8253xRoot);
4489
4490#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
4491
4492      kfree(Sab8253xRoot.name);
4493
4494#endif
4495
4496      kfree(Sab8253xRoot);
4497
4498      Sab8253xRoot = priv->next_dev;
4499
4500    }
4501
4502
4503
4504  while(AuraPortRoot)           /* free up port memory */
4505
4506    {
4507
4508      portptr = AuraPortRoot;
4509
4510      AuraPortRoot = portptr->next;
4511
4512      if(portptr->dcontrol2.receive)
4513
4514        {
4515
4516          kfree(portptr->dcontrol2.receive);
4517
4518        }
4519
4520      if(portptr->dcontrol2.transmit)
4521
4522        {
4523
4524          kfree(portptr->dcontrol2.transmit);
4525
4526        }
4527
4528      kfree(portptr);
4529
4530    }
4531
4532}
4533
4534
4535
4536_Design Summary_
4537
4538
4539
4540The 10 key data structures are shared by all the logic of the system.
4541The logic enforces both exclusive and cooperative access to the physical
4542hardware on the basis of certain rules established by the core logic at
4543device/port open time. While the driver is mostly self-configuring, the
4544data structure sharing simplifies the user interface because an ioctl to
4545one driver functionality (e.g., the TTY functionality) configures the
4546rest of the driver functionality (e.g., the network and character device
4547functionality).   In other words, a single serial port acts virtually as
4548three arbitrated devices:  a TTY device, which may be asynchronous,
4549synchronous or call out, a network device or a character device.  Yet,
4550except at the time of initialization, time of driver unload and very
4551early in interrupt processing all hardware details are concealed and the
4552driver logic is applied to an abstract, simplified port entity.  Thus,
4553the user application interfaces to three abstract virtual devices, which
4554have a single configuration interface (otherwise it might be possible to
4555have an inconsistent configuration) and not to a complex real single
4556port in the context of an equally complex adapter card or unit. This
4557simplification makes it possible to provide a high degree of serial
4558functionality across the family of Aurora synchronous/asynchronous PCI
4559hardware through a straightforward uniform application interface.
4560
4561
4562
4563