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