diff -u --recursive --new-file v2.1.36/linux/CREDITS linux/CREDITS --- v2.1.36/linux/CREDITS Wed Apr 16 14:14:58 1997 +++ linux/CREDITS Tue May 13 21:52:27 1997 @@ -149,12 +149,8 @@ S: Germany N: Bill Bogstad -E: bogstad@cs.jhu.edu -D: Wrote /proc/self patch -S: Johns Hopkins University -S: Computer Science Department -S: Baltimore, Maryland 21218 -S: USA +E: bogstad@pobox.com +D: wrote /proc/self hack, minor samba & dosemu patches N: Axel Boldt E: boldt@math.ucsb.edu @@ -468,7 +464,7 @@ S: USA N: Philip Gladstone -E: philipg@onsett.com +E: philip@raptor.com D: Kernel / timekeeping stuff N: Michael A. Griffith diff -u --recursive --new-file v2.1.36/linux/Documentation/00-INDEX linux/Documentation/00-INDEX --- v2.1.36/linux/Documentation/00-INDEX Wed Jan 15 18:46:05 1997 +++ linux/Documentation/00-INDEX Mon May 12 10:35:37 1997 @@ -26,6 +26,8 @@ - plain ASCII listing of all the nodes in /dev/ with major minor #'s digiboard.txt - info on the Digiboard PC/X{i,e,eve} multiport boards. +digiepca.txt + - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards. exception.txt - how linux v2.1 handles exceptions without verify_area etc. ez.txt diff -u --recursive --new-file v2.1.36/linux/Documentation/Changes linux/Documentation/Changes --- v2.1.36/linux/Documentation/Changes Wed Apr 23 19:01:13 1997 +++ linux/Documentation/Changes Mon May 12 20:47:22 1997 @@ -29,7 +29,7 @@ Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: April 17, 1997. +Last updated: May 12, 1997. Current Author: Chris Ricker (gt1355b@prism.gatech.edu). Current Minimal Requirements @@ -40,16 +40,16 @@ - Kernel modules modutils-2.1.34 - Gnu C 2.7.2.1 -- Binutils 2.7.0.9 +- Binutils 2.8.0.3 - Linux C Library 5.4.23 - Dynamic Linker (ld.so) 1.8.5 - Linux C++ Library 2.7.2.1 - Procps 1.01 -- Mount 2.6e -- Net-tools 1.32-alpha +- Mount 2.6g +- Net-tools 1.41 - Loadlin 1.6a - Sh-utils 1.16 -- Autofs 970409 +- Autofs 0.3.0 - NFS 0.4.21 Upgrade notes @@ -131,6 +131,9 @@ To run bootpd, you'll need to issue the following command: echo 1 >/proc/sys/net/ipv4/ip_boot_agent + For support for new features like IPv6, upgrade to the latest +net-tools. + Mount and network file systems ============================== @@ -179,8 +182,7 @@ ************************************************* There are some simple methods useful to know the version of the -installed programs and libraries. The SysVinit version display -requires that you be logged in as root. +installed programs and libraries. Binutils: ld -v Gnu C: gcc -v or gcc --version @@ -190,6 +192,7 @@ Libc++: ls -l /usr/lib/libg++.so.* Modutils: insmod -V Mount: mount --version +Net-tools: hostname -V Procps: ps --version RPM: rpm --version Sh-utils: expr --v @@ -200,12 +203,12 @@ Binutils ======== -The 2.7.0.9 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.7.0.9.bin.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.7.0.9.bin.tar.gz +The 2.8.0.3 release: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.0.3.bin.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.0.3.bin.tar.gz Installation notes: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.7.0.9 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.7.0.9 +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.0.3 +ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.0.3 Gnu C ===== @@ -295,14 +298,14 @@ Mount ===== -The 2.6e release: -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6e.tar.gz +The 2.6g release: +ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6g.tar.gz Autofs ====== -The 970409 release: -ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-970409.tar.gz +The 0.3.0 release: +ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.0.tar.gz NFS === @@ -310,6 +313,13 @@ The 0.4.21 release: ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz ftp://linux.nrao.edu/pub/people/okir/linux-nfs-0.4.21.tar.gz + +Net-tools +========= + +The 0.41 release: +ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz +ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz Other Info ========== diff -u --recursive --new-file v2.1.36/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.36/linux/Documentation/Configure.help Wed Apr 23 19:01:14 1997 +++ linux/Documentation/Configure.help Mon May 12 10:35:37 1997 @@ -2072,6 +2072,20 @@ and read Documentation/modules.txt. The module will be called NCR53c406.o. +Tekram DC390W/U/F (T) SCSI support +CONFIG_SCSI_DC390W + This driver supports the Tekram DC390W/U/F (T) PCI SCSI host adapters with + the NCR/Symbios 53c825/875 chips. If you have a DC390 (T) adaptor with the + Am53C974A chip use the DC390(T) driver. + +Tekram DC390(T) (AMD PCscsi) SCSI support +CONFIG_SCSI_DC390T + This driver supports the Tekram DC390(T) PCI SCSI Hostadapter with + the Am53C974A chip, and perhaps other cards using the same chip. + + This driver does _not_ support the DC390W/U/F adaptor with the + NCR/Symbios chips. + AM53/79C974 PCI SCSI support CONFIG_SCSI_AM53C974 This is support for the AM53/79C974 SCSI host adapters. Please read @@ -4036,6 +4050,16 @@ N here so that they can use the serial port for modem, mouse or some other device. +Digi Intl. epca support +CONFIG_DIGIEPCA + This is a driver for Digi Internationals Xx, Xeve, and Xem + series of cards. This driver supports the original PC (ISA) boards as + well as PCI, and EISA. If you have a card like this, say Y here and read + the file Documentation/digiepca.txt. NOTE: This driver is seperate from + the driver written and copyrighted by Troy De Jongh. Because they both + attempt (In some cases) to access the same hardware only one of these + drivers (CONFIG_DIGIEPCA or CONFIG_DIGI) should be selected. + Digiboard PC/Xx Support CONFIG_DIGI This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards @@ -4918,9 +4942,13 @@ Amiga AutoConfig Identification CONFIG_ZORRO This enables support for automatic identification of Amiga expansion - cards that obey the AutoConfig(tm) specification. You should say Y - to this question unless you have no expansion cards and no intention - of getting any. + cards that obey the AutoConfig(tm) specification. + Say Y if you want your expansion cards to be identified on bootup; + it will enlarge your kernel by about 10KB. The identification + information is also available through /proc/zorro (say Y to + "/proc filesystem support"!). + Note that even if you say N here, you can still use your expansion + cards. If in doubt, say Y. Amiga OCS chipset support CONFIG_AMIFB_OCS @@ -4948,6 +4976,8 @@ Please note that its use is not all that intuitive (i.e. if you have any questions, be sure to ask!). Say N unless you have a Cybervision 64 or plan to get one before you next recompile the kernel. + Please note that this driver DOES NOT support the Cybervision 64 3D + card at present, as they use incompatible video chips. Amiga GSP (TMS340x0) support CONFIG_AMIGA_GSP @@ -5188,6 +5218,16 @@ want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +Atari DSP56k Digital Signal Processor support +CONFIG_ATARI_DSP56K + If you want to be able to use the DSP56001 in Falcons, say Y. + This driver is still experimental, and if you don't know what it is, + or if you don't have this processor, just say N. + This driver is also available as a module ( = code which can be inserted + in and removed from the running kernel whenever you want). If you + want to compile it as a module, say M here and read + Documentation/modules.txt. + Amiga builtin serial support CONFIG_AMIGA_BUILTIN_SERIAL If you want to use your Amiga's built-in serial port in Linux, say @@ -5317,7 +5357,7 @@ # LocalWords: mgetty sendfax gert greenie muc lowlevel Lasermate LanManager io # LocalWords: OOPSes trackball binghamton mobileip ncr IOMAPPED settags ns ser # LocalWords: setsync NEGO MPARITY autotuning prefetch PIIX cdwrite utils rc -# LocalWords: PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu +# LocalWords: PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu # LocalWords: YAMADA tetsu cauchy nslab ntt nevod perm su doc kaf kheops wsc # LocalWords: traduc Bourgin dbourgin helptext menuconfig kfill READMEs HOWTOs # LocalWords: IDEDISK IDEFLOPPY EIDE firewalls QMAGIC ZMAGIC LocalWords opti diff -u --recursive --new-file v2.1.36/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v2.1.36/linux/Documentation/devices.tex Sun Apr 13 10:18:20 1997 +++ linux/Documentation/devices.tex Mon May 12 10:35:37 1997 @@ -15,6 +15,7 @@ % \begin{document} \newcommand{\file}{\tt} % Style to use for a filename +\newcommand{\url}{\it} % Style to use for an URL \newcommand{\hex}{\tt} % Style to use for a hex number \newcommand{\ud}{(Under development)} % Abbreviation \newcommand{\1}{\({}^1\)} @@ -46,7 +47,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: April 7, 1997} +\date{Last revised: May 1, 1997} \maketitle % \noindent @@ -60,17 +61,19 @@ \LaTeX\ version is authoritative. This document is included by reference into the Linux Filesystem -Standard (FSSTND). The FSSTND is available via FTP from -tsx-11.mit.edu in the directory {\file -/pub/linux/docs/linux-standards/fsstnd}. +Standard (FSSTND). The FSSTND is available from +{\url ftp://tsx-11.mit.edu/pub/linux/docs/linux-standards/fsstnd/}. To have a major number allocated, or a minor number in situations where that applies (e.g.\ busmice), please contact me with the -appropriate device information. Also, if you have additional -information regarding any of the devices listed below, or if I have -made a mistake, I would greatly appreciate a note. When sending me -mail, {\em please\/} include the word ``device'' in the subject so -your mail won't accidentally get buried! +appropriate device information. I *very* much appreciate if you send +me a device description in the same format as the ones already in this +file. Also, if you have additional information regarding any of the +devices listed below, or if I have made a mistake, I would greatly +appreciate a note. + +NOTE: When sending me mail, {\em please\/} include the word ``device'' +in the subject so your mail won't accidentally get buried! Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga platform only. Allocations marked (68k/Atari) apply to Linux/68k on @@ -207,7 +210,9 @@ \major{79}{}{char }{PAM Software's multimodem boards -- alternate devices} \major{80}{}{char }{Photometrics AT200 CCD camera} \major{81}{}{char }{Brooktree Bt848 frame grabbers} -\major{82}{--119}{}{Unallocated} +\major{82}{}{char }{WiNRADiO communications receiver card} +\major{83}{}{char }{Teletext/videotext interfaces} +\major{84}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} \major{128}{--239}{}{Unallocated} \major{240}{--254}{}{Local/experimental use} @@ -1243,7 +1248,7 @@ \end{devicelist} \noindent -See {\em http://www.coda.cs.cmu.edu\/} for information about Coda. +See {\url http://www.coda.cs.cmu.edu\/} for information about Coda. \begin{devicelist} \major{68}{}{char }{CAPI 2.0 interface} @@ -1392,7 +1397,28 @@ \end{devicelist} \begin{devicelist} -\major{82}{--119}{}{Unallocated} +\major{82}{}{char }{WiNRADiO communications receiver card} + \major{0}{/dev/winradio0}{First WiNRADiO card} + \major{1}{/dev/winradio1}{Second WiNRADiO card} + \minordots +\end{devicelist} + +\noindent +The driver and documentation may be obtained from +{\url http://www.proximity.com.au/~brian/winradio/\/}. + +\begin{devicelist} +\major{83}{}{char }{Teletext/videotext interfaces} + \minor{0}{/dev/vtx}{Teletext decoder} + \minor{16}{/dev/vttuner}{TV tuner on teletext interface} +\end{devicelist} + +\noindent +Devices for the driver contained in the VideoteXt package. More information +on {\url http://home.pages.de/~videotext/\/}. + +\begin{devicelist} +\major{84}{--119}{}{Unallocated} \end{devicelist} \begin{devicelist} diff -u --recursive --new-file v2.1.36/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.1.36/linux/Documentation/devices.txt Sun Apr 13 10:18:20 1997 +++ linux/Documentation/devices.txt Mon May 12 10:35:37 1997 @@ -1,7 +1,7 @@ LINUX ALLOCATED DEVICES Maintained by H. Peter Anvin - Last revised: April 7, 1997 + Last revised: May 1, 1997 This list is the successor to Rick Miller's Linux Device List, which he stopped maintaining when he got busy with other things in 1993. It @@ -18,11 +18,14 @@ To have a major number allocated, or a minor number in situations where that applies (e.g. busmice), please contact me with the -appropriate device information. Also, if you have additional -information regarding any of the devices listed below, or if I have -made a mistake, I would greatly appreciate a note. When sending me -mail, *please* include the word "device" in the subject so your mail -won't accidentally get buried! +appropriate device information. I *very* much appreciate if you send +me a device description in the same format as the ones already in this +file. Also, if you have additional information regarding any of the +devices listed below, or if I have made a mistake, I would greatly +appreciate a note. + +NOTE: When sending me mail, *please* include the word "device" in the +subject so your mail won't accidentally get buried! Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga platform only. Allocations marked (68k/Atari) apply to Linux/68k on @@ -979,7 +982,22 @@ 33 = /dev/bttv-vbi1 VBI data of second Bt848 card ... - 82-119 UNALLOCATED + 82 char WiNRADiO communications receiver card + 0 = /dev/winradio0 First WiNRADiO card + 1 = /dev/winradio1 Second WiNRADiO card + ... + + The driver and documentation may be obtained from + http://www.proximity.com.au/~brian/winradio/ + + 83 char Teletext/videotext interfaces + 0 = /dev/vtx Teletext decoder + 16 = /dev/vttuner TV tuner on teletext interface + + Devices for the driver contained in the VideoteXt package. + More information on http://home.pages.de/~videotext/ + + 84-119 UNALLOCATED 120-127 LOCAL/EXPERIMENTAL USE diff -u --recursive --new-file v2.1.36/linux/Documentation/digiepca.txt linux/Documentation/digiepca.txt --- v2.1.36/linux/Documentation/digiepca.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/digiepca.txt Mon May 12 10:35:37 1997 @@ -0,0 +1,96 @@ +The Digi Intl. epca driver. +---------------------------- +The Digi Intl. epca driver for Linux supports the following boards: + +Digi PC/Xem, PC/Xr, PC/Xe, PC/Xi, PC/Xeve +Digi EISA/Xem, PCI/Xem, PCI/Xr + +Limitations: +------------ +Currently the driver only autoprobes for supported PCI boards. + +The Linux MAKEDEV command does not support generating the Digiboard +Devices. Users executing digiConfig to setup EISA and PC series cards +will have their device nodes automaticly constructed (cud?? for ~CLOCAL, +and ttyD?? for CLOCAL). Users wishing to boot their board from the LILO +prompt, or those users booting PCI cards may use buildDIGI to construct +the necessary nodes. + +Notes: +------ +This driver may be configured via LILO. For users who have already configured +their driver using digiConfig, configuring from lilo will override previous +settings. Multiple boards may be configured by issuing multiple LILO command +lines. For examples see the bottom of this document. + +Device names start at 0 and continue up. Beware of this as previous Digi +drivers started device names with 1. + +PCI boards are auto-detected and configured by the driver. PCI boards will +be allocated device numbers (internally) begining with the lowest PCI slot +first. In other words a PCI card in slot 3 will always have higher device +nodes than a PCI card in slot 1. + +LILO config examples: +--------------------- +Using LILO's APPEND command, a string of comma separated identifiers or +integers can be used to configure supported boards. The six values in order +are: + + Enable/Disable this card or Override, + Type of card: PC/Xe (AccelePort) (0), PC/Xeve (1), PC/Xem or PC/Xr (2), + EISA/Xem (3), PC/64Xe (4), PC/Xi (5), + Enable/Disable alternate pin arrangement, + Number of ports on this card, + I/O Port where card is configured (in HEX if using string identifiers), + Base of memory window (in HEX if using string identifiers), + +NOTE : PCI boards are auto-detected and configured. Do not attempt to +configure PCI boards with the LILO append comand. If you wish to override +previous configuration data (As set by digiConfig), but you do not wish to +configure any specific card (Example if there are PCI cards in the system) +the following override command will accomplish this: +-> append="digi=2" + +Samples: + append="digiepca=E,PC/Xe,D,16,200,D0000" + or + append="digi=1,0,0,16,512,851968" + +Supporting Tools: +----------------- +Supporting tools include digiDload, digiConfig, buildPCI, and ditty. See +/usr/src/linux/Documentation/README.epca.dir/user.doc for more details. Note, +this driver REQUIRES that digiDload be executed prior to it being used. +Failure to do this will result in an ENODEV error. + +The latest version of the tool package is available at: +ftp://ftp.dgii.com/drivers/linux/released/async/ + +Documentation: +-------------- +Complete documentation for this product may be found in the tool package. + +Sources of information and support: +----------------------------------- +Digi Intl. support site for this product: +-> digilnux@dgii.com + +Related information and information concerning other drivers supporting +Digi Intl. products: + +-> FTP: ftp://dgii.com +-> Webpage: http://www.dgii.com +-> Webpage: http://private.fuller.edu/clameter/digi.html +-> Mailing List: digiboard@list.fuller.edu Note write e-mail to subscribe + common ListServ commands will not work. + +Acknowledgments: +---------------- +Much of this work (And even text) was derived from a similar document +supporting the original public domain DigiBoard driver Copyright (C) +1994,1995 Troy De Jongh. Many thanks to Christoph Lameter +(clameter@fuller.edu) and Mike McLagan (mike.mclagan@linux.org) who authored +and contributed to the original document. + + diff -u --recursive --new-file v2.1.36/linux/Documentation/locks.txt linux/Documentation/locks.txt --- v2.1.36/linux/Documentation/locks.txt Thu Oct 10 21:33:33 1996 +++ linux/Documentation/locks.txt Mon May 12 10:50:31 1997 @@ -2,42 +2,30 @@ Andy Walker - 21 Sep 1996 + 12 May 1997 1. What's New? -------------- -1.1 Flock Emulation Warnings ----------------------------- -Many people will have noticed the ugly messages that the file locking -code started generating with the release of kernel version 1.3.95. The -messages look something like this: - - fcntl_setlk() called by process XX with broken flock() emulation - -This is a warning for people using older C libraries that those libraries -are still calling the pre 1.3.x flock() emulation routines, instead of -the real flock() system call. The old routines are quite badly broken, -especially with respect to parent-child lock sharing, and can give bad -results if, for example, sendmail attempts to use them. - -Fixed versions of the C libraries have been on public release for many -months. The latest versions at the time of writing are 5.3.12 (released) -or 5.4.6 (testing) for ELF. There is also a 4.7.6 release for people -using a.out systems. - -With the release of Linux 2.0 Linus decided to be lenient on the -stragglers and changed the warning message so that the kernel will only -complain once and then shut up. That should make life more bearable even -for people who, for some reason, don't want to upgrade their libraries. +1.1 Broken Flock Emulation +-------------------------- +The old flock(2) emulation in the kernel was swapped for proper BSD +compatible flock(2) support in the 1.3.x series of kernels. With the +release of the 2.1.x kernel series, support for the old emulation has +been totally removed, so that we don't need to carry this baggage +forever. + +This should not cause problems for anybody, since everybody using a +2.1.x kernel should have updated their C library to a suitable version +anyway (see the file "linux/Documentation/Changes".) -1.2 Disallow Mixed Locks ------------------------- +1.2 Allow Mixed Locks Again +--------------------------- -1.2.1 Sendmail Problems ---------------------- +1.2.1 Typical Problems - Sendmail +--------------------------------- Because sendmail was unable to use the old flock() emulation, many sendmail installations use fcntl() instead of flock(). This is true of Slackware 3.0 for example. This gave rise to some other subtle problems if sendmail was @@ -50,23 +38,17 @@ 1.2.2 The Solution ------------------ -I have chosen the rather cruel solution of disallowing mixed locking styles -on a given file at a given time. Attempts to lock a file with flock() when -fcntl() locks exist, or vice versa, return with an error status of EBUSY. -This seemed to be the only way to avoid all possible deadlock conditions, -as flock() locks do not strictly have one owner process and so can't be -checked for deadlocking in the usual manner. - -The process that created a lock with flock() might have forked multiple -children and exited. Previously the parent process would have been marked -as the owner of the lock, but deadlocks could just have easily occurred in -one or more of the children, which we would not have been able to identify -and avoid. - -Some programs may break (again, groan). In particular the aforementioned -sendmail may have problems running in 'newaliases' mode. It will no longer -deadlock though. Recompile sendmail to use flock() and your troubles will -be over. +The solution I have chosen, after much experimentation and discussion, +is to make flock() and fcntl() locks oblivious to each other. Both can +exists, and neither will have any effect on the other. + +I wanted the two lock styles to be cooperative, but there were so many +race and deadlock conditions that the current solution was the only +practical one. It puts us in the same position as, for example, SunOS +4.1.x and serveral other commercial Unices. The only OS's that support +cooperative flock()/fcntl() are those that emulate flock() using +fcntl(), with all the problems that implies. + 1.3 Mandatory Locking As A Mount Option --------------------------------------- diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/00-INDEX linux/Documentation/m68k/00-INDEX --- v2.1.36/linux/Documentation/m68k/00-INDEX Wed Dec 31 16:00:00 1969 +++ linux/Documentation/m68k/00-INDEX Mon May 12 10:35:37 1997 @@ -0,0 +1,9 @@ +00-INDEX + - this file +amiboot.txt + - info and options for the Linux/m68k Amiga bootstrap (Amiboot) +framebuffer.txt + - info about the Linux/m68k frame buffer device +kernel-options.txt + - command line options for Linux/m68k + diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/amiboot.README linux/Documentation/m68k/amiboot.README --- v2.1.36/linux/Documentation/m68k/amiboot.README Fri Dec 20 01:19:57 1996 +++ linux/Documentation/m68k/amiboot.README Wed Dec 31 16:00:00 1969 @@ -1,241 +0,0 @@ - - Linux/m68k Amiga Bootstrap version 5.1 - -------------------------------------- - - -0. Introduction ---------------- - -Amiboot is used to boot Linux/m68k on Amiga from the CLI/Shell. - -Before you try to boot Linux/m68k for the first time, please read the FAQ - - http://www-agrw.informatik.uni-kl.de/~jmayer/linux68k/linux68k-faq - -and the Installation Guide - - http://www.informatik.uni-oldenburg.de/~amigo/inst.html - -first. Although the Installation Guide is getting a bit outdated, it's still a -good starting point. - -Amiboot 5.1 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo -interface versions 1.x and 2.x). Please use an older version for older kernels. - - -1. Running Amiboot ------------------- - -The Amiboot invocation syntax looks like - - amiboot [options] [kernel command line] - -Valid options are: - - --help Display the usage information - - --kernel file Use kernel image `file' (default is `vmlinux') - - --ramdisk file Use ramdisk image `file'. - - --debug Enable debug mode - - --baud Set the serial port speed (default is 9600) - - --memfile file Use memory file `file' - - --keep-video Don't reset the video mode - - --model id Set the Amiga model to `id'. - -The kernel command line contains the options you want to pass to the kernel and -to init, the process that's started first by Linux. Please read -linux/Documentation/m68k/kernel-options.txt for more information. - -Normally you only use the --kernel option to specify the file that contains the -Linux/m68k kernel image, and --ramdisk if you want to boot from a ramdisk file, -i.e. a file containing a complete file system, instead of from a hard disk -partition. - -Example: - - amiboot -k vmlinux-2.1.13 root=/dev/hda3 video=font:PEARL8x8 - -Amiboot will boot the kernel image `vmlinux-2.1.13' and will pass -`root=/dev/hda3 video=font:PEARL8x8' to the kernel. - - -The other options are more specialized. Don't use them unless you really have -to and you know what you're doing. - -The --baud option allows you to specify the serial port speed for initial boot -information and initial kernel messages. Note: this option does not work with -kernels with bootinfo interface versions prior to 2.0. - -The --memfile option is used to specify the blocks of memory that will be used -by Linux. - -The --keep-video option is necessary if you want to retain the current graphics -mode (on a graphics board) under Linux. Currently this is only useful if you -have a CyberVision 64 graphics board. - -Finally, --model allows you to specify your Amiga model, and --debug is for -debugging purposes. - - -2. The memory file ------------------- - -If you have some non-AutoConfig memory you want to use under Linux, or if you -want to disable some parts of your memory (e.g. Zorro II RAM on '040 based -systems), you have to use a memory file and the --memfile option. This file -contains information about the memory chunks you want to use under Linux. The -format for the file is: - - chipramsize - [0xfastchunkaddr fastchunksize] - [0xfastchunkaddr fastchunksize] - ... - -For example, if you don't want Linux to use your 2nd meg of chipram, you would -create a file that looks contains only: - - 1048576 - -If you had 1M of chip ram, 2M of 16 bit FAST ram at address 0x200000 and 16M of -32 bit FAST ram at address 0x80000000, and you didn't want Linux to use the -slow 16 bit FAST ram, you'd create a file that looks like: - - 1048576 - 0x80000000 16777216 - -The memory file can also be used to specify in which block of memory the kernel -will be put. Normally Amiboot will put the kernel in the first block of Fast -RAM it will find. If you use a memory file, it will put the kernel in the first -block of fast RAM you specify. - - -3. Amiga models ---------------- - -If Amiboot incorrectly detects the model of your Amiga, you can force it to -detect any model you want using the --model option. `id' must be one of the -numbers as defined in linux/include/asm-m68k/amigahw.h (AMI_*). Currently the -following models are known: - - Model ID - ----- -- - Amiga 500 1 - Amiga 500+ 2 - Amiga 600 3 - Amiga 1000 4 - Amiga 1200 5 - Amiga 2000 6 - Amiga 2500 7 - Amiga 3000 8 - Amiga 3000T 9 - Amiga 3000+ 10 - Amiga 4000 11 - Amiga 4000T 12 - CDTV 13 - CD32 14 - Draco 15 - -Note that Amiboot can't distinguish among Amiga models that are very similar to -each other (e.g. A500/A1000/A2000/A2500 and A3000/A3000T). Of course this is -harmless and there's no real need to use --model in that case. - -Please send me the output of amiboot used with the --debug option if your Amiga -model is detected incorrectly. - - -4. Abbreviations ----------------- - -All options also have a shorthand: - - --help -h - --kernel -k - --ramdisk -r - --debug -d - --baud -b - --memfile -m - --keep-video -v - --model -t - - -5. Miscellaneous ----------------- - -Some expansion boards keep on generating interrupts once they were initialized -under AmigaOS. This can cause an interrupt deadlock while booting Linux. The -following boards are recognized and disabled: - - o Helfrich Rainbow 3 Graphics Board - o Helfrich Piccolo Graphics Board - o Helfrich SD64 Graphics Board - o Village Tronic Ariadne Ethernet Board - o Hydra Systems Amiganet Ethernet Board - -The following boards are known to cause problems but we don't have a disable -routine for them yet: - - o Commodore A2060 Arcnet Card - o Ameristar A560 Arcnet Card - -If you write a routine to disable an expansion board, please let me know. - - -6. Troubleshooting ------------------- - - - Amiboot says - - This bootstrap is too old/new for this kernel - - This means that you're using a version of Amiboot that's not compatible - with the kernel you want to boot. - - Solution: use the correct Amiboot, or use another kernel. - - - Amiboot says - - Warning: too many AutoConfig devices. Ignoring device at 0x???????? - - or - - Warning: too many memory blocks. Ignoring block of ???K at 0x???????? - - This means that you have more AutoConfig devices or memory chunks than - Amiboot supports. Note that you can still boot Linux/m68k, but that the - additional devices or memory blocks can't be used. - - Solution: increase the ZORRO_NUM_AUTO (for AutoConfig devices) or - NUM_MEMINFO (for memory chunks) values in the kernel sources - (linux/include/asm-m68k/zorro.h and linux/include/asm-m68k/setup.h) and - recompile both Amiboot and the kernel. - - - If all you get is a grey screen, or if Linux/m68k suddenly locks up during - booting, try the following things: - - o Boot with the Startup-Sequence disabled, run SetPatch and try again. - - o If that doesn't work, remove any expansion devices and retry. - - o Look at the characters that are dumped to the serial port during - booting. - - -7. Amiga-Lilo -------------- - -Once you have a stable Linux/m68k installation, you may want to try Amiga-Lilo. -Amiga-Lilo allows you to boot Linux/m68k without the overhead of booting -AmigaOS first, and it provides you with a boot menu. - - -8. Credits ----------- - -This readme was written by Geert Uytterhoeven. A lot of information was taken -from the ANNOUNCE-* files by Hamish Macdonald. diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/amiboot.txt linux/Documentation/m68k/amiboot.txt --- v2.1.36/linux/Documentation/m68k/amiboot.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/m68k/amiboot.txt Mon May 12 10:35:37 1997 @@ -0,0 +1,282 @@ + + Linux/m68k Amiga Bootstrap version 5.5 + -------------------------------------- + +Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) +Last revised: March 27, 1997 + + +0. Introduction +--------------- + +Amiboot is used to boot Linux/m68k on Amiga from the CLI/Shell. + +Before you try to boot Linux/m68k for the first time, please read the FAQ + + http://www.clark.net/pub/lawrencc/linux/faq/faq.html + +and the Installation Guide + + http://www.informatik.uni-oldenburg.de/~amigo/inst.html + +first. Although the Installation Guide is getting a bit outdated, it's still a +good starting point. + +Amiboot 5.5 is meant for Linux/m68k 2.0.x, 2.1.x or higher (kernel bootinfo +interface versions 1.x and 2.x). Please use an older version for older kernels. + + +1. Running Amiboot +------------------ + +The Amiboot invocation syntax looks like + + amiboot [options] [kernel command line] + +Basic options: + + --help Display the usage information + + --kernel file Use kernel image `file' (default is `vmlinux') + + --ramdisk file Use ramdisk image `file' + +Advanced options: + + --debug Enable debug mode + + --baud speed Set the serial port speed (default is 9600 bps) + + --memfile file Use memory file `file' + + --keep-video Don't reset the video mode + + --model id Set the Amiga model to `id' + + --processor cfm Set the processor type to `cfm' + +The kernel command line contains the options you want to pass to the kernel and +to init, the process that's started first by Linux. Please read +linux/Documentation/m68k/kernel-options.txt for more information. + +Normally you only use the --kernel option to specify the file that contains the +Linux/m68k kernel image, and --ramdisk if you want to boot from a ramdisk file, +i.e. a file containing a complete file system, instead of from a hard disk +partition. + +Note that both the kernel image and the ramdisk image can be compressed with +gzip. Amiboot knows how to deal with gzipped kernel images, and the kernel +recognizes gzipped ramdisk images. + +Example: + + amiboot -k vmlinux-2.1.13 root=/dev/hda3 video=font:PEARL8x8 + +Amiboot will boot the kernel image `vmlinux-2.1.13' and will pass +`root=/dev/hda3 video=font:PEARL8x8' to the kernel. + + +The other options are more advanced. Don't use them unless you really have to +and you know what you're doing. + +The --baud option allows you to specify the serial port speed for initial boot +information and initial kernel messages. Note: this option does not work with +kernels with bootinfo interface versions prior to 2.0. + +The --memfile option is used to specify the blocks of memory that will be used +by Linux. + +The --keep-video option is necessary if you want to retain the current graphics +mode (on a graphics board) under Linux. Currently this is only useful if you +have a CyberVision 64 graphics board. + +Finally, --model and --processor allow you to specify your Amiga model and +processor type if they are detected incorrectly, and --debug dumps some +information which simplifies debugging. + + +2. The memory file +------------------ + +If you have some non-AutoConfig memory you want to use under Linux, or if you +want to disable some parts of your memory (e.g. Zorro II RAM on '040 based +systems), you have to use a memory file and the --memfile option. This file +contains information about the memory chunks you want to use under Linux. The +format for the file is: + + chipramsize + [0xfastchunkaddr fastchunksize] + [0xfastchunkaddr fastchunksize] + ... + +For example, if you don't want Linux to use your 2nd meg of chipram, you would +create a file that contains only: + + 1048576 + +If you had 1M of chip ram, 2M of 16 bit FAST ram at address 0x200000 and 16M of +32 bit FAST ram at address 0x80000000, and you didn't want Linux to use the +slow 16 bit FAST ram, you'd create a file that looks like: + + 1048576 + 0x80000000 16777216 + +The memory file can also be used to specify in which block of memory the kernel +will be put. Normally Amiboot will put the kernel in the first block of Fast +RAM it will find. If you use a memory file, it will put the kernel in the first +block of fast RAM you specify. + + +3. Amiga models +--------------- + +If Amiboot incorrectly detects the model of your Amiga, you can force it to +detect any model you want using the --model option. `id' must be one of the +numbers as defined in linux/include/asm-m68k/amigahw.h (AMI_*). Currently the +following models are known: + + Model ID + ----- -- + Amiga 500 1 + Amiga 500+ 2 + Amiga 600 3 + Amiga 1000 4 + Amiga 1200 5 + Amiga 2000 6 + Amiga 2500 7 + Amiga 3000 8 + Amiga 3000T 9 + Amiga 3000+ 10 + Amiga 4000 11 + Amiga 4000T 12 + CDTV 13 + CD32 14 + Draco 15 + +Note that Amiboot can't distinguish among Amiga models that are very similar to +each other (e.g. A500/A1000/A2000/A2500 and A3000/A3000T). Of course this is +harmless and there's no real need to use --model in that case. + +Please send me the output of amiboot used with the --debug option if your Amiga +model is detected incorrectly. + + +4. Processor types +------------------ + +If your processor is detected incorrectly, you can override this using the +`--processor cfm' option. `cfm' must be a three-digit number with + + - `c' the CPU (Central Processing Unit) type, + - 'f' the FPU (Floating Point Unit) type, + - 'm' the MMU (Memory Management Unit) type, + +from the table below: + + value | CPU | FPU | MMU + -------+-------+-------+------- + 0 | - | - | - + 1 | 68020 | 68881 | 68851 + 2 | 68030 | 68882 | 68030 + 3 | 68040 | 68040 | 68040 + 4 | 68060 | 68060 | 68060 + +e.g. `444' if you have a 68060 and `303' if you have a 68LC040. + +Note that normally you don't have to use this option. It's only needed for some +combinations of an old Kickstart ROM and a new processor (e.g. a 68060). + + +5. Abbreviations +---------------- + +All options also have a shorthand: + + --help -h + --kernel -k + --ramdisk -r + --debug -d + --baud -b + --memfile -m + --keep-video -v + --model -t + --processor -p + + +6. Miscellaneous +---------------- + +Some expansion boards keep on generating interrupts once they were initialized +under AmigaOS. This can cause an interrupt deadlock while booting Linux. The +following boards are recognized and disabled: + + o Helfrich Rainbow 3 Graphics Board + o Helfrich Piccolo Graphics Board + o Helfrich SD64 Graphics Board + o Village Tronic Ariadne Ethernet Board + o Hydra Systems Amiganet Ethernet Board + +The following boards are known to cause problems but we don't have a disable +routine for them yet: + + o Commodore A2060 Arcnet Card + o Ameristar A560 Arcnet Card + +If you write a routine to disable an expansion board, please let me know. + + +7. Troubleshooting +------------------ + + - Amiboot says + + This bootstrap is too old/new for this kernel + + This means that you're using a version of Amiboot that's not compatible + with the kernel you want to boot. + + Solution: use the correct Amiboot, or use another kernel. + + - Amiboot says + + Warning: too many AutoConfig devices. Ignoring device at 0x???????? + + or + + Warning: too many memory blocks. Ignoring block of ???K at 0x???????? + + This means that you have more AutoConfig devices or memory chunks than + Amiboot supports. Note that you can still boot Linux/m68k, but that the + additional devices or memory blocks can't be used. + + Solution: increase the ZORRO_NUM_AUTO (for AutoConfig devices) or + NUM_MEMINFO (for memory chunks) values in the kernel sources + (linux/include/asm-m68k/zorro.h and linux/include/asm-m68k/setup.h) and + recompile both Amiboot and the kernel. + + - If all you get is a grey screen, or if Linux/m68k suddenly locks up during + booting, try the following things: + + o Boot with the Startup-Sequence disabled, run SetPatch and try again. + + o If that doesn't work, remove any expansion devices and retry. + + o Check the detected Amiga model and processor type. + + o Look at the characters that are dumped to the serial port during + booting. + + +8. Amiga-Lilo +------------- + +Once you have a stable Linux/m68k installation, you may want to try Amiga-Lilo. +Amiga-Lilo allows you to boot Linux/m68k without the overhead of booting +AmigaOS first, and it provides you with a boot menu. + + +9. Credits +---------- + +This readme was written by Geert Uytterhoeven. A lot of information was taken +from the ANNOUNCE-* files by Hamish Macdonald. diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/framebuffer.txt linux/Documentation/m68k/framebuffer.txt --- v2.1.36/linux/Documentation/m68k/framebuffer.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/m68k/framebuffer.txt Mon May 12 10:35:37 1997 @@ -0,0 +1,370 @@ + + The Linux/m68k Frame Buffer Device + ---------------------------------- + +Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) +Last revised: March 23, 1997 + + +0. Introduction +--------------- + +The frame buffer device provides an abstraction for the graphics hardware. It +represents the frame buffer of some video hardware and allows application +software to access the graphics hardware through a well-defined interface, so +the software doesn't need to know anything about the low-level (hardware +register) stuff. + +The device is accessed through special device nodes, usually located in the +/dev directory, i.e. /dev/fb*. + + +1. User's View of /dev/fb* +-------------------------- + +From the user's point of view, the frame buffer device looks just like any +other device in /dev. It's a character device using major 29, the minor is +divided into a frame buffer number in the upper 3 bits (allowing max. 8 frame +buffers simultaneously) and a resolution code in the lower 5 bits of the minor. + +By convention, the following device nodes are used (numbers indicate the device +minor numbers): + + First frame buffer + 0 = /dev/fb0current Current resolution + 1 = /dev/fb0autodetect Default resolution + 2 = /dev/fb0predefined0 Predefined resolutions (22) + ... + 23 = /dev/fb0predefined21 + 24 = /dev/fb0user0 User defined resolutions (8) + ... + 31 = /dev/fb0user7 + + Second frame buffer + 32 = /dev/fb1current Current resolution + 33 = /dev/fb1autodetect Default resolution + 34 = /dev/fb1predefined0 Predefined resolutions (22) + ... + 55 = /dev/fb1predefined21 + 56 = /dev/fb1user0 User defined resolutions (8) + ... + 63 = /dev/fb1user7 + +and so on... + +The device with (minor & 31) == 0 (/dev/fb?current) stands for the frame buffer +together with the currently set video parameters; (minor & 31) == 1 +(/dev/fb?autodetect) is the video mode detected at boot time. Any other minor +stands for some predefined or user defined video mode. + +The predefined entries (/dev/fb?predefined*) usually have a device dependent +name, e.g. for major 29, minor 5, we have /dev/fb0multiscan on Amiga and +/dev/fb0ttmid on Atari. These are meant to contain hardware dependent +resolutions. + +The user defined resolutions (/dev/fb?user?) are meant to be filled in by the +user. This way the user can store his favorite 8 resolutions during boot up. + +Note: if you need more than 8 user defined resolutions, you can always override +the predefined resolutions by storing them in one of the predefined entries. +But this is not recommended. Similarly, if there are more than 22 predefined +resolutions, the device writer can decide to store them in the user defined +entries. + +If the device is opened (for writing), the frame buffer driver switches to the +selected video mode. Thus, you can switch video modes by writing to a frame +buffer device, e.g. + + > /dev/fb0ttlow + +will switch your video to TT low mode. Note: if you specify a resolution which +contains a value that's not possible on your hardware, the frame buffer device +will round it up (if possible) or return an error condition. + +The frame buffer devices are also `normal' memory devices, this means, you can +read and write their contents. You can, for example, make a screen snapshot by + + cp /dev/fb0current myfile + +There also can be more than one frame buffer at a time, e.g. if you have a +graphics card in addition to the built-in hardware. The corresponding frame +buffer devices (/dev/fb0* and /dev/fb1* etc.) work independently. + +Application software that uses the frame buffer device (e.g. the X server) will +use /dev/fb0current by default. You can specify an alternative resolution by +setting the environment variable $FRAMEBUFFER to the path name of a frame +buffer device, e.g. (for sh/bash users): + + export FRAMEBUFFER=/dev/fb0multiscan + +or (for csh users): + + setenv FRAMEBUFFER /dev/fb0multiscan + +After this the X server will use the multiscan video mode. + + +2. Programmer's View of /dev/fb* +-------------------------------- + +As you already know, a frame buffer device is a memory device like /dev/mem and +it has the same features. You can read it, write it, seek to some location in +it and mmap() it (the main usage). The difference is just that the memory that +appears in the special file is not the whole memory, but the frame buffer of +some video hardware. + +/dev/fb* also allows several ioctls on it, by which lots of information about +the hardware can be queried and set. The color map handling works via ioctls, +too. Look into for more information on what ioctls exist and on +which data structures they work. Here's just a brief overview: + + - You can request unchangeable information about the hardware, like name, + organization of the screen memory (planes, packed pixels, ...) and address + and length of the screen memory. + + - You can request and change variable information about the hardware, like + visible and virtual geometry, depth, color map format, timing, and so on. + If you try to change that informations, the driver maybe will round up some + values to meet the hardware's capabilities (or return EINVAL if that isn't + possible). + + - You can get and set parts of the color map. Communication is done with 16 + bit per color part (red, green, blue, transparency) to support all existing + hardware. The driver does all the computations needed to bring it into the + hardware (round it down to less bits, maybe throw away transparency). + +All this hardware abstraction makes the implementation of application programs +easier and more portable. E.g. the X server works completely on /dev/fb* and +thus doesn't need to know, for example, how the color registers of the concrete +hardware are organized. XF68_FBDev is a general X server for bitmapped, +unaccelerated video hardware. The only thing that has to be built into +application programs is the screen organization (bitplanes or chunky pixels +etc.), because it works on the frame buffer image data directly. + +For the future it is planned that frame buffer drivers for graphics cards and +the like can be implemented as kernel modules that are loaded at runtime. Such +a driver just has to call register_framebuffer() and supply some functions. +Writing and distributing such drivers independently from the kernel will save +much trouble... + + +3. Frame Buffer Resolution Maintenance +-------------------------------------- + +Frame buffer resolutions are maintained using the utility `fbset'. It allows to +change the video mode properties of the current or a user defined resolution. +It's main usage is to tune video modes and to store custom resolutions into one +of the /dev/fb?user? entries, e.g. during boot up in one of your /etc/rc.* or +/etc/init.d/* files, after which those resolutions can be used by applications. + +Fbset uses a video mode database stored in a configuration file, so you can +easily add your own modes and refer to them with a simple identifier. The fbset +install script also creates the special device nodes for the device dependent +predefined resolutions. + + +4. The X Server +--------------- + +The X server (XF68_FBDev) is the most notable application program for the frame +buffer device. The current X server is part of the XFree86/XFree68 release 3.2 +package and has 2 modes: + + - If the `Display' subsection for the `fbdev' driver in the /etc/XF86Config + file contains a + + Modes "default" + + line, the X server will use the scheme discussed above, i.e. it will start + up in the resolution determined by /dev/fb0current (or $FRAMEBUFFER, if + set). This is the default for the configuration file supplied with XFree68 + 3.2. It's the most simple configuration (and the only possible one if you + want to have a broadcast compatible display, e.g. PAL or NTSC), but it has + some limitations. + + - Therefore it's also possible to specify resolutions in the /etc/XF86Config + file. This allows for on-the-fly resolution switching while retaining the + same virtual desktop size. The frame buffer device that's used is still + /dev/fb0current (or $FRAMEBUFFER), but the available resolutions are + defined by /etc/XF86Config now. The disadvantage is that you have to + specify the timings in a different format (but `fbset -x' may help) and + that you can't have a broadcast compatible display (e.g. no PAL or NTSC). + +To tune a video mode, you can use fbset or xvidtune. Note that xvidtune doesn't +work 100% with XF68_FBDev: the reported clock values are always incorrect. + +There exists also an accelerated X server for the Cybervision 64 graphics +board, but that's not discussed here. + + +5. Video Mode Timings +--------------------- + +A monitor draws an image on the screen by using an electron beam (3 electron +beams for most color models, 1 electron beam for Trinitron color monitors and +monochrone monitors). The front of the screen is covered by a pattern of +colored phospors (pixels). If a phospor is hit by an electron, it emits a +photon and thus becomes visible. + +The electron beam draws horizontal lines (scanlines) from left to right, and +from the top to the bottom of the screen. By modifying the intensity of the +electron beam, pixels with various colors and intensities can be shown. + +After each scanline the electron beam has to move back to the left side of the +screen and to the next line: this is called the horizontal retrace. After the +whole screen (frame) was painted, the beam moves back to the upper left corner: +this is called the vertical retrace. During both the horizontal and vertical +retrace, the electron beam is turned off (blanked). + +The speed at which the electron beam paints the pixels is determined by the +dotclock in the graphics board. For a dotclock of e.g. 28.37516 MHz (millions +of cycles per second), each pixel is 35242 ps (picoseconds) long: + + 1/(28.37516E6 Hz) = 35.242E-9 s + +If the screen resolution is 640x480, it will take + + 640*35.242E-9 s = 22.555E-6 s + +to paint the 640 (xres) pixels on one scanline. But the horizontal retrace +also takes time (e.g. 272 `pixels'), so a full scanline takes + + (640+272)*35.242E-9 s = 32.141E-6 s + +We'll say that the horizontal scanrate is about 31 kHz: + + 1/(32.141E-6 s) = 31.113E3 Hz + +A full screen counts 480 (yres) lines, but we have to consider the vertical +retrace too (e.g. 49 `pixels'). So a full screen will take + + (480+49)*32.141E-6 s = 17.002E-3 s + +The vertical scanrate is about 59 Hz: + + 1/(17.002E-3 s) = 58.815 Hz + +This means the screen data is refreshed about 59 times per second. To have a +stable picture without visible flicker, VESA recommends a vertical scanrate of +at least 72 Hz. But the perceived flicker is very human dependent: some people +can use 50 Hz without any trouble, while I'll notice if it's less than 80 Hz. + +Since the monitor doesn't know when a new scanline starts, the graphics board +will supply a synchronization pulse (horizontal sync or hsync) for each +scanline. Similarly it supplies a synchronization pulse (vertical sync or +vsync) for each new frame. The position of the image on the screen is +influenced by the moments at which the synchronization pulses occur. + +The following picture summarizes all timings. The horizontal retrace time is +the sum of the left margin, the right margin and the hsync length, while the +vertical retrace time is the sum of the upper margin, the lower margin and the +vsync length. + + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |upper_margin | | | + | | ¥ | | | + +----------###############################################----------+-------+ + | # ^ # | | + | # | # | | + | # | # | | + | # | # | | + | left # | # right | hsync | + | margin # | xres # margin | len | + |<-------->#<---------------+--------------------------->#<-------->|<----->| + | # | # | | + | # | # | | + | # | # | | + | # |yres # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # | # | | + | # ¥ # | | + +----------###############################################----------+-------+ + | | ^ | | | + | | |lower_margin | | | + | | ¥ | | | + +----------+---------------------------------------------+----------+-------+ + | | ^ | | | + | | |vsync_len | | | + | | ¥ | | | + +----------+---------------------------------------------+----------+-------+ + +The frame buffer device expects all horizontal timings in number of dotclocks +(in picoseconds, 1E-12 s), and vertical timings in number of scanlines. + + +6. Converting XFree86 timing values info frame buffer device timings +-------------------------------------------------------------------- + +An XFree86 mode line consists of the following fields: + "800x600" 50 800 856 976 1040 600 637 643 666 + < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL + +The frame buffer device uses the following fields: + + - pixclock: pixel clock in ps (pico seconds) + - left_margin: time from sync to picture + - right_margin: time from picture to sync + - upper_margin: time from sync to picture + - lower_margin: time from picture to sync + - hsync_len: length of horizontal sync + - vsync_len: length of vertical sync + +1) Pixelclock: + xfree: in MHz + fb: In Picoseconds (ps) + + pixclock = 1000000 / DCF + +2) horizontal timings: + left_margin = HFL - SH2 + right_margin = SH1 - HR + hsync_len = SH2 - SH1 + +3) vertical timings: + upper_margin = VFL - SV2 + lower_margin = SV1 - VR + vsync_len = SV2 - SV1 + +Good examples for VESA timings can be found in the XFree86 source tree, +under "xc/programs/Xserver/hw/xfree86/doc/modeDB.txt". + + +7. References +------------- + +For more specific information about the frame buffer device and its +applications, please refer to the following documentation: + + - The manual pages for fbset: fbset(8), fb.modes(5) + - The manual pages for XFree68: XF68_FBDev(1), XF86Config(4/5) + - The mighty kernel sources: + o linux/include/linux/fb.h + o linux/drivers/char/fbmem.c + o linux/arch/m68k/*/*fb.c + + +8. Downloading +-------------- + +All necessary files can be found at + + ftp://ftp.uni-erlangen.de/pub/Linux/LOCAL/680x0/ + +and on its mirrors. + + +9. Credits +---------- + +This readme was written by Geert Uytterhoeven, partly based on the original +`X-framebuffer.README' by Roman Hodek and Martin Schaller. Section 6 was +provided by Frank Neumann. + +The frame buffer device abstraction was designed by Martin Schaller. diff -u --recursive --new-file v2.1.36/linux/Documentation/m68k/kernel-options.txt linux/Documentation/m68k/kernel-options.txt --- v2.1.36/linux/Documentation/m68k/kernel-options.txt Fri Dec 20 01:19:57 1996 +++ linux/Documentation/m68k/kernel-options.txt Mon May 12 10:35:37 1997 @@ -800,6 +800,18 @@ No argument. Used to separate blocks of keywords when there's more than one host adapter in the system. +5.3.7) nodma +------------ + +Syntax: nodma:x + + If x is 1 (or if the option is just written as "nodma"), the WD33c93 +controller will not use DMA (= direct memory access) to access the +Amiga's memory. This is useful for some systems (like A3000's and +A4000's with the A3640 accelerator, revision 3.0) that have problems +using DMA to chip memory. The default is 0, i.e. to use DMA if +possible. + 5.4) gvp11= ----------- diff -u --recursive --new-file v2.1.36/linux/Documentation/networking/net-modules.txt linux/Documentation/networking/net-modules.txt --- v2.1.36/linux/Documentation/networking/net-modules.txt Sat Dec 21 03:16:57 1996 +++ linux/Documentation/networking/net-modules.txt Mon May 12 10:35:37 1997 @@ -109,6 +109,10 @@ 8390.c: (No public options, several other modules need this one) +a2065.c: + Since this is a Zorro board, it supports full autoprobing, even for + multiple boards. (m68k/Amiga) + ac3200.c: io = 0 (Checks 0x1000 to 0x8fff in 0x1000 intervals) irq = 0 (Read from config register) @@ -133,11 +137,24 @@ 0x310, 0x320, 0x330, 0x340, 0x350, 0x360, 0x370, 0x380, 0x390, 0x3A0, 0x3E0, 0x3F0 ) +ariadne.c: + Since this is a Zorro board, it supports full autoprobing, even for + multiple boards. (m68k/Amiga) + at1700.c: io = 0x260 irq = 0 (Probes ports: 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300) +atari_bionet.c: + Supports full autoprobing. (m68k/Atari) + +atari_pamsnet.c: + Supports full autoprobing. (m68k/Atari) + +atarilance.c: + Supports full autoprobing. (m68k/Atari) + atp.c: *Not modularized* (Probes ports: 0x378, 0x278, 0x3BC; fixed IRQs: 5 and 7 ) @@ -211,6 +228,10 @@ (Does EISA-probing, if on EISA-slot; On ISA-bus probes all ports from 0x100 thru to 0x3E0 in increments of 0x020) + +hydra.c: + Since this is a Zorro board, it supports full autoprobing, even for + multiple boards. (m68k/Amiga) ibmtr.c: io = 0xa20, 0xa24 (autoprobed by default) diff -u --recursive --new-file v2.1.36/linux/Documentation/serial-console.txt linux/Documentation/serial-console.txt --- v2.1.36/linux/Documentation/serial-console.txt Sun Feb 2 05:18:29 1997 +++ linux/Documentation/serial-console.txt Mon May 12 10:35:37 1997 @@ -47,7 +47,7 @@ Sysvinit remembers its stty settings in a file in /etc, called `/etc/ioctl.save'. REMOVE THIS FILE before using the serial console for the first time, because otherwise init will probably - set the baudrate to 38400 (bausdrate of the virtual console). + set the baudrate to 38400 (baudrate of the virtual console). 5. /dev/console and X Programs that want to do something with the virtual console usually diff -u --recursive --new-file v2.1.36/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.36/linux/MAINTAINERS Sun Apr 13 10:18:20 1997 +++ linux/MAINTAINERS Mon May 12 10:35:37 1997 @@ -336,11 +336,12 @@ W: http://www-plateau.cs.berkeley.edu/people/chaffee S: Maintained -DIGIBOARD DRIVER: -P: Christoph Lameter -M: clameter@fuller.edu -L: digiboard@list.fuller.edu -S: Maintained +DIGI INTL. EPCA DRIVER: +P: Daniel Taylor +M: support@dgii.com +M: digilnux@dgii.com +L: digiboard@list.fuller.edu +S: Maintained RISCOM8 DRIVER: P: Dmitry Gorodchanin diff -u --recursive --new-file v2.1.36/linux/Makefile linux/Makefile --- v2.1.36/linux/Makefile Wed Apr 23 19:01:14 1997 +++ linux/Makefile Mon May 12 10:35:37 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 36 +SUBLEVEL = 37 ARCH := $(shell uname -m | sed s/i.86/i386/) @@ -352,6 +352,8 @@ rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS + rm -f drivers/sound/Config.in + cp drivers/sound/Config.std drivers/sound/Config.in backup: mrproper cd .. && tar cf - linux/ | gzip -9 > backup.gz diff -u --recursive --new-file v2.1.36/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.1.36/linux/arch/alpha/defconfig Wed Apr 16 14:14:59 1997 +++ linux/arch/alpha/defconfig Mon May 12 10:35:37 1997 @@ -42,6 +42,13 @@ CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_EM86=y +# CONFIG_PNP_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set # # Floppy, IDE, and other block devices @@ -72,9 +79,10 @@ # CONFIG_FIREWALL is not set # CONFIG_NET_ALIAS is not set CONFIG_INET=y -# CONFIG_IP_FORWARD is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ACCT is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set # # (it is safe to leave these untouched) @@ -133,11 +141,11 @@ # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set -# CONFIG_SCSI_PPA is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_QLOGIC_FAS is not set CONFIG_SCSI_QLOGIC_ISP=y # CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set @@ -155,19 +163,22 @@ # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y +# CONFIG_PCNET32 is not set # CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set CONFIG_DE4X5=y # CONFIG_DEC_ELCP is not set # CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_DLCI is not set -# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_NET_RADIO is not set -# CONFIG_LAPBETHER is not set # CONFIG_SLIP is not set # CONFIG_TR is not set +# CONFIG_LAPBETHER is not set +# CONFIG_X25_ASY is not set # # ISDN subsystem @@ -192,12 +203,16 @@ CONFIG_PROC_FS=y CONFIG_NFS_FS=y # CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y # CONFIG_SMB_FS is not set CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_ROMFS_FS is not set +# CONFIG_AUTOFS_FS is not set # CONFIG_UFS_FS is not set # @@ -206,12 +221,8 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_SERIAL=y -# CONFIG_DIGI is not set -# CONFIG_CYCLADES is not set -# CONFIG_STALDRV is not set -# CONFIG_RISCOM8 is not set -# CONFIG_ESPSERIAL is not set -# CONFIG_PRINTER is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set CONFIG_MOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set @@ -224,7 +235,6 @@ # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set -CONFIG_RTC_ARC=y # # Sound diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.36/linux/arch/alpha/kernel/entry.S Wed Apr 23 19:01:14 1997 +++ linux/arch/alpha/kernel/entry.S Mon May 12 10:35:37 1997 @@ -126,7 +126,8 @@ .ent entInt entInt: SAVE_ALL - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 jsr $26,do_entInt br $31,ret_from_sys_call .end entInt @@ -147,7 +148,8 @@ stq $15,48($30) addq $30,56,$19 /* handle the fault */ - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 jsr $26,do_page_fault /* reload the registers after the exception code played. */ ldq $9,0($30) @@ -167,7 +169,8 @@ .ent entArith entArith: SAVE_ALL - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 /* How much of a win is this clockwise? We are, after all, messing up the call/return prefetch stack. -- rth */ lda $27,do_entArith @@ -180,7 +183,8 @@ .ent entIF entIF: SAVE_ALL - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 lda $27,do_entIF lda $26,ret_from_sys_call jsr $31,($27),do_entIF @@ -221,12 +225,13 @@ .globl __kernel_thread .ent __kernel_thread __kernel_thread: + ldgp $29,0($27) /* we can be called from a module */ .frame $30, 4*8, $26 subq $30,4*8,$30 stq $10,16($30) stq $9,8($30) stq $26,0($30) - .prologue 0 + .prologue 1 bis $17,$17,$9 /* save fn */ bis $18,$18,$10 /* save arg */ bsr $26,kernel_clone @@ -238,10 +243,9 @@ ret $31,($26),1 /* this is in child: look out as we don't have any stack here.. */ 1: bis $9,$9,$27 /* get fn */ - br $29,2f -2: ldgp $29,0($29) + lda $8,0x3fff bis $10,$10,$16 /* get arg */ - ldq $8,current_set + bic $30,$8,$8 /* get current */ jsr $26,($27) bis $0,$0,$16 jsr $26,sys_exit @@ -382,7 +386,8 @@ stq $29,232($30) stq $30,240($30) stq $31,248($30) - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 jsr $26,do_entUna ldq $0,0($30) ldq $1,8($30) @@ -432,7 +437,8 @@ stq $14,40($30) stq $15,48($30) bis $31,$30,$19 - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 jsr $26,do_entUnaUser ldq $9,0($30) ldq $10,8($30) @@ -497,7 +503,8 @@ .ent entSys entSys: SAVE_ALL - ldq $8,current_set + lda $8,0x3fff + bic $30,$8,$8 lda $4,NR_SYSCALLS($31) stq $16,SP_OFF+24($30) lda $5,sys_call_table @@ -532,7 +539,7 @@ ret_from_reschedule: lda $0,need_resched ldl $2,0($0) - lda $4,init_task + lda $4,init_task_union bne $2,reschedule xor $4,$8,$4 beq $4,restore_all diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.1.36/linux/arch/alpha/kernel/head.S Wed Apr 16 14:14:59 1997 +++ linux/arch/alpha/kernel/head.S Mon May 12 10:35:37 1997 @@ -23,9 +23,11 @@ __start: br $27,1f 1: ldgp $29,0($27) - /* We need to get current loaded up with our first task. */ - ldq $8,current_set - /* And then we can start the kernel. */ + /* We need to get current loaded up with our first task... */ + lda $8,init_task_union + /* ... and find our stack ... */ + lda $30,0x4000($8) + /* ... and then we can start the kernel. */ jsr $26,start_kernel halt .end __start @@ -61,22 +63,6 @@ call_pal PAL_rdusp ret ($26) .end rdusp - - .align 3 - .globl tbi - .ent tbi -tbi: - call_pal PAL_tbi - ret ($26) - .end tbi - - .align 3 - .globl imb - .ent imb -imb: - call_pal PAL_imb - ret ($26) - .end imb .align 3 .globl rdmces diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.1.36/linux/arch/alpha/kernel/process.c Wed Apr 23 19:01:14 1997 +++ linux/arch/alpha/kernel/process.c Mon May 12 10:35:37 1997 @@ -37,6 +37,24 @@ #include #include #include +#include + +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ + +unsigned long init_user_stack[1024] = { STACK_MAGIC, }; +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +union task_union init_task_union __attribute__((section("init_task"))) + = { task: INIT_TASK }; /* * No need to acquire the kernel lock, we're entirely local.. @@ -186,7 +204,7 @@ stack_offset = PAGE_SIZE - sizeof(struct pt_regs); if (!(regs->ps & 8)) stack_offset = (PAGE_SIZE-1) & (unsigned long) regs; - childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset); + childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p); *childregs = *regs; childregs->r0 = 0; diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.1.36/linux/arch/alpha/kernel/ptrace.c Sun Jan 26 03:40:45 1997 +++ linux/arch/alpha/kernel/ptrace.c Mon May 12 10:35:37 1997 @@ -67,7 +67,7 @@ * | | | * | | v * +================================+ <------------------------- - * task->kernel_stack_page + * task + PAGE_SIZE */ #define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \ + (long)&((struct pt_regs *)0)->reg) @@ -107,19 +107,6 @@ static long zero; - -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * Get contents of register REGNO in task TASK. */ @@ -133,7 +120,7 @@ zero = 0; addr = &zero; } else { - addr = (long *) (task->kernel_stack_page + regoff[regno]); + addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task); } return *addr; } @@ -150,7 +137,7 @@ } else if (regno == 31) { addr = &zero; } else { - addr = (long *) (task->kernel_stack_page + regoff[regno]); + addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task); } *addr = data; return 0; @@ -507,7 +494,7 @@ if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) goto out; if (request == PTRACE_ATTACH) { ret = -EPERM; diff -u --recursive --new-file v2.1.36/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.1.36/linux/arch/alpha/kernel/setup.c Wed Apr 16 14:14:59 1997 +++ linux/arch/alpha/kernel/setup.c Mon May 12 10:35:37 1997 @@ -21,9 +21,9 @@ #include #include #include /* CONFIG_ALPHA_LCA etc */ +#include #ifdef CONFIG_RTC -#include #include #endif diff -u --recursive --new-file v2.1.36/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.1.36/linux/arch/alpha/mm/init.c Wed Apr 23 19:01:14 1997 +++ linux/arch/alpha/mm/init.c Mon May 12 10:35:37 1997 @@ -133,7 +133,6 @@ init_task.tss.ptbr = newptbr; init_task.tss.pal_flags = 1; /* set FEN, clear everything else */ init_task.tss.flags = 0; - init_task.kernel_stack_page = INIT_STACK; load_PCB(&init_task.tss); flush_tlb_all(); @@ -182,7 +181,7 @@ atomic_set(&mem_map[MAP_NR(addr)].count, 1); free_page(addr); } - printk ("Freeing unused kernel memory: %dk freed\n", + printk ("Freeing unused kernel memory: %ldk freed\n", (&__init_end - &__init_begin) >> 10); } diff -u --recursive --new-file v2.1.36/linux/arch/alpha/vmlinux.lds linux/arch/alpha/vmlinux.lds --- v2.1.36/linux/arch/alpha/vmlinux.lds Wed Apr 23 19:01:14 1997 +++ linux/arch/alpha/vmlinux.lds Mon May 12 10:35:37 1997 @@ -5,6 +5,7 @@ . = 0xfffffc0000310000; _text = .; .text : { *(.text) } + .text2 : { *(.text2) } _etext = .; /* Exception table */ @@ -25,8 +26,11 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } - . = ALIGN(8192); + . = ALIGN(2*8192); /* Align double page for init_task_union */ __init_end = .; + + /* The initial task and kernel stack */ + init_task : { *(init_task) } /* Global data */ _data = .; diff -u --recursive --new-file v2.1.36/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.1.36/linux/arch/i386/Makefile Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/Makefile Mon May 12 10:35:37 1997 @@ -45,7 +45,7 @@ CFLAGS := $(CFLAGS) -D__SMP__ endif -HEAD := arch/i386/kernel/head.o +HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) @@ -85,7 +85,7 @@ @$(MAKEBOOT) BOOTIMAGE=bzImage zdisk install: vmlinux - @$(MAKEBOOT) install + @$(MAKEBOOT) BOOTIMAGE=zImage install archclean: @$(MAKEBOOT) clean diff -u --recursive --new-file v2.1.36/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.36/linux/arch/i386/defconfig Mon Apr 14 16:28:06 1997 +++ linux/arch/i386/defconfig Mon May 12 10:53:01 1997 @@ -141,6 +141,7 @@ # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.1.36/linux/arch/i386/kernel/Makefile Sun Jan 26 02:07:04 1997 +++ linux/arch/i386/kernel/Makefile Mon May 12 10:35:37 1997 @@ -15,7 +15,7 @@ $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o endif -all: kernel.o head.o +all: kernel.o head.o init_task.o O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \ diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.1.36/linux/arch/i386/kernel/bios32.c Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/bios32.c Mon May 12 10:35:37 1997 @@ -52,6 +52,9 @@ * Feb 3, 1997 : Set internal functions to static, save/restore flags * avoid dead locks reading broken PCI BIOS, werner@suse.de * + * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS + * (mj@atrey.karlin.mff.cuni.cz) + * */ #include @@ -173,10 +176,10 @@ case 0: return address + entry; case 0x80: /* Not present */ - printk("bios32_service(%ld) : not present\n", service); + printk("bios32_service(0x%lx) : not present\n", service); return 0; default: /* Shouldn't happen */ - printk("bios32_service(%ld) : returned 0x%x, mail drew@colorado.edu\n", + printk("bios32_service(0x%lx) : returned 0x%x, mail drew@colorado.edu\n", service, return_code); return 0; } @@ -189,7 +192,7 @@ } pci_indirect = { 0, KERNEL_CS }; -__initfunc(static unsigned long check_pcibios(unsigned long memory_start, unsigned long memory_end)) +__initfunc(static int check_pcibios(void)) { unsigned long signature; unsigned char present_status; @@ -212,7 +215,7 @@ : "1" (PCIBIOS_PCI_BIOS_PRESENT), "D" (&pci_indirect) : "bx", "cx"); - restore_flags(flags); + restore_flags(flags); present_status = (pack >> 16) & 0xff; major_revision = (pack >> 8) & 0xff; @@ -232,9 +235,10 @@ if (pcibios_entry) { printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n", major_revision, minor_revision, pcibios_entry); + return 1; } } - return memory_start; + return 0; } @@ -912,13 +916,11 @@ bios32_entry = check->fields.entry; printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry); bios32_indirect.address = bios32_entry + PAGE_OFFSET; - access_pci = &pci_bios_access; } } } - if (bios32_entry) { - memory_start = check_pcibios (memory_start, memory_end); - } + if (bios32_entry && check_pcibios()) + access_pci = &pci_bios_access; #endif return memory_start; } diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.36/linux/arch/i386/kernel/entry.S Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/entry.S Mon May 12 10:35:37 1997 @@ -110,62 +110,45 @@ addl $4,%esp; \ iret -#ifdef __SMP__ -/* Get the processor ID multiplied by 4 */ -#define GET_PROCESSOR_OFFSET(reg) \ - movl SYMBOL_NAME(apic_reg), reg; \ - movl 32(reg), reg; \ - shrl $22, reg; \ - andl $0x3C, reg; - -#define GET_CURRENT(reg) \ - GET_PROCESSOR_OFFSET(reg) \ - movl SYMBOL_NAME(current_set)(reg),reg - -#else - #define GET_CURRENT(reg) \ - movl SYMBOL_NAME(current_set),reg - -#endif + movl %esp, reg; \ + andl $-8192, reg; ENTRY(lcall7) pushfl # We get a different stack layout with call gates, pushl %eax # which has to be cleaned up later.. SAVE_ALL - GET_CURRENT(%ebx) movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. movl CS(%esp),%edx # this is eip.. movl EFLAGS(%esp),%ecx # and this is cs.. movl %eax,EFLAGS(%esp) # movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # - movl %esp,%eax - GET_CURRENT(%edx) - pushl %eax - movl exec_domain(%edx),%edx # Get the execution domain + movl %esp,%ebx + pushl %ebx + andl $-8192,%ebx # GET_CURRENT + movl exec_domain(%ebx),%edx # Get the execution domain movl 4(%edx),%edx # Get the lcall7 handler for the domain call *%edx popl %eax jmp ret_from_sys_call + #ifdef __SMP__ ALIGN .globl ret_from_smpfork ret_from_smpfork: + GET_CURRENT(%ebx) btrl $0, SYMBOL_NAME(scheduler_lock) jmp ret_from_sys_call #endif /* __SMP__ */ - ALIGN -handle_bottom_half: - pushl $2f - jmp SYMBOL_NAME(do_bottom_half) - - ALIGN -reschedule: - pushl $ret_from_sys_call - jmp SYMBOL_NAME(schedule) # test +/* + * Return to user mode is not as complex as all this looks, + * but we want the default path for a system call return to + * go as quickly as possible which is why some of this is + * less clear than it otherwise should be. + */ ENTRY(system_call) pushl %eax # save orig_eax @@ -180,16 +163,11 @@ ALIGN .globl ret_from_sys_call .globl ret_from_intr -ret_from_intr: ret_from_sys_call: - GET_CURRENT(%ebx) movl SYMBOL_NAME(bh_mask),%eax andl SYMBOL_NAME(bh_active),%eax jne handle_bottom_half -2: movl EFLAGS(%esp),%eax # mix EFLAGS and CS - movb CS(%esp),%al - testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? - je 1f +ret_with_reschedule: cmpl $0,SYMBOL_NAME(need_resched) jne reschedule movl blocked(%ebx),%eax @@ -197,7 +175,6 @@ notl %eax andl signal(%ebx),%eax jne signal_return -1: RESTORE_ALL ALIGN signal_return: @@ -230,6 +207,30 @@ movl $-ENOSYS,EAX(%esp) jmp ret_from_sys_call + ALIGN +ret_from_exception: + movl SYMBOL_NAME(bh_mask),%eax + andl SYMBOL_NAME(bh_active),%eax + jne handle_bottom_half + ALIGN +ret_from_intr: + GET_CURRENT(%ebx) + movl EFLAGS(%esp),%eax # mix EFLAGS and CS + movb CS(%esp),%al + testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? + jne ret_with_reschedule + RESTORE_ALL + + ALIGN +handle_bottom_half: + pushl $ret_from_intr + jmp SYMBOL_NAME(do_bottom_half) + + ALIGN +reschedule: + pushl $ret_from_sys_call + jmp SYMBOL_NAME(schedule) # test + ENTRY(divide_error) pushl $0 # no error code @@ -260,7 +261,7 @@ GET_CURRENT(%ebx) call *%ecx addl $8,%esp - jmp ret_from_sys_call + jmp ret_from_exception ENTRY(coprocessor_error) pushl $0 @@ -271,7 +272,7 @@ pushl $-1 # mark this as an int SAVE_ALL GET_CURRENT(%ebx) - pushl $ret_from_sys_call + pushl $ret_from_exception movl %cr0,%eax testl $0x4,%eax # EM (math emulation bit) je SYMBOL_NAME(math_state_restore) diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.1.36/linux/arch/i386/kernel/head.S Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/head.S Mon May 12 10:35:37 1997 @@ -39,19 +39,21 @@ jz 1f /* * New page tables may be in 4Mbyte page mode and may - * be using the global pages. + * be using the global pages. + * + * NOTE! We have to correct for the fact that we're + * not yet offset 0xC0000000.. */ +#define cr4_bits mmu_cr4_features-0xC0000000 #ifdef GAS_KNOWS_CR4 movl %cr4,%eax # Turn on 4Mb pages - orl $16+128,%eax + orl cr4_bits,%eax movl %eax,%cr4 #else .byte 0x0f,0x20,0xe0 - orl $16+128,%eax + orl cr4_bits,%eax .byte 0x0f,0x22,0xe0 #endif - movl %eax,%cr3 /* flush TLB as per app note */ - movl %cr0,%eax #endif /* * Setup paging (the tables are already set up, just switch them on) @@ -67,24 +69,16 @@ movl $1f,%eax jmp *%eax /* make sure eip is relocated */ 1: + /* Set up the stack pointer */ + lss stack_start,%esp #ifdef __SMP__ orw %bx,%bx jz 1f /* Initial CPU cleans BSS */ -/* - * Set up the stack - */ - movl $(KERNEL_DS),%eax /* walken modif */ - mov %ax,%ss - xorl %eax,%eax - movw %cx, %ax - movl %eax,%esp - addl $0xC0000000, %esp /* shift it to the upper mapping */ pushl $0 popfl jmp checkCPUtype 1: - lss stack_start,%esp #endif __SMP__ /* * Clear BSS first so that there are no surprises... @@ -305,15 +299,53 @@ jne rp_sidt ret +ENTRY(stack_start) + .long SYMBOL_NAME(init_task_union)+8192 + .long KERNEL_DS + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n" + ALIGN +ignore_int: + cld + pushl %eax + pushl %ecx + pushl %edx + push %ds + movl $(KERNEL_DS),%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + pushl $int_msg + call SYMBOL_NAME(printk) + popl %eax + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +/* + * The interrupt descriptor table has room for 256 idt's + */ + ALIGN +.word 0 +idt_descr: + .word 256*8-1 # idt contains 256 entries + .long SYMBOL_NAME(idt) + + ALIGN +.word 0 +gdt_descr: +#ifdef CONFIG_APM + .word (11+2*NR_TASKS)*8-1 +#else + .word (8+2*NR_TASKS)*8-1 +#endif + .long SYMBOL_NAME(gdt) /* - * page 0 is made non-existent, so that kernel NULL pointer references get - * caught. Thus the swapper page directory has been moved to 0x101000 - * with the introduction of the compressed boot code. Theoretically, - * the original design of overlaying the startup code with the swapper - * page directory is still possible --- it would reduce the size of the kernel - * by 2-3k. This would be a good thing to do at some point..... - * * This is initialized to create a identity-mapping at 0-4M (for bootup * purposes) and another mapping of the 0-4M area at virtual address * 0xC0000000. @@ -471,63 +503,29 @@ ENTRY(empty_zero_page) .org 0x6000 - -stack_start: - .long SYMBOL_NAME(init_user_stack)+4096 - .long KERNEL_DS - -/* This is the default interrupt "handler" :-) */ -int_msg: - .asciz "Unknown interrupt\n" - ALIGN -ignore_int: - cld - pushl %eax - pushl %ecx - pushl %edx - push %ds - push %es - push %fs - movl $(KERNEL_DS),%eax - mov %ax,%ds - mov %ax,%es - mov %ax,%fs - pushl $int_msg - call SYMBOL_NAME(printk) - popl %eax - pop %fs - pop %es - pop %ds - popl %edx - popl %ecx - popl %eax - iret +ENTRY(this_must_match_init_task) /* - * The interrupt descriptor table has room for 256 idt's + * This starts the data section. Note that the above is all + * in the text section because it has alignment requirements + * that we cannot fulfill any other way. */ - ALIGN -.word 0 -idt_descr: - .word 256*8-1 # idt contains 256 entries - .long SYMBOL_NAME(idt) +.data +ALIGN +/* 256 quadwords - 2048 bytes of idt */ ENTRY(idt) .fill 256,8,0 # idt is uninitialized - ALIGN -.word 0 -gdt_descr: -#ifdef CONFIG_APM - .word (11+2*NR_TASKS)*8-1 -#else - .word (8+2*NR_TASKS)*8-1 -#endif - .long SYMBOL_NAME(gdt) - /* * This gdt setup gives the kernel a 1GB address space at virtual * address 0xC0000000 - space enough for expansion, I hope. + * + * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of + * gdt entries. Ugh. + * + * NOTE! Make sure the gdt descriptor in head.S matches this if you + * change anything. */ ENTRY(gdt) .quad 0x0000000000000000 /* NULL descriptor */ diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.1.36/linux/arch/i386/kernel/i386_ksyms.c Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/i386_ksyms.c Mon May 12 10:35:37 1997 @@ -39,12 +39,13 @@ #ifdef __SMP__ EXPORT_SYMBOL(apic_reg); /* Needed internally for the I386 inlines */ EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(kernel_flag); -EXPORT_SYMBOL(active_kernel_processor); +EXPORT_SYMBOL_NOVERS(kernel_flag); +EXPORT_SYMBOL_NOVERS(active_kernel_processor); EXPORT_SYMBOL(smp_invalidate_needed); EXPORT_SYMBOL_NOVERS(__lock_kernel); /* Global SMP irq stuff */ +EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c --- v2.1.36/linux/arch/i386/kernel/init_task.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/kernel/init_task.c Mon May 12 10:35:37 1997 @@ -0,0 +1,22 @@ +#include +#include + +#include + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +/* + * Initial task structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by making sure + * the linker maps this in the .text segment right after head.S, + * and making head.S ensure the proper alignment. + * + * The things we do for performance.. + */ +union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.36/linux/arch/i386/kernel/irq.c Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/irq.c Mon May 12 10:35:37 1997 @@ -44,9 +44,6 @@ #define CR0_NE 32 -static unsigned char cache_21 = 0xff; -static unsigned char cache_A1 = 0xff; - unsigned int local_irq_count[NR_CPUS]; #ifdef __SMP__ atomic_t __intel_bh_counter; @@ -58,51 +55,84 @@ static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},}; #endif -static inline void mask_irq(unsigned int irq_nr) -{ - unsigned char mask; +/* + * This contains the irq mask for both irq controllers + */ +static unsigned int cached_irq_mask = 0xffff; + +#define cached_21 (((char *)(&cached_irq_mask))[0]) +#define cached_A1 (((char *)(&cached_irq_mask))[1]) - mask = 1 << (irq_nr & 7); - if (irq_nr < 8) { - cache_21 |= mask; - outb(cache_21,0x21); +spinlock_t irq_controller_lock; + +/* + * This is always called from an interrupt context + * with local interrupts disabled. Don't worry about + * irq-safe locks. + * + * Note that we always ack the primary irq controller, + * even if the interrupt came from the secondary, as + * the primary will still have routed it. Oh, the joys + * of PC hardware. + */ +static inline void mask_and_ack_irq(int irq_nr) +{ + spin_lock(&irq_controller_lock); + cached_irq_mask |= 1 << irq_nr; + if (irq_nr & 8) { + inb(0xA1); /* DUMMY */ + outb(cached_A1,0xA1); + outb(0x20,0xA0); } else { - cache_A1 |= mask; - outb(cache_A1,0xA1); + inb(0x21); /* DUMMY */ + outb(cached_21,0x21); } + outb(0x20,0x20); + spin_unlock(&irq_controller_lock); } -static inline void unmask_irq(unsigned int irq_nr) +static inline void set_irq_mask(int irq_nr) { - unsigned char mask; - - mask = ~(1 << (irq_nr & 7)); - if (irq_nr < 8) { - cache_21 &= mask; - outb(cache_21,0x21); + if (irq_nr & 8) { + outb(cached_A1,0xA1); } else { - cache_A1 &= mask; - outb(cache_A1,0xA1); + outb(cached_21,0x21); } } +/* + * These have to be protected by the spinlock + * before being called. + */ +static inline void mask_irq(unsigned int irq_nr) +{ + cached_irq_mask |= 1 << irq_nr; + set_irq_mask(irq_nr); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + cached_irq_mask &= ~(1 << irq_nr); + set_irq_mask(irq_nr); +} + void disable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&irq_controller_lock, flags); mask_irq(irq_nr); - restore_flags(flags); + spin_unlock_irqrestore(&irq_controller_lock, flags); + synchronize_irq(); } void enable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + + spin_lock_irqsave(&irq_controller_lock, flags); unmask_irq(irq_nr); - restore_flags(flags); + spin_unlock_irqrestore(&irq_controller_lock, flags); } /* @@ -133,7 +163,8 @@ #error make irq stub building NR_IRQS dependent and remove me. #endif -BUILD_TIMER_IRQ(FIRST,0,0x01) +BUILD_COMMON_IRQ() +BUILD_IRQ(FIRST,0,0x01) BUILD_IRQ(FIRST,1,0x02) BUILD_IRQ(FIRST,2,0x04) BUILD_IRQ(FIRST,3,0x08) @@ -157,10 +188,6 @@ BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt) #endif -/* - * Pointers to the low-level handlers: first the general ones, then the - * fast ones, then the bad ones. - */ static void (*interrupt[17])(void) = { IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt, IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, @@ -168,28 +195,6 @@ IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt }; -static void (*fast_interrupt[16])(void) = { - fast_IRQ0_interrupt, fast_IRQ1_interrupt, - fast_IRQ2_interrupt, fast_IRQ3_interrupt, - fast_IRQ4_interrupt, fast_IRQ5_interrupt, - fast_IRQ6_interrupt, fast_IRQ7_interrupt, - fast_IRQ8_interrupt, fast_IRQ9_interrupt, - fast_IRQ10_interrupt, fast_IRQ11_interrupt, - fast_IRQ12_interrupt, fast_IRQ13_interrupt, - fast_IRQ14_interrupt, fast_IRQ15_interrupt -}; - -static void (*bad_interrupt[16])(void) = { - bad_IRQ0_interrupt, bad_IRQ1_interrupt, - bad_IRQ2_interrupt, bad_IRQ3_interrupt, - bad_IRQ4_interrupt, bad_IRQ5_interrupt, - bad_IRQ6_interrupt, bad_IRQ7_interrupt, - bad_IRQ8_interrupt, bad_IRQ9_interrupt, - bad_IRQ10_interrupt, bad_IRQ11_interrupt, - bad_IRQ12_interrupt, bad_IRQ13_interrupt, - bad_IRQ14_interrupt, bad_IRQ15_interrupt -}; - /* * Initial irq handlers. */ @@ -240,14 +245,10 @@ action = irq_action[i]; if (!action) continue; - len += sprintf(buf+len, "%2d: %10u %c %s", - i, kstat.interrupts[i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); + len += sprintf(buf+len, "%2d: %10u %s", + i, kstat.interrupts[i], action->name); for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); + len += sprintf(buf+len, ", %s", action->name); } len += sprintf(buf+len, "\n"); } @@ -298,13 +299,9 @@ for (j=0;jflags & SA_INTERRUPT) ? '+' : ' ', - action->name); + len += sprintf(buf+len, " %s", action->name); for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); + len += sprintf(buf+len, ", %s", action->name); } len += sprintf(buf+len, "\n"); } @@ -393,16 +390,8 @@ static unsigned long previous_irqholder; -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } - static inline void wait_on_irq(int cpu, unsigned long where) { - int stuck = INIT_STUCK; int local_count = local_irq_count[cpu]; /* Are we the only one in an interrupt context? */ @@ -421,13 +410,12 @@ * their things before trying to get the lock again. */ for (;;) { - STUCK; check_smp_invalidate(cpu); if (atomic_read(&global_irq_count)) continue; if (global_irq_lock) continue; - if (!set_bit(0,&global_irq_lock)) + if (!test_and_set_bit(0,&global_irq_lock)) break; } atomic_add(local_count, &global_irq_count); @@ -456,28 +444,18 @@ } } -#undef INIT_STUCK -#define INIT_STUCK 10000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} - static inline void get_irqlock(int cpu, unsigned long where) { - int stuck = INIT_STUCK; - - if (set_bit(0,&global_irq_lock)) { + if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ if ((unsigned char) cpu == global_irq_holder) return; /* Uhhuh.. Somebody else got it. Wait.. */ do { do { - STUCK; check_smp_invalidate(cpu); } while (test_bit(0,&global_irq_lock)); - } while (set_bit(0,&global_irq_lock)); + } while (test_and_set_bit(0,&global_irq_lock)); } /* * Ok, we got the lock bit. @@ -519,7 +497,8 @@ { switch (flags) { case 0: - __global_sti(); + release_irqlock(smp_processor_id()); + __sti(); break; case 1: __global_cli(); @@ -533,56 +512,58 @@ #endif /* - * do_IRQ handles IRQ's that have been installed without the - * SA_INTERRUPT flag: it uses the full signal-handling return - * and runs with other interrupts enabled. All relatively slow - * IRQ's should use this format: notably the keyboard/timer - * routines. + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). */ -asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +asmlinkage void do_IRQ(struct pt_regs regs) { + int irq = regs.orig_eax & 0xff; struct irqaction * action; - int do_random, cpu = smp_processor_id(); + int status, cpu; + + /* + * mask and ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + */ + mask_and_ack_irq(irq); + cpu = smp_processor_id(); irq_enter(cpu, irq); kstat.interrupts[irq]++; - /* slow interrupts run with interrupts enabled */ - __sti(); + /* Return with this interrupt masked if no action */ + status = 0; action = *(irq + irq_action); - do_random = 0; - while (action) { - do_random |= action->flags; - action->handler(irq, action->dev_id, regs); - action = action->next; - } - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - irq_exit(cpu, irq); -} - -/* - * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return - * stuff - the handler is also running with interrupts disabled unless - * it explicitly enables them later. - */ -asmlinkage void do_fast_IRQ(int irq) -{ - struct irqaction * action; - int do_random, cpu = smp_processor_id(); + if (action) { + do { + status |= action->flags; + action->handler(irq, action->dev_id, ®s); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); - irq_enter(cpu, irq); - kstat.interrupts[irq]++; - action = *(irq + irq_action); - do_random = 0; - while (action) { - do_random |= action->flags; - action->handler(irq, action->dev_id, NULL); - action = action->next; + __cli(); + spin_lock(&irq_controller_lock); + unmask_irq(irq); + spin_unlock(&irq_controller_lock); } - if (do_random & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); + irq_exit(cpu, irq); + /* + * This should be conditional: we should really get + * a return code from the irq handler to tell us + * whether the handler wants us to do software bottom + * half handling or not.. + */ + if (1) { + if (bh_active & bh_mask) + do_bottom_half(); + } } int setup_x86_irq(int irq, struct irqaction * new) @@ -597,10 +578,6 @@ if (!(old->flags & new->flags & SA_SHIRQ)) return -EBUSY; - /* Can't share interrupts unless both are same type */ - if ((old->flags ^ new->flags) & SA_INTERRUPT) - return -EBUSY; - /* add new interrupt at end of irq queue */ do { p = &old->next; @@ -617,11 +594,9 @@ *p = new; if (!shared) { - if (new->flags & SA_INTERRUPT) - set_intr_gate(0x20+irq,fast_interrupt[irq]); - else - set_intr_gate(0x20+irq,interrupt[irq]); + spin_lock(&irq_controller_lock); unmask_irq(irq); + spin_unlock(&irq_controller_lock); } restore_flags(flags); return 0; @@ -676,10 +651,6 @@ save_flags(flags); cli(); *p = action->next; - if (!irq[irq_action]) { - mask_irq(irq); - set_intr_gate(0x20+irq,bad_interrupt[irq]); - } restore_flags(flags); kfree(action); return; @@ -689,7 +660,7 @@ unsigned long probe_irq_on (void) { - unsigned int i, irqs = 0, irqmask; + unsigned int i, irqs = 0; unsigned long delay; /* first, enable any unassigned irqs */ @@ -705,19 +676,17 @@ /* about 100ms delay */; /* now filter out any obviously spurious interrupts */ - irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; - return irqs & ~irqmask; + return irqs & ~cached_irq_mask; } int probe_irq_off (unsigned long irqs) { - unsigned int i, irqmask; + unsigned int i; - irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; #ifdef DEBUG - printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, irqmask); + printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, cached_irq_mask); #endif - irqs &= irqmask; + irqs &= cached_irq_mask; if (!irqs) return 0; i = ffz(~irqs); @@ -729,10 +698,6 @@ __initfunc(void init_IRQ(void)) { int i; - static unsigned char smptrap=0; - if(smptrap) - return; - smptrap=1; /* set the clock to 100 Hz */ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ @@ -740,7 +705,7 @@ outb(LATCH >> 8 , 0x40); /* MSB */ for (i = 0; i < NR_IRQS ; i++) - set_intr_gate(0x20+i,bad_interrupt[i]); + set_intr_gate(0x20+i,interrupt[i]); #ifdef __SMP__ /* diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h --- v2.1.36/linux/arch/i386/kernel/irq.h Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/irq.h Mon May 12 10:35:37 1997 @@ -33,7 +33,6 @@ static inline void irq_exit(int cpu, int irq) { - __cli(); hardirq_exit(cpu); release_irqlock(cpu); } @@ -64,18 +63,8 @@ "mov %dx,%es\n\t" /* - * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers, - * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't - * call the routines that do signal handling etc on return, and can have - * more relaxed register-saving etc. They are also atomic, and are thus - * suited for small, fast interrupts like the serial lines or the harddisk - * drivers, which don't actually need signal handling etc. - * - * Also note that we actually save only those registers that are used in - * C subroutines (%eax, %edx and %ecx), so if you do something weird, - * you're on your own. The only segments that are saved (not counting the - * automatic stack and code segment handling) are %ds and %es, and they - * point to kernel space. No messing around with %fs here. + * These are used just for the "bad" interrupt handlers, + * which just clear the mask and return.. */ #define SAVE_MOST \ "cld\n\t" \ @@ -96,92 +85,13 @@ "pop %es\n\t" \ "iret" -/* - * Some fast irq handlers might want to access saved registers (mostly - * cs or flags) - */ - -struct fast_irq_regs { - long ecx; - long edx; - long eax; - int xds; - int xes; - long eip; - int xcs; - long eflags; - long esp; - int xss; -}; - -/* - * The "inb" instructions are not needed, but seem to change the timings - * a bit - without them it seems that the harddisk driver won't work on - * all hardware. Arghh. - */ -#define ACK_FIRST(mask,nr) \ - "inb $0x21,%al\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \ - "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \ - "outb %al,$0x21\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\tmovb $0x20,%al\n\t" \ - "outb %al,$0x20\n\t" - -#define ACK_SECOND(mask,nr) \ - "inb $0xA1,%al\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \ - "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \ - "outb %al,$0xA1\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\tmovb $0x20,%al\n\t" \ - "outb %al,$0xA0\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\toutb %al,$0x20\n\t" - -#define UNBLK_FIRST(mask) \ - "inb $0x21,%al\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \ - "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \ - "outb %al,$0x21\n\t" - -#define UNBLK_SECOND(mask) \ - "inb $0xA1,%al\n\t" \ - "jmp 1f\n" \ - "1:\tjmp 1f\n" \ - "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \ - "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \ - "outb %al,$0xA1\n\t" - #define IRQ_NAME2(nr) nr##_interrupt(void) #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) -#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr) #define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) -#ifdef __SMP__ - #define GET_CURRENT \ - "movl "SYMBOL_NAME_STR(apic_reg)", %ebx\n\t" \ - "movl 32(%ebx), %ebx\n\t" \ - "shrl $22,%ebx\n\t" \ - "andl $0x3C,%ebx\n\t" \ - "movl " SYMBOL_NAME_STR(current_set) "(,%ebx),%ebx\n\t" - -#else - -#define GET_CURRENT \ - "movl " SYMBOL_NAME_STR(current_set) ",%ebx\n\t" - -#endif + "movl %esp, %ebx\n\t" \ + "andl $-8192, %ebx\n\t" #ifdef __SMP__ @@ -205,66 +115,30 @@ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(x) ":\n\t" \ "pushl $-1\n\t" \ - SAVE_ALL \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ + SAVE_ALL \ + "movl %esp,%eax\n\t" \ + "pushl %eax\n\t" \ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \ - "addl $4,%esp\n\t" \ + "addl $4,%esp\n\t" \ "jmp ret_from_intr\n"); #endif /* __SMP__ */ -#define BUILD_IRQ(chip,nr,mask) \ -asmlinkage void IRQ_NAME(nr); \ -asmlinkage void FAST_IRQ_NAME(nr); \ -asmlinkage void BAD_IRQ_NAME(nr); \ +#define BUILD_COMMON_IRQ() \ __asm__( \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $-"#nr"-2\n\t" \ + "\n" __ALIGN_STR"\n" \ + "common_interrupt:\n\t" \ SAVE_ALL \ - ACK_##chip(mask,(nr&7)) \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ - "addl $8,%esp\n\t" \ - UNBLK_##chip(mask) \ - "jmp ret_from_intr\n" \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ - SAVE_MOST \ - ACK_##chip(mask,(nr&7)) \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \ - "addl $4,%esp\n\t" \ - UNBLK_##chip(mask) \ - RESTORE_MOST \ -"\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ - SAVE_MOST \ - ACK_##chip(mask,(nr&7)) \ - RESTORE_MOST); - -#define BUILD_TIMER_IRQ(chip,nr,mask) \ + "pushl $ret_from_intr\n\t" \ + "jmp "SYMBOL_NAME_STR(do_IRQ)); + +#define BUILD_IRQ(chip,nr,mask) \ asmlinkage void IRQ_NAME(nr); \ -asmlinkage void FAST_IRQ_NAME(nr); \ -asmlinkage void BAD_IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ -SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \ -SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ - "pushl $-"#nr"-2\n\t" \ - SAVE_ALL \ - ACK_##chip(mask,(nr&7)) \ - "movl %esp,%eax\n\t" \ - "pushl %eax\n\t" \ - "pushl $" #nr "\n\t" \ - "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ - "addl $8,%esp\n\t" \ - UNBLK_##chip(mask) \ - "jmp ret_from_intr\n"); + "pushl $"#nr"-256\n\t" \ + "jmp common_interrupt"); /* * x86 profiling function, SMP safe. We might want to do this in diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.1.36/linux/arch/i386/kernel/process.c Sun Apr 13 10:18:20 1997 +++ linux/arch/i386/kernel/process.c Mon May 12 10:35:37 1997 @@ -30,6 +30,7 @@ #include #include #include +#include #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) #include #endif @@ -149,7 +150,8 @@ current->priority = -100; while(1) { - if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched) + if(cpu_data[smp_processor_id()].hlt_works_ok && + !hlt_counter && !need_resched) __asm("hlt"); /* * tq_scheduler currently assumes we're running in a process @@ -183,7 +185,7 @@ static int reboot_mode = 0; static int reboot_thru_bios = 0; -void reboot_setup(char *str, int *ints) +__initfunc(void reboot_setup(char *str, int *ints)) { while(1) { switch (*str) { @@ -324,11 +326,14 @@ pg0 [0] = 7; - /* Use `swapper_pg_dir' as our page directory. Don't bother with - `SET_PAGE_DIR' because interrupts are disabled and we're rebooting. - This instruction flushes the TLB. */ + /* + * Use `swapper_pg_dir' as our page directory. We bother with + * `SET_PAGE_DIR' because although might be rebooting, but if we change + * the way we set root page dir in the future, then we wont break a + * seldom used feature ;) + */ - __asm__ __volatile__ ("movl %0,%%cr3" : : "a" (swapper_pg_dir) : "memory"); + SET_PAGE_DIR(current,swapper_pg_dir); /* Write 0x1234 to absolute memory location 0x472. The BIOS reads this on booting to tell it to "Bypass memory test (also warm @@ -473,6 +478,8 @@ int i; struct pt_regs * childregs; + p->tss.tr = _TSS(nr); + p->tss.ldt = _LDT(nr); p->tss.es = KERNEL_DS; p->tss.cs = KERNEL_CS; p->tss.ss = KERNEL_DS; @@ -480,9 +487,8 @@ p->tss.fs = USER_DS; p->tss.gs = USER_DS; p->tss.ss0 = KERNEL_DS; - p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE; - p->tss.tr = _TSS(nr); - childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1; + p->tss.esp0 = 2*PAGE_SIZE + (unsigned long) p; + childregs = ((struct pt_regs *) (p->tss.esp0)) - 1; p->tss.esp = (unsigned long) childregs; #ifdef __SMP__ p->tss.eip = (unsigned long) ret_from_smpfork; @@ -496,7 +502,6 @@ childregs->eax = 0; childregs->esp = esp; p->tss.back_link = 0; - p->tss.ldt = _LDT(nr); if (p->ldt) { p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); if (p->ldt != NULL) @@ -512,6 +517,7 @@ p->tss.io_bitmap[i] = ~0; if (last_task_used_math == current) __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387)); + return 0; } diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.1.36/linux/arch/i386/kernel/ptrace.c Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/ptrace.c Mon May 12 17:39:50 1997 @@ -34,18 +34,6 @@ */ #define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs)) -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * this routine will get a word off of the processes privileged stack. * the offset is how far from the base addr as stored in the TSS. @@ -95,7 +83,7 @@ repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(vma, addr, 0); goto repeat; } if (pgd_bad(*pgdir)) { @@ -105,7 +93,7 @@ } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(vma, addr, 0); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -115,7 +103,7 @@ } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 0); + handle_mm_fault(vma, addr, 0); goto repeat; } page = pte_page(*pgtable); @@ -146,7 +134,7 @@ repeat: pgdir = pgd_offset(vma->vm_mm, addr); if (!pgd_present(*pgdir)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(vma, addr, 1); goto repeat; } if (pgd_bad(*pgdir)) { @@ -156,7 +144,7 @@ } pgmiddle = pmd_offset(pgdir, addr); if (pmd_none(*pgmiddle)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(vma, addr, 1); goto repeat; } if (pmd_bad(*pgmiddle)) { @@ -166,12 +154,12 @@ } pgtable = pte_offset(pgmiddle, addr); if (!pte_present(*pgtable)) { - do_no_page(tsk, vma, addr, 1); + handle_mm_fault(vma, addr, 1); goto repeat; } page = pte_page(*pgtable); if (!pte_write(*pgtable)) { - do_wp_page(tsk, vma, addr, 1); + handle_mm_fault(vma, addr, 1); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -381,7 +369,7 @@ if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) goto out; ret = -EPERM; if (request == PTRACE_ATTACH) { diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.36/linux/arch/i386/kernel/setup.c Wed Apr 16 14:14:59 1997 +++ linux/arch/i386/kernel/setup.c Tue May 13 17:48:58 1997 @@ -247,7 +247,7 @@ static const char * i686model(unsigned int nr) { static const char *model[] = { - "PPro A-step", "Pentium Pro" + "PPro A-step", "Pentium Pro", "2", "Pentium II" }; if (nr < sizeof(model)/sizeof(char *)) return model[nr]; @@ -279,9 +279,10 @@ int get_cpuinfo(char * buffer) { int i, len = 0; + int sep_bug; static const char *x86_cap_flags[] = { "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", - "cx8", "apic", "10", "11", "mtrr", "pge", "mca", "cmov", + "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov", "16", "17", "18", "19", "20", "21", "22", "mmx", "24", "25", "26", "27", "28", "29", "30", "31" }; @@ -321,10 +322,16 @@ else len += sprintf(buffer+len, "stepping\t: unknown\n"); + + sep_bug = CD(have_cpuid) && + (CD(x86_capability) & 0x800) && + CD(x86_model) < 3 && + CD(x86_mask) < 3; len += sprintf(buffer+len, "fdiv_bug\t: %s\n" "hlt_bug\t\t: %s\n" + "sep_bug\t\t: %s\n" "fpu\t\t: %s\n" "fpu_exception\t: %s\n" "cpuid\t\t: %s\n" @@ -332,6 +339,7 @@ "flags\t\t:", CD(fdiv_bug) ? "yes" : "no", CD(hlt_works_ok) ? "no" : "yes", + sep_bug ? "yes" : "no", CD(hard_math) ? "yes" : "no", (CD(hard_math) && ignore_irq13) ? "yes" : "no", diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.1.36/linux/arch/i386/kernel/signal.c Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/signal.c Mon May 12 10:35:38 1997 @@ -318,6 +318,14 @@ unsigned long signr; struct sigaction * sa; + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if ((regs->xcs & 3) != 3) + return 1; mask = ~current->blocked; while ((signr = current->signal & mask)) { /* diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.1.36/linux/arch/i386/kernel/smp.c Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/kernel/smp.c Mon May 12 17:39:50 1997 @@ -1,5 +1,5 @@ /* - * Intel MP v1.1/v1.4 specification support routines for multi-pentium + * Intel MP v1.1/v1.4 specification support routines for multi-pentium * hosts. * * (c) 1995 Alan Cox, CymruNET Ltd @@ -46,14 +46,15 @@ #include #include +#define __KERNEL_SYSCALLS__ +#include + #include "irq.h" extern unsigned long start_kernel, _etext; extern void update_one_process( struct task_struct *p, - unsigned long ticks, unsigned long user, - unsigned long system); -void setup_APIC_clock (void); - + unsigned long ticks, unsigned long user, + unsigned long system); /* * Some notes on processor bugs: * @@ -67,7 +68,7 @@ * Pentium * There is a marginal case where REP MOVS on 100MHz SMP * machines with B stepping processors can fail. XXX should provide - * an L1cache=Writethrough or L1cache=off option. + * an L1cache=Writethrough or L1cache=off option. * * B stepping CPU's may hang. There are hardware work arounds * for this. We warn about it in case your board doesnt have the work @@ -91,12 +92,12 @@ * If this sounds worrying believe me these bugs are ___RARE___ and * there's about nothing of note with C stepping upwards. */ - - + + /* * Why isn't this somewhere standard ?? */ - + extern __inline int max(int a,int b) { if(a>b) @@ -121,7 +122,6 @@ static unsigned int num_processors = 1; /* Internal processor count */ static unsigned long io_apic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */ unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */ -static unsigned char *kstack_base,*kstack_end; /* Kernel stack list pointers */ static int smp_activated = 0; /* Tripped once we need to start cross invalidating */ int apic_version[NR_CPUS]; /* APIC version number */ static volatile int smp_commenced=0; /* Tripped when we start scheduling */ @@ -129,7 +129,6 @@ unsigned long nlong = 0; /* dummy used for apic_reg address + 0x20 */ unsigned char *apic_reg=((unsigned char *)(&nlong))-0x20;/* Later set to the ioremap() of the APIC */ unsigned long apic_retval; /* Just debugging the assembler.. */ -unsigned char *kernel_stacks[NR_CPUS]; /* Kernel stack pointers for CPU's (debugging) */ static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; /* True if this processor is sending an IPI */ @@ -195,10 +194,10 @@ apic_write(APIC_EOI, 0); } -/* +/* * Checksum an MP configuration block. */ - + static int mpf_checksum(unsigned char *mp, int len) { int sum=0; @@ -210,7 +209,7 @@ /* * Processor encoding in an MP configuration block */ - + static char *mpc_family(int family,int model) { static char n[32]; @@ -274,11 +273,11 @@ /* set the local APIC address */ apic_addr = (unsigned long)phys_to_virt((unsigned long)mpc->mpc_lapic); - + /* * Now process the configuration blocks. */ - + while(countmpc_length) { switch(*mpt) @@ -290,13 +289,13 @@ if(m->mpc_cpuflag&CPU_ENABLED) { printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, + m->mpc_apicid, mpc_family((m->mpc_cpufeature& CPU_FAMILY_MASK)>>8, (m->mpc_cpufeature& CPU_MODEL_MASK)>>4), m->mpc_apicver); -#ifdef SMP_DEBUG +#ifdef SMP_DEBUG if(m->mpc_featureflag&(1<<0)) printk(" Floating point unit present.\n"); if(m->mpc_featureflag&(1<<7)) @@ -305,7 +304,7 @@ printk(" 64 bit compare & exchange supported.\n"); if(m->mpc_featureflag&(1<<9)) printk(" Internal APIC present.\n"); -#endif +#endif if(m->mpc_cpuflag&CPU_BOOTPROCESSOR) { SMP_PRINTK((" Bootup CPU\n")); @@ -313,10 +312,10 @@ } else /* Boot CPU already counted */ num_processors++; - + if(m->mpc_apicid>NR_CPUS) printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS); - else + else { cpu_present_map|=(1<mpc_apicid); apic_version[m->mpc_apicid]=m->mpc_apicver; @@ -337,7 +336,7 @@ str)); mpt+=sizeof(*m); count+=sizeof(*m); - break; + break; } case MP_IOAPIC: { @@ -346,20 +345,20 @@ if(m->mpc_flags&MPC_APIC_USABLE) { apics++; - printk("I/O APIC #%d Version %d at 0x%lX.\n", - m->mpc_apicid,m->mpc_apicver, - m->mpc_apicaddr); - io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr); - } - mpt+=sizeof(*m); - count+=sizeof(*m); - break; + printk("I/O APIC #%d Version %d at 0x%lX.\n", + m->mpc_apicid,m->mpc_apicver, + m->mpc_apicaddr); + io_apic_addr = (unsigned long)phys_to_virt(m->mpc_apicaddr); + } + mpt+=sizeof(*m); + count+=sizeof(*m); + break; } case MP_INTSRC: { struct mpc_config_intsrc *m= (struct mpc_config_intsrc *)mpt; - + mpt+=sizeof(*m); count+=sizeof(*m); break; @@ -376,29 +375,29 @@ } if(apics>1) printk("Warning: Multiple APIC's not supported.\n"); - return num_processors; + return num_processors; } /* * Scan the memory blocks for an SMP configuration block. */ - + __initfunc(int smp_scan_config(unsigned long base, unsigned long length)) { unsigned long *bp=phys_to_virt(base); struct intel_mp_floating *mpf; - + SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n", bp,length)); if(sizeof(*mpf)!=16) printk("Error: MPF size\n"); - + while(length>0) { if(*bp==SMP_MAGIC_IDENT) { mpf=(struct intel_mp_floating *)bp; - if(mpf->mpf_length==1 && + if(mpf->mpf_length==1 && !mpf_checksum((unsigned char *)bp,16) && (mpf->mpf_specification == 1 || mpf->mpf_specification == 4) ) @@ -433,7 +432,7 @@ * We know that page 0 is not * used. Steal it for now! */ - + cfg=pg0[0]; pg0[0] = (apic_addr | 7); local_flush_tlb(); @@ -451,7 +450,7 @@ * * END OF HACK END OF HACK END OF HACK END OF HACK END OF HACK * - */ + */ /* * 2 CPUs, numbered 0 & 1. */ @@ -513,6 +512,7 @@ nlong = boot_cpu_id<<24; /* Dummy 'self' for bootup */ cpu_logical_map[0] = boot_cpu_id; global_irq_holder = boot_cpu_id; + current->processor = boot_cpu_id; printk("Processors: %d\n", num_processors); /* @@ -534,61 +534,37 @@ extern unsigned char trampoline_data []; extern unsigned char trampoline_end []; +static unsigned char *trampoline_base; /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller * has made sure it's suitably aligned. */ - -__initfunc(static void install_trampoline(unsigned char *mp)) + +__initfunc(static unsigned long setup_trampoline(void)) { - memcpy(mp, trampoline_data, trampoline_end - trampoline_data); + memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data); + return virt_to_phys(trampoline_base); } /* - * We are called very early to get the low memory for the trampoline/kernel stacks - * This has to be done by mm/init.c to parcel us out nice low memory. We allocate - * the kernel stacks at 4K, 8K, 12K... currently (0-03FF is preserved for SMM and - * other things). + * We are called very early to get the low memory for the + * SMP bootup trampoline page. */ - __initfunc(unsigned long smp_alloc_memory(unsigned long mem_base)) { - int size=(num_processors-1)*PAGE_SIZE; /* Number of stacks needed */ - - /* - * Our stacks have to be below the 1Mb line, and mem_base on entry - * is 4K aligned. - */ - - if(virt_to_phys((void *)(mem_base+size))>=0x9F000) - panic("smp_alloc_memory: Insufficient low memory for kernel stacks 0x%lx.\n", mem_base); - kstack_base=(void *)mem_base; - mem_base+=size; - kstack_end=(void *)mem_base; - return mem_base; -} - -/* - * Hand out stacks one at a time. - */ - -__initfunc(static void *get_kernel_stack(void)) -{ - void *stack=kstack_base; - if(kstack_base>=kstack_end) - return NULL; - kstack_base+=PAGE_SIZE; - return stack; + if (virt_to_phys((void *)mem_base) >= 0x9F000) + panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.\n", mem_base); + trampoline_base = (void *)mem_base; + return mem_base + PAGE_SIZE; } - /* * The bootstrap kernel entry code has set these up. Save them for * a given CPU */ - + __initfunc(void smp_store_cpu_info(int id)) { struct cpuinfo_x86 *c=&cpu_data[id]; @@ -615,7 +591,7 @@ * fired off. This allows the BP to have everything in order [we hope]. * At the end of this all the AP's will hit the system scheduling and off * we go. Each AP will load the system gdt's and jump through the kernel - * init into idle(). At this point the scheduler will one day take over + * init into idle(). At this point the scheduler will one day take over * and give them jobs to do. smp_callin is a standard routine * we use to track CPU's as they power up. */ @@ -634,74 +610,276 @@ extern void calibrate_delay(void); int cpuid=GET_APIC_ID(apic_read(APIC_ID)); unsigned long l; - + /* * Activate our APIC */ - - SMP_PRINTK(("CALLIN %d\n",smp_processor_id())); + + SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id())); l=apic_read(APIC_SPIV); l|=(1<<8); /* Enable */ apic_write(APIC_SPIV,l); /* - * Set up our APIC timer. + * Set up our APIC timer. */ setup_APIC_clock (); sti(); /* * Get our bogomips. - */ + */ calibrate_delay(); SMP_PRINTK(("Stack at about %p\n",&cpuid)); - + /* * Save our processor parameters */ smp_store_cpu_info(cpuid); + /* * Allow the master to continue. - */ + */ set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]); +} + +static int cpucount = 0; + +extern int cpu_idle(void * unused); + +/* + * Activate a secondary processor. + */ +__initfunc(int start_secondary(void *unused)) +{ + smp_callin(); + while (!smp_commenced) + barrier(); + return cpu_idle(NULL); +} + +/* + * Everything has been set up for the secondary + * CPU's - they just need to reload everything + * from the task structure + */ +__initfunc(void initialize_secondary(void)) +{ + struct thread_struct * p = ¤t->tss; + /* - * Until we are ready for SMP scheduling + * We don't actually need to load the full TSS, + * basically just the stack pointer and the eip. */ - load_ldt(0); - local_flush_tlb(); - - while (cpu_number_map[cpuid] == -1) - barrier(); + asm volatile("lldt %%ax": :"a" (p->ldt)); + asm volatile("ltr %%ax": :"a" (p->tr)); + asm volatile( + "movl %0,%%esp\n\t" + "jmp *%1" + : + :"r" (p->esp),"r" (p->eip)); +} - while(!task[cpuid] || current_set[cpuid] != task[cpu_number_map[cpuid]]) - barrier(); +extern struct { + void * esp; + unsigned short ss; +} stack_start; - local_flush_tlb(); - load_TR(cpu_number_map[cpuid]); +__initfunc(static void do_boot_cpu(int i)) +{ + unsigned long cfg; + pgd_t maincfg; + struct task_struct *idle; + unsigned long send_status, accept_status; + int timeout, num_starts, j; + unsigned long start_eip; - while(!smp_commenced) - barrier(); - + /* + * We need an idle process for each processor. + */ + + kernel_thread(start_secondary, NULL, CLONE_PID); + cpucount++; + + idle = task[cpucount]; + if (!idle) + panic("No idle process for CPU %d\n", i); + + idle->processor = i; + cpu_logical_map[cpucount] = i; + cpu_number_map[i] = cpucount; + + /* start_eip had better be page-aligned! */ + start_eip = setup_trampoline(); + + printk("Booting processor %d eip %lx: ", i, start_eip); /* So we see what's up */ + stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); + + /* + * This grunge runs the startup process for + * the targeted processor. + */ + + SMP_PRINTK(("Setting warm reset code and vector.\n")); + + CMOS_WRITE(0xa, 0xf); local_flush_tlb(); + SMP_PRINTK(("1.\n")); + *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4; + SMP_PRINTK(("2.\n")); + *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf; + SMP_PRINTK(("3.\n")); + + maincfg=swapper_pg_dir[0]; + ((unsigned long *)swapper_pg_dir)[0]=0x102007; + + /* + * Be paranoid about clearing APIC errors. + */ + + if ( apic_version[i] & 0xF0 ) + { + apic_write(APIC_ESR, 0); + accept_status = (apic_read(APIC_ESR) & 0xEF); + } + + /* + * Status is now clean + */ - SMP_PRINTK(("Commenced..\n")); + send_status = 0; + accept_status = 0; + + /* + * Starting actual IPI sequence... + */ + + SMP_PRINTK(("Asserting INIT.\n")); + + /* + * Turn INIT on + */ + + cfg=apic_read(APIC_ICR2); + cfg&=0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ + cfg=apic_read(APIC_ICR); + cfg&=~0xCDFFF; /* Clear bits */ + cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG + | APIC_DEST_ASSERT | APIC_DEST_DM_INIT); + apic_write(APIC_ICR, cfg); /* Send IPI */ + + udelay(200); + SMP_PRINTK(("Deasserting INIT.\n")); + + cfg=apic_read(APIC_ICR2); + cfg&=0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ + cfg=apic_read(APIC_ICR); + cfg&=~0xCDFFF; /* Clear bits */ + cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG + | APIC_DEST_DM_INIT); + apic_write(APIC_ICR, cfg); /* Send IPI */ + + /* + * Should we send STARTUP IPIs ? + * + * Determine this based on the APIC version. + * If we don't have an integrated APIC, don't + * send the STARTUP IPIs. + */ + + if ( apic_version[i] & 0xF0 ) + num_starts = 2; + else + num_starts = 0; + + /* + * Run STARTUP IPI loop. + */ + + for (j = 1; !(send_status || accept_status) + && (j <= num_starts) ; j++) + { + SMP_PRINTK(("Sending STARTUP #%d.\n",j)); + apic_write(APIC_ESR, 0); + SMP_PRINTK(("After apic_write.\n")); + + /* + * STARTUP IPI + */ + + cfg=apic_read(APIC_ICR2); + cfg&=0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ + cfg=apic_read(APIC_ICR); + cfg&=~0xCDFFF; /* Clear bits */ + cfg |= (APIC_DEST_FIELD + | APIC_DEST_DM_STARTUP + | (start_eip >> 12)); /* Boot on the stack */ + SMP_PRINTK(("Before start apic_write.\n")); + apic_write(APIC_ICR, cfg); /* Kick the second */ + + SMP_PRINTK(("Startup point 1.\n")); + timeout = 0; + do { + SMP_PRINTK(("Sleeping.\n")); udelay(1000000); + udelay(10); + } while ( (send_status = (apic_read(APIC_ICR) & 0x1000)) + && (timeout++ < 1000)); + udelay(200); + accept_status = (apic_read(APIC_ESR) & 0xEF); + } + SMP_PRINTK(("After Startup.\n")); + + if (send_status) /* APIC never delivered?? */ + printk("APIC never delivered???\n"); + if (accept_status) /* Send accept error */ + printk("APIC delivery error (%lx).\n", accept_status); + + if( !(send_status || accept_status) ) + { + for(timeout=0;timeout<50000;timeout++) + { + if(cpu_callin_map[0]&(1< cpucount+1)) { - unsigned long send_status, accept_status; - int timeout, num_starts, j; - - /* - * We need a kernel stack for each processor. - */ - - stack=get_kernel_stack(); /* We allocated these earlier */ - if(stack==NULL) - panic("No memory for processor stacks.\n"); - - kernel_stacks[i]=(void *)phys_to_virt((unsigned long)stack); - install_trampoline(stack); - - printk("Booting processor %d stack %p: ",i,stack); /* So we set what's up */ - - /* - * This grunge runs the startup process for - * the targeted processor. - */ - - SMP_PRINTK(("Setting warm reset code and vector.\n")); - - /* - * Install a writable page 0 entry. - */ - - cfg=pg0[0]; - - CMOS_WRITE(0xa, 0xf); - pg0[0]=7; - local_flush_tlb(); - SMP_PRINTK(("1.\n")); - *((volatile unsigned short *) phys_to_virt(0x469)) = ((unsigned long)stack)>>4; - SMP_PRINTK(("2.\n")); - *((volatile unsigned short *) phys_to_virt(0x467)) = 0; - SMP_PRINTK(("3.\n")); - - /* - * Protect it again - */ - - pg0[0]= cfg; - local_flush_tlb(); - - /* walken modif - * enable mapping of the first 4M at virtual - * address zero - */ - - maincfg=swapper_pg_dir[0]; - ((unsigned long *)swapper_pg_dir)[0]=0x102007; - - /* no need to local_flush_tlb : - we are setting this up for the slave processor ! */ - - /* - * Be paranoid about clearing APIC errors. - */ - - if ( apic_version[i] & 0xF0 ) - { - apic_write(APIC_ESR, 0); - accept_status = (apic_read(APIC_ESR) & 0xEF); - } - - /* - * Status is now clean - */ - - send_status = 0; - accept_status = 0; - - /* - * Starting actual IPI sequence... - */ - - SMP_PRINTK(("Asserting INIT.\n")); - - /* - * Turn INIT on - */ - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG - | APIC_DEST_ASSERT | APIC_DEST_DM_INIT); - apic_write(APIC_ICR, cfg); /* Send IPI */ - - udelay(200); - SMP_PRINTK(("Deasserting INIT.\n")); - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG - | APIC_DEST_DM_INIT); - apic_write(APIC_ICR, cfg); /* Send IPI */ - - /* - * Should we send STARTUP IPIs ? - * - * Determine this based on the APIC version. - * If we don't have an integrated APIC, don't - * send the STARTUP IPIs. - */ - - if ( apic_version[i] & 0xF0 ) - num_starts = 2; - else - num_starts = 0; - - /* - * Run STARTUP IPI loop. - */ - - for (j = 1; !(send_status || accept_status) - && (j <= num_starts) ; j++) - { - SMP_PRINTK(("Sending STARTUP #%d.\n",j)); - - apic_write(APIC_ESR, 0); - SMP_PRINTK(("After apic_write.\n")); - - /* - * STARTUP IPI - */ - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_FIELD - | APIC_DEST_DM_STARTUP - | (((int)virt_to_phys(stack)) >> 12)); /* Boot on the stack */ - SMP_PRINTK(("Before start apic_write.\n")); - apic_write(APIC_ICR, cfg); /* Kick the second */ - - SMP_PRINTK(("Startup point 1.\n")); - timeout = 0; - do { - SMP_PRINTK(("Sleeping.\n")); udelay(1000000); - udelay(10); - } while ( (send_status = (apic_read(APIC_ICR) & 0x1000)) - && (timeout++ < 1000)); - udelay(200); - - accept_status = (apic_read(APIC_ESR) & 0xEF); - } - SMP_PRINTK(("After Startup.\n")); - - if (send_status) /* APIC never delivered?? */ - printk("APIC never delivered???\n"); - if (accept_status) /* Send accept error */ - printk("APIC delivery error (%lx).\n", accept_status); - - if( !(send_status || accept_status) ) - { - for(timeout=0;timeout<50000;timeout++) - { - if(cpu_callin_map[0]&(1< #include #include +#include #include #include @@ -379,11 +380,15 @@ do_timer(regs); /* * In the SMP case we use the local APIC timer interrupt to do the - * profiling. + * profiling, except when we simulate SMP mode on a uniprocessor + * system, in that case we have to call the local interrupt handler. */ #ifndef __SMP__ if (!user_mode(regs)) x86_do_profile(regs->eip); +#else + if (!smp_found_config) + smp_local_timer_interrupt(regs); #endif /* diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/trampoline.S linux/arch/i386/kernel/trampoline.S --- v2.1.36/linux/arch/i386/kernel/trampoline.S Sun Jan 26 02:07:04 1997 +++ linux/arch/i386/kernel/trampoline.S Mon May 12 10:35:38 1997 @@ -21,13 +21,9 @@ * and IP is zero. Thus, data addresses need to be absolute * (no relocation) and are taken with regard to r_base. * - * On the transition to protected mode, this page appears at - * address 8192, so protected mode addresses are with regard - * to p_base. - * * If you work on this file, check the object module with objdump * --full-contents --reloc to make sure there are no relocation - * entries. + * entries except for the gdt one.. */ #include @@ -39,15 +35,10 @@ ENTRY(trampoline_data) r_base = . -p_base = . - 8192 mov %cs, %ax # Code and data in the same place mov %ax, %ds - mov %ax, %cx # Pass stack info to the 32bit boot - shl $4, %cx # Segment -> Offset - add $4096, %cx # End of page is wanted - mov $1, %bx # Flag an SMP trampoline cli # We should be safe anyway @@ -71,37 +62,7 @@ gdt_48: .word 0x0800 # gdt limit = 2048, 256 GDT entries - .word gdt - p_base, 0x0 # gdt base = gdt (first SMP CPU) - # we load the others with first table - # saves rewriting gdt_48 for each -gdt: - .word 0, 0, 0, 0 # dummy - - .word 0, 0, 0, 0 # unused - -# walken modif - - .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb) - .word 0x0000 # base address = 0 - .word 0x9A00 # code read / exec - .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit) - - .word 0xFFFF # 4 Gb - (0x100000*0x1000 = 4Gb) - .word 0x0000 # base address = 0 - .word 0x9200 # data read / write - .word 0x00CF # granularity = 4096, 386 (+5th nibble of limit) - -# walken modif - -# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb) -# .word 0x0000 # base address = 0 -# .word 0x9A00 # code read / exec -# .word 0x00C0 # granularity = 4096, 386 - -# .word 0x07FF # 8 Mb - limit = 2047 (2048 * 4096 = 8 Mb) -# .word 0x0000 # base address = 0 -# .word 0x9200 # data read / write -# .word 0x00C0 # granularity = 4096, 386 + .long gdt-0xc0000000 # gdt base = gdt (first SMP CPU) .globl SYMBOL_NAME(trampoline_end) SYMBOL_NAME_LABEL(trampoline_end) diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.1.36/linux/arch/i386/kernel/traps.c Wed Apr 16 14:14:59 1997 +++ linux/arch/i386/kernel/traps.c Mon May 12 10:35:38 1997 @@ -23,10 +23,12 @@ #include #include #include +#include #include #include #include +#include asmlinkage int system_call(void); asmlinkage void lcall7(void); @@ -121,7 +123,7 @@ unsigned long esp; unsigned short ss; unsigned long *stack, addr, module_start, module_end; - extern char start_kernel, _etext; + extern char _stext, _etext; esp = (unsigned long) ®s->esp; ss = KERNEL_DS; @@ -129,8 +131,8 @@ esp = regs->esp; ss = regs->xss & 0xffff; } - printk("CPU: %d\n", smp_processor_id()); - printk("EIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->xcs,regs->eip,regs->eflags); + printk("CPU: %d\nEIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", + smp_processor_id(), 0xffff & regs->xcs, regs->eip, regs->eflags); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", @@ -138,10 +140,8 @@ printk("ds: %04x es: %04x ss: %04x\n", regs->xds & 0xffff, regs->xes & 0xffff, ss); store_TR(i); - if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page) - printk("Corrupted stack page\n"); printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ", - current->comm, current->pid, 0xffff & i, current->kernel_stack_page); + current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current); stack = (unsigned long *) esp; for(i=0; i < kstack_depth_to_print; i++) { if (((long) stack & 4095) == 0) @@ -166,7 +166,7 @@ * down the cause of the crash will be able to figure * out the call path that was taken. */ - if (((addr >= (unsigned long) &start_kernel) && + if (((addr >= (unsigned long) &_stext) && (addr <= (unsigned long) &_etext)) || ((addr >= module_start) && (addr <= module_end))) { if (i && ((i % 8) == 0)) @@ -181,13 +181,19 @@ printk("\n"); } +spinlock_t die_lock; + /*static*/ void die_if_kernel(const char * str, struct pt_regs * regs, long err) { if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3) return; console_verbose(); + spin_lock_irq(&die_lock); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); +do { int i=2000000000; while (i) i--; } while (0); +do { int i=2000000000; while (i) i--; } while (0); + spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } @@ -235,18 +241,45 @@ unlock_kernel(); } -asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +static void mem_parity_error(unsigned char reason, struct pt_regs * regs) { - printk("NMI\n"); show_registers(regs); -#ifdef CONFIG_SMP_NMI_INVAL - smp_flush_tlb_rcv(); -#else -#ifndef CONFIG_IGNORE_NMI printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); - printk("You probably have a hardware problem with your RAM chips or a\n"); - printk("power saving mode enabled.\n"); -#endif -#endif + printk("You probably have a hardware problem with your RAM chips\n"); +} + +static void io_check_error(unsigned char reason, struct pt_regs * regs) +{ + unsigned long i; + + printk("NMI: IOCK error (debug interrupt?)\n"); + show_registers(regs); + + /* Re-enable the IOCK line, wait for a few seconds */ + reason |= 8; + outb(reason, 0x61); + i = 2000; + while (--i) udelay(1000); + reason &= ~8; + outb(reason, 0x61); +} + +static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) +{ + printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); + printk("Dazed and confused, but trying to continue\n"); + printk("Do you have a strange power saving mode enabled?\n"); +} + +asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +{ + unsigned char reason = inb(0x61); + + if (reason & 0x80) + mem_parity_error(reason, regs); + if (reason & 0x40) + io_check_error(reason, regs); + if (!(reason & 0xc0)) + unknown_nmi_error(reason, regs); } asmlinkage void do_debug(struct pt_regs * regs, long error_code) @@ -380,15 +413,7 @@ { int i; struct desc_struct * p; - static int smptrap=0; - - if(smptrap) - { - __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); - load_ldt(0); - return; - } - smptrap++; + if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) EISA_bus = 1; set_call_gate(&default_ldt,lcall7); diff -u --recursive --new-file v2.1.36/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.1.36/linux/arch/i386/kernel/vm86.c Thu Feb 27 10:57:29 1997 +++ linux/arch/i386/kernel/vm86.c Mon May 12 10:35:38 1997 @@ -81,8 +81,8 @@ printk("vm86: could not access userspace vm86_info\n"); do_exit(SIGSEGV); } - current->tss.esp0 = current->saved_kernel_stack; - current->saved_kernel_stack = 0; + current->tss.esp0 = current->tss.saved_esp0; + current->tss.saved_esp0 = 0; ret = KVM86->regs32; unlock_kernel(); return ret; @@ -137,7 +137,7 @@ lock_kernel(); tsk = current; - if (tsk->saved_kernel_stack) + if (tsk->tss.saved_esp0) goto out; tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1); tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2, @@ -187,7 +187,7 @@ /* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */ ret = -EPERM; - if (tsk->saved_kernel_stack) + if (tsk->tss.saved_esp0) goto out; tmp = copy_from_user(&info, v86, VM86_REGS_SIZE1); tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2, @@ -247,7 +247,7 @@ * Save old state, set default return value (%eax) to 0 */ info->regs32->eax = 0; - tsk->saved_kernel_stack = tsk->tss.esp0; + tsk->tss.saved_esp0 = tsk->tss.esp0; tsk->tss.esp0 = (unsigned long) &info->VM86_TSS_ESP0; tsk->tss.screen_bitmap = info->screen_bitmap; @@ -601,11 +601,17 @@ static inline int task_valid(struct task_struct *tsk) { struct task_struct *p; + int ret = 0; + read_lock(&tasklist_lock); for_each_task(p) { - if ((p == tsk) && (p->sig)) return 1; + if ((p == tsk) && (p->sig)) { + ret = 1; + break; + } } - return 0; + read_unlock(&tasklist_lock); + return ret; } static inline void handle_irq_zombies(void) diff -u --recursive --new-file v2.1.36/linux/arch/i386/lib/locks.S linux/arch/i386/lib/locks.S --- v2.1.36/linux/arch/i386/lib/locks.S Sun Jan 26 02:07:05 1997 +++ linux/arch/i386/lib/locks.S Mon May 12 10:35:38 1997 @@ -10,7 +10,6 @@ * %eax contains callers PC and %edx holds this cpu ID. */ ENTRY(__lock_kernel) - pushl %eax ! return address 1: lock btsl $0, SYMBOL_NAME(kernel_flag) @@ -21,8 +20,10 @@ lock btrl %dl, SYMBOL_NAME(smp_invalidate_needed) jnc 0f + pushl %eax movl %cr3, %eax movl %eax, %cr3 + popl %eax 0: btl $0, SYMBOL_NAME(kernel_flag) jc 2b diff -u --recursive --new-file v2.1.36/linux/arch/i386/lib/semaphore.S linux/arch/i386/lib/semaphore.S --- v2.1.36/linux/arch/i386/lib/semaphore.S Wed Jan 15 09:32:17 1997 +++ linux/arch/i386/lib/semaphore.S Mon May 12 17:39:50 1997 @@ -13,28 +13,31 @@ * there is contention on the semaphore. */ ENTRY(__down_failed) - pushl %eax /* return address */ + pushl %eax /* save %eax */ pushl %edx /* save %edx */ pushl %ecx /* save %ecx (and argument) */ call SYMBOL_NAME(__down) popl %ecx /* restore %ecx (count on __down not changing it) */ popl %edx /* restore %edx */ + popl %eax /* restore %eax */ ret ENTRY(__down_failed_interruptible) - pushl %eax /* return address */ + pushl %eax /* save %eax */ pushl %edx /* save %edx */ pushl %ecx /* save %ecx (and argument) */ call SYMBOL_NAME(__down_interruptible) popl %ecx /* restore %ecx (count on __down_interruptible not changing it) */ popl %edx /* restore %edx */ + popl %eax /* restore %eax */ ret ENTRY(__up_wakeup) - pushl %eax /* return address */ + pushl %eax /* save %eax */ pushl %edx /* save %edx */ pushl %ecx /* save %ecx (and argument) */ call SYMBOL_NAME(__up) popl %ecx /* restore %ecx (count on __up not changing it) */ popl %edx /* restore %edx */ + popl %eax /* restore %eax */ ret diff -u --recursive --new-file v2.1.36/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.1.36/linux/arch/i386/mm/fault.c Sun Apr 13 10:18:20 1997 +++ linux/arch/i386/mm/fault.c Mon May 12 17:39:50 1997 @@ -49,7 +49,7 @@ start &= PAGE_MASK; for (;;) { - do_wp_page(current, vma, start, 1); + handle_mm_fault(vma, start, 1); if (!size) break; size--; @@ -86,10 +86,6 @@ */ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) { - void (*handler)(struct task_struct *, - struct vm_area_struct *, - unsigned long, - int); struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; struct vm_area_struct * vma; @@ -128,10 +124,8 @@ */ good_area: write = 0; - handler = do_no_page; switch (error_code & 3) { default: /* 3: write, present */ - handler = do_wp_page; #ifdef TEST_VERIFY_AREA if (regs->cs == KERNEL_CS) printk("WP fault at %08lx\n", regs->eip); @@ -148,7 +142,7 @@ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handler(tsk, vma, address, write); + handle_mm_fault(vma, address, write); up(&mm->mmap_sem); /* * Did it hit the DOS screen memory VA from vm86 mode? @@ -169,7 +163,10 @@ /* Are we prepared to handle this fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { - printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", regs->eip, fixup); + printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", + current->comm, + regs->eip, + fixup); regs->eip = fixup; goto out; } diff -u --recursive --new-file v2.1.36/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.1.36/linux/arch/i386/mm/init.c Wed Apr 23 19:01:14 1997 +++ linux/arch/i386/mm/init.c Mon May 12 10:35:38 1997 @@ -139,12 +139,23 @@ #define write_cr4 ".byte 0x0f,0x22,0xe0" #endif -#define set_in_cr4(x) \ -__asm__(read_cr4 "\n\t" \ - "orl %0,%%eax\n\t" \ - write_cr4 \ - : : "i" (x) \ - :"ax"); +/* + * Save the cr4 feature set we're using (ie + * Pentium 4MB enable and PPro Global page + * enable), so that any CPU's that boot up + * after us can get the correct flags. + */ +unsigned long mmu_cr4_features __initdata = 0; + +static inline void set_in_cr4(unsigned long mask) +{ + mmu_cr4_features |= mask; + __asm__(read_cr4 "\n\t" + "orl %0,%%eax\n\t" + write_cr4 + : : "irg" (mask) + :"ax"); +} /* * paging_init() sets up the page tables - note that the first 4MB are diff -u --recursive --new-file v2.1.36/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds --- v2.1.36/linux/arch/i386/vmlinux.lds Wed Apr 16 14:15:00 1997 +++ linux/arch/i386/vmlinux.lds Mon May 12 10:35:38 1997 @@ -13,6 +13,7 @@ *(.fixup) *(.gnu.warning) } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } diff -u --recursive --new-file v2.1.36/linux/arch/m68k/Makefile linux/arch/m68k/Makefile --- v2.1.36/linux/arch/m68k/Makefile Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/Makefile Mon May 12 10:35:38 1997 @@ -24,17 +24,7 @@ CROSS_COMPILE = m68k-linux- endif -# -# Set these to indicate how to link it.. -# -# -zmagic: -# -# LINKFLAGS = -Ttext 0x100000 -# -# -qmagic (we need to remove the 32 byte header for bootup purposes) -# - -LINKFLAGS = -Ttext 0x1000 +LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds CFLAGS := $(CFLAGS) -pipe -fno-strength-reduce diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c --- v2.1.36/linux/arch/m68k/amiga/amifb.c Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/amifb.c Mon May 12 10:35:38 1997 @@ -50,12 +50,14 @@ #include #include #include +#include +#include + #include #include #include #include #include -#include #define DEBUG @@ -1802,7 +1804,7 @@ * Initialisation */ -struct fb_info *amiga_fb_init(long *mem_start) +__initfunc(struct fb_info *amiga_fb_init(long *mem_start)) { int err, tag, i; u_long chipptr; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c --- v2.1.36/linux/arch/m68k/amiga/amiints.c Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/amiints.c Mon May 12 10:35:38 1997 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -68,7 +69,7 @@ * the amiga IRQ handling routines. */ -void amiga_init_IRQ(void) +__initfunc(void amiga_init_IRQ(void)) { int i; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c --- v2.1.36/linux/arch/m68k/amiga/amikeyb.c Fri Dec 20 01:19:57 1996 +++ linux/arch/m68k/amiga/amikeyb.c Mon May 12 10:35:38 1997 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -295,7 +296,7 @@ } } -int amiga_keyb_init(void) +__initfunc(int amiga_keyb_init(void)) { if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) return -EIO; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c --- v2.1.36/linux/arch/m68k/amiga/amisound.c Fri Dec 20 01:19:57 1996 +++ linux/arch/m68k/amiga/amisound.c Mon May 12 10:35:38 1997 @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -39,7 +40,7 @@ static u_long clock_constant; -static void init_sound(void) +__initfunc(static void init_sound(void)) { snd_data = amiga_chip_alloc(sizeof(sine_data)); if (!snd_data) { @@ -84,7 +85,7 @@ custom.aud[2].audlc = snd_data; custom.aud[2].audlen = sizeof(sine_data)/2; custom.aud[2].audper = (u_short)period; - custom.aud[2].audvol = 64; /* maxvol */ + custom.aud[2].audvol = 32; /* 50% of maxvol */ if (ticks) { sound_timer.expires = jiffies + ticks; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c --- v2.1.36/linux/arch/m68k/amiga/chipram.c Fri Dec 20 01:19:57 1996 +++ linux/arch/m68k/amiga/chipram.c Mon May 12 10:35:38 1997 @@ -8,6 +8,7 @@ #include #include +#include #include struct chip_desc { @@ -21,19 +22,18 @@ #define DP(ptr) ((struct chip_desc *)(ptr)) u_long amiga_chip_size; -static unsigned long chipavail; /*MILAN*/ +static unsigned long chipavail; -/*MILAN*/ unsigned long amiga_chip_avail( void ) { #ifdef DEBUG - printk("chip_avail : %ld bytes\n",chipavail); + printk("chip_avail : %ld bytes\n",chipavail); #endif - return chipavail; + return chipavail; } -void amiga_chip_init (void) +__initfunc(void amiga_chip_init (void)) { struct chip_desc *dp; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/cia.c linux/arch/m68k/amiga/cia.c --- v2.1.36/linux/arch/m68k/amiga/cia.c Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/cia.c Mon May 12 10:35:38 1997 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -152,7 +153,7 @@ amiga_do_irq_list(base->server_irq, fp, &base->server); } -void cia_init_IRQ(struct ciabase *base) +__initfunc(void cia_init_IRQ(struct ciabase *base)) { int i; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c --- v2.1.36/linux/arch/m68k/amiga/config.c Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/config.c Mon May 12 10:35:38 1997 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -148,7 +149,7 @@ * Setup the Amiga configuration info */ -void config_amiga(void) +__initfunc(void config_amiga(void)) { /* Fill in some default values, if necessary */ if (amiga_eclock == 0) @@ -376,8 +377,8 @@ static unsigned short jiffy_ticks; -static void amiga_sched_init(void (*timer_routine)(int, void *, - struct pt_regs *)) +__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *, + struct pt_regs *))) { jiffy_ticks = (amiga_eclock+HZ/2)/HZ; @@ -796,7 +797,7 @@ } #endif -static void amiga_debug_init(void) +__initfunc(static void amiga_debug_init(void)) { if (!strcmp( m68k_debug_device, "ser" )) { /* no initialization required (?) */ diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/cyberfb.c linux/arch/m68k/amiga/cyberfb.c --- v2.1.36/linux/arch/m68k/amiga/cyberfb.c Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/cyberfb.c Mon May 12 10:35:38 1997 @@ -29,12 +29,13 @@ #include #include #include +#include +#include +#include #include #include #include -#include #include -#include #include "s3blit.h" @@ -1157,7 +1158,7 @@ * Initialization */ -struct fb_info *Cyber_fb_init(long *mem_start) +__initfunc(struct fb_info *Cyber_fb_init(long *mem_start)) { int err; struct Cyber_fb_par par; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/retz3fb.c linux/arch/m68k/amiga/retz3fb.c --- v2.1.36/linux/arch/m68k/amiga/retz3fb.c Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/retz3fb.c Mon May 12 10:35:38 1997 @@ -30,1762 +30,11 @@ #include #include #include +#include +#include #include #include #include -#include -#include - -#include "retz3fb.h" - -/* #define DEBUG if(1) */ -#define DEBUG if(0) - -/* - * Reserve space for one pattern line. - * - * For the time being we only support 4MB boards! - */ - -#define PAT_MEM_SIZE 16*3 -#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE) - -#define arraysize(x) (sizeof(x)/sizeof(*(x))) - -struct retz3_fb_par { - int xres; - int yres; - int xres_vir; - int yres_vir; - int xoffset; - int yoffset; - int bpp; - - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; - - int pixclock; - int left_margin; /* time from sync to picture */ - int right_margin; /* time from picture to sync */ - int upper_margin; /* time from sync to picture */ - int lower_margin; - int hsync_len; /* length of horizontal sync */ - int vsync_len; /* length of vertical sync */ - int vmode; -}; - -struct display_data { - long h_total; /* Horizontal Total */ - long h_sstart; /* Horizontal Sync Start */ - long h_sstop; /* Horizontal Sync Stop */ - long h_bstart; /* Horizontal Blank Start */ - long h_bstop; /* Horizontal Blank Stop */ - long h_dispend; /* Horizontal Display End */ - long v_total; /* Vertical Total */ - long v_sstart; /* Vertical Sync Start */ - long v_sstop; /* Vertical Sync Stop */ - long v_bstart; /* Vertical Blank Start */ - long v_bstop; /* Vertical Blank Stop */ - long v_dispend; /* Horizontal Display End */ -}; - -static struct retz3_fb_par current_par; - -static int current_par_valid = 0; -static int currcon = 0; - -static struct display disp[MAX_NR_CONSOLES]; -static struct fb_info fb_info; - -static int node; /* node of the /dev/fb?current file */ - - -/* - * Switch for Chipset Independency - */ - -static struct fb_hwswitch { - - /* Initialisation */ - - int (*init)(void); - - /* Display Control */ - - int (*encode_fix)(struct fb_fix_screeninfo *fix, struct retz3_fb_par *par); - int (*decode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); - int (*encode_var)(struct fb_var_screeninfo *var, struct retz3_fb_par *par); - int (*getcolreg)(unsigned int regno, unsigned int *red, unsigned - int *green, unsigned int *blue, unsigned int *transp); - int (*setcolreg)(unsigned int regno, unsigned int red, unsigned int - green, unsigned int blue, unsigned int transp); - void (*blank)(int blank); -} *fbhw; - - -/* - * Frame Buffer Name - */ - -static char retz3_fb_name[16] = "RetinaZ3"; - - -static int z3_key = 0; -static unsigned char retz3_color_table [256][4]; -static unsigned long z3_mem; -static unsigned long z3_fbmem; -static unsigned long z3_size; -static volatile unsigned char *z3_regs; - -static long *memstart; - - -/* - * Predefined Video Mode Names - */ - -static char *retz3_fb_modenames[] = { - - /* - * Autodetect (Default) Video Mode - */ - - "default", - - /* - * Predefined Video Modes - */ - - "640x480", /* RetinaZ3 8 bpp */ - "800x600", /* RetinaZ3 8 bpp */ - "1024x768i", - "640x480-16", /* RetinaZ3 16 bpp */ - "640x480-24", /* RetinaZ3 24 bpp */ - - /* - * Dummy Video Modes - */ - - "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", - "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", - "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", - - /* - * User Defined Video Modes - * - * This doesn't work yet!! - */ - - "user0", "user1", "user2", "user3", - "user4", "user5", "user6", "user7" -}; - -/* - * A small info on how to convert XFree86 timing values into fb - * timings - by Frank Neumann: - * -An XFree86 mode line consists of the following fields: - "800x600" 50 800 856 976 1040 600 637 643 666 - < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL - -The fields in the fb_var_screeninfo structure are: - unsigned long pixclock; * pixel clock in ps (pico seconds) * - unsigned long left_margin; * time from sync to picture * - unsigned long right_margin; * time from picture to sync * - unsigned long upper_margin; * time from sync to picture * - unsigned long lower_margin; - unsigned long hsync_len; * length of horizontal sync * - unsigned long vsync_len; * length of vertical sync * - -1) Pixelclock: - xfree: in MHz - fb: In Picoseconds (ps) - - pixclock = 1000000 / DCF - -2) horizontal timings: - left_margin = HFL - SH2 - right_margin = SH1 - HR - hsync_len = SH2 - SH1 - -3) vertical timings: - upper_margin = VFL - SV2 - lower_margin = SV1 - VR - vsync_len = SV2 - SV1 - -Good examples for VESA timings can be found in the XFree86 source tree, -under "programs/Xserver/hw/xfree86/doc/modeDB.txt". -*/ - -/* - * Predefined Video Mode Definitions - */ - -static struct fb_var_screeninfo retz3_fb_predefined[] = { - - /* - * Autodetect (Default) Video Mode - */ - - { 0, }, - - /* - * Predefined Video Modes - */ - - /* - * NB: it is very important to adjust the pixel-clock to the color-depth. - */ - - { - 640, 480, 640, 480, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, - /* - ModeLine "800x600" 36 800 824 896 1024 600 601 603 625 - < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL - */ - { - /* 800 x 600, 8 bpp */ - 800, 600, 800, 600, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 27778, 64, 24, 22, 1, 120, 2, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, - /* - ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace - < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL - */ - { - /* 1024 x 768, 8 bpp, interlaced */ - 1024, 768, 1024, 768, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 22222, 40, 40, 32, 9, 160, 8, - FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED - }, - { - 640, 480, 640, 480, 0, 0, 16, 0, - {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/2, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, - { - 640, 480, 640, 480, 0, 0, 24, 0, - {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCEL_RETINAZ3, 38461/3, 28, 32, 12, 10, 96, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, - - /* - * Dummy Video Modes - */ - - { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, - { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, - { 0, }, { 0, }, - - /* - * User Defined Video Modes - */ - - { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, } -}; - - -#define NUM_TOTAL_MODES arraysize(retz3_fb_predefined) -#define NUM_PREDEF_MODES (5) - - -static int z3fb_inverse = 0; -static int z3fb_mode = 0; - - -/* - * Interface used by the world - */ - -int retz3_probe(void); -void retz3_video_setup(char *options, int *ints); - -static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con); -static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con); -static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con); -static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con); -static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con); -static int retz3_fb_pan_display(struct fb_var_screeninfo *var, int con); -static int retz3_fb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con); - - -/* - * Interface to the low level console driver - */ - -struct fb_info *retz3_fb_init(long *mem_start); /* Through amiga_fb_init() */ -static int z3fb_switch(int con); -static int z3fb_updatevar(int con); -static void z3fb_blank(int blank); -static int z3fb_setcmap(struct fb_cmap *cmap, int con); - - -/* - * Accelerated Functions used by the low level console driver - */ - -void retz3_bitblt(struct fb_var_screeninfo *scr, - unsigned short curx, unsigned short cury, unsigned - short destx, unsigned short desty, unsigned short - width, unsigned short height, unsigned short cmd, - unsigned short mask); -void retz3_fill(unsigned short x, unsigned short y, unsigned short - width, unsigned short height, unsigned short mode, - unsigned short color); - -/* - * Hardware Specific Routines - */ - -static int retz3_init(void); -static int retz3_encode_fix(struct fb_fix_screeninfo *fix, - struct retz3_fb_par *par); -static int retz3_decode_var(struct fb_var_screeninfo *var, - struct retz3_fb_par *par); -static int retz3_encode_var(struct fb_var_screeninfo *var, - struct retz3_fb_par *par); -static int retz3_getcolreg(unsigned int regno, unsigned int *red, - unsigned int *green, unsigned int *blue, - unsigned int *transp); -static int retz3_setcolreg(unsigned int regno, unsigned int red, - unsigned int green, unsigned int blue, - unsigned int transp); -static void retz3_blank(int blank); - - -/* - * Internal routines - */ - -static void retz3_fb_get_par(struct retz3_fb_par *par); -static void retz3_fb_set_par(struct retz3_fb_par *par); -static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive); -static struct fb_cmap *get_default_colormap(int bpp); -static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, - int kspc); -static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, - int kspc); -static void do_install_cmap(int con); -static void memcpy_fs(int fsfromto, void *to, void *from, int len); -static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto); -static int alloc_cmap(struct fb_cmap *cmap, int len, int transp); -static void retz3_fb_set_disp(int con); -static int get_video_mode(const char *name); - - -/* -------------------- Hardware specific routines -------------------------- */ - -static unsigned short find_fq(unsigned int freq) -{ - unsigned long f; - long tmp; - long prev = 0x7fffffff; - long n2, n1 = 3; - unsigned long m; - unsigned short res = 0; - - if (freq <= 31250000) - n2 = 3; - else if (freq <= 62500000) - n2 = 2; - else if (freq <= 125000000) - n2 = 1; - else if (freq <= 250000000) - n2 = 0; - else - return(0); - - - do { - f = freq >> (10 - n2); - - m = (f * n1) / (14318180/1024); - - if (m > 129) - break; - - tmp = (((m * 14318180) >> n2) / n1) - freq; - if (tmp < 0) - tmp = -tmp; - - if (tmp < prev) { - prev = tmp; - res = (((n2 << 5) | (n1-2)) << 8) | (m-2); - } - - } while ( (++n1) <= 21); - - return res; -} - - -static int retz3_set_video(struct fb_var_screeninfo *var, - struct retz3_fb_par *par) -{ - float freq_f; - long freq; - - int xres, hfront, hsync, hback; - int yres, vfront, vsync, vback; - unsigned char tmp; - unsigned short best_freq; - struct display_data data; - - short clocksel = 0; /* Apparantly this is always zero */ - - int bpp = var->bits_per_pixel; - - /* - * XXX - */ - if (bpp == 24) - return 0; - - if ((bpp != 8) && (bpp != 16) && (bpp != 24)) - return -EFAULT; - - par->xoffset = 0; - par->yoffset = 0; - - xres = var->xres * bpp / 4; - hfront = var->right_margin * bpp / 4; - hsync = var->hsync_len * bpp / 4; - hback = var->left_margin * bpp / 4; - - if (var->vmode & FB_VMODE_DOUBLE) - { - yres = var->yres * 2; - vfront = var->lower_margin * 2; - vsync = var->vsync_len * 2; - vback = var->upper_margin * 2; - } - else if (var->vmode & FB_VMODE_INTERLACED) - { - yres = (var->yres + 1) / 2; - vfront = (var->lower_margin + 1) / 2; - vsync = (var->vsync_len + 1) / 2; - vback = (var->upper_margin + 1) / 2; - } - else - { - yres = var->yres; /* -1 ? */ - vfront = var->lower_margin; - vsync = var->vsync_len; - vback = var->upper_margin; - } - - data.h_total = (hback / 8) + (xres / 8) - + (hfront / 8) + (hsync / 8) - 1 /* + 1 */; - data.h_dispend = ((xres + bpp - 1)/ 8) - 1; - data.h_bstart = xres / 8 /* + 1 */; - - data.h_bstop = data.h_total+1 + 2 + 1; - data.h_sstart = (xres / 8) + (hfront / 8) + 1; - data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1; - - data.v_total = yres + vfront + vsync + vback - 1; - - data.v_dispend = yres - 1; - data.v_bstart = yres; - - data.v_bstop = data.v_total; - data.v_sstart = yres + vfront - 1 - 2; - data.v_sstop = yres + vfront + vsync - 1; - -#if 0 /* testing */ - - printk("HBS: %i\n", data.h_bstart); - printk("HSS: %i\n", data.h_sstart); - printk("HSE: %i\n", data.h_sstop); - printk("HBE: %i\n", data.h_bstop); - printk("HT: %i\n", data.h_total); - - printk("hsync: %i\n", hsync); - printk("hfront: %i\n", hfront); - printk("hback: %i\n", hback); - - printk("VBS: %i\n", data.v_bstart); - printk("VSS: %i\n", data.v_sstart); - printk("VSE: %i\n", data.v_sstop); - printk("VBE: %i\n", data.v_bstop); - printk("VT: %i\n", data.v_total); - - printk("vsync: %i\n", vsync); - printk("vfront: %i\n", vfront); - printk("vback: %i\n", vback); -#endif - - if (data.v_total >= 1024) - printk("MAYDAY: v_total >= 1024; bailing out!\n"); - - reg_w(GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); - reg_w(GREG_FEATURE_CONTROL_W, 0x00); - - seq_w(SEQ_RESET, 0x00); - seq_w(SEQ_RESET, 0x03); /* reset sequencer logic */ - - /* - * CLOCKING_MODE bits: - * 2: This one is only set for certain text-modes, wonder if - * it may be for EGA-lines? (it was referred to as CLKDIV2) - * (The CL drivers sets it to 0x21 with the comment: - * FullBandwidth (video off) and 8/9 dot clock) - */ - seq_w(SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); - - seq_w(SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ - seq_w(SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ - seq_w(SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ - seq_w(SEQ_RESET, 0x01); - seq_w(SEQ_RESET, 0x03); - - seq_w(SEQ_EXTENDED_ENABLE, 0x05); - - seq_w(SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ - seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); - seq_w(SEQ_PRIM_HOST_OFF_HI, 0x00); - seq_w(SEQ_LINEAR_0, 0x4a); - seq_w(SEQ_LINEAR_1, 0x00); - - seq_w(SEQ_SEC_HOST_OFF_HI, 0x00); - seq_w(SEQ_SEC_HOST_OFF_LO, 0x00); - seq_w(SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); - - /* - * The lower 4 bits (0-3) are used to set the font-width for - * text-mode - DON'T try to set this for gfx-mode. - */ - seq_w(SEQ_EXT_CLOCK_MODE, 0x10); - seq_w(SEQ_EXT_VIDEO_ADDR, 0x03); - - /* - * Extended Pixel Control: - * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?) - * bit 1: (Packed/Nibble Pixel Format ?) - * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp - */ - seq_w(SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); - - seq_w(SEQ_BUS_WIDTH_FEEDB, 0x04); - seq_w(SEQ_COLOR_EXP_WFG, 0x01); - seq_w(SEQ_COLOR_EXP_WBG, 0x00); - seq_w(SEQ_EXT_RW_CONTROL, 0x00); - seq_w(SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); - seq_w(SEQ_COLOR_KEY_CNTL, 0x40); - seq_w(SEQ_COLOR_KEY_MATCH0, 0x00); - seq_w(SEQ_COLOR_KEY_MATCH1, 0x00); - seq_w(SEQ_COLOR_KEY_MATCH2, 0x00); - seq_w(SEQ_CRC_CONTROL, 0x00); - seq_w(SEQ_PERF_SELECT, 0x10); - seq_w(SEQ_ACM_APERTURE_1, 0x00); - seq_w(SEQ_ACM_APERTURE_2, 0x30); - seq_w(SEQ_ACM_APERTURE_3, 0x00); - seq_w(SEQ_MEMORY_MAP_CNTL, 0x03); - - - /* unlock register CRT0..CRT7 */ - crt_w(CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); - - /* Zuerst zu schreibende Werte nur per printk ausgeben */ - DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total); - crt_w(CRT_HOR_TOTAL, data.h_total & 0xff); - - DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend); - crt_w(CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); - - DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart); - crt_w(CRT_START_HOR_BLANK, data.h_bstart & 0xff); - - DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32); - crt_w(CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); - - DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart); - crt_w(CRT_START_HOR_RETR, data.h_sstart & 0xff); - - tmp = (data.h_sstop & 0x1f); - if (data.h_bstop & 0x20) - tmp |= 0x80; - DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp); - crt_w(CRT_END_HOR_RETR, tmp); - - DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff); - crt_w(CRT_VER_TOTAL, (data.v_total & 0xff)); - - tmp = 0x10; /* LineCompare bit #9 */ - if (data.v_total & 256) - tmp |= 0x01; - if (data.v_dispend & 256) - tmp |= 0x02; - if (data.v_sstart & 256) - tmp |= 0x04; - if (data.v_bstart & 256) - tmp |= 0x08; - if (data.v_total & 512) - tmp |= 0x20; - if (data.v_dispend & 512) - tmp |= 0x40; - if (data.v_sstart & 512) - tmp |= 0x80; - DEBUG printk("CRT_OVERFLOW: %d\n", tmp); - crt_w(CRT_OVERFLOW, tmp); - - crt_w(CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ - - tmp = 0x40; /* LineCompare bit #8 */ - if (data.v_bstart & 512) - tmp |= 0x20; - if (var->vmode & FB_VMODE_DOUBLE) - tmp |= 0x80; - DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp); - crt_w(CRT_MAX_SCAN_LINE, tmp); - - crt_w(CRT_CURSOR_START, 0x00); - crt_w(CRT_CURSOR_END, 8 & 0x1f); /* font height */ - - crt_w(CRT_START_ADDR_HIGH, 0x00); - crt_w(CRT_START_ADDR_LOW, 0x00); - - crt_w(CRT_CURSOR_LOC_HIGH, 0x00); - crt_w(CRT_CURSOR_LOC_LOW, 0x00); - - DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff); - crt_w(CRT_START_VER_RETR, (data.v_sstart & 0xff)); - -#if 1 - /* 5 refresh cycles per scanline */ - DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16); - crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); -#else - DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16); - crt_w(CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); -#endif - DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff); - crt_w(CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); - - DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff); - crt_w(CRT_START_VER_BLANK, (data.v_bstart & 0xff)); - - DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff); - crt_w(CRT_END_VER_BLANK, (data.v_bstop & 0xff)); - - DEBUG printk("CRT_MODE_CONTROL: 0xe3\n"); - crt_w(CRT_MODE_CONTROL, 0xe3); - - DEBUG printk("CRT_LINE_COMPARE: 0xff\n"); - crt_w(CRT_LINE_COMPARE, 0xff); - - tmp = (var->xres_virtual / 8) * (bpp / 8); - crt_w(CRT_OFFSET, tmp); - - crt_w(CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ - - tmp = 0x20; /* Enable extended end bits */ - if (data.h_total & 0x100) - tmp |= 0x01; - if ((data.h_dispend) & 0x100) - tmp |= 0x02; - if (data.h_bstart & 0x100) - tmp |= 0x04; - if (data.h_sstart & 0x100) - tmp |= 0x08; - if (var->vmode & FB_VMODE_INTERLACED) - tmp |= 0x10; - DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp); - crt_w(CRT_EXT_HOR_TIMING1, tmp); - - tmp = 0x00; - if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100) - tmp |= 0x10; - crt_w(CRT_EXT_START_ADDR, tmp); - - tmp = 0x00; - if (data.h_total & 0x200) - tmp |= 0x01; - if ((data.h_dispend) & 0x200) - tmp |= 0x02; - if (data.h_bstart & 0x200) - tmp |= 0x04; - if (data.h_sstart & 0x200) - tmp |= 0x08; - tmp |= ((data.h_bstop & 0xc0) >> 2); - tmp |= ((data.h_sstop & 0x60) << 1); - crt_w(CRT_EXT_HOR_TIMING2, tmp); - DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp); - - tmp = 0x10; /* Line compare bit 10 */ - if (data.v_total & 0x400) - tmp |= 0x01; - if ((data.v_dispend) & 0x400) - tmp |= 0x02; - if (data.v_bstart & 0x400) - tmp |= 0x04; - if (data.v_sstart & 0x400) - tmp |= 0x08; - tmp |= ((data.v_bstop & 0x300) >> 3); - if (data.v_sstop & 0x10) - tmp |= 0x80; - crt_w(CRT_EXT_VER_TIMING, tmp); - DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp); - - crt_w(CRT_MONITOR_POWER, 0x00); - - /* - * Convert from ps to Hz. - */ - freq_f = (1.0/(float)var->pixclock) * 1000000000; - freq = ((long)freq_f) * 1000; - - best_freq = find_fq(freq); - pll_w(0x02, best_freq); - best_freq = find_fq(61000000); - pll_w(0x0a, best_freq); - pll_w(0x0e, 0x22); - - gfx_w(GFX_SET_RESET, 0x00); - gfx_w(GFX_ENABLE_SET_RESET, 0x00); - gfx_w(GFX_COLOR_COMPARE, 0x00); - gfx_w(GFX_DATA_ROTATE, 0x00); - gfx_w(GFX_READ_MAP_SELECT, 0x00); - gfx_w(GFX_GRAPHICS_MODE, 0x00); - gfx_w(GFX_MISC, 0x05); - gfx_w(GFX_COLOR_XCARE, 0x0f); - gfx_w(GFX_BITMASK, 0xff); - - reg_r(ACT_ADDRESS_RESET); - attr_w(ACT_PALETTE0 , 0x00); - attr_w(ACT_PALETTE1 , 0x01); - attr_w(ACT_PALETTE2 , 0x02); - attr_w(ACT_PALETTE3 , 0x03); - attr_w(ACT_PALETTE4 , 0x04); - attr_w(ACT_PALETTE5 , 0x05); - attr_w(ACT_PALETTE6 , 0x06); - attr_w(ACT_PALETTE7 , 0x07); - attr_w(ACT_PALETTE8 , 0x08); - attr_w(ACT_PALETTE9 , 0x09); - attr_w(ACT_PALETTE10, 0x0a); - attr_w(ACT_PALETTE11, 0x0b); - attr_w(ACT_PALETTE12, 0x0c); - attr_w(ACT_PALETTE13, 0x0d); - attr_w(ACT_PALETTE14, 0x0e); - attr_w(ACT_PALETTE15, 0x0f); - reg_r(ACT_ADDRESS_RESET); - - attr_w(ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ - - attr_w(ACT_OVERSCAN_COLOR, 0x00); - attr_w(ACT_COLOR_PLANE_ENA, 0x0f); - attr_w(ACT_HOR_PEL_PANNING, 0x00); - attr_w(ACT_COLOR_SELECT, 0x00); - - reg_r(ACT_ADDRESS_RESET); - reg_w(ACT_DATA, 0x20); - - reg_w(VDAC_MASK, 0xff); - - /* - * Extended palette adressing ??? - */ - switch (bpp){ - case 8: - reg_w(0x83c6, 0x00); - break; - case 16: - reg_w(0x83c6, 0x60); - break; - case 24: - reg_w(0x83c6, 0xe0); - break; - default: - printk("Illegal color-depth: %i\n", bpp); - } - - reg_w(VDAC_ADDRESS, 0x00); - - seq_w(SEQ_MAP_MASK, 0x0f ); - - return 0; -} - -/* - * Initialization - * - * Set the default video mode for this chipset. If a video mode was - * specified on the command line, it will override the default mode. - */ - -static int retz3_init(void) -{ - int i; -#if 0 - volatile unsigned long *CursorBase; -#endif - unsigned long board_addr, board_size; - struct ConfigDev *cd; - - cd = zorro_get_board (z3_key); - zorro_config_board (z3_key, 0); - board_addr = (unsigned long)cd->cd_BoardAddr; - board_size = (unsigned long)cd->cd_BoardSize; - - for (i = 0; i < 256; i++){ - for (i = 0; i < 256; i++){ - retz3_color_table [i][0] = i; - retz3_color_table [i][1] = i; - retz3_color_table [i][2] = i; - retz3_color_table [i][3] = 0; - } - } - - *memstart = (*memstart + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - - z3_mem = kernel_map (board_addr, board_size, - KERNELMAP_NOCACHE_SER, memstart); - - z3_regs = (char*) z3_mem; - z3_fbmem = z3_mem + VIDEO_MEM_OFFSET; - - /* Get memory size - for now we asume its a 4MB board */ - - z3_size = 0x00400000; /* 4 MB */ - - memset ((char*)z3_fbmem, 0, z3_size); - - /* Disable hardware cursor */ - - seq_w(SEQ_CURSOR_Y_INDEX, 0x00); - - -#if 0 - /* Initialize hardware cursor */ - CursorBase = (unsigned long *)((char *)(z3_mem) + z3_size - 0x400); - for (i=0; i < 8; i++){ - *(CursorBase +(i*4)) = 0xffffff00; - *(CursorBase+1+(i*4)) = 0xffff0000; - *(CursorBase+2+(i*4)) = 0xffff0000; - *(CursorBase+3+(i*4)) = 0xffff0000; - } - for (i=8; i < 64; i++){ - *(CursorBase +(i*4)) = 0xffff0000; - *(CursorBase+1+(i*4)) = 0xffff0000; - *(CursorBase+2+(i*4)) = 0xffff0000; - *(CursorBase+3+(i*4)) = 0xffff0000; - } -#endif - - retz3_setcolreg (255, 56, 100, 160, 0); - retz3_setcolreg (254, 0, 0, 0, 0); - - return 0; -} - - -/* - * This function should fill in the `fix' structure based on the - * values in the `par' structure. - */ - -static int retz3_encode_fix(struct fb_fix_screeninfo *fix, - struct retz3_fb_par *par) -{ - int i; - - strcpy(fix->id, retz3_fb_name); - fix->smem_start = z3_fbmem; - fix->smem_len = z3_size; - - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - if (par->bpp == 8) - fix->visual = FB_VISUAL_PSEUDOCOLOR; - else - fix->visual = FB_VISUAL_DIRECTCOLOR; - - fix->xpanstep = 0; - fix->ypanstep = 0; - fix->ywrapstep = 0; - fix->line_length = 0; - - for (i = 0; i < arraysize(fix->reserved); i++) - fix->reserved[i] = 0; - - return 0; -} - - -/* - * Get the video params out of `var'. If a value doesn't fit, round - * it up, if it's too big, return -EINVAL. - */ - -static int retz3_decode_var(struct fb_var_screeninfo *var, - struct retz3_fb_par *par) -{ - par->xres = var->xres; - par->yres = var->yres; - par->xres_vir = var->xres_virtual; - par->yres_vir = var->yres_virtual; - par->bpp = var->bits_per_pixel; - par->pixclock = var->pixclock; - par->vmode = var->vmode; - - par->red = var->red; - par->green = var->green; - par->blue = var->blue; - par->transp = var->transp; - - par->left_margin = var->left_margin; - par->right_margin = var->right_margin; - par->upper_margin = var->upper_margin; - par->lower_margin = var->lower_margin; - par->hsync_len = var->hsync_len; - par->vsync_len = var->vsync_len; - - return 0; -} - - -/* - * Fill the `var' structure based on the values in `par' and maybe - * other values read out of the hardware. - */ - -static int retz3_encode_var(struct fb_var_screeninfo *var, - struct retz3_fb_par *par) -{ - int i; - - var->xres = par->xres; - var->yres = par->yres; - var->xres_virtual = par->xres_vir; - var->yres_virtual = par->yres_vir; - var->xoffset = 0; - var->yoffset = 0; - - var->bits_per_pixel = par->bpp; - var->grayscale = 0; - - var->red = par->red; - var->green = par->green; - var->blue = par->blue; - var->transp = par->transp; - - var->nonstd = 0; - var->activate = 0; - - var->height = -1; - var->width = -1; - - var->accel = FB_ACCEL_RETINAZ3; - - var->pixclock = par->pixclock; - - var->sync = 0; /* ??? */ - var->left_margin = par->left_margin; - var->right_margin = par->right_margin; - var->upper_margin = par->upper_margin; - var->lower_margin = par->lower_margin; - var->hsync_len = par->hsync_len; - var->vsync_len = par->vsync_len; - - for (i = 0; i < arraysize(var->reserved); i++) - var->reserved[i] = 0; - - var->vmode = par->vmode; - return 0; -} - - -/* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int retz3_setcolreg(unsigned int regno, unsigned int red, - unsigned int green, unsigned int blue, - unsigned int transp) -{ - /* We'll get to this */ - - if (regno > 255) - return 1; - - retz3_color_table [regno][0] = red & 0xff; - retz3_color_table [regno][1] = green & 0xff; - retz3_color_table [regno][2] = blue & 0xff; - retz3_color_table [regno][3] = transp; - - reg_w(VDAC_ADDRESS_W, regno); - reg_w(VDAC_DATA, (red & 0xff) >> 2); - reg_w(VDAC_DATA, (green & 0xff) >> 2); - reg_w(VDAC_DATA, (blue & 0xff) >> 2); - - return 0; -} - - -/* - * Read a single color register and split it into - * colors/transparent. Return != 0 for invalid regno. - */ - -static int retz3_getcolreg(unsigned int regno, unsigned int *red, - unsigned int *green, unsigned int *blue, - unsigned int *transp) -{ - if (regno > 255) - return 1; - *red = retz3_color_table [regno][0]; - *green = retz3_color_table [regno][1]; - *blue = retz3_color_table [regno][2]; - *transp = retz3_color_table [regno][3]; - return 0; -} - - -/* - * (Un)Blank the screen - */ - -void retz3_blank(int blank) -{ - int i; - - if (blank) - for (i = 0; i < 256; i++){ - reg_w(VDAC_ADDRESS_W, i); - reg_w(VDAC_DATA, 0); - reg_w(VDAC_DATA, 0); - reg_w(VDAC_DATA, 0); - } - else - for (i = 0; i < 256; i++){ - reg_w(VDAC_ADDRESS_W, i); - reg_w(VDAC_DATA, retz3_color_table [i][0] >> 2); - reg_w(VDAC_DATA, retz3_color_table [i][1] >> 2); - reg_w(VDAC_DATA, retz3_color_table [i][2] >> 2); - } -} - - -void retz3_bitblt (struct fb_var_screeninfo *var, - unsigned short srcx, unsigned short srcy, unsigned - short destx, unsigned short desty, unsigned short - width, unsigned short height, unsigned short cmd, - unsigned short mask) -{ - - volatile unsigned long *acm = (unsigned long *) (z3_mem + ACM_OFFSET); - unsigned long *pattern = (unsigned long *)(z3_fbmem + PAT_MEM_OFF); - - unsigned short mod; - unsigned long tmp; - unsigned long pat, src, dst; - unsigned char blt_status; - - int i, xres_virtual = var->xres_virtual; - short bpp = (var->bits_per_pixel & 0xff); - - if (bpp < 8) - bpp = 8; - - tmp = mask | (mask << 16); - -#if 0 - /* - * Check for blitter finished before we start messing with the - * pattern. - */ - do{ - blt_status = *(((volatile unsigned char *)acm) + - (ACM_START_STATUS + 2)); - }while ((blt_status & 1) == 0); -#endif - - i = 0; - do{ - *pattern++ = tmp; - }while(i++ < bpp/4); - - tmp = cmd << 8; - *(acm + ACM_RASTEROP_ROTATION/4) = tmp; - - mod = 0xc0c2; - - pat = 8 * PAT_MEM_OFF; - dst = bpp * (destx + desty * xres_virtual); - - /* - * Source is not set for clear. - */ - if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) { - src = bpp * (srcx + srcy * xres_virtual); - - if (destx > srcx) { - mod &= ~0x8000; - src += bpp * (width - 1); - dst += bpp * (width - 1); - pat += bpp * 2; - } - if (desty > srcy) { - mod &= ~0x4000; - src += bpp * (height - 1) * xres_virtual; - dst += bpp * (height - 1) * xres_virtual; - pat += bpp * 4; - } - - *(acm + ACM_SOURCE/4) = cpu_to_le32(src); - } - - *(acm + ACM_PATTERN/4) = cpu_to_le32(pat); - - *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst); - - tmp = mod << 16; - *(acm + ACM_CONTROL/4) = tmp; - - tmp = width | (height << 16); - - *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp); - - *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00; - *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01; - - /* - * No reason to wait for the blitter to finish, it is better - * just to check if it has finished before we use it again. - */ -#if 1 -#if 0 - while ((*(((volatile unsigned char *)acm) + - (ACM_START_STATUS + 2)) & 1) == 0); -#else - do{ - blt_status = *(((volatile unsigned char *)acm) + - (ACM_START_STATUS + 2)); - } - while ((blt_status & 1) == 0); -#endif -#endif -} - -#if 0 -void retz3_fill (unsigned short x, unsigned short y, unsigned - short width, unsigned short height, - unsigned short mode, unsigned short color) -{ - -} -#endif - - -/************************************************************** - * Move cursor to x, y - */ -void retz3_MoveCursor (unsigned short x, unsigned short y) -{ - /* Guess we gotta deal with the cursor at some point */ -} - - -/* -------------------- Interfaces to hardware functions -------------------- */ - - -static struct fb_hwswitch retz3_switch = { - retz3_init, retz3_encode_fix, retz3_decode_var, retz3_encode_var, - retz3_getcolreg, retz3_setcolreg, retz3_blank -}; - - -/* -------------------- Generic routines ------------------------------------ */ - - -/* - * Fill the hardware's `par' structure. - */ - -static void retz3_fb_get_par(struct retz3_fb_par *par) -{ - if (current_par_valid) - *par = current_par; - else - fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], par); -} - - -static void retz3_fb_set_par(struct retz3_fb_par *par) -{ - current_par = *par; - current_par_valid = 1; -} - - -static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) -{ - int err, activate; - struct retz3_fb_par par; - - if ((err = fbhw->decode_var(var, &par))) - return err; - activate = var->activate; - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) - retz3_fb_set_par(&par); - fbhw->encode_var(var, &par); - var->activate = activate; - -#if 1 - retz3_set_video(var, ¤t_par); -#endif - return 0; -} - - -/* - * Default Colormaps - */ - -static unsigned short red16[] = - { 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xc000, - 0x8000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }; -static unsigned short green16[] = - { 0x0000, 0x0000, 0xc000, 0xc000, 0x0000, 0x0000, 0xc000, 0xc000, - 0x8000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff }; -static unsigned short blue16[] = - { 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000, - 0x8000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff }; - - -static struct fb_cmap default_16_colors = - { 0, 16, red16, green16, blue16, NULL }; - - -static struct fb_cmap *get_default_colormap(int bpp) -{ - return &default_16_colors; -} - - -#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7fff-(val))>>16) -#define CNVT_FROMHW(val,width) (((width) ? ((((val)<<16)-(val)) / \ - ((1<<(width))-1)) : 0)) - -static int do_fb_get_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, - int kspc) -{ - int i, start; - unsigned short *red, *green, *blue, *transp; - unsigned int hred, hgreen, hblue, htransp; - - red = cmap->red; - green = cmap->green; - blue = cmap->blue; - transp = cmap->transp; - start = cmap->start; - - if (start < 0) - return -EINVAL; - for (i = 0; i < cmap->len; i++) { - if (fbhw->getcolreg(start++, &hred, &hgreen, &hblue, &htransp)) - return 0; - hred = CNVT_FROMHW(hred, var->red.length); - hgreen = CNVT_FROMHW(hgreen, var->green.length); - hblue = CNVT_FROMHW(hblue, var->blue.length); - htransp = CNVT_FROMHW(htransp, var->transp.length); - if (kspc) { - *red = hred; - *green = hgreen; - *blue = hblue; - if (transp) - *transp = htransp; - } else { - put_user(hred, red); - put_user(hgreen, green); - put_user(hblue, blue); - if (transp) - put_user(htransp, transp); - } - red++; - green++; - blue++; - if (transp) - transp++; - } - return 0; -} - - -static int do_fb_set_cmap(struct fb_cmap *cmap, struct fb_var_screeninfo *var, - int kspc) -{ - int i, start; - unsigned short *red, *green, *blue, *transp; - unsigned int hred, hgreen, hblue, htransp; - - red = cmap->red; - green = cmap->green; - blue = cmap->blue; - transp = cmap->transp; - start = cmap->start; - - if (start < 0) - return -EINVAL; - for (i = 0; i < cmap->len; i++) { - if (kspc) { - hred = *red; - hgreen = *green; - hblue = *blue; - htransp = transp ? *transp : 0; - } else { - get_user(hred, red); - get_user(hgreen, green); - get_user(hblue, blue); - if (transp) - get_user(htransp, transp); - else - htransp = 0; - } - hred = CNVT_TOHW(hred, var->red.length); - hgreen = CNVT_TOHW(hgreen, var->green.length); - hblue = CNVT_TOHW(hblue, var->blue.length); - htransp = CNVT_TOHW(htransp, var->transp.length); - red++; - green++; - blue++; - if (transp) - transp++; - if (fbhw->setcolreg(start++, hred, hgreen, hblue, htransp)) - return 0; - } - return 0; -} - - -static void do_install_cmap(int con) -{ - if (con != currcon) - return; - if (disp[con].cmap.len) - do_fb_set_cmap(&disp[con].cmap, &disp[con].var, 1); - else - do_fb_set_cmap(get_default_colormap(disp[con].var.bits_per_pixel), - &disp[con].var, 1); -} - - -static void memcpy_fs(int fsfromto, void *to, void *from, int len) -{ - switch (fsfromto) { - case 0: - memcpy(to, from, len); - return; - case 1: - copy_from_user(to, from, len); - return; - case 2: - copy_to_user(to, from, len); - return; - } -} - - -static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) -{ - int size; - int tooff = 0, fromoff = 0; - - if (to->start > from->start) - fromoff = to->start-from->start; - else - tooff = from->start-to->start; - size = to->len-tooff; - if (size > from->len-fromoff) - size = from->len-fromoff; - if (size < 0) - return; - size *= sizeof(unsigned short); - memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); - memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); - memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); - if (from->transp && to->transp) - memcpy_fs(fsfromto, to->transp+tooff, - from->transp+fromoff, size); -} - - -static int alloc_cmap(struct fb_cmap *cmap, int len, int transp) -{ - int size = len*sizeof(unsigned short); - - if (cmap->len != len) { - if (cmap->red) - kfree(cmap->red); - if (cmap->green) - kfree(cmap->green); - if (cmap->blue) - kfree(cmap->blue); - if (cmap->transp) - kfree(cmap->transp); - cmap->red = cmap->green = cmap->blue = cmap->transp = NULL; - cmap->len = 0; - if (!len) - return 0; - if (!(cmap->red = kmalloc(size, GFP_ATOMIC))) - return -1; - if (!(cmap->green = kmalloc(size, GFP_ATOMIC))) - return -1; - if (!(cmap->blue = kmalloc(size, GFP_ATOMIC))) - return -1; - if (transp) { - if (!(cmap->transp = kmalloc(size, GFP_ATOMIC))) - return -1; - } else - cmap->transp = NULL; - } - cmap->start = 0; - cmap->len = len; - copy_cmap(get_default_colormap(len), cmap, 0); - return 0; -} - - -/* - * Get the Fixed Part of the Display - */ - -static int retz3_fb_get_fix(struct fb_fix_screeninfo *fix, int con) -{ - struct retz3_fb_par par; - int error = 0; - - if (con == -1) - retz3_fb_get_par(&par); - else - error = fbhw->decode_var(&disp[con].var, &par); - return(error ? error : fbhw->encode_fix(fix, &par)); -} - - -/* - * Get the User Defined Part of the Display - */ - -static int retz3_fb_get_var(struct fb_var_screeninfo *var, int con) -{ - struct retz3_fb_par par; - int error = 0; - - if (con == -1) { - retz3_fb_get_par(&par); - error = fbhw->encode_var(var, &par); - } else - *var = disp[con].var; - return error; -} - - -static void retz3_fb_set_disp(int con) -{ - struct fb_fix_screeninfo fix; - - retz3_fb_get_fix(&fix, con); - if (con == -1) - con = 0; - disp[con].screen_base = (unsigned char *)fix.smem_start; - disp[con].visual = fix.visual; - disp[con].type = fix.type; - disp[con].type_aux = fix.type_aux; - disp[con].ypanstep = fix.ypanstep; - disp[con].ywrapstep = fix.ywrapstep; - disp[con].can_soft_blank = 1; - disp[con].inverse = z3fb_inverse; -} - - -/* - * Set the User Defined Part of the Display - */ - -static int retz3_fb_set_var(struct fb_var_screeninfo *var, int con) -{ - int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp; - - if ((err = do_fb_set_var(var, con == currcon))) - return err; - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - oldxres = disp[con].var.xres; - oldyres = disp[con].var.yres; - oldvxres = disp[con].var.xres_virtual; - oldvyres = disp[con].var.yres_virtual; - oldbpp = disp[con].var.bits_per_pixel; - disp[con].var = *var; - if (oldxres != var->xres || oldyres != var->yres || - oldvxres != var->xres_virtual || - oldvyres != var->yres_virtual || - oldbpp != var->bits_per_pixel) { - retz3_fb_set_disp(con); - (*fb_info.changevar)(con); - alloc_cmap(&disp[con].cmap, 0, 0); - do_install_cmap(con); - } - } - var->activate = 0; - return 0; -} - - -/* - * Get the Colormap - */ - -static int retz3_fb_get_cmap(struct fb_cmap *cmap, int kspc, int con) -{ - if (con == currcon) /* current console? */ - return(do_fb_get_cmap(cmap, &disp[con].var, kspc)); - else if (disp[con].cmap.len) /* non default colormap? */ - copy_cmap(&disp[con].cmap, cmap, kspc ? 0 : 2); - else - copy_cmap(get_default_colormap(disp[con].var.bits_per_pixel), - cmap, kspc ? 0 : 2); - return 0; -} - - -/* - * Set the Colormap - */ - -static int retz3_fb_set_cmap(struct fb_cmap *cmap, int kspc, int con) -{ - int err; - - if (!disp[con].cmap.len) { /* no colormap allocated? */ - if ((err = alloc_cmap(&disp[con].cmap, - 1<init(); - - if (z3fb_mode == -1) - z3fb_mode = 1; - - fbhw->decode_var(&retz3_fb_predefined[z3fb_mode], &par); - fbhw->encode_var(&retz3_fb_predefined[0], &par); - - strcpy(fb_info.modename, retz3_fb_name); - fb_info.disp = disp; - fb_info.switch_con = &z3fb_switch; - fb_info.updatevar = &z3fb_updatevar; - fb_info.blank = &z3fb_blank; - fb_info.setcmap = &z3fb_setcmap; - - do_fb_set_var(&retz3_fb_predefined[0], 0); - retz3_fb_get_var(&disp[0].var, -1); - retz3_fb_set_disp(-1); - do_install_cmap(0); - - return &fb_info; -} - - -static int z3fb_switch(int con) -{ - /* Do we have to save the colormap? */ - if (disp[currcon].cmap.len) - do_fb_get_cmap(&disp[currcon].cmap, &disp[currcon].var, 1); - - do_fb_set_var(&disp[con].var, 1); - currcon = con; - /* Install new colormap */ - do_install_cmap(con); - return 0; -} - - -/* - * Update the `var' structure (called by fbcon.c) - * - * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. - * Since it's called by a kernel driver, no range checking is done. - */ - -static int z3fb_updatevar(int con) -{ - return 0; -} - - -/* - * Blank the display. - */ - -static void z3fb_blank(int blank) -{ - fbhw->blank(blank); -} - - -/* - * Set the colormap - */ - -static int z3fb_setcmap(struct fb_cmap *cmap, int con) -{ - return(retz3_fb_set_cmap(cmap, 1, con)); -} - - -/* - * Get a Video Mode - */ - -static int get_video_mode(const char *name) -{ - int i; - - for (i = 1; i <= NUM_PREDEF_MODES; i++) - if (!strcmp(name, retz3_fb_modenames[i])){ - retz3_fb_predefined[0] = retz3_fb_predefined[i]; - return i; - } - return -1; -} -/* - * Linux/arch/m68k/amiga/retz3fb.c -- Low level implementation of the - * RetinaZ3 frame buffer device - * - * Copyright (C) 1997 Jes Sorensen - * - * This file is based on the CyberVision64 frame buffer device and - * the generic Cirrus Logic driver. - * - * cyberfb.c: Copyright (C) 1996 Martin Apel, - * Geert Uytterhoeven - * clgen.c: Copyright (C) 1996 Frank Neumann - * - * History: - * - 22 Jan 97: Initial work - * - 14 Feb 97: Screen initialization works somewhat, still only - * 8-bit packed pixel is supported. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include "retz3fb.h" @@ -3402,7 +1651,7 @@ * Initialization */ -struct fb_info *retz3_fb_init(long *mem_start) +__initfunc(struct fb_info *retz3_fb_init(long *mem_start)) { int err; struct retz3_fb_par par; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/retz3fb.h linux/arch/m68k/amiga/retz3fb.h --- v2.1.36/linux/arch/m68k/amiga/retz3fb.h Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/retz3fb.h Mon May 12 10:35:38 1997 @@ -284,289 +284,3 @@ #define Z3BLTorInverted 0xb0 /* NOT src OR dst */ #define Z3BLTnand 0x70 /* NOT src OR NOT dst */ #define Z3BLTset 0xf0 /* 1 */ -/* - * Linux/arch/m68k/amiga/retz3fb.h -- Defines and macros for the - * RetinaZ3 frame buffer device - * - * Copyright (C) 1997 Jes Sorensen - * - * History: - * - 22 Jan 97: Initial work - * - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -/* - * Macros to read and write to registers. - */ -#define reg_w(reg,dat) (*(z3_regs + reg) = dat) -#define reg_r(reg) (*(z3_regs + reg)) - -/* - * Macro to access the sequencer. - */ -#define seq_w(sreg,sdat) \ - do{ reg_w(SEQ_IDX, sreg); reg_w(SEQ_DATA, sdat); } while(0) - -/* - * Macro to access the CRT controller. - */ -#define crt_w(creg,cdat) \ - do{ reg_w(CRT_IDX, creg); reg_w(CRT_DATA, cdat); } while(0) - -/* - * Macro to access the graphics controller. - */ -#define gfx_w(greg,gdat) \ - do{ reg_w(GFX_IDX, greg); reg_w(GFX_DATA, gdat); } while(0) - -/* - * Macro to access the attribute controller. - */ -#define attr_w(areg,adat) \ - do{ reg_w(ACT_IDX, areg); reg_w(ACT_DATA, adat); } while(0) - -/* - * Macro to access the pll. - */ -#define pll_w(preg,pdat) \ - do{ reg_w(PLL_IDX, preg); \ - reg_w(PLL_DATA, (pdat & 0xff)); \ - reg_w(PLL_DATA, (pdat >> 8));\ - } while(0) - -/* - * Offsets - */ -#define VIDEO_MEM_OFFSET 0x00c00000 -#define ACM_OFFSET 0x00b00000 - -/* - * Accelerator Control Menu - */ -#define ACM_PRIMARY_OFFSET 0x00 -#define ACM_SECONDARY_OFFSET 0x04 -#define ACM_MODE_CONTROL 0x08 -#define ACM_CURSOR_POSITION 0x0c -#define ACM_START_STATUS 0x30 -#define ACM_CONTROL 0x34 -#define ACM_RASTEROP_ROTATION 0x38 -#define ACM_BITMAP_DIMENSION 0x3c -#define ACM_DESTINATION 0x40 -#define ACM_SOURCE 0x44 -#define ACM_PATTERN 0x48 -#define ACM_FOREGROUND 0x4c -#define ACM_BACKGROUND 0x50 - -/* - * Video DAC addresses - */ -#define VDAC_ADDRESS 0x03c8 -#define VDAC_ADDRESS_W 0x03c8 -#define VDAC_ADDRESS_R 0x03c7 -#define VDAC_STATE 0x03c7 -#define VDAC_DATA 0x03c9 -#define VDAC_MASK 0x03c6 - -/* - * Sequencer - */ -#define SEQ_IDX 0x03c4 /* Sequencer Index */ -#define SEQ_DATA 0x03c5 -#define SEQ_RESET 0x00 -#define SEQ_CLOCKING_MODE 0x01 -#define SEQ_MAP_MASK 0x02 -#define SEQ_CHAR_MAP_SELECT 0x03 -#define SEQ_MEMORY_MODE 0x04 -#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */ -#define SEQ_UNKNOWN1 0x06 -#define SEQ_UNKNOWN2 0x07 -#define SEQ_CHIP_ID 0x08 -#define SEQ_UNKNOWN3 0x09 -#define SEQ_CURSOR_COLOR1 0x0a -#define SEQ_CURSOR_COLOR0 0x0b -#define SEQ_CURSOR_CONTROL 0x0c -#define SEQ_CURSOR_X_LOC_HI 0x0d -#define SEQ_CURSOR_X_LOC_LO 0x0e -#define SEQ_CURSOR_Y_LOC_HI 0x0f -#define SEQ_CURSOR_Y_LOC_LO 0x10 -#define SEQ_CURSOR_X_INDEX 0x11 -#define SEQ_CURSOR_Y_INDEX 0x12 -#define SEQ_CURSOR_STORE_HI 0x13 -#define SEQ_CURSOR_STORE_LO 0x14 -#define SEQ_CURSOR_ST_OFF_HI 0x15 -#define SEQ_CURSOR_ST_OFF_LO 0x16 -#define SEQ_CURSOR_PIXELMASK 0x17 -#define SEQ_PRIM_HOST_OFF_HI 0x18 -#define SEQ_PRIM_HOST_OFF_LO 0x19 -#define SEQ_LINEAR_0 0x1a -#define SEQ_LINEAR_1 0x1b -#define SEQ_SEC_HOST_OFF_HI 0x1c -#define SEQ_SEC_HOST_OFF_LO 0x1d -#define SEQ_EXTENDED_MEM_ENA 0x1e -#define SEQ_EXT_CLOCK_MODE 0x1f -#define SEQ_EXT_VIDEO_ADDR 0x20 -#define SEQ_EXT_PIXEL_CNTL 0x21 -#define SEQ_BUS_WIDTH_FEEDB 0x22 -#define SEQ_PERF_SELECT 0x23 -#define SEQ_COLOR_EXP_WFG 0x24 -#define SEQ_COLOR_EXP_WBG 0x25 -#define SEQ_EXT_RW_CONTROL 0x26 -#define SEQ_MISC_FEATURE_SEL 0x27 -#define SEQ_COLOR_KEY_CNTL 0x28 -#define SEQ_COLOR_KEY_MATCH0 0x29 -#define SEQ_COLOR_KEY_MATCH1 0x2a -#define SEQ_COLOR_KEY_MATCH2 0x2b -#define SEQ_UNKNOWN6 0x2c -#define SEQ_CRC_CONTROL 0x2d -#define SEQ_CRC_DATA_LOW 0x2e -#define SEQ_CRC_DATA_HIGH 0x2f -#define SEQ_MEMORY_MAP_CNTL 0x30 -#define SEQ_ACM_APERTURE_1 0x31 -#define SEQ_ACM_APERTURE_2 0x32 -#define SEQ_ACM_APERTURE_3 0x33 -#define SEQ_BIOS_UTILITY_0 0x3e -#define SEQ_BIOS_UTILITY_1 0x3f - -/* - * Graphics Controller - */ -#define GFX_IDX 0x03ce -#define GFX_DATA 0x03cf -#define GFX_SET_RESET 0x00 -#define GFX_ENABLE_SET_RESET 0x01 -#define GFX_COLOR_COMPARE 0x02 -#define GFX_DATA_ROTATE 0x03 -#define GFX_READ_MAP_SELECT 0x04 -#define GFX_GRAPHICS_MODE 0x05 -#define GFX_MISC 0x06 -#define GFX_COLOR_XCARE 0x07 -#define GFX_BITMASK 0x08 - -/* - * CRT Controller - */ -#define CRT_IDX 0x03d4 -#define CRT_DATA 0x03d5 -#define CRT_HOR_TOTAL 0x00 -#define CRT_HOR_DISP_ENA_END 0x01 -#define CRT_START_HOR_BLANK 0x02 -#define CRT_END_HOR_BLANK 0x03 -#define CRT_START_HOR_RETR 0x04 -#define CRT_END_HOR_RETR 0x05 -#define CRT_VER_TOTAL 0x06 -#define CRT_OVERFLOW 0x07 -#define CRT_PRESET_ROW_SCAN 0x08 -#define CRT_MAX_SCAN_LINE 0x09 -#define CRT_CURSOR_START 0x0a -#define CRT_CURSOR_END 0x0b -#define CRT_START_ADDR_HIGH 0x0c -#define CRT_START_ADDR_LOW 0x0d -#define CRT_CURSOR_LOC_HIGH 0x0e -#define CRT_CURSOR_LOC_LOW 0x0f -#define CRT_START_VER_RETR 0x10 -#define CRT_END_VER_RETR 0x11 -#define CRT_VER_DISP_ENA_END 0x12 -#define CRT_OFFSET 0x13 -#define CRT_UNDERLINE_LOC 0x14 -#define CRT_START_VER_BLANK 0x15 -#define CRT_END_VER_BLANK 0x16 -#define CRT_MODE_CONTROL 0x17 -#define CRT_LINE_COMPARE 0x18 -#define CRT_UNKNOWN1 0x19 -#define CRT_UNKNOWN2 0x1a -#define CRT_UNKNOWN3 0x1b -#define CRT_UNKNOWN4 0x1c -#define CRT_UNKNOWN5 0x1d -#define CRT_UNKNOWN6 0x1e -#define CRT_UNKNOWN7 0x1f -#define CRT_UNKNOWN8 0x20 -#define CRT_UNKNOWN9 0x21 -#define CRT_UNKNOWN10 0x22 -#define CRT_UNKNOWN11 0x23 -#define CRT_UNKNOWN12 0x24 -#define CRT_UNKNOWN13 0x25 -#define CRT_UNKNOWN14 0x26 -#define CRT_UNKNOWN15 0x27 -#define CRT_UNKNOWN16 0x28 -#define CRT_UNKNOWN17 0x29 -#define CRT_UNKNOWN18 0x2a -#define CRT_UNKNOWN19 0x2b -#define CRT_UNKNOWN20 0x2c -#define CRT_UNKNOWN21 0x2d -#define CRT_UNKNOWN22 0x2e -#define CRT_UNKNOWN23 0x2f -#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */ -#define CRT_EXT_START_ADDR 0x31 -#define CRT_EXT_HOR_TIMING2 0x32 -#define CRT_EXT_VER_TIMING 0x33 -#define CRT_MONITOR_POWER 0x34 - -/* - * General Registers - */ -#define GREG_STATUS0_R 0x03c2 -#define GREG_STATUS1_R 0x03da -#define GREG_MISC_OUTPUT_R 0x03cc -#define GREG_MISC_OUTPUT_W 0x03c2 -#define GREG_FEATURE_CONTROL_R 0x03ca -#define GREG_FEATURE_CONTROL_W 0x03da -#define GREG_POS 0x0102 - -/* - * Attribute Controller - */ -#define ACT_IDX 0x03C0 -#define ACT_ADDRESS_R 0x03C0 -#define ACT_DATA 0x03C0 -#define ACT_ADDRESS_RESET 0x03DA -#define ACT_PALETTE0 0x00 -#define ACT_PALETTE1 0x01 -#define ACT_PALETTE2 0x02 -#define ACT_PALETTE3 0x03 -#define ACT_PALETTE4 0x04 -#define ACT_PALETTE5 0x05 -#define ACT_PALETTE6 0x06 -#define ACT_PALETTE7 0x07 -#define ACT_PALETTE8 0x08 -#define ACT_PALETTE9 0x09 -#define ACT_PALETTE10 0x0A -#define ACT_PALETTE11 0x0B -#define ACT_PALETTE12 0x0C -#define ACT_PALETTE13 0x0D -#define ACT_PALETTE14 0x0E -#define ACT_PALETTE15 0x0F -#define ACT_ATTR_MODE_CNTL 0x10 -#define ACT_OVERSCAN_COLOR 0x11 -#define ACT_COLOR_PLANE_ENA 0x12 -#define ACT_HOR_PEL_PANNING 0x13 -#define ACT_COLOR_SELECT 0x14 - -/* - * PLL - */ -#define PLL_IDX 0x83c8 -#define PLL_DATA 0x83c9 - -/* - * Blitter operations - */ -#define Z3BLTclear 0x00 /* 0 */ -#define Z3BLTand 0x80 /* src AND dst */ -#define Z3BLTandReverse 0x40 /* src AND NOT dst */ -#define Z3BLTcopy 0xc0 /* src */ -#define Z3BLTandInverted 0x20 /* NOT src AND dst */ -#define Z3BLTnoop 0xa0 /* dst */ -#define Z3BLTxor 0x60 /* src XOR dst */ -#define Z3BLTor 0xe0 /* src OR dst */ -#define Z3BLTnor 0x10 /* NOT src AND NOT dst */ -#define Z3BLTequiv 0x90 /* NOT src XOR dst */ -#define Z3BLTinvert 0x50 /* NOT dst */ -#define Z3BLTorReverse 0xd0 /* src OR NOT dst */ -#define Z3BLTcopyInverted 0x30 /* NOT src */ -#define Z3BLTorInverted 0xb0 /* NOT src OR dst */ -#define Z3BLTnand 0x70 /* NOT src OR NOT dst */ -#define Z3BLTset 0xf0 /* 1 */ diff -u --recursive --new-file v2.1.36/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c --- v2.1.36/linux/arch/m68k/amiga/zorro.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/amiga/zorro.c Mon May 12 10:35:38 1997 @@ -13,10 +13,11 @@ #include #include #include +#include +#include #include #include #include -#include #ifdef CONFIG_ZORRO @@ -415,10 +416,6 @@ PROD("MVD 819", MVD_819) END -BEGIN_PROD(DELACOMP) - PROD("RAM Expansion 2000", DELACOMP_RAM_2000) -END - BEGIN_PROD(VILLAGE_TRONIC) PROD("Domino Graphics Board (RAM)", DOMINO_RAM) PROD("Domino Graphics Board (REG)", DOMINO_REG) @@ -656,7 +653,6 @@ MANUF("Helfrich", HELFRICH1) MANUF("Software Result Enterprises", SW_RESULT_ENTS) MANUF("Masoboshi", MASOBOSHI) - MANUF("DelaComp", DELACOMP) MANUF("Village Tronic", VILLAGE_TRONIC) MANUF("Utilities Unlimited", UTILITIES_ULTD) MANUF("Amitrix", AMITRIX) @@ -992,7 +988,7 @@ * Initialization */ -void zorro_init(void) +__initfunc(void zorro_init(void)) { int i; struct ConfigDev *cd; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c --- v2.1.36/linux/arch/m68k/atari/atafb.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/atari/atafb.c Mon May 12 10:35:38 1997 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -2911,8 +2912,8 @@ return(atari_fb_set_cmap(cmap, 1, con)); } -struct fb_info * -atari_fb_init(long *mem_start) +__initfunc(struct fb_info * +atari_fb_init(long *mem_start)) { int err; int pad; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c --- v2.1.36/linux/arch/m68k/atari/ataints.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/atari/ataints.c Mon May 12 10:35:38 1997 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -331,7 +332,7 @@ * the atari IRQ handling routines. */ -void atari_init_IRQ(void) +__initfunc(void atari_init_IRQ(void)) { int i; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c --- v2.1.36/linux/arch/m68k/atari/atakeyb.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/atari/atakeyb.c Mon May 12 10:35:38 1997 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -804,7 +805,7 @@ * Martin Rogge, 20 Aug 1995 */ -int atari_keyb_init(void) +__initfunc(int atari_keyb_init(void)) { /* setup key map */ key_maps[0] = ataplain_map; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c --- v2.1.36/linux/arch/m68k/atari/config.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/atari/config.c Mon May 12 10:35:38 1997 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -106,7 +107,7 @@ * a temporary VBR and a vector table for the duration of the test. */ -static int hwreg_present( volatile void *regp ) +__initfunc(static int hwreg_present( volatile void *regp )) { int ret = 0; long save_sp, save_vbr; @@ -132,9 +133,8 @@ } #if 0 -static int hwreg_present_bywrite( volatile void *regp, - unsigned char val ) - +__initfunc(static int +hwreg_present_bywrite(volatile void *regp, unsigned char val)) { int ret; long save_sp, save_vbr; @@ -166,7 +166,7 @@ /* Basically the same, but writes a value into a word register, protected * by a bus error handler */ -static int hwreg_write( volatile void *regp, unsigned short val ) +__initfunc(static int hwreg_write( volatile void *regp, unsigned short val )) { int ret; long save_sp, save_vbr; @@ -201,7 +201,7 @@ * should be readable without trouble (from channel A!). */ -static int scc_test( volatile char *ctla ) +__initfunc(static int scc_test( volatile char *ctla )) { if (!hwreg_present( ctla )) return( 0 ); @@ -228,7 +228,7 @@ * Parse an Atari-specific record in the bootinfo */ -int atari_parse_bootinfo(const struct bi_record *record) +__initfunc(int atari_parse_bootinfo(const struct bi_record *record)) { int unknown = 0; const u_long *data = record->data; @@ -247,7 +247,7 @@ * Setup the Atari configuration info */ -void config_atari(void) +__initfunc(void config_atari(void)) { memset(&atari_hw_present, 0, sizeof(atari_hw_present)); @@ -493,7 +493,8 @@ } } -static void atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) +__initfunc(static void +atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) { /* set Timer C data Register */ mfp.tim_dt_c = INT_TICKS; @@ -976,7 +977,7 @@ } -static void atari_debug_init(void) +__initfunc(static void atari_debug_init(void)) { #ifdef CONFIG_KGDB /* if the m68k_debug_device is used by the GDB stub, do nothing here */ diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c --- v2.1.36/linux/arch/m68k/atari/joystick.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/atari/joystick.c Mon May 12 10:35:38 1997 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -128,7 +129,7 @@ release_joystick }; -int atari_joystick_init(void) +__initfunc(int atari_joystick_init(void)) { joystick[0].active = joystick[1].active = 0; joystick[0].ready = joystick[1].ready = 0; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c --- v2.1.36/linux/arch/m68k/atari/stdma.c Fri Dec 20 01:19:58 1996 +++ linux/arch/m68k/atari/stdma.c Mon May 12 10:35:38 1997 @@ -32,6 +32,8 @@ #include #include #include +#include + #include #include #include @@ -171,7 +173,7 @@ * */ -void stdma_init(void) +__initfunc(void stdma_init(void)) { stdma_isr = NULL; request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW, diff -u --recursive --new-file v2.1.36/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c --- v2.1.36/linux/arch/m68k/atari/stram.c Fri Dec 20 01:19:58 1996 +++ linux/arch/m68k/atari/stram.c Mon May 12 10:35:38 1997 @@ -149,6 +149,7 @@ #else #include +#include /* ++roman: * @@ -190,7 +191,7 @@ /* Overall end of ST-Ram */ -void atari_stram_init( void ) +__initfunc(void atari_stram_init( void )) { int i; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/boot/amiga/linuxboot.c linux/arch/m68k/boot/amiga/linuxboot.c --- v2.1.36/linux/arch/m68k/boot/amiga/linuxboot.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/boot/amiga/linuxboot.c Mon May 12 10:35:38 1997 @@ -22,6 +22,8 @@ * for more details. * * History: + * 27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo + * interface version 1.0 (Geert) * 03 Feb 1997 Implemented kernel decompression (Geert, based on Roman's * code for ataboot) * 30 Dec 1996 Reverted the CPU detection to the old scheme @@ -791,6 +793,7 @@ static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu) { *cpu = *fpu = 0; + if (SysBase->AttnFlags & AFF_68060) *cpu = CPU_68060; else if (SysBase->AttnFlags & AFF_68040) @@ -799,15 +802,15 @@ *cpu = CPU_68030; else if (SysBase->AttnFlags & AFF_68020) *cpu = CPU_68020; + if (*cpu == CPU_68040 || *cpu == CPU_68060) { if (SysBase->AttnFlags & AFF_FPU40) *fpu = *cpu; - } else { - if (SysBase->AttnFlags & AFF_68882) - *fpu = FPU_68882; - else if (SysBase->AttnFlags & AFF_68881) - *fpu = FPU_68881; - } + } else if (SysBase->AttnFlags & AFF_68882) + *fpu = FPU_68882; + else if (SysBase->AttnFlags & AFF_68881) + *fpu = FPU_68881; + *mmu = *cpu; } @@ -1047,7 +1050,7 @@ compat_bootinfo.cputype |= COMPAT_FPU_68040; else if (bi.fputype & FPU_68060) compat_bootinfo.cputype |= COMPAT_FPU_68060; - else { + else if (bi.fputype) { Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype); return(0); } diff -u --recursive --new-file v2.1.36/linux/arch/m68k/boot/amiga/linuxboot.h linux/arch/m68k/boot/amiga/linuxboot.h --- v2.1.36/linux/arch/m68k/boot/amiga/linuxboot.h Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/boot/amiga/linuxboot.h Mon May 12 10:35:38 1997 @@ -31,7 +31,7 @@ * Amiboot Version */ -#define AMIBOOT_VERSION "5.4" +#define AMIBOOT_VERSION "5.5" /* diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c --- v2.1.36/linux/arch/m68k/kernel/ints.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/kernel/ints.c Mon May 12 10:35:38 1997 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -79,7 +80,7 @@ * the IRQ handling routines. */ -void init_IRQ(void) +__initfunc(void init_IRQ(void)) { int i; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.1.36/linux/arch/m68k/kernel/m68k_ksyms.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/kernel/m68k_ksyms.c Mon May 12 10:35:38 1997 @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -14,6 +16,7 @@ #include #include #include +#include asmlinkage long long __ashrdi3 (long long, int); extern char m68k_debug_device[]; @@ -40,6 +43,7 @@ EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(__m68k_bh_counter); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- v2.1.36/linux/arch/m68k/kernel/process.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/kernel/process.c Mon May 12 10:35:38 1997 @@ -10,6 +10,7 @@ * This file handles the architecture-dependent parts of process handling.. */ +#include #include #include #include @@ -30,6 +31,22 @@ #include #include +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ +static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, }; +unsigned long init_user_stack[1024] = { STACK_MAGIC, }; +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; + +struct mm_struct init_mm = INIT_MM; +struct task_struct init_task = INIT_TASK; + asmlinkage void ret_from_exception(void); /* @@ -46,8 +63,16 @@ /* endless idle loop with no priority at all */ current->priority = -100; current->counter = -100; - for (;;) + for (;;){ + if (!need_resched) +#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) + /* block out HSYNC on the atari (falcon) */ + __asm__("stop #0x2200" : : : "cc"); +#else /* portable version */ + __asm__("stop #0x2000" : : : "cc"); +#endif /* machine compilation types */ schedule(); + } ret = 0; out: unlock_kernel(); diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c --- v2.1.36/linux/arch/m68k/kernel/ptrace.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/kernel/ptrace.c Mon May 12 10:35:38 1997 @@ -52,18 +52,6 @@ PT_REG(orig_d0), PT_REG(sr), PT_REG(pc), }; -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * Get contents of register REGNO in task TASK. */ @@ -340,7 +328,7 @@ if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) goto out; ret = -EPERM; if (request == PTRACE_ATTACH) { diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.1.36/linux/arch/m68k/kernel/setup.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/kernel/setup.c Mon May 12 10:35:38 1997 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -55,13 +56,13 @@ static char m68k_command_line[CL_SIZE]; char saved_command_line[CL_SIZE]; -void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)); +void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata; /* machine dependent keyboard functions */ -int (*mach_keyb_init) (void); +int (*mach_keyb_init) (void) __initdata; int (*mach_kbdrate) (struct kbd_repeat *) = NULL; void (*mach_kbd_leds) (unsigned int) = NULL; /* machine dependent irq functions */ -void (*mach_init_IRQ) (void); +void (*mach_init_IRQ) (void) __initdata; void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; void (*mach_get_model) (char *model) = NULL; int (*mach_get_hardware_list) (char *buffer) = NULL; @@ -73,12 +74,12 @@ int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; void (*mach_reset)( void ); -struct fb_info *(*mach_fb_init)(long *); +struct fb_info *(*mach_fb_init)(long *) __initdata; long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -void (*mach_video_setup) (char *, int *); +void (*mach_video_setup) (char *, int *) __initdata; #ifdef CONFIG_BLK_DEV_FD -int (*mach_floppy_init) (void) = NULL; -void (*mach_floppy_setup) (char *, int *) = NULL; +int (*mach_floppy_init) (void) __initdata = NULL; +void (*mach_floppy_setup) (char *, int *) __initdata = NULL; void (*mach_floppy_eject) (void) = NULL; #endif @@ -94,7 +95,7 @@ #define MASK_256K 0xfffc0000 -static void m68k_parse_bootinfo(const struct bi_record *record) +__initfunc(static void m68k_parse_bootinfo(const struct bi_record *record)) { while (record->tag != BI_LAST) { int unknown = 0; @@ -141,8 +142,8 @@ } } -void setup_arch(char **cmdline_p, unsigned long * memory_start_p, - unsigned long * memory_end_p) + __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, + unsigned long * memory_end_p)) { unsigned long memory_start, memory_end; extern int _etext, _edata, _end; @@ -337,7 +338,7 @@ } #ifdef CONFIG_BLK_DEV_FD -int floppy_init(void) +__initfunc(int floppy_init(void)) { if (mach_floppy_init) return mach_floppy_init(); @@ -345,7 +346,7 @@ return 0; } -void floppy_setup(char *str, int *ints) +__initfunc(void floppy_setup(char *str, int *ints)) { if (mach_floppy_setup) mach_floppy_setup (str, ints); @@ -358,7 +359,7 @@ } #endif -unsigned long arch_kbd_init(void) +__initfunc(unsigned long arch_kbd_init(void)) { return mach_keyb_init(); } @@ -372,7 +373,7 @@ *year = *mon = *day = *hour = *min = *sec = 0; } -void video_setup (char *options, int *ints) +__initfunc(void video_setup (char *options, int *ints)) { if (mach_video_setup) mach_video_setup (options, ints); diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v2.1.36/linux/arch/m68k/kernel/signal.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/kernel/signal.c Mon May 12 10:35:38 1997 @@ -42,7 +42,9 @@ #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) -asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); + asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); const int frame_extra_sizes[16] = { @@ -466,7 +468,7 @@ if (signr != SIGCHLD) continue; /* check for SIGCHLD: it's special */ - while (sys_waitpid(-1,NULL,WNOHANG) > 0) + while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0) /* nothing */; continue; } diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c --- v2.1.36/linux/arch/m68k/kernel/time.c Fri Nov 22 05:56:35 1996 +++ linux/arch/m68k/kernel/time.c Mon May 12 10:35:38 1997 @@ -27,6 +27,24 @@ return -1; } +static inline void do_profile (unsigned long pc) +{ + if (prof_buffer && current->pid) { + extern int _stext; + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + if (pc < prof_len) + ++prof_buffer[pc]; + else + /* + * Dont ignore out-of-bounds PC values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + ++prof_buffer[prof_len-1]; + } +} + /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -37,6 +55,9 @@ static long last_rtc_update=0; do_timer(regs); + + if (!user_mode(regs)) + do_profile(regs->pc); /* * If we have an externally synchronized Linux clock, then update diff -u --recursive --new-file v2.1.36/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c --- v2.1.36/linux/arch/m68k/kernel/traps.c Wed Apr 23 19:01:15 1997 +++ linux/arch/m68k/kernel/traps.c Mon May 12 10:35:38 1997 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -63,7 +64,7 @@ __ALIGN_STR "\n" SYMBOL_NAME_STR(nmihandler) ": rte"); -void trap_init (void) +__initfunc(void trap_init (void)) { int i; diff -u --recursive --new-file v2.1.36/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.1.36/linux/arch/m68k/mm/init.c Wed Apr 23 19:01:16 1997 +++ linux/arch/m68k/mm/init.c Mon May 12 10:35:38 1997 @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_RAM #include #endif @@ -116,9 +117,8 @@ return ptablep; } -static unsigned long map_chunk (unsigned long addr, - unsigned long size, - unsigned long *memavailp) +__initfunc(static unsigned long +map_chunk (unsigned long addr, unsigned long size, unsigned long *memavailp)) { #define ONEMEG (1024*1024) #define L3TREESIZE (256*1024) @@ -283,6 +283,11 @@ extern unsigned long free_area_init(unsigned long, unsigned long); +/* References to section boundaries */ + +extern char _text, _etext, _edata, __bss_start, _end; +extern char __init_begin, __init_end; + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* @@ -291,7 +296,7 @@ * The parameters are pointers to where to stick the starting and ending * addresses of available kernel virtual memory. */ -unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) +__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) { int chunk; unsigned long mem_avail = 0; @@ -395,12 +400,12 @@ return PAGE_ALIGN(free_area_init (start_mem, end_mem)); } -void mem_init(unsigned long start_mem, unsigned long end_mem) +__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) { int codepages = 0; int datapages = 0; + int initpages = 0; unsigned long tmp; - extern int _etext; end_mem &= PAGE_MASK; high_memory = (void *) end_mem; @@ -448,8 +453,15 @@ if (VTOP (tmp) >= mach_max_dma_address) clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); if (PageReserved(mem_map+MAP_NR(tmp))) { - if (tmp < (unsigned long)&_etext) - codepages++; + if (tmp >= (unsigned long)&_text + && tmp < (unsigned long)&_edata) { + if (tmp < (unsigned long) &_etext) + codepages++; + else + datapages++; + } else if (tmp >= (unsigned long) &__init_begin + && tmp < (unsigned long) &__init_end) + initpages++; else datapages++; continue; @@ -461,16 +473,26 @@ #endif free_page(tmp); } - printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n", + printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), - datapages << (PAGE_SHIFT-10)); + datapages << (PAGE_SHIFT-10), + initpages << (PAGE_SHIFT-10)); } void free_initmem(void) { - /* To be written */ + unsigned long addr; + + addr = (unsigned long)&__init_begin; + for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) { + mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); + atomic_set(&mem_map[MAP_NR(addr)].count, 1); + free_page(addr); + } + printk ("Freeing unused kernel memory: %dk freed\n", + (&__init_end - &__init_begin) >> 10); } void si_meminfo(struct sysinfo *val) diff -u --recursive --new-file v2.1.36/linux/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds --- v2.1.36/linux/arch/m68k/vmlinux.lds Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/vmlinux.lds Mon May 12 10:35:38 1997 @@ -0,0 +1,56 @@ +/* ld script to make m68k Linux kernel */ +OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") +OUTPUT_ARCH(m68k) +ENTRY(_start) +SECTIONS +{ + . = 0x1000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x4e75 + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -u --recursive --new-file v2.1.36/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- v2.1.36/linux/arch/mips/kernel/process.c Thu Dec 19 06:48:08 1996 +++ linux/arch/mips/kernel/process.c Mon May 12 10:35:38 1997 @@ -29,6 +29,22 @@ #include #include +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ +static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, }; +unsigned long init_user_stack[1024] = { STACK_MAGIC, }; +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; + +struct mm_struct init_mm = INIT_MM; +struct task_struct init_task = INIT_TASK; + asmlinkage void ret_from_sys_call(void); /* diff -u --recursive --new-file v2.1.36/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c --- v2.1.36/linux/arch/mips/kernel/ptrace.c Wed Dec 13 02:39:44 1995 +++ linux/arch/mips/kernel/ptrace.c Mon May 12 10:35:38 1997 @@ -33,18 +33,6 @@ */ #define MAGICNUMBER 68 -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * this routine will get a word off of the processes privileged stack. * the offset is how far from the base addr as stored in the TSS. @@ -295,7 +283,7 @@ } if (pid == 1) /* you may not mess with init */ return -EPERM; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) return -ESRCH; if (request == PTRACE_ATTACH) { if (child == current) diff -u --recursive --new-file v2.1.36/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h --- v2.1.36/linux/arch/mips/kernel/syscalls.h Wed Dec 13 02:39:44 1995 +++ linux/arch/mips/kernel/syscalls.h Mon May 12 10:35:38 1997 @@ -174,3 +174,4 @@ SYS(sys_munlock, 2) /* 4155 */ SYS(sys_mlockall, 1) SYS(sys_munlockall, 0) +SYS(sys_nfsservctl, 3) diff -u --recursive --new-file v2.1.36/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c --- v2.1.36/linux/arch/mips/kernel/traps.c Wed Dec 13 02:39:44 1995 +++ linux/arch/mips/kernel/traps.c Mon May 12 10:35:38 1997 @@ -178,6 +178,7 @@ void do_ades(struct pt_regs *regs) { + struct task_struct *p; unsigned long pc = regs->cp0_epc; int i; @@ -187,12 +188,14 @@ return; } while(1); - for(i=0; ipid >= 2) - { - printk("Process %d\n", task[i]->pid); - dump_list_process(task[i], pc); + read_lock(&tasklist_lock); + for_each_task(p) { + if(p->pid >= 2) { + printk("Process %d\n", p->pid); + dump_list_process(p, pc); } + } + read_unlock(&tasklist_lock); show_regs(regs); dump_tlb_nonwired(); send_sig(SIGSEGV, current, 1); @@ -251,14 +254,16 @@ void do_ri(struct pt_regs *regs) { + struct task_struct *p; int i; - for(i=0; ipid >= 2) - { - printk("Process %d\n", task[i]->pid); - dump_list_process(task[i], 0x7ffff000); + read_lock(&tasklist_lock); + for_each_task(p) { + if(p->pid >= 2) { + printk("Process %d\n", p->pid); + dump_list_process(p, 0x7ffff000); } + } show_regs(regs); while(1); send_sig(SIGILL, current, 1); diff -u --recursive --new-file v2.1.36/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.1.36/linux/arch/ppc/kernel/misc.S Wed Dec 18 00:49:52 1996 +++ linux/arch/ppc/kernel/misc.S Mon May 12 10:35:38 1997 @@ -855,5 +855,6 @@ .long sys_mremap .long SYMBOL_NAME(sys_setresuid) .long SYMBOL_NAME(sys_getresuid) - .space (NR_syscalls-165)*4 + .long SYMBOL_NAME(sys_nfsservctl) + .space (NR_syscalls-166)*4 diff -u --recursive --new-file v2.1.36/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.1.36/linux/arch/ppc/kernel/process.c Sun Jan 26 02:07:05 1997 +++ linux/arch/ppc/kernel/process.c Mon May 12 10:35:38 1997 @@ -29,6 +29,24 @@ #include #include + +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ +static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, }; +unsigned long init_user_stack[1024] = { STACK_MAGIC, }; +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; + +struct mm_struct init_mm = INIT_MM; +struct task_struct init_task = INIT_TASK; + + int dump_fpu(void); void hard_reset_now(void); void switch_to(struct task_struct *, struct task_struct *); diff -u --recursive --new-file v2.1.36/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c --- v2.1.36/linux/arch/ppc/kernel/ptrace.c Sun Jan 26 02:07:05 1997 +++ linux/arch/ppc/kernel/ptrace.c Mon May 12 10:35:38 1997 @@ -42,18 +42,6 @@ static int regoff[] = { }; -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * Get contents of register REGNO in task TASK. */ @@ -394,7 +382,7 @@ if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = get_task(pid))) + if (!(child = find_task_by_pid(pid))) goto out; ret = -EPERM; if (request == PTRACE_ATTACH) { diff -u --recursive --new-file v2.1.36/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.1.36/linux/arch/ppc/mm/init.c Mon Apr 14 16:28:06 1997 +++ linux/arch/ppc/mm/init.c Mon May 12 10:35:38 1997 @@ -58,69 +58,62 @@ void show_mem(void) { - unsigned long i,free = 0,total = 0,reserved = 0; - unsigned long shared = 0; - PTE *ptr; - unsigned long full = 0, overflow = 0; - unsigned int ti; + struct task_struct *p; + unsigned long i,free = 0,total = 0,reserved = 0; + unsigned long shared = 0; + PTE *ptr; + unsigned long full = 0, overflow = 0; + unsigned int ti; - printk("Mem-info:\n"); - show_free_areas(); - printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = MAP_NR(high_memory); - while (i-- > 0) { - total++; - if (PageReserved(mem_map+i)) - reserved++; - else if (!atomic_read(&mem_map[i].count)) - free++; - else - shared += atomic_read(&mem_map[i].count) - 1; - } - printk("%lu pages of RAM\n",total); - printk("%lu free pages\n",free); - printk("%lu reserved pages\n",reserved); - printk("%lu pages shared\n",shared); - show_buffers(); + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = MAP_NR(high_memory); + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (!atomic_read(&mem_map[i].count)) + free++; + else + shared += atomic_read(&mem_map[i].count) - 1; + } + printk("%lu pages of RAM\n",total); + printk("%lu free pages\n",free); + printk("%lu reserved pages\n",reserved); + printk("%lu pages shared\n",shared); + show_buffers(); #ifdef CONFIG_NET - show_net_buffers(); + show_net_buffers(); #endif #ifdef HASHSTATS - printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8); - for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) - { - if ( hashhits[i] >= 20 ) - { - printk("[%lu] \t %lu\n", i,hashhits[i]); - } - } + printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8); + for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) { + if ( hashhits[i] >= 20 ) + printk("[%lu] \t %lu\n", i,hashhits[i]); + } #endif - for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) - { - if (ptr->v) - { - full++; - if (ptr->h == 1) - overflow++; - } - } - printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n", - Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10, - full,Hash_size/sizeof(PTE), - (full*100)/(Hash_size/sizeof(PTE)), - overflow); - printk(" Task context vsid0\n"); - for ( ti = 0; ti < NR_TASKS ; ti++ ); - { - if ( task[ti] ) - { - printk("%5d %8x %8x\n", - task[ti]->pid,task[ti]->mm->context, - ((SEGREG *)task[ti]->tss.segs)[0].vsid); - } - } - + for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) { + if (ptr->v) { + full++; + if (ptr->h == 1) + overflow++; + } + } + printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n", + Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10, + full,Hash_size/sizeof(PTE), + (full*100)/(Hash_size/sizeof(PTE)), + overflow); + printk(" Task context vsid0\n"); + read_lock(&tasklist_lock); + for_each_task(p) { + printk("%5d %8x %8x\n", + p->pid,p->mm->context, + ((SEGREG *)p->tss.segs)[0].vsid); + } + read_unlock(&tasklist_lock); } extern unsigned long free_area_init(unsigned long, unsigned long); diff -u --recursive --new-file v2.1.36/linux/arch/sparc/Makefile linux/arch/sparc/Makefile --- v2.1.36/linux/arch/sparc/Makefile Mon Apr 14 16:28:06 1997 +++ linux/arch/sparc/Makefile Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.27 1997/04/07 06:54:08 davem Exp $ +# $Id: Makefile,v 1.28 1997/05/01 01:41:21 davem Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -21,7 +21,7 @@ #LINKFLAGS = -N -Ttext 0xf0004000 LINKFLAGS = -T arch/sparc/vmlinux.lds -HEAD := arch/sparc/kernel/head.o +HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \ arch/sparc/prom diff -u --recursive --new-file v2.1.36/linux/arch/sparc/ap1000/bnet.c linux/arch/sparc/ap1000/bnet.c --- v2.1.36/linux/arch/sparc/ap1000/bnet.c Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/ap1000/bnet.c Mon May 12 10:35:38 1997 @@ -872,12 +872,12 @@ len = req->size - sizeof(*req); if (len == 0) { int pid = req->data[1]; - for_each_task(p) - if (p->pid == pid) { - send_sig(sig,p,1); - return; - } - printk("cell %d: no task with pid %d\n",mpp_cid(),pid); + p = find_task_by_pid(pid); + + if(p) + send_sig(sig, p, 1); + else + printk("cell %d: no task with pid %d\n",mpp_cid(),pid); return; } @@ -889,9 +889,11 @@ read_bif(name,len); name[len] = 0; + read_lock(&tasklist_lock); for_each_task(p) if (strcmp(name,p->comm) == 0) send_sig(sig,p,1); + read_unlock(&tasklist_lock); } diff -u --recursive --new-file v2.1.36/linux/arch/sparc/ap1000/hw.c linux/arch/sparc/ap1000/hw.c --- v2.1.36/linux/arch/sparc/ap1000/hw.c Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/ap1000/hw.c Mon May 12 10:35:38 1997 @@ -86,14 +86,21 @@ static void show_ptasks(void) { extern struct task_struct *task[]; + struct task_struct *p; int i; int count=0; - for (i=MPP_TASK_BASE;itarray_ptr; + + if(tp >= &task[MPP_TASK_BASE]) { + show_task(p); count++; } + } + read_unlock(&tasklist_lock); + if (count == 0) printk("no parallel tasks on cell %d\n",mpp_cid()); } @@ -101,14 +108,18 @@ static void show_utasks(void) { extern struct task_struct *task[]; + struct task_struct *p; int i; int count=0; - for (i=0;iuid > 1) { + read_lock(&tasklist_lock); + for_each_task(p) { + if(p->uid > 1) { show_task(task[i]); count++; } + } + read_unlock(&tasklist_lock); if (count == 0) printk("no user tasks on cell %d\n",mpp_cid()); @@ -118,15 +129,19 @@ static void show_otasks(void) { extern struct task_struct *task[]; + struct task_struct *p; int i; int count=0; extern int ap_current_uid; - for (i=0;iuid == ap_current_uid) { + read_lock(&tasklist_lock); + for_each_task(p) { + if(p->uid == ap_current_uid) { show_task(task[i]); count++; } + } + read_unlock(&tasklist_lock); if (count == 0) printk("no tasks on cell %d\n",mpp_cid()); diff -u --recursive --new-file v2.1.36/linux/arch/sparc/ap1000/mpp.c linux/arch/sparc/ap1000/mpp.c --- v2.1.36/linux/arch/sparc/ap1000/mpp.c Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/ap1000/mpp.c Mon May 12 10:35:38 1997 @@ -66,6 +66,7 @@ if (block_parallel_tasks) return -1000; + /* XXX task[] fixme */ if (last_task && last_task != tsk->taskid && task[last_task] && !msc_switch_ok()) return -1000; diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v2.1.36/linux/arch/sparc/kernel/Makefile Mon Apr 14 16:28:07 1997 +++ linux/arch/sparc/kernel/Makefile Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.39 1997/04/01 02:21:44 davem Exp $ +# $Id: Makefile,v 1.40 1997/05/01 01:40:36 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -28,7 +28,7 @@ CHECKASM_CC = $(CC) endif -all: kernel.o head.o +all: kernel.o head.o init_task.o O_TARGET := kernel.o IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S --- v2.1.36/linux/arch/sparc/kernel/etrap.S Mon Mar 17 14:54:20 1997 +++ linux/arch/sparc/kernel/etrap.S Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.23 1997/03/04 16:26:25 jj Exp $ +/* $Id: etrap.S,v 1.26 1997/05/01 08:53:32 davem Exp $ * etrap.S: Sparc trap window preparation for entry into the * Linux kernel. * @@ -129,15 +129,23 @@ trap_setup_from_user: /* We can't use %curptr yet. */ LOAD_CURRENT(t_kstack, t_twinmask) + + mov 1, %t_twinmask + sll %t_twinmask, (PAGE_SHIFT + 1), %t_twinmask + sub %t_twinmask, (TRACEREG_SZ + REGWIN_SZ), %t_twinmask + add %t_kstack, %t_twinmask, %t_kstack + mov 1, %t_twinmask - ld [%t_kstack + AOFF_task_saved_kernel_stack], %t_kstack sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr) /* Build pt_regs frame. */ STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2) /* Clear current->tss.w_saved */ - LOAD_CURRENT(curptr, g1) + mov 1, %curptr + sll %curptr, (PAGE_SHIFT + 1), %curptr + sub %curptr, (TRACEREG_SZ + REGWIN_SZ), %curptr + sub %t_kstack, %curptr, %curptr st %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved] /* See if we are in the trap window. */ diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S --- v2.1.36/linux/arch/sparc/kernel/head.S Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/kernel/head.S Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.81 1997/04/16 07:15:48 davem Exp $ +/* $Id: head.S,v 1.82 1997/05/01 01:40:38 davem Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -393,12 +393,6 @@ BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff) - .globl C_LABEL(cpu0_stack), C_LABEL(cpu1_stack), C_LABEL(cpu2_stack) - .globl C_LABEL(cpu3_stack) -C_LABEL(cpu0_stack): .skip 0x2000 -C_LABEL(cpu1_stack): .skip 0x2000 -C_LABEL(cpu2_stack): .skip 0x2000 -C_LABEL(cpu3_stack): .skip 0x2000 #endif .skip 4096 @@ -742,6 +736,9 @@ jmpl %g1, %g0 nop + /* This is to align init_task_union properly, be careful. -DaveM */ + .align 8192 + /* The code above should be at beginning and we have to take care about * short jumps, as branching to .text.init section from .text is usually * impossible */ @@ -986,12 +983,10 @@ /* Initialize the umask value for init_task just in case. * But first make current_set[0] point to something useful. */ - set C_LABEL(init_task), %g6 + set C_LABEL(init_task_union), %g6 set C_LABEL(current_set), %g2 st %g6, [%g2] - set C_LABEL(bootup_kernel_stack), %g3 - st %g3, [%g6 + AOFF_task_kernel_stack_page] st %g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask] /* Compute NWINDOWS and stash it away. Now uses %wim trick explained diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c --- v2.1.36/linux/arch/sparc/kernel/init_task.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc/kernel/init_task.c Mon May 12 10:35:38 1997 @@ -0,0 +1,18 @@ +#include +#include + +#include +#include + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +/* .text section in head.S is aligned at 2 page boundry and this gets linked + * right after that so that the init_task_union is aligned properly as well. + * We really don't need this special alignment like the Intel does, but + * I do it anyways for completeness. + */ +union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.1.36/linux/arch/sparc/kernel/process.c Mon Apr 14 16:28:07 1997 +++ linux/arch/sparc/kernel/process.c Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.93 1997/04/11 08:55:40 davem Exp $ +/* $Id: process.c,v 1.96 1997/05/01 08:53:33 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -441,12 +441,12 @@ if(regs->psr & PSR_PS) stack_offset -= REGWIN_SZ; - childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset)); + childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset)); copy_regs(childregs, regs); new_stack = (((struct reg_window *) childregs) - 1); copy_regwin(new_stack, (((struct reg_window *) regs) - 1)); - p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack; + p->tss.ksp = (unsigned long) new_stack; #ifdef __SMP__ p->tss.kpc = (((unsigned long) ret_from_smpfork) - 0x8); p->tss.kpsr = current->tss.fork_kpsr | PSR_PIL; @@ -467,7 +467,7 @@ p->tss.flags &= ~SPARC_FLAG_KTHREAD; p->tss.current_ds = USER_DS; - if (sp != current->tss.kregs->u_regs[UREG_FP]) { + if (sp != regs->u_regs[UREG_FP]) { struct sparc_stackf *childstack; struct sparc_stackf *parentstack; @@ -475,9 +475,8 @@ * This is a clone() call with supplied user stack. * Set some valid stack frames to give to the child. */ - childstack = (struct sparc_stackf *)sp; - parentstack = (struct sparc_stackf *) - current->tss.kregs->u_regs[UREG_FP]; + childstack = (struct sparc_stackf *) sp; + parentstack = (struct sparc_stackf *) regs->u_regs[UREG_FP]; #if 0 printk("clone: parent stack:\n"); diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.1.36/linux/arch/sparc/kernel/ptrace.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/kernel/ptrace.c Mon May 12 10:35:38 1997 @@ -24,18 +24,6 @@ #define MAGIC_CONSTANT 0x80000000 -/* change a pid into a task struct. */ -static inline struct task_struct * get_task(int pid) -{ - int i; - - for (i = 1; i < NR_TASKS; i++) { - if (task[i] != NULL && (task[i]->pid == pid)) - return task[i]; - } - return NULL; -} - /* * This routine gets a long from any process space by following the page * tables. NOTE! You should check that the long isn't on a page boundary, @@ -533,7 +521,7 @@ goto out; } #endif - if(!(child = get_task(pid))) { + if(!(child = find_task_by_pid(pid))) { pt_error_return(regs, ESRCH); goto out; } diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.1.36/linux/arch/sparc/kernel/smp.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/kernel/smp.c Mon May 12 10:35:38 1997 @@ -4,16 +4,18 @@ */ #include -#include -#include #include +#include #include #include #include #include #include +#include +#include + #include #include #include @@ -24,6 +26,9 @@ #include #include +#define __KERNEL_SYSCALLS__ +#include + #define IRQ_RESCHEDULE 13 #define IRQ_STOP_CPU 14 #define IRQ_CROSS_CALL 15 @@ -118,16 +123,6 @@ cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */ } -/* - * Architecture specific routine called by the kernel just before init is - * fired off. This allows the BP to have everything in order [we hope]. - * At the end of this all the AP's will hit the system scheduling and off - * we go. Each AP will load the system gdt's and jump through the kernel - * init into idle(). At this point the scheduler will one day take over - * and give them jobs to do. smp_callin is a standard routine - * we use to track CPU's as they power up. - */ - void smp_commence(void) { /* @@ -144,7 +139,7 @@ void smp_callin(void) { - int cpuid = smp_processor_id(); + int cpuid = hard_smp_processor_id(); local_flush_cache_all(); local_flush_tlb_all(); @@ -183,6 +178,25 @@ __sti(); } +extern int cpu_idle(void *unused); +extern void init_IRQ(void); + +/* Only broken Intel needs this, thus it should not even be referenced + * globally... + */ +void initialize_secondary(void) +{ +} + +/* Activate a secondary processor. */ +int start_secondary(void *unused) +{ + trap_init(); + init_IRQ(); + smp_callin(); + return cpu_idle(NULL); +} + void cpu_panic(void) { printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id()); @@ -220,6 +234,7 @@ cpu_number_map[boot_cpu_id] = 0; cpu_logical_map[0] = boot_cpu_id; klock_info.akp = boot_cpu_id; + current->processor = boot_cpu_id; smp_store_cpu_info(boot_cpu_id); set_irq_udt(mid_xlate[boot_cpu_id]); smp_setup_percpu_timer(); @@ -233,10 +248,19 @@ if(cpu_present_map & (1 << i)) { extern unsigned long sparc_cpu_startup; unsigned long *entry = &sparc_cpu_startup; + struct task_struct *p; int timeout; + /* Cook up an idler for this guy. */ + kernel_thread(start_secondary, NULL, CLONE_PID); + + p = task[++cpucount]; + + p->processor = i; + current_set[i] = p; + /* See trampoline.S for details... */ - entry += ((i-1) * 6); + entry += ((i-1) * 3); /* whirrr, whirrr, whirrrrrrrrr... */ printk("Starting CPU %d at %p\n", i, entry); @@ -253,10 +277,10 @@ } if(cpu_callin_map[i]) { /* Another "Red Snapper". */ - cpucount++; cpu_number_map[i] = i; cpu_logical_map[i] = i; } else { + cpucount--; printk("Processor %d is stuck.\n", i); } } @@ -376,14 +400,11 @@ void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - unsigned long me = smp_processor_id(); - unsigned long flags, mask; - int i, timeout; - if(smp_processors_ready) { - __save_flags(flags); - __cli(); - spin_lock(&cross_call_lock); + register int ncpus = smp_num_cpus; + unsigned long flags; + + spin_lock_irqsave(&cross_call_lock, flags); /* Init function glue. */ ccall_info.func = func; @@ -393,56 +414,47 @@ ccall_info.arg4 = arg4; ccall_info.arg5 = arg5; - /* Init receive/complete mapping. */ - for(i = 0; i < smp_num_cpus; i++) { - ccall_info.processors_in[i] = 0; - ccall_info.processors_out[i] = 0; - } - ccall_info.processors_in[me] = 1; - ccall_info.processors_out[me] = 1; - - /* Fire it off. */ - mask = (cpu_present_map & ~(1 << me)); - for(i = 0; i < 4; i++) { - if(mask & (1 << i)) - set_cpu_int(mid_xlate[i], IRQ_CROSS_CALL); - } - - /* For debugging purposes right now we can timeout - * on both callin and callexit. - */ - timeout = CCALL_TIMEOUT; - for(i = 0; i < smp_num_cpus; i++) { - while(!ccall_info.processors_in[i] && timeout-- > 0) - barrier(); - if(!ccall_info.processors_in[i]) - goto procs_time_out; + /* Init receive/complete mapping, plus fire the IPI's off. */ + { + register void (*send_ipi)(int,int) = set_cpu_int; + register unsigned long mask; + register int i; + + mask = (cpu_present_map & ~(1 << smp_processor_id())); + for(i = 0; i < ncpus; i++) { + if(mask & (1 << i)) { + ccall_info.processors_in[i] = 0; + ccall_info.processors_out[i] = 0; + send_ipi(mid_xlate[i], IRQ_CROSS_CALL); + } else { + ccall_info.processors_in[i] = 1; + ccall_info.processors_out[i] = 1; + } + } } - /* Run local copy. */ + /* First, run local copy. */ func(arg1, arg2, arg3, arg4, arg5); - /* Spin on proc dispersion. */ - timeout = CCALL_TIMEOUT; - for(i = 0; i < smp_num_cpus; i++) { - while(!ccall_info.processors_out[i] && timeout-- > 0) - barrier(); - if(!ccall_info.processors_out[i]) - goto procs_time_out; + { + register int i; + + i = 0; + do { + while(!ccall_info.processors_in[i]) + barrier(); + } while(++i < ncpus); + + i = 0; + do { + while(!ccall_info.processors_out[i]) + barrier(); + } while(++i < ncpus); } - spin_unlock(&cross_call_lock); - __restore_flags(flags); - return; /* made it... */ - -procs_time_out: - printk("smp: Wheee, penguin drops off the bus\n"); - spin_unlock(&cross_call_lock); - __restore_flags(flags); - return; /* why me... why me... */ - } - /* Just need to run local copy. */ - func(arg1, arg2, arg3, arg4, arg5); + spin_unlock_irqrestore(&cross_call_lock, flags); + } else + func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */ } void smp_flush_cache_all(void) diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.1.36/linux/arch/sparc/kernel/sys_sunos.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/kernel/sys_sunos.c Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.78 1997/04/16 05:56:12 davem Exp $ +/* $Id: sys_sunos.c,v 1.79 1997/04/23 23:01:15 ecd Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1031,7 +1032,48 @@ unlock_kernel(); return ret; } - + +extern asmlinkage int sys_msgget (key_t key, int msgflg); +extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, + size_t msgsz, long msgtyp, int msgflg); +extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, + size_t msgsz, int msgflg); +extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); + +asmlinkage int sunos_msgsys(int op, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4) +{ + struct sparc_stackf *sp; + unsigned long arg5; + int rval; + + lock_kernel(); + switch(op) { + case 0: + rval = sys_msgget((key_t)arg1, (int)arg2); + break; + case 1: + rval = sys_msgctl((int)arg1, (int)arg2, + (struct msqid_ds *)arg3); + break; + case 2: + sp = (struct sparc_stackf *)current->tss.kregs->u_regs[UREG_FP]; + arg5 = sp->xxargs[0]; + rval = sys_msgrcv((int)arg1, (struct msgbuf *)arg2, + (size_t)arg3, (long)arg4, (int)arg5); + break; + case 3: + rval = sys_msgsnd((int)arg1, (struct msgbuf *)arg2, + (size_t)arg3, (int)arg4); + break; + default: + rval = -EINVAL; + break; + } + unlock_kernel(); + return rval; +} + extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); extern asmlinkage int sys_shmdt (char *shmaddr); diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v2.1.36/linux/arch/sparc/kernel/systbls.S Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/kernel/systbls.S Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.60 1997/04/19 08:52:15 jj Exp $ +/* $Id: systbls.S,v 1.62 1997/04/23 23:01:08 ecd Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -106,15 +106,26 @@ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek) /* "We are the Knights of the Forest of Ni!!" */ - .long C_LABEL(sys_mlock), C_LABEL(sys_munlock), C_LABEL(sys_mlockall) - .long C_LABEL(sys_munlockall), C_LABEL(sys_sched_setparam) - .long C_LABEL(sys_sched_getparam), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_sched_get_priority_max), C_LABEL(sys_sched_get_priority_min) - .long C_LABEL(sys_sched_rr_get_interval), C_LABEL(sys_nanosleep) + .long C_LABEL(sys_mlock) + .long C_LABEL(sys_munlock) + .long C_LABEL(sys_mlockall) +/*240*/ .long C_LABEL(sys_munlockall) + .long C_LABEL(sys_sched_setparam) + .long C_LABEL(sys_sched_getparam) + .long C_LABEL(sys_sched_setscheduler) + .long C_LABEL(sys_sched_getscheduler) +/*245*/ .long C_LABEL(sys_sched_yield) + .long C_LABEL(sys_sched_get_priority_max) + .long C_LABEL(sys_sched_get_priority_min) + .long C_LABEL(sys_sched_rr_get_interval) + .long C_LABEL(sys_nanosleep) /*250*/ .long C_LABEL(sys_mremap) .long C_LABEL(sys_sysctl) - .long C_LABEL(sys_getsid), C_LABEL(sys_fdatasync), C_LABEL(sys_nfsservctl) - .long C_LABEL(sys_aplib), C_LABEL(sys_nis_syscall) + .long C_LABEL(sys_getsid) + .long C_LABEL(sys_fdatasync) + .long C_LABEL(sys_nfsservctl) +/*255*/ .long C_LABEL(sys_aplib) + .long C_LABEL(sys_nis_syscall) /* Now the SunOS syscall table. */ @@ -179,7 +190,7 @@ .long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname) .long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys) .long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit) + .long C_LABEL(sunos_msgsys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit) .long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid) .long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/tadpole.c linux/arch/sparc/kernel/tadpole.c --- v2.1.36/linux/arch/sparc/kernel/tadpole.c Sat Nov 9 00:11:50 1996 +++ linux/arch/sparc/kernel/tadpole.c Mon May 12 10:35:38 1997 @@ -4,6 +4,8 @@ */ #include +#include +#include #include #include diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/trampoline.S linux/arch/sparc/kernel/trampoline.S --- v2.1.36/linux/arch/sparc/kernel/trampoline.S Mon Apr 14 16:28:07 1997 +++ linux/arch/sparc/kernel/trampoline.S Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.6 1997/04/14 05:38:33 davem Exp $ +/* $Id: trampoline.S,v 1.9 1997/05/01 08:53:34 davem Exp $ * trampoline.S: SMP cpu boot-up trampoline code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -25,27 +26,18 @@ C_LABEL(sparc_cpu_startup): cpu1_startup: sethi %hi(C_LABEL(trapbase_cpu1)), %g3 - or %g3, %lo(C_LABEL(trapbase_cpu1)), %g3 - sethi %hi(C_LABEL(cpu1_stack)), %g2 - or %g2, %lo(C_LABEL(cpu1_stack)), %g2 b 1f - nop + or %g3, %lo(C_LABEL(trapbase_cpu1)), %g3 cpu2_startup: sethi %hi(C_LABEL(trapbase_cpu2)), %g3 - or %g3, %lo(C_LABEL(trapbase_cpu2)), %g3 - sethi %hi(C_LABEL(cpu2_stack)), %g2 - or %g2, %lo(C_LABEL(cpu2_stack)), %g2 b 1f - nop + or %g3, %lo(C_LABEL(trapbase_cpu2)), %g3 cpu3_startup: sethi %hi(C_LABEL(trapbase_cpu3)), %g3 - or %g3, %lo(C_LABEL(trapbase_cpu3)), %g3 - sethi %hi(C_LABEL(cpu3_stack)), %g2 - or %g2, %lo(C_LABEL(cpu3_stack)), %g2 b 1f - nop + or %g3, %lo(C_LABEL(trapbase_cpu3)), %g3 1: /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */ @@ -62,14 +54,16 @@ wr %g3, 0x0, %tbr WRITE_PAUSE - /* Give ourselves a stack. */ - set 0x2000, %g5 - add %g2, %g5, %g2 ! end of stack - sub %g2, REGWIN_SZ, %sp - mov 0, %fp - - /* Set up curptr. */ - set C_LABEL(init_task), %g6 + /* Give ourselves a stack and curptr. */ + set C_LABEL(current_set), %g5 + srl %g3, 10, %g4 + and %g4, 0xc, %g4 + ld [%g5 + %g4], %g6 + + mov 1, %sp + sll %sp, (PAGE_SHIFT + 1), %sp + sub %sp, REGWIN_SZ, %sp + add %g6, %sp, %sp /* Turn on traps (PSR_ET). */ rd %psr, %g1 diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S --- v2.1.36/linux/arch/sparc/kernel/wof.S Mon Mar 17 14:54:21 1997 +++ linux/arch/sparc/kernel/wof.S Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: wof.S,v 1.33 1997/03/04 16:26:35 jj Exp $ +/* $Id: wof.S,v 1.36 1997/05/01 08:53:35 davem Exp $ * wof.S: Sparc window overflow handler. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -234,15 +234,20 @@ spnwin_patch3: and %twin_tmp, 0xff, %twin_tmp ! patched on 7win Sparcs st %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] - /* Jump onto kernel stack for this process... */ - ld [%curptr + AOFF_task_saved_kernel_stack], %sp + mov 1, %sp + sll %sp, (PAGE_SHIFT + 1), %sp + sub %sp, (TRACEREG_SZ + REGWIN_SZ), %sp + add %curptr, %sp, %sp /* Restore the saved globals and build a pt_regs frame. */ mov %saved_g5, %g5 - mov %g6, %l4 mov %saved_g6, %g6 STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1) - mov %l4, %g6 + + mov 1, %g6 + sll %g6, (PAGE_SHIFT + 1), %g6 + sub %g6, (TRACEREG_SZ + REGWIN_SZ), %g6 + sub %sp, %g6, %g6 /* Turn on traps and call c-code to deal with it. */ wr %t_psr, PSR_ET, %psr diff -u --recursive --new-file v2.1.36/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S --- v2.1.36/linux/arch/sparc/kernel/wuf.S Mon Mar 17 14:54:21 1997 +++ linux/arch/sparc/kernel/wuf.S Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: wuf.S,v 1.31 1997/03/04 16:26:37 jj Exp $ +/* $Id: wuf.S,v 1.34 1997/05/01 08:53:36 davem Exp $ * wuf.S: Window underflow trap handler for the Sparc. * * Copyright (C) 1995 David S. Miller @@ -145,14 +145,17 @@ * to the trap window and call c-code to deal with this. */ LOAD_CURRENT(l4, l5) - ld [%l4 + AOFF_task_saved_kernel_stack], %l5 + + mov 1, %l5 + sll %l5, (PAGE_SHIFT + 1), %l5 + sub %l5, (TRACEREG_SZ + REGWIN_SZ), %l5 + add %l4, %l5, %l5 /* Store globals into pt_regs frame. */ STORE_PT_GLOBALS(l5) STORE_PT_YREG(l5, g3) - /* Save kernel %sp in global while we change windows. */ - mov %l5, %g2 + /* Save current in a global while we change windows. */ mov %l4, %curptr save %g0, %g0, %g0 @@ -166,7 +169,10 @@ /* LOCATION: Window 'T' */ - mov %g2, %sp /* Jump onto kernel %sp being held */ + mov 1, %sp + sll %sp, (PAGE_SHIFT + 1), %sp + sub %sp, (TRACEREG_SZ + REGWIN_SZ), %sp + add %curptr, %sp, %sp /* Build rest of pt_regs. */ STORE_PT_INS(sp) diff -u --recursive --new-file v2.1.36/linux/arch/sparc/lib/irqlock.S linux/arch/sparc/lib/irqlock.S --- v2.1.36/linux/arch/sparc/lib/irqlock.S Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/lib/irqlock.S Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: irqlock.S,v 1.2 1997/04/19 04:33:37 davem Exp $ +/* $Id: irqlock.S,v 1.4 1997/05/01 02:26:54 davem Exp $ * irqlock.S: High performance IRQ global locking and interrupt entry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.1.36/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.1.36/linux/arch/sparc/mm/srmmu.c Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc/mm/srmmu.c Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.136 1997/04/20 14:11:51 ecd Exp $ +/* $Id: srmmu.c,v 1.140 1997/05/01 08:53:39 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -659,27 +659,6 @@ srmmu_set_entry(ptep, pte_val(pteval)); } -static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval) -{ - unsigned long page = ((unsigned long)ptep) & PAGE_MASK; - - srmmu_set_entry(ptep, pte_val(pteval)); - __asm__ __volatile__(" - lda [%0] %2, %%g4 - orcc %%g4, 0x0, %%g0 - be 2f - sethi %%hi(%7), %%g5 -1: subcc %%g5, %6, %%g5 ! hyper_flush_cache_page - bne 1b - sta %%g0, [%1 + %%g5] %3 - lda [%4] %5, %%g0 -2:" : /* no outputs */ - : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE), - "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS), - "r" (vac_line_size), "i" (PAGE_SIZE) - : "g4", "g5", "cc"); -} - static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval) { register unsigned long a, b, c, d, e, f, g; @@ -860,30 +839,12 @@ */ struct task_struct *srmmu_alloc_task_struct(void) { - return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL); -} - -unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk) -{ - unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0); - - if(!kstk) - kstk = (unsigned long) vmalloc(PAGE_SIZE << 1); - - return kstk; + return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1, 0); } static void srmmu_free_task_struct(struct task_struct *tsk) { - kfree(tsk); -} - -static void srmmu_free_kernel_stack(unsigned long stack) -{ - if(stack < VMALLOC_START) - free_pages(stack, 1); - else - vfree((char *)stack); + free_pages((unsigned long)tsk, 1); } /* Tsunami flushes. It's page level tlb invalidation is not very @@ -1365,17 +1326,28 @@ extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end); extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); +static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval) +{ + unsigned long page = ((unsigned long)ptep) & PAGE_MASK; + + srmmu_set_entry(ptep, pte_val(pteval)); + hypersparc_flush_page_to_ram(page); +} + static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) { + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4)))); + hypersparc_flush_page_to_ram((unsigned long)ctxp); hyper_flush_whole_icache(); - set_pte((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4)))); } static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) { unsigned long page = ((unsigned long) pgdp) & PAGE_MASK; - hypersparc_flush_page_to_ram(page); + if(pgdp != swapper_pg_dir) + hypersparc_flush_page_to_ram(page); + if(tsk->mm->context != NO_CONTEXT) { flush_cache_mm(tsk->mm); ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); @@ -1429,26 +1401,29 @@ static void hypersparc_switch_to_context(struct task_struct *tsk) { - hyper_flush_whole_icache(); if(tsk->mm->context == NO_CONTEXT) { + ctxd_t *ctxp; + alloc_context(tsk->mm); - flush_cache_mm(tsk->mm); - ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd); - flush_tlb_mm(tsk->mm); + ctxp = &srmmu_context_table[tsk->mm->context]; + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4)))); + hypersparc_flush_page_to_ram((unsigned long)ctxp); } + hyper_flush_whole_icache(); srmmu_set_context(tsk->mm->context); } static void hypersparc_init_new_context(struct mm_struct *mm) { - hyper_flush_whole_icache(); + ctxd_t *ctxp; alloc_context(mm); - flush_cache_mm(mm); - ctxd_set(&srmmu_context_table[mm->context], mm->pgd); - flush_tlb_mm(mm); + ctxp = &srmmu_context_table[mm->context]; + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4)))); + hypersparc_flush_page_to_ram((unsigned long)ctxp); + hyper_flush_whole_icache(); if(mm == current->mm) srmmu_set_context(mm->context); } @@ -2355,13 +2330,19 @@ static void hypersparc_destroy_context(struct mm_struct *mm) { if(mm->context != NO_CONTEXT && mm->count == 1) { + ctxd_t *ctxp; + /* HyperSparc is copy-back, any data for this * process in a modified cache line is stale * and must be written back to main memory now * else we eat shit later big time. */ flush_cache_mm(mm); - ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); + + ctxp = &srmmu_context_table[mm->context]; + srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) swapper_pg_dir) >> 4)))); + hypersparc_flush_page_to_ram((unsigned long)ctxp); + flush_tlb_mm(mm); free_context(mm->context); mm->context = NO_CONTEXT; @@ -3014,9 +2995,7 @@ mmu_p2v = srmmu_p2v; /* Task struct and kernel stack allocating/freeing. */ - alloc_kernel_stack = srmmu_alloc_kernel_stack; alloc_task_struct = srmmu_alloc_task_struct; - free_kernel_stack = srmmu_free_kernel_stack; free_task_struct = srmmu_free_task_struct; quick_kernel_fault = srmmu_quick_kernel_fault; diff -u --recursive --new-file v2.1.36/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.1.36/linux/arch/sparc/mm/sun4c.c Mon Apr 14 16:28:08 1997 +++ linux/arch/sparc/mm/sun4c.c Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.143 1997/04/11 00:42:14 davem Exp $ +/* $Id: sun4c.c,v 1.147 1997/05/01 08:53:42 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -1093,8 +1093,7 @@ panic("sun4c kernel fault handler bolixed..."); } -/* - * 4 page buckets for task struct and kernel stack allocation. +/* 2 page buckets for task struct and kernel stack allocation. * * TASK_STACK_BEGIN * bucket[0] @@ -1105,24 +1104,17 @@ * * Each slot looks like: * - * page 1 -- task struct - * page 2 -- unmapped, for stack redzone (maybe use for pgd) - * page 3/4 -- kernel stack + * page 1 -- task struct + beginning of kernel stack + * page 2 -- rest of kernel stack */ -struct task_bucket { - struct task_struct task; - char _unused1[PAGE_SIZE - sizeof(struct task_struct)]; - char kstack[(PAGE_SIZE*3)]; -}; - -struct task_bucket *sun4c_bucket[NR_TASKS]; +union task_union *sun4c_bucket[NR_TASKS]; static int sun4c_lowbucket_avail; -#define BUCKET_EMPTY ((struct task_bucket *) 0) -#define BUCKET_SIZE (PAGE_SIZE << 2) -#define BUCKET_SHIFT 14 /* log2(sizeof(struct task_bucket)) */ +#define BUCKET_EMPTY ((union task_union *) 0) +#define BUCKET_SHIFT (PAGE_SHIFT + 1) /* log2(sizeof(struct task_bucket)) */ +#define BUCKET_SIZE (1 << BUCKET_SHIFT) #define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT)) #define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR) #define BUCKET_PTE(page) \ @@ -1177,10 +1169,10 @@ { int start, end; - /* 16 buckets per segment... */ - entry &= ~15; + /* 32 buckets per segment... */ + entry &= ~31; start = entry; - for(end = (start + 16); start < end; start++) + for(end = (start + 32); start < end; start++) if(sun4c_bucket[start] != BUCKET_EMPTY) return; @@ -1190,121 +1182,70 @@ static struct task_struct *sun4c_alloc_task_struct(void) { - unsigned long addr, page; + unsigned long addr, pages; int entry; - page = get_free_page(GFP_KERNEL); - if(!page) + pages = __get_free_pages(GFP_KERNEL, 1, 0); + if(!pages) return (struct task_struct *) 0; for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++) if(sun4c_bucket[entry] == BUCKET_EMPTY) break; if(entry == NR_TASKS) { - free_page(page); + free_pages(pages, 1); return (struct task_struct *) 0; } if(entry >= sun4c_lowbucket_avail) sun4c_lowbucket_avail = entry + 1; addr = BUCKET_ADDR(entry); - sun4c_bucket[entry] = (struct task_bucket *) addr; + sun4c_bucket[entry] = (union task_union *) addr; if(sun4c_get_segmap(addr) == invalid_segment) get_locked_segment(addr); - sun4c_put_pte(addr, BUCKET_PTE(page)); + sun4c_put_pte(addr, BUCKET_PTE(pages)); + sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE)); return (struct task_struct *) addr; } -static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk) -{ - unsigned long saddr = (unsigned long) tsk; - unsigned long page[2]; - - if(!saddr) - return 0; - page[0] = __get_free_page(GFP_KERNEL); - if(!page[0]) - return 0; - page[1] = __get_free_page(GFP_KERNEL); - if(!page[1]) { - free_page(page[0]); - return 0; - } - - saddr += PAGE_SIZE << 1; - sun4c_put_pte(saddr, BUCKET_PTE(page[0])); - sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1])); - return saddr; -} - -static void sun4c_free_kernel_stack_hw(unsigned long stack) -{ - unsigned long page[2]; - - page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack)); - page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE)); - - /* We are deleting a mapping, so the flushes here are mandatory. */ - sun4c_flush_page_hw(stack); - sun4c_flush_page_hw(stack + PAGE_SIZE); - - sun4c_put_pte(stack, 0); - sun4c_put_pte(stack + PAGE_SIZE, 0); - free_page(page[0]); - free_page(page[1]); -} - static void sun4c_free_task_struct_hw(struct task_struct *tsk) { unsigned long tsaddr = (unsigned long) tsk; - unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); + unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); int entry = BUCKET_NUM(tsaddr); /* We are deleting a mapping, so the flush here is mandatory. */ sun4c_flush_page_hw(tsaddr); + sun4c_flush_page_hw(tsaddr + PAGE_SIZE); sun4c_put_pte(tsaddr, 0); + sun4c_put_pte(tsaddr + PAGE_SIZE, 0); sun4c_bucket[entry] = BUCKET_EMPTY; if(entry < sun4c_lowbucket_avail) sun4c_lowbucket_avail = entry; - free_page(page); + free_pages(pages, 1); garbage_collect(entry); } -static void sun4c_free_kernel_stack_sw(unsigned long stack) -{ - unsigned long page[2]; - - page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack)); - page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE)); - - /* We are deleting a mapping, so the flushes here are mandatory. */ - sun4c_flush_page_sw(stack); - sun4c_flush_page_sw(stack + PAGE_SIZE); - - sun4c_put_pte(stack, 0); - sun4c_put_pte(stack + PAGE_SIZE, 0); - free_page(page[0]); - free_page(page[1]); -} - static void sun4c_free_task_struct_sw(struct task_struct *tsk) { unsigned long tsaddr = (unsigned long) tsk; - unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); + unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr)); int entry = BUCKET_NUM(tsaddr); /* We are deleting a mapping, so the flush here is mandatory. */ sun4c_flush_page_sw(tsaddr); + sun4c_flush_page_sw(tsaddr + PAGE_SIZE); sun4c_put_pte(tsaddr, 0); + sun4c_put_pte(tsaddr + PAGE_SIZE, 0); sun4c_bucket[entry] = BUCKET_EMPTY; if(entry < sun4c_lowbucket_avail) sun4c_lowbucket_avail = entry; - free_page(page); + free_pages(pages, 1); garbage_collect(entry); } @@ -1312,8 +1253,8 @@ { int entry; - if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) { - prom_printf("task bucket not 4 pages!\n"); + if(sizeof(union task_union) != (PAGE_SIZE << 1)) { + prom_printf("task union not 2 pages!\n"); prom_halt(); } for(entry = 0; entry < NR_TASKS; entry++) @@ -2645,7 +2586,6 @@ flush_tlb_mm = sun4c_flush_tlb_mm_hw; flush_tlb_range = sun4c_flush_tlb_range_hw; flush_tlb_page = sun4c_flush_tlb_page_hw; - free_kernel_stack = sun4c_free_kernel_stack_hw; free_task_struct = sun4c_free_task_struct_hw; switch_to_context = sun4c_switch_to_context_hw; destroy_context = sun4c_destroy_context_hw; @@ -2658,7 +2598,6 @@ flush_tlb_mm = sun4c_flush_tlb_mm_sw; flush_tlb_range = sun4c_flush_tlb_range_sw; flush_tlb_page = sun4c_flush_tlb_page_sw; - free_kernel_stack = sun4c_free_kernel_stack_sw; free_task_struct = sun4c_free_task_struct_sw; switch_to_context = sun4c_switch_to_context_sw; destroy_context = sun4c_destroy_context_sw; @@ -2736,7 +2675,6 @@ mmu_p2v = sun4c_p2v; /* Task struct and kernel stack allocating/freeing. */ - alloc_kernel_stack = sun4c_alloc_kernel_stack; alloc_task_struct = sun4c_alloc_task_struct; quick_kernel_fault = sun4c_quick_kernel_fault; diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c --- v2.1.36/linux/arch/sparc/prom/console.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc/prom/console.c Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.11 1997/03/18 17:58:10 jj Exp $ +/* $Id: console.c,v 1.12 1997/05/01 01:41:30 davem Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * @@ -42,7 +42,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return i; /* Ugh, we could spin forever on unsupported proms ;( */ @@ -83,7 +83,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return i; /* Ugh, we could spin forever on unsupported proms ;( */ @@ -130,7 +130,7 @@ save_flags(flags); cli(); st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); if(prom_node_has_property(st_p, "keyboard")) @@ -177,7 +177,7 @@ save_flags(flags); cli(); st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/devmap.c linux/arch/sparc/prom/devmap.c --- v2.1.36/linux/arch/sparc/prom/devmap.c Sat Nov 9 00:12:24 1996 +++ linux/arch/sparc/prom/devmap.c Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: devmap.c,v 1.3 1996/09/19 20:27:19 davem Exp $ +/* $Id: devmap.c,v 1.4 1997/05/01 01:41:31 davem Exp $ * promdevmap.c: Map device/IO areas to virtual addresses. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -33,7 +33,7 @@ ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr, num_bytes); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return ret; @@ -49,7 +49,7 @@ save_flags(flags); cli(); (*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return; diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/devops.c linux/arch/sparc/prom/devops.c --- v2.1.36/linux/arch/sparc/prom/devops.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc/prom/devops.c Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: devops.c,v 1.7 1997/03/18 17:58:19 jj Exp $ +/* $Id: devops.c,v 1.8 1997/05/01 01:41:31 davem Exp $ * devops.c: Device operations using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -35,7 +35,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); @@ -60,7 +60,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return 0; @@ -86,7 +86,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c --- v2.1.36/linux/arch/sparc/prom/misc.c Mon Apr 14 16:28:08 1997 +++ linux/arch/sparc/prom/misc.c Mon May 12 10:35:38 1997 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.13 1997/04/10 05:12:59 davem Exp $ +/* $Id: misc.c,v 1.14 1997/05/01 01:41:32 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -22,7 +22,7 @@ (*(romvec->pv_reboot))(bcommand); /* Never get here. */ __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); } @@ -40,7 +40,7 @@ else (*(romvec->pv_fortheval.v2_eval))(fstring); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); } @@ -72,7 +72,7 @@ save_flags(flags); cli(); (*(romvec->pv_abort))(); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); install_linux_ticker(); @@ -97,7 +97,7 @@ (*(romvec->pv_halt))(); /* Never get here. */ __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); goto again; /* PROM is out to get me -DaveM */ diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/mp.c linux/arch/sparc/prom/mp.c --- v2.1.36/linux/arch/sparc/prom/mp.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc/prom/mp.c Mon May 12 10:35:39 1997 @@ -1,4 +1,4 @@ -/* $Id: mp.c,v 1.7 1997/03/18 17:58:23 jj Exp $ +/* $Id: mp.c,v 1.8 1997/05/01 01:41:32 davem Exp $ * mp.c: OpenBoot Prom Multiprocessor support routines. Don't call * these on a UP or else you will halt and catch fire. ;) * @@ -36,7 +36,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); @@ -65,7 +65,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); @@ -94,7 +94,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); @@ -123,7 +123,7 @@ break; }; __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/segment.c linux/arch/sparc/prom/segment.c --- v2.1.36/linux/arch/sparc/prom/segment.c Sat Nov 9 00:12:30 1996 +++ linux/arch/sparc/prom/segment.c Mon May 12 10:35:39 1997 @@ -1,4 +1,4 @@ -/* $Id: segment.c,v 1.3 1996/09/19 20:27:28 davem Exp $ +/* $Id: segment.c,v 1.4 1997/05/01 01:41:33 davem Exp $ * segment.c: Prom routine to map segments in other contexts before * a standalone is completely mapped. This is for sun4 and * sun4c architectures only. @@ -22,7 +22,7 @@ save_flags(flags); cli(); (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment); __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : + "r" (¤t_set[hard_smp_processor_id()]) : "memory"); restore_flags(flags); return; diff -u --recursive --new-file v2.1.36/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c --- v2.1.36/linux/arch/sparc/prom/tree.c Thu Mar 27 14:40:00 1997 +++ linux/arch/sparc/prom/tree.c Mon May 12 10:35:39 1997 @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.16 1997/03/19 14:53:16 davem Exp $ +/* $Id: tree.c,v 1.17 1997/05/01 01:41:33 davem Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * @@ -18,7 +18,7 @@ /* Macro to restore "current" to the g6 register. */ #define restore_current() __asm__ __volatile__("ld [%0], %%g6\n\t" : : \ - "r" (¤t_set[smp_processor_id()]) : \ + "r" (¤t_set[hard_smp_processor_id()]) : \ "memory") static char promlib_buf[128]; diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.1.36/linux/arch/sparc64/kernel/entry.S Mon Apr 14 16:28:09 1997 +++ linux/arch/sparc64/kernel/entry.S Mon May 12 10:35:39 1997 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $ +/* $Id: entry.S,v 1.15 1997/04/28 14:57:08 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -34,21 +34,37 @@ call sparc64_dtlb_fault_handler nop + /* Note, DMMU SFAR not updated for fast tlb data access miss + * traps, so we must use tag access to find the right page. + */ sparc64_dtlb_refbit_catch: + wr %g0, ASI_DMMU, %asi rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 + srlx %g5, PAGE_SHIFT, %g5 + ldxa [%g0 + TLB_SFSR] %asi, %g4 + sllx %g5, PAGE_SHIFT, %g5 ba,pt %xcc, etrap rd %pc, %g7 - call sparc64_dtlb_refbit_handler - add %sp, STACK_BIAS + REGWIN_SZ, %o0 + + clr %o1 ! text_fault == 0 + mov %l5, %o3 ! address == sfar + and %l4, 0x4, %o2 ! write == sfsr.W + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr sparc64_itlb_refbit_catch: rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate ba,pt %xcc, etrap rd %pc, %g7 - call sparc64_dtlb_refbit_handler - nop + + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3 + mov 1, %o1 ! text_fault == 1 + clr %o2 ! write == 0 + call do_sparc64_fault + add %sp, STACK_BIAS + REGWIN_SZ, %o0 ! pt_regs ptr /* Note check out head.h, this code isn't even used for UP, * for SMP things will be different. In particular the data diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S --- v2.1.36/linux/arch/sparc64/kernel/etrap.S Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc64/kernel/etrap.S Mon May 12 10:35:39 1997 @@ -1,7 +1,7 @@ -/* $Id: etrap.S,v 1.11 1997/04/14 17:04:45 jj Exp $ +/* $Id: etrap.S,v 1.12 1997/04/28 14:57:07 davem Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ @@ -11,24 +11,28 @@ #include #include -/* We assume that pstate, when entering this, has AG and IE bits set, MG and IG clear */ + /* We assume that pstate, when entering this, has AG and + * IE bits set, MG and IG clear. + * + * We also guarentee for caller that AG %g4 and %g5 will have + * their values preserved and left in %l4 and %l5 respectively + * for him (fault handling needs this). + */ .text .align 32 .globl etrap, etrap_irq etrap: - rdpr %pil, %g4 + rdpr %pil, %g2 etrap_irq: rdpr %tstate, %g1 - sllx %g4, 20, %g4 - rdpr %tpc, %g2 - or %g1, %g4, %g1 - rdpr %tnpc, %g3 + sllx %g2, 20, %g2 + or %g1, %g2, %g1 /* What happens more often? etrap when already in priv or from userland? */ andcc %g1, TSTATE_PRIV, %g0 bne,a,pn %xcc, 1f - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5 + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 /* Just when going from userland to privileged mode, * we have to change this stuff. @@ -38,41 +42,47 @@ * trap level until PRIMARY_CONTEXT is set to zero, else * we fall out of NUCLEUS too soon and crash hard. */ - rdpr %wstate, %g5 - mov PRIMARY_CONTEXT, %g7 - ldxa [%g7] ASI_DMMU, %g4 - mov SECONDARY_CONTEXT, %g6 - stxa %g0, [%g7] ASI_DMMU - stxa %g4, [%g6] ASI_DMMU - wrpr %g0, 0x0, %tl - - sll %g5, 3, %g5 - sethi %uhi(KERNBASE), %g4 - or %g4, %ulo(KERNBASE), %g4 - sethi %hi(current_set), %g6 - or %g6, %lo(current_set), %g6 - sllx %g4, 32, %g4 - wrpr %g5, %wstate - rdpr %canrestore, %g5 - ldx [%g6 + %g4], %g6 + mov PRIMARY_CONTEXT, %g1 + ldxa [%g1] ASI_DMMU, %g2 + stxa %g0, [%g1] ASI_DMMU + + mov SECONDARY_CONTEXT, %g1 + stxa %g2, [%g1] ASI_DMMU + + rdpr %wstate, %g1 + sll %g1, 3, %g1 + wrpr %g1, %wstate + + sethi %uhi(KERNBASE), %g2 + or %g2, %ulo(KERNBASE), %g2 + sethi %hi(current_set), %g1 + or %g1, %lo(current_set), %g1 + sllx %g2, 32, %g2 + ldx [%g1 + %g2], %g1 #ifdef __SMP__ /* FIXME: Fix the above insn for SMP */ #endif + rdpr %canrestore, %g2 wrpr %g0, 0, %canrestore - wrpr %g5, 0, %otherwin - ba,pt %xcc, 2f - ldx [%g6 + AOFF_task_saved_kernel_stack], %g5 + wrpr %g2, 0, %otherwin + + ldx [%g1 + AOFF_task_saved_kernel_stack], %g2 1: + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] + rdpr %tpc, %g1 + rdpr %tnpc, %g3 + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TPC] + rd %y, %g1 + stx %g3, [%g2 + REGWIN_SZ + PT_V9_TNPC] + stx %g1, [%g2 + REGWIN_SZ + PT_V9_Y] + wrpr %g0, 0x0, %tl -2: - rd %y, %g4 - stx %g1, [%g5 + REGWIN_SZ + PT_V9_TSTATE] - stx %g2, [%g5 + REGWIN_SZ + PT_V9_TPC] - stx %g3, [%g5 + REGWIN_SZ + PT_V9_TNPC] - stx %g4, [%g5 + REGWIN_SZ + PT_V9_Y] + rdpr %pstate, %g1 - save %g5, -STACK_BIAS, %sp + save %g2, -STACK_BIAS, %sp mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 mov %g7, %l2 wrpr %l1, PSTATE_AG, %pstate stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] @@ -104,11 +114,6 @@ .globl etraptl1 etraptl1: - rdpr %tl, %g4 rdpr %tstate, %g1 - sub %g4, 1, %g4 - rdpr %tpc, %g2 - rdpr %tnpc, %g3 - wrpr %g4, 0x0, %tl ba,pt %xcc, 1b - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5 + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S --- v2.1.36/linux/arch/sparc64/lib/checksum.S Wed Apr 23 19:01:16 1997 +++ linux/arch/sparc64/lib/checksum.S Mon May 12 10:35:39 1997 @@ -555,7 +555,7 @@ add %i1, %i2, %i1 2: mov %i1, %o0 - wr %%g0, ASI_S, %%asi + wr %g0, ASI_S, %asi call __bzero_noasi mov %i3, %o1 1: diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/lib/copy_from_user.S linux/arch/sparc64/lib/copy_from_user.S --- v2.1.36/linux/arch/sparc64/lib/copy_from_user.S Mon Apr 14 16:28:10 1997 +++ linux/arch/sparc64/lib/copy_from_user.S Mon May 12 10:35:39 1997 @@ -15,12 +15,16 @@ #include #include +#include + +#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4; #define EX(x,y,a,b,z) \ 98: x,y; \ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ -99: retl; \ +99: PRE_RETL \ + retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ .align 4; \ @@ -33,6 +37,7 @@ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ 99: c, d, e; \ + PRE_RETL \ retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ @@ -234,6 +239,7 @@ EX(lduba [%o1] %asi, %g2, add %g0, 1,#) stb %g2, [%o0] 1: + PRE_RETL retl clr %o0 @@ -332,6 +338,7 @@ EX(lduba [%o1] %asi, %g2, add %g0, 1,#) stb %g2, [%o0] 1: + PRE_RETL retl clr %o0 @@ -355,6 +362,7 @@ .section .fixup,#alloc,#execinstr .align 4 97: + PRE_RETL retl mov %o2, %o0 /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */ @@ -388,6 +396,7 @@ 1: and %g1, 0x7f, %o0 add %o0, %g7, %o0 + PRE_RETL retl sub %o0, %g2, %o0 51: @@ -413,6 +422,7 @@ 3: sll %g2, 2, %g2 2: + PRE_RETL retl add %g1, %g2, %o0 52: @@ -431,6 +441,7 @@ add %g2, %g4, %g2 and %o2, 0xf, %o0 add %o0, %o3, %o0 + PRE_RETL retl sub %o0, %g2, %o0 54: @@ -441,6 +452,7 @@ and %o2, 0xf, %o2 sub %o3, %o1, %o3 sub %o2, %o4, %o2 + PRE_RETL retl add %o2, %o3, %o0 55: @@ -452,5 +464,6 @@ and %g2, 1, %g2 sll %o1, 1, %o1 add %o2, %g2, %o0 + PRE_RETL retl add %o0, %o1, %o0 diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/lib/copy_to_user.S linux/arch/sparc64/lib/copy_to_user.S --- v2.1.36/linux/arch/sparc64/lib/copy_to_user.S Mon Apr 14 16:28:10 1997 +++ linux/arch/sparc64/lib/copy_to_user.S Mon May 12 10:35:39 1997 @@ -14,13 +14,17 @@ */ #include +#include #include +#define PRE_RETL sethi %uhi(KERNBASE), %g4; sllx %g4, 32, %g4; + #define EX(x,y,a,b,z) \ 98: x,y; \ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ -99: retl; \ +99: PRE_RETL \ + retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ .align 4; \ @@ -33,6 +37,7 @@ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ 99: c, d, e; \ + PRE_RETL \ retl; \ a, b, %o0; \ .section __ex_table,z##alloc; \ @@ -234,6 +239,7 @@ ldub [%o1], %g2 EX(stba %g2, [%o0] %asi, add %g0, 1,#) 1: + PRE_RETL retl clr %o0 @@ -332,6 +338,7 @@ ldub [%o1], %g2 EX(stba %g2, [%o0] %asi, add %g0, 1,#) 1: + PRE_RETL retl clr %o0 @@ -355,6 +362,7 @@ .section .fixup,#alloc,#execinstr .align 4 97: + PRE_RETL retl mov %o2, %o0 /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */ @@ -388,6 +396,7 @@ 1: and %g1, 0x7f, %o0 add %o0, %g7, %o0 + PRE_RETL retl sub %o0, %g2, %o0 51: @@ -413,6 +422,7 @@ 3: sll %g2, 2, %g2 2: + PRE_RETL retl add %g1, %g2, %o0 52: @@ -431,6 +441,7 @@ add %g2, %g4, %g2 and %o2, 0xf, %o0 add %o0, %o3, %o0 + PRE_RETL retl sub %o0, %g2, %o0 54: @@ -441,6 +452,7 @@ and %o2, 0xf, %o2 sub %o3, %o1, %o3 sub %o2, %o4, %o2 + PRE_RETL retl add %o2, %o3, %o0 55: @@ -452,5 +464,6 @@ and %g2, 1, %g2 sll %o1, 1, %o1 add %o2, %g2, %o0 + PRE_RETL retl add %o0, %o1, %o0 diff -u --recursive --new-file v2.1.36/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.1.36/linux/arch/sparc64/mm/init.c Wed Apr 23 19:01:17 1997 +++ linux/arch/sparc64/mm/init.c Mon May 12 10:35:39 1997 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.24 1997/04/17 21:49:41 jj Exp $ +/* $Id: init.c,v 1.25 1997/04/28 14:57:11 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -694,6 +694,11 @@ min_free_pages = 16; free_pages_low = min_free_pages + (min_free_pages >> 1); free_pages_high = min_free_pages + min_free_pages; + +#if 0 + printk("Testing fault handling...\n"); + *(char *)0x00000deadbef0000UL = 0; +#endif } void free_initmem (void) diff -u --recursive --new-file v2.1.36/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.1.36/linux/drivers/block/amiflop.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/block/amiflop.c Mon May 12 10:35:39 1997 @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -1712,7 +1713,7 @@ } -static void probe_drives(void) +__initfunc(static void probe_drives(void)) { int drive,found; @@ -1860,7 +1861,7 @@ } -int amiga_floppy_init(void) +__initfunc(int amiga_floppy_init(void)) { int i; diff -u --recursive --new-file v2.1.36/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c --- v2.1.36/linux/drivers/block/ataflop.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/block/ataflop.c Mon May 12 10:35:39 1997 @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -1777,7 +1778,7 @@ /* Initialize the 'unit' variable for drive 'drive' */ -static void fd_probe( int drive ) +__initfunc(static void fd_probe( int drive )) { UD.connected = 0; UDT = NULL; @@ -1820,7 +1821,7 @@ * declared absent. */ -static int fd_test_drive_present( int drive ) +__initfunc(static int fd_test_drive_present( int drive )) { unsigned long timeout; unsigned char status; @@ -1867,7 +1868,7 @@ * floppies, additionally start the disk-change and motor-off timers. */ -static void config_types( void ) +__initfunc(static void config_types( void )) { int drive, cnt = 0; @@ -2010,7 +2011,7 @@ floppy_revalidate, /* revalidate */ }; -int atari_floppy_init (void) +__initfunc(int atari_floppy_init (void)) { int i; @@ -2070,7 +2071,7 @@ } -void atari_floppy_setup( char *str, int *ints ) +__initfunc(void atari_floppy_setup( char *str, int *ints )) { int i; diff -u --recursive --new-file v2.1.36/linux/drivers/block/ez.c linux/drivers/block/ez.c --- v2.1.36/linux/drivers/block/ez.c Wed Dec 18 05:57:28 1996 +++ linux/drivers/block/ez.c Mon May 12 10:35:39 1997 @@ -101,6 +101,7 @@ #include #include #include +#include #include #include @@ -256,7 +257,7 @@ ez_revalidate /* revalidate new media */ }; -int ez_init (void) /* preliminary initialisation */ +__initfunc(int ez_init (void)) /* preliminary initialisation */ { if (register_blkdev(MAJOR_NR,"ez",&ez_fops)) { @@ -271,7 +272,7 @@ return 0; } -static void ez_geninit (struct gendisk *ignored) /* real init */ +__initfunc(static void ez_geninit (struct gendisk *ignored)) /* real init */ { int i; @@ -507,7 +508,7 @@ syntax: ez=base[,irq[,rep[,nybble]]] */ -void ez_setup(char *str, int *ints) +__initfunc(void ez_setup(char *str, int *ints)) { if (ints[0] > 0) ez_base = ints[1]; if (ints[0] > 1) ez_irq = ints[2]; @@ -748,7 +749,7 @@ /* ez_media_check: check for and acknowledge the MC flag */ -static void ez_media_check( void ) +__initfunc(static void ez_media_check( void )) { int r; @@ -768,7 +769,7 @@ disconnect(); } -static int ez_identify( void ) +__initfunc(static int ez_identify( void )) { int k, r; @@ -800,7 +801,7 @@ #define word_val(n) (ez_scratch[2*n]+256*ez_scratch[2*n+1]) -static void ez_get_capacity( void ) +__initfunc(static void ez_get_capacity( void )) { int ez_cylinders; @@ -821,7 +822,7 @@ ez_heads,ez_sectors); } -static void ez_standby_off( void ) +__initfunc(static void ez_standby_off( void )) { connect(); wait_for(0,NULL); @@ -830,7 +831,7 @@ disconnect(); } -static int ez_port_check( void ) /* check for 8-bit port */ +__initfunc(static int ez_port_check( void )) /* check for 8-bit port */ { int r; @@ -843,7 +844,7 @@ return 0; } -static int ez_detect( void ) +__initfunc(static int ez_detect( void )) { int j, k; char sig[EZ_SIGLEN] = EZ_SIG; diff -u --recursive --new-file v2.1.36/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.36/linux/drivers/block/floppy.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/block/floppy.c Mon May 12 10:35:39 1997 @@ -140,6 +140,7 @@ #include /* CMOS defines */ #include #include +#include #include #include @@ -3726,7 +3727,7 @@ /* Determine the floppy disk controller type */ /* This routine was written by David C. Niemi */ -static char get_fdc_version(void) +__initfunc(static char get_fdc_version(void)) { int r; @@ -3804,7 +3805,7 @@ /* lilo configuration */ -static void floppy_set_flags(int *ints,int param, int param2) +__initfunc(static void floppy_set_flags(int *ints,int param, int param2)) { int i; @@ -3817,7 +3818,7 @@ DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param); } -static void daring(int *ints,int param, int param2) +__initfunc(static void daring(int *ints,int param, int param2)) { int i; @@ -3833,7 +3834,7 @@ DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken"); } -static void set_cmos(int *ints, int dummy, int dummy2) +__initfunc(static void set_cmos(int *ints, int dummy, int dummy2)) { int current_drive=0; @@ -3894,7 +3895,7 @@ { "L40SX", 0, &print_unex, 0, 0 } }; #define FLOPPY_SETUP -void floppy_setup(char *str, int *ints) +__initfunc(void floppy_setup(char *str, int *ints)) { int i; int param; @@ -3930,7 +3931,7 @@ static int have_no_fdc= -EIO; -int floppy_init(void) +__initfunc(int floppy_init(void)) { int i,unit,drive; @@ -4135,7 +4136,7 @@ char *floppy=NULL; -static void parse_floppy_cfg_string(char *cfg) +__initfunc(static void parse_floppy_cfg_string(char *cfg)) { char *ptr; int ints[11]; @@ -4151,7 +4152,7 @@ } } -static void mod_setup(char *pattern, void (*setup)(char *, int *)) +__initfunc(static void mod_setup(char *pattern, void (*setup)(char *, int *))) { unsigned long i; char c; diff -u --recursive --new-file v2.1.36/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.1.36/linux/drivers/block/genhd.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/block/genhd.c Mon May 12 10:35:39 1997 @@ -191,7 +191,7 @@ */ bh->b_state = 0; - if (le16_to_cpu(*(unsigned short *) (bh->b_data+510)) != MSDOS_LABEL_MAGIC) + if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC)) goto done; p = (struct partition *) (0x1BE + bh->b_data); @@ -316,7 +316,7 @@ #ifdef CONFIG_BLK_DEV_IDE check_table: #endif - if (le16_to_cpu(*(unsigned short *) (0x1fe + data)) != MSDOS_LABEL_MAGIC) { + if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { brelse(bh); return 0; } @@ -359,7 +359,7 @@ goto read_mbr; /* start over with new MBR */ } } else if (sig <= 0x1ae && - le16_to_cpu(*(unsigned short *)(data + sig)) == 0x55AA && + *(unsigned short *)(data + sig) == cpu_to_le16(0x55AA) && (1 & *(unsigned char *)(data + sig + 2))) { /* DM6 signature in MBR, courtesy of OnTrack */ (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]"); @@ -424,7 +424,7 @@ /* * Check for old-style Disk Manager partition table */ - if (le16_to_cpu(*(unsigned short *) (data+0xfc)) == MSDOS_LABEL_MAGIC) { + if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) { p = (struct partition *) (0x1be + data); for (i = 4 ; i < 16 ; i++, current_minor++) { p--; @@ -603,7 +603,7 @@ } static int -amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) +amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) { struct buffer_head *bh; struct RigidDiskBlock *rdb; @@ -618,13 +618,15 @@ for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) { if(!(bh = bread(dev,blk,512))) { - printk("Dev %d: unable to read RDB block %d\n",dev,blk); + printk("Dev %s: unable to read RDB block %d\n", + kdevname(dev),blk); goto rdb_done; } - if (*(__u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) { + if (*(u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) { rdb = (struct RigidDiskBlock *)bh->b_data; - if (checksum_block((__u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) { - printk("Dev %d: RDB in block %d has bad checksum\n",dev,blk); + if (checksum_block((u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) { + printk("Dev %s: RDB in block %d has bad checksum\n", + kdevname(dev),blk); brelse(bh); continue; } @@ -633,14 +635,14 @@ brelse(bh); for (part = 1; blk > 0 && part <= 16; part++) { if (!(bh = bread(dev,blk,512))) { - printk("Dev %d: unable to read partition block %d\n", - dev,blk); + printk("Dev %s: unable to read partition block %d\n", + kdevname(dev),blk); goto rdb_done; } pb = (struct PartitionBlock *)bh->b_data; blk = htonl(pb->pb_Next); if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block( - (__u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) { + (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) { /* Tell Kernel about it */ diff -u --recursive --new-file v2.1.36/linux/drivers/block/hd.c linux/drivers/block/hd.c --- v2.1.36/linux/drivers/block/hd.c Fri Apr 4 08:52:17 1997 +++ linux/drivers/block/hd.c Mon May 12 10:35:39 1997 @@ -39,6 +39,7 @@ #include #include #include /* CMOS defines */ +#include #define REALLY_SLOW_IO #include @@ -110,7 +111,7 @@ } #endif -void hd_setup(char *str, int *ints) +__initfunc(void hd_setup(char *str, int *ints)) { int hdind = 0; @@ -792,7 +793,7 @@ block_fsync /* fsync */ }; -int hd_init(void) +__initfunc(int hd_init(void)) { if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) { printk("hd: unable to get major %d for harddisk\n",MAJOR_NR); diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.1.36/linux/drivers/block/ide-disk.c Wed Dec 11 06:45:54 1996 +++ linux/drivers/block/ide-disk.c Mon May 12 10:35:39 1997 @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -59,6 +58,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.1.36/linux/drivers/block/ide-floppy.c Thu Mar 27 14:40:02 1997 +++ linux/drivers/block/ide-floppy.c Mon May 12 17:39:50 1997 @@ -726,7 +726,7 @@ return; } #ifdef CONFIG_BLK_DEV_TRITON - if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { + if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n"); printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n"); HWIF(drive)->dmaproc(ide_dma_off, drive); @@ -842,7 +842,7 @@ bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ #ifdef CONFIG_BLK_DEV_TRITON - if (clear_bit (PC_DMA_ERROR, &pc->flags)) { + if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n"); HWIF(drive)->dmaproc(ide_dma_off, drive); } @@ -1182,7 +1182,7 @@ { idefloppy_floppy_t *floppy = drive->driver_data; - return clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags); + return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags); } /* diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.1.36/linux/drivers/block/ide-probe.c Sat Jan 25 10:51:17 1997 +++ linux/drivers/block/ide-probe.c Mon May 12 10:35:39 1997 @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -58,6 +57,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.1.36/linux/drivers/block/ide-tape.c Fri Apr 4 08:52:17 1997 +++ linux/drivers/block/ide-tape.c Mon May 12 17:39:50 1997 @@ -1777,7 +1777,7 @@ return; } #ifdef CONFIG_BLK_DEV_TRITON - if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { + if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n"); printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); HWIF(drive)->dmaproc(ide_dma_off, drive); @@ -1916,7 +1916,7 @@ bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ #ifdef CONFIG_BLK_DEV_TRITON - if (clear_bit (PC_DMA_ERROR, &pc->flags)) { + if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n"); HWIF(drive)->dmaproc(ide_dma_off, drive); } @@ -2248,7 +2248,7 @@ status.all = GET_STAT(); if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2) set_bit (IDETAPE_IGNORE_DSC, &tape->flags); - if (!clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) { + if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) { if (postponed_rq == NULL) { tape->dsc_polling_start = jiffies; tape->dsc_polling_frequency = tape->best_dsc_rw_frequency; @@ -2506,7 +2506,7 @@ if (!idetape_pipeline_active (tape) && tape->nr_stages >= (3 * tape->max_stages) / 4) idetape_insert_pipeline_into_queue (drive); - if (clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags)) /* Return a deferred error */ + if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags)) /* Return a deferred error */ return -EIO; return blocks; } @@ -3254,7 +3254,7 @@ return -ENXIO; tape = drive->driver_data; - if (set_bit (IDETAPE_BUSY, &tape->flags)) + if (test_and_set_bit (IDETAPE_BUSY, &tape->flags)) return -EBUSY; MOD_INC_USE_COUNT; idetape_create_read_position_cmd (&pc); diff -u --recursive --new-file v2.1.36/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.36/linux/drivers/block/ide.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/block/ide.c Mon May 12 10:35:39 1997 @@ -294,7 +294,6 @@ #include #include #include -#include #include #include #include @@ -307,6 +306,8 @@ #include #include #include +#include +#include #include #include @@ -2144,7 +2145,7 @@ * stridx() returns the offset of c within s, * or -1 if c is '\0' or not found within s. */ -static int stridx (const char *s, char c) +__initfunc(static int stridx (const char *s, char c)) { char *i = strchr(s, c); return (i && c) ? i - s : -1; @@ -2162,7 +2163,7 @@ * and base16 is allowed when prefixed with "0x". * 4. otherwise, zero is returned. */ -static int match_parm (char *s, const char *keywords[], int vals[], int max_vals) +__initfunc(static int match_parm (char *s, const char *keywords[], int vals[], int max_vals)) { static const char *decimal = "0123456789"; static const char *hex = "0123456789abcdef"; @@ -2261,7 +2262,7 @@ * "ide0=ali14xx" : probe/support ali14xx chipsets (ALI M1439, M1443, M1445) * "ide0=umc8672" : probe/support umc8672 chipsets */ -void ide_setup (char *s) +__initfunc(void ide_setup (char *s)) { int i, vals[3]; ide_hwif_t *hwif; @@ -2558,7 +2559,7 @@ * ide_probe_pci() scans PCI for a specific vendor/device function, * and invokes the supplied init routine for each instance detected. */ -static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj) +__initfunc(static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj)) { unsigned long flags; unsigned index; @@ -2581,7 +2582,7 @@ * This routine should ideally be using pcibios_find_class() to find all * PCI IDE interfaces, but that function causes some systems to "go weird". */ -static void probe_for_hwifs (void) +__initfunc(static void probe_for_hwifs (void)) { #ifdef CONFIG_PCI /* @@ -2620,7 +2621,7 @@ #endif } -void ide_init_builtin_drivers (void) +__initfunc(void ide_init_builtin_drivers (void)) { /* * Probe for special "known" interface chipsets @@ -2889,7 +2890,7 @@ /* * This is gets invoked once during initialization, to set *everything* up */ -int ide_init (void) +__initfunc(int ide_init (void)) { init_ide_data (); @@ -2904,7 +2905,7 @@ char *options = NULL; MODULE_PARM(options,"s"); -static void parse_options (char *line) +__initfunc(static void parse_options (char *line)) { char *next = line; diff -u --recursive --new-file v2.1.36/linux/drivers/block/linear.c linux/drivers/block/linear.c --- v2.1.36/linux/drivers/block/linear.c Fri Nov 22 06:07:23 1996 +++ linux/drivers/block/linear.c Mon May 12 10:35:39 1997 @@ -21,6 +21,7 @@ #include #include +#include #include "linear.h" @@ -180,7 +181,7 @@ #ifndef MODULE -void linear_init (void) +__initfunc(void linear_init (void)) { register_md_personality (LINEAR, &linear_personality); } diff -u --recursive --new-file v2.1.36/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.1.36/linux/drivers/block/loop.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/block/loop.c Mon May 12 10:35:39 1997 @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -537,8 +538,8 @@ #define loop_init init_module #endif -int -loop_init( void ) { +__initfunc(int +loop_init( void )) { int i; if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) { diff -u --recursive --new-file v2.1.36/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.1.36/linux/drivers/block/md.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/block/md.c Mon May 12 10:35:39 1997 @@ -35,6 +35,7 @@ #include #endif #include +#include #define MAJOR_NR MD_MAJOR #define MD_DRIVER @@ -546,7 +547,7 @@ void raid1_init (void); void raid5_init (void); -int md_init (void) +__initfunc(int md_init (void)) { printk ("md driver %s MAX_MD_DEV=%d, MAX_REAL=%d\n", MD_VERSION, MAX_MD_DEV, MAX_REAL); diff -u --recursive --new-file v2.1.36/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c --- v2.1.36/linux/drivers/block/ps2esdi.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/block/ps2esdi.c Mon May 12 10:35:39 1997 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -176,7 +177,7 @@ }; /* initialization routine called by ll_rw_blk.c */ -int ps2esdi_init(void) +__initfunc(int ps2esdi_init(void)) { /* register the device - pass the name, major number and operations @@ -197,7 +198,7 @@ } /* ps2esdi_init */ /* handles boot time command line parameters */ -void tp720_setup(char *str, int *ints) +__initfunc(void tp720_setup(char *str, int *ints)) { /* no params, just sets the tp720esdi flag if it exists */ @@ -205,7 +206,7 @@ tp720esdi = 1; } -void ed_setup(char *str, int *ints) +__initfunc(void ed_setup(char *str, int *ints)) { int hdind = 0; @@ -252,10 +253,9 @@ } /* ps2 esdi specific initialization - called thru the gendisk chain */ -static void ps2esdi_geninit(struct gendisk *ignored) +__initfunc(static void ps2esdi_geninit(struct gendisk *ignored)) { /* - The first part contains the initialization code for the ESDI disk subsystem. All we really do is search for the POS registers of the controller @@ -386,7 +386,7 @@ } /* ps2esdi_geninit */ -static void ps2esdi_get_device_cfg(void) +__initfunc(static void ps2esdi_get_device_cfg(void)) { u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH]; diff -u --recursive --new-file v2.1.36/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.1.36/linux/drivers/block/rd.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/block/rd.c Mon May 12 10:35:39 1997 @@ -51,9 +51,11 @@ #include #include #include +#include #include #include +#include extern void wait_for_keypress(void); @@ -269,7 +271,7 @@ }; /* This is the registration and initialization section of the ramdisk driver */ -int rd_init(void) +__initfunc(int rd_init(void)) { int i; @@ -334,8 +336,8 @@ * romfs * gzip */ -int -identify_ramdisk_image(kdev_t device, struct file *fp, int start_block) +__initfunc(int +identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)) { const int size = 512; struct minix_super_block *minixsb; @@ -440,7 +442,7 @@ /* * This routine loads in the ramdisk image. */ -static void rd_load_image(kdev_t device,int offset) +__initfunc(static void rd_load_image(kdev_t device,int offset)) { struct inode inode, out_inode; struct file infile, outfile; @@ -527,7 +529,7 @@ } -void rd_load() +__initfunc(void rd_load(void)) { if (rd_doload == 0) return; @@ -549,7 +551,7 @@ #ifdef CONFIG_BLK_DEV_INITRD -void initrd_load(void) +__initfunc(void initrd_load(void)) { rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0); } @@ -608,21 +610,21 @@ #include "../../lib/inflate.c" -static void *malloc(int size) +__initfunc(static void *malloc(int size)) { return kmalloc(size, GFP_KERNEL); } -static void free(void *where) +__initfunc(static void free(void *where)) { kfree(where); } -static void gzip_mark(void **ptr) +__initfunc(static void gzip_mark(void **ptr)) { } -static void gzip_release(void **ptr) +__initfunc(static void gzip_release(void **ptr)) { } @@ -631,7 +633,7 @@ * Fill the input buffer. This is called only when the buffer is empty * and at least one byte is really needed. */ -static int fill_inbuf() +__initfunc(static int fill_inbuf(void)) { if (exit_code) return -1; @@ -648,7 +650,7 @@ * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ -static void flush_window() +__initfunc(static void flush_window(void)) { ulg c = crc; /* temporary variable */ unsigned n; @@ -666,14 +668,14 @@ outcnt = 0; } -static void error(char *x) +__initfunc(static void error(char *x)) { printk(KERN_ERR "%s", x); exit_code = 1; } -static int -crd_load(struct file * fp, struct file *outfp) +__initfunc(static int +crd_load(struct file * fp, struct file *outfp)) { int result; diff -u --recursive --new-file v2.1.36/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.1.36/linux/drivers/block/xd.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/block/xd.c Mon May 12 10:35:39 1997 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -126,7 +127,7 @@ static u_short xd_iobase = 0; /* xd_init: register the block device number and set up pointer tables */ -int xd_init (void) +__initfunc(int xd_init (void)) { if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) { printk("xd_init: unable to get major number %d\n",MAJOR_NR); @@ -141,7 +142,7 @@ } /* xd_detect: scan the possible BIOS ROM locations for the signature strings */ -static u_char xd_detect (u_char *controller, unsigned int *address) +__initfunc(static u_char xd_detect (u_char *controller, unsigned int *address)) { u_char i,j,found = 0; @@ -164,7 +165,7 @@ /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */ /* and set up the "raw" device entries in the table */ -static void xd_geninit (struct gendisk *ignored) +__initfunc(static void xd_geninit (struct gendisk *ignored)) { u_char i,controller; unsigned int address; @@ -527,7 +528,7 @@ return (csb & CSB_ERROR); } -static u_char xd_initdrives (void (*init_drive)(u_char drive)) +__initfunc(static u_char xd_initdrives (void (*init_drive)(u_char drive))) { u_char cmdblk[6],i,count = 0; @@ -541,7 +542,7 @@ return (count); } -static void xd_dtc_init_controller (unsigned int address) +__initfunc(static void xd_dtc_init_controller (unsigned int address)) { switch (address) { case 0xC8000: xd_iobase = 0x320; break; @@ -556,7 +557,7 @@ outb(0,XD_RESET); /* reset the controller */ } -static void xd_dtc_init_drive (u_char drive) +__initfunc(static void xd_dtc_init_drive (u_char drive)) { u_char cmdblk[6],buf[64]; @@ -581,7 +582,7 @@ printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive); } -static void xd_wd_init_controller (unsigned int address) +__initfunc(static void xd_wd_init_controller (unsigned int address)) { switch (address) { case 0xC8000: xd_iobase = 0x320; break; @@ -600,7 +601,7 @@ /* outb(0,XD_RESET); */ /* reset the controller */ } -static void xd_wd_init_drive (u_char drive) +__initfunc(static void xd_wd_init_drive (u_char drive)) { u_char cmdblk[6],buf[0x200]; @@ -622,7 +623,7 @@ printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive); } -static void xd_seagate_init_controller (unsigned int address) +__initfunc(static void xd_seagate_init_controller (unsigned int address)) { switch (address) { case 0xC8000: xd_iobase = 0x320; break; @@ -639,7 +640,7 @@ outb(0,XD_RESET); /* reset the controller */ } -static void xd_seagate_init_drive (u_char drive) +__initfunc(static void xd_seagate_init_drive (u_char drive)) { u_char cmdblk[6],buf[0x200]; @@ -655,7 +656,7 @@ } /* Omti support courtesy Dirk Melchers */ -static void xd_omti_init_controller (unsigned int address) +__initfunc(static void xd_omti_init_controller (unsigned int address)) { switch (address) { case 0xC8000: xd_iobase = 0x320; break; @@ -673,7 +674,7 @@ outb(0,XD_RESET); /* reset the controller */ } -static void xd_omti_init_drive (u_char drive) +__initfunc(static void xd_omti_init_drive (u_char drive)) { /* gets infos from drive */ xd_override_init_drive(drive); @@ -684,7 +685,7 @@ /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */ -static void xd_override_init_drive (u_char drive) +__initfunc(static void xd_override_init_drive (u_char drive)) { u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 }; u_char cmdblk[6],i; @@ -707,7 +708,7 @@ } /* xd_setup: initialise from command line parameters */ -void xd_setup (char *command,int *integers) +__initfunc(void xd_setup (char *command,int *integers)) { xd_override = 1; @@ -720,7 +721,7 @@ } /* xd_setparam: set the drive characteristics */ -static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc) +__initfunc(static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)) { u_char cmdblk[14]; diff -u --recursive --new-file v2.1.36/linux/drivers/block/z2ram.c linux/drivers/block/z2ram.c --- v2.1.36/linux/drivers/block/z2ram.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/block/z2ram.c Mon May 12 10:35:39 1997 @@ -28,6 +28,7 @@ #include #include #include +#include #if defined(MODULE) #include @@ -282,8 +283,8 @@ block_fsync /* fsync */ }; -int -z2_init( void ) +__initfunc(int +z2_init( void )) { if ( !MACH_IS_AMIGA ) diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v2.1.36/linux/drivers/cdrom/aztcd.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/aztcd.c Mon May 12 10:35:39 1997 @@ -166,6 +166,7 @@ #include #include #include +#include #include #include @@ -1049,7 +1050,7 @@ Kernel Interface Functions ########################################################################## */ -void aztcd_setup(char *str, int *ints) +__initfunc(void aztcd_setup(char *str, int *ints)) { if (ints[0] > 0) azt_port = ints[1]; if (ints[0] > 1) @@ -1567,7 +1568,7 @@ * Test for presence of drive and initialize it. Called at boot time. */ -int aztcd_init(void) +__initfunc(int aztcd_init(void)) { long int count, max_count; unsigned char result[50]; int st; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/bpcd.c linux/drivers/cdrom/bpcd.c --- v2.1.36/linux/drivers/cdrom/bpcd.c Sun Jan 26 02:07:11 1997 +++ linux/drivers/cdrom/bpcd.c Mon May 12 10:35:39 1997 @@ -113,6 +113,7 @@ #include #include #include +#include #include #include @@ -201,7 +202,7 @@ nybble value. The following function initialises the table. */ -static void init_nyb_map( void ) +__initfunc(static void init_nyb_map( void )) { int i, j; @@ -212,7 +213,7 @@ } } -int bpcd_init (void) /* preliminary initialisation */ +__initfunc(int bpcd_init (void)) /* preliminary initialisation */ { init_nyb_map(); @@ -327,7 +328,7 @@ syntax: bpcd=base[,nybble[,rep]] */ -void bpcd_setup(char *str, int *ints) +__initfunc(void bpcd_setup(char *str, int *ints)) { if (ints[0] > 0) bp_base = ints[1]; if (ints[0] > 1) bp_nybble = ints[2]; @@ -425,7 +426,7 @@ if (bp_mode == 2) { t2(1); t2(0x20); } } -static int probe( int id ) +__initfunc(static int probe( int id )) { int l, h, t; int r = -1; @@ -588,7 +589,7 @@ bp_atapi(ej_cmd,0,"eject"); } -static int bp_reset( void ) +__initfunc(static int bp_reset( void )) /* the ATAPI standard actually specifies the contents of all 7 registers after a reset, but the specification is ambiguous concerning the last @@ -615,7 +616,7 @@ return flg-1; } -static int bp_identify( char * id ) +__initfunc(static int bp_identify( char * id )) { int k; char id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0}; @@ -627,7 +628,7 @@ return 0; } -static int bp_port_check( void ) /* check for 8-bit port */ +__initfunc(static int bp_port_check( void )) /* check for 8-bit port */ { int r; @@ -640,7 +641,7 @@ return 0; } -static int bp_locate( void ) +__initfunc(static int bp_locate( void )) { int k; @@ -652,7 +653,7 @@ return -1; } -static int bp_do_detect( int autop ) +__initfunc(static int bp_do_detect( int autop )) { char id[18]; @@ -705,7 +706,7 @@ add it here .... */ -static int bp_detect( void ) +__initfunc(static int bp_detect( void )) { if (bp_base) return bp_do_detect(0); if (!bp_do_detect(0x378)) return 0; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/cdi.c linux/drivers/cdrom/cdi.c --- v2.1.36/linux/drivers/cdrom/cdi.c Tue Feb 13 00:30:25 1996 +++ linux/drivers/cdrom/cdi.c Mon May 12 10:35:39 1997 @@ -28,6 +28,7 @@ #include #include /* where the proto type of cdi_init() is */ +#include #ifdef CONFIG_ISP16_CDI #include #endif CONFIG_ISP16_CDI @@ -35,8 +36,8 @@ /* * Cdrom interface configuration. */ -int -cdi_init(void) +__initfunc(int +cdi_init(void)) { int ret_val = -1; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c --- v2.1.36/linux/drivers/cdrom/cdu31a.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/cdu31a.c Mon May 12 10:35:39 1997 @@ -190,6 +190,7 @@ #include #include #include +#include #include #include @@ -220,7 +221,7 @@ unsigned short base; /* I/O Base Address */ short int_num; /* Interrupt Number (-1 means scan for it, 0 means don't use) */ -} cdu31a_addresses[] = +} cdu31a_addresses[] __initdata = { #if 0 /* No autoconfig any more. See Note at beginning of this file. */ @@ -2963,12 +2964,12 @@ /* The different types of disc loading mechanisms supported */ -static const char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" }; +static const char *load_mech[] __initdata = { "caddy", "tray", "pop-up", "unknown" }; -static void +__initfunc(static void get_drive_configuration(unsigned short base_io, unsigned char res_reg[], - unsigned int *res_size) + unsigned int *res_size)) { int retry_count; @@ -3032,9 +3033,9 @@ /* * Set up base I/O and interrupts, called from main.c. */ -void +__initfunc(void cdu31a_setup(char *strings, - int *ints) + int *ints)) { if (ints[0] > 0) { @@ -3063,8 +3064,8 @@ /* * Initialize the driver. */ -int -cdu31a_init(void) +__initfunc(int +cdu31a_init(void)) { struct s_sony_drive_config drive_config; unsigned int res_size; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c --- v2.1.36/linux/drivers/cdrom/cm206.c Fri Dec 27 02:03:20 1996 +++ linux/drivers/cdrom/cm206.c Mon May 12 10:35:39 1997 @@ -138,6 +138,7 @@ #include #include #include +#include #include @@ -1186,7 +1187,7 @@ check_region, 15 bits of one port and 6 of another make things likely enough to accept the region on the first hit... */ -int probe_base_port(int base) +__initfunc(int probe_base_port(int base)) { int b=0x300, e=0x370; /* this is the range of start addresses */ volatile int fool, i; @@ -1206,7 +1207,7 @@ #if !defined(MODULE) || defined(AUTO_PROBE_MODULE) /* Probe for irq# nr. If nr==0, probe for all possible irq's. */ -int probe_irq(int nr) { +__initfunc(int probe_irq(int nr)) { int irqs, irq; outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */ sti(); @@ -1220,7 +1221,7 @@ } #endif -int cm206_init(void) +__initfunc(int cm206_init(void)) { uch e=0; long int size=sizeof(struct cm206_struct); @@ -1303,7 +1304,7 @@ static int cm206[2] = {0,0}; /* for compatible `insmod' parameter passing */ -void parse_options(void) +__initfunc(void parse_options(void)) { int i; for (i=0; i<2; i++) { @@ -1337,7 +1338,7 @@ /* This setup function accepts either `auto' or numbers in the range * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */ -void cm206_setup(char *s, int *p) +__initfunc(void cm206_setup(char *s, int *p)) { int i; if (!strcmp(s, "auto")) auto_probe=1; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c --- v2.1.36/linux/drivers/cdrom/gscd.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/gscd.c Mon May 12 10:35:39 1997 @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -191,7 +192,7 @@ } -void gscd_setup (char *str, int *ints) +__initfunc(void gscd_setup (char *str, int *ints)) { if (ints[0] > 0) { @@ -848,7 +849,7 @@ return; } -int find_drives (void) +__initfunc(int find_drives (void)) { int *pdrv; int drvnum; @@ -899,7 +900,7 @@ return drvnum; } -void init_cd_drive ( int num ) +__initfunc(void init_cd_drive ( int num )) { char resp [50]; int i; @@ -991,7 +992,7 @@ /* Test for presence of drive and initialize it. Called only at boot time. */ -int gscd_init (void) +__initfunc(int gscd_init (void)) { return my_gscd_init (); } @@ -999,7 +1000,7 @@ /* This is the common initialisation for the GoldStar drive. */ /* It is called at boot time AND for module init. */ -int my_gscd_init (void) +__initfunc(int my_gscd_init (void)) { int i; int result; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/isp16.c linux/drivers/cdrom/isp16.c --- v2.1.36/linux/drivers/cdrom/isp16.c Sun Feb 2 05:18:30 1997 +++ linux/drivers/cdrom/isp16.c Mon May 12 10:35:39 1997 @@ -48,6 +48,7 @@ #include #include #include +#include #include static short isp16_detect(void); @@ -76,8 +77,8 @@ #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) -void -isp16_setup(char *str, int *ints) +__initfunc(void +isp16_setup(char *str, int *ints)) { if ( ints[0] > 0 ) isp16_cdrom_base = ints[1]; @@ -93,8 +94,8 @@ * ISP16 initialisation. * */ -int -isp16_init(void) +__initfunc(int +isp16_init(void)) { u_char expected_drive; @@ -143,8 +144,8 @@ return(0); } -static short -isp16_detect(void) +__initfunc(static short +isp16_detect(void)) { if ( isp16_c929__detect() >= 0 ) @@ -153,8 +154,8 @@ return(isp16_c928__detect()); } -static short -isp16_c928__detect(void) +__initfunc(static short +isp16_c928__detect(void)) { u_char ctrl; u_char enable_cdrom; @@ -202,8 +203,8 @@ return(i); } -static short -isp16_c929__detect(void) +__initfunc(static short +isp16_c929__detect(void)) { u_char ctrl; u_char tmp; @@ -229,8 +230,8 @@ return(2); } -static short -isp16_cdi_config(int base, u_char drive_type, int irq, int dma) +__initfunc(static short +isp16_cdi_config(int base, u_char drive_type, int irq, int dma)) { u_char base_code; u_char irq_code; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v2.1.36/linux/drivers/cdrom/mcd.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/mcd.c Mon May 12 10:35:39 1997 @@ -80,6 +80,7 @@ #include #include #include +#include /* #define REALLY_SLOW_IO */ #include @@ -196,7 +197,7 @@ static int getValue(unsigned char *result); -void mcd_setup(char *str, int *ints) +__initfunc(void mcd_setup(char *str, int *ints)) { if (ints[0] > 0) mcd_port = ints[1]; @@ -1175,7 +1176,7 @@ * Test for presence of drive and initialize it. Called at boot time. */ -int mcd_init(void) +__initfunc(int mcd_init(void)) { int count; unsigned char result[3]; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c --- v2.1.36/linux/drivers/cdrom/mcdx.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/mcdx.c Mon May 12 10:35:39 1997 @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -910,7 +911,7 @@ return 1; } -void mcdx_setup(char *str, int *pi) +__initfunc(void mcdx_setup(char *str, int *pi)) { if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1]; if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2]; @@ -1160,7 +1161,7 @@ /* Support functions ************************************************/ -int mcdx_init(void) +__initfunc(int mcdx_init(void)) { int drive; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c --- v2.1.36/linux/drivers/cdrom/optcd.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/optcd.c Mon May 12 10:35:39 1997 @@ -65,6 +65,7 @@ #include #include #include +#include #include #define MAJOR_NR OPTICS_CDROM_MAJOR @@ -1961,7 +1962,7 @@ /* Returns 1 if a drive is detected with a version string starting with "DOLPHIN". Otherwise 0. */ -static int version_ok(void) +__initfunc(static int version_ok(void)) { char devname[100]; int count, i, ch, status; @@ -2016,7 +2017,7 @@ /* Get kernel parameter when used as a kernel driver */ -void optcd_setup(char *str, int *ints) +__initfunc(void optcd_setup(char *str, int *ints)) { if (ints[0] > 0) optcd_port = ints[1]; @@ -2024,7 +2025,7 @@ /* Test for presence of drive and initialize it. Called at boot time or during module initialisation. */ -int optcd_init(void) +__initfunc(int optcd_init(void)) { int status; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.1.36/linux/drivers/cdrom/sbpcd.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/sbpcd.c Mon May 12 10:35:39 1997 @@ -328,6 +328,7 @@ #include #include #include +#include #include #include @@ -3052,7 +3053,7 @@ } #endif FUTURE /*==========================================================================*/ -static void check_datarate(void) +__initfunc(static void check_datarate(void)) { int i=0; @@ -3122,7 +3123,7 @@ } #endif /*==========================================================================*/ -static void ask_mail(void) +__initfunc(static void ask_mail(void)) { int i; @@ -3141,7 +3142,7 @@ msg(DBG_INF,"infobuf =%s\n", msgbuf); } /*==========================================================================*/ -static int check_version(void) +__initfunc(static int check_version(void)) { int i, j, l; int teac_possible=0; @@ -3439,7 +3440,7 @@ /* * probe for the presence of an interface card */ -static int check_card(int port) +__initfunc(static int check_card(int port)) { #undef N_RESPO #define N_RESPO 20 @@ -3543,7 +3544,7 @@ /* * probe for the presence of drives on the selected controller */ -static int check_drives(void) +__initfunc(static int check_drives(void)) { int i, j; @@ -5285,9 +5286,10 @@ * */ #if (SBPCD_ISSUE-1) -static +__initfunc(static void sbpcd_setup(const char *s, int *p)) +#else +__initfunc(void sbpcd_setup(const char *s, int *p)) #endif -void sbpcd_setup(const char *s, int *p) { setup_done++; msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s); @@ -5338,7 +5340,7 @@ * port 0x330, we have to use an offset of 8; so, the real CDROM port * address is 0x338. */ -static int config_spea(void) +__initfunc(static int config_spea(void)) { /* * base address offset between configuration port and CDROM port, @@ -5397,7 +5399,7 @@ #ifdef MODULE int init_module(void) #else -int SBPCD_INIT(void) +__initfunc(int SBPCD_INIT(void)) #endif MODULE { int i=0, j=0; diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c --- v2.1.36/linux/drivers/cdrom/sjcd.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/sjcd.c Mon May 12 10:35:39 1997 @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -159,7 +160,7 @@ * Set up device, i.e., use command line data to set * base address. */ -void sjcd_setup( char *str, int *ints ) +__initfunc(void sjcd_setup( char *str, int *ints )) { if (ints[0] > 0) sjcd_base = ints[1]; @@ -1449,7 +1450,7 @@ * Test for presence of drive and initialize it. Called at boot time. * Probe cdrom, find out version and status. */ -int sjcd_init( void ){ +__initfunc(int sjcd_init( void )){ int i; printk(KERN_INFO "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR, diff -u --recursive --new-file v2.1.36/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c --- v2.1.36/linux/drivers/cdrom/sonycd535.c Fri Apr 4 08:52:18 1997 +++ linux/drivers/cdrom/sonycd535.c Mon May 12 10:35:39 1997 @@ -120,6 +120,7 @@ #include #include #include +#include #define REALLY_SLOW_IO #include @@ -1484,8 +1485,8 @@ /* * Initialize the driver. */ -int -sony535_init(void) +__initfunc(int +sony535_init(void)) { struct s535_sony_drive_config drive_config; Byte cmd_buff[3]; @@ -1649,8 +1650,8 @@ * * the address value has to be the existing CDROM port address. */ -void -sonycd535_setup(char *strings, int *ints) +__initfunc(void +sonycd535_setup(char *strings, int *ints)) { /* if IRQ change and default io base desired, * then call with io base of 0 diff -u --recursive --new-file v2.1.36/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.1.36/linux/drivers/char/Config.in Sun Apr 13 10:18:20 1997 +++ linux/drivers/char/Config.in Mon May 12 10:35:39 1997 @@ -19,7 +19,10 @@ fi bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then - tristate 'Digiboard PC/Xx Support' CONFIG_DIGI + tristate 'Digiboard Intelligent Async Support' CONFIG_DIGIEPCA + if [ "$CONFIG_DIGIEPCA" = "n" ]; then + tristate 'Digiboard PC/Xx Support' CONFIG_DIGI + fi tristate 'Cyclades async mux support' CONFIG_CYCLADES bool 'Stallion multiport serial support' CONFIG_STALDRV if [ "$CONFIG_STALDRV" = "y" ]; then diff -u --recursive --new-file v2.1.36/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.36/linux/drivers/char/Makefile Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/Makefile Mon May 12 10:35:39 1997 @@ -61,6 +61,14 @@ endif endif +ifeq ($(CONFIG_DIGIEPCA),y) +L_OBJS += epca.o +else + ifeq ($(CONFIG_DIGIEPCA),m) + M_OBJS += epca.o + endif +endif + ifeq ($(CONFIG_CYCLADES),y) L_OBJS += cyclades.o else diff -u --recursive --new-file v2.1.36/linux/drivers/char/README.epca linux/drivers/char/README.epca --- v2.1.36/linux/drivers/char/README.epca Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/README.epca Mon May 12 10:35:39 1997 @@ -0,0 +1,506 @@ +user.doc +Digi International driver package for the PC/Xe, PC/Xi, PC/Xr, PC/Xem as well +the EISA and PCI variants of these boards where applicable. +Copyright (C) 1996 Digi International. Written by Ronnie Sanford digilnux@dgii.com + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (At your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not write to the Free Software Foundation, Inc., + 675 Mass Ave, Cambridge, MA 02139, USA. + + +This document describes the software used with the Digi/Linux driver package. +The four user programs listed below are described in this document: + + 1. digiConfig -> Application that configures the Digi driver. + + 2. digiDload -> Application which initializes the Digi hardware. + + 3. buildPCI -> Application which provides the user a method of + building device nodes for PCI devices. + + 4. ditty -> Application which provides the user a method of + configuring terminal options on Digi hardware. + + + +-------------------------------------------------------------------------- +1. Configuring driver/kernel for Digi products +-------------------------------------------------------------------------- + + The Digi driver must be configured each time Digi hardware is added + or removed. There are two supported methods of doing this. The + first method configures the driver dynamically at boot time but requires + the user to utilize the lilo loader. This method is the preffered method + as it does not require the rebuilding of the kernel. In order to use lilo + to configure Digi boards at boot time an appropriate append command should + be added to /etc/lilo.conf below the appropriate label decleration. + See footer 4. The append commands format is a string of comma seperated + identifiers or integers used to configure supported boards. These six + values in order are: + + Enable/Disable this card or Override, + Type of card: PC/Xe (AccelePort) (0), PC/Xeve (1), PC/Xem or PC/Xr (2), + EISA/Xem (3), PC/Xe (64K) (4), PC/Xi (5). + Enable/Disable alternate pin arrangement, + Number of ports on this card, + I/O Port where card is configured (in HEX if using string identifiers), + Base of memory window (in HEX if using string identifiers) + + A sample append command is given below which if used would configure and + enable a PC/Xe with 8 ports, at i/o address 200, memory address 0xd0000 + with alt pin turned off. The lilo.conf file should look like this: + + image = /vmlinuz + root = /dev/hda2 + label = vmlinuz + append="digiepca=E,PC/Xe,D,8,200,D0000" + + likewise the below will perform the same function: + + image = /vmlinuz + root = /dev/hda2 + label = vmlinuz + append="digiepca=1,0,0,8,512,851968" + + Note: + + PCI boards are auto-detected and configured (Hence their codes are + not given here). Do not attempt to configure PCI boards with the lilo + append command. + + If configuration data has been specified by using digiConfig (Described + below), and you wish to override this configuration using lilo without + specifying a specific card (Example if there are PCI cards in the system) + the following override command will accomplish this: + + -> append="digiepca=2" + + If lilo is not enabled, the second method of configuring Digi hardware + will have to be used. digiConfig is an application that can be used + to inform the system of any additions, deletions, or modifications + involving Digi hardware. To use this method the operator executes + digiConfig anytime an EISA or ISA card is added that he wishes to use. + This routine is also used to remove cards from the system, and to modify + parameters of those cards already present in the system. Upon being + executed digiConfig modifies files accessed by the Digi driver. To make + these changes permanent; the operating system must be recompiled. After + the operating system has been recompiled and booted, the changes made with + digiConfig will be introduced to the user. This program MUST be executed + every time Digi EISA/ISA hardware configuration changes. Note, it is not + necessary to execute digiConfig in order to configure the Digi PCI cards. + These cards are self-identifying and will be recognized by the driver. + They cannot be displayed using digiConfig nor will digiConfig build the + device nodes their device nodes. See footer 1. + + To execute digiConfig; simply type: digiConfig + + The application will query you for the type, memory address, port + address, number of ports, alt pin disposition and status of each board + that exist on the system. Note, currently this driver only supports + PC/Xe, PC/Xeve, PC/Xi, PC/Xr, and PC/Xem as well as their EISA and PCI + implementations if applicable. All supported cards (Other than PCI) that + are present should be registered via digiConfig. See footer 2. + + After all cards have been configured select exit. The system will then + inform you if any changes have been made, and ask you if it is okay to + make these changes permanent. If the data entered is correct, select okay. + Selecting cancel will prevent the changes from becoming active. digiConfig + can then be re-executed to configure the system again. + +-------------------------------------------------------------------------- +2. Initializing Digi hardware with digiDload +-------------------------------------------------------------------------- + + digiDload is the application executed after the Digi driver has been + loaded. It is responsible for initializing the hardware and leaving + it in a state such that the Digi board may be operated by the user. + The application may be placed anywhere on the path, but its related + support files must be located in /etc/digi. The related files are: + + sxfep.bin + sxbios.bin + xxfep.bin + xxbios.bin + + The format for this command is "digiDload [v]". If given the "v" + option turns on verbosity. If not given the application runs in quite + mode. To execute the program simply type: + + digiDload + + Upon completion digiDload will generate the below message: + + "digiDload complete: Card initialized" + + At this point the card is configured and ready for normal usage. See + technotes.doc for information on how how ports are determined and + assigned. + +-------------------------------------------------------------------------- +3. Build PCI device nodes with buildPCI +-------------------------------------------------------------------------- + + buildPCI is an application useful for building the necessary device nodes + for Digi PCI cards. It is reccomended that this tool be used because the + current digiConfig application does not provide this function for PCI cards + (Though it does build device nodes for non-PCI cards). To use this program + execute the following:first install the driver, and execute digiDload (See above). After digiDload + has sucessfully loaded, execute the following: + + buildPCI + + Where arg1 is the number of ports connected to Digi cards that are not PCI + (As shown by the digiConfig utility), and arg2 is the number of ports + connected to Digi cards that are PCI. + + Note, buildPCI only has to be ran once to build the necessary device + nodes. Though this program may be executed at anytime, we reccomend + delaying execution until the first time you install the package and after + digiDload has been executed. + +-------------------------------------------------------------------------- +4. Setting Terminal Options with ditty +-------------------------------------------------------------------------- + +ditty is a utility program that sets and displays the terminal options +for Digi intelligent serial products. See man ditty for detailed information. + + +Footnotes: + +1. The 1.2.x kernel does not provide a method of mapping the high + addresses (Normally higher than RAM) associated with PCI. For this + reason, this driver disables PCI support while running under the 1.2.x + kernels. + +2. PCI cards should not and cannot be registered with digiConfig. After + the driver has been loaded buildPCI may be executed to construct the + necessary device nodes. This step is not necessary for system not + having Digi PCI cards. + +3. This is because we forsee a time when buildPCI may auto-detect the + available Digi PCI cards and this would only work if the program is + executed after digiDload. + +4. A complete example is given in install.doc. + +-------------CHANGES-------------------- + +All changes should be recorded here. All changes should be explained in +verbose detail. +----------------------------------------------------------------------- +Programmer : Ronnie Sanford +Date : June 1, 1996 +Description (Verbose) : Initial release of driver package. +Files affected : all +Release version : 1.0.0f (BETA) +----------------------------------------------------------------------- +----------------------------------------------------------------------- +Programmer : Ronnie Sanford +Date : August 7, 1996 +Description (Verbose) : Made several modifications to provide PCI and EISA + support: + + 1. We now allocate the termios structures based on + the maximum number of channels that COULD be + available to the system. We no longer use the + number of channels declared in epcaconfig.h + (NBDEVS) as the total channel number. This is + because this value does not represent channels + available to potential PCI cards. This new + larger value is also passed back to the os in + the num field of tty_driver. + + 2. Added code to copy the previous board structure + (Now called static_boards) into a new local + copy of the boards structure. This has been + done so that PCI cards may be added to this + board array and later referenced (And even + queried.). + + 3. Added code to pc_init that checks for supported + PCI cards. If found this code initializes a new + entry into the drivers local board structure + with the PCI cards address, and type, etc.. It + also bumps the card count (num_cards). + + 4. Modified code in post_fep_init so that when this + routine is executed the number of ports supported + by a particular PCI card will be determined and + loaded into the board structure. It would be + much better if this code was placed in pc_init + (Because we could then report to the os the true + number of ports available; not just the max), but + since the card has to be booted to determine the + number of ports it supports, we are forced to do it + after DIGI_INIT has called post_fep_init. In the + future we may attempt to read the num ports + attached directly (address 0x1ac). + + 5. Added board types to epca.h in support of various + PCI boards (Some of which do not exist yet). + Added procedures for these boards throughout the + code. Note, windowing is not necessary for PCI + boards. + + 6. Added code supporting the EISA/XEM. This included + modifying epca.h with the new board type and + adding this type into the driver. The EISA/XEM + is basically identical to the PC/XEM, other than + it's base address does not have to be (And cannot + be configured directly). + + 7. Modified digiConfig to prompt for EISA/XEM cards. + +Files affected : epca.c, epca.h, digi1.h, digiConfig +Release version : 1.0.0g (BETA) +----------------------------------------------------------------------- +----------------------------------------------------------------------- +Programmer : Ronnie Sanford +Date : August 21, 1996 +Description (Verbose) : Made the following modifications: + + 1. A problem affecting hard flow control was found + in the termios2digi_h routine. Specifically, + when the user activated hard flow control using + the CRTSCTS specification, the values used to + program hard flow control on the board were + incorrect. The solution was to change a line + that read "res |= ((ch->m_dtr) | (ch->m_rts));" + to "res |= ((ch->m_cts) | (ch->m_rts));" This + line only applies if cflag & CRTSCTS. Special + thanks to Matt Robinson (matt@mania.com.au) who + found and fixed this problem. + + 2. In previous betas the cud device was set to CLOCAL + on driver boot up. Likewise the ttyD device was + set to ~CLOCAL. This has been fixed in this driver. + Now ttyD is CLOCAL and cud is ~CLOCAL. The fix + for this can be found in pc_init. + + 3. In ditty.c many changes were made to eliminate bugs + and warning messages. Two ioctl calls were eliminated + as well a problem involving using the returned baud + index to determine the drivers baud rate. Newer + Linux kernels support higher baud rates by using + 0x1000 bit. When the returned value (ored with + 0x1000) was used to reference our fbaud table a + serious memory problem occured. This has been fixed. + + 4. Added a request_region call to post_fep_init. This + should cause the i/o ports being used to be + registered with proc. + + 5. Modified digiConfig to set all cud and ttyD devices + to read/write all permission. + + 6. Developed a new apps called buildPCI that provides + an easy way to build device nodes for PCI cards. + + 7. Modified user.doc and technotes.doc document the + use of buildPCI. + +Files affected : epca.c, ditty.c, digiConfig, user.doc, technotes.doc +Release version : 1.0.0 (Official release) +----------------------------------------------------------------------- +Programmer : Ronnie Sanford +Date : August 21, 1996 +Description (Verbose) : Made the following modifications: + + 1. Removed code from pc_close which closes the + drivers line discipline and restores its original + line discipline. This is currently unecessary, + though future fast cook enhancements may require + this. + + 2. Removed code in block_til_ready that set the + asyncflags to either ASYNC_CALLOUT_ACTIVE, or + ASYNC_NORMAL_ACTIVE. This code was redundant + as it already existed in block_til_ready. + + 3. Added code in block_til_ready to cause a return + prior to schedule being called if the device + was a CALLOUT device. CALLOUT devices never + block on CD. (This was a serious bug that + prevented the CALLOUT devices (ttyD) from + functioning properly in some instances. + + Make a change in the MODEMCHG_IND case of doevent + such that it does not require ASYNC_CALLOUT_ACTIVE + or ASYNC_NORMAL_ACTIVE to be set in order to + unblock an open (Using wait_interruptible). + + Thanks to Mike McLagan (mike.mclagan@linux.org) + for diagnosing and fixing this problem. + + 4. Made changes to the disposition of CLOCAL on + both SERIAL NORMAL and CALLOUT devices. Both + device types now have CLOCAL active at default. + This may be changed with a stty command. + + 5. Made changes to digiConfig such that it checks + major.h (If valid) for the correct major + numbers to use. + +Files affected : epca.c, digiConfig +Release version : 1.0.1a + + +----------------------------------------------------------------------- +Programmer : Ronnie Sanford +Date : September 17, 1996 +Description (Verbose) : Made the following modifications: + + 1. Modified pc_open such that it no longer checks + the cflag value returned by termios2digi_c for + CLOCAL. Digi hardware does not use this value + and thus termios2digi_c rightly screens this + value out. This driver checks for CLOCAL using + the drivers cflag value as known by the Linux OS. + (The value passed into termios2digi_c) + + 2. Modified termios2digi_c to screen out the + CBAUDEX in CBAUD. This error caused parity to + automaticaly be enabled on at higher baud rates. + + + 3. Added the "disable_bh()" call to the shutdown + subroutine. Hopefully this will allow the driver + to correctly clean up after itself when used as a + module. + + 4. Added support for the PC/XI and 64K PC/XE cards. + This involved primarily modifying digiDload to + initialize and boot the new cards; however + driver modifications were also required to + provide the proper windowing for the newly + supported cards. (Code was also added to + determine the memory segment of the XI card as + that card may have more than 64K. Currently + digiDload assumes a 64K XI card.) + + 5. Added subroutine called epca_setup that can be + called during LILO boot up. This provides the + user an easy way to change cards; without + running digiConfig and without recompiling the + kernel. Added code in pc_init and pc_open to + support the epca_setup routine. pc_init checks + the liloconfig flag (Which is set by epca_setup) + to determine if the driver is using the LILO + arguments. If not pc_init loads the board data + found in epcaconfig.h; if so it DOESN'T load + epcaconfig data depending on epca_setup to handle + board configuration. pc_open has been modified + such that it checks to insure that no errors + occured during the LILO boot process. If a + user attempts to boot the driver (via. LILO) + with incorrect data, the open will fail. + + 6. Modified the windowing routines pcxe_rxwinon + and pcxe_txwinon routines. A bug existed such + that those routines checked to see if the rxwin + and txwin flags were reset. If so they assumed + the board was an XI or 64K XE. Furthermore since + these flags were never initialized in our driver + sometimes they were 0 and therefore caused a + memory fault (Or at least a window overrun). This + code has been removed since the pcxe shares + nothing in common with the 64K XI and XE. + + 7. Added code in pc_init to set the memory_seg for + the various boards. This code was necessary to + correct a bug in the PCXE, PCXEVE code where + receive and transmit pointers were being calculated + from an uninitialized variable (memory_seg). + + 8. Modified digiConfig to allow 64K PC/XI and 64K + PC/XE cards to be configured. + + 9. Made changes to support the new 2.1.x development + kernel. In particular this required changing all + references to vremap to ioremap. + + 10. Modified digiConfig such that it now generates + node names corresponding to their internal + as opposed to the label on the port itself. Nodes + (ttyD?? and cud??) now start at 0. Example: + ttyD0 and cud0 represent port 1 on any supported + Digi product. A similar change has been made + in buildPCI.c. + + 12. At the early portion of post_fep_init if a PCI + card is detected a warning message could be given + incorrectly if 64 ports were attached to a PCI + card. The below line : + + epcaassert(bd->numports > 64,"PCI returned a invalid number of ports"); + + was changed to : + + epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); + + Remember that epcaassert checks for NOT true. + Special thanks to Daniel Taylor for fixing this. + + 13. Modified the epcaparam routine. In version 100 + and 101a there was a line that looked like the + below: + + if (ch->omodem != mval) + + The problem with this line was that the first time + through omodem was not initialized. Secondly, since + many TIOC commands did not alter mval (They use + a different variable) changes made by these commands + could be lost. This line was changed to: + + mval ^= ch->modemfake & (mval ^ ch->modem); + + if (ch->omodem ^ mval) + + 14. Modified digiConfig in such a way that it checks + the version number of the kernel and if it finds + a 2.x.x kernel or higher it reads the necessary + major numbers for cud and ttyD devices from major.h. + This was also done in prior versions but these + versions required a #define which identified the + kernel as a version which did not have major numbers + assigned to Digi systems. This #define is no + longer required allowing the same source tree for + multiple kernel releases. + + 15. Used macros to replace kernel specific calls such + as put_fs_long, get_fs_long, put_user, and get_user + the kernel version is now detected and the macro + is defined as to correspond with the kernel it + is being compiled into. Again this was done to + allow one source tree for multiple kernel releases. + + 16. Added support for the new 2.1.x development kernels + to digiInstall. + +Files affected : epca.c, digiConfig +Release version : 1.1.0 +----------------------------------------------------------------------- +Programmer : Daniel Taylor +Date : April 25, 1997 +Description (Verbose) : Updated driver: + 1. Fixed DCD bug. (&tq_scheduler) + 2. Removed BH handler code, as it was only handling + hangups, and not being called for that. + 3. Namespace cleanup (DIGI_TIMER2 => DIGI_TIMER) + 4. Updated to 2.1.36, removed #ifdefs for earlier + kernel revisions. +Files affected : epca.c +Release version : 1.1.1 (BETA) +----------------------------------------------------------------------- diff -u --recursive --new-file v2.1.36/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.1.36/linux/drivers/char/busmouse.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/busmouse.c Mon May 12 10:35:39 1997 @@ -56,7 +56,7 @@ static struct mouse_status mouse; static int mouse_irq = MOUSE_IRQ; -void bmouse_setup(char *str, int *ints) +__initfunc(void bmouse_setup(char *str, int *ints)) { if (ints[0] > 0) mouse_irq=ints[1]; diff -u --recursive --new-file v2.1.36/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.36/linux/drivers/char/console.c Sun Apr 13 10:18:20 1997 +++ linux/drivers/char/console.c Mon May 12 10:35:39 1997 @@ -101,6 +101,7 @@ #include #include #include +#include #ifdef CONFIG_APM #include #endif @@ -1979,7 +1980,7 @@ * Reads the information preserved by setup.s to determine the current display * type and sets everything accordingly. */ -unsigned long con_init(unsigned long kmem_start) +__initfunc(unsigned long con_init(unsigned long kmem_start)) { const char *display_desc = "????"; int currcons = 0; diff -u --recursive --new-file v2.1.36/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c --- v2.1.36/linux/drivers/char/consolemap.c Sun Apr 13 10:18:20 1997 +++ linux/drivers/char/consolemap.c Mon May 12 10:35:39 1997 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "consolemap.h" @@ -483,8 +484,8 @@ * initialized. It must be possible to call kmalloc(..., GFP_KERNEL) * from this function, hence the call from sys_setup. */ -void -console_map_init(void) +__initfunc(void +console_map_init(void)) { con_set_default_unimap(); } diff -u --recursive --new-file v2.1.36/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.1.36/linux/drivers/char/cyclades.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/cyclades.c Mon May 12 10:35:39 1997 @@ -1,5 +1,7 @@ +#define BLOCKMOVE static char rcsid[] = -"$Revision: 1.36.3.9 $$Date: 1996/10/07 19:47:13 $"; +"$Revision: 1.36.4.27 $$Date: 1997/03/26 10:30:00 $"; + /* * linux/drivers/char/cyclades.c * @@ -22,11 +24,128 @@ * This module exports the following rs232 io functions: * int cy_init(void); * int cy_open(struct tty_struct *tty, struct file *filp); + * and the following functions for modularization. + * int init_module(void); + * void cleanup_module(void); * * $Log: cyclades.c,v $ - * Revision 1.36.3.9 1996/10/07 19:47:13 bentson - * add MOD_DEC_USE_COUNT in one return from cy_close (as - * noted by Jon Lewis ) + * Revision 1.36.4.27 1997/03/26 10:30:00 daniel + * Changed for suport linux versions 2.1.X. + * Backward compatible with linux versions 2.0.X. + * Corrected illegal use of filler field in + * CH_CTRL struct. + * Deleted some debug messages. + * + * Revision 1.36.4.26 1997/02/27 12:00:00 daniel + * Included check for NULL tty pointer in cyz_poll. + * + * Revision 1.36.4.25 1997/02/26 16:28:30 bentson + * Bill Foster at Blarg! Online services noticed that + * some of the switch elements of -Z modem control + * lacked a closing "break;" + * + * Revision 1.36.4.24 1997/02/24 11:00:00 daniel + * Changed low water threshold for buffer xmit_buf + * + * Revision 1.36.4.23 1996/12/02 21:50:16 bentson + * Marcio provided fix to modem status fetch for -Z + * + * Revision 1.36.4.22 1996/10/28 22:41:17 bentson + * improve mapping of -Z control page (thanks to Steve + * Price for help on this) + * + * Revision 1.36.4.21 1996/09/10 17:00:10 bentson + * shift from cpu-bound to memcopy in cyz_polling operation + * + * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson + * Added support to set and report higher speeds. + * + * Revision 1.36.4.19c 1996/08/09 10:00:00 Marcio Saito + * Some fixes in the HW flow control for the BETA release. + * Don't try to register the IRQ. + * + * Revision 1.36.4.19 1996/08/08 16:23:18 Bentson + * make sure "cyc" appears in all kernel messages; all soft interrupts + * handled by same routine; recognize out-of-band reception; comment + * out some diagnostic messages; leave RTS/CTS flow control to hardware; + * fix race condition in -Z buffer management; only -Y needs to explictly + * flush chars; tidy up some startup messages; + * + * Revision 1.36.4.18 1996/07/25 18:57:31 bentson + * shift MOD_INC_USE_COUNT location to match + * serial.c; purge some diagnostic messages; + * + * Revision 1.36.4.17 1996/07/25 18:01:08 bentson + * enable modem status messages and fetch & process them; note + * time of last activity type for each port; set_line_char now + * supports more than line 0 and treats 0 baud correctly; + * get_modem_info senses rs_status; + * + * Revision 1.36.4.16 1996/07/20 08:43:15 bentson + * barely works--now's time to turn on + * more features 'til it breaks + * + * Revision 1.36.4.15 1996/07/19 22:30:06 bentson + * check more -Z board status; shorten boot message + * + * Revision 1.36.4.14 1996/07/19 22:20:37 bentson + * fix reference to ch_ctrl in startup; verify return + * values from cyz_issue_cmd and cyz_update_channel; + * more stuff to get modem control correct; + * + * Revision 1.36.4.13 1996/07/11 19:53:33 bentson + * more -Z stuff folded in; re-order changes to put -Z stuff + * after -Y stuff (to make changes clearer) + * + * Revision 1.36.4.12 1996/07/11 15:40:55 bentson + * Add code to poll Cyclom-Z. Add code to get & set RS-232 control. + * Add code to send break. Clear firmware ID word at startup (so + * that other code won't talk to inactive board). + * + * Revision 1.36.4.11 1996/07/09 05:28:29 bentson + * add code for -Z in set_line_char + * + * Revision 1.36.4.10 1996/07/08 19:28:37 bentson + * fold more -Z stuff (or in some cases, error messages) + * into driver; add text to "don't know what to do" messages. + * + * Revision 1.36.4.9 1996/07/08 18:38:38 bentson + * moved compile-time flags near top of file; cosmetic changes + * to narrow text (to allow 2-up printing); changed many declarations + * to "static" to limit external symbols; shuffled code order to + * coalesce -Y and -Z specific code, also to put internal functions + * in order of tty_driver structure; added code to recognize -Z + * ports (and for moment, do nothing or report error); add cy_startup + * to parse boot command line for extra base addresses for ISA probes; + * + * Revision 1.36.4.8 1996/06/25 17:40:19 bentson + * reorder some code, fix types of some vars (int vs. long), + * add cy_setup to support user declared ISA addresses + * + * Revision 1.36.4.7 1996/06/21 23:06:18 bentson + * dump ioctl based firmware load (it's now a user level + * program); ensure uninitialzed ports cannot be used + * + * Revision 1.36.4.6 1996/06/20 23:17:19 bentson + * rename vars and restructure some code + * + * Revision 1.36.4.5 1996/06/14 15:09:44 bentson + * get right status back after boot load + * + * Revision 1.36.4.4 1996/06/13 19:51:44 bentson + * successfully loads firmware + * + * Revision 1.36.4.3 1996/06/13 06:08:33 bentson + * add more of the code for the boot/load ioctls + * + * Revision 1.36.4.2 1996/06/11 21:00:51 bentson + * start to add Z functionality--starting with ioctl + * for loading firmware + * + * Revision 1.36.4.1 1996/06/10 18:03:02 bentson + * added code to recognize Z/PCI card at initialization; report + * presence, but card is not initialized (because firmware needs + * to be loaded) * * Revision 1.36.3.8 1996/06/07 16:29:00 bentson * starting minor number at zero; added missing verify_area @@ -38,7 +157,7 @@ * remove unused diagnostic statements; minor 0 is first; * * Revision 1.36.3.6 1996/03/13 13:21:17 marcio - * The kernel function ioremap (available only in later 1.3.xx kernels) + * The kernel function vremap (available only in later 1.3.xx kernels) * allows the access to memory addresses above the RAM. This revision * of the driver supports PCI boards below 1Mb (device id 0x100) and * above 1Mb (device id 0x101). @@ -261,6 +380,52 @@ * */ +/* If you need to install more boards than NR_CARDS, change the constant + in the definition below. No other change is necessary to support up to + eight boards. Beyond that you'll have to extend cy_isa_addresses. */ + +#define NR_CARDS 4 + +/* + If the total number of ports is larger than NR_PORTS, change this + constant in the definition below. No other change is necessary to + support more boards/ports. */ + +#define NR_PORTS 64 + +#define SERIAL_PARANOIA_CHECK +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_THROTTLE +#undef SERIAL_DEBUG_OTHER +#undef SERIAL_DEBUG_IO +#undef SERIAL_DEBUG_COUNT +#undef SERIAL_DEBUG_DTR +#undef CYCLOM_16Y_HACK +#undef CYCLOM_ENABLE_MONITORING +#undef CY_PCI_DEBUG + + +#if 0 +#define PAUSE __asm__("nop"); +#else +#define PAUSE ; +#endif + +#define cy_min(a,b) (((a)<(b))?(a):(b)) + +#define CHARS_IN_BUF(buf_ctrl) \ + ((buf_ctrl->rx_put - \ + buf_ctrl->rx_get + \ + buf_ctrl->rx_bufsize) % \ + buf_ctrl->rx_bufsize) + +#define SPACE_IN_BUF(buf_ctrl) \ + ((buf_ctrl->tx_get - \ + buf_ctrl->tx_put + \ + buf_ctrl->tx_bufsize - 1) % \ + buf_ctrl->tx_bufsize) + + #include #include @@ -280,7 +445,7 @@ #include #include -#include +#include #include #include @@ -290,24 +455,34 @@ #include #include -#define small_delay(x) for(j=0;j +#if LINUX_VERSION_CODE >= 131328 -#define SERIAL_PARANOIA_CHECK -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_THROTTLE -#undef SERIAL_DEBUG_OTHER -#undef SERIAL_DEBUG_IO -#undef SERIAL_DEBUG_COUNT -#undef SERIAL_DEBUG_DTR -#undef CYCLOM_16Y_HACK -#undef CYCLOM_ENABLE_MONITORING +#include + +#define memcpy_fromfs copy_from_user +#define memcpy_tofs copy_to_user +#define put_fs_long put_user +#define vremap ioremap + +static unsigned long get_fs_long(unsigned long *addr) +{ + unsigned long result = 0; + int error = get_user (result, addr); + if (error) + printk ("cyclades: get_fs_long: error == %d\n", error); + return result; +} + +#endif #ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +#define IS_CYC_Z(card) ((card).num_chips == 1) -#define WAKEUP_CHARS 256 +#define WAKEUP_CHARS (SERIAL_XMIT_SIZE-256) #define STD_COM_FLAGS (0) @@ -325,72 +500,39 @@ static unsigned char *intr_base_addr; -/* This is the address lockup table. The driver will probe for Cyclom-Y/ISA - boards at all addresses in here. If you want the driver to probe addresses - in a different address, add it to this table. - If the driver is probing some other board and causing problems, remove the - address from this table. */ +/* This is the address lookup table. The driver will probe for + Cyclom-Y/ISA boards at all addresses in here. If you want the + driver to probe addresses at a different address, add it to + this table. If the driver is probing some other board and + causing problems, remove the offending address from this table. + The cy_setup function extracts additional addresses from the + boot options line. The form is "cyclades=address,address..." +*/ static unsigned char *cy_isa_addresses[] = { - (unsigned char *) 0xD0000, - (unsigned char *) 0xD2000, - (unsigned char *) 0xD4000, - (unsigned char *) 0xD6000, - (unsigned char *) 0xD8000, - (unsigned char *) 0xDA000, - (unsigned char *) 0xDC000, - (unsigned char *) 0xDE000, + (unsigned char *) 0xD0000, + (unsigned char *) 0xD2000, + (unsigned char *) 0xD4000, + (unsigned char *) 0xD6000, + (unsigned char *) 0xD8000, + (unsigned char *) 0xDA000, + (unsigned char *) 0xDC000, + (unsigned char *) 0xDE000, + 0,0,0,0,0,0,0,0 }; -#define NR_ISA_ADDRESSES (sizeof(cy_isa_addresses)/sizeof(unsigned char *)) +#define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*)) /* This is the per-card data structure containing address, irq, number of - channels, etc. This driver supports a maximum of NR_CARDS cards. If - you need to install more boards, change this constant in the definition - below. No other change is necessary to support more boards. */ - -#define NR_CARDS 4 - + channels, etc. This driver supports a maximum of NR_CARDS cards. +*/ static struct cyclades_card cy_card[NR_CARDS]; /* This is the per-channel data structure containing pointers, flags - and variables for the port. This driver supports a maximum of NR_PORTS. - If the total number of ports is larger than NR_PORTS, change this - constant in the definition below. No other change is necessary to - support more boards/ports. */ - -#define NR_PORTS 64 - + and variables for the port. This driver supports a maximum of NR_PORTS. +*/ static struct cyclades_port cy_port[NR_PORTS]; -/* The Cyclom-Ye has placed the sequential chips in non-sequential - * address order. This look-up table overcomes that problem. - */ -static int cy_chip_offset [] = - { 0x0000, - 0x0400, - 0x0800, - 0x0C00, - 0x0200, - 0x0600, - 0x0A00, - 0x0E00 - }; - -/* PCI related definitions */ - -static unsigned short cy_pci_nboard = 0; -static unsigned short cy_isa_nboard = 0; -static unsigned short cy_nboard = 0; -static unsigned short cy_pci_dev_id[] = { - PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */ - PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */ - 0 /* end of table */ - }; - -int cy_detect_isa(void); -int cy_detect_pci(void); - -static int cy_next_channel = 0; /* next minor available */ +static int cy_next_channel = 0; /* next minor available */ static int serial_refcount; @@ -401,17 +543,18 @@ /* This is the per-irq data structure, it maps an irq to the corresponding card */ -struct cyclades_card *IRQ_cards[16]; +static struct cyclades_card *IRQ_cards[16]; /* * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, + * lock it in case the memcpy_fromfs blocks while swapping in a page, * and some other program tries to do a serial write at the same time. * Since the lock will only come under contention when the system is * swapping and available memory is low, it makes sense to share one * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. + * memory if large numbers of serial ports are open. This buffer is + * allocated when the first cy_open occurs. */ static unsigned char *tmp_buf = 0; static struct semaphore tmp_buf_sem = MUTEX; @@ -420,83 +563,127 @@ * This is used to look up the divisor speeds and the timeouts * We're normally limited to 15 distinct baud rates. The extra * are accessed via settings in info->flags. - * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - * HI VHI + * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + * HI VHI */ static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000, - 0}; + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000, + 0}; static char baud_co[] = { /* 25 MHz clock option table */ - /* value => 00 01 02 03 04 */ - /* divide by 8 32 128 512 2048 */ - 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, - 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + /* value => 00 01 02 03 04 */ + /* divide by 8 32 128 512 2048 */ + 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, + 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static char baud_bpr[] = { /* 25 MHz baud rate period table */ - 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, - 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15}; + 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, + 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15}; static char baud_cor3[] = { /* receive threshold */ - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07}; + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07}; +/* The Cyclom-Ye has placed the sequential chips in non-sequential + * address order. This look-up table overcomes that problem. + */ +static int cy_chip_offset [] = + { 0x0000, + 0x0400, + 0x0800, + 0x0C00, + 0x0200, + 0x0600, + 0x0A00, + 0x0E00 + }; + +/* PCI related definitions */ -static void shutdown(struct cyclades_port *); -static int startup (struct cyclades_port *); -static void cy_throttle(struct tty_struct *); -static void cy_unthrottle(struct tty_struct *); -static void config_setup(struct cyclades_port *); +static unsigned short cy_pci_nboard = 0; +static unsigned short cy_isa_nboard = 0; +static unsigned short cy_nboard = 0; +static unsigned short cy_pci_dev_id[] = { + PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */ + PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */ + PCI_DEVICE_ID_CYCLOM_Z_Lo,/* PCI below 1Mb */ + PCI_DEVICE_ID_CYCLOM_Z_Hi,/* PCI above 1Mb */ + 0 /* end of table */ + }; + + +static void cy_start(struct tty_struct *); +static void set_line_char(struct cyclades_port *); +static void cy_probe(int, void *, struct pt_regs *); +static void cyz_poll(unsigned long); #ifdef CYCLOM_SHOW_STATUS static void show_status(int); #endif +static int cyz_timeron = 0; +static struct timer_list +cyz_timerlist = { + NULL, NULL, 0, 0, cyz_poll +}; + + +/************************************************** +error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long)); +memcpy_tofs (to, from, count); +*************************************************************** +error = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned long *)); +memcpy_fromfs(to, from, count); +**************************************************/ + + static inline int serial_paranoia_check(struct cyclades_port *info, - kdev_t device, const char *routine) + kdev_t device, const char *routine) { #ifdef SERIAL_PARANOIA_CHECK static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; + "cyc Warning: bad magic number for serial struct (%s) in %s\n"; static const char *badinfo = - "Warning: null cyclades_port for (%s) in %s\n"; + "cyc Warning: null cyclades_port for (%s) in %s\n"; static const char *badrange = - "Warning: cyclades_port out of range for (%s) in %s\n"; + "cyc Warning: cyclades_port out of range for (%s) in %s\n"; if (!info) { - printk(badinfo, kdevname(device), routine); - return 1; + printk(badinfo, kdevname(device), routine); + return 1; } if( (long)info < (long)(&cy_port[0]) || (long)(&cy_port[NR_PORTS]) < (long)info ){ - printk(badrange, kdevname(device), routine); - return 1; + printk(badrange, kdevname(device), routine); + return 1; } if (info->magic != CYCLADES_MAGIC) { - printk(badmagic, kdevname(device), routine); - return 1; + printk(badmagic, kdevname(device), routine); + return 1; } #endif - return 0; + return 0; } /* serial_paranoia_check */ + /* The following diagnostic routines allow the driver to spew information on the screen, even (especially!) during interrupts. */ -void +static void SP(char *data){ unsigned long flags; save_flags(flags); cli(); console_print(data); restore_flags(flags); -} -void +}/* SP */ + +static void CP(char data){ unsigned long flags; char scrn[2]; @@ -507,161 +694,312 @@ restore_flags(flags); }/* CP */ -void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */ -void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */ -void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */ -void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */ +static void CP4(int data) + { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP4 */ +static void CP8(int data) + { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */ +static void CP16(int data) + { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */ +static void CP32(long data) + { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */ -/* This routine waits up to 1000 micro-seconds for the previous - command to the Cirrus chip to complete and then issues the - new command. An error is returned if the previous command - didn't finish within the time limit. + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver + * (also known as the "bottom half"). This can be called any + * number of times for any channel without harm. */ -u_short -write_cy_cmd(u_char *base_addr, u_char cmd, int index) +static inline void +cy_sched_event(struct cyclades_port *info, int event) { - unsigned long flags; - volatile int i; - - save_flags(flags); cli(); - /* Check to see that the previous command has completed */ - for(i = 0 ; i < 100 ; i++){ - if (base_addr[CyCCR<event |= 1 << event; /* remember what kind of event and who */ + queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */ + mark_bh(CYCLADES_BH); /* then trigger event */ +} /* cy_sched_event */ - /* Issue the new command */ - base_addr[CyCCR<driver_data; - unsigned char *base_addr; - int chip,channel,index; - unsigned long flags; + struct cyclades_port *info = (struct cyclades_port *) private_; + struct tty_struct *tty; -#ifdef SERIAL_DEBUG_OTHER - printk("cy_stop ttyC%d\n", info->line); /* */ -#endif + tty = info->tty; + if (!tty) + return; - if (serial_paranoia_check(info, tty->device, "cy_stop")) - return; - - cinfo = &cy_card[info->card]; - index = cinfo->bus_index; - channel = info->line - cinfo->first_line; - chip = channel>>2; - channel &= 0x03; - base_addr = (unsigned char*) - (cy_card[info->card].base_addr + (cy_chip_offset[chip]<event)) { + tty_hangup(info->tty); + wake_up_interruptible(&info->open_wait); + info->flags &= ~(ASYNC_NORMAL_ACTIVE| + ASYNC_CALLOUT_ACTIVE); + } + if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { + wake_up_interruptible(&info->open_wait); + } + if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { + if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) + && tty->ldisc.write_wakeup){ + (tty->ldisc.write_wakeup)(tty); + } + wake_up_interruptible(&tty->write_wait); + } +} /* do_softint */ - save_flags(flags); cli(); - base_addr[CyCAR<driver_data; - unsigned char *base_addr; - int chip,channel,index; unsigned long flags; - -#ifdef SERIAL_DEBUG_OTHER - printk("cy_start ttyC%d\n", info->line); /* */ -#endif - - if (serial_paranoia_check(info, tty->device, "cy_start")) - return; - - cinfo = &cy_card[info->card]; - index = cinfo->bus_index; - channel = info->line - cinfo->first_line; - chip = channel>>2; - channel &= 0x03; - base_addr = (unsigned char*) - (cy_card[info->card].base_addr + (cy_chip_offset[chip]<event |= 1 << event; /* remember what kind of event and who */ - queue_task_irq_off(&info->tqueue, &tq_cyclades); /* it belongs to */ - mark_bh(CYCLADES_BH); /* then trigger event */ -} /* cy_sched_event */ - - -static int probe_ready; + int irq_lines = 0; + int i, mask; + + for (i = 0, mask = 1; i < 16; i++, mask <<= 1) { + if (!(mask & dontgrab) + && !request_irq(i, cy_probe, + SA_INTERRUPT, "serial probe", NULL)) { + irq_lines |= mask; + } + } + return irq_lines; +} /* grab_all_interrupts */ /* - * This interrupt routine is used - * while we are probing for submarines. + * Release all interrupts grabbed by grab_all_interrupts */ static void -cy_probe(int irq, void *dev_id, struct pt_regs *regs) +free_all_interrupts(int irq_lines) { - int save_xir, save_car; - int index = 0; /* probing interrupts is only for ISA */ - - if (!probe_ready) { - *(intr_base_addr + (Cy_ClrIntr<= jiffies) + ; + + cy_triggered = 0; /* Reset after letting things settle */ + + timeout = jiffies+10; + while (timeout >= jiffies) + ; + + for (i = 0, mask = 1; i < 16; i++, mask <<= 1) { + if ((cy_triggered & (1 << i)) && + (irq_lines & (1 << i))) { + wild_interrupts |= mask; + } + } + free_all_interrupts(irq_lines); + restore_flags(flags); + return wild_interrupts; +} /* check_wild_interrupts */ + +/* + * This routine is called by do_auto_irq(); it attempts to determine + * which interrupt a serial port is configured to use. It is not + * fool-proof, but it works a large part of the time. + */ +static int +get_auto_irq(unsigned char *address) +{ + unsigned long timeout; + unsigned char *base_addr; + int index; + + index = 0; /* IRQ probing is only for ISA */ + base_addr = address; + intr_base_addr = address; + + /* + * Enable interrupts and see who answers + */ + cy_irq_triggered = 0; + cli(); + base_addr[CyCAR<= jiffies) { + if (cy_irq_triggered) + break; + } + probe_ready = 0; + return(cy_irq_triggered); +} /* get_auto_irq */ + +/* + * Calls get_auto_irq() multiple times, to make sure we don't get + * faked out by random interrupts + */ +static int +do_auto_irq(unsigned char *address) +{ + int irq_lines = 0; + int irq_try_1 = 0, irq_try_2 = 0; + int retries; + unsigned long flags; + + /* Turn on interrupts (they may be off) */ + save_flags(flags); sti(); + + probe_ready = 0; + + cy_wild_int_mask = check_wild_interrupts(); + + irq_lines = grab_all_interrupts(cy_wild_int_mask); + + for (retries = 0; retries < 5; retries++) { + if (!irq_try_1) + irq_try_1 = get_auto_irq(address); + if (!irq_try_2) + irq_try_2 = get_auto_irq(address); + if (irq_try_1 && irq_try_2) { + if (irq_try_1 == irq_try_2) + break; + irq_try_1 = irq_try_2 = 0; + } + } + restore_flags(flags); + free_all_interrupts(irq_lines); + return (irq_try_1 == irq_try_2) ? irq_try_1 : 0; +} /* do_auto_irq */ + + +/* + * This interrupt routine is used + * while we are probing for submarines. + */ +static void +cy_probe(int irq, void *dev_id, struct pt_regs *regs) +{ + int save_xir, save_car; + int index = 0; /* probing interrupts is only for ISA */ + + if (!probe_ready) { + *(intr_base_addr + (Cy_ClrIntr<num_chips ; chip ++) { - base_addr = (unsigned char *) - (cinfo->base_addr + (cy_chip_offset[chip]<base_addr + (cy_chip_offset[chip]<first_line; @@ -746,82 +1084,84 @@ continue; } if (tty->flip.count < TTY_FLIPBUF_SIZE){ - tty->flip.count++; - if (data & info->read_status_mask){ - if(data & CyBREAK){ - *tty->flip.flag_buf_ptr++ = - TTY_BREAK; - *tty->flip.char_buf_ptr++ = - base_addr[CyRDSR<flags & ASYNC_SAK){ - do_SAK(tty); - } - }else if(data & CyFRAME){ - *tty->flip.flag_buf_ptr++ = - TTY_FRAME; - *tty->flip.char_buf_ptr++ = - base_addr[CyRDSR<flip.flag_buf_ptr++ = - TTY_PARITY; - *tty->flip.char_buf_ptr++ = - base_addr[CyRDSR<flip.flag_buf_ptr++ = - TTY_OVERRUN; - *tty->flip.char_buf_ptr++ = 0; - /* If the flip buffer itself is - overflowing, we still loose - the next incoming character. - */ - if(tty->flip.count < TTY_FLIPBUF_SIZE){ - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = - TTY_NORMAL; - *tty->flip.char_buf_ptr++ = - base_addr[CyRDSR<flip.flag_buf_ptr++ = 0; - *tty->flip.char_buf_ptr++ = 0; - } - }else{ - *tty->flip.flag_buf_ptr++ = 0; - *tty->flip.char_buf_ptr++ = 0; - } + tty->flip.count++; + if (data & info->read_status_mask){ + if(data & CyBREAK){ + *tty->flip.flag_buf_ptr++ = + TTY_BREAK; + *tty->flip.char_buf_ptr++ = + base_addr[CyRDSR<flags & ASYNC_SAK){ + do_SAK(tty); + } + }else if(data & CyFRAME){ + *tty->flip.flag_buf_ptr++ = + TTY_FRAME; + *tty->flip.char_buf_ptr++ = + base_addr[CyRDSR<flip.flag_buf_ptr++ = + TTY_PARITY; + *tty->flip.char_buf_ptr++ = + base_addr[CyRDSR<flip.flag_buf_ptr++ = + TTY_OVERRUN; + *tty->flip.char_buf_ptr++ = 0; + /* If the flip buffer itself is + overflowing, we still loose + the next incoming character. + */ + if(tty->flip.count + < TTY_FLIPBUF_SIZE){ + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = + TTY_NORMAL; + *tty->flip.char_buf_ptr++ = + base_addr[CyRDSR<flip.flag_buf_ptr++ = 0; + *tty->flip.char_buf_ptr++ = 0; + } + }else{ + *tty->flip.flag_buf_ptr++ = 0; + *tty->flip.char_buf_ptr++ = 0; + } }else{ - /* there was a software buffer overrun - and nothing could be done about it!!! */ + /* there was a software buffer + overrun and nothing could be + done about it!!! */ } } else { /* normal character reception */ - /* load # characters available from the chip */ + /* load # chars available from the chip */ char_count = base_addr[CyRDCR<mon.int_count; - info->mon.char_count += char_count; - if (char_count > info->mon.char_max) - info->mon.char_max = char_count; - info->mon.char_last = char_count; + ++info->mon.int_count; + info->mon.char_count += char_count; + if (char_count > info->mon.char_max) + info->mon.char_max = char_count; + info->mon.char_last = char_count; #endif while(char_count--){ - if (tty->flip.count >= TTY_FLIPBUF_SIZE){ + if (tty->flip.count >= TTY_FLIPBUF_SIZE){ break; } - tty->flip.count++; + tty->flip.count++; data = base_addr[CyRDSR<flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = data; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = data; #ifdef CYCLOM_16Y_HACK - udelay(10L); + udelay(10L); #endif } } - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + queue_task(&tty->flip.tqueue, &tq_timer); } /* end of service */ base_addr[CyRIR<first_line; save_car = base_addr[CyCAR<xmit_fifo_size; @@ -863,64 +1204,65 @@ info->x_char = 0; } - if (info->x_break){ - /* The Cirrus chip requires the "Embedded Transmit - Commands" of start break, delay, and end break - sequences to be sent. The duration of the - break is given in TICs, which runs at HZ - (typically 100) and the PPR runs at 200 Hz, - so the delay is duration * 200/HZ, and thus a - break can run from 1/100 sec to about 5/4 sec. - */ - base_addr[CyTDR<x_break*200/HZ; - base_addr[CyTDR<x_break = 0; - } + if (info->x_break){ + /* The Cirrus chip requires the "Embedded + Transmit Commands" of start break, delay, + and end break sequences to be sent. The + duration of the break is given in TICs, + which runs at HZ (typically 100) and the + PPR runs at 200 Hz, so the delay is + duration * 200/HZ, and thus a break can + run from 1/100 sec to about 5/4 sec. + */ + base_addr[CyTDR<x_break*200/HZ; + base_addr[CyTDR<x_break = 0; + } while (char_count-- > 0){ if (!info->xmit_cnt){ - base_addr[CySRER<xmit_buf == 0){ - base_addr[CySRER<tty->stopped || info->tty->hw_stopped){ - base_addr[CySRER<xmit_buf == 0){ + base_addr[CySRER<tty->stopped || info->tty->hw_stopped){ + base_addr[CySRER<xmit_buf[info->xmit_tail]; if( outch ){ - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) - & (PAGE_SIZE - 1); - base_addr[CyTDR<xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) + & (PAGE_SIZE - 1); + base_addr[CyTDR< 1){ - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) - & (PAGE_SIZE - 1); - base_addr[CyTDR<xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) + & (PAGE_SIZE - 1); + base_addr[CyTDR<first_line]; + info = &cy_port[channel + chip * 4 + + cinfo->first_line]; info->last_active = jiffies; save_car = base_addr[CyCAR<tty == 0){ /* nowhere to put the data, ignore it */ + if(info->tty == 0){/* no place for data, ignore it*/ ; }else{ if((mdm_change & CyDCD) && (info->flags & ASYNC_CHECK_CD)){ if(mdm_status & CyDCD){ - cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); - }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE) - &&(info->flags & ASYNC_CALLOUT_NOHUP))){ - cy_sched_event(info, Cy_EVENT_HANGUP); + cy_sched_event(info, + Cy_EVENT_OPEN_WAKEUP); + }else if(!((info->flags + & ASYNC_CALLOUT_ACTIVE) + &&(info->flags + & ASYNC_CALLOUT_NOHUP))){ + cy_sched_event(info, + Cy_EVENT_HANGUP); } } if((mdm_change & CyCTS) && (info->flags & ASYNC_CTS_FLOW)){ if(info->tty->hw_stopped){ if(mdm_status & CyCTS){ - /* !!! cy_start isn't used because... */ + /* cy_start isn't used + because... !!! */ info->tty->hw_stopped = 0; - base_addr[CySRER<tty->hw_stopped = 1; - base_addr[CySRER<tty; - if (!tty) - return; +} /* cyy_interrupt */ - if (clear_bit(Cy_EVENT_HANGUP, &info->event)) { - tty_hangup(info->tty); - wake_up_interruptible(&info->open_wait); - info->flags &= ~(ASYNC_NORMAL_ACTIVE| - ASYNC_CALLOUT_ACTIVE); - } - if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { - wake_up_interruptible(&info->open_wait); - } - if (clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } - wake_up_interruptible(&tty->write_wait); - } -} /* do_softint */ +/***********************************************************/ +/********* End of block of Cyclom-Y specific code **********/ +/******** Start of block of Cyclom-Z specific code *********/ +/***********************************************************/ -/* - * Grab all interrupts in preparation for doing an automatic irq - * detection. dontgrab is a mask of irq's _not_ to grab. Returns a - * mask of irq's which were grabbed and should therefore be freed - * using free_all_interrupts(). - */ static int -grab_all_interrupts(int dontgrab) +cyz_fetch_msg( struct cyclades_card *cinfo, + u_long *channel, u_char *cmd, u_long **param) { - int irq_lines = 0; - int i, mask; - - for (i = 0, mask = 1; i < 16; i++, mask <<= 1) { - if (!(mask & dontgrab) - && !request_irq(i, cy_probe, SA_INTERRUPT, "serial probe", NULL)) { - irq_lines |= mask; - } + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + unsigned long loc_doorbell; + + firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + if (firm_id->signature != ZFIRM_ID){ + return (-1); + } + zfw_ctrl = (struct ZFW_CTRL *) + (cinfo->base_addr + firm_id->zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + + loc_doorbell = ((struct RUNTIME_9060 *) + (cinfo->ctl_addr))->loc_doorbell; + if (loc_doorbell){ + *cmd = (char)(0xff & loc_doorbell); + *channel = board_ctrl->fwcmd_channel; + *param = board_ctrl->fwcmd_param; + ((struct RUNTIME_9060 *) + (cinfo->ctl_addr))->loc_doorbell = 0xffffffff; + return 1; } - return irq_lines; -} /* grab_all_interrupts */ + return 0; +} /* cyz_fetch_msg */ -/* - * Release all interrupts grabbed by grab_all_interrupts - */ -static void -free_all_interrupts(int irq_lines) -{ - int i; - - for (i = 0; i < 16; i++) { - if (irq_lines & (1 << i)) - free_irq(i,NULL); - } -} /* free_all_interrupts */ -/* - * This routine returns a bitfield of "wild interrupts". Basically, - * any unclaimed interrupts which is flapping around. - */ static int -check_wild_interrupts(void) +cyz_issue_cmd( struct cyclades_card *cinfo, + u_long channel, u_char cmd, u_long *param) { - int i, mask; - int wild_interrupts = 0; - int irq_lines; - unsigned long timeout; - unsigned long flags; - - /*Turn on interrupts (they may be off) */ - save_flags(flags); sti(); - - irq_lines = grab_all_interrupts(0); - - /* - * Delay for 0.1 seconds -- we use a busy loop since this may - * occur during the bootup sequence - */ - timeout = jiffies+10; - while (timeout >= jiffies) - ; - - cy_triggered = 0; /* Reset after letting things settle */ - - timeout = jiffies+10; - while (timeout >= jiffies) - ; - - for (i = 0, mask = 1; i < 16; i++, mask <<= 1) { - if ((cy_triggered & (1 << i)) && - (irq_lines & (1 << i))) { - wild_interrupts |= mask; - } - } - free_all_interrupts(irq_lines); - restore_flags(flags); - return wild_interrupts; -} /* check_wild_interrupts */ + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + volatile unsigned long *pci_doorbell; + int index; + + firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + if (firm_id->signature != ZFIRM_ID){ + return (-1); + } + zfw_ctrl = (struct ZFW_CTRL *) + (cinfo->base_addr + firm_id->zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + + index = 0; + pci_doorbell = &((struct RUNTIME_9060 *) + (cinfo->ctl_addr))->pci_doorbell; + while( (*pci_doorbell & 0xff) != 0){ + if (index++ == 100){ + return(-1); + } + udelay(50L); + } + board_ctrl->hcmd_channel = channel; + board_ctrl->hcmd_param = param; + *pci_doorbell = (long)cmd; -/* - * This routine is called by do_auto_irq(); it attempts to determine - * which interrupt a serial port is configured to use. It is not - * fool-proof, but it works a large part of the time. - */ -static int -get_auto_irq(unsigned char *address) -{ - unsigned long timeout; - unsigned char *base_addr; - int index; + return(0); +} /* cyz_issue_cmd */ - index = 0; /* IRQ probing is only for ISA */ - base_addr = address; - intr_base_addr = address; - - /* - * Enable interrupts and see who answers - */ - cy_irq_triggered = 0; - cli(); - base_addr[CyCAR<= jiffies) { - if (cy_irq_triggered) - break; - } - probe_ready = 0; - return(cy_irq_triggered); -} /* get_auto_irq */ -/* - * Calls get_auto_irq() multiple times, to make sure we don't get - * faked out by random interrupts - */ static int -do_auto_irq(unsigned char *address) -{ - int irq_lines = 0; - int irq_try_1 = 0, irq_try_2 = 0; - int retries; - unsigned long flags; +cyz_update_channel( struct cyclades_card *cinfo, + u_long channel, u_char mode, u_char cmd) +{ + struct FIRM_ID *firm_id = + (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); + struct ZFW_CTRL *zfw_ctrl; + struct CH_CTRL *ch_ctrl; + + if (firm_id->signature != ZFIRM_ID){ + return (-1); + } + zfw_ctrl = + (struct ZFW_CTRL *)(cinfo->base_addr + firm_id->zfwctrl_addr); + ch_ctrl = zfw_ctrl->ch_ctrl; - /* Turn on interrupts (they may be off) */ - save_flags(flags); sti(); + ch_ctrl[channel].op_mode = (long)mode; - probe_ready = 0; - - cy_wild_int_mask = check_wild_interrupts(); + return cyz_issue_cmd(cinfo, channel, cmd, 0L); - irq_lines = grab_all_interrupts(cy_wild_int_mask); - - for (retries = 0; retries < 5; retries++) { - if (!irq_try_1) - irq_try_1 = get_auto_irq(address); - if (!irq_try_2) - irq_try_2 = get_auto_irq(address); - if (irq_try_1 && irq_try_2) { - if (irq_try_1 == irq_try_2) - break; - irq_try_1 = irq_try_2 = 0; - } - } - restore_flags(flags); - free_all_interrupts(irq_lines); - return (irq_try_1 == irq_try_2) ? irq_try_1 : 0; -} /* do_auto_irq */ +} /* cyz_update_channel */ -/* This is called whenever a port becomes active; - interrupts are enabled and DTR & RTS are turned on. - */ -static int -startup(struct cyclades_port * info) +static void +cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - unsigned long flags; - unsigned char *base_addr; - int card,chip,channel,index; +} /* cyz_interrupt */ - if (info->flags & ASYNC_INITIALIZED){ - return 0; - } - if (!info->type){ - if (info->tty){ - set_bit(TTY_IO_ERROR, &info->tty->flags); - } - return 0; - } - if (!info->xmit_buf){ - info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL); - if (!info->xmit_buf){ - return -ENOMEM; +static void +cyz_poll(unsigned long arg) +{ + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + struct CH_CTRL *ch_ctrl; + struct BUF_CTRL *buf_ctrl; + struct cyclades_card *cinfo; + struct cyclades_port *info; + struct tty_struct *tty; + int card, port; + int char_count, small_count; + char data; + u_long channel; + u_char cmd; + u_long *param; + + cyz_timerlist.expires = jiffies + 100; + + for (card = 0 ; card < NR_CARDS ; card++){ + cinfo = &cy_card[card]; + if (!IS_CYC_Z(*cinfo)) continue; + + firm_id = (struct FIRM_ID *) + (cinfo->base_addr + ID_ADDRESS); + if (firm_id->signature != ZFIRM_ID){ + continue; } - } - - config_setup(info); + + zfw_ctrl = + (struct ZFW_CTRL *) + (cinfo->base_addr + firm_id->zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + + while( cyz_fetch_msg( cinfo, &channel, &cmd, ¶m) == 1){ + char_count = 0; + info = &cy_port[ channel + cinfo->first_line ]; + if((tty = info->tty) == 0) continue; + ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); + buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); + info->jiffies[0] = jiffies; + + switch(cmd){ + case C_CM_PR_ERROR: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + *tty->flip.char_buf_ptr++ = 0; + char_count++; + break; + case C_CM_FR_ERROR: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + *tty->flip.char_buf_ptr++ = 0; + char_count++; + break; + case C_CM_RXBRK: + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + *tty->flip.char_buf_ptr++ = 0; + char_count++; + break; + case C_CM_MDCD: + if (info->flags & ASYNC_CHECK_CD){ + if( ch_ctrl[channel].rs_status & C_RS_DCD){ + /* SP("Open Wakeup\n"); */ + cy_sched_event(info, + Cy_EVENT_OPEN_WAKEUP); + }else if(!((info->flags + & ASYNC_CALLOUT_ACTIVE) + &&(info->flags + & ASYNC_CALLOUT_NOHUP))){ + /* SP("Hangup\n"); */ + cy_sched_event(info, + Cy_EVENT_HANGUP); + } + } + break; + case C_CM_MCTS: + if (info->flags & ASYNC_CTS_FLOW) { + if(info->tty->hw_stopped){ + if( ch_ctrl[channel].rs_status & C_RS_DCD){ + /* cy_start isn't used because... + HW flow is handled by the board */ + /* SP("Write Wakeup\n"); */ + cy_sched_event(info, + Cy_EVENT_WRITE_WAKEUP); + } + }else{ + if(!(ch_ctrl[channel].rs_status & C_RS_CTS)){ + /* cy_stop isn't used because + HW flow is handled by the board */ + /* SP("Write stop\n"); */ + } + } + } + break; + case C_CM_MRI: + break; + case C_CM_MDSR: + break; + case C_CM_FATAL: + /* should do something with this !!! */ + break; + } + if(char_count){ + queue_task(&tty->flip.tqueue, &tq_timer); + } + } + + for (port = 0; port < board_ctrl->n_channel; port++){ + info = &cy_port[ port + cinfo->first_line ]; + tty = info->tty; + ch_ctrl = &(zfw_ctrl->ch_ctrl[port]); + buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); + + if ((char_count = CHARS_IN_BUF(buf_ctrl))){ + info->last_active = jiffies; + info->jiffies[1] = jiffies; + +#ifdef CYCLOM_ENABLE_MONITORING + info->mon.int_count++; + info->mon.char_count += char_count; + if (char_count > info->mon.char_max) + info->mon.char_max = char_count; + info->mon.char_last = char_count; +#endif + if( tty == 0){ + /* flush received characters */ + buf_ctrl->rx_get = + (buf_ctrl->rx_get + char_count) + % buf_ctrl->rx_bufsize; + /* SP("-"); */ + info->rflush_count++; + }else{ +#ifdef BLOCKMOVE + /* we'd like to use memcpy(t, f, n) and memset(s, c, count) + for performance, but because of buffer boundaries, there + may be several steps to the operation */ + while(0 < (small_count + = cy_min( (buf_ctrl->rx_bufsize - buf_ctrl->rx_get), + cy_min( (TTY_FLIPBUF_SIZE - tty->flip.count), + char_count)))){ + memcpy(tty->flip.char_buf_ptr, + (char *)(cinfo->base_addr + + buf_ctrl->rx_bufaddr + + buf_ctrl->rx_get), + small_count); + tty->flip.char_buf_ptr += small_count; + memset(tty->flip.flag_buf_ptr, + TTY_NORMAL, + small_count); + tty->flip.flag_buf_ptr += small_count; + buf_ctrl->rx_get = + (buf_ctrl->rx_get + small_count) + % buf_ctrl->rx_bufsize; + char_count -= small_count; + tty->flip.count += small_count; + } +#else + while(char_count--){ + if (tty->flip.count >= TTY_FLIPBUF_SIZE){ + break; + } + data = *(char *) (cinfo->base_addr + + buf_ctrl->rx_bufaddr + + buf_ctrl->rx_get); + buf_ctrl->rx_get = + (buf_ctrl->rx_get + 1) + % buf_ctrl->rx_bufsize; + + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + *tty->flip.char_buf_ptr++ = data; + } +#endif + queue_task(&tty->flip.tqueue, &tq_timer); + } + } + + if ((char_count = SPACE_IN_BUF(buf_ctrl))){ + if( tty == 0){ + goto ztxdone; + } + + if(info->x_char) { /* send special char */ + data = info->x_char; + + *(char *) (cinfo->base_addr + + buf_ctrl->tx_bufaddr + + buf_ctrl->tx_put) = data; + buf_ctrl->tx_put = + (buf_ctrl->tx_put + 1) + % buf_ctrl->tx_bufsize; + info->x_char = 0; + char_count--; + info->last_active = jiffies; + info->jiffies[2] = jiffies; + } + if (info->x_break){ + printk("cyc cyz_poll shouldn't see x_break\n"); + info->x_break = 0; + info->last_active = jiffies; + info->jiffies[2] = jiffies; + } +#ifdef BLOCKMOVE + while(0 < (small_count + = cy_min( (buf_ctrl->tx_bufsize - buf_ctrl->tx_put), + cy_min ( (PAGE_SIZE - info->xmit_tail), + cy_min( info->xmit_cnt, char_count))))){ + memcpy((char *)(cinfo->base_addr + + buf_ctrl->tx_bufaddr + + buf_ctrl->tx_put), + &info->xmit_buf[info->xmit_tail], + small_count); + buf_ctrl->tx_put = + (buf_ctrl->tx_put + small_count) + % buf_ctrl->tx_bufsize; + char_count -= small_count; + info->xmit_cnt -= small_count; + info->xmit_tail = + (info->xmit_tail + small_count) & (PAGE_SIZE - 1); + info->last_active = jiffies; + info->jiffies[2] = jiffies; + } +#else + while (info->xmit_cnt && char_count){ + data = info->xmit_buf[info->xmit_tail]; + info->xmit_cnt--; + info->xmit_tail = + (info->xmit_tail + 1) & (PAGE_SIZE - 1); + + *(char *) (cinfo->base_addr + + buf_ctrl->tx_bufaddr + + buf_ctrl->tx_put) = data; + buf_ctrl->tx_put = + (buf_ctrl->tx_put + 1) + % buf_ctrl->tx_bufsize; + char_count--; + info->last_active = jiffies; + info->jiffies[2] = jiffies; + } +#endif + ztxdone: + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + } + } + + /* poll every 40 ms */ + cyz_timerlist.expires = jiffies + 4; + } + add_timer(&cyz_timerlist); + + return; +} /* cyz_poll */ + + +/********** End of block of Cyclom-Z specific code *********/ +/***********************************************************/ + + +/* This is called whenever a port becomes active; + interrupts are enabled and DTR & RTS are turned on. + */ +static int +startup(struct cyclades_port * info) +{ + unsigned long flags; + unsigned char *base_addr; + int card,chip,channel,index; + + if (info->flags & ASYNC_INITIALIZED){ + return 0; + } + + if (!info->type){ + if (info->tty){ + set_bit(TTY_IO_ERROR, &info->tty->flags); + } + return 0; + } + if (!info->xmit_buf){ + info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL); + if (!info->xmit_buf){ + return -ENOMEM; + } + } + + set_line_char(info); card = info->card; channel = (info->line) - (cy_card[card].first_line); - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) (cy_card[card].base_addr + (cy_chip_offset[chip]<default_timeout + ? info->default_timeout + : 0x02); /* 10ms rx timeout */ + + cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index); + + base_addr[CyCAR<default_timeout - ? info->default_timeout - : 0x02); /* 10ms rx timeout */ +#ifdef SERIAL_DEBUG_DTR + printk("cyc:startup raising DTR\n"); + printk(" status: 0x%x, 0x%x\n", + base_addr[CyMSVR1<flags |= ASYNC_INITIALIZED; + + if (info->tty){ + clear_bit(TTY_IO_ERROR, &info->tty->flags); + } + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + } else { + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + struct CH_CTRL *ch_ctrl; + int retval; + + base_addr = (unsigned char*) (cy_card[card].base_addr); + + firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); + if (firm_id->signature != ZFIRM_ID){ + return -ENODEV; + } - write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index); + zfw_ctrl = + (struct ZFW_CTRL *) + (cy_card[card].base_addr + firm_id->zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + +#ifdef SERIAL_DEBUG_OPEN + printk("cyc startup Z card %d, channel %d, base_addr %lx\n", + card, channel, (long)base_addr);/**/ +#endif - base_addr[CyCAR<card], + channel, C_CM_IOCTLM, 0L); + if (retval != 0){ + printk("cyc:startup(2) retval was %x\n", retval); + } #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: raising DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<flags |= ASYNC_INITIALIZED; + /* enable send, recv, modem !!! */ + info->flags |= ASYNC_INITIALIZED; if (info->tty){ clear_bit(TTY_IO_ERROR, &info->tty->flags); } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - restore_flags(flags); + } #ifdef SERIAL_DEBUG_OPEN - printk(" done\n"); + printk(" cyc startup done\n"); #endif - return 0; + return 0; } /* startup */ -void + +static void start_xmit( struct cyclades_port *info ) { unsigned long flags; @@ -1291,18 +1856,24 @@ card = info->card; channel = (info->line) - (cy_card[card].first_line); - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<flags & ASYNC_INITIALIZED)){ - return; + return; } card = info->card; channel = info->line - cy_card[card].first_line; - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<xmit_buf){ + unsigned char * temp; + temp = info->xmit_buf; + info->xmit_buf = 0; + free_page((unsigned long) temp); + } + + base_addr[CyCAR<tty || (info->tty->termios->c_cflag & HUPCL)) { + base_addr[CyMSVR1<tty){ + set_bit(TTY_IO_ERROR, &info->tty->flags); + } + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); + } else { + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + struct CH_CTRL *ch_ctrl; + int retval; + base_addr = (unsigned char*) (cy_card[card].base_addr); #ifdef SERIAL_DEBUG_OPEN - printk("shutdown card %d, chip %d, channel %d, base_addr %lx\n", - card, chip, channel, (long)base_addr); + printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n", + card, channel, (long)base_addr); #endif - /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE - SENT BEFORE DROPPING THE LINE !!! (Perhaps - set some flag that is read when XMTY happens.) - Other choices are to delay some fixed interval - or schedule some later processing. + firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); + if (firm_id->signature != ZFIRM_ID){ + return; + } + + zfw_ctrl = + (struct ZFW_CTRL *) + (cy_card[card].base_addr + firm_id->zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + + save_flags(flags); cli(); + if (info->xmit_buf){ + unsigned char * temp; + temp = info->xmit_buf; + info->xmit_buf = 0; + free_page((unsigned long) temp); + } + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + ch_ctrl[channel].rs_control &= + ~(C_RS_RTS | C_RS_DTR ); + retval = cyz_issue_cmd(&cy_card[info->card], + channel, C_CM_IOCTLM, 0L); + if (retval != 0){ + printk("cyc:shutdown retval was %x\n", + retval); + } +#ifdef SERIAL_DEBUG_DTR + printk("cyc:shutdown dropping Z DTR\n"); +#endif + } + + if (info->tty){ + set_bit(TTY_IO_ERROR, &info->tty->flags); + } + info->flags &= ~ASYNC_INITIALIZED; + + restore_flags(flags); + } + +#ifdef SERIAL_DEBUG_OPEN + printk(" cyc shutdown done\n"); +#endif + return; +} /* shutdown */ + + +/* + * ------------------------------------------------------------ + * cy_open() and friends + * ------------------------------------------------------------ + */ + +static int +block_til_ready(struct tty_struct *tty, struct file * filp, + struct cyclades_port *info) +{ + struct wait_queue wait = { current, NULL }; + struct cyclades_card *cinfo; + unsigned long flags; + int chip, channel,index; + int retval; + char *base_addr; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. */ - save_flags(flags); cli(); - if (info->xmit_buf){ - unsigned char * temp; - temp = info->xmit_buf; - info->xmit_buf = 0; - free_page((unsigned long) temp); + if (info->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&info->close_wait); + if (info->flags & ASYNC_HUP_NOTIFY){ + return -EAGAIN; + }else{ + return -ERESTARTSYS; + } + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE){ + return -EBUSY; + } + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)){ + return -EBUSY; + } + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)){ + return -EBUSY; + } + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if (filp->f_flags & O_NONBLOCK) { + if (info->flags & ASYNC_CALLOUT_ACTIVE){ + return -EBUSY; + } + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * cy_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("cyc block_til_ready before block: ttyC%d, count = %d\n", + info->line, info->count);/**/ +#endif + info->count--; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc block_til_ready: (%d): decrementing count to %d\n", + current->pid, info->count); +#endif + info->blocked_open++; + + cinfo = &cy_card[info->card]; + channel = info->line - cinfo->first_line; + if (!IS_CYC_Z(*cinfo)) { + chip = channel>>2; + channel &= 0x03; + index = cinfo->bus_index; + base_addr = (char *)(cinfo->base_addr + + (cy_chip_offset[chip]<flags & ASYNC_CALLOUT_ACTIVE)){ + base_addr[CyCAR<state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) + || !(info->flags & ASYNC_INITIALIZED) ){ + if (info->flags & ASYNC_HUP_NOTIFY) { + retval = -EAGAIN; + }else{ + retval = -ERESTARTSYS; + } + break; + } + save_flags(flags); cli(); + base_addr[CyCAR<flags & ASYNC_CALLOUT_ACTIVE) + && !(info->flags & ASYNC_CLOSING) + && (C_CLOCAL(tty) + || (base_addr[CyMSVR1<signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("cyc block_til_ready blocking: ttyC%d, count = %d\n", + info->line, info->count);/**/ +#endif + schedule(); + } + } else { + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + struct CH_CTRL *ch_ctrl; + int retval; + + base_addr = (char *)(cinfo->base_addr); + firm_id = (struct FIRM_ID *) + (base_addr + ID_ADDRESS); + if (firm_id->signature != ZFIRM_ID){ + return -EINVAL; } - base_addr[CyCAR<tty || (info->tty->termios->c_cflag & HUPCL)) { - base_addr[CyMSVR1<zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + + while (1) { + ch_ctrl[channel].rs_control |= + C_RS_RTS | C_RS_DTR ; + retval = cyz_issue_cmd(&cy_card[info->card], + channel, C_CM_IOCTLM, 0L); + if (retval != 0){ + printk("cyc:block_til_ready retval was %x\n", retval); + } #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: dropping DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) + || !(info->flags & ASYNC_INITIALIZED) ){ + if (info->flags & ASYNC_HUP_NOTIFY) { + retval = -EAGAIN; + }else{ + retval = -ERESTARTSYS; + } + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) + && !(info->flags & ASYNC_CLOSING) + && (C_CLOCAL(tty) + || (ch_ctrl[channel].rs_status & C_RS_DCD))) { + break; + } + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("cyc block_til_ready blocking: ttyC%d, count = %d\n", + info->line, info->count);/**/ +#endif + schedule(); + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)){ + info->count++; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc:block_til_ready (%d): incrementing count to %d\n", + current->pid, info->count); +#endif + } + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n", + info->line, info->count);/**/ +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} /* block_til_ready */ + + +/* + * This routine is called whenever a serial port is opened. It + * performs the serial-specific initialization for the tty structure. + */ +int +cy_open(struct tty_struct *tty, struct file * filp) +{ + struct cyclades_port *info; + int retval, line; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (NR_PORTS <= line)){ + return -ENODEV; + } + info = &cy_port[line]; + if (info->line < 0){ + return -ENODEV; + } + + /* If the card's firmware hasn't been loaded, + treat it as absent from the system. This + will make the user pay attention. + */ + if (IS_CYC_Z(cy_card[info->card])) { + struct FIRM_ID *firm_id = + (struct FIRM_ID *) + (cy_card[info->card].base_addr + ID_ADDRESS); + if (firm_id->signature != ZFIRM_ID){ + printk("Cyclom-Z firmware not yet loaded\n"); + return -ENODEV; + } + } +#ifdef SERIAL_DEBUG_OTHER + printk("cyc:cy_open ttyC%d\n", info->line); /* */ +#endif + if (serial_paranoia_check(info, tty->device, "cy_open")){ + return -ENODEV; + } +#ifdef SERIAL_DEBUG_OPEN + printk("cyc:cy_open ttyC%d, count = %d\n", + info->line, info->count);/**/ +#endif + info->count++; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc:cy_open (%d): incrementing count to %d\n", + current->pid, info->count); +#endif + tty->driver_data = info; + info->tty = tty; + + /* Some drivers have (incorrect/incomplete) code to test + against a race condition. Should add good code here!!! */ + if (!tmp_buf) { + tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL); + if (!tmp_buf){ + return -ENOMEM; + } + } + + if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + } + /* + * Start up serial port + */ + retval = startup(info); + if (retval){ + return retval; + } + + MOD_INC_USE_COUNT; + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("cyc:cy_open returning after block_til_ready with %d\n", + retval); #endif - } - write_cy_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index); - /* it may be appropriate to clear _XMIT at - some later date (after testing)!!! */ + return retval; + } - if (info->tty){ - set_bit(TTY_IO_ERROR, &info->tty->flags); - } - info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + info->session = current->session; + info->pgrp = current->pgrp; #ifdef SERIAL_DEBUG_OPEN - printk(" done\n"); + printk(" cyc:cy_open done\n");/**/ #endif - return; -} /* shutdown */ + return 0; +} /* cy_open */ + /* - * This routine finds or computes the various line characteristics. + * This routine is called when a particular tty device is closed. */ static void -config_setup(struct cyclades_port * info) +cy_close(struct tty_struct * tty, struct file * filp) { + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; unsigned long flags; - unsigned char *base_addr; - int card,chip,channel,index; - unsigned cflag; - int i; - if (!info->tty || !info->tty->termios){ +#ifdef SERIAL_DEBUG_OTHER + printk("cyc:cy_close ttyC%d\n", info->line); +#endif + + if (!info + || serial_paranoia_check(info, tty->device, "cy_close")){ return; } - if (info->line == -1){ +#ifdef SERIAL_DEBUG_OPEN + printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count); +#endif + + save_flags(flags); cli(); + + /* If the TTY is being hung up, nothing to do */ + if (tty_hung_up_p(filp)) { + restore_flags(flags); return; } - cflag = info->tty->termios->c_cflag; - - /* baud rate */ - i = cflag & CBAUD; -#ifdef CBAUDEX -/* Starting with kernel 1.1.65, there is direct support for - higher baud rates. The following code supports those - changes. The conditional aspect allows this driver to be - used for earlier as well as later kernel versions. (The - mapping is slightly different from serial.c because there - is still the possibility of supporting 75 kbit/sec with - the Cyclades board.) - */ - if (i & CBAUDEX) { - if (i == B57600) - i = 16; - else if(i == B115200) - i = 18; -#ifdef B78600 - else if(i == B78600) - i = 17; -#endif - else - info->tty->termios->c_cflag &= ~CBAUDEX; + + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("cyc:cy_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; } +#ifdef SERIAL_DEBUG_COUNT + printk("cyc:cy_close at (%d): decrementing count to %d\n", + current->pid, info->count - 1); #endif - if (i == 15) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - i += 1; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - i += 3; - } - info->tbpr = baud_bpr[i]; /* Tx BPR */ - info->tco = baud_co[i]; /* Tx CO */ - info->rbpr = baud_bpr[i]; /* Rx BPR */ - info->rco = baud_co[i]; /* Rx CO */ - if (baud_table[i] == 134) { - info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; - /* get it right for 134.5 baud */ - } else if (baud_table[i]) { - info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2; - /* this needs to be propagated into the card info */ - } else { - info->timeout = 0; + if (--info->count < 0) { +#ifdef SERIAL_DEBUG_COUNT + printk("cyc:cyc_close setting count to 0\n"); +#endif + info->count = 0; } - /* By tradition (is it a standard?) a baud rate of zero - implies the line should be/has been closed. A bit - later in this routine such a test is performed. */ - - /* byte size and parity */ - info->cor5 = 0; - info->cor4 = 0; - info->cor3 = (info->default_threshold - ? info->default_threshold - : baud_cor3[i]); /* receive threshold */ - info->cor2 = CyETC; - switch(cflag & CSIZE){ - case CS5: - info->cor1 = Cy_5_BITS; - break; - case CS6: - info->cor1 = Cy_6_BITS; - break; - case CS7: - info->cor1 = Cy_7_BITS; - break; - case CS8: - info->cor1 = Cy_8_BITS; - break; - } - if(cflag & CSTOPB){ - info->cor1 |= Cy_2_STOP; - } - if (cflag & PARENB){ - if (cflag & PARODD){ - info->cor1 |= CyPARITY_O; - }else{ - info->cor1 |= CyPARITY_E; - } - }else{ - info->cor1 |= CyPARITY_NONE; + if (info->count) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; } - - /* CTS flow control flag */ - if (cflag & CRTSCTS){ - info->flags |= ASYNC_CTS_FLOW; - info->cor2 |= CyCtsAE; - }else{ - info->flags &= ~ASYNC_CTS_FLOW; - info->cor2 &= ~CyCtsAE; + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + if (info->flags & ASYNC_INITIALIZED) + tty_wait_until_sent(tty, 5*HZ); /* 5 seconds timeout */ + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + info->close_delay; + schedule(); + } + wake_up_interruptible(&info->open_wait); } - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else - info->flags |= ASYNC_CHECK_CD; - - /*********************************************** - The hardware option, CyRtsAO, presents RTS when - the chip has characters to send. Since most modems - use RTS as reverse (inbound) flow control, this - option is not used. If inbound flow control is - necessary, DTR can be programmed to provide the - appropriate signals for use with a non-standard - cable. Contact Marcio Saito for details. - ***********************************************/ - - card = info->card; - channel = (info->line) - (cy_card[card].first_line); - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); - /* tx and rx baud rate */ +#ifdef SERIAL_DEBUG_OTHER + printk(" cyc:cy_close done\n"); +#endif - base_addr[CyTCOR<tco; - base_addr[CyTBPR<tbpr; - base_addr[CyRCOR<rco; - base_addr[CyRBPR<rbpr; + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; +} /* cy_close */ - /* set line characteristics according configuration */ - base_addr[CySCHR1<tty); - base_addr[CySCHR2<tty); - base_addr[CyCOR1<cor1; - base_addr[CyCOR2<cor2; - base_addr[CyCOR3<cor3; - base_addr[CyCOR4<cor4; - base_addr[CyCOR5<cor5; +/* This routine gets called when tty_write has put something into + * the write_queue. The characters may come from user space or + * kernel space. + * + * This routine will return the number of characters actually + * accepted for writing. + * + * If the port is not already transmitting stuff, start it off by + * enabling interrupts. The interrupt service routine will then + * ensure that the characters are sent. + * If the port is already active, there is no need to kick it. + * + */ +static int +cy_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + int c, total = 0; - write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index); +#ifdef SERIAL_DEBUG_IO + printk("cyc:cy_write ttyC%d\n", info->line); /* */ +#endif - base_addr[CyCAR<device, "cy_write")){ + return 0; + } + + if (!tty || !info->xmit_buf || !tmp_buf){ + return 0; + } - base_addr[CyRTPR<default_timeout - ? info->default_timeout - : 0x02); /* 10ms rx timeout */ - - if (C_CLOCAL(info->tty)) { - base_addr[CySRER<0 modem transitions */ - base_addr[CyMCOR1<1 modem transitions */ - base_addr[CyMCOR2<0 modem transitions */ - base_addr[CyMCOR1<1 modem transitions */ - base_addr[CyMCOR2<xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0){ + restore_flags(flags); + break; + } - if(i == 0){ /* baud rate is zero, turn off line */ - base_addr[CyMSVR2<xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + } else + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; +#if 0 + SP("CW"); + CP16(c); + SP(" "); #endif - } - - if (info->tty){ - clear_bit(TTY_IO_ERROR, &info->tty->flags); - } + } + if (from_user) + up(&tmp_buf_sem); - restore_flags(flags); -} /* config_setup */ + if (info->xmit_cnt + && !tty->stopped + && !tty->hw_stopped ) { + start_xmit(info); + } + return total; +} /* cy_write */ +/* + * This routine is called by the kernel to write a single + * character to the tty device. If the kernel uses this routine, + * it must call the flush_chars() routine (if defined) when it is + * done stuffing characters into the driver. If there is no room + * in the queue, the character is ignored. + */ static void cy_put_char(struct tty_struct *tty, unsigned char ch) { @@ -1574,28 +2493,35 @@ unsigned long flags; #ifdef SERIAL_DEBUG_IO - printk("cy_put_char ttyC%d\n", info->line); + printk("cyc:cy_put_char ttyC%d\n", info->line); #endif if (serial_paranoia_check(info, tty->device, "cy_put_char")) - return; + return; if (!tty || !info->xmit_buf) - return; + return; save_flags(flags); cli(); - if (info->xmit_cnt >= PAGE_SIZE - 1) { - restore_flags(flags); - return; - } + if (info->xmit_cnt >= PAGE_SIZE - 1) { + restore_flags(flags); + return; + } - info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= PAGE_SIZE - 1; - info->xmit_cnt++; + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= PAGE_SIZE - 1; + info->xmit_cnt++; restore_flags(flags); +#if 0 + SP("+"); +#endif } /* cy_put_char */ +/* + * This routine is called by the kernel after it has written a + * series of characters to the tty device using put_char(). + */ static void cy_flush_chars(struct tty_struct *tty) { @@ -1603,110 +2529,60 @@ unsigned long flags; unsigned char *base_addr; int card,chip,channel,index; - + #ifdef SERIAL_DEBUG_IO - printk("cy_flush_chars ttyC%d\n", info->line); /* */ + printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */ #endif if (serial_paranoia_check(info, tty->device, "cy_flush_chars")) - return; + return; if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf) - return; + return; card = info->card; channel = info->line - cy_card[card].first_line; - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<driver_data; - unsigned long flags; - int c, total = 0; - -#ifdef SERIAL_DEBUG_IO - printk("cy_write ttyC%d\n", info->line); /* */ -#endif - - if (serial_paranoia_check(info, tty->device, "cy_write")){ - return 0; - } - - if (!tty || !info->xmit_buf || !tmp_buf){ - return 0; - } - - while (1) { - save_flags(flags); cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0){ - restore_flags(flags); - break; - } + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - up(&tmp_buf_sem); - } else - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; + save_flags(flags); cli(); + base_addr[CyCAR<xmit_cnt - && !tty->stopped - && !tty->hw_stopped ) { - start_xmit(info); + } else { + /* Since polling is already in place, + nothing further need be done. */ } - return total; -} /* cy_write */ +} /* cy_flush_chars */ +/* + * This routine returns the numbers of characters the tty driver + * will accept for queuing to be written. This number is subject + * to change as output buffers get emptied, or if the output flow + * control is activated. + */ static int cy_write_room(struct tty_struct *tty) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - int ret; - + int ret; + #ifdef SERIAL_DEBUG_IO - printk("cy_write_room ttyC%d\n", info->line); /* */ + printk("cyc:cy_write_room ttyC%d\n", info->line); /* */ #endif if (serial_paranoia_check(info, tty->device, "cy_write_room")) - return 0; + return 0; ret = PAGE_SIZE - info->xmit_cnt - 1; if (ret < 0) - ret = 0; + ret = 0; return ret; } /* cy_write_room */ @@ -1715,126 +2591,351 @@ cy_chars_in_buffer(struct tty_struct *tty) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - + #ifdef SERIAL_DEBUG_IO - printk("cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */ + printk("cyc:cy_chars_in_buffer ttyC%d %d\n", + info->line, info->xmit_cnt); /* */ #endif if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer")) - return 0; + return 0; return info->xmit_cnt; } /* cy_chars_in_buffer */ -static void -cy_flush_buffer(struct tty_struct *tty) -{ - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - unsigned long flags; - -#ifdef SERIAL_DEBUG_IO - printk("cy_flush_buffer ttyC%d\n", info->line); /* */ -#endif - - if (serial_paranoia_check(info, tty->device, "cy_flush_buffer")) - return; - save_flags(flags); cli(); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - restore_flags(flags); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); -} /* cy_flush_buffer */ +/* + * ------------------------------------------------------------ + * cy_ioctl() and friends + * ------------------------------------------------------------ + */ -/* This routine is called by the upper-layer tty layer to signal - that incoming characters should be throttled or that the - throttle should be released. +/* + * This routine finds or computes the various line characteristics. + * It used to be called config_setup */ static void -cy_throttle(struct tty_struct * tty) +set_line_char(struct cyclades_port * info) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; unsigned char *base_addr; int card,chip,channel,index; + unsigned cflag; + int i; + + if (!info->tty || !info->tty->termios){ + return; + } + if (info->line == -1){ + return; + } + cflag = info->tty->termios->c_cflag; + + card = info->card; + channel = (info->line) - (cy_card[card].first_line); + + if (!IS_CYC_Z(cy_card[card])) { + /* baud rate */ + i = cflag & CBAUD; + + if (i & CBAUDEX) { + if (i == B57600) + i = 16; + else if(i == B115200) + i = 18; +#ifdef B76800 + else if(i == B76800) + i = 17; +#endif + else + info->tty->termios->c_cflag &= ~CBAUDEX; + } + + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i += 1; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i += 3; + } + info->tbpr = baud_bpr[i]; /* Tx BPR */ + info->tco = baud_co[i]; /* Tx CO */ + info->rbpr = baud_bpr[i]; /* Rx BPR */ + info->rco = baud_co[i]; /* Rx CO */ + if (baud_table[i] == 134) { + info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; + /* get it right for 134.5 baud */ + } else if (baud_table[i]) { + info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2; + /* this needs to be propagated into the card info */ + } else { + info->timeout = 0; + } + /* By tradition (is it a standard?) a baud rate of zero + implies the line should be/has been closed. A bit + later in this routine such a test is performed. */ + + /* byte size and parity */ + info->cor5 = 0; + info->cor4 = 0; + info->cor3 = (info->default_threshold + ? info->default_threshold + : baud_cor3[i]); /* receive threshold */ + info->cor2 = CyETC; + switch(cflag & CSIZE){ + case CS5: + info->cor1 = Cy_5_BITS; + break; + case CS6: + info->cor1 = Cy_6_BITS; + break; + case CS7: + info->cor1 = Cy_7_BITS; + break; + case CS8: + info->cor1 = Cy_8_BITS; + break; + } + if(cflag & CSTOPB){ + info->cor1 |= Cy_2_STOP; + } + if (cflag & PARENB){ + if (cflag & PARODD){ + info->cor1 |= CyPARITY_O; + }else{ + info->cor1 |= CyPARITY_E; + } + }else{ + info->cor1 |= CyPARITY_NONE; + } + + /* CTS flow control flag */ + if (cflag & CRTSCTS){ + info->flags |= ASYNC_CTS_FLOW; + info->cor2 |= CyCtsAE; + }else{ + info->flags &= ~ASYNC_CTS_FLOW; + info->cor2 &= ~CyCtsAE; + } + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + /*********************************************** + The hardware option, CyRtsAO, presents RTS when + the chip has characters to send. Since most modems + use RTS as reverse (inbound) flow control, this + option is not used. If inbound flow control is + necessary, DTR can be programmed to provide the + appropriate signals for use with a non-standard + cable. Contact Marcio Saito for details. + ***********************************************/ + + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<ldisc.chars_in_buffer(tty)); - printk("cy_throttle ttyC%d\n", info->line); + /* tx and rx baud rate */ + + base_addr[CyTCOR<tco; + base_addr[CyTBPR<tbpr; + base_addr[CyRCOR<rco; + base_addr[CyRBPR<rbpr; + + /* set line characteristics according configuration */ + + base_addr[CySCHR1<tty); + base_addr[CySCHR2<tty); + base_addr[CyCOR1<cor1; + base_addr[CyCOR2<cor2; + base_addr[CyCOR3<cor3; + base_addr[CyCOR4<cor4; + base_addr[CyCOR5<cor5; + + cyy_issue_cmd(base_addr, + CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index); + + base_addr[CyCAR<default_timeout + ? info->default_timeout + : 0x02); /* 10ms rx timeout */ + + if (C_CLOCAL(info->tty)) { + base_addr[CySRER<0 modem transitions */ + base_addr[CyMCOR1<1 modem transitions */ + base_addr[CyMCOR2<0 modem transitions */ + base_addr[CyMCOR1<1 modem transitions */ + base_addr[CyMCOR2<device, "cy_nthrottle")){ + if (info->tty){ + clear_bit(TTY_IO_ERROR, &info->tty->flags); + } + + restore_flags(flags); + } else { + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + struct CH_CTRL *ch_ctrl; + struct BUF_CTRL *buf_ctrl; + int retval; + + firm_id = (struct FIRM_ID *) + (cy_card[card].base_addr + ID_ADDRESS); + if (firm_id->signature != ZFIRM_ID){ return; - } + } - if (I_IXOFF(tty)) { - info->x_char = STOP_CHAR(tty); - /* Should use the "Send Special Character" feature!!! */ - } + zfw_ctrl = + (struct ZFW_CTRL *) + (cy_card[card].base_addr + firm_id->zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = &zfw_ctrl->ch_ctrl[channel]; + buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; - card = info->card; - channel = info->line - cy_card[card].first_line; - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<comm_baud = 0; break; + */ + case B50: ch_ctrl->comm_baud = 50; break; + case B75: ch_ctrl->comm_baud = 75; break; + case B110: ch_ctrl->comm_baud = 110; break; + case B134: ch_ctrl->comm_baud = 134; break; + case B150: ch_ctrl->comm_baud = 150; break; + case B200: ch_ctrl->comm_baud = 200; break; + case B300: ch_ctrl->comm_baud = 300; break; + case B600: ch_ctrl->comm_baud = 600; break; + case B1200: ch_ctrl->comm_baud = 1200; break; + case B1800: ch_ctrl->comm_baud = 1800; break; + case B2400: ch_ctrl->comm_baud = 2400; break; + case B4800: ch_ctrl->comm_baud = 4800; break; + case B9600: ch_ctrl->comm_baud = 9600; break; + case B19200: ch_ctrl->comm_baud = 19200; break; + case B38400: + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI){ + ch_ctrl->comm_baud = 57600; + }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI){ + ch_ctrl->comm_baud = 115200; + }else{ + ch_ctrl->comm_baud = 38400; + } + break; + case B57600: ch_ctrl->comm_baud = 57600; break; +#ifdef B76800 + case B76800: ch_ctrl->comm_baud = 76800; break; +#endif + case B115200: ch_ctrl->comm_baud = 115200; break; + case B230400: ch_ctrl->comm_baud = 230400; break; + case B460800: ch_ctrl->comm_baud = 460800; break; + } + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){ + ch_ctrl->comm_baud = info->baud; + } - save_flags(flags); cli(); - base_addr[CyCAR<comm_data_l = C_DL_CS5; break; + case CS6: ch_ctrl->comm_data_l = C_DL_CS6; break; + case CS7: ch_ctrl->comm_data_l = C_DL_CS7; break; + case CS8: ch_ctrl->comm_data_l = C_DL_CS8; break; + } + if(cflag & CSTOPB){ + ch_ctrl->comm_data_l |= C_DL_2STOP; + }else{ + ch_ctrl->comm_data_l |= C_DL_1STOP; + } + if (cflag & PARENB){ + if (cflag & PARODD){ + ch_ctrl->comm_parity = C_PR_ODD; + }else{ + ch_ctrl->comm_parity = C_PR_EVEN; + } + }else{ + ch_ctrl->comm_parity = C_PR_NONE; + } - return; -} /* cy_throttle */ + /* CTS flow control flag */ + if (cflag & CRTSCTS){ + info->flags |= ASYNC_CTS_FLOW; + ch_ctrl->hw_flow |= C_RS_CTS | C_RS_RTS; + }else{ + info->flags &= ~ASYNC_CTS_FLOW; + ch_ctrl->hw_flow &= ~(C_RS_CTS | C_RS_RTS); + } + retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L); + if (retval != 0){ + printk("cyc:set_line_char retval at %d was %x\n", + __LINE__, retval); + } -static void -cy_unthrottle(struct tty_struct * tty) -{ - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - unsigned long flags; - unsigned char *base_addr; - int card,chip,channel,index; + /* CD sensitivity */ + if (cflag & CLOCAL){ + info->flags &= ~ASYNC_CHECK_CD; + }else{ + info->flags |= ASYNC_CHECK_CD; + } -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); - printk("cy_unthrottle ttyC%d\n", info->line); + if(i == 0){ /* baud rate is zero, turn off line */ + ch_ctrl->rs_control &= ~C_RS_DTR; +#ifdef SERIAL_DEBUG_DTR + printk("cyc:set_line_char dropping Z DTR\n"); +#endif + }else{ + ch_ctrl->rs_control |= C_RS_DTR; +#ifdef SERIAL_DEBUG_DTR + printk("cyc:set_line_char raising Z DTR\n"); #endif + } - if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){ - return; - } + retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L); + if (retval != 0){ + printk("cyc:set_line_char retval at %d was %x\n", + __LINE__, retval); + } - if (I_IXOFF(tty)) { - info->x_char = START_CHAR(tty); - /* Should use the "Send Special Character" feature!!! */ + if (info->tty){ + clear_bit(TTY_IO_ERROR, &info->tty->flags); + } } - card = info->card; - channel = info->line - cy_card[card].first_line; - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<card * 0x100 + info->line - cinfo->first_line; tmp.irq = cinfo->irq; tmp.flags = info->flags; - tmp.baud_base = 0; /*!!!*/ tmp.close_delay = info->close_delay; + tmp.baud_base = info->baud; tmp.custom_divisor = 0; /*!!!*/ tmp.hub6 = 0; /*!!!*/ - copy_to_user(retinfo,&tmp,sizeof(*retinfo)); + memcpy_tofs(retinfo,&tmp,sizeof(*retinfo)); return 0; } /* get_serial_info */ + static int set_serial_info(struct cyclades_port * info, struct serial_struct * new_info) @@ -1867,18 +2969,19 @@ struct cyclades_port old_info; if (!new_info) - return -EFAULT; - copy_from_user(&new_serial,new_info,sizeof(new_serial)); + return -EFAULT; + memcpy_fromfs(&new_serial,new_info,sizeof(new_serial)); old_info = *info; if (!suser()) { - if ((new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != - (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) - return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - goto check_and_exit; + if ((new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != + (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->baud = new_serial.baud_base; + goto check_and_exit; } @@ -1888,19 +2991,21 @@ */ info->flags = ((info->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); + (new_serial.flags & ASYNC_FLAGS)); + info->baud = new_serial.baud_base; info->close_delay = new_serial.close_delay; check_and_exit: if (info->flags & ASYNC_INITIALIZED){ - config_setup(info); - return 0; + set_line_char(info); + return 0; }else{ return startup(info); } } /* set_serial_info */ + static int get_modem_info(struct cyclades_port * info, unsigned int *value) { @@ -1908,259 +3013,423 @@ unsigned char *base_addr; unsigned long flags; unsigned char status; + unsigned long lstatus; unsigned int result; + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + struct CH_CTRL *ch_ctrl; card = info->card; channel = (info->line) - (cy_card[card].first_line); - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<signature == ZFIRM_ID){ + zfw_ctrl = + (struct ZFW_CTRL *) + (cy_card[card].base_addr + firm_id->zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + lstatus = ch_ctrl[channel].rs_status; + result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) + | ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) + | ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) + | ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) + | ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) + | ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0); + }else{ + result = 0; + return -ENODEV; + } - result = ((status & CyRTS) ? TIOCM_RTS : 0) - | ((status & CyDTR) ? TIOCM_DTR : 0) - | ((status & CyDCD) ? TIOCM_CAR : 0) - | ((status & CyRI) ? TIOCM_RNG : 0) - | ((status & CyDSR) ? TIOCM_DSR : 0) - | ((status & CyCTS) ? TIOCM_CTS : 0); - put_user(result,(unsigned int *) value); + } + put_fs_long(result,(unsigned long *) value); return 0; } /* get_modem_info */ + static int set_modem_info(struct cyclades_port * info, unsigned int cmd, unsigned int *value) { - int card,chip,channel,index; - unsigned char *base_addr; - unsigned long flags; - unsigned int arg; - int error; - - error = get_user(arg, value); - if (error) - return error; + int card,chip,channel,index; + unsigned char *base_addr; + unsigned long flags; + unsigned int arg = get_fs_long((unsigned long *) value); + struct FIRM_ID *firm_id; + struct ZFW_CTRL *zfw_ctrl; + struct BOARD_CTRL *board_ctrl; + struct CH_CTRL *ch_ctrl; + int retval; card = info->card; channel = (info->line) - (cy_card[card].first_line); - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<signature == ZFIRM_ID){ + zfw_ctrl = + (struct ZFW_CTRL *) + (cy_card[card].base_addr + firm_id->zfwctrl_addr); + board_ctrl = &zfw_ctrl->board_ctrl; + ch_ctrl = zfw_ctrl->ch_ctrl; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS){ + ch_ctrl[channel].rs_control |= C_RS_RTS; + } + if (arg & TIOCM_DTR){ + ch_ctrl[channel].rs_control |= C_RS_DTR; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: raising DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1<card], + channel, C_CM_IOCTLM,0L); + if (retval != 0){ + printk("cyc:set_modem_info retval at %d was %x\n", + __LINE__, retval); + } + } return 0; } /* set_modem_info */ + static void send_break( struct cyclades_port * info, int duration) -{ /* Let the transmit ISR take care of this (since it - requires stuffing characters into the output stream). - */ - info->x_break = duration; - if (!info->xmit_cnt ) { - start_xmit(info); +{ + + if (!IS_CYC_Z(cy_card[info->card])) { + /* Let the transmit ISR take care of this (since it + requires stuffing characters into the output stream). + */ + info->x_break = duration; + if (!info->xmit_cnt ) { + start_xmit(info); + } + } else { + /* For the moment we ignore the duration parameter!!! + A better implementation will use C_CM_SET_BREAK + and C_CM_CLR_BREAK with the appropriate delay. + */ +#if 0 +this appears to wedge the output data stream +int retval; + retval = cyz_issue_cmd(&cy_card[info->card], + (info->line) - (cy_card[info->card].first_line), + C_CM_SENDBRK, 0L); + if (retval != 0){ + printk("cyc:send_break retval at %d was %x\n", + __LINE__, retval); + } +#endif } } /* send_break */ + static int get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon) { - copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)); - info->mon.int_count = 0; - info->mon.char_count = 0; - info->mon.char_max = 0; - info->mon.char_last = 0; - return 0; -} + memcpy_tofs(mon, &info->mon, sizeof(struct cyclades_monitor)); + info->mon.int_count = 0; + info->mon.char_count = 0; + info->mon.char_max = 0; + info->mon.char_last = 0; + return 0; +}/* get_mon_info */ + static int set_threshold(struct cyclades_port * info, unsigned long value) { - unsigned char *base_addr; - int card,channel,chip,index; + unsigned char *base_addr; + int card,channel,chip,index; - card = info->card; - channel = info->line - cy_card[card].first_line; - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<card; + channel = info->line - cy_card[card].first_line; + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<cor3 &= ~CyREC_FIFO; + info->cor3 |= value & CyREC_FIFO; + base_addr[CyCOR3<cor3; + cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index); + } else { + // Nothing to do! + } + return 0; +}/* set_threshold */ - info->cor3 &= ~CyREC_FIFO; - info->cor3 |= value & CyREC_FIFO; - base_addr[CyCOR3<cor3; - write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index); - return 0; -} static int get_threshold(struct cyclades_port * info, unsigned long *value) { - unsigned char *base_addr; - int card,channel,chip,index; - unsigned long tmp; + unsigned char *base_addr; + int card,channel,chip,index; + unsigned long tmp; - card = info->card; - channel = info->line - cy_card[card].first_line; - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<card; + channel = info->line - cy_card[card].first_line; + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<default_threshold = value & 0x0f; - return 0; -} + info->default_threshold = value & 0x0f; + return 0; +}/* set_default_threshold */ + static int get_default_threshold(struct cyclades_port * info, unsigned long *value) { - put_user(info->default_threshold,value); - return 0; -} + put_fs_long(info->default_threshold,value); + return 0; +}/* get_default_threshold */ + static int set_timeout(struct cyclades_port * info, unsigned long value) { - unsigned char *base_addr; - int card,channel,chip,index; + unsigned char *base_addr; + int card,channel,chip,index; - card = info->card; - channel = info->line - cy_card[card].first_line; - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<card; + channel = info->line - cy_card[card].first_line; + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<card; - channel = info->line - cy_card[card].first_line; - chip = channel>>2; - channel &= 0x03; - index = cy_card[card].bus_index; - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]<card; + channel = info->line - cy_card[card].first_line; + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<default_timeout = value & 0xff; - return 0; -} + info->default_timeout = value & 0xff; + return 0; +}/* set_default_timeout */ + static int get_default_timeout(struct cyclades_port * info, unsigned long *value) { - put_user(info->default_timeout,value); - return 0; -} + put_fs_long(info->default_timeout,value); + return 0; +}/* get_default_timeout */ + +/* + * This routine allows the tty driver to implement device- + * specific ioctl's. If the ioctl number passed in cmd is + * not recognized by the driver, it should return ENOIOCTLCMD. + */ static int cy_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) @@ -2170,7 +3439,8 @@ int ret_val = 0; #ifdef SERIAL_DEBUG_OTHER - printk("cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */ + printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", + info->line, cmd, arg); /* */ #endif switch (cmd) { @@ -2182,7 +3452,7 @@ break; } ret_val = get_mon_info(info, (struct cyclades_monitor *)arg); - break; + break; case CYGETTHRESH: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned long)); @@ -2190,11 +3460,11 @@ ret_val = error; break; } - ret_val = get_threshold(info, (unsigned long *)arg); - break; + ret_val = get_threshold(info, (unsigned long *)arg); + break; case CYSETTHRESH: ret_val = set_threshold(info, (unsigned long)arg); - break; + break; case CYGETDEFTHRESH: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned long)); @@ -2202,11 +3472,11 @@ ret_val = error; break; } - ret_val = get_default_threshold(info, (unsigned long *)arg); - break; + ret_val = get_default_threshold(info, (unsigned long *)arg); + break; case CYSETDEFTHRESH: ret_val = set_default_threshold(info, (unsigned long)arg); - break; + break; case CYGETTIMEOUT: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned long)); @@ -2214,11 +3484,11 @@ ret_val = error; break; } - ret_val = get_timeout(info, (unsigned long *)arg); - break; + ret_val = get_timeout(info, (unsigned long *)arg); + break; case CYSETTIMEOUT: ret_val = set_timeout(info, (unsigned long)arg); - break; + break; case CYGETDEFTIMEOUT: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned long)); @@ -2226,23 +3496,23 @@ ret_val = error; break; } - ret_val = get_default_timeout(info, (unsigned long *)arg); - break; + ret_val = get_default_timeout(info, (unsigned long *)arg); + break; case CYSETDEFTIMEOUT: ret_val = set_default_timeout(info, (unsigned long)arg); - break; + break; case TCSBRK: /* SVID version: non-zero arg --> no break */ - ret_val = tty_check_change(tty); - if (ret_val) - return ret_val; + ret_val = tty_check_change(tty); + if (ret_val) + return ret_val; tty_wait_until_sent(tty,0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ break; case TCSBRKP: /* support for POSIX tcsendbreak() */ - ret_val = tty_check_change(tty); - if (ret_val) - return ret_val; + ret_val = tty_check_change(tty); + if (ret_val) + return ret_val; tty_wait_until_sent(tty,0); send_break(info, arg ? arg*(HZ/10) : HZ/4); break; @@ -2254,19 +3524,31 @@ /* The following commands are incompletely implemented!!! */ case TIOCGSOFTCAR: - ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg); - break; + error = verify_area(VERIFY_WRITE, (void *) arg + ,sizeof(unsigned int *)); + if (error){ + ret_val = error; + break; + } + put_fs_long(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + break; case TIOCSSOFTCAR: - ret_val = get_user(arg,(unsigned int *) arg); - if (ret_val) - break; + error = verify_area(VERIFY_READ, (void *) arg + ,sizeof(unsigned long *)); + if (error) { + ret_val = error; + break; + } + + arg = get_fs_long((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); break; case TIOCMGET: error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(unsigned int)); + ,sizeof(unsigned int *)); if (error){ ret_val = error; break; @@ -2294,31 +3576,35 @@ (struct serial_struct *) arg); break; default: - ret_val = -ENOIOCTLCMD; + ret_val = -ENOIOCTLCMD; } #ifdef SERIAL_DEBUG_OTHER - printk("cy_ioctl done\n"); + printk(" cyc:cy_ioctl done\n"); #endif return ret_val; } /* cy_ioctl */ - - +/* + * This routine allows the tty driver to be notified when + * device's termios settings have changed. Note that a + * well-designed tty driver should be prepared to accept the case + * where old == NULL, and try to do something rational. + */ static void cy_set_termios(struct tty_struct *tty, struct termios * old_termios) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; #ifdef SERIAL_DEBUG_OTHER - printk("cy_set_termios ttyC%d\n", info->line); + printk("cyc:cy_set_termios ttyC%d\n", info->line); #endif if (tty->termios->c_cflag == old_termios->c_cflag) return; - config_setup(info); + set_line_char(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -2335,353 +3621,243 @@ } /* cy_set_termios */ +/* + * void (*set_ldisc)(struct tty_struct *tty); + * + * This routine allows the tty driver to be notified when the + * device's termios settings have changed. + * + */ + + +/* This routine is called by the upper-layer tty layer to signal + that incoming characters should be throttled because the input + buffers are close to full. + */ static void -cy_close(struct tty_struct * tty, struct file * filp) +cy_throttle(struct tty_struct * tty) { - struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; + unsigned char *base_addr; + int card,chip,channel,index; -#ifdef SERIAL_DEBUG_OTHER - printk("cy_close ttyC%d\n", info->line); +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("cyc:throttle %s: %d....ttyC%d\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty), info->line); #endif - if (!info - || serial_paranoia_check(info, tty->device, "cy_close")){ - return; + if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){ + return; } -#ifdef SERIAL_DEBUG_OPEN - printk("cy_close ttyC%d, count = %d\n", info->line, info->count); -#endif - - save_flags(flags); cli(); - /* If the TTY is being hung up, nothing to do */ - if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("cy_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } -#ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count - 1); -#endif - if (--info->count < 0) { -#ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: setting count to 0\n", __LINE__); -#endif - info->count = 0; + if (I_IXOFF(tty)) { + info->x_char = STOP_CHAR(tty); + /* Should use the "Send Special Character" feature!!! */ } - if (info->count) - { - MOD_DEC_USE_COUNT; + + card = info->card; + channel = info->line - cy_card[card].first_line; + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<flags |= ASYNC_CLOSING; - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; - if (info->flags & ASYNC_INITIALIZED) - tty_wait_until_sent(tty, 30*HZ); /* 30 seconds timeout */ - shutdown(info); - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - info->event = 0; - info->tty = 0; - if (info->blocked_open) { - if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); - } - wake_up_interruptible(&info->open_wait); + } else { + // Nothing to do! } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - -#ifdef SERIAL_DEBUG_OTHER - printk("cy_close done\n"); -#endif - MOD_DEC_USE_COUNT; - restore_flags(flags); return; -} /* cy_close */ - -/* - * cy_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -void -cy_hangup(struct tty_struct *tty) -{ - struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; - -#ifdef SERIAL_DEBUG_OTHER - printk("cy_hangup ttyC%d\n", info->line); /* */ -#endif - - if (serial_paranoia_check(info, tty->device, "cy_hangup")) - return; - - shutdown(info); - info->event = 0; - info->count = 0; -#ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d(%d): setting count to 0\n", __LINE__, current->pid); -#endif - info->tty = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); - wake_up_interruptible(&info->open_wait); -} /* cy_hangup */ - +} /* cy_throttle */ /* - * ------------------------------------------------------------ - * cy_open() and friends - * ------------------------------------------------------------ + * This routine notifies the tty driver that it should signal + * that characters can now be sent to the tty without fear of + * overrunning the input buffers of the line disciplines. */ - -static int -block_til_ready(struct tty_struct *tty, struct file * filp, - struct cyclades_port *info) +static void +cy_unthrottle(struct tty_struct * tty) { - struct wait_queue wait = { current, NULL }; - struct cyclades_card *cinfo; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; - int chip, channel,index; - int retval; - char *base_addr; + unsigned char *base_addr; + int card,chip,channel,index; - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&info->close_wait); - if (info->flags & ASYNC_HUP_NOTIFY){ - return -EAGAIN; - }else{ - return -ERESTARTSYS; - } - } +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("cyc:throttle %s: %d....ttyC%d\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty), info->line); +#endif - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE){ - return -EBUSY; - } - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)){ - return -EBUSY; - } - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)){ - return -EBUSY; - } - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; + if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){ + return; } - /* - * If non-blocking mode is set, then make the check up front - * and then exit. - */ - if (filp->f_flags & O_NONBLOCK) { - if (info->flags & ASYNC_CALLOUT_ACTIVE){ - return -EBUSY; - } - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; + if (I_IXOFF(tty)) { + info->x_char = START_CHAR(tty); + /* Should use the "Send Special Character" feature!!! */ } - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * cy_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttyC%d, count = %d\n", - info->line, info->count);/**/ -#endif - info->count--; -#ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count); -#endif - info->blocked_open++; - - cinfo = &cy_card[info->card]; - channel = info->line - cinfo->first_line; - chip = channel>>2; - channel &= 0x03; - index = cinfo->bus_index; - base_addr = (char *) (cinfo->base_addr + (cy_chip_offset[chip]<card; + channel = info->line - cy_card[card].first_line; + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char*) + (cy_card[card].base_addr + + (cy_chip_offset[chip]<flags & ASYNC_CALLOUT_ACTIVE)){ - base_addr[CyCAR<state = TASK_INTERRUPTIBLE; - if (tty_hung_up_p(filp) - || !(info->flags & ASYNC_INITIALIZED) ){ - if (info->flags & ASYNC_HUP_NOTIFY) { - retval = -EAGAIN; - }else{ - retval = -ERESTARTSYS; - } - break; - } save_flags(flags); cli(); base_addr[CyCAR<flags & ASYNC_CALLOUT_ACTIVE) - && !(info->flags & ASYNC_CLOSING) - && (C_CLOCAL(tty) - || (base_addr[CyMSVR1<signal & ~current->blocked) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttyC%d, count = %d\n", - info->line, info->count);/**/ -#endif - schedule(); + }else{ + // Nothing to do! } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)){ - info->count++; -#ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count); + + return; +} /* cy_unthrottle */ + + +/* cy_start and cy_stop provide software output flow control as a + function of XON/XOFF, software CTS, and other such stuff. +*/ +static void +cy_stop(struct tty_struct *tty) +{ + struct cyclades_card *cinfo; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned char *base_addr; + int chip,channel,index; + unsigned long flags; + +#ifdef SERIAL_DEBUG_OTHER + printk("cyc:cy_stop ttyC%d\n", info->line); /* */ #endif + + if (serial_paranoia_check(info, tty->device, "cy_stop")) + return; + + cinfo = &cy_card[info->card]; + channel = info->line - cinfo->first_line; + if (!IS_CYC_Z(*cinfo)) { + index = cinfo->bus_index; + chip = channel>>2; + channel &= 0x03; + base_addr = (unsigned char*) + (cy_card[info->card].base_addr + + (cy_chip_offset[chip]<blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttyC%d, count = %d\n", - info->line, info->count);/**/ -#endif - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} /* block_til_ready */ -/* - * This routine is called whenever a serial port is opened. It - * performs the serial-specific initialization for the tty structure. - */ -int -cy_open(struct tty_struct *tty, struct file * filp) + return; +} /* cy_stop */ + + +static void +cy_start(struct tty_struct *tty) { - struct cyclades_port *info; - int retval, line; + struct cyclades_card *cinfo; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned char *base_addr; + int chip,channel,index; + unsigned long flags; - line = MINOR(tty->device) - tty->driver.minor_start; - if ((line < 0) || (NR_PORTS <= line)){ - return -ENODEV; - } - info = &cy_port[line]; - if (info->line < 0){ - return -ENODEV; - } #ifdef SERIAL_DEBUG_OTHER - printk("cy_open ttyC%d\n", info->line); /* */ -#endif - if (serial_paranoia_check(info, tty->device, "cy_open")){ - return -ENODEV; - } -#ifdef SERIAL_DEBUG_OPEN - printk("cy_open ttyC%d, count = %d\n", info->line, info->count);/**/ -#endif - info->count++; -#ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count); + printk("cyc:cy_start ttyC%d\n", info->line); /* */ #endif - tty->driver_data = info; - info->tty = tty; - if (!tmp_buf) { - tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL); - if (!tmp_buf){ - return -ENOMEM; - } + if (serial_paranoia_check(info, tty->device, "cy_start")) + return; + + cinfo = &cy_card[info->card]; + channel = info->line - cinfo->first_line; + index = cinfo->bus_index; + if (!IS_CYC_Z(*cinfo)) { + chip = channel>>2; + channel &= 0x03; + base_addr = (unsigned char*) + (cy_card[info->card].base_addr + + (cy_chip_offset[chip]<count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; - } - /* - * Start up serial port - */ - retval = startup(info); - if (retval){ - return retval; - } + return; +} /* cy_start */ - MOD_INC_USE_COUNT; - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("cy_open returning after block_til_ready with %d\n", - retval); +/* + * cy_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void +cy_hangup(struct tty_struct *tty) +{ + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; + +#ifdef SERIAL_DEBUG_OTHER + printk("cyc:cy_hangup ttyC%d\n", info->line); /* */ #endif - return retval; - } - info->session = current->session; - info->pgrp = current->pgrp; + if (serial_paranoia_check(info, tty->device, "cy_hangup")) + return; + + shutdown(info); + info->event = 0; + info->count = 0; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid); +#endif + info->tty = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + wake_up_interruptible(&info->open_wait); +} /* cy_hangup */ -#ifdef SERIAL_DEBUG_OPEN - printk("cy_open done\n");/**/ + +static void +cy_flush_buffer(struct tty_struct *tty) +{ + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + unsigned long flags; + +#ifdef SERIAL_DEBUG_IO + printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */ #endif - return 0; -} /* cy_open */ + if (serial_paranoia_check(info, tty->device, "cy_flush_buffer")) + return; + save_flags(flags); cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) + && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} /* cy_flush_buffer */ /* @@ -2692,21 +3868,11 @@ * --------------------------------------------------------------------- */ -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static inline void -show_version(void) -{ - printk("Cyclom driver %s\n",rcsid); -} /* show_version */ -/* initialize chips on card -- return number of valid +/* initialize chips on Cyclom-Y card -- return number of valid chips (which is number of ports/4) */ __initfunc(static int -cy_init_card(unsigned char *true_base_addr,int index)) +cyy_init_card(unsigned char *true_base_addr,int index)) { unsigned int chip_number; unsigned char* base_addr; @@ -2716,7 +3882,8 @@ udelay(500L); for(chip_number=0; chip_number= 131328 + cy_isa_address = vremap((unsigned int)cy_isa_address,0x2000); +#endif + cy_isa_nchan = 4 * cyy_init_card(cy_isa_address,0); + if (cy_isa_nchan == 0) { + continue; + } + + /* find out the board's irq by probing */ + cy_isa_irq = do_auto_irq(cy_isa_address); + if (cy_isa_irq == 0) { + printk("Cyclom-Y/ISA found at 0x%x ", + (unsigned int) cy_isa_address); + printk("but the IRQ could not be detected.\n"); + continue; + } + + if((cy_next_channel+cy_isa_nchan) > NR_PORTS) { + printk("Cyclom-Y/ISA found at 0x%x ", + (unsigned int) cy_isa_address); + printk("but no more channels are available.\n"); + return(nboard); + } + /* fill the next cy_card structure available */ + for (j = 0 ; j < NR_CARDS ; j++) { + if (cy_card[j].base_addr == 0) break; + } + if (j == NR_CARDS) { /* no more cy_cards available */ + printk("Cyclom-Y/ISA found at 0x%x ", + (unsigned int) cy_isa_address); + printk("but no more cards can be used .\n"); + return(nboard); + } + + /* allocate IRQ */ + if(request_irq(cy_isa_irq, cyy_interrupt, + SA_INTERRUPT, "cyclomY", NULL)) + { + printk("Cyclom-Y/ISA found at 0x%x ", + (unsigned int) cy_isa_address); + printk("but could not allocate IRQ#%d.\n", + cy_isa_irq); + return(nboard); + } + + /* set cy_card */ + cy_card[j].base_addr = (int) cy_isa_address; + cy_card[j].ctl_addr = 0; + cy_card[j].irq = (int) cy_isa_irq; + cy_card[j].bus_index = 0; + cy_card[j].first_line = cy_next_channel; + cy_card[j].num_chips = cy_isa_nchan/4; + IRQ_cards[cy_isa_irq] = &cy_card[j]; + nboard++; + + /* print message */ + printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, ", + j+1, (unsigned int) cy_isa_address, + (unsigned int)(cy_isa_address + 0x1fff), + cy_isa_irq); + printk("%d channels starting from port %d.\n", + cy_isa_nchan, cy_next_channel); + cy_next_channel += cy_isa_nchan; + } + return(nboard); + +} /* cy_detect_isa */ + +/* + * --------------------------------------------------------------------- + * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI. + * sets global variables and return the number of PCI boards found. + * --------------------------------------------------------------------- + */ +__initfunc(static int +cy_detect_pci(void)) +{ +#ifdef CONFIG_PCI + unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id; + unsigned long pci_intr_ctrl; + unsigned char cy_pci_irq; + unsigned int cy_pci_addr0, cy_pci_addr1, cy_pci_addr2; + unsigned short i,j,cy_pci_nchan; + unsigned short device_id,dev_index = 0,board_index = 0; + + if(pcibios_present() == 0) { /* PCI bus not present */ + return(0); + } + for (i = 0; i < NR_CARDS; i++) { + /* look for a Cyclades card by vendor and device id */ + while((device_id = cy_pci_dev_id[dev_index]) != 0) { + if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES, + device_id,board_index, + &cyy_bus, &cyy_dev_fn) != 0) + { + dev_index++; /* try next device id */ + board_index = 0; + } else { + board_index++; + break; /* found a board */ + } + } + + /* read PCI configuration area */ + pcibios_read_config_byte(cyy_bus, cyy_dev_fn, + PCI_INTERRUPT_LINE, &cy_pci_irq); + pcibios_read_config_dword(cyy_bus, cyy_dev_fn, + PCI_BASE_ADDRESS_0, &cy_pci_addr0); + pcibios_read_config_dword(cyy_bus, cyy_dev_fn, + PCI_BASE_ADDRESS_1, &cy_pci_addr1); + pcibios_read_config_dword(cyy_bus, cyy_dev_fn, + PCI_BASE_ADDRESS_2, &cy_pci_addr2); + pcibios_read_config_byte(cyy_bus, cyy_dev_fn, + PCI_REVISION_ID, &cyy_rev_id); + if (device_id == 0){ + break; + }else if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) + || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){ +#ifdef CY_PCI_DEBUG + printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", + cyy_bus, cyy_dev_fn); + printk("rev_id=%d) IRQ%d\n", + cyy_rev_id, (int)cy_pci_irq); + printk("Cyclom-Y/PCI:found winaddr=0x%x ioaddr=0x%x\n", + cy_pci_addr2, cy_pci_addr1); +#endif + cy_pci_addr1 &= 0xfffffffc; + cy_pci_addr2 &= 0xfffffff0; + +#if LINUX_VERSION_CODE < 131328 + if ((ulong)cy_pci_addr2 >= 0x100000) /* above 1M? */ +#endif + cy_pci_addr2 = + (unsigned int) vremap(cy_pci_addr2,CyPCI_Ywin); + +#ifdef CY_PCI_DEBUG + printk("Cyclom-Y/PCI: relocate winaddr=0x%x ioaddr=0x%x\n", + cy_pci_addr2, cy_pci_addr1); +#endif + cy_pci_nchan = 4 * cyy_init_card((unsigned char *) + cy_pci_addr2,1); + if(cy_pci_nchan == 0) { + printk("Cyclom-Y PCI host card with "); + printk("no Serial-Modules at 0x%x.\n", + (unsigned int) cy_pci_addr2); + continue; + } + if((cy_next_channel+cy_pci_nchan) > NR_PORTS) { + printk("Cyclom-Y/PCI found at 0x%x ", + (unsigned int) cy_pci_addr2); + printk("but no channels are available.\n"); + return(i); + } + /* fill the next cy_card structure available */ + for (j = 0 ; j < NR_CARDS ; j++) { + if (cy_card[j].base_addr == 0) break; + } + if (j == NR_CARDS) { /* no more cy_cards available */ + printk("Cyclom-Y/PCI found at 0x%x ", + (unsigned int) cy_pci_addr2); + printk("but no more cards can be used.\n"); + return(i); + } + + /* allocate IRQ */ + if(request_irq(cy_pci_irq, cyy_interrupt, + SA_INTERRUPT, "cyclomY", NULL)) + { + printk("Cyclom-Y/PCI found at 0x%x ", + (unsigned int) cy_pci_addr2); + printk("but could not allocate IRQ%d.\n", + cy_pci_irq); + return(i); + } + + /* set cy_card */ + cy_card[j].base_addr = (int) cy_pci_addr2; + cy_card[j].ctl_addr = 0; + cy_card[j].irq = (int) cy_pci_irq; + cy_card[j].bus_index = 1; + cy_card[j].first_line = cy_next_channel; + cy_card[j].num_chips = cy_pci_nchan/4; + IRQ_cards[cy_pci_irq] = &cy_card[j]; + + /* enable interrupts in the PCI interface */ + outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68); + pci_intr_ctrl = (unsigned long) + (inw(cy_pci_addr1+0x68) + | inw(cy_pci_addr1+0x6a)<<16); + + /* print message */ + printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, ", + j+1, cy_pci_addr2, (cy_pci_addr2 + CyPCI_Ywin - 1), + (int)cy_pci_irq); + printk("%d channels starting from port %d.\n", + cy_pci_nchan, cy_next_channel); + + cy_next_channel += cy_pci_nchan; + }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){ + /* print message */ + printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ", + cyy_bus, cyy_dev_fn); + printk("rev_id=%d) IRQ%d\n", + cyy_rev_id, (int)cy_pci_irq); + printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n", + cy_pci_addr2, cy_pci_addr0); + printk("Cyclom-Z/PCI not supported for low addresses\n"); + break; + }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){ +#ifdef CY_PCI_DEBUG + printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ", + cyy_bus, cyy_dev_fn); + printk("rev_id=%d) IRQ%d\n", + cyy_rev_id, (int)cy_pci_irq); + printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n", + cy_pci_addr2, cy_pci_addr0); +#endif + cy_pci_addr2 &= 0xfffffff0; + cy_pci_addr2 = (unsigned int) vremap( + cy_pci_addr2 & PAGE_MASK, + PAGE_ALIGN(CyPCI_Zwin)) + + (cy_pci_addr2 & (PAGE_SIZE-1)); + cy_pci_addr0 &= 0xfffffff0; + cy_pci_addr0 = (unsigned int) vremap( + cy_pci_addr0 & PAGE_MASK, + PAGE_ALIGN(CyPCI_Zctl)) + + (cy_pci_addr0 & (PAGE_SIZE-1)); +#ifdef CY_PCI_DEBUG + printk("Cyclom-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n", + cy_pci_addr2, cy_pci_addr0); + ((struct RUNTIME_9060 *)(cy_pci_addr0)) + ->loc_addr_base = WIN_CREG; + PAUSE + printk("Cyclom-Z/PCI: FPGA id %lx, ver %lx\n", + 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_id, + 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_version); + ((struct RUNTIME_9060 *)(cy_pci_addr0)) + ->loc_addr_base = WIN_RAM; +#endif + /* The following clears the firmware id word. This ensures + that the driver will not attempt to talk to the board + until it has been properly initialized. + */ + PAUSE + *(unsigned long *)(cy_pci_addr2+ID_ADDRESS) = 0L; + + /* This must be a Cyclom-8Zo/PCI. The extendable + version will have a different device_id and will + be allocated its maximum number of ports. */ + cy_pci_nchan = 8; + + /* fill the next cy_card structure available */ + for (j = 0 ; j < NR_CARDS ; j++) { + if (cy_card[j].base_addr == 0) break; + } + if (j == NR_CARDS) { /* no more cy_cards available */ + printk("Cyclom-Z/PCI found at 0x%x ", + (unsigned int) cy_pci_addr2); + printk("but no more cards can be used.\n"); + return(i); + } + + /* allocate IRQ only if board has an IRQ */ + if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) { + if(request_irq(cy_pci_irq,cyz_interrupt, + SA_INTERRUPT,"cyclomZ",NULL)) + { + printk("Could not allocate IRQ%d ", + (unsigned int) cy_pci_addr2); + printk("for Cyclom-Z/PCI at 0x%x.\n", + cy_pci_irq); + return(i); + } + } + + /* set cy_card */ + cy_card[j].base_addr = cy_pci_addr2; + cy_card[j].ctl_addr = cy_pci_addr0; + cy_card[j].irq = (int) cy_pci_irq; + cy_card[j].bus_index = 1; + cy_card[j].first_line = cy_next_channel; + cy_card[j].num_chips = 1; + IRQ_cards[cy_pci_irq] = &cy_card[j]; + + /* print message */ + /* don't report IRQ if board is no IRQ */ + if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) { + printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ", + j+1,cy_pci_addr2, + (cy_pci_addr2 + CyPCI_Zwin - 1), + (int)cy_pci_irq); + }else{ + printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, ", + j+1,cy_pci_addr2, + (cy_pci_addr2 + CyPCI_Zwin - 1)); + } + printk("%d channels starting from port %d.\n", + cy_pci_nchan,cy_next_channel); + cy_next_channel += cy_pci_nchan; + } + } + return(i); +#else + return(0); +#endif /* ifdef CONFIG_PCI */ +} /* cy_detect_pci */ + + +/* + * This routine prints out the appropriate serial driver version number + * and identifies which options were configured into this driver. + */ +static inline void +show_version(void) +{ + char *rcsvers, *rcsdate, *tmp; + rcsvers = strchr(rcsid, ' '); rcsvers++; + tmp = strchr(rcsvers, ' '); *tmp++ = '\0'; + rcsdate = strchr(tmp, ' '); rcsdate++; + tmp = strrchr(rcsdate, ' '); *tmp = '\0'; + printk("Cyclom driver %s %s\n", + rcsvers, rcsdate); + printk("\tbuilt %s %s\n", + __DATE__, __TIME__); +} /* show_version */ + /* The serial driver boot-time initialization code! Hardware I/O ports are mapped to character special devices on a @@ -2783,15 +4307,18 @@ device driver because the Cyclom is more properly a multiplexer, not just an aggregation of serial ports on one card. - If there are more cards with more ports than have been statically - allocated above, a warning is printed and the extra ports are ignored. + If there are more cards with more ports than have been + statically allocated above, a warning is printed and the + extra ports are ignored. */ + __initfunc(int cy_init(void)) { - struct cyclades_port *info; + struct cyclades_port *info; struct cyclades_card *cinfo; - int board,port,i; + int number_z_boards = 0; + int board,port,i; show_version(); @@ -2807,7 +4334,7 @@ cy_serial_driver.subtype = SERIAL_TYPE_NORMAL; cy_serial_driver.init_termios = tty_std_termios; cy_serial_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; + B9600 | CS8 | CREAD | HUPCL | CLOCAL; cy_serial_driver.flags = TTY_DRIVER_REAL_RAW; cy_serial_driver.refcount = &serial_refcount; cy_serial_driver.table = serial_table; @@ -2839,27 +4366,27 @@ cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&cy_serial_driver)) - panic("Couldn't register Cyclom serial driver\n"); + panic("Couldn't register Cyclom serial driver\n"); if (tty_register_driver(&cy_callout_driver)) - panic("Couldn't register Cyclom callout driver\n"); + panic("Couldn't register Cyclom callout driver\n"); init_bh(CYCLADES_BH, do_cyclades_bh); for (i = 0; i < 16; i++) { - IRQ_cards[i] = 0; + IRQ_cards[i] = 0; } for (i = 0; i < NR_CARDS; i++) { - /* base_addr=0 indicates board not found */ - cy_card[i].base_addr = 0; + /* base_addr=0 indicates board not found */ + cy_card[i].base_addr = 0; } /* the code below is responsible to find the boards. Each different type of board has its own detection routine. If a board is found, the next cy_card structure available is set by the detection - routine. These functions are responsible for checking the availability - of cy_card and cy_port data structures and updating the - cy_next_channel. */ + routine. These functions are responsible for checking the + availability of cy_card and cy_port data structures and updating + the cy_next_channel. */ /* look for isa boards */ cy_isa_nboard = cy_detect_isa(); @@ -2871,289 +4398,195 @@ /* invalidate remaining cy_card structures */ for (i = 0 ; i < NR_CARDS ; i++) { - if (cy_card[i].base_addr == 0) { - cy_card[i].first_line = -1; - } + if (cy_card[i].base_addr == 0) { + cy_card[i].first_line = -1; + cy_card[i].ctl_addr = 0; + cy_card[i].irq = 0; + cy_card[i].bus_index = 0; + cy_card[i].first_line = 0; + cy_card[i].num_chips = 0; + } } /* invalidate remaining cy_port structures */ for (i = cy_next_channel ; i < NR_PORTS ; i++) { - cy_port[i].line = -1; - cy_port[i].magic = -1; + cy_port[i].line = -1; + cy_port[i].magic = -1; } /* initialize per-port data structures for each valid board found */ for (board = 0 ; board < cy_nboard ; board++) { - cinfo = &cy_card[board]; - for (port = cinfo->first_line ; - port < cinfo->first_line + 4*cinfo->num_chips ; - port++) - { - info = &cy_port[port]; - info->magic = CYCLADES_MAGIC; - info->type = PORT_CIRRUS; - info->card = board; - info->line = port; - info->flags = STD_COM_FLAGS; - info->tty = 0; - info->xmit_fifo_size = 12; - info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS; - info->cor2 = CyETC; - info->cor3 = 0x08; /* _very_ small receive threshold */ - info->cor4 = 0; - info->cor5 = 0; - info->tbpr = baud_bpr[13]; /* Tx BPR */ - info->tco = baud_co[13]; /* Tx CO */ - info->rbpr = baud_bpr[13]; /* Rx BPR */ - info->rco = baud_co[13]; /* Rx CO */ - info->close_delay = 0; - info->x_char = 0; - info->event = 0; - info->count = 0; + cinfo = &cy_card[board]; + if (cinfo->num_chips == 1){ /* Cyclom-8Zo/PCI */ + number_z_boards++; + for (port = cinfo->first_line ; + port < cinfo->first_line + 8; + port++) + { + info = &cy_port[port]; + info->magic = CYCLADES_MAGIC; + info->type = PORT_STARTECH; + info->card = board; + info->line = port; + info->flags = STD_COM_FLAGS; + info->tty = 0; + info->xmit_fifo_size = 0; + info->cor1 = 0; + info->cor2 = 0; + info->cor3 = 0; + info->cor4 = 0; + info->cor5 = 0; + info->tbpr = 0; + info->tco = 0; + info->rbpr = 0; + info->rco = 0; + info->close_delay = 0; + info->x_char = 0; + info->event = 0; + info->count = 0; #ifdef SERIAL_DEBUG_COUNT - printk("cyc: %d: setting count to 0\n", __LINE__); + printk("cyc:cy_init(1) setting Z count to 0\n"); +#endif + info->blocked_open = 0; + info->default_threshold = 0; + info->default_timeout = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->callout_termios = + cy_callout_driver.init_termios; + info->normal_termios = + cy_serial_driver.init_termios; + info->open_wait = 0; + info->close_wait = 0; + /* info->session */ + /* info->pgrp */ + info->read_status_mask = 0; + /* info->timeout */ + /* Bentson's vars */ + info->jiffies[0] = 0; + info->jiffies[1] = 0; + info->jiffies[2] = 0; + info->rflush_count = 0; + } + continue; + }else{ /* Cyclom-Y of some kind*/ + for (port = cinfo->first_line ; + port < cinfo->first_line + 4*cinfo->num_chips ; + port++) + { + info = &cy_port[port]; + info->magic = CYCLADES_MAGIC; + info->type = PORT_CIRRUS; + info->card = board; + info->line = port; + info->flags = STD_COM_FLAGS; + info->tty = 0; + info->xmit_fifo_size = 12; + info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS; + info->cor2 = CyETC; + info->cor3 = 0x08; /* _very_ small rcv threshold */ + info->cor4 = 0; + info->cor5 = 0; + info->tbpr = baud_bpr[13]; /* Tx BPR */ + info->tco = baud_co[13]; /* Tx CO */ + info->rbpr = baud_bpr[13]; /* Rx BPR */ + info->rco = baud_co[13]; /* Rx CO */ + info->close_delay = 0; + info->x_char = 0; + info->event = 0; + info->count = 0; +#ifdef SERIAL_DEBUG_COUNT + printk("cyc:cy_init(2) setting Y count to 0\n"); +#endif + info->blocked_open = 0; + info->default_threshold = 0; + info->default_timeout = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->callout_termios = + cy_callout_driver.init_termios; + info->normal_termios = + cy_serial_driver.init_termios; + info->open_wait = 0; + info->close_wait = 0; + /* info->session */ + /* info->pgrp */ + info->read_status_mask = + CyTIMEOUT| CySPECHAR| CyBREAK + | CyPARITY| CyFRAME| CyOVERRUN; + /* info->timeout */ + } + } + } + + if ( number_z_boards && !cyz_timeron){ + cyz_timeron++; + cyz_timerlist.expires = jiffies + 1; + add_timer(&cyz_timerlist); +#ifdef CY_PCI_DEBUG + printk("Cyclom-Z polling initialized\n"); #endif - info->blocked_open = 0; - info->default_threshold = 0; - info->default_timeout = 0; - info->tqueue.routine = do_softint; - info->tqueue.data = info; - info->callout_termios =cy_callout_driver.init_termios; - info->normal_termios = cy_serial_driver.init_termios; - info->open_wait = 0; - info->close_wait = 0; - /* info->session */ - /* info->pgrp */ - info->read_status_mask = CyTIMEOUT| CySPECHAR| CyBREAK - | CyPARITY| CyFRAME| CyOVERRUN; - /* info->timeout */ - } } + return 0; } /* cy_init */ #ifdef MODULE +/* See linux/drivers/char/riscom.c for ideas on how to + pass additional base addresses to the driver!!! */ int init_module(void) { return(cy_init()); -} +} /* init_module */ void cleanup_module(void) { - unsigned long flags; int i; + unsigned long flags; + + + if (cyz_timeron){ + cyz_timeron = 0; + del_timer(&cyz_timerlist); + } save_flags(flags); cli(); - remove_bh(CYCLADES_BH); + remove_bh(CYCLADES_BH); if (tty_unregister_driver(&cy_callout_driver)) - printk("Couldn't unregister Cyclom callout driver\n"); + printk("Couldn't unregister Cyclom callout driver\n"); if (tty_unregister_driver(&cy_serial_driver)) - printk("Couldn't unregister Cyclom serial driver\n"); + printk("Couldn't unregister Cyclom serial driver\n"); restore_flags(flags); for (i = 0; i < NR_CARDS; i++) { - if (cy_card[i].base_addr != 0) - { - free_irq(cy_card[i].irq,NULL); - } + if (cy_card[i].base_addr != 0 + && cy_card[i].irq) + { + free_irq(cy_card[i].irq,NULL); + } } -} -#endif - -/* - * --------------------------------------------------------------------- - * cy_detect_isa() - Probe for Cyclom-Y/ISA boards. - * sets global variables and return the number of ISA boards found. - * --------------------------------------------------------------------- - */ -__initfunc(int -cy_detect_isa()) -{ - unsigned int cy_isa_irq,nboard; - unsigned char *cy_isa_address; - unsigned short i,j,cy_isa_nchan; - - nboard = 0; - - /* scan the address table probing for Cyclom-Y/ISA boards */ - for (i = 0 ; i < NR_ISA_ADDRESSES ; i++) { - cy_isa_address = cy_isa_addresses[i]; - if (cy_isa_address == 0x0000) { - return(nboard); - } - - /* probe for CD1400... */ - cy_isa_nchan = 4 * cy_init_card(cy_isa_address,0); - if (cy_isa_nchan == 0) { - continue; - } - - /* find out the board's irq by probing */ - cy_isa_irq = do_auto_irq(cy_isa_address); - if (cy_isa_irq == 0) { - printk("Cyclom-Y/ISA found at 0x%x but the IRQ could not be detected.\n", - (unsigned int) cy_isa_address); - continue; - } - - if((cy_next_channel+cy_isa_nchan) > NR_PORTS) { - printk("Cyclom-Y/ISA found at 0x%x but no more channel structures are available.\n", - (unsigned int) cy_isa_address); - return(nboard); - } - /* fill the next cy_card structure available */ - for (j = 0 ; j < NR_CARDS ; j++) { - if (cy_card[j].base_addr == 0) break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclom-Y/ISA found at 0x%x but no more card structures are available.\n", - (unsigned int) cy_isa_address); - return(nboard); - } - - /* allocate IRQ */ - if(request_irq(cy_isa_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL)) - { - printk("Cyclom-Y/ISA found at 0x%x but could not allocate interrupt IRQ#%d.\n", - (unsigned int) cy_isa_address,cy_isa_irq); - return(nboard); - } - - /* set cy_card */ - cy_card[j].base_addr = (int) cy_isa_address; - cy_card[j].irq = (int) cy_isa_irq; - cy_card[j].bus_index = 0; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = cy_isa_nchan/4; - IRQ_cards[cy_isa_irq] = &cy_card[j]; - nboard++; - - /* print message */ - printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n", - j+1,(unsigned int) cy_isa_address, - (unsigned int)(cy_isa_address + 0x1fff), - cy_isa_irq,cy_isa_nchan,cy_next_channel); - cy_next_channel += cy_isa_nchan; - } - return(nboard); - -} - -/* - * --------------------------------------------------------------------- - * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI. - * sets global variables and return the number of PCI boards found. - * --------------------------------------------------------------------- - */ -__initfunc(int -cy_detect_pci()) +} /* cleanup_module */ +#else +/* called by linux/init/main.c to parse command line options */ +void +cy_setup(char *str, int *ints) { -#ifdef CONFIG_PCI - unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id; - unsigned long pci_intr_ctrl; - unsigned char cy_pci_irq; - unsigned int cy_pci_address, cy_pci_io; - unsigned short i,j,cy_pci_nchan; - unsigned short device_id,dev_index = 0,board_index = 0; - - if(pcibios_present() == 0) { /* PCI bus not present */ - return(0); - } - for (i = 0; i < NR_CARDS; i++) { - /* look for a Cyclom-Y card by vendor and device id */ - while((device_id = cy_pci_dev_id[dev_index]) != 0) { - if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES, - device_id,board_index, - &cyy_bus, &cyy_dev_fn) != 0) - { - dev_index++; /* try next device id */ - board_index = 0; - } else { - board_index++; - break; /* found a board */ - } - } - if (device_id == 0) break; - - /* read PCI configuration area */ - pcibios_read_config_byte(cyy_bus, cyy_dev_fn, - PCI_INTERRUPT_LINE, &cy_pci_irq); - pcibios_read_config_dword(cyy_bus, cyy_dev_fn, - PCI_BASE_ADDRESS_1, &cy_pci_io); - pcibios_read_config_dword(cyy_bus, cyy_dev_fn, - PCI_BASE_ADDRESS_2, &cy_pci_address); - pcibios_read_config_byte(cyy_bus, cyy_dev_fn, - PCI_REVISION_ID, &cyy_rev_id); - cy_pci_address &= 0xfffffff0; - if ((ulong)cy_pci_address >= 0x100000) { /* above 1M? */ - cy_pci_address = - (unsigned int) ioremap(cy_pci_address,0x4000); - } - cy_pci_io &= 0xfffffffc; - cy_pci_nchan = 4 * cy_init_card((unsigned char *) - cy_pci_address,1); - if(cy_pci_nchan == 0) { - printk("Cyclom-Y PCI host card with no Serial-Modules at 0x%x.\n", - (unsigned int) cy_pci_address); - continue; - } - if((cy_next_channel+cy_pci_nchan) > NR_PORTS) { - printk("Cyclom-Y/PCI found at 0x%x but no more channel structures are available.\n", - (unsigned int) cy_pci_address); - return(i); - } -#ifdef CY_PCI_DEBUG - printk("Cyclom-Ye/PCI #%d (bus=0x0%x, pci_id=0x%x, rev_id=%d).\n", - i+1,cyy_bus,cyy_dev_fn,cyy_rev_id); - printk("Cyclom-Ye/PCI: found at 0x%x, IRQ%d, ioaddr = 0x%lx.\n", - cy_pci_address,(int)cy_pci_irq,cy_pci_io); -#endif - /* fill the next cy_card structure available */ - for (j = 0 ; j < NR_CARDS ; j++) { - if (cy_card[j].base_addr == 0) break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclom-Y/PCI found at 0x%x but no more card structures are available.\n", - (unsigned int) cy_pci_address); - return(i); - } - - /* allocate IRQ */ - if(request_irq(cy_pci_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL)) - { - printk("Cyclom-Y/PCI found at 0x%x but could not allocate interrupt IRQ%d.\n", - (unsigned int) cy_pci_address,cy_pci_irq); - return(i); - } + int i, j; - /* set cy_card */ - cy_card[j].base_addr = (int) cy_pci_address; - cy_card[j].irq = (int) cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = cy_pci_nchan/4; - IRQ_cards[cy_pci_irq] = &cy_card[j]; - - /* enable interrupts in the PCI interface */ - outw(inw(cy_pci_io+0x68)|0x0900,cy_pci_io+0x68); - pci_intr_ctrl = (unsigned long)(inw(cy_pci_io+0x68) | inw(cy_pci_io+0x6a)<<16); - - /* print message */ - printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n", - j+1,(unsigned int) cy_pci_address, - (unsigned int)(cy_pci_address + 0x3fff), - (int)cy_pci_irq,cy_pci_nchan,cy_next_channel); + for (i = 0 ; i < NR_ISA_ADDRS ; i++) { + if (cy_isa_addresses[i] == 0) break; + } + for (j = 1; j <= ints[0]; j++){ + if ( i < NR_ISA_ADDRS ){ + cy_isa_addresses[i++] = (unsigned char *)(ints[j]); + } + } - cy_next_channel += cy_pci_nchan; - } - return(i); -#else - return(0); -#endif /* ifdef CONFIG_PCI */ -} +} /* cy_setup */ +#endif #ifdef CYCLOM_SHOW_STATUS @@ -3181,7 +4614,8 @@ printk(" cy_port\n"); printk(" card line flags = %d %d %x\n", info->card, info->line, info->flags); - printk(" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n", + printk(" *tty read_status_mask timeout xmit_fifo_size ", + printk("= %lx %x %x %x\n", (long)info->tty, info->read_status_mask, info->timeout, info->xmit_fifo_size); printk(" cor1,cor2,cor3,cor4,cor5 = %x %x %x %x %x\n", @@ -3198,59 +4632,60 @@ save_flags(flags); cli(); - base_addr = (unsigned char*) - (cy_card[card].base_addr + (cy_chip_offset[chip]< /* guess what */ #include #include +#include #include #include @@ -529,582 +530,7 @@ static int init_error = 0; -void dsp56k_init(void) -{ - if(!ATARIHW_PRESENT(DSP56K)) { - init_error = 1; - printk("DSP56k driver: Hardware not present\n"); - return; - } - -#ifndef MODULE - if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) { - printk("DSP56k driver: Unable to register driver\n"); - return; - } -#endif /* !MODULE */ - - dsp56k.in_use = 0; - - printk("DSP56k driver installed\n"); -} - -#ifdef MODULE -int init_module(void) -{ - int r; - - init_error = 0; - dsp56k_init(); - if(init_error) - return -EPERM; - - r = register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops); - if(r) { - printk("DSP56k driver: Unable to register driver\n"); - return r; - } - - return 0; -} - -void cleanup_module(void) -{ - unregister_chrdev(DSP56K_MAJOR, "dsp56k"); -} -#endif /* MODULE */ -/* - * The DSP56001 Device Driver, saviour of the Free World(tm) - * - * Authors: Fredrik Noring - * lars brinkhoff - * Tomas Berndtsson - * - * First version May 1996 - * - * History: - * 97-01-29 Tomas Berndtsson, - * Integrated with Linux 2.1.21 kernel sources. - * 97-02-15 Tomas Berndtsson, - * Fixed for kernel 2.1.26 - * - * BUGS: - * Hmm... there must be something here :) - * - * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include /* for kmalloc() and kfree() */ -#include /* for struct wait_queue etc */ -#include -#include -#include -#include /* guess what */ -#include -#include - -#include -#include -#include -#include /* For put_user and get_user */ - -#include - -/* minor devices */ -#define DSP56K_DEV_56001 0 /* The only device so far */ - -#define TIMEOUT 10 /* Host port timeout in number of tries */ -#define MAXIO 2048 /* Maximum number of words before sleep */ -#define DSP56K_MAX_BINARY_LENGTH (3*64*1024) - -#define DSP56K_TX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_TREQ -#define DSP56K_RX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_RREQ -#define DSP56K_TX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ -#define DSP56K_RX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ - -#define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE) -#define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF) - -#define max(a,b) ((a) > (b) ? (a) : (b)) -#define min(a,b) ((a) < (b) ? (a) : (b)) - -#define wait_some(n) \ -{ \ - current->state = TASK_INTERRUPTIBLE; \ - current->timeout = jiffies + n; \ - schedule(); \ -} - -#define handshake(count, maxio, timeout, ENABLE, f) \ -{ \ - long i, t, m; \ - while (count > 0) { \ - m = min(count, maxio); \ - for (i = 0; i < m; i++) { \ - for (t = 0; t < timeout && !ENABLE; t++) \ - wait_some(2); \ - if(!ENABLE) \ - return -EIO; \ - f; \ - } \ - count -= m; \ - if (m == maxio) wait_some(2); \ - } \ -} - -#define tx_wait(n) \ -{ \ - int t; \ - for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \ - wait_some(1); \ - if(!DSP56K_TRANSMIT) { \ - return -EIO; \ - } \ -} - -#define rx_wait(n) \ -{ \ - int t; \ - for(t = 0; t < n && !DSP56K_RECEIVE; t++) \ - wait_some(1); \ - if(!DSP56K_RECEIVE) { \ - return -EIO; \ - } \ -} - -/* DSP56001 bootstrap code */ -static char bootstrap[] = { - 0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4, - 0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47, - 0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00, - 0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe, - 0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0, - 0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a, - 0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4, - 0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01, - 0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08, - 0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46, - 0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa, - 0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00, - 0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9, - 0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80, - 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a, - 0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0, - 0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4, - 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a, - 0xf0, 0x80, 0x00, 0x7e, 0xad}; -static int sizeof_bootstrap = 375; - - -static struct dsp56k_device { - int in_use; - long maxio, timeout; - int tx_wsize, rx_wsize; -} dsp56k; - -static int dsp56k_reset(void) -{ - u_char status; - - /* Power down the DSP */ - sound_ym.rd_data_reg_sel = 14; - status = sound_ym.rd_data_reg_sel & 0xef; - sound_ym.wd_data = status; - sound_ym.wd_data = status | 0x10; - - udelay(10); - - /* Power up the DSP */ - sound_ym.rd_data_reg_sel = 14; - sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef; - - return 0; -} - -static int dsp56k_upload(u_char *bin, int len) -{ - int i; - u_char *p; - - dsp56k_reset(); - - p = bootstrap; - for (i = 0; i < sizeof_bootstrap/3; i++) { - /* tx_wait(10); */ - dsp56k_host_interface.data.b[1] = *p++; - dsp56k_host_interface.data.b[2] = *p++; - dsp56k_host_interface.data.b[3] = *p++; - } - for (; i < 512; i++) { - /* tx_wait(10); */ - dsp56k_host_interface.data.b[1] = 0; - dsp56k_host_interface.data.b[2] = 0; - dsp56k_host_interface.data.b[3] = 0; - } - - for (i = 0; i < len; i++) { - tx_wait(10); - get_user(dsp56k_host_interface.data.b[1], bin++); - get_user(dsp56k_host_interface.data.b[2], bin++); - get_user(dsp56k_host_interface.data.b[3], bin++); - } - - tx_wait(10); - dsp56k_host_interface.data.l = 3; /* Magic execute */ - - return 0; -} - -static long dsp56k_read(struct inode *inode, struct file *file, - char *buf, unsigned long count) -{ - int dev = MINOR(inode->i_rdev) & 0x0f; - - switch(dev) - { - case DSP56K_DEV_56001: - { - - long n; - - /* Don't do anything if nothing is to be done */ - if (!count) return 0; - - n = 0; - switch (dsp56k.rx_wsize) { - case 1: /* 8 bit */ - { - handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, - put_user(dsp56k_host_interface.data.b[3], buf+n++)); - return n; - } - case 2: /* 16 bit */ - { - short *data; - - count /= 2; - data = (short*) buf; - handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, - put_user(dsp56k_host_interface.data.w[1], data+n++)); - return 2*n; - } - case 3: /* 24 bit */ - { - count /= 3; - handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, - put_user(dsp56k_host_interface.data.b[1], buf+n++); - put_user(dsp56k_host_interface.data.b[2], buf+n++); - put_user(dsp56k_host_interface.data.b[3], buf+n++)); - return 3*n; - } - case 4: /* 32 bit */ - { - long *data; - - count /= 4; - data = (long*) buf; - handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, - put_user(dsp56k_host_interface.data.l, data+n++)); - return 4*n; - } - } - return -EFAULT; - } - - default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); - return -ENXIO; - } -} - -static long dsp56k_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count) -{ - int dev = MINOR(inode->i_rdev) & 0x0f; - - switch(dev) - { - case DSP56K_DEV_56001: - { - long n; - - /* Don't do anything if nothing is to be done */ - if (!count) return 0; - - n = 0; - switch (dsp56k.tx_wsize) { - case 1: /* 8 bit */ - { - handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, - get_user(dsp56k_host_interface.data.b[3], buf+n++)); - return n; - } - case 2: /* 16 bit */ - { - short *data; - - count /= 2; - data = (short*) buf; - handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, - get_user(dsp56k_host_interface.data.w[1], data+n++)); - return 2*n; - } - case 3: /* 24 bit */ - { - count /= 3; - handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, - get_user(dsp56k_host_interface.data.b[1], buf+n++); - get_user(dsp56k_host_interface.data.b[2], buf+n++); - get_user(dsp56k_host_interface.data.b[3], buf+n++)); - return 3*n; - } - case 4: /* 32 bit */ - { - long *data; - - count /= 4; - data = (long*) buf; - handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, - get_user(dsp56k_host_interface.data.l, data+n++)); - return 4*n; - } - } - - return -EFAULT; - } - default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); - return -ENXIO; - } -} - -static int dsp56k_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int dev = MINOR(inode->i_rdev) & 0x0f; - - switch(dev) - { - case DSP56K_DEV_56001: - - switch(cmd) { - case DSP56K_UPLOAD: - { - char *bin; - int r, len; - struct dsp56k_upload *binary = (struct dsp56k_upload *) arg; - - if(get_user(len, &binary->len) < 0) - return -EFAULT; - if(get_user(bin, &binary->bin) < 0) - return -EFAULT; - - if (len == 0) { - return -EINVAL; /* nothing to upload?!? */ - } - if (len > DSP56K_MAX_BINARY_LENGTH) { - return -EINVAL; - } - - r = dsp56k_upload(bin, len); - if (r < 0) { - return r; - } - - break; - } - case DSP56K_SET_TX_WSIZE: - if (arg > 4 || arg < 1) - return -EINVAL; - dsp56k.tx_wsize = (int) arg; - break; - case DSP56K_SET_RX_WSIZE: - if (arg > 4 || arg < 1) - return -EINVAL; - dsp56k.rx_wsize = (int) arg; - break; - case DSP56K_HOST_FLAGS: - { - int dir, out, status; - struct dsp56k_host_flags *hf = (struct dsp56k_host_flags*) arg; - - if(get_user(dir, &hf->dir) < 0) - return -EFAULT; - if(get_user(out, &hf->out) < 0) - return -EFAULT; - - if ((dir & 0x1) && (out & 0x1)) - dsp56k_host_interface.icr |= DSP56K_ICR_HF0; - else if (dir & 0x1) - dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0; - if ((dir & 0x2) && (out & 0x2)) - dsp56k_host_interface.icr |= DSP56K_ICR_HF1; - else if (dir & 0x2) - dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1; - - status = 0; - if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1; - if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2; - if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4; - if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8; - - if(put_user(status, &hf->status) < 0) - return -EFAULT; - break; - } - case DSP56K_HOST_CMD: - if (arg > 31 || arg < 0) - return -EINVAL; - dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) | - DSP56K_CVR_HC); - break; - default: - return -EINVAL; - } - return 0; - - default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); - return -ENXIO; - } -} - -/* As of 2.1.26 this should be dsp56k_poll, - * but how do I then check device minor number? - * Do I need this function at all??? - */ -#ifdef 0 -static int dsp56k_select(struct inode *inode, struct file *file, int sel_type, - select_table *wait) -{ - int dev = MINOR(inode->i_rdev) & 0x0f; - - switch(dev) - { - case DSP56K_DEV_56001: - - switch(sel_type) { - case SEL_IN: /* read */ - return 1; - case SEL_OUT: /* write */ - return 1; - default: - return 1; - } - - default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); - return -ENXIO; - } -} -#endif - -static int dsp56k_open(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev) & 0x0f; - - switch(dev) - { - case DSP56K_DEV_56001: - - if (dsp56k.in_use) - return -EBUSY; - - dsp56k.in_use = 1; - dsp56k.timeout = TIMEOUT; - dsp56k.maxio = MAXIO; - dsp56k.rx_wsize = dsp56k.tx_wsize = 4; - - DSP56K_TX_INT_OFF; - DSP56K_RX_INT_OFF; - - /* Zero host flags */ - dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0; - dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1; - - break; - - default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); - return -ENXIO; - } - -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif /* MODULE */ - - return 0; -} - -static void dsp56k_release(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev) & 0x0f; - - switch(dev) - { - case DSP56K_DEV_56001: - - dsp56k.in_use = 0; - - break; - default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); - return; - } - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif /* MODULE */ -} - -static struct file_operations dsp56k_fops = { - NULL, /* no special dsp56k_lseek */ - dsp56k_read, - dsp56k_write, - NULL, /* no special dsp56k_readdir */ - NULL, /* dsp56k_poll? */ - dsp56k_ioctl, - NULL, /* no special dsp56k_mmap */ - dsp56k_open, - dsp56k_release, - NULL, /* no special dsp56k_fsync */ - NULL, /* no special dsp56k_fasync */ - NULL, /* no special dsp56k_check_media_change */ - NULL /* no special dsp56k_revalidate */ -}; - - -/****** Init and module functions ******/ - -static int init_error = 0; - -void dsp56k_init(void) +__initfunc(void dsp56k_init(void)) { if(!ATARIHW_PRESENT(DSP56K)) { init_error = 1; diff -u --recursive --new-file v2.1.36/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.1.36/linux/drivers/char/epca.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/epca.c Mon May 12 10:35:39 1997 @@ -0,0 +1,4313 @@ +/* + + + Copyright (C) 1996 Digi International. + + For technical support please email digiLinux@dgii.com or + call Digi tech support at (612) 912-3456 + + Much of this design and code came from epca.c which was + copyright (C) 1994, 1995 Troy De Jongh, and subsquently + modified by David Nugent, Christoph Lameter, Mike McLagan. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +--------------------------------------------------------------------------- */ +/* See README.epca for change history --DAT*/ + + +#ifdef MODVERSIONS +#define MODULE +#endif + +/* ----------------------------------------------------------------------- + This way modules should work regardless if they defined MODULE or + MODVERSIONS. (MODVERSIONS is for the newer kernels ... +-------------------------------------------------------------------------- */ + +#ifdef MODULE +#include +#endif /* MODULE */ + +#include + +#define NEW_MODULES + +#ifdef NEW_MODULES +#ifdef MODVERSIONS +#include +#endif /* MODVERSIONS */ +#endif /* NEW_MODULES */ + +#ifdef MODULE +#include +#endif /* MODULE */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MODULE +#ifndef NEW_MODULES +char kernel_version[]=UTS_RELEASE; +#endif /* NEW_MODULE */ +#endif /* MODULE */ + + +#ifdef CONFIG_PCI +#define ENABLE_PCI +#endif /* CONFIG_PCI */ + + + +#include +#define putUser(arg1, arg2) put_user(arg1, (unsigned long *)arg2) +#define getUser(arg1, arg2) get_user(arg1, (unsigned int *)arg2) + + + +#ifdef ENABLE_PCI +#include +#include +#include +#endif /* ENABLE_PCI */ + +#include +#include +#include +#include + +/* ---------------------- Begin defines ------------------------ */ + +#define VERSION "1.1.0" + +/* This major needs to be submitted to Linux to join the majors list */ + +#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */ + + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAXCARDS 7 +#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg) + +/* ----------------- Begin global definitions ------------------- */ + +static char mesg[100]; +static int pc_refcount, nbdevs = 0, num_cards = 0, liloconfig = 0; +static int digi_poller_inhibited = 1 ; + +static int setup_error_code = 0; +static int invalid_lilo_config = 0; + +/* ----------------------------------------------------------------------- + MAXBOARDS is typically 12, but ISA and EISA cards are restricted to + 7 below. +--------------------------------------------------------------------------*/ +static struct board_info boards[7]; + + +/* ------------- Begin structures used for driver registeration ---------- */ + +struct tty_driver pc_driver; +struct tty_driver pc_callout; +struct tty_driver pc_info; + +/* The below structures are used to initialize the tty_driver structures. */ + +/* ------------------------------------------------------------------------- + Note : MAX_ALLOC is currently limited to 0x100. This restriction is + placed on us by Linux not Digi. +----------------------------------------------------------------------------*/ +static struct tty_struct *pc_table[MAX_ALLOC]; +static struct termios *pc_termios[MAX_ALLOC]; +static struct termios *pc_termios_locked[MAX_ALLOC]; + + +/* ------------------ Begin Digi specific structures -------------------- */ + +/* ------------------------------------------------------------------------ + digi_channels represents an array of structures that keep track of + each channel of the Digi product. Information such as transmit and + receive pointers, termio data, and signal definitions (DTR, CTS, etc ...) + are stored here. This structure is NOT used to overlay the cards + physical channel structure. +-------------------------------------------------------------------------- */ + +static struct channel digi_channels[MAX_ALLOC]; + +/* ------------------------------------------------------------------------ + card_ptr is an array used to hold the address of the + first channel structure of each card. This array will hold + the addresses of various channels located in digi_channels. +-------------------------------------------------------------------------- */ +static struct channel *card_ptr[MAXCARDS]; + +/* ---------------------- Begin function prototypes --------------------- */ + +/* ---------------------------------------------------------------------- + Begin generic memory functions. These functions will be alias + (point at) more specific functions dependant on the board being + configured. +----------------------------------------------------------------------- */ + + +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#endif /* MODULE */ + +static inline void memwinon(struct board_info *b, unsigned int win); +static inline void memwinoff(struct board_info *b, unsigned int win); +static inline void globalwinon(struct channel *ch); +static inline void rxwinon(struct channel *ch); +static inline void txwinon(struct channel *ch); +static inline void memoff(struct channel *ch); +static inline void assertgwinon(struct channel *ch); +static inline void assertmemoff(struct channel *ch); + +/* ---- Begin more 'specific' memory functions for cx_like products --- */ + +static inline void pcxem_memwinon(struct board_info *b, unsigned int win); +static inline void pcxem_memwinoff(struct board_info *b, unsigned int win); +static inline void pcxem_globalwinon(struct channel *ch); +static inline void pcxem_rxwinon(struct channel *ch); +static inline void pcxem_txwinon(struct channel *ch); +static inline void pcxem_memoff(struct channel *ch); + +/* ------ Begin more 'specific' memory functions for the pcxe ------- */ + +static inline void pcxe_memwinon(struct board_info *b, unsigned int win); +static inline void pcxe_memwinoff(struct board_info *b, unsigned int win); +static inline void pcxe_globalwinon(struct channel *ch); +static inline void pcxe_rxwinon(struct channel *ch); +static inline void pcxe_txwinon(struct channel *ch); +static inline void pcxe_memoff(struct channel *ch); + +/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */ +/* Note : pc64xe and pcxi share the same windowing routines */ + +static inline void pcxi_memwinon(struct board_info *b, unsigned int win); +static inline void pcxi_memwinoff(struct board_info *b, unsigned int win); +static inline void pcxi_globalwinon(struct channel *ch); +static inline void pcxi_rxwinon(struct channel *ch); +static inline void pcxi_txwinon(struct channel *ch); +static inline void pcxi_memoff(struct channel *ch); + +/* - Begin 'specific' do nothing memory functions needed for some cards - */ + +static inline void dummy_memwinon(struct board_info *b, unsigned int win); +static inline void dummy_memwinoff(struct board_info *b, unsigned int win); +static inline void dummy_globalwinon(struct channel *ch); +static inline void dummy_rxwinon(struct channel *ch); +static inline void dummy_txwinon(struct channel *ch); +static inline void dummy_memoff(struct channel *ch); +static inline void dummy_assertgwinon(struct channel *ch); +static inline void dummy_assertmemoff(struct channel *ch); + +/* ------------------- Begin declare functions ----------------------- */ + +static inline struct channel *verifyChannel(register struct tty_struct *); +static inline void pc_sched_event(struct channel *, int); +static void epca_error(int, char *); +static void pc_close(struct tty_struct *, struct file *); +static void shutdown(struct channel *); +static void pc_hangup(struct tty_struct *); +static void pc_put_char(struct tty_struct *, unsigned char); +static int pc_write_room(struct tty_struct *); +static int pc_chars_in_buffer(struct tty_struct *); +static void pc_flush_buffer(struct tty_struct *); +static void pc_flush_chars(struct tty_struct *); +static int block_til_ready(struct tty_struct *, struct file *, + struct channel *); +static int pc_open(struct tty_struct *, struct file *); +static void post_fep_init(unsigned int crd); +static void epcapoll(unsigned long); +static void doevent(int); +static void fepcmd(struct channel *, int, int, int, int, int); +static unsigned termios2digi_h(struct channel *ch, unsigned); +static unsigned termios2digi_i(struct channel *ch, unsigned); +static unsigned termios2digi_c(struct channel *ch, unsigned); +static void epcaparam(struct tty_struct *, struct channel *); +static void receive_data(struct channel *); +static int pc_ioctl(struct tty_struct *, struct file *, + unsigned int, unsigned long); +static void pc_set_termios(struct tty_struct *, struct termios *); +static void do_softint(void *); +static void pc_stop(struct tty_struct *); +static void pc_start(struct tty_struct *); +static void pc_throttle(struct tty_struct * tty); +static void pc_unthrottle(struct tty_struct *tty); +static void digi_send_break(struct channel *ch, int msec); +static void setup_empty_event(struct tty_struct *tty, struct channel *ch); +void epca_setup(char *, int *); +void console_print(const char *); + +static int get_termio(struct tty_struct *, struct termio *); +static int pc_write(struct tty_struct *, int, const unsigned char *, int); +int pc_init(void); + +#ifdef ENABLE_PCI +static int init_PCI(int); +static int get_PCI_configuration(char, char, unsigned int *, unsigned int *, + unsigned int *, unsigned int *, + unsigned int *, unsigned int *); +#endif /* ENABLE_PCI */ + + +/* ------------------------------------------------------------------ + Table of functions for each board to handle memory. Mantaining + parallelism is a *very* good idea here. The idea is for the + runtime code to blindly call these functions, not knowing/caring + about the underlying hardware. This stuff should contain no + conditionals; if more functionality is needed a different entry + should be established. These calls are the interface calls and + are the only functions that should be accessed. Anyone caught + making direct calls deserves what they get. +-------------------------------------------------------------------- */ + +static inline void memwinon(struct board_info *b, unsigned int win) +{ + (b->memwinon)(b, win); +} + +static inline void memwinoff(struct board_info *b, unsigned int win) +{ + (b->memwinoff)(b, win); +} + +static inline void globalwinon(struct channel *ch) +{ + (ch->board->globalwinon)(ch); +} + +static inline void rxwinon(struct channel *ch) +{ + (ch->board->rxwinon)(ch); +} + +static inline void txwinon(struct channel *ch) +{ + (ch->board->txwinon)(ch); +} + +static inline void memoff(struct channel *ch) +{ + (ch->board->memoff)(ch); +} +static inline void assertgwinon(struct channel *ch) +{ + (ch->board->assertgwinon)(ch); +} + +static inline void assertmemoff(struct channel *ch) +{ + (ch->board->assertmemoff)(ch); +} + +/* --------------------------------------------------------- + PCXEM windowing is the same as that used in the PCXR + and CX series cards. +------------------------------------------------------------ */ + +static inline void pcxem_memwinon(struct board_info *b, unsigned int win) +{ + outb_p(FEPWIN|win, (int)b->port + 1); +} + +static inline void pcxem_memwinoff(struct board_info *b, unsigned int win) +{ + outb_p(0, (int)b->port + 1); +} + +static inline void pcxem_globalwinon(struct channel *ch) +{ + outb_p( FEPWIN, (int)ch->board->port + 1); +} + +static inline void pcxem_rxwinon(struct channel *ch) +{ + outb_p(ch->rxwin, (int)ch->board->port + 1); +} + +static inline void pcxem_txwinon(struct channel *ch) +{ + outb_p(ch->txwin, (int)ch->board->port + 1); +} + +static inline void pcxem_memoff(struct channel *ch) +{ + outb_p(0, (int)ch->board->port + 1); +} + +/* ----------------- Begin pcxe memory window stuff ------------------ */ + +static inline void pcxe_memwinon(struct board_info *b, unsigned int win) +{ + outb_p(FEPWIN | win, (int)b->port + 1); +} + +static inline void pcxe_memwinoff(struct board_info *b, unsigned int win) +{ + outb_p(inb((int)b->port) & ~FEPMEM, + (int)b->port + 1); + outb_p(0, (int)b->port + 1); +} + +static inline void pcxe_globalwinon(struct channel *ch) +{ + outb_p( FEPWIN, (int)ch->board->port + 1); +} + +static inline void pcxe_rxwinon(struct channel *ch) +{ + outb_p(ch->rxwin, (int)ch->board->port + 1); +} + +static inline void pcxe_txwinon(struct channel *ch) +{ + outb_p(ch->txwin, (int)ch->board->port + 1); +} + +static inline void pcxe_memoff(struct channel *ch) +{ + outb_p(0, (int)ch->board->port); + outb_p(0, (int)ch->board->port + 1); +} + +/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */ + +static inline void pcxi_memwinon(struct board_info *b, unsigned int win) +{ + outb_p(inb((int)b->port) | FEPMEM, (int)b->port); +} + +static inline void pcxi_memwinoff(struct board_info *b, unsigned int win) +{ + outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port); +} + +static inline void pcxi_globalwinon(struct channel *ch) +{ + outb_p(FEPMEM, (int)ch->board->port); +} + +static inline void pcxi_rxwinon(struct channel *ch) +{ + outb_p(FEPMEM, (int)ch->board->port); +} + +static inline void pcxi_txwinon(struct channel *ch) +{ + outb_p(FEPMEM, (int)ch->board->port); +} + +static inline void pcxi_memoff(struct channel *ch) +{ + outb_p(0, (int)ch->board->port); +} + +static inline void pcxi_assertgwinon(struct channel *ch) +{ + epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off"); +} + +static inline void pcxi_assertmemoff(struct channel *ch) +{ + epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on"); +} + + +/* ---------------------------------------------------------------------- + Not all of the cards need specific memory windowing routines. Some + cards (Such as PCI) needs no windowing routines at all. We provide + these do nothing routines so that the same code base can be used. + The driver will ALWAYS call a windowing routine if it thinks it needs + to; regardless of the card. However, dependant on the card the routine + may or may not do anything. +---------------------------------------------------------------------------*/ + +static inline void dummy_memwinon(struct board_info *b, unsigned int win) +{ +} + +static inline void dummy_memwinoff(struct board_info *b, unsigned int win) +{ +} + +static inline void dummy_globalwinon(struct channel *ch) +{ +} + +static inline void dummy_rxwinon(struct channel *ch) +{ +} + +static inline void dummy_txwinon(struct channel *ch) +{ +} + +static inline void dummy_memoff(struct channel *ch) +{ +} + +static inline void dummy_assertgwinon(struct channel *ch) +{ +} + +static inline void dummy_assertmemoff(struct channel *ch) +{ +} + +/* ----------------- Begin verifyChannel function ----------------------- */ +static inline struct channel *verifyChannel(register struct tty_struct *tty) +{ /* Begin verifyChannel */ + + /* -------------------------------------------------------------------- + This routine basically provides a sanity check. It insures that + the channel returned is within the proper range of addresses as + well as properly initialized. If some bogus info gets passed in + through tty->driver_data this should catch it. + --------------------------------------------------------------------- */ + + if (tty) + { /* Begin if tty */ + + register struct channel *ch = (struct channel *)tty->driver_data; + + if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) + { + if (ch->magic == EPCA_MAGIC) + return ch; + } + + } /* End if tty */ + + /* Else return a NULL for invalid */ + return NULL; + +} /* End verifyChannel */ + +/* ------------------ Begin pc_sched_event ------------------------- */ + +static inline void pc_sched_event(struct channel *ch, int event) +{ /* Begin pc_sched_event */ + + + /* ---------------------------------------------------------------------- + We call this to schedule interrupt processing on some event. The + kernel sees our request and calls the related routine in OUR driver. + -------------------------------------------------------------------------*/ + + ch->event |= 1 << event; + queue_task(&ch->tqueue, &tq_scheduler); + + +} /* End pc_sched_event */ + +/* ------------------ Begin epca_error ------------------------- */ + +static void epca_error(int line, char *msg) +{ /* Begin epca_error */ + + printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg); + return; + +} /* End epca_error */ + +/* ------------------ Begin pc_close ------------------------- */ +static void pc_close(struct tty_struct * tty, struct file * filp) +{ /* Begin pc_close */ + + struct channel *ch; + unsigned long flags; + + if (tty->driver.subtype == SERIAL_TYPE_INFO) + { + return; + } + + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { /* Begin if ch != NULL */ + + save_flags(flags); + cli(); + + if (tty_hung_up_p(filp)) + { + restore_flags(flags); + return; + } + + /* Check to see if the channel is open more than once */ + if (ch->count-- > 1) + { /* Begin channel is open more than once */ + + /* ------------------------------------------------------------- + Return without doing anything. Someone might still be using + the channel. + ---------------------------------------------------------------- */ + + restore_flags(flags); + return; + } /* End channel is open more than once */ + + /* Port open only once go ahead with shutdown & reset */ + + if (ch->count < 0) + { + ch->count = 0; + } + + /* --------------------------------------------------------------- + Let the rest of the driver know the channel is being closed. + This becomes important if an open is attempted before close + is finished. + ------------------------------------------------------------------ */ + + ch->asyncflags |= ASYNC_CLOSING; + + /* ------------------------------------------------------------- + Save the termios structure, since this port may have + separate termios for callout and dialin. + --------------------------------------------------------------- */ + + if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) + ch->normal_termios = *tty->termios; + + if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) + ch->callout_termios = *tty->termios; + + tty->closing = 1; + + if (ch->asyncflags & ASYNC_INITIALIZED) + { + /* Setup an event to indicate when the transmit buffer empties */ + setup_empty_event(tty, ch); + tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ + } + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + shutdown(ch); + tty->closing = 0; + ch->event = 0; + ch->tty = NULL; + + if (ch->blocked_open) + { /* Begin if blocked_open */ + + if (ch->close_delay) + { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + ch->close_delay; + schedule(); + } + + wake_up_interruptible(&ch->open_wait); + + } /* End if blocked_open */ + + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | + ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING); + wake_up_interruptible(&ch->close_wait); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + restore_flags(flags); + + } /* End if ch != NULL */ + +} /* End pc_close */ + +/* ------------------ Begin shutdown ------------------------- */ + +static void shutdown(struct channel *ch) +{ /* Begin shutdown */ + + unsigned long flags; + struct tty_struct *tty; + volatile struct board_chan *bc; + + if (!(ch->asyncflags & ASYNC_INITIALIZED)) + return; + + save_flags(flags); + cli(); + globalwinon(ch); + + bc = ch->brdchan; + + /* ------------------------------------------------------------------ + In order for an event to be generated on the receipt of data the + idata flag must be set. Since we are shutting down, this is not + necessary clear this flag. + --------------------------------------------------------------------- */ + + if (bc) + bc->idata = 0; + + tty = ch->tty; + + /* ---------------------------------------------------------------- + If we're a modem control device and HUPCL is on, drop RTS & DTR. + ------------------------------------------------------------------ */ + + if (tty->termios->c_cflag & HUPCL) + { + ch->omodem &= ~(ch->m_rts | ch->m_dtr); + fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1); + } + + memoff(ch); + + /* ------------------------------------------------------------------ + The channel has officialy been closed. The next time it is opened + it will have to reinitialized. Set a flag to indicate this. + ---------------------------------------------------------------------- */ + + /* Prevent future Digi programmed interrupts from coming active */ + + ch->asyncflags &= ~ASYNC_INITIALIZED; + restore_flags(flags); + +} /* End shutdown */ + +/* ------------------ Begin pc_hangup ------------------------- */ + +static void pc_hangup(struct tty_struct *tty) +{ /* Begin pc_hangup */ + + struct channel *ch; + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { /* Begin if ch != NULL */ + + unsigned long flags; + + save_flags(flags); + cli(); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + shutdown(ch); + +#ifdef MODULE + if (ch->count) + MOD_DEC_USE_COUNT; +#endif /* MODULE */ + + + ch->tty = NULL; + ch->event = 0; + ch->count = 0; + restore_flags(flags); + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CALLOUT_ACTIVE); + wake_up_interruptible(&ch->open_wait); + + } /* End if ch != NULL */ + +} /* End pc_hangup */ + +/* ------------------ Begin pc_write ------------------------- */ + +static int pc_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int bytesAvailable) +{ /* Begin pc_write */ + + register unsigned int head, tail; + register int dataLen; + register int size; + register int amountCopied; + + + struct channel *ch; + unsigned long flags; + int remain; + volatile struct board_chan *bc; + + + /* ---------------------------------------------------------------- + pc_write is primarily called directly by the kernel routine + tty_write (Though it can also be called by put_char) found in + tty_io.c. pc_write is passed a line discipline buffer where + the data to be written out is stored. The line discipline + implementation itself is done at the kernel level and is not + brought into the driver. + ------------------------------------------------------------------- */ + + /* Stop users from hurting themselves on control minor */ + + if (tty->driver.subtype == SERIAL_TYPE_INFO) + { + return (0) ; + } + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) == NULL) + return 0; + + /* Make a pointer to the channel data structure found on the board. */ + + bc = ch->brdchan; + size = ch->txbufsize; + + if (from_user) + { /* Begin from_user */ + + save_flags(flags); + cli(); + + globalwinon(ch); + + /* ----------------------------------------------------------------- + Anding against size will wrap the pointer back to its begining + position if it is necessary. This will only work if size is + a power of 2 which should always be the case. Size is determined + by the cards on board FEP/OS. + -------------------------------------------------------------------- */ + + /* head refers to the next empty location in which data may be stored */ + + head = bc->tin & (size - 1); + + /* tail refers to the next data byte to be transmitted */ + + tail = bc->tout; + + /* Consider changing this to a do statement to make sure */ + + if (tail != bc->tout) + tail = bc->tout; + + /* ------------------------------------------------------------------ + Anding against size will wrap the pointer back to its begining + position if it is necessary. This will only work if size is + a power of 2 which should always be the case. Size is determined + by the cards on board FEP/OS. + --------------------------------------------------------------------- */ + + tail &= (size - 1); + + /* ----------------------------------------------------------------- + Two situations can affect how space in the transmit buffer + is calculated. You can have a situation where the transmit + in pointer (tin) head has wrapped around and actually has a + lower address than the transmit out pointer (tout) tail; or + the transmit in pointer (tin) head will not be wrapped around + yet, and have a higher address than the transmit out pointer + (tout) tail. Obviously space available in the transmit buffer + is calculated differently for each case. + + Example 1: + + Consider a 10 byte buffer where head is a pointer to the next + empty location in the buffer and tail is a pointer to the next + byte to transmit. In this example head will not have wrapped + around and therefore head > tail. + + 0 1 2 3 4 5 6 7 8 9 + tail head + + The above diagram shows that buffer locations 2,3,4,5 and 6 have + data to be transmited, while head points at the next empty + location. To calculate how much space is available first we have + to determine if the head pointer (tin) has wrapped. To do this + compare the head pointer to the tail pointer, If head is equal + or greater than tail; then it has not wrapped; and the space may + be calculated by subtracting tail from head and then subtracting + that value from the buffers size. A one is subtracted from the + new value to indicate how much space is available between the + head pointer and end of buffer; as well as the space between the + begining of the buffer and the tail. If the head is not greater + or equal to the tail this indicates that the head has wrapped + around to the begining of the buffer. To calculate the space + available in this case simply subtract head from tail. This new + value minus one represents the space available betwwen the head + and tail pointers. In this example head (7) is greater than tail (2) + and therefore has not wrapped around. We find the space by first + subtracting tail from head (7-2=5). We then subtract this value + from the buffer size of ten and subtract one (10-5-1=4). The space + remaining is 4 bytes. + + Example 2: + + Consider a 10 byte buffer where head is a pointer to the next + empty location in the buffer and tail is a pointer to the next + byte to transmit. In this example head will wrapped around and + therefore head < tail. + + 0 1 2 3 4 5 6 7 8 9 + head tail + + The above diagram shows that buffer locations 7,8,9,0 and 1 have + data to be transmited, while head points at the next empty + location. To find the space available we compare head to tail. If + head is not equal to, or greater than tail this indicates that head + has wrapped around. In this case head (2) is not equal to, or + greater than tail (7) and therefore has already wrapped around. To + calculate the available space between the two pointers we subtract + head from tail (7-2=5). We then subtract one from this new value + (5-1=4). We have 5 bytes empty remaining in the buffer. Unlike the + previous example these five bytes are located between the head and + tail pointers. + + ----------------------------------------------------------------------- */ + + dataLen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1); + + /* ---------------------------------------------------------------------- + In this case bytesAvailable has been passed into pc_write and + represents the amount of data that needs to be written. dataLen + represents the amount of space available on the card. Whichever + value is smaller will be the amount actually written. + bytesAvailable will then take on this newly calculated value. + ---------------------------------------------------------------------- */ + + bytesAvailable = MIN(dataLen, bytesAvailable); + + /* First we read the data in from the file system into a temp buffer */ + + if (bytesAvailable) + { /* Begin bytesAvailable */ + + /* Can the user buffer be accessed at the moment ? */ + if (verify_area(VERIFY_READ, (char*)buf, bytesAvailable)) + bytesAvailable = 0; /* Can't do; try again later */ + else /* Evidently it can, began transmission */ + { /* Begin if area verified */ + /* --------------------------------------------------------------- + The below function reads data from user memory. This routine + can not be used in an interrupt routine. (Because it may + generate a page fault) It can only be called while we can the + user context is accessible. + + The prototype is : + inline void copy_from_user(void * to, const void * from, + unsigned long count); + + You must include + I also think (Check hackers guide) that optimization must + be turned ON. (Which sounds strange to me...) + + Remember copy_from_user WILL generate a page fault if the + user memory being accessed has been swapped out. This can + cause this routine to temporarily sleep while this page + fault is occuring. + + ----------------------------------------------------------------- */ + + copy_from_user(ch->tmp_buf, buf, bytesAvailable); + + } /* End if area verified */ + + } /* End bytesAvailable */ + + /* ------------------------------------------------------------------ + Set buf to this address for the moment. tmp_buf was allocated in + post_fep_init. + --------------------------------------------------------------------- */ + buf = ch->tmp_buf; + memoff(ch); + restore_flags(flags); + + } /* End from_user */ + + /* All data is now local */ + + amountCopied = 0; + save_flags(flags); + cli(); + + globalwinon(ch); + + head = bc->tin & (size - 1); + tail = bc->tout; + + if (tail != bc->tout) + tail = bc->tout; + tail &= (size - 1); + + /* If head >= tail, head has not wrapped around. */ + if (head >= tail) + { /* Begin head has not wrapped */ + + /* --------------------------------------------------------------- + remain (much like dataLen above) represents the total amount of + space available on the card for data. Here dataLen represents + the space existing between the head pointer and the end of + buffer. This is important because a memcpy cannot be told to + automatically wrap around when it hits the buffer end. + ------------------------------------------------------------------ */ + + dataLen = size - head; + remain = size - (head - tail) - 1; + + } /* End head has not wrapped */ + else + { /* Begin head has wrapped around */ + + remain = tail - head - 1; + dataLen = remain; + + } /* End head has wrapped around */ + + /* ------------------------------------------------------------------- + Check the space on the card. If we have more data than + space; reduce the amount of data to fit the space. + ---------------------------------------------------------------------- */ + + bytesAvailable = MIN(remain, bytesAvailable); + + txwinon(ch); + while (bytesAvailable > 0) + { /* Begin while there is data to copy onto card */ + + /* ----------------------------------------------------------------- + If head is not wrapped, the below will make sure the first + data copy fills to the end of card buffer. + ------------------------------------------------------------------- */ + + dataLen = MIN(bytesAvailable, dataLen); + memcpy(ch->txptr + head, buf, dataLen); + buf += dataLen; + head += dataLen; + amountCopied += dataLen; + bytesAvailable -= dataLen; + + if (head >= size) + { + head = 0; + dataLen = tail; + } + + } /* End while there is data to copy onto card */ + + ch->statusflags |= TXBUSY; + globalwinon(ch); + bc->tin = head; + + if ((ch->statusflags & LOWWAIT) == 0) + { + ch->statusflags |= LOWWAIT; + bc->ilow = 1; + } + memoff(ch); + restore_flags(flags); + + return(amountCopied); + +} /* End pc_write */ + +/* ------------------ Begin pc_put_char ------------------------- */ + +static void pc_put_char(struct tty_struct *tty, unsigned char c) +{ /* Begin pc_put_char */ + + + pc_write(tty, 0, &c, 1); + return; + +} /* End pc_put_char */ + +/* ------------------ Begin pc_write_room ------------------------- */ + +static int pc_write_room(struct tty_struct *tty) +{ /* Begin pc_write_room */ + + int remain; + struct channel *ch; + unsigned long flags; + unsigned int head, tail; + volatile struct board_chan *bc; + + remain = 0; + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { + save_flags(flags); + cli(); + globalwinon(ch); + + bc = ch->brdchan; + head = bc->tin & (ch->txbufsize - 1); + tail = bc->tout; + + if (tail != bc->tout) + tail = bc->tout; + /* Wrap tail if necessary */ + tail &= (ch->txbufsize - 1); + + if ((remain = tail - head - 1) < 0 ) + remain += ch->txbufsize; + + if (remain && (ch->statusflags & LOWWAIT) == 0) + { + ch->statusflags |= LOWWAIT; + bc->ilow = 1; + } + memoff(ch); + restore_flags(flags); + } + + /* Return how much room is left on card */ + return remain; + +} /* End pc_write_room */ + +/* ------------------ Begin pc_chars_in_buffer ---------------------- */ + +static int pc_chars_in_buffer(struct tty_struct *tty) +{ /* Begin pc_chars_in_buffer */ + + int chars; + unsigned int ctail, head, tail; + int remain; + unsigned long flags; + struct channel *ch; + volatile struct board_chan *bc; + + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) == NULL) + return(0); + + save_flags(flags); + cli(); + globalwinon(ch); + + bc = ch->brdchan; + tail = bc->tout; + head = bc->tin; + ctail = ch->mailbox->cout; + + if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0) + chars = 0; + else + { /* Begin if some space on the card has been used */ + + head = bc->tin & (ch->txbufsize - 1); + tail &= (ch->txbufsize - 1); + + /* -------------------------------------------------------------- + The logic here is basically opposite of the above pc_write_room + here we are finding the amount of bytes in the buffer filled. + Not the amount of bytes empty. + ------------------------------------------------------------------- */ + + if ((remain = tail - head - 1) < 0 ) + remain += ch->txbufsize; + + chars = (int)(ch->txbufsize - remain); + + /* ------------------------------------------------------------- + Make it possible to wakeup anything waiting for output + in tty_ioctl.c, etc. + + If not already set. Setup an event to indicate when the + transmit buffer empties + ----------------------------------------------------------------- */ + + if (!(ch->statusflags & EMPTYWAIT)) + setup_empty_event(tty,ch); + + } /* End if some space on the card has been used */ + + memoff(ch); + restore_flags(flags); + + /* Return number of characters residing on card. */ + return(chars); + +} /* End pc_chars_in_buffer */ + +/* ------------------ Begin pc_flush_buffer ---------------------- */ + +static void pc_flush_buffer(struct tty_struct *tty) +{ /* Begin pc_flush_buffer */ + + unsigned int tail; + unsigned long flags; + struct channel *ch; + volatile struct board_chan *bc; + + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) == NULL) + return; + + save_flags(flags); + cli(); + + globalwinon(ch); + + bc = ch->brdchan; + tail = bc->tout; + + /* Have FEP move tout pointer; effectively flushing transmit buffer */ + + fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0); + + memoff(ch); + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + +} /* End pc_flush_buffer */ + +/* ------------------ Begin pc_flush_chars ---------------------- */ + +static void pc_flush_chars(struct tty_struct *tty) +{ /* Begin pc_flush_chars */ + + struct channel * ch; + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { + unsigned long flags; + + save_flags(flags); + cli(); + + /* ---------------------------------------------------------------- + If not already set and the transmitter is busy setup an event + to indicate when the transmit empties. + ------------------------------------------------------------------- */ + + if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT)) + setup_empty_event(tty,ch); + + restore_flags(flags); + } + +} /* End pc_flush_chars */ + +/* ------------------ Begin block_til_ready ---------------------- */ + +static int block_til_ready(struct tty_struct *tty, + struct file *filp, struct channel *ch) +{ /* Begin block_til_ready */ + + struct wait_queue wait = {current, NULL}; + int retval, do_clocal = 0; + unsigned long flags; + + + if (tty_hung_up_p(filp)) + { + if (ch->asyncflags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + return(retval); + } + + /* ----------------------------------------------------------------- + If the device is in the middle of being closed, then block + until it's done, and then try again. + -------------------------------------------------------------------- */ + if (ch->asyncflags & ASYNC_CLOSING) + { + interruptible_sleep_on(&ch->close_wait); + + if (ch->asyncflags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + /* ----------------------------------------------------------------- + If this is a callout device, then just make sure the normal + device isn't being used. + -------------------------------------------------------------------- */ + + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) + { /* A cud device has been opened */ + if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + + if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + (ch->asyncflags & ASYNC_SESSION_LOCKOUT) && + (ch->session != current->session)) + return -EBUSY; + + if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + (ch->asyncflags & ASYNC_PGRP_LOCKOUT) && + (ch->pgrp != current->pgrp)) + return -EBUSY; + + ch->asyncflags |= ASYNC_CALLOUT_ACTIVE; + + return 0; + } /* End a cud device has been opened */ + + if (filp->f_flags & O_NONBLOCK) + { + /* ----------------------------------------------------------------- + If non-blocking mode is set, then make the check up front + and then exit. + -------------------------------------------------------------------- */ + + if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + + return 0; + } + + + if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) + { + if (ch->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } + else + { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* Block waiting for the carrier detect and the line to become free */ + + retval = 0; + add_wait_queue(&ch->open_wait, &wait); + save_flags(flags); + cli(); + + + /* We dec count so that pc_close will know when to free things */ + if (!tty_hung_up_p(filp)) + ch->count--; + + restore_flags(flags); + + ch->blocked_open++; + + while(1) + { /* Begin forever while */ + + current->state = TASK_INTERRUPTIBLE; + + if (tty_hung_up_p(filp) || + !(ch->asyncflags & ASYNC_INITIALIZED)) + { + if (ch->asyncflags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + + if (!(ch->asyncflags & ASYNC_CLOSING) && + !(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && + (do_clocal || (ch->imodem & ch->dcd))) + break; + + if (current->signal & ~current->blocked) + { + retval = -ERESTARTSYS; + break; + } + + /* --------------------------------------------------------------- + Allow someone else to be scheduled. We will occasionaly go + through this loop until one of the above conditions change. + The below schedule call will allow other processes to enter and + prevent this loop from hogging the cpu. + ------------------------------------------------------------------ */ + schedule(); + + } /* End forever while */ + + current->state = TASK_RUNNING; + remove_wait_queue(&ch->open_wait, &wait); + cli(); + if (!tty_hung_up_p(filp)) + ch->count++; + restore_flags(flags); + + ch->blocked_open--; + + if (retval) + return retval; + + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + + return 0; + +} /* End block_til_ready */ + +/* ------------------ Begin pc_open ---------------------- */ + +static int pc_open(struct tty_struct *tty, struct file * filp) +{ /* Begin pc_open */ + + struct channel *ch; + unsigned long flags; + int line, retval, boardnum; + volatile struct board_chan *bc; + volatile unsigned int head; + + /* Nothing "real" happens in open of control device */ + + if (tty->driver.subtype == SERIAL_TYPE_INFO) + { + return (0) ; + } + + line = MINOR(tty->device) - tty->driver.minor_start; + if (line < 0 || line >= nbdevs) + { + printk(KERN_ERR " - pc_open : line out of range in pc_open\n"); + tty->driver_data = NULL; + return(-ENODEV); + } + +#ifdef MODULE + + MOD_INC_USE_COUNT; + +#endif + + ch = &digi_channels[line]; + boardnum = ch->boardnum; + + /* Check status of board configured in system. */ + + /* ----------------------------------------------------------------- + I check to see if the epca_setup routine detected an user error. + It might be better to put this in pc_init, but for the moment it + goes here. + ---------------------------------------------------------------------- */ + + if (invalid_lilo_config) + { + if (setup_error_code & INVALID_BOARD_TYPE) + printk(KERN_ERR " - pc_open: Invalid board type specified in LILO command\n"); + + if (setup_error_code & INVALID_NUM_PORTS) + printk(KERN_ERR " - pc_open: Invalid number of ports specified in LILO command\n"); + + if (setup_error_code & INVALID_MEM_BASE) + printk(KERN_ERR " - pc_open: Invalid board memory address specified in LILO command\n"); + + if (setup_error_code & INVALID_PORT_BASE) + printk(KERN_ERR " - pc_open: Invalid board port address specified in LILO command\n"); + + if (setup_error_code & INVALID_BOARD_STATUS) + printk(KERN_ERR " - pc_open: Invalid board status specified in LILO command\n"); + + if (setup_error_code & INVALID_ALTPIN) + printk(KERN_ERR " - pc_open: Invalid board altpin specified in LILO command\n"); + + tty->driver_data = NULL; /* Mark this device as 'down' */ + return(-ENODEV); + } + + if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED)) + { + tty->driver_data = NULL; /* Mark this device as 'down' */ + return(-ENODEV); + } + + if (( bc = ch->brdchan) == 0) + { + tty->driver_data = NULL; + return(-ENODEV); + } + + /* ------------------------------------------------------------------ + Every time a channel is opened, increment a counter. This is + necessary because we do not wish to flush and shutdown the channel + until the last app holding the channel open, closes it. + --------------------------------------------------------------------- */ + + ch->count++; + + /* ---------------------------------------------------------------- + Set a kernel structures pointer to our local channel + structure. This way we can get to it when passed only + a tty struct. + ------------------------------------------------------------------ */ + + tty->driver_data = ch; + + /* ---------------------------------------------------------------- + If this is the first time the channel has been opened, initialize + the tty->termios struct otherwise let pc_close handle it. + -------------------------------------------------------------------- */ + + /* Should this be here except for SPLIT termios ? */ + if (ch->count == 1) + { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = ch->normal_termios; + else + *tty->termios = ch->callout_termios; + } + + ch->session = current->session; + ch->pgrp = current->pgrp; + + save_flags(flags); + cli(); + + globalwinon(ch); + ch->statusflags = 0; + + /* Save boards current modem status */ + ch->imodem = bc->mstat; + + /* ---------------------------------------------------------------- + Set receive head and tail ptrs to each other. This indicates + no data available to read. + ----------------------------------------------------------------- */ + head = bc->rin; + bc->rout = head; + + /* Set the channels associated tty structure */ + ch->tty = tty; + + /* ----------------------------------------------------------------- + The below routine generally sets up parity, baud, flow control + issues, etc.... It effect both control flags and input flags. + -------------------------------------------------------------------- */ + epcaparam(tty,ch); + + ch->asyncflags |= ASYNC_INITIALIZED; + memoff(ch); + + restore_flags(flags); + + retval = block_til_ready(tty, filp, ch); + if (retval) + { + return retval; + } + + /* ------------------------------------------------------------- + Set this again in case a hangup set it to zero while this + open() was waiting for the line... + --------------------------------------------------------------- */ + ch->tty = tty; + + save_flags(flags); + cli(); + globalwinon(ch); + + /* Enable Digi Data events */ + bc->idata = 1; + + memoff(ch); + restore_flags(flags); + + return 0; + +} /* End pc_open */ + +#ifdef MODULE +/* -------------------- Begin init_module ---------------------- */ +int init_module() +{ /* Begin init_module */ + + unsigned long flags; + + save_flags(flags); + cli(); + + pc_init(); + + restore_flags(flags); + + return(0); +} /* End init_module */ + +#endif +#ifdef MODULE +/* -------------------- Begin cleanup_module ---------------------- */ +void cleanup_module() +{ /* Begin cleanup_module */ + + int count, crd; + struct board_info *bd; + struct channel *ch; + unsigned long flags; + + + save_flags(flags); + cli(); + + timer_table[DIGI_TIMER].fn = 0; + + if ((tty_unregister_driver(&pc_driver)) || + (tty_unregister_driver(&pc_callout))) + { + printk(KERN_WARNING " - DIGI : cleanup_module failed to un-register tty driver\n"); + restore_flags(flags); + return; + } + + for (crd = 0; crd < num_cards; crd++) + { /* Begin for each card */ + + bd = &boards[crd]; + + if (!bd) + { /* Begin sanity check */ + printk(KERN_ERR " - Digi : cleanup_module failed\n"); + return; + } /* End sanity check */ + + ch = card_ptr[crd]; + + for (count = 0; count < bd->numports; count++, ch++) + { /* Begin for each port */ + + if (ch) + { + if (ch->tty) + tty_hangup(ch->tty); + kfree_s(ch->tmp_buf, ch->txbufsize); + } + + } /* End for each port */ + } /* End for each card */ + + + restore_flags(flags); + +} /* End cleanup_module */ +#endif /* MODULE */ + +/* ------------------ Begin pc_init ---------------------- */ + +int pc_init(void) +{ /* Begin pc_init */ + + /* ---------------------------------------------------------------- + pc_init is called by the operating system during boot up prior to + any open calls being made. In the older versions of Linux (Prior + to 2.0.0) an entry is made into tty_io.c. A pointer to the last + memory location (from kernel space) used (kmem_start) is passed + to pc_init. It is pc_inits responsibility to modify this value + for any memory that the Digi driver might need and then return + this value to the operating system. For example if the driver + wishes to allocate 1K of kernel memory, pc_init would return + (kmem_start + 1024). This memory (Between kmem_start and kmem_start + + 1024) would then be available for use exclusively by the driver. + In this case our driver does not allocate any of this kernel + memory. + ------------------------------------------------------------------*/ + + ulong flags, save_loops_per_sec; + int crd; + struct board_info *bd; + unsigned char board_id = 0; + + +#ifdef ENABLE_PCI + int pci_boards_found, pci_count; + + pci_count = 0; +#endif /* ENABLE_PCI */ + + /* ----------------------------------------------------------------------- + If epca_setup has not been ran by LILO set num_cards to defaults; copy + board structure defined by digiConfig into drivers board structure. + Note : If LILO has ran epca_setup then epca_setup will handle defining + num_cards as well as copying the data into the board structure. + -------------------------------------------------------------------------- */ + if (!liloconfig) + { /* Begin driver has been configured via. epcaconfig */ + + nbdevs = NBDEVS; + num_cards = NUMCARDS; + memcpy((void *)&boards, (void *)&static_boards, + (sizeof(struct board_info) * NUMCARDS)); + } /* End driver has been configured via. epcaconfig */ + + /* ----------------------------------------------------------------- + Note : If lilo was used to configure the driver and the + ignore epcaconfig option was choosen (digiepca=2) then + nbdevs and num_cards will equal 0 at this point. This is + okay; PCI cards will still be picked up if detected. + --------------------------------------------------------------------- */ + + /* ----------------------------------------------------------- + Set up interrupt, we will worry about memory allocation in + post_fep_init. + --------------------------------------------------------------- */ + + + printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION); + +#ifdef ENABLE_PCI + + /* ------------------------------------------------------------------ + NOTE : This code assumes that the number of ports found in + the boards array is correct. This could be wrong if + the card in question is PCI (And therefore has no ports + entry in the boards structure.) The rest of the + information will be valid for PCI because the begining + of pc_init scans for PCI and determines i/o and base + memory addresses. I am not sure if it is possible to + read the number of ports supported by the card prior to + it being booted (Since that is the state it is in when + pc_init is run). Because it is not possible to query the + number of supported ports until after the card has booted; + we are required to calculate the card_ptrs as the card is + is initialized (Inside post_fep_init). The negative thing + about this approach is that digiDload's call to GET_INFO + will have a bad port value. (Since this is called prior + to post_fep_init.) + + --------------------------------------------------------------------- */ + + pci_boards_found = 0; + if (pcibios_present()) + { + if(num_cards < MAXBOARDS) + pci_boards_found += init_PCI(num_cards); + num_cards += pci_boards_found; + } + else + { + printk(KERN_ERR " - No PCI BIOS found\n"); + } + +#endif /* ENABLE_PCI */ + + memset(&pc_driver, 0, sizeof(struct tty_driver)); + memset(&pc_callout, 0, sizeof(struct tty_driver)); + memset(&pc_info, 0, sizeof(struct tty_driver)); + + pc_driver.magic = TTY_DRIVER_MAGIC; + pc_driver.name = "ttyD"; + pc_driver.major = DIGI_MAJOR; + pc_driver.minor_start = 0; + pc_driver.num = MAX_ALLOC; + pc_driver.type = TTY_DRIVER_TYPE_SERIAL; + pc_driver.subtype = SERIAL_TYPE_NORMAL; + pc_driver.init_termios = tty_std_termios; + pc_driver.init_termios.c_iflag = 0; + pc_driver.init_termios.c_oflag = 0; + + pc_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; + pc_driver.init_termios.c_lflag = 0; + pc_driver.flags = TTY_DRIVER_REAL_RAW; + pc_driver.refcount = &pc_refcount; + pc_driver.table = pc_table; + + /* pc_termios is an array of pointers pointing at termios structs */ + /* The below should get the first pointer */ + pc_driver.termios = pc_termios; + pc_driver.termios_locked = pc_termios_locked; + + /* ------------------------------------------------------------------ + Setup entry points for the driver. These are primarily called by + the kernel in tty_io.c and n_tty.c + --------------------------------------------------------------------- */ + + pc_driver.open = pc_open; + pc_driver.close = pc_close; + pc_driver.write = pc_write; + pc_driver.write_room = pc_write_room; + pc_driver.flush_buffer = pc_flush_buffer; + pc_driver.chars_in_buffer = pc_chars_in_buffer; + pc_driver.flush_chars = pc_flush_chars; + pc_driver.put_char = pc_put_char; + pc_driver.ioctl = pc_ioctl; + pc_driver.set_termios = pc_set_termios; + pc_driver.stop = pc_stop; + pc_driver.start = pc_start; + pc_driver.throttle = pc_throttle; + pc_driver.unthrottle = pc_unthrottle; + pc_driver.hangup = pc_hangup; + pc_callout = pc_driver; + + pc_callout.name = "cud"; + pc_callout.major = DIGICU_MAJOR; + pc_callout.minor_start = 0; + pc_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; + pc_callout.subtype = SERIAL_TYPE_CALLOUT; + + pc_info = pc_driver; + pc_info.name = "digiCtl"; + pc_info.major = DIGIINFOMAJOR; + pc_info.minor_start = 0; + pc_info.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; + pc_info.subtype = SERIAL_TYPE_INFO; + + + /* --------------------------------------------------------------------- + loops_per_sec hasn't been set at this point :-(, so fake it out... + I set it, so that I can use the __delay() function. + ------------------------------------------------------------------------ */ + save_loops_per_sec = loops_per_sec; + loops_per_sec = 13L * 500000L; + + save_flags(flags); + cli(); + + for (crd = 0; crd < num_cards; crd++) + { /* Begin for each card */ + + /* ------------------------------------------------------------------ + This is where the appropriate memory handlers for the hardware is + set. Everything at runtime blindly jumps through these vectors. + ---------------------------------------------------------------------- */ + + /* defined in epcaconfig.h */ + bd = &boards[crd]; + + switch (bd->type) + { /* Begin switch on bd->type {board type} */ + case PCXEM: + case EISAXEM: + bd->memwinon = pcxem_memwinon ; + bd->memwinoff = pcxem_memwinoff ; + bd->globalwinon = pcxem_globalwinon ; + bd->txwinon = pcxem_txwinon ; + bd->rxwinon = pcxem_rxwinon ; + bd->memoff = pcxem_memoff ; + bd->assertgwinon = dummy_assertgwinon; + bd->assertmemoff = dummy_assertmemoff; + break; + + case PCIXEM: + case PCIXRJ: + case PCIXR: + bd->memwinon = dummy_memwinon; + bd->memwinoff = dummy_memwinoff; + bd->globalwinon = dummy_globalwinon; + bd->txwinon = dummy_txwinon; + bd->rxwinon = dummy_rxwinon; + bd->memoff = dummy_memoff; + bd->assertgwinon = dummy_assertgwinon; + bd->assertmemoff = dummy_assertmemoff; + break; + + case PCXE: + case PCXEVE: + + bd->memwinon = pcxe_memwinon; + bd->memwinoff = pcxe_memwinoff; + bd->globalwinon = pcxe_globalwinon; + bd->txwinon = pcxe_txwinon; + bd->rxwinon = pcxe_rxwinon; + bd->memoff = pcxe_memoff; + bd->assertgwinon = dummy_assertgwinon; + bd->assertmemoff = dummy_assertmemoff; + break; + + case PCXI: + case PC64XE: + + bd->memwinon = pcxi_memwinon; + bd->memwinoff = pcxi_memwinoff; + bd->globalwinon = pcxi_globalwinon; + bd->txwinon = pcxi_txwinon; + bd->rxwinon = pcxi_rxwinon; + bd->memoff = pcxi_memoff; + bd->assertgwinon = pcxi_assertgwinon; + bd->assertmemoff = pcxi_assertmemoff; + break; + + default: + break; + + } /* End switch on bd->type */ + + /* --------------------------------------------------------------- + Some cards need a memory segment to be defined for use in + transmit and receive windowing operations. These boards + are listed in the below switch. In the case of the XI the + amount of memory on the board is variable so the memory_seg + is also variable. This code determines what they segment + should be. + ----------------------------------------------------------------- */ + + switch (bd->type) + { /* Begin switch on bd->type {board type} */ + + case PCXE: + case PCXEVE: + case PC64XE: + bd->memory_seg = 0xf000; + break; + + case PCXI: + board_id = inb((int)bd->port); + if ((board_id & 0x1) == 0x1) + { /* Begin its an XI card */ + + /* Is it a 64K board */ + if ((board_id & 0x30) == 0) + bd->memory_seg = 0xf000; + + /* Is it a 128K board */ + if ((board_id & 0x30) == 0x10) + bd->memory_seg = 0xe000; + + /* Is is a 256K board */ + if ((board_id & 0x30) == 0x20) + bd->memory_seg = 0xc000; + + /* Is it a 512K board */ + if ((board_id & 0x30) == 0x30) + bd->memory_seg = 0x8000; + + } /* End it is an XI card */ + else + { + printk(KERN_ERR " - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); + } + break; + + } /* End switch on bd->type */ + + } /* End for each card */ + + if (tty_register_driver(&pc_driver)) + panic("Couldn't register Digi PC/ driver"); + + if (tty_register_driver(&pc_callout)) + panic("Couldn't register Digi PC/ callout"); + + if (tty_register_driver(&pc_info)) + panic("Couldn't register Digi PC/ info "); + + loops_per_sec = save_loops_per_sec; /* reset it to what it should be */ + + /* ------------------------------------------------------------------- + Start up the poller to check for events on all enabled boards + ---------------------------------------------------------------------- */ + + timer_table[DIGI_TIMER].fn = (void *)epcapoll; + timer_table[DIGI_TIMER].expires = 0; + + restore_flags(flags); + + timer_active |= 1 << DIGI_TIMER; + return 0; + +} /* End pc_init */ + +/* ------------------ Begin post_fep_init ---------------------- */ + +static void post_fep_init(unsigned int crd) +{ /* Begin post_fep_init */ + + int i; + unchar *memaddr; + volatile struct global_data *gd; + struct board_info *bd; + volatile struct board_chan *bc; + struct channel *ch; + int shrinkmem = 0, lowwater ; + + /* ------------------------------------------------------------- + This call is made by the user via. the ioctl call DIGI_INIT. + It is resposible for setting up all the card specific stuff. + ---------------------------------------------------------------- */ + bd = &boards[crd]; + + /* ----------------------------------------------------------------- + If this is a PCI board, get the port info. Remember PCI cards + do not have entries into the epcaconfig.h file, so we can't get + the number of ports from it. Unfortunetly, this means that anyone + doing a DIGI_GETINFO before the board has booted will get an invalid + number of ports returned (It should return 0). Calls to DIGI_GETINFO + after DIGI_INIT has been called will return the proper values. + ------------------------------------------------------------------- */ + + if (bd->type >= PCIXEM) /* If the board in question is PCI */ + { /* Begin get PCI number of ports */ + + /* -------------------------------------------------------------------- + Below we use XEMPORTS as a memory offset regardless of which PCI + card it is. This is because all of the supported PCI cards have + the same memory offset for the channel data. This will have to be + changed if we ever develop a PCI/XE card. NOTE : The FEP manual + states that the port offset is 0xC22 as opposed to 0xC02. This is + only true for PC/XE, and PC/XI cards; not for the XEM, or CX series. + On the PCI cards the number of ports is determined by reading a + ID PROM located in the box attached to the card. The card can then + determine the index the id to determine the number of ports available. + (FYI - The id should be located at 0x1ac (And may use up to 4 bytes + if the box in question is a XEM or CX)). + ------------------------------------------------------------------------ */ + + bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long) + (bd->re_map_membase + XEMPORTS)); + + + epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); + nbdevs += (bd->numports); + + } /* End get PCI number of ports */ + + if (crd != 0) + card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports; + else + card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */ + + ch = card_ptr[crd]; + + + epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range"); + + if (bd->membase < (unsigned char *)0x100000) + memaddr = (unchar *) bd->membase; + else /* Else get special mapped memory above RAM */ + memaddr = (unchar *)bd->re_map_membase; + + /* + The below command is necessary because newer kernels (2.1.x and + up) do not have a 1:1 virtual to physical mapping. The below + call adjust for that. + */ + + memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr); + + /* ----------------------------------------------------------------- + The below assignment will set bc to point at the BEGINING of + the cards channel structures. For 1 card there will be between + 8 and 64 of these structures. + -------------------------------------------------------------------- */ + + bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT); + + /* ------------------------------------------------------------------- + The below assignment will set gd to point at the BEGINING of + global memory address 0xc00. The first data in that global + memory actually starts at address 0xc1a. The command in + pointer begins at 0xd10. + ---------------------------------------------------------------------- */ + + gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL); + + /* -------------------------------------------------------------------- + XEPORTS (address 0xc22) points at the number of channels the + card supports. (For 64XE, XI, XEM, and XR use 0xc02) + ----------------------------------------------------------------------- */ + + if (((bd->type == PCXEVE) | (bd->type == PCXE)) && + (*(ushort *)((ulong)memaddr + XEPORTS) < 3)) + shrinkmem = 1; + if (bd->type < PCIXEM) + request_region((int)bd->port, 4, board_desc[bd->type]); + + memwinon(bd, 0); + + /* -------------------------------------------------------------------- + Remember ch is the main drivers channels structure, while bc is + the cards channel structure. + ------------------------------------------------------------------------ */ + + /* For every port on the card do ..... */ + + for (i = 0; i < bd->numports; i++, ch++, bc++) + { /* Begin for each port */ + + ch->brdchan = bc; + ch->mailbox = gd; + ch->tqueue.routine = do_softint; + ch->tqueue.data = ch; + ch->board = &boards[crd]; + + switch (bd->type) + { /* Begin switch bd->type */ + + /* ---------------------------------------------------------------- + Since some of the boards use different bitmaps for their + control signals we cannot hard code these values and retain + portability. We virtualize this data here. + ------------------------------------------------------------------- */ + case EISAXEM: + case PCXEM: + case PCIXEM: + case PCIXRJ: + case PCIXR: + ch->m_rts = 0x02 ; + ch->m_dcd = 0x80 ; + ch->m_dsr = 0x20 ; + ch->m_cts = 0x10 ; + ch->m_ri = 0x40 ; + ch->m_dtr = 0x01 ; + break; + + case PCXE: + case PCXEVE: + case PCXI: + case PC64XE: + ch->m_rts = 0x02 ; + ch->m_dcd = 0x08 ; + ch->m_dsr = 0x10 ; + ch->m_cts = 0x20 ; + ch->m_ri = 0x40 ; + ch->m_dtr = 0x80 ; + break; + + } /* End switch bd->type */ + + if (boards[crd].altpin) + { + ch->dsr = ch->m_dcd; + ch->dcd = ch->m_dsr; + ch->digiext.digi_flags |= DIGI_ALTPIN; + } + else + { + ch->dcd = ch->m_dcd; + ch->dsr = ch->m_dsr; + } + + ch->boardnum = crd; + ch->channelnum = i; + ch->magic = EPCA_MAGIC; + ch->tty = 0; + + if (shrinkmem) + { + fepcmd(ch, SETBUFFER, 32, 0, 0, 0); + shrinkmem = 0; + } + + switch (bd->type) + { /* Begin switch bd->type */ + + case PCIXEM: + case PCIXRJ: + case PCIXR: + /* Cover all the 2MEG cards */ + ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff); + ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff); + ch->txwin = FEPWIN | ((bc->tseg) >> 11); + ch->rxwin = FEPWIN | ((bc->rseg) >> 11); + break; + + case PCXEM: + case EISAXEM: + /* Cover all the 32K windowed cards */ + /* Mask equal to window size - 1 */ + ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff); + ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff); + ch->txwin = FEPWIN | ((bc->tseg) >> 11); + ch->rxwin = FEPWIN | ((bc->rseg) >> 11); + break; + + case PCXEVE: + case PCXE: + ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff); + ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9); + ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff); + ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 ); + break; + + case PCXI: + case PC64XE: + ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4); + ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4); + ch->txwin = ch->rxwin = 0; + break; + + } /* End switch bd->type */ + + ch->txbufhead = 0; + ch->txbufsize = bc->tmax + 1; + + ch->rxbufhead = 0; + ch->rxbufsize = bc->rmax + 1; + + lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2); + + /* Set transmitter low water mark */ + fepcmd(ch, STXLWATER, lowwater, 0, 10, 0); + + /* Set receiver low water mark */ + + fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0); + + /* Set receiver high water mark */ + + fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0); + + bc->edelay = 100; + bc->idata = 1; + + ch->startc = bc->startc; + ch->stopc = bc->stopc; + ch->startca = bc->startca; + ch->stopca = bc->stopca; + + ch->fepcflag = 0; + ch->fepiflag = 0; + ch->fepoflag = 0; + ch->fepstartc = 0; + ch->fepstopc = 0; + ch->fepstartca = 0; + ch->fepstopca = 0; + + ch->close_delay = 50; + ch->count = 0; + ch->blocked_open = 0; + ch->callout_termios = pc_callout.init_termios; + ch->normal_termios = pc_driver.init_termios; + ch->open_wait = 0; + ch->close_wait = 0; + ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL); + if (!(ch->tmp_buf)) + { + printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i); + + } + memset((void *)ch->tmp_buf,0,ch->txbufsize); + } /* End for each port */ + + printk(KERN_INFO + "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", + VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports); + sprintf(mesg, + "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", + VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports); + console_print(mesg); + + memwinoff(bd, 0); + +} /* End post_fep_init */ + +/* --------------------- Begin epcapoll ------------------------ */ + +static void epcapoll(unsigned long ignored) +{ /* Begin epcapoll */ + + unsigned long flags; + int crd; + volatile unsigned int head, tail; + struct channel *ch; + struct board_info *bd; + + /* ------------------------------------------------------------------- + This routine is called upon every timer interrupt. Even though + the Digi series cards are capable of generating interupts this + method of non-looping polling is more efficient. This routine + checks for card generated events (Such as receive data, are transmit + buffer empty) and acts on those events. + ----------------------------------------------------------------------- */ + + save_flags(flags); + cli(); + + for (crd = 0; crd < num_cards; crd++) + { /* Begin for each card */ + + bd = &boards[crd]; + ch = card_ptr[crd]; + + if ((bd->status == DISABLED) || digi_poller_inhibited) + continue; /* Begin loop next interation */ + + /* ----------------------------------------------------------- + assertmemoff is not needed here; indeed it is an empty subroutine. + It is being kept because future boards may need this as well as + some legacy boards. + ---------------------------------------------------------------- */ + + assertmemoff(ch); + + globalwinon(ch); + + /* --------------------------------------------------------------- + In this case head and tail actually refer to the event queue not + the transmit or receive queue. + ------------------------------------------------------------------- */ + + head = ch->mailbox->ein; + tail = ch->mailbox->eout; + + /* If head isn't equal to tail we have an event */ + + if (head != tail) + doevent(crd); + + memoff(ch); + + } /* End for each card */ + + timer_table[DIGI_TIMER].fn = (void *)epcapoll; + timer_table[DIGI_TIMER].expires = jiffies + (HZ / 25); + timer_active |= 1 << DIGI_TIMER; + + restore_flags(flags); + +} /* End epcapoll */ + +/* --------------------- Begin doevent ------------------------ */ + +static void doevent(int crd) +{ /* Begin doevent */ + + volatile unchar *eventbuf; + struct channel *ch, *chan0; + static struct tty_struct *tty; + volatile struct board_info *bd; + volatile struct board_chan *bc; + register volatile unsigned int tail, head; + register int event, channel; + register int mstat, lstat; + + /* ------------------------------------------------------------------- + This subroutine is called by epcapoll when an event is detected + in the event queue. This routine responds to those events. + --------------------------------------------------------------------- */ + + bd = &boards[crd]; + + chan0 = card_ptr[crd]; + epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range"); + + assertgwinon(chan0); + + while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) + { /* Begin while something in event queue */ + + assertgwinon(chan0); + + if (bd->membase < (unsigned char *)0x100000) + eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->membase + tail + ISTART)); + else + { + eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART)); + } + + /* Get the channel the event occured on */ + channel = eventbuf[0]; + + /* Get the actual event code that occured */ + event = eventbuf[1]; + + /* ---------------------------------------------------------------- + The two assignments below get the current modem status (mstat) + and the previous modem status (lstat). These are useful becuase + an event could signal a change in modem signals itself. + ------------------------------------------------------------------- */ + + mstat = eventbuf[2]; + lstat = eventbuf[3]; + + ch = chan0 + channel; + + if ((unsigned)channel >= bd->numports || !ch) + { + if (channel >= bd->numports) + ch = chan0; + bc = ch->brdchan; + goto next; + } + + if ((bc = ch->brdchan) == NULL) + goto next; + + if (event & DATA_IND) + { /* Begin DATA_IND */ + + receive_data(ch); + assertgwinon(ch); + + } /* End DATA_IND */ + else + if (event & MODEMCHG_IND) + { /* Begin MODEMCHG_IND */ + + /* A modem signal change has been indicated */ + + ch->imodem = mstat; + + if (ch->asyncflags & ASYNC_CHECK_CD) + { + if (mstat & ch->dcd) /* We are now receiving dcd */ + wake_up_interruptible(&ch->open_wait); + else + pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */ + } + + } /* End MODEMCHG_IND */ + + tty = ch->tty; + if (tty) + { /* Begin if valid tty */ + + if (event & BREAK_IND) + { /* Begin if BREAK_IND */ + + /* A break has been indicated */ + + tty->flip.count++; + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + + *tty->flip.char_buf_ptr++ = 0; + + tty_schedule_flip(tty); + + } /* End if BREAK_IND */ + else + if (event & LOWTX_IND) + { /* Begin LOWTX_IND */ + + if (ch->statusflags & LOWWAIT) + { /* Begin if LOWWAIT */ + + ch->statusflags &= ~LOWWAIT; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + + } /* End if LOWWAIT */ + + } /* End LOWTX_IND */ + else + if (event & EMPTYTX_IND) + { /* Begin EMPTYTX_IND */ + + /* This event is generated by setup_empty_event */ + + ch->statusflags &= ~TXBUSY; + if (ch->statusflags & EMPTYWAIT) + { /* Begin if EMPTYWAIT */ + + ch->statusflags &= ~EMPTYWAIT; + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + wake_up_interruptible(&tty->write_wait); + + } /* End if EMPTYWAIT */ + + } /* End EMPTYTX_IND */ + + } /* End if valid tty */ + + + next: + globalwinon(ch); + + if (!bc) + printk(KERN_ERR " - bc == NULL in doevent!\n"); + else + bc->idata = 1; + + chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4); + globalwinon(chan0); + + } /* End while something in event queue */ + +} /* End doevent */ + +/* --------------------- Begin fepcmd ------------------------ */ + +static void fepcmd(struct channel *ch, int cmd, int word_or_byte, + int byte2, int ncmds, int bytecmd) +{ /* Begin fepcmd */ + + unchar *memaddr; + unsigned int head, cmdTail, cmdStart, cmdMax; + long count; + int n; + + /* This is the routine in which commands may be passed to the card. */ + + if (ch->board->status == DISABLED) + { + return; + } + + assertgwinon(ch); + + /* Remember head (As well as max) is just an offset not a base addr */ + head = ch->mailbox->cin; + + /* cmdStart is a base address */ + cmdStart = ch->mailbox->cstart; + + /* ------------------------------------------------------------------ + We do the addition below because we do not want a max pointer + relative to cmdStart. We want a max pointer that points at the + physical end of the command queue. + -------------------------------------------------------------------- */ + + cmdMax = (cmdStart + 4 + (ch->mailbox->cmax)); + + if (ch->board->membase < (unsigned char *)0x100000) + memaddr = ch->board->membase; + else + memaddr = ch->board->re_map_membase; + + /* + The below command is necessary because newer kernels (2.1.x and + up) do not have a 1:1 virtual to physical mapping. The below + call adjust for that. + */ + + memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr); + + if (head >= (cmdMax - cmdStart) || (head & 03)) + { + printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, + cmd, head); + printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, + cmdMax, cmdStart); + return; + } + + if (bytecmd) + { + *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd; + + *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum; + /* Below word_or_byte is bits to set */ + *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte; + /* Below byte2 is bits to reset */ + *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2; + + } + else + { + *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd; + *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum; + *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte; + } + + head = (head + 4) & (cmdMax - cmdStart - 4); + ch->mailbox->cin = head; + + count = FEPTIMEOUT; + + for (;;) + { /* Begin forever loop */ + + count--; + if (count == 0) + { + printk(KERN_ERR " - Fep not responding in fepcmd()\n"); + return; + } + + head = ch->mailbox->cin; + cmdTail = ch->mailbox->cout; + + n = (head - cmdTail) & (cmdMax - cmdStart - 4); + + /* ---------------------------------------------------------- + Basically this will break when the FEP acknowledges the + command by incrementing cmdTail (Making it equal to head). + ------------------------------------------------------------- */ + + if (n <= ncmds * (sizeof(short) * 4)) + break; /* Well nearly forever :-) */ + + } /* End forever loop */ + +} /* End fepcmd */ + +/* --------------------------------------------------------------------- + Digi products use fields in their channels structures that are very + similar to the c_cflag and c_iflag fields typically found in UNIX + termios structures. The below three routines allow mappings + between these hardware "flags" and their respective Linux flags. +------------------------------------------------------------------------- */ + +/* --------------------- Begin termios2digi_h -------------------- */ + +static unsigned termios2digi_h(struct channel *ch, unsigned cflag) +{ /* Begin termios2digi_h */ + + unsigned res = 0; + + if (cflag & CRTSCTS) + { + ch->digiext.digi_flags |= (RTSPACE | CTSPACE); + res |= ((ch->m_cts) | (ch->m_rts)); + } + + if (ch->digiext.digi_flags & RTSPACE) + res |= ch->m_rts; + + if (ch->digiext.digi_flags & DTRPACE) + res |= ch->m_dtr; + + if (ch->digiext.digi_flags & CTSPACE) + res |= ch->m_cts; + + if (ch->digiext.digi_flags & DSRPACE) + res |= ch->dsr; + + if (ch->digiext.digi_flags & DCDPACE) + res |= ch->dcd; + + if (res & (ch->m_rts)) + ch->digiext.digi_flags |= RTSPACE; + + if (res & (ch->m_cts)) + ch->digiext.digi_flags |= CTSPACE; + + return res; + +} /* End termios2digi_h */ + +/* --------------------- Begin termios2digi_i -------------------- */ +static unsigned termios2digi_i(struct channel *ch, unsigned iflag) +{ /* Begin termios2digi_i */ + + unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | + INPCK | ISTRIP|IXON|IXANY|IXOFF); + + if (ch->digiext.digi_flags & DIGI_AIXON) + res |= IAIXON; + return res; + +} /* End termios2digi_i */ + +/* --------------------- Begin termios2digi_c -------------------- */ + +static unsigned termios2digi_c(struct channel *ch, unsigned cflag) +{ /* Begin termios2digi_c */ + + unsigned res = 0; + +#ifdef SPEED_HACK + /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */ + if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200; + if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600; +#endif /* SPEED_HACK */ + + if (cflag & CBAUDEX) + { /* Begin detected CBAUDEX */ + + ch->digiext.digi_flags |= DIGI_FAST; + + /* ------------------------------------------------------------- + HUPCL bit is used by FEP to indicate fast baud + table is to be used. + ----------------------------------------------------------------- */ + + res |= FEP_HUPCL; + + } /* End detected CBAUDEX */ + else ch->digiext.digi_flags &= ~DIGI_FAST; + + /* ------------------------------------------------------------------- + CBAUD has bit position 0x1000 set these days to indicate Linux + baud rate remap. Digi hardware can't handle the bit assignment. + (We use a different bit assignment for high speed.). Clear this + bit out. + ---------------------------------------------------------------------- */ + res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE); + + /* ------------------------------------------------------------- + This gets a little confusing. The Digi cards have their own + representation of c_cflags controling baud rate. For the most + part this is identical to the Linux implementation. However; + Digi supports one rate (76800) that Linux doesn't. This means + that the c_cflag entry that would normally mean 76800 for Digi + actually means 115200 under Linux. Without the below mapping, + a stty 115200 would only drive the board at 76800. Since + the rate 230400 is also found after 76800, the same problem afflicts + us when we choose a rate of 230400. Without the below modificiation + stty 230400 would actually give us 115200. + + There are two additional differences. The Linux value for CLOCAL + (0x800; 0004000) has no meaning to the Digi hardware. Also in + later releases of Linux; the CBAUD define has CBAUDEX (0x1000; + 0010000) ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX + should be checked for a screened out prior to termios2digi_c + returning. Since CLOCAL isn't used by the board this can be + ignored as long as the returned value is used only by Digi hardware. + ----------------------------------------------------------------- */ + + if (cflag & CBAUDEX) + { + /* ------------------------------------------------------------- + The below code is trying to guarantee that only baud rates + 115200 and 230400 are remapped. We use exclusive or because + the various baud rates share common bit positions and therefore + can't be tested for easily. + ----------------------------------------------------------------- */ + + + if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) || + (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX)))) + { + res += 1; + } + } + + return res; + +} /* End termios2digi_c */ + +/* --------------------- Begin epcaparam ----------------------- */ + +static void epcaparam(struct tty_struct *tty, struct channel *ch) +{ /* Begin epcaparam */ + + unsigned int cmdHead; + struct termios *ts; + volatile struct board_chan *bc; + unsigned mval, hflow, cflag, iflag; + + bc = ch->brdchan; + epcaassert(bc !=0, "bc out of range"); + + assertgwinon(ch); + + ts = tty->termios; + + if ((ts->c_cflag & CBAUD) == 0) + { /* Begin CBAUD detected */ + + cmdHead = bc->rin; + bc->rout = cmdHead; + cmdHead = bc->tin; + + /* Changing baud in mid-stream transmission can be wonderful */ + /* --------------------------------------------------------------- + Flush current transmit buffer by setting cmdTail pointer (tout) + to cmdHead pointer (tin). Hopefully the transmit buffer is empty. + ----------------------------------------------------------------- */ + + fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0); + mval = 0; + + } /* End CBAUD detected */ + else + { /* Begin CBAUD not detected */ + + /* ------------------------------------------------------------------- + c_cflags have changed but that change had nothing to do with BAUD. + Propagate the change to the card. + ---------------------------------------------------------------------- */ + + cflag = termios2digi_c(ch, ts->c_cflag); + + if (cflag != ch->fepcflag) + { + ch->fepcflag = cflag; + /* Set baud rate, char size, stop bits, parity */ + fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0); + } + + + /* ---------------------------------------------------------------- + If the user has not forced CLOCAL and if the device is not a + CALLOUT device (Which is always CLOCAL) we set flags such that + the driver will wait on carrier detect. + ------------------------------------------------------------------- */ + + if ((ts->c_cflag & CLOCAL) || (tty->driver.subtype == SERIAL_TYPE_CALLOUT)) + { /* Begin it is a cud device or a ttyD device with CLOCAL on */ + ch->asyncflags &= ~ASYNC_CHECK_CD; + } /* End it is a cud device or a ttyD device with CLOCAL on */ + else + { /* Begin it is a ttyD device */ + ch->asyncflags |= ASYNC_CHECK_CD; + } /* End it is a ttyD device */ + + mval = ch->m_dtr | ch->m_rts; + + } /* End CBAUD not detected */ + + iflag = termios2digi_i(ch, ts->c_iflag); + + /* Check input mode flags */ + + if (iflag != ch->fepiflag) + { + ch->fepiflag = iflag; + + /* --------------------------------------------------------------- + Command sets channels iflag structure on the board. Such things + as input soft flow control, handeling of parity errors, and + break handeling are all set here. + ------------------------------------------------------------------- */ + + /* break handeling, parity handeling, input stripping, flow control chars */ + fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0); + } + + /* --------------------------------------------------------------- + Set the board mint value for this channel. This will cause hardware + events to be generated each time the DCD signal (Described in mint) + changes. + ------------------------------------------------------------------- */ + bc->mint = ch->dcd; + + if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD)) + if (ch->digiext.digi_flags & DIGI_FORCEDCD) + bc->mint = 0; + + ch->imodem = bc->mstat; + + hflow = termios2digi_h(ch, ts->c_cflag); + + if (hflow != ch->hflow) + { + ch->hflow = hflow; + + /* -------------------------------------------------------------- + Hard flow control has been selected but the board is not + using it. Activate hard flow control now. + ----------------------------------------------------------------- */ + + fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1); + } + + + mval ^= ch->modemfake & (mval ^ ch->modem); + + if (ch->omodem ^ mval) + { + ch->omodem = mval; + + /* -------------------------------------------------------------- + The below command sets the DTR and RTS mstat structure. If + hard flow control is NOT active these changes will drive the + output of the actual DTR and RTS lines. If hard flow control + is active, the changes will be saved in the mstat structure and + only asserted when hard flow control is turned off. + ----------------------------------------------------------------- */ + + /* First reset DTR & RTS; then set them */ + fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1); + fepcmd(ch, SETMODEM, mval, 0, 0, 1); + + } + + if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) + { + ch->fepstartc = ch->startc; + ch->fepstopc = ch->stopc; + + /* ------------------------------------------------------------ + The XON / XOFF characters have changed; propogate these + changes to the card. + --------------------------------------------------------------- */ + + fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1); + } + + if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) + { + ch->fepstartca = ch->startca; + ch->fepstopca = ch->stopca; + + /* --------------------------------------------------------------- + Similar to the above, this time the auxilarly XON / XOFF + characters have changed; propogate these changes to the card. + ------------------------------------------------------------------ */ + + fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1); + } + +} /* End epcaparam */ + +/* --------------------- Begin receive_data ----------------------- */ + +static void receive_data(struct channel *ch) +{ /* Begin receive_data */ + + unchar *rptr; + struct termios *ts = 0; + struct tty_struct *tty; + volatile struct board_chan *bc; + register int dataToRead, wrapgap, bytesAvailable; + register unsigned int tail, head; + unsigned int wrapmask; + int rc; + + + /* --------------------------------------------------------------- + This routine is called by doint when a receive data event + has taken place. + ------------------------------------------------------------------- */ + + globalwinon(ch); + + if (ch->statusflags & RXSTOPPED) + return; + + tty = ch->tty; + if (tty) + ts = tty->termios; + + bc = ch->brdchan; + + if (!bc) + { + printk(KERN_ERR " - bc is NULL in receive_data!\n"); + return; + } + + wrapmask = ch->rxbufsize - 1; + + /* --------------------------------------------------------------------- + Get the head and tail pointers to the receiver queue. Wrap the + head pointer if it has reached the end of the buffer. + ------------------------------------------------------------------------ */ + + head = bc->rin; + head &= wrapmask; + tail = bc->rout & wrapmask; + + bytesAvailable = (head - tail) & wrapmask; + + if (bytesAvailable == 0) + return; + + /* ------------------------------------------------------------------ + If CREAD bit is off or device not open, set TX tail to head + --------------------------------------------------------------------- */ + + if (!tty || !ts || !(ts->c_cflag & CREAD)) + { + bc->rout = head; + return; + } + + if (tty->flip.count == TTY_FLIPBUF_SIZE) + return; + + if (bc->orun) + { + bc->orun = 0; + printk(KERN_WARNING "overrun! DigiBoard device minor = %d\n",MINOR(tty->device)); + } + + rxwinon(ch); + rptr = tty->flip.char_buf_ptr; + rc = tty->flip.count; + + while (bytesAvailable > 0) + { /* Begin while there is data on the card */ + + wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail; + + /* --------------------------------------------------------------- + Even if head has wrapped around only report the amount of + data to be equal to the size - tail. Remember memcpy can't + automaticly wrap around the receive buffer. + ----------------------------------------------------------------- */ + + dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable; + + /* -------------------------------------------------------------- + Make sure we don't overflow the buffer + ----------------------------------------------------------------- */ + + if ((rc + dataToRead) > TTY_FLIPBUF_SIZE) + dataToRead = TTY_FLIPBUF_SIZE - rc; + + if (dataToRead == 0) + break; + + /* --------------------------------------------------------------- + Move data read from our card into the line disciplines buffer + for translation if necessary. + ------------------------------------------------------------------ */ + + if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr) + printk(KERN_ERR " - receive_data : memcpy failed\n"); + + rc += dataToRead; + rptr += dataToRead; + tail = (tail + dataToRead) & wrapmask; + bytesAvailable -= dataToRead; + + } /* End while there is data on the card */ + + + tty->flip.count = rc; + tty->flip.char_buf_ptr = rptr; + globalwinon(ch); + bc->rout = tail; + + /* Must be called with global data */ + tty_schedule_flip(ch->tty); + return; + +} /* End receive_data */ + +/* --------------------- Begin pc_ioctl ----------------------- */ + +static int pc_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ /* Begin pc_ioctl */ + + digiflow_t dflow; + int retval, error; + unsigned long flags; + unsigned int mflag, mstat; + unsigned char startc, stopc; + volatile struct board_chan *bc; + struct channel *ch = (struct channel *) tty->driver_data; + + /* The control device has it's own set of commands */ + if (tty->driver.subtype == SERIAL_TYPE_INFO) + { /* Begin if subtype is the control device */ + + switch (cmd) + { /* Begin switch cmd */ + + case DIGI_GETINFO: + { /* Begin case DIGI_GETINFO */ + + struct digi_info di ; + int brd; + + getUser(brd, (unsigned int *)arg); + + if ((error = verify_area(VERIFY_WRITE, (char*)arg, sizeof(di)))) + { + printk(KERN_ERR "DIGI_GETINFO : verify area size 0x%x failed\n",sizeof(di)); + return(error); + } + + if ((brd < 0) || (brd >= num_cards) || (num_cards == 0)) + return (-ENODEV); + + memset(&di, 0, sizeof(di)); + + di.board = brd ; + di.status = boards[brd].status; + di.type = boards[brd].type ; + di.numports = boards[brd].numports ; + di.port = boards[brd].port ; + di.membase = boards[brd].membase ; + + copy_to_user((char *)arg, &di, sizeof (di)); + break; + + } /* End case DIGI_GETINFO */ + + case DIGI_POLLER: + { /* Begin case DIGI_POLLER */ + + int brd = arg & 0xff000000 >> 16 ; + unsigned char state = arg & 0xff ; + + if ((brd < 0) || (brd >= num_cards)) + { + printk(KERN_ERR " - DIGI POLLER : brd not valid!\n"); + return (-ENODEV); + } + + digi_poller_inhibited = state ; + break ; + + } /* End case DIGI_POLLER */ + + case DIGI_INIT: + { /* Begin case DIGI_INIT */ + + /* ------------------------------------------------------------ + This call is made by the apps to complete the initilization + of the board(s). This routine is responsible for setting + the card to its initial state and setting the drivers control + fields to the sutianle settings for the card in question. + ---------------------------------------------------------------- */ + + int crd ; + for (crd = 0; crd < num_cards; crd++) + post_fep_init (crd); + + break ; + + } /* End case DIGI_INIT */ + + + default: + return -ENOIOCTLCMD; + + } /* End switch cmd */ + return (0) ; + + } /* End if subtype is the control device */ + + if (ch) + bc = ch->brdchan; + else + { + printk(KERN_ERR " - ch is NULL in pc_ioctl!\n"); + return(-EINVAL); + } + + save_flags(flags); + + /* ------------------------------------------------------------------- + For POSIX compliance we need to add more ioctls. See tty_ioctl.c + in /usr/src/linux/drivers/char for a good example. In particular + think about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS. + ---------------------------------------------------------------------- */ + + switch (cmd) + { /* Begin switch cmd */ + + case TCGETS: + retval = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct termios)); + + if (retval) + return(retval); + + copy_to_user((struct termios *)arg, + tty->termios, sizeof(struct termios)); + return(0); + + case TCGETA: + return get_termio(tty, (struct termio *)arg); + + case TCSBRK: /* SVID version: non-zero arg --> no break */ + + retval = tty_check_change(tty); + if (retval) + return retval; + + /* Setup an event to indicate when the transmit buffer empties */ + + setup_empty_event(tty,ch); + tty_wait_until_sent(tty, 0); + if (!arg) + digi_send_break(ch, HZ/4); /* 1/4 second */ + return 0; + + case TCSBRKP: /* support for POSIX tcsendbreak() */ + + retval = tty_check_change(tty); + if (retval) + return retval; + + /* Setup an event to indicate when the transmit buffer empties */ + + setup_empty_event(tty,ch); + tty_wait_until_sent(tty, 0); + digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4); + return 0; + + case TIOCGSOFTCAR: + + error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); + if (error) + return error; + + putUser(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + return 0; + + case TIOCSSOFTCAR: + /*RONNIE PUT VERIFY_READ (See above) check here */ + { + unsigned int value; + + getUser(value, (unsigned int *)arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (value ? CLOCAL : 0)); + return 0; + } + + case TIOCMODG: + case TIOCMGET: + + mflag = 0; + + cli(); + globalwinon(ch); + mstat = bc->mstat; + memoff(ch); + restore_flags(flags); + + if (mstat & ch->m_dtr) + mflag |= TIOCM_DTR; + + if (mstat & ch->m_rts) + mflag |= TIOCM_RTS; + + if (mstat & ch->m_cts) + mflag |= TIOCM_CTS; + + if (mstat & ch->dsr) + mflag |= TIOCM_DSR; + + if (mstat & ch->m_ri) + mflag |= TIOCM_RI; + + if (mstat & ch->dcd) + mflag |= TIOCM_CD; + + error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); + + if (error) + return error; + + putUser(mflag, (unsigned long *) arg); + + break; + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMODS: + case TIOCMSET: + + getUser(mstat, (unsigned int *)arg); + + mflag = 0; + if (mstat & TIOCM_DTR) + mflag |= ch->m_dtr; + + if (mstat & TIOCM_RTS) + mflag |= ch->m_rts; + + switch (cmd) + { /* Begin switch cmd */ + + case TIOCMODS: + case TIOCMSET: + ch->modemfake = ch->m_dtr|ch->m_rts; + ch->modem = mflag; + break; + + case TIOCMBIS: + ch->modemfake |= mflag; + ch->modem |= mflag; + break; + + case TIOCMBIC: + ch->modemfake |= mflag; + ch->modem &= ~mflag; + break; + + } /* End switch cmd */ + + cli(); + globalwinon(ch); + + /* -------------------------------------------------------------- + The below routine generally sets up parity, baud, flow control + issues, etc.... It effect both control flags and input flags. + ------------------------------------------------------------------ */ + + epcaparam(tty,ch); + memoff(ch); + restore_flags(flags); + break; + + case TIOCSDTR: + ch->omodem |= ch->m_dtr; + cli(); + globalwinon(ch); + fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1); + memoff(ch); + restore_flags(flags); + break; + + case TIOCCDTR: + ch->omodem &= ~ch->m_dtr; + cli(); + globalwinon(ch); + fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1); + memoff(ch); + restore_flags(flags); + break; + + case DIGI_GETA: + if ((error= + verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t)))) + { + printk(KERN_ERR " - Digi GETA failed\n"); + return(error); + } + + copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t)); + break; + + case DIGI_SETAW: + case DIGI_SETAF: + if ((cmd) == (DIGI_SETAW)) + { + /* Setup an event to indicate when the transmit buffer empties */ + + setup_empty_event(tty,ch); + tty_wait_until_sent(tty, 0); + } + else + { + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + } + + /* Fall Thru */ + + case DIGI_SETA: + if ((error = + verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t)))) + return(error); + + copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t)); + + if (ch->digiext.digi_flags & DIGI_ALTPIN) + { + ch->dcd = ch->m_dsr; + ch->dsr = ch->m_dcd; + } + else + { + ch->dcd = ch->m_dcd; + ch->dsr = ch->m_dsr; + } + + cli(); + globalwinon(ch); + + /* ----------------------------------------------------------------- + The below routine generally sets up parity, baud, flow control + issues, etc.... It effect both control flags and input flags. + ------------------------------------------------------------------- */ + + epcaparam(tty,ch); + memoff(ch); + restore_flags(flags); + break; + + case DIGI_GETFLOW: + case DIGI_GETAFLOW: + cli(); + globalwinon(ch); + if ((cmd) == (DIGI_GETFLOW)) + { + dflow.startc = bc->startc; + dflow.stopc = bc->stopc; + } + else + { + dflow.startc = bc->startca; + dflow.stopc = bc->stopca; + } + memoff(ch); + restore_flags(flags); + + if ((error = verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow)))) + return(error); + + copy_to_user((char*)arg, &dflow, sizeof(dflow)); + break; + + case DIGI_SETAFLOW: + case DIGI_SETFLOW: + if ((cmd) == (DIGI_SETFLOW)) + { + startc = ch->startc; + stopc = ch->stopc; + } + else + { + startc = ch->startca; + stopc = ch->stopca; + } + + if ((error = verify_area(VERIFY_READ, (char*)arg,sizeof(dflow)))) + return(error); + + copy_from_user(&dflow, (char*)arg, sizeof(dflow)); + + if (dflow.startc != startc || dflow.stopc != stopc) + { /* Begin if setflow toggled */ + cli(); + globalwinon(ch); + + if ((cmd) == (DIGI_SETFLOW)) + { + ch->fepstartc = ch->startc = dflow.startc; + ch->fepstopc = ch->stopc = dflow.stopc; + fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1); + } + else + { + ch->fepstartca = ch->startca = dflow.startc; + ch->fepstopca = ch->stopca = dflow.stopc; + fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1); + } + + if (ch->statusflags & TXSTOPPED) + pc_start(tty); + + memoff(ch); + restore_flags(flags); + + } /* End if setflow toggled */ + break; + + default: + return -ENOIOCTLCMD; + + } /* End switch cmd */ + + return 0; + +} /* End pc_ioctl */ + +/* --------------------- Begin pc_set_termios ----------------------- */ + +static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ /* Begin pc_set_termios */ + + struct channel *ch; + unsigned long flags; + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { /* Begin if channel valid */ + + save_flags(flags); + cli(); + globalwinon(ch); + epcaparam(tty, ch); + memoff(ch); + + if ((old_termios->c_cflag & CRTSCTS) && + ((tty->termios->c_cflag & CRTSCTS) == 0)) + tty->hw_stopped = 0; + + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&ch->open_wait); + + restore_flags(flags); + + } /* End if channel valid */ + +} /* End pc_set_termios */ + +/* --------------------- Begin do_softint ----------------------- */ + +static void do_softint(void *private_) +{ /* Begin do_softint */ + + struct channel *ch = (struct channel *) private_; + + + /* Called in response to a modem change event */ + + if (ch && ch->magic == EPCA_MAGIC) + { /* Begin EPCA_MAGIC */ + + struct tty_struct *tty = ch->tty; + + if (tty && tty->driver_data) + { + if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) + { /* Begin if clear_bit */ + + tty_hangup(tty); + wake_up_interruptible(&ch->open_wait); + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + + } /* End if clear_bit */ + } + + } /* End EPCA_MAGIC */ + +} /* End do_softint */ + +/* ------------------------------------------------------------ + pc_stop and pc_start provide software flow control to the + routine and the pc_ioctl routine. +---------------------------------------------------------------- */ + +/* --------------------- Begin pc_stop ----------------------- */ + +static void pc_stop(struct tty_struct *tty) +{ /* Begin pc_stop */ + + struct channel *ch; + unsigned long flags; + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { /* Begin if valid channel */ + + save_flags(flags); + cli(); + + if ((ch->statusflags & TXSTOPPED) == 0) + { /* Begin if transmit stop requested */ + + globalwinon(ch); + + /* STOP transmitting now !! */ + + fepcmd(ch, PAUSETX, 0, 0, 0, 0); + + ch->statusflags |= TXSTOPPED; + memoff(ch); + + } /* End if transmit stop requested */ + + restore_flags(flags); + + } /* End if valid channel */ + +} /* End pc_stop */ + +/* --------------------- Begin pc_start ----------------------- */ + +static void pc_start(struct tty_struct *tty) +{ /* Begin pc_start */ + + struct channel *ch; + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { /* Begin if channel valid */ + + unsigned long flags; + + save_flags(flags); + cli(); + + /* Just in case output was resumed because of a change in Digi-flow */ + if (ch->statusflags & TXSTOPPED) + { /* Begin transmit resume requested */ + + volatile struct board_chan *bc; + + globalwinon(ch); + bc = ch->brdchan; + if (ch->statusflags & LOWWAIT) + bc->ilow = 1; + + /* Okay, you can start transmitting again... */ + + fepcmd(ch, RESUMETX, 0, 0, 0, 0); + + ch->statusflags &= ~TXSTOPPED; + memoff(ch); + + } /* End transmit resume requested */ + + restore_flags(flags); + + } /* End if channel valid */ + +} /* End pc_start */ + +/* ------------------------------------------------------------------ + The below routines pc_throttle and pc_unthrottle are used + to slow (And resume) the receipt of data into the kernels + receive buffers. The exact occurence of this depends on the + size of the kernels receive buffer and what the 'watermarks' + are set to for that buffer. See the n_ttys.c file for more + details. +______________________________________________________________________ */ +/* --------------------- Begin throttle ----------------------- */ + +static void pc_throttle(struct tty_struct * tty) +{ /* Begin pc_throttle */ + + struct channel *ch; + unsigned long flags; + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { /* Begin if channel valid */ + + + save_flags(flags); + cli(); + + if ((ch->statusflags & RXSTOPPED) == 0) + { + globalwinon(ch); + fepcmd(ch, PAUSERX, 0, 0, 0, 0); + + ch->statusflags |= RXSTOPPED; + memoff(ch); + } + restore_flags(flags); + + } /* End if channel valid */ + +} /* End pc_throttle */ + +/* --------------------- Begin unthrottle ----------------------- */ + +static void pc_unthrottle(struct tty_struct *tty) +{ /* Begin pc_unthrottle */ + + struct channel *ch; + unsigned long flags; + volatile struct board_chan *bc; + + + /* --------------------------------------------------------- + verifyChannel returns the channel from the tty struct + if it is valid. This serves as a sanity check. + ------------------------------------------------------------- */ + + if ((ch = verifyChannel(tty)) != NULL) + { /* Begin if channel valid */ + + + /* Just in case output was resumed because of a change in Digi-flow */ + save_flags(flags); + cli(); + + if (ch->statusflags & RXSTOPPED) + { + + globalwinon(ch); + bc = ch->brdchan; + fepcmd(ch, RESUMERX, 0, 0, 0, 0); + + ch->statusflags &= ~RXSTOPPED; + memoff(ch); + } + restore_flags(flags); + + } /* End if channel valid */ + +} /* End pc_unthrottle */ + +/* --------------------- Begin digi_send_break ----------------------- */ + +void digi_send_break(struct channel *ch, int msec) +{ /* Begin digi_send_break */ + + unsigned long flags; + + save_flags(flags); + cli(); + globalwinon(ch); + + /* -------------------------------------------------------------------- + Maybe I should send an infinite break here, schedule() for + msec amount of time, and then stop the break. This way, + the user can't screw up the FEP by causing digi_send_break() + to be called (i.e. via an ioctl()) more than once in msec amount + of time. Try this for now... + ------------------------------------------------------------------------ */ + + fepcmd(ch, SENDBREAK, msec, 0, 10, 0); + memoff(ch); + + restore_flags(flags); + +} /* End digi_send_break */ + +/* --------------------- Begin setup_empty_event ----------------------- */ + +static void setup_empty_event(struct tty_struct *tty, struct channel *ch) +{ /* Begin setup_empty_event */ + + volatile struct board_chan *bc = ch->brdchan; + unsigned long int flags; + + save_flags(flags); + cli(); + globalwinon(ch); + ch->statusflags |= EMPTYWAIT; + + /* ------------------------------------------------------------------ + When set the iempty flag request a event to be generated when the + transmit buffer is empty (If there is no BREAK in progress). + --------------------------------------------------------------------- */ + + bc->iempty = 1; + memoff(ch); + restore_flags(flags); + +} /* End setup_empty_event */ + +/* --------------------- Begin get_termio ----------------------- */ + +static int get_termio(struct tty_struct * tty, struct termio * termio) +{ /* Begin get_termio */ + int error; + + error = verify_area(VERIFY_WRITE, termio, sizeof (struct termio)); + if (error) + return error; + + kernel_termios_to_user_termio(termio, tty->termios); + + return 0; +} /* End get_termio */ +/* ---------------------- Begin epca_setup -------------------------- */ +void epca_setup(char *str, int *ints) +{ /* Begin epca_setup */ + + struct board_info board; + int index, loop, last; + char *temp, *t2; + unsigned len; + + /* ---------------------------------------------------------------------- + If this routine looks a little strange it is because it is only called + if a LILO append command is given to boot the kernel with parameters. + In this way, we can provide the user a method of changing his board + configuration without rebuilding the kernel. + ----------------------------------------------------------------------- */ + if (!liloconfig) + liloconfig = 1; + + memset(&board, 0, sizeof(board)); + + /* Assume the data is int first, later we can change it */ + /* I think that array position 0 of ints holds the number of args */ + for (last = 0, index = 1; index <= ints[0]; index++) + switch(index) + { /* Begin parse switch */ + + case 1: + board.status = ints[index]; + + /* --------------------------------------------------------- + We check for 2 (As opposed to 1; because 2 is a flag + instructing the driver to ignore epcaconfig.) For this + reason we check for 2. + ------------------------------------------------------------ */ + if (board.status == 2) + { /* Begin ignore epcaconfig as well as lilo cmd line */ + nbdevs = 0; + num_cards = 0; + return; + } /* End ignore epcaconfig as well as lilo cmd line */ + + if (board.status > 2) + { + printk(KERN_ERR " - epca_setup: Invalid board status 0x%x\n", board.status); + invalid_lilo_config = 1; + setup_error_code |= INVALID_BOARD_STATUS; + return; + } + last = index; + break; + + case 2: + board.type = ints[index]; + if (board.type >= PCIXEM) + { + printk(KERN_ERR " - epca_setup: Invalid board type 0x%x\n", board.type); + invalid_lilo_config = 1; + setup_error_code |= INVALID_BOARD_TYPE; + return; + } + last = index; + break; + + case 3: + board.altpin = ints[index]; + if (board.altpin > 1) + { + printk(KERN_ERR " - epca_setup: Invalid board altpin 0x%x\n", board.altpin); + invalid_lilo_config = 1; + setup_error_code |= INVALID_ALTPIN; + return; + } + last = index; + break; + + case 4: + board.numports = ints[index]; + if ((board.numports < 2) || (board.numports > 256)) + { + printk(KERN_ERR " - epca_setup: Invalid board numports 0x%x\n", board.numports); + invalid_lilo_config = 1; + setup_error_code |= INVALID_NUM_PORTS; + return; + } + nbdevs += board.numports; + last = index; + break; + + case 5: + board.port = (unsigned char *)ints[index]; + if (board.port <= 0) + { + printk(KERN_ERR " - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port); + invalid_lilo_config = 1; + setup_error_code |= INVALID_PORT_BASE; + return; + } + last = index; + break; + + case 6: + board.membase = (unsigned char *)ints[index]; + if (board.membase <= 0) + { + printk(KERN_ERR " - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase); + invalid_lilo_config = 1; + setup_error_code |= INVALID_MEM_BASE; + return; + } + last = index; + break; + + default: + printk(KERN_ERR " - epca_setup: Too many integer parms\n"); + return; + + } /* End parse switch */ + + while (str && *str) + { /* Begin while there is a string arg */ + + /* find the next comma or terminator */ + temp = str; + + /* While string is not null, and a comma hasn't been found */ + while (*temp && (*temp != ',')) + temp++; + + if (!*temp) + temp = NULL; + else + *temp++ = 0; + + /* Set index to the number of args + 1 */ + index = last + 1; + + switch(index) + { + case 1: + len = strlen(str); + if (strncmp("Disable", str, len) == 0) + board.status = 0; + else + if (strncmp("Enable", str, len) == 0) + board.status = 1; + else + { + printk(KERN_ERR " - epca_setup: Invalid status %s\n", str); + invalid_lilo_config = 1; + setup_error_code |= INVALID_BOARD_STATUS; + return; + } + last = index; + break; + + case 2: + + for(loop = 0; loop < EPCA_NUM_TYPES; loop++) + if (strcmp(board_desc[loop], str) == 0) + break; + + + /* --------------------------------------------------------------- + If the index incremented above refers to a legitamate board + type set it here. + ------------------------------------------------------------------*/ + + if (index < EPCA_NUM_TYPES) + board.type = loop; + else + { + printk(KERN_ERR " - epca_setup: Invalid board type: %s\n", str); + invalid_lilo_config = 1; + setup_error_code |= INVALID_BOARD_TYPE; + return; + } + last = index; + break; + + case 3: + len = strlen(str); + if (strncmp("Disable", str, len) == 0) + board.altpin = 0; + else + if (strncmp("Enable", str, len) == 0) + board.altpin = 1; + else + { + printk(KERN_ERR " - epca_setup: Invalid altpin %s\n", str); + invalid_lilo_config = 1; + setup_error_code |= INVALID_ALTPIN; + return; + } + last = index; + break; + + case 4: + t2 = str; + while (isdigit(*t2)) + t2++; + + if (*t2) + { + printk(KERN_ERR " - epca_setup: Invalid port count %s\n", str); + invalid_lilo_config = 1; + setup_error_code |= INVALID_NUM_PORTS; + return; + } + + /* ------------------------------------------------------------ + There is not a man page for simple_strtoul but the code can be + found in vsprintf.c. The first argument is the string to + translate (To an unsigned long obviously), the second argument + can be the address of any character variable or a NULL. If a + variable is given, the end pointer of the string will be stored + in that variable; if a NULL is given the the end pointer will + not be returned. The last argument is the base to use. If + a 0 is indicated, the routine will attempt to determine the + proper base by looking at the values prefix (A '0' for octal, + a 'x' for hex, etc ... If a value is given it will use that + value as the base. + ---------------------------------------------------------------- */ + board.numports = simple_strtoul(str, NULL, 0); + nbdevs += board.numports; + last = index; + break; + + case 5: + t2 = str; + while (isxdigit(*t2)) + t2++; + + if (*t2) + { + printk(KERN_ERR " - epca_setup: Invalid i/o address %s\n", str); + invalid_lilo_config = 1; + setup_error_code |= INVALID_PORT_BASE; + return; + } + + board.port = (unsigned char *)simple_strtoul(str, NULL, 16); + last = index; + break; + + case 6: + t2 = str; + while (isxdigit(*t2)) + t2++; + + if (*t2) + { + printk(KERN_ERR " - epca_setup: Invalid memory base %s\n",str); + invalid_lilo_config = 1; + setup_error_code |= INVALID_MEM_BASE; + return; + } + + board.membase = (unsigned char *)simple_strtoul(str, NULL, 16); + last = index; + break; + + default: + printk(KERN_ERR "PC/Xx: Too many string parms\n"); + return; + } + str = temp; + + } /* End while there is a string arg */ + + + if (last < 6) + { + printk(KERN_ERR "PC/Xx: Insufficient parms specified\n"); + return; + } + + /* I should REALLY validate the stuff here */ + + /* Copies our local copy of board into boards */ + memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board)); + + + /* Does this get called once per lilo arg are what ? */ + + printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n", + num_cards, board_desc[board.type], + board.numports, (int)board.port, (unsigned int) board.membase); + + num_cards++; + +} /* End epca_setup */ + + + +#ifdef ENABLE_PCI +/* --------------------- Begin get_PCI_configuration ---------------------- */ + +int get_PCI_configuration(char bus, char device_fn, + unsigned int *base_addr0, unsigned int *base_addr1, + unsigned int *base_addr2, unsigned int *base_addr3, + unsigned int *base_addr4, unsigned int *base_addr5) +{ /* Begin get_PCI_configuration */ + + int error; + + error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, + base_addr0); + + error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, + base_addr1); + + error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2, + base_addr2); + + error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_3, + base_addr3); + + error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_4, + base_addr4); + + error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_5, + base_addr5); + + /* ------------------------------------------------------------------------ + NOTE - The code below mask out either the 2 or 4 bits dependant on the + space being addressed. (base_addr value reflecting io space, have their + first 2 bits mask out, while base_addr value reflecting mem space, have + their first 4 bits mask out.) These bits are flag bits and should always + be 0 when used as an address. + ---------------------------------------------------------------------------- */ + + if ((*base_addr0) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ + (*base_addr0) &= PCI_BASE_ADDRESS_IO_MASK; + else + (*base_addr0) &= PCI_BASE_ADDRESS_MEM_MASK; + + if ((*base_addr1) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ + (*base_addr1) &= PCI_BASE_ADDRESS_IO_MASK; + else + (*base_addr1) &= PCI_BASE_ADDRESS_MEM_MASK; + + if ((*base_addr2) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ + (*base_addr2) &= PCI_BASE_ADDRESS_IO_MASK; + else + (*base_addr2) &= PCI_BASE_ADDRESS_MEM_MASK; + + if ((*base_addr3) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ + (*base_addr3) &= PCI_BASE_ADDRESS_IO_MASK; + else + (*base_addr3) &= PCI_BASE_ADDRESS_MEM_MASK; + + if ((*base_addr4) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ + (*base_addr4) &= PCI_BASE_ADDRESS_IO_MASK; + else + (*base_addr4) &= PCI_BASE_ADDRESS_MEM_MASK; + + if ((*base_addr5) & PCI_BASE_ADDRESS_SPACE_IO) /* Is this an io address ? */ + (*base_addr5) &= PCI_BASE_ADDRESS_IO_MASK; + else + (*base_addr5) &= PCI_BASE_ADDRESS_MEM_MASK; + + if (error) + { + printk(KERN_ERR " - DIGI PCI error: board not initializing due to error\n"); + return(0); + } + return(1); +} /* End get_PCI_configuration */ + +/* ------------------------ Begin init_PCI --------------------------- */ + +int init_PCI(int boards_found) +{ /* Begin init_PCI */ + + unsigned char bus, device_fn; + int i, pci_count = 0; + unsigned int base_addr0, base_addr1, base_addr2, + base_addr3, base_addr4, base_addr5; + + base_addr0 = base_addr1 = base_addr2 = 0; + base_addr3 = base_addr4 = base_addr5 = 0; + + for(i = 0; i < (MAXBOARDS - boards_found); i++) + { /* Begin for each POSSIBLE remaining board */ + + if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XR, + i, &bus, &device_fn)) + { /* Begin found XR */ + if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1, + &base_addr2, &base_addr3, + &base_addr4, &base_addr5)) + { /* Store a PCI/XR into the boards structure */ + + + boards[boards_found + pci_count].status = ENABLED; + boards[boards_found + pci_count].type = PCIXR; + + boards[boards_found + pci_count].numports = 0x0; + + boards[boards_found + pci_count].port = (unsigned char *)((char *)base_addr0 + PCI_IO_OFFSET); + /* Most cards use base_addr0, but some use base_addr2 */ + boards[boards_found + pci_count].membase = (unsigned char *)base_addr0; + + if (base_addr0 >= 0x100000) + { + /* ------------------------------------------------------------ + Standard physical addresses are valid to the kernel as long + as they aren't above RAM. Higher addresses (Such as are + typical of a PCI system) need to be mapped in with the + ioremap command. For boards using such high addresses the + driver will store both addresses. One address (The physical) + will be held for the apps use (And mmap) and the other (The + ioremapped address) will be used in the kernel. + + ---------------------------------------------------------------- */ + boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000); + boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000); + } + + pci_count++; + + /* -------------------------------------------------------------- + I don't know what the below does, but the hardware guys say + its required on everything except PLX (In this case XRJ). + ---------------------------------------------------------------- */ + pcibios_write_config_byte(bus, device_fn, 0x40, 0); + pcibios_write_config_byte(bus, device_fn, 0x46, 0); + + } /* End store a PCI/XR into the board structure */ + + } /* End found XR */ + + if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XEM, + i, &bus, &device_fn)) + { /* Begin found XEM */ + + if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1, + &base_addr2, &base_addr3, + &base_addr4, &base_addr5)) + { /* Begin store a PCI/XEM into the boards structure */ + + boards[boards_found + pci_count].status = ENABLED; + boards[boards_found + pci_count].type = PCIXEM; + + boards[boards_found + pci_count].numports = 0x0; + boards[boards_found + pci_count].port = (char *)((char *)base_addr0 + PCI_IO_OFFSET); + /* Most cards use base_addr0, but some use base_addr2 */ + boards[boards_found + pci_count].membase = (unsigned char *)base_addr0; + + if (base_addr0 >= 0x100000) + { + /* ------------------------------------------------------------ + Standard physical addresses are valid to the kernel as long + as they aren't above RAM. Higher addresses (Such as are + typical of a PCI system) need to be mapped in with the + ioremap command. For boards using such high addresses the + driver will store both addresses. One address (The physical) + will be held for the apps use (And mmap) and the other (The + vremapped address) will be used in the kernel. + + ---------------------------------------------------------------- */ + boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000); + boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000); + } + + pci_count++; + /* -------------------------------------------------------------- + I don't know what the below does, but the hardware guys say + its required on everything except PLX (In this case XRJ). + ---------------------------------------------------------------- */ + pcibios_write_config_byte(bus, device_fn, 0x40, 0); + pcibios_write_config_byte(bus, device_fn, 0x46, 0); + + } /* End store a PCI/XEM into the boards structure */ + + } /* End found XEM */ + + + if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_CX, + i, &bus, &device_fn)) + { /* Begin found CX */ + + if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1, + &base_addr2, &base_addr3, + &base_addr4, &base_addr5)) + { /* Begin store a PCI/CX into the boards structure */ + + boards[boards_found + pci_count].status = ENABLED; + boards[boards_found + pci_count].type = PCICX; + + boards[boards_found + pci_count].numports = 0x0; + boards[boards_found + pci_count].port = (char *)((char *)base_addr0 + PCI_IO_OFFSET); + /* Most cards use base_addr0, but some use base_addr2 */ + boards[boards_found + pci_count].membase = (unsigned char *)base_addr0; + + if (base_addr0 >= 0x100000) + { + /* ------------------------------------------------------------ + Standard physical addresses are valid to the kernel as long + as they aren't above RAM. Higher addresses (Such as are + typical of a PCI system) need to be mapped in with the + ioremap command. For boards using such high addresses the + driver will store both addresses. One address (The physical) + will be held for the apps use (And mmap) and the other (The + vremapped address) will be used in the kernel. + + ---------------------------------------------------------------- */ + boards[boards_found + pci_count].re_map_port = ioremap((base_addr0 + PCI_IO_OFFSET),0x200000); + boards[boards_found + pci_count].re_map_membase = ioremap(base_addr0, 0x200000); + } + + pci_count++; + /* -------------------------------------------------------------- + I don't know what the below does, but the hardware guys say + its required on everything except PLX (In this case XRJ). + ---------------------------------------------------------------- */ + pcibios_write_config_byte(bus, device_fn, 0x40, 0); + pcibios_write_config_byte(bus, device_fn, 0x46, 0); + + } /* End store a PCI/CX into the boards structure */ + + } /* End found CX */ + + if (!pcibios_find_device(PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, + i, &bus, &device_fn)) + { /* Begin found XRJ */ + + if (get_PCI_configuration(bus, device_fn, &base_addr0, &base_addr1, + &base_addr2, &base_addr3, + &base_addr4, &base_addr5)) + { /* Begin store a PCI/XRJ into the boards structure */ + + boards[boards_found + pci_count].status = ENABLED; + boards[boards_found + pci_count].type = PCIXRJ; + + boards[boards_found + pci_count].numports = 0x0; + boards[boards_found + pci_count].port = (unsigned char *)(base_addr2 + PCI_IO_OFFSET); + /* Most cards use base_addr0, but some use base_addr2 */ + boards[boards_found + pci_count].membase = (unsigned char *)base_addr2; + + if (base_addr2 >= 0x100000) + { + /* ------------------------------------------------------------ + Standard physical addresses are valid to the kernel as long + as they aren't above RAM. Higher addresses (Such as are + typical of a PCI system) need to be mapped in with the + ioremap command. For boards using such high addresses the + driver will store both addresses. One address (The physical) + will be held for the apps use (And mmap) and the other (The + vremapped address) will be used in the kernel. + + ---------------------------------------------------------------- */ + boards[boards_found + pci_count].re_map_port = ioremap((base_addr2 + PCI_IO_OFFSET),0x200000); + boards[boards_found + pci_count].re_map_membase = ioremap(base_addr2, 0x200000); + } + + pci_count++; + + } /* End store a PCI/XRJ into the boards structure */ + + } /* End found XRJ */ + + } /* End for each POSSIBLE remaining board */ + + return(pci_count); + +} /* End init_PCI */ + +#endif /* ENABLE_PCI */ + + diff -u --recursive --new-file v2.1.36/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.1.36/linux/drivers/char/esp.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/esp.c Mon May 12 10:35:40 1997 @@ -689,7 +689,7 @@ if (!tty) return; - if (clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) { + if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); diff -u --recursive --new-file v2.1.36/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c --- v2.1.36/linux/drivers/char/fbmem.c Fri Apr 4 08:52:19 1997 +++ linux/drivers/char/fbmem.c Mon May 12 10:35:40 1997 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -300,8 +301,8 @@ return 0; } -void -fbmem_init(void) +__initfunc(void +fbmem_init(void)) { if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR); diff -u --recursive --new-file v2.1.36/linux/drivers/char/ftape/kernel-interface.c linux/drivers/char/ftape/kernel-interface.c --- v2.1.36/linux/drivers/char/ftape/kernel-interface.c Fri Apr 4 08:52:19 1997 +++ linux/drivers/char/ftape/kernel-interface.c Mon May 12 10:35:40 1997 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -120,7 +121,7 @@ #define ftape_init init_module #endif -int ftape_init(void) +__initfunc(int ftape_init(void)) { int n; int order; diff -u --recursive --new-file v2.1.36/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.1.36/linux/drivers/char/istallion.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/istallion.c Mon May 12 10:35:40 1997 @@ -1005,7 +1005,7 @@ set_bit(ST_GETSIGS, &portp->state); if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0) return(rc); - if (clear_bit(ST_GETSIGS, &portp->state)) + if (test_and_clear_bit(ST_GETSIGS, &portp->state)) portp->sigs = stli_mktiocm(portp->asig.sigvalue); stli_mkasysigs(&portp->asig, 1, 1); if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0) diff -u --recursive --new-file v2.1.36/linux/drivers/char/keyb_m68k.c linux/drivers/char/keyb_m68k.c --- v2.1.36/linux/drivers/char/keyb_m68k.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/keyb_m68k.c Mon May 12 17:39:50 1997 @@ -205,7 +205,7 @@ keycode &= 0x7f; if (up_flag) { rep = 0; - if(!clear_bit(keycode, key_down)) { + if(!test_and_clear_bit(keycode, key_down)) { /* unexpected, but this can happen: maybe this was a key release for a FOCUS 9000 PF key; if we want to see it, we have to clear @@ -216,7 +216,7 @@ #endif } } else - rep = set_bit(keycode, key_down); + rep = test_and_set_bit(keycode, key_down); if (raw_mode) return; diff -u --recursive --new-file v2.1.36/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.1.36/linux/drivers/char/keyboard.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/keyboard.c Mon May 12 10:35:40 1997 @@ -501,7 +501,7 @@ if (up_flag) { rep = 0; - if(!clear_bit(keycode, key_down)) { + if(!test_and_clear_bit(keycode, key_down)) { /* unexpected, but this can happen: maybe this was a key release for a FOCUS 9000 PF key; if we want to see it, we have to clear @@ -510,7 +510,7 @@ up_flag = 0; } } else - rep = set_bit(keycode, key_down); + rep = test_and_set_bit(keycode, key_down); if (kbd->kbdmode == VC_MEDIUMRAW) { /* soon keycodes will require more than one byte */ diff -u --recursive --new-file v2.1.36/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.36/linux/drivers/char/lp.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/lp.c Mon May 12 10:35:40 1997 @@ -631,7 +631,7 @@ static int parport_ptr = 0; -void lp_setup(char *str, int *ints) +__initfunc(void lp_setup(char *str, int *ints)) { /* Ugh. */ if (!strncmp(str, "parport", 7)) { diff -u --recursive --new-file v2.1.36/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c --- v2.1.36/linux/drivers/char/lp_intern.c Fri Dec 20 01:20:00 1996 +++ linux/drivers/char/lp_intern.c Mon May 12 10:35:40 1997 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_AMIGA @@ -33,7 +34,6 @@ #endif #include -static int my_inter = 0; static int minor = -1; static void lp_int_out(int, int); @@ -126,24 +126,18 @@ } } -static int lp_int_my_interrupt(int dev) -{ - return my_inter; -} - static void lp_int_interrupt(int irq, void *data, struct pt_regs *fp) { - my_inter = 1; - lp_interrupt(irq, data, fp); - my_inter = 0; + lp_interrupt(minor); } -static void lp_int_open(void) +static int lp_int_open(int dev) { MOD_INC_USE_COUNT; + return 0; } -static void lp_int_release(void) +static void lp_int_release(int dev) { MOD_DEC_USE_COUNT; } @@ -155,7 +149,7 @@ lp_int_busy, lp_int_pout, lp_int_online, - lp_int_my_interrupt, + 0, NULL, /* ioctl */ lp_int_open, lp_int_release, @@ -167,7 +161,7 @@ NULL, }; -int lp_internal_init(void) +__initfunc(int lp_internal_init(void)) { #ifdef CONFIG_AMIGA if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) diff -u --recursive --new-file v2.1.36/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c --- v2.1.36/linux/drivers/char/lp_m68k.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/lp_m68k.c Mon May 12 10:35:40 1997 @@ -41,6 +41,7 @@ #include #include #include +#include #include #ifdef CONFIG_KERNELD #include @@ -465,7 +466,7 @@ EXPORT_SYMBOL(register_parallel); EXPORT_SYMBOL(unregister_parallel); -int lp_init(void) +__initfunc(int lp_init(void)) { extern char m68k_debug_device[]; @@ -498,7 +499,7 @@ /* * Currently we do not accept any lp-parameters, but that may change. */ -void lp_setup(char *str, int *ints) +__initfunc(void lp_setup(char *str, int *ints)) { } diff -u --recursive --new-file v2.1.36/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.1.36/linux/drivers/char/mem.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/mem.c Mon May 12 10:35:40 1997 @@ -139,7 +139,8 @@ else tmp = count; read = tmp; -#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */ +#if defined(__sparc__) || defined(__mc68000__) + /* we don't have page 0 mapped on sparc and m68k.. */ while (p < PAGE_SIZE && tmp > 0) { put_user(0,buf); buf++; @@ -172,7 +173,8 @@ if (count > (unsigned long) high_memory - p) count = (unsigned long) high_memory - p; written = 0; -#if defined(__sparc__) /* we don't have page 0 mapped on sparc.. */ +#if defined(__sparc__) || defined(__mc68000__) + /* we don't have page 0 mapped on sparc and m68k.. */ while (p < PAGE_SIZE && count > 0) { /* Hmm. Do something? */ buf++; diff -u --recursive --new-file v2.1.36/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.36/linux/drivers/char/misc.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/misc.c Mon May 12 10:35:40 1997 @@ -73,6 +73,7 @@ extern void wdt_init(void); extern void pcwatchdog_init(void); extern int rtc_init(void); +extern int dsp56k_init(void); #ifdef CONFIG_PROC_FS static int misc_read_proc(char *buf, char **start, off_t offset, @@ -234,6 +235,9 @@ #endif #ifdef CONFIG_RTC rtc_init(); +#endif +#ifdef CONFIG_ATARI_DSP56K + dsp56k_init(); #endif #endif /* !MODULE */ if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { diff -u --recursive --new-file v2.1.36/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c --- v2.1.36/linux/drivers/char/msbusmouse.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/msbusmouse.c Mon May 12 10:35:40 1997 @@ -51,7 +51,7 @@ static struct mouse_status mouse; static int mouse_irq = MOUSE_IRQ; -void msmouse_setup(char *str, int *ints) +__initfunc(void msmouse_setup(char *str, int *ints)) { if (ints[0] > 0) mouse_irq=ints[1]; diff -u --recursive --new-file v2.1.36/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.1.36/linux/drivers/char/n_tty.c Mon Apr 14 16:28:11 1997 +++ linux/drivers/char/n_tty.c Mon May 12 10:35:40 1997 @@ -78,7 +78,7 @@ return; if (tty->driver.unthrottle && - clear_bit(TTY_THROTTLED, &tty->flags)) + test_and_clear_bit(TTY_THROTTLED, &tty->flags)) tty->driver.unthrottle(tty); if (tty->link->packet) { tty->ctrl_status |= TIOCPKT_FLUSHREAD; @@ -598,7 +598,7 @@ if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) && tty->driver.throttle && - !set_bit(TTY_THROTTLED, &tty->flags)) + !test_and_set_bit(TTY_THROTTLED, &tty->flags)) tty->driver.throttle(tty); } @@ -874,7 +874,7 @@ if (!tty->read_cnt) { break; } - eol = clear_bit(tty->read_tail, + eol = test_and_clear_bit(tty->read_tail, &tty->read_flags); c = tty->read_buf[tty->read_tail]; tty->read_tail = ((tty->read_tail+1) & @@ -904,7 +904,7 @@ low-level driver know. */ if (tty->driver.unthrottle && (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE) - && clear_bit(TTY_THROTTLED, &tty->flags)) + && test_and_clear_bit(TTY_THROTTLED, &tty->flags)) tty->driver.unthrottle(tty); if (b - buf >= minimum || !nr) @@ -923,7 +923,7 @@ size = b - buf; if (size && nr) clear_bit(TTY_PUSH, &tty->flags); - if (!size && clear_bit(TTY_PUSH, &tty->flags)) + if (!size && test_and_clear_bit(TTY_PUSH, &tty->flags)) goto do_it_again; if (!size && !retval) clear_bit(TTY_PUSH, &tty->flags); diff -u --recursive --new-file v2.1.36/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.1.36/linux/drivers/char/pcxx.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/pcxx.c Mon May 12 10:35:40 1997 @@ -895,7 +895,7 @@ * Driver setup function when linked into the kernel to optionally parse multible * "digi="-lines and initialize the driver at boot time. No probing. */ -void pcxx_setup(char *str, int *ints) +__initfunc(void pcxx_setup(char *str, int *ints)) { struct board_info board; @@ -2358,7 +2358,7 @@ if(info && info->magic == PCXX_MAGIC) { struct tty_struct *tty = info->tty; if (tty && tty->driver_data) { - if(clear_bit(PCXE_EVENT_HANGUP, &info->event)) { + if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) { tty_hangup(tty); wake_up_interruptible(&info->open_wait); info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); diff -u --recursive --new-file v2.1.36/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.1.36/linux/drivers/char/random.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/random.c Mon May 12 10:35:40 1997 @@ -1,7 +1,7 @@ /* * random.c -- A strong random number generator * - * Version 1.01, last modified 13-Feb-97 + * Version 1.02, last modified 15-Apr-97 * * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997. All rights reserved. * @@ -839,6 +839,18 @@ digest[ 4 ] += E; } +#undef ROTL +#undef f1 +#undef f2 +#undef f3 +#undef f4 +#undef K1 +#undef K2 +#undef K3 +#undef K4 +#undef expand +#undef subRound + #else #define HASH_BUFFER_SIZE 4 #define HASH_TRANSFORM MD5Transform @@ -1324,22 +1336,90 @@ * attacks which rely on guessing the initial TCP sequence number. * This algorithm was suggested by Steve Bellovin. */ + +/* F, G and H are basic MD4 functions: selection, majority, parity */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) ) + +/* FF, GG and HH are MD4 transformations for rounds 1, 2 and 3 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s) \ + {(a) += F ((b), (c), (d)) + (x); \ + (a) = ROTL ((s), (a));} +#define GG(a, b, c, d, x, s) \ + {(a) += G ((b), (c), (d)) + (x) + 013240474631UL; \ + (a) = ROTL ((s), (a));} +#define HH(a, b, c, d, x, s) \ + {(a) += H ((b), (c), (d)) + (x) + 015666365641UL; \ + (a) = ROTL ((s), (a));} + +/* + * Basic cut-down MD4 transform + */ +static void halfMD4Transform (__u32 buf[4], __u32 in[8]) +{ + __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ + FF (a, b, c, d, in[ 0], 3); + FF (d, a, b, c, in[ 1], 7); + FF (c, d, a, b, in[ 2], 11); + FF (b, c, d, a, in[ 3], 19); + FF (a, b, c, d, in[ 4], 3); + FF (d, a, b, c, in[ 5], 7); + FF (c, d, a, b, in[ 6], 11); + FF (b, c, d, a, in[ 7], 19); + + /* Round 2 */ + GG (a, b, c, d, in[ 0], 3); + GG (d, a, b, c, in[ 4], 5); + GG (a, b, c, d, in[ 1], 9); + GG (d, a, b, c, in[ 5], 13); + GG (a, b, c, d, in[ 2], 3); + GG (d, a, b, c, in[ 6], 5); + GG (a, b, c, d, in[ 3], 9); + GG (d, a, b, c, in[ 7], 13); + + /* Round 3 */ + HH (a, b, c, d, in[ 0], 3); + HH (c, d, a, b, in[ 4], 9); + HH (a, b, c, d, in[ 2], 11); + HH (c, d, a, b, in[ 6], 15); + HH (a, b, c, d, in[ 1], 3); + HH (c, d, a, b, in[ 5], 9); + HH (a, b, c, d, in[ 3], 11); + HH (c, d, a, b, in[ 7], 15); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#define REKEY_INTERVAL 300 + __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport) { - static int is_init = 0; - static __u32 secret[16]; + static __u32 rekey_time = 0; + static __u32 secret[12]; + static char count = 0; struct timeval tv; - __u32 tmp[16]; + __u32 tmp[12]; __u32 seq; /* - * Pick a random secret the first time we open a TCP - * connection. + * Pick a random secret every REKEY_INTERVAL seconds */ - if (is_init == 0) { + do_gettimeofday(&tv); + if (!rekey_time || + (tv.tv_sec - rekey_time) > REKEY_INTERVAL) { get_random_bytes(&secret, sizeof(secret)); - is_init = 1; + rekey_time = tv.tv_sec; + count++; } memcpy(tmp, secret, sizeof(tmp)); @@ -1350,7 +1430,7 @@ tmp[8]=saddr; tmp[9]=daddr; tmp[10]=(sport << 16) + dport; - HASH_TRANSFORM(tmp, tmp); + halfMD4Transform(tmp, tmp+4); /* * As close as possible to RFC 793, which @@ -1359,8 +1439,8 @@ * For 10MB/s ethernet, a 1MHz clock is appropriate. * That's funny, Linux has one built in! Use it! */ - do_gettimeofday(&tv); - seq = tmp[1] + tv.tv_usec+tv.tv_sec*1000000; + seq = (tmp[1]&0xFFFFFF) + (tv.tv_usec+tv.tv_sec*1000000) + + (count << 24); #if 0 printk("init_seq(%lx, %lx, %d, %d) = %d\n", saddr, daddr, sport, dport, seq); diff -u --recursive --new-file v2.1.36/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c --- v2.1.36/linux/drivers/char/riscom8.c Wed Apr 23 19:01:17 1997 +++ linux/drivers/char/riscom8.c Mon May 12 10:35:40 1997 @@ -1711,7 +1711,7 @@ if(!(tty = port->tty)) return; - if (clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); @@ -1821,7 +1821,7 @@ * addresses in this case. * */ -void riscom8_setup(char *str, int * ints) +__initfunc(void riscom8_setup(char *str, int * ints)) { int i; diff -u --recursive --new-file v2.1.36/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.1.36/linux/drivers/char/serial.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/char/serial.c Mon May 12 10:35:40 1997 @@ -899,7 +899,7 @@ if (!tty) return; - if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); diff -u --recursive --new-file v2.1.36/linux/drivers/char/tga.c linux/drivers/char/tga.c --- v2.1.36/linux/drivers/char/tga.c Mon Apr 14 16:28:11 1997 +++ linux/drivers/char/tga.c Mon May 12 10:35:40 1997 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -140,35 +141,35 @@ unsigned long tga_regs_base; unsigned int tga_bpp, tga_fb_width, tga_fb_height, tga_fb_stride; -static unsigned int fb_offset_presets[4] = { +static unsigned int fb_offset_presets[4] __initdata = { TGA_8PLANE_FB_OFFSET, TGA_24PLANE_FB_OFFSET, 0xffffffff, TGA_24PLUSZ_FB_OFFSET }; -static unsigned int deep_presets[4] = { +static unsigned int deep_presets[4] __initdata = { 0x00014000, 0x0001440d, 0xffffffff, 0x0001441d }; -static unsigned int rasterop_presets[4] = { +static unsigned int rasterop_presets[4] __initdata = { 0x00000003, 0x00000303, 0xffffffff, 0x00000303 }; -static unsigned int mode_presets[4] = { +static unsigned int mode_presets[4] __initdata = { 0x00002000, 0x00002300, 0xffffffff, 0x00002300 }; -static unsigned int base_addr_presets[4] = { +static unsigned int base_addr_presets[4] __initdata = { 0x00000000, 0x00000001, 0xffffffff, @@ -304,8 +305,8 @@ restore_flags(flags); } -unsigned long -con_type_init(unsigned long kmem_start, const char **display_desc) +__initfunc(unsigned long +con_type_init(unsigned long kmem_start, const char **display_desc)) { can_do_color = 1; @@ -323,8 +324,8 @@ return kmem_start; } -void -con_type_init_finish(void) +__initfunc(void +con_type_init_finish(void)) { } @@ -447,8 +448,8 @@ * when TGA console is configured, at the end of the probing code, * we call here to look for a TGA device, and proceed... */ -void -tga_console_init(void) +__initfunc(void +tga_console_init(void)) { unsigned char pci_bus, pci_devfn; int status; @@ -490,9 +491,9 @@ #endif } -unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 }; +unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 }; -const unsigned long bt485_cursor_source[64] = { +const unsigned long bt485_cursor_source[64] __initdata = { 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff, @@ -502,7 +503,7 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -const unsigned int bt463_cursor_source[256] = { +const unsigned int bt463_cursor_source[256] __initdata = { 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, 0xffff0000, 0x00000000, 0x00000000, 0x00000000, @@ -533,8 +534,8 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -void -tga_init_video() +__initfunc(void +tga_init_video(void)) { int i, j, temp; unsigned char *cbp; @@ -750,8 +751,8 @@ tga_fb_stride = tga_fb_width / sizeof(int); } -void -tga_clear_screen() +__initfunc(void +tga_clear_screen(void)) { register int i, j; register unsigned int *dst; diff -u --recursive --new-file v2.1.36/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.1.36/linux/drivers/char/tpqic02.c Fri Apr 4 08:52:19 1997 +++ linux/drivers/char/tpqic02.c Mon May 12 10:35:40 1997 @@ -89,6 +89,7 @@ #include #include #include +#include #include #include @@ -2866,10 +2867,7 @@ return 0; } /* qic02_get_resources */ -#ifdef MODULE -static -#endif -int qic02_tape_init(void) +__initfunc(static int qic02_tape_init(void)) { if (TPSTATSIZE != 6) { diff -u --recursive --new-file v2.1.36/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.36/linux/drivers/char/tty_io.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/char/tty_io.c Mon May 12 10:35:40 1997 @@ -166,14 +166,11 @@ { #ifdef CHECK_TTY_COUNT struct file *f; - int i, count = 0; + int count = 0; - for (f = first_file, i=0; if_next) { - if (!f->f_count) - continue; - if (f->private_data == tty) { + for(f = inuse_filps; f; f = f->f_next) { + if(f->private_data == tty) count++; - } } if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_SLAVE && @@ -363,16 +360,14 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) { - int i; + struct file * filp; struct task_struct *p; if (!tty) return; check_tty_count(tty, "do_tty_hangup"); - for (filp = first_file, i=0; if_next) { - if (!filp->f_count) - continue; + for (filp = inuse_filps; filp; filp = filp->f_next) { if (filp->private_data != tty) continue; if (!filp->f_inode) @@ -405,13 +400,14 @@ tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) { - i = (tty->ldisc.open)(tty); + int i = (tty->ldisc.open)(tty); if (i < 0) printk("do_tty_hangup: N_TTY open: error %d\n", -i); } } + read_lock(&tasklist_lock); for_each_task(p) { if ((tty->session > 0) && (p->session == tty->session) && p->leader) { @@ -423,6 +419,8 @@ if (p->tty == tty) p->tty = NULL; } + read_unlock(&tasklist_lock); + tty->flags = 0; tty->session = 0; tty->pgrp = -1; @@ -494,9 +492,11 @@ tty->session = 0; tty->pgrp = -1; + read_lock(&tasklist_lock); for_each_task(p) if (p->session == current->session) p->tty = NULL; + read_unlock(&tasklist_lock); } void wait_for_keypress(void) @@ -1338,9 +1338,11 @@ */ struct task_struct *p; + read_lock(&tasklist_lock); for_each_task(p) if (p->tty == tty) p->tty = NULL; + read_unlock(&tasklist_lock); } else return -EPERM; } @@ -1760,6 +1762,9 @@ #endif #ifdef CONFIG_DIGI pcxe_init(); +#endif +#ifdef CONFIG_DIGIEPCA + pc_init(); #endif #ifdef CONFIG_RISCOM8 riscom8_init(); diff -u --recursive --new-file v2.1.36/linux/drivers/char/vga.c linux/drivers/char/vga.c --- v2.1.36/linux/drivers/char/vga.c Mon Apr 7 11:35:29 1997 +++ linux/drivers/char/vga.c Mon May 12 10:35:40 1997 @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -146,8 +147,8 @@ hide_cursor(); } -unsigned long -con_type_init(unsigned long kmem_start, const char **display_desc) +__initfunc(unsigned long +con_type_init(unsigned long kmem_start, const char **display_desc)) { if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */ { @@ -239,8 +240,8 @@ return kmem_start; } -void -con_type_init_finish(void) +__initfunc(void +con_type_init_finish(void)) { } diff -u --recursive --new-file v2.1.36/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.1.36/linux/drivers/char/vt.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/char/vt.c Mon May 12 10:35:40 1997 @@ -123,6 +123,7 @@ } } + read_lock(&tasklist_lock); for_each_task(p) { if ( p->tty && MAJOR(p->tty->device) == TTY_MAJOR && @@ -131,6 +132,7 @@ send_sig(SIGWINCH, p, 1); } } + read_unlock(&tasklist_lock); return 0; } diff -u --recursive --new-file v2.1.36/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.1.36/linux/drivers/char/wdt.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/char/wdt.c Mon May 12 10:35:40 1997 @@ -61,7 +61,7 @@ * Setup options */ -void wdt_setup(char *str, int *ints) +__initfunc(void wdt_setup(char *str, int *ints)) { if(ints[0]>0) { diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.1.36/linux/drivers/isdn/Config.in Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/Config.in Mon May 12 10:35:40 1997 @@ -11,7 +11,6 @@ bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN -dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0 diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v2.1.36/linux/drivers/isdn/Makefile Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/Makefile Mon May 12 10:35:40 1997 @@ -1,6 +1,6 @@ SUB_DIRS := MOD_SUB_DIRS := -ALL_SUB_DIRS := icn teles pcbit hisax +ALL_SUB_DIRS := icn pcbit hisax L_OBJS := LX_OBJS := @@ -33,16 +33,6 @@ ifdef CONFIG_ISDN_AUDIO O_OBJS += isdn_audio.o endif - endif -endif - -ifeq ($(CONFIG_ISDN_DRV_TELES),y) - L_OBJS += teles/teles.o - SUB_DIRS += teles - MOD_SUB_DIRS += teles -else - ifeq ($(CONFIG_ISDN_DRV_TELES),m) - MOD_SUB_DIRS += teles endif endif diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c --- v2.1.36/linux/drivers/isdn/hisax/isdnl1.c Thu Feb 27 10:57:29 1997 +++ linux/drivers/isdn/hisax/isdnl1.c Mon May 12 17:39:50 1997 @@ -461,11 +461,11 @@ if (!sp) return; - if (clear_bit(ISAC_PHCHANGE, &sp->event)) + if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event)) process_new_ph(sp); - if (clear_bit(ISAC_RCVBUFREADY, &sp->event)) + if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event)) process_rcv(sp); - if (clear_bit(ISAC_XMTBUFREADY, &sp->event)) + if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event)) process_xmt(sp); } @@ -578,9 +578,9 @@ if (!hsp) return; - if (clear_bit(HSCX_RCVBUFREADY, &hsp->event)) + if (test_and_clear_bit(HSCX_RCVBUFREADY, &hsp->event)) hscx_process_rcv(hsp); - if (clear_bit(HSCX_XMTBUFREADY, &hsp->event)) + if (test_and_clear_bit(HSCX_XMTBUFREADY, &hsp->event)) hscx_process_xmt(hsp); } diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.1.36/linux/drivers/isdn/isdn_net.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/isdn_net.c Mon May 12 17:39:50 1997 @@ -934,7 +934,7 @@ return 0; } /* Avoid timer-based retransmission conflicts. */ - if (set_bit(0, (void *) &ndev->tbusy) != 0) + if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", ndev->name); diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/sc/Makefile linux/drivers/isdn/sc/Makefile --- v2.1.36/linux/drivers/isdn/sc/Makefile Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/sc/Makefile Mon May 12 10:35:40 1997 @@ -1,5 +1,5 @@ # -# $Id: Makefile.kernel,v 1.1 1996/11/07 13:07:40 fritz Exp $ +# $Id: Makefile,v 1.2 1997/05/01 08:53:47 davem Exp $ # Copyright (C) 1996 SpellCaster Telecommunications Inc. # # This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/Makefile linux/drivers/isdn/teles/Makefile --- v2.1.36/linux/drivers/isdn/teles/Makefile Mon Feb 26 01:58:05 1996 +++ linux/drivers/isdn/teles/Makefile Wed Dec 31 16:00:00 1969 @@ -1,17 +0,0 @@ -L_OBJS := -M_OBJS := -O_OBJS := mod.o card.o config.o buffers.o tei.o isdnl2.o isdnl3.o \ -llglue.o q931.o callc.o fsm.o - -O_TARGET := -ifeq ($(CONFIG_ISDN_DRV_TELES),y) - O_TARGET += teles.o -else - ifeq ($(CONFIG_ISDN_DRV_TELES),m) - O_TARGET += teles.o - M_OBJS += teles.o - endif -endif - -include $(TOPDIR)/Rules.make - diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/buffers.c linux/drivers/isdn/teles/buffers.c --- v2.1.36/linux/drivers/isdn/teles/buffers.c Sat Jun 1 01:56:51 1996 +++ linux/drivers/isdn/teles/buffers.c Wed Dec 31 16:00:00 1969 @@ -1,326 +0,0 @@ -/* $Id: buffers.c,v 1.3 1996/05/31 00:56:53 fritz Exp $ - * - * $Log: buffers.c,v $ - * Revision 1.3 1996/05/31 00:56:53 fritz - * removed cli() from BufPoolAdd, since it is called - * with interrupts off anyway. - * - * Revision 1.2 1996/04/29 22:48:14 fritz - * Removed compatibility-macros. No longer needed. - * - * Revision 1.1 1996/04/13 10:19:28 fritz - * Initial revision - * - * - */ -#define __NO_VERSION__ -#include "teles.h" -#include -#include - - -void -BufPoolInit(struct BufPool *bp, int order, int bpps, - int maxpages) -{ -#ifdef DEBUG_MAGIC - generateerror - bp->magic = 010167; -#endif - -#if 0 - printk(KERN_DEBUG "BufPoolInit bp %x\n", bp); -#endif - - bp->freelist = NULL; - bp->pageslist = NULL; - bp->pageorder = order; - bp->pagescount = 0; - bp->bpps = bpps; - bp->bufsize = BUFFER_SIZE(order, bpps); - bp->maxpages = maxpages; -} - -int -BufPoolAdd(struct BufPool *bp, int priority) -{ - struct Pages *ptr; - byte *bptr; - int i; - struct BufHeader *bh = NULL, *prev, *first; - -#if 0 - printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp); -#endif - - ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0); - if (!ptr) { - printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n"); - return (-1); - } -#if 0 - printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr); -#endif - - ptr->next = bp->pageslist; - bp->pageslist = ptr; - bp->pagescount++; - - bptr = (byte *) ptr + sizeof(struct Pages *); - - i = bp->bpps; - first = (struct BufHeader *) bptr; - prev = NULL; - while (i--) { - bh = (struct BufHeader *) bptr; -#ifdef DEBUG_MAGIC - bh->magic = 020167; -#endif - bh->next = prev; - prev = bh; - bh->bp = bp; - bptr += PART_SIZE(bp->pageorder, bp->bpps); - } - - first->next = bp->freelist; - bp->freelist = bh; - return (0); -} - -void -BufPoolFree(struct BufPool *bp) -{ - struct Pages *p; - -#if 0 - printk(KERN_DEBUG "BufPoolFree bp %x\n", bp); -#endif - - while (bp->pagescount--) { - p = bp->pageslist->next; - free_pages((unsigned long) bp->pageslist, bp->pageorder); -#if 0 - printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder); -#endif - bp->pageslist = p; - } -} - -int -BufPoolGet(struct BufHeader **bh, - struct BufPool *bp, int priority, void *heldby, int where) -{ - long flags; - int i; - -#ifdef DEBUG_MAGIC - if (bp->magic != 010167) { - printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n"); - return (-1); - } -#endif - - save_flags(flags); - cli(); - i = 0; - while (!0) { - if (bp->freelist) { - *bh = bp->freelist; - bp->freelist = bp->freelist->next; - (*bh)->heldby = heldby; - (*bh)->where = where; - restore_flags(flags); - return (0); - } - if ((i == 0) && (bp->pagescount < bp->maxpages)) { - if (BufPoolAdd(bp, priority)) { - restore_flags(flags); - return -1; - } - i++; - } else { - *bh = NULL; - restore_flags(flags); - return (-1); - } - } - -} - -void -BufPoolRelease(struct BufHeader *bh) -{ - struct BufPool *bp; - long flags; - -#ifdef DEBUG_MAGIC - if (bh->magic != 020167) { - printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n"); - printk(KERN_DEBUG "called from %x\n", __builtin_return_address(0)); - return; - } -#endif - - bp = bh->bp; - -#ifdef DEBUG_MAGIC - if (bp->magic != 010167) { - printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n"); - return; - } -#endif - - save_flags(flags); - cli(); - bh->next = bp->freelist; - bp->freelist = bh; - restore_flags(flags); -} - -void -BufQueueLink(struct BufQueue *bq, - struct BufHeader *bh) -{ - unsigned long flags; - - save_flags(flags); - cli(); - if (!bq->head) - bq->head = bh; - if (bq->tail) - bq->tail->next = bh; - bq->tail = bh; - bh->next = NULL; - restore_flags(flags); -} - -void -BufQueueLinkFront(struct BufQueue *bq, - struct BufHeader *bh) -{ - unsigned long flags; - - save_flags(flags); - cli(); - bh->next = bq->head; - bq->head = bh; - if (!bq->tail) - bq->tail = bh; - restore_flags(flags); -} - -int -BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq) -{ - long flags; - - save_flags(flags); - cli(); - - if (bq->head) { - if (bq->tail == bq->head) - bq->tail = NULL; - *bh = bq->head; - bq->head = (*bh)->next; - restore_flags(flags); - return (0); - } else { - restore_flags(flags); - return (-1); - } -} - -void -BufQueueInit(struct BufQueue *bq) -{ -#ifdef DEBUG_MAGIC - bq->magic = 030167; -#endif - bq->head = NULL; - bq->tail = NULL; -} - -void -BufQueueRelease(struct BufQueue *bq) -{ - struct BufHeader *bh; - - while (bq->head) { - BufQueueUnlink(&bh, bq); - BufPoolRelease(bh); - } -} - -int -BufQueueLength(struct BufQueue *bq) -{ - int i = 0; - struct BufHeader *bh; - - bh = bq->head; - while (bh) { - i++; - bh = bh->next; - } - return (i); -} - -void -BufQueueDiscard(struct BufQueue *q, int pr, void *heldby, - int releasetoo) -{ - long flags; - struct BufHeader *sp; - - save_flags(flags); - cli(); - - while (!0) { - sp = q->head; - if (!sp) - break; - if ((sp->primitive == pr) && (sp->heldby == heldby)) { - q->head = sp->next; - if (q->tail == sp) - q->tail = NULL; - if (releasetoo) - BufPoolRelease(sp); - } else - break; - } - - sp = q->head; - if (sp) - while (sp->next) { - if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) { - if (q->tail == sp->next) - q->tail = sp; - if (releasetoo) - BufPoolRelease(sp->next); - sp->next = sp->next->next; - } else - sp = sp->next; - } - restore_flags(flags); -} - -void -Sfree(byte * ptr) -{ -#if 0 - printk(KERN_DEBUG "Sfree %x\n", ptr); -#endif - kfree(ptr); -} - -byte * -Smalloc(int size, int pr, char *why) -{ - byte *p; - - p = (byte *) kmalloc(size, pr); -#if 0 - printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, p); -#endif - return (p); -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c --- v2.1.36/linux/drivers/isdn/teles/callc.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/callc.c Wed Dec 31 16:00:00 1969 @@ -1,1453 +0,0 @@ -/* $Id: callc.c,v 1.16 1997/02/11 01:39:46 keil Exp $ - * - * $Log: callc.c,v $ - * Revision 1.16 1997/02/11 01:39:46 keil - * Changed setup-interface (incoming and outgoing) - * - * Revision 1.15 1996/11/23 11:32:20 keil - * windowsize = 7 X.75 bugfix Thanks to Martin Maurer - * - * Revision 1.14 1996/10/22 23:14:14 fritz - * Changes for compatibility to 2.0.X and 2.1.X kernels. - * - * Revision 1.13 1996/06/24 17:15:55 fritz - * corrected return code of teles_writebuf() - * - * Revision 1.12 1996/06/12 16:15:33 fritz - * Extended user-configurable debugging flags. - * - * Revision 1.11 1996/06/07 12:32:20 fritz - * More changes to support suspend/resume. - * - * Revision 1.10 1996/06/06 21:24:21 fritz - * Started adding support for suspend/resume. - * - * Revision 1.9 1996/05/31 12:23:57 jdenoud - * Jan: added channel open check to teles_writebuf - * - * Revision 1.8 1996/05/31 01:00:38 fritz - * Changed return code of teles_writebuf, when out of memory. - * - * Revision 1.7 1996/05/17 03:40:37 fritz - * General cleanup. - * - * Revision 1.6 1996/05/10 22:42:07 fritz - * Added entry for EV_RELEASE_CNF in ST_OUT (if no D-Channel avail.) - * - * Revision 1.5 1996/05/06 10:16:15 fritz - * Added voice stuff. - * - * Revision 1.4 1996/04/30 22:04:05 isdn4dev - * improved callback Karsten Keil - * - * Revision 1.3 1996/04/30 10:04:19 fritz - * Started voice support. - * Added printk() to debug-switcher for easier - * synchronization between printk()'s and output - * of /dev/isdnctrl. - * - * Revision 1.2 1996/04/20 16:42:29 fritz - * Changed statemachine to allow reject of incoming calls. - * - * Revision 1.1 1996/04/13 10:20:59 fritz - * Initial revision - * - * - */ -#define __NO_VERSION__ -#include "teles.h" - -extern struct IsdnCard cards[]; -extern int nrcards; -extern int drid; -extern isdn_if iif; -extern void teles_mod_dec_use_count(void); -extern void teles_mod_inc_use_count(void); - -static int init_ds(int chan, int incoming); -static void release_ds(int chan); - -static struct Fsm callcfsm = -{NULL, 0, 0}, lcfsm = -{NULL, 0, 0}; - -struct Channel *chanlist; -static int chancount = 0; -unsigned int debugflags = 0; - -#define TMR_DCHAN_EST 2000 - -static void -stat_debug(struct Channel *chanp, char *s) -{ - char tmp[100], tm[32]; - - jiftime(tm, jiffies); - sprintf(tmp, "%s Channel %d HL->LL %s\n", tm, chanp->chan, s); - teles_putstatus(tmp); -} - -enum { - ST_NULL, /* 0 inactive */ - ST_OUT, /* 1 outgoing, awaiting SETUP confirm */ - ST_CLEAR, /* 2 call release, awaiting RELEASE confirm */ - ST_OUT_W, /* 3 outgoing, awaiting d-channel establishment */ - ST_REL_W, /* 4 awaiting d-channel release */ - ST_IN_W, /* 5 incoming, awaiting d-channel establishment */ - ST_IN, /* 6 incoming call received */ - ST_IN_SETUP, /* 7 incoming, SETUP response sent */ - ST_IN_DACT, /* 8 incoming connected, no b-channel prot. */ - ST_OUT_ESTB, /* 10 outgoing connected, awaiting b-channel prot. estbl. */ - ST_ACTIVE, /* 11 active, b channel prot. established */ - ST_BC_HANGUP, /* 12 call clear. (initiator), awaiting b channel prot. rel. */ - ST_PRO_W, /* 13 call clear. (initiator), DISCONNECT req. sent */ - ST_ANT_W, /* 14 call clear. (receiver), awaiting DISCONNECT ind. */ - ST_DISC_BC_HANGUP, /* d channel gone, wait for b channel deactivation */ - ST_OUT_W_HANGUP, /* Outgoing waiting for D-Channel hangup received */ - ST_D_ERR, /* d channel released while active */ -}; - -#define STATE_COUNT (ST_D_ERR+1) - -static char *strState[] = -{ - "ST_NULL", - "ST_OUT", - "ST_CLEAR", - "ST_OUT_W", - "ST_REL_W", - "ST_IN_W", - "ST_IN", - "ST_IN_SETUP", - "ST_IN_DACT", - "ST_OUT_ESTB", - "ST_ACTIVE", - "ST_BC_HANGUP", - "ST_PRO_W", - "ST_ANT_W", - "ST_DISC_BC_HANGUP", - "ST_OUT_W_HANGUP", - "ST_D_ERR", -}; - -enum { - EV_DIAL, /* 0 */ - EV_SETUP_CNF, /* 1 */ - EV_ACCEPTB, /* 2 */ - EV_DISCONNECT_CNF, /* 5 */ - EV_DISCONNECT_IND, /* 6 */ - EV_RELEASE_CNF, /* 7 */ - EV_DLEST, /* 8 */ - EV_DLRL, /* 9 */ - EV_SETUP_IND, /* 10 */ - EV_RELEASE_IND, /* 11 */ - EV_ACCEPTD, /* 12 */ - EV_SETUP_CMPL_IND, /* 13 */ - EV_BC_EST, /* 14 */ - EV_WRITEBUF, /* 15 */ - EV_DATAIN, /* 16 */ - EV_HANGUP, /* 17 */ - EV_BC_REL, /* 18 */ - EV_CINF, /* 19 */ - EV_SUSPEND, /* 20 */ - EV_RESUME, /* 21 */ -}; - -#define EVENT_COUNT (EV_CINF+1) - -static char *strEvent[] = -{ - "EV_DIAL", - "EV_SETUP_CNF", - "EV_ACCEPTB", - "EV_DISCONNECT_CNF", - "EV_DISCONNECT_IND", - "EV_RELEASE_CNF", - "EV_DLEST", - "EV_DLRL", - "EV_SETUP_IND", - "EV_RELEASE_IND", - "EV_ACCEPTD", - "EV_SETUP_CMPL_IND", - "EV_BC_EST", - "EV_WRITEBUF", - "EV_DATAIN", - "EV_HANGUP", - "EV_BC_REL", - "EV_CINF", - "EV_SUSPEND", - "EV_RESUME", -}; - -enum { - ST_LC_NULL, - ST_LC_ACTIVATE_WAIT, - ST_LC_DELAY, - ST_LC_ESTABLISH_WAIT, - ST_LC_CONNECTED, - ST_LC_RELEASE_WAIT, -}; - -#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1) - -static char *strLcState[] = -{ - "ST_LC_NULL", - "ST_LC_ACTIVATE_WAIT", - "ST_LC_DELAY", - "ST_LC_ESTABLISH_WAIT", - "ST_LC_CONNECTED", - "ST_LC_RELEASE_WAIT", -}; - -enum { - EV_LC_ESTABLISH, - EV_LC_PH_ACTIVATE, - EV_LC_PH_DEACTIVATE, - EV_LC_DL_ESTABLISH, - EV_LC_TIMER, - EV_LC_DL_RELEASE, - EV_LC_RELEASE, -}; - -#define LC_EVENT_COUNT (EV_LC_RELEASE+1) - -static char *strLcEvent[] = -{ - "EV_LC_ESTABLISH", - "EV_LC_PH_ACTIVATE", - "EV_LC_PH_DEACTIVATE", - "EV_LC_DL_ESTABLISH", - "EV_LC_TIMER", - "EV_LC_DL_RELEASE", - "EV_LC_RELEASE", -}; - -#define LC_D 0 -#define LC_B 1 - -/* - * Dial out - */ -static void -r1(struct FsmInst *fi, int event, void *arg) -{ - isdn_ctrl *ic = arg; - struct Channel *chanp = fi->userdata; - - chanp->para.setup = ic->parm.setup; - if (!strcmp(chanp->para.setup.eazmsn, "0")) - chanp->para.setup.eazmsn[0] = '\0'; - - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = 0; - chanp->lc_b.l2_start = !0; - - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - chanp->lc_b.l2_establish = !0; - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_TRANS): - chanp->lc_b.l2_establish = 0; - break; - default: - printk(KERN_WARNING "r1 unknown protocol\n"); - break; - } - - FsmChangeState(fi, ST_OUT_W); - FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL); -} - -static void -ll_hangup(struct Channel *chanp, int bchantoo) -{ - isdn_ctrl ic; - - if (bchantoo) { - if (chanp->debug & 1) - stat_debug(chanp, "STAT_BHUP"); - ic.driver = drid; - ic.command = ISDN_STAT_BHUP; - ic.arg = chanp->chan; - iif.statcallb(&ic); - } - if (chanp->debug & 1) - stat_debug(chanp, "STAT_DHUP"); - ic.driver = drid; - ic.command = ISDN_STAT_DHUP; - ic.arg = chanp->chan; - iif.statcallb(&ic); -} - -static void -r2(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL); - - FsmChangeState(fi, ST_CLEAR); - ll_hangup(chanp, 0); -} - - -static void -r2_1(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL); - - FsmChangeState(fi, ST_OUT_W_HANGUP); -} - - -static void -r2_2(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_REL_W); - FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); - ll_hangup(chanp, 0); -} - - -static void -r3(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); - FsmChangeState(fi, ST_REL_W); -} - - -static void -r3_1(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); - - FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); - FsmChangeState(fi, ST_REL_W); - ll_hangup(chanp, 0); -} - - -static void -r4(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp=fi->userdata; - - chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); - FsmChangeState(fi, ST_NULL); -} - -static void -r5(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->para.callref = chanp->outcallref; - - chanp->outcallref++; - if (chanp->outcallref == 128) - chanp->outcallref = 64; - - chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL); - - FsmChangeState(fi, ST_OUT); -} - -static void -r6(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_IN_W); - FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL); -} - -static void -r7(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - /* - * Report incoming calls only once to linklevel, use octet 3 of - * channel identification information element. (it's value - * is copied to chanp->para.bchannel in l3s12(), file isdnl3.c) - */ - if (((chanp->chan & 1) + 1) & chanp->para.bchannel) { - chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL); - FsmChangeState(fi, ST_IN); - if (chanp->debug & 1) - stat_debug(chanp, "STAT_ICALL"); - ic.driver = drid; - ic.command = ISDN_STAT_ICALL; - ic.arg = chanp->chan; - /* - * No need to return "unknown" for calls without OAD, - * cause that's handled in linklevel now (replaced by '0') - */ - ic.parm.setup = chanp->para.setup; - iif.statcallb(&ic); - } else { - chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); - FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); - FsmChangeState(fi, ST_REL_W); - } -} - -static void -r8(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_IN_SETUP); - chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL); - -} - -static void -r9(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_IN_DACT); - - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = !0; - chanp->lc_b.l2_start = 0; - - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - chanp->lc_b.l2_establish = !0; - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_TRANS): - chanp->lc_b.l2_establish = 0; - break; - default: - printk(KERN_WARNING "r9 unknown protocol\n"); - break; - } - - init_ds(chanp->chan, !0); - - FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL); -} - -static void -r10(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_OUT_ESTB); - - init_ds(chanp->chan, 0); - FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL); - -} - -static void -r12(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - FsmChangeState(fi, ST_ACTIVE); - chanp->data_open = !0; - - if (chanp->debug & 1) - stat_debug(chanp, "STAT_DCONN"); - ic.driver = drid; - ic.command = ISDN_STAT_DCONN; - ic.arg = chanp->chan; - iif.statcallb(&ic); - - if (chanp->debug & 1) - stat_debug(chanp, "STAT_BCONN"); - ic.driver = drid; - ic.command = ISDN_STAT_BCONN; - ic.arg = chanp->chan; - iif.statcallb(&ic); -} - -static void -r15(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - FsmChangeState(fi, ST_BC_HANGUP); - FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL); -} - -static void -r16(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_ds(chanp->chan); - - FsmChangeState(fi, ST_PRO_W); - chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL); -} - -static void -r17(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - release_ds(chanp->chan); - - FsmChangeState(fi, ST_ANT_W); -} - - -static void -r17_1(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - release_ds(chanp->chan); - - chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); - - FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); - - FsmChangeState(fi, ST_NULL); - - ll_hangup(chanp,!0); -} - -static void -r18(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_REL_W); - FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); - - ll_hangup(chanp, !0); -} - -static void -r19(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_CLEAR); - - chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL); - - ll_hangup(chanp, !0); -} - -static void -r20(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); - - FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); - - FsmChangeState(fi, ST_NULL); - - ll_hangup(chanp, 0); -} - - -static void -r21(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - FsmChangeState(fi, ST_DISC_BC_HANGUP); - FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL); -} - -static void -r22(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_ds(chanp->chan); - - FsmChangeState(fi, ST_CLEAR); - - chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL); - - ll_hangup(chanp, !0); -} - -static void -r23(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_ds(chanp->chan); - - FsmChangeState(fi, ST_PRO_W); - chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL); -} - -static void -r23_1(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_ds(chanp->chan); - - chanp->is.l4.l4l3(&chanp->is, CC_DLRL,NULL); - - FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE,NULL); - - FsmChangeState(fi, ST_NULL); - - ll_hangup(chanp,!0); -} - -static void -r24(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - FsmChangeState(fi, ST_D_ERR); - FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL); -} - -static void -r25(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_ds(chanp->chan); - - FsmChangeState(fi, ST_NULL); - - ll_hangup(chanp, !0); -} - -static void -r26(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - - ic.driver = drid; - ic.command = ISDN_STAT_CINF; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "%d", chanp->para.chargeinfo); - iif.statcallb(&ic); -} - - - -static struct FsmNode fnlist[] = -{ - {ST_NULL, EV_DIAL, r1}, - {ST_OUT_W, EV_DLEST, r5}, - {ST_OUT_W, EV_DLRL, r20}, - {ST_OUT_W, EV_RELEASE_CNF, r2_2 }, - {ST_OUT, EV_DISCONNECT_IND, r2}, - {ST_OUT, EV_SETUP_CNF, r10}, - {ST_OUT, EV_HANGUP, r2_1}, - {ST_OUT, EV_RELEASE_IND, r20}, - {ST_OUT, EV_RELEASE_CNF, r20}, - {ST_OUT, EV_DLRL, r2_2}, - {ST_OUT_W_HANGUP, EV_RELEASE_IND, r2_2}, - {ST_OUT_W_HANGUP, EV_DLRL, r20}, - {ST_CLEAR, EV_RELEASE_CNF, r3}, - {ST_CLEAR, EV_DLRL, r20}, - {ST_REL_W, EV_DLRL, r4}, - {ST_NULL, EV_SETUP_IND, r6}, - {ST_IN_W, EV_DLEST, r7}, - {ST_IN_W, EV_DLRL, r3_1}, - {ST_IN, EV_DLRL, r3_1}, - {ST_IN, EV_HANGUP, r2_1}, - {ST_IN, EV_RELEASE_IND, r2_2}, - {ST_IN, EV_RELEASE_CNF, r2_2}, - {ST_IN, EV_ACCEPTD, r8}, - {ST_IN_SETUP, EV_HANGUP, r2_1}, - {ST_IN_SETUP, EV_SETUP_CMPL_IND, r9}, - {ST_IN_SETUP, EV_RELEASE_IND, r2_2}, - {ST_IN_SETUP, EV_DISCONNECT_IND, r2}, - {ST_IN_SETUP, EV_DLRL, r20}, - {ST_OUT_ESTB, EV_BC_EST, r12}, - {ST_OUT_ESTB, EV_BC_REL, r23}, - {ST_OUT_ESTB, EV_DLRL, r23_1}, - {ST_IN_DACT, EV_BC_EST, r12}, - {ST_IN_DACT, EV_BC_REL, r17}, - {ST_IN_DACT, EV_DLRL, r17_1}, - {ST_ACTIVE, EV_HANGUP, r15}, - {ST_ACTIVE, EV_BC_REL, r17}, - {ST_ACTIVE, EV_DISCONNECT_IND, r21}, - {ST_ACTIVE, EV_DLRL, r24}, - {ST_ACTIVE, EV_CINF, r26}, - {ST_ACTIVE, EV_RELEASE_IND, r17}, - {ST_BC_HANGUP, EV_BC_REL, r16}, - {ST_BC_HANGUP, EV_DISCONNECT_IND, r21}, - {ST_PRO_W, EV_RELEASE_IND, r18}, - {ST_ANT_W, EV_DISCONNECT_IND, r19}, - {ST_DISC_BC_HANGUP, EV_BC_REL, r22}, - {ST_D_ERR, EV_BC_REL, r25}, -}; - -#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) - -static void -lc_r1(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmChangeState(fi, ST_LC_ACTIVATE_WAIT); - FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50); - lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL); - -} - -static void -lc_r6(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmDelTimer(&lf->act_timer, 50); - FsmChangeState(fi, ST_LC_DELAY); - FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51); -} - -static void -lc_r2(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - if (lf->l2_establish) { - FsmChangeState(fi, ST_LC_ESTABLISH_WAIT); - if (lf->l2_start) - lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL); - } else { - FsmChangeState(fi, ST_LC_CONNECTED); - lf->lccall(lf, LC_ESTABLISH, NULL); - } -} - -static void -lc_r3(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmChangeState(fi, ST_LC_CONNECTED); - lf->lccall(lf, LC_ESTABLISH, NULL); -} - -static void -lc_r4(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - if (lf->l2_establish) { - FsmChangeState(fi, ST_LC_RELEASE_WAIT); - lf->st->ma.manl2(lf->st, DL_RELEASE, NULL); - } else { - FsmChangeState(fi, ST_LC_NULL); - lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL); - lf->lccall(lf, LC_RELEASE, NULL); - } -} - -static void -lc_r5(struct FsmInst *fi, int event, void *arg) -{ - struct LcFsm *lf = fi->userdata; - - FsmChangeState(fi, ST_LC_NULL); - lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL); - lf->lccall(lf, LC_RELEASE, NULL); -} - -static struct FsmNode LcFnList[] = -{ - {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1}, - {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6}, - {ST_LC_DELAY, EV_LC_TIMER, lc_r2}, - {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3}, - {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4}, - {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5}, - {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5}, - {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5}, - {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5}, -}; - -#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode)) - -void -CallcNew(void) -{ - callcfsm.state_count = STATE_COUNT; - callcfsm.event_count = EVENT_COUNT; - callcfsm.strEvent = strEvent; - callcfsm.strState = strState; - FsmNew(&callcfsm, fnlist, FNCOUNT); - - lcfsm.state_count = LC_STATE_COUNT; - lcfsm.event_count = LC_EVENT_COUNT; - lcfsm.strEvent = strLcEvent; - lcfsm.strState = strLcState; - FsmNew(&lcfsm, LcFnList, LC_FN_COUNT); -} - -void -CallcFree(void) -{ - FsmFree(&lcfsm); - FsmFree(&callcfsm); -} - -static void -release_ds(int chan) -{ - struct PStack *st = &chanlist[chan].ds; - struct IsdnCardState *sp; - struct HscxState *hsp; - - sp = st->l1.hardware; - hsp = sp->hs + chanlist[chan].hscx; - - close_hscxstate(hsp); - - switch (chanlist[chan].l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - releasestack_isdnl2(st); - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_TRANS): - releasestack_transl2(st); - break; - } -} - -static void -cc_l1man(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->l4.userdata; - - switch (pr) { - case (PH_ACTIVATE): - FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE): - FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL); - break; - } -} - -static void -cc_l2man(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->l4.userdata; - - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL); - break; - case (DL_RELEASE): - FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL); - break; - } -} - -static void -dcc_l1man(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->l4.userdata; - - switch (pr) { - case (PH_ACTIVATE): - FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE): - FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL); - break; - } -} - -static void -dcc_l2man(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->l4.userdata; - - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL); - break; - case (DL_RELEASE): - FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL); - break; - } -} - -static void -ll_handler(struct PStack *st, int pr, - struct BufHeader *ibh) -{ - struct Channel *chanp = (struct Channel *) st->l4.userdata; - - switch (pr) { - case (CC_DISCONNECT_IND): - FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); - break; - case (CC_RELEASE_CNF): - FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL); - break; - case (CC_SETUP_IND): - FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); - break; - case (CC_RELEASE_IND): - FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL); - break; - case (CC_SETUP_COMPLETE_IND): - FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL); - break; - case (CC_SETUP_CNF): - FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); - break; - case (CC_INFO_CHARGE): - FsmEvent(&chanp->fi, EV_CINF, NULL); - break; - } -} - -static void -init_is(int chan, unsigned int ces) -{ - struct PStack *st = &(chanlist[chan].is); - struct IsdnCardState *sp = chanlist[chan].sp; - char tmp[128]; - - setstack_teles(st, sp); - - st->l2.sap = 0; - - st->l2.tei = 255; - - st->l2.ces = ces; - st->l2.extended = !0; - st->l2.laptype = LAPD; - st->l2.window = 1; - st->l2.orig = !0; - st->l2.t200 = 1000; /* 1000 milliseconds */ - if (st->protocol == ISDN_PTYPE_1TR6) { - st->l2.n200 = 3; /* try 3 times */ - st->l2.t203 = 10000; /* 10000 milliseconds */ - } else { - st->l2.n200 = 4; /* try 4 times */ - st->l2.t203 = 5000; /* 5000 milliseconds */ - } - - sprintf(tmp, "Channel %d q.921", chan); - setstack_isdnl2(st, tmp); - setstack_isdnl3(st); - st->l2.debug = 2; - st->l3.debug = 2; - st->l2.debug = 0xff; - st->l3.debug = 0xff; - st->l4.userdata = chanlist + chan; - st->l4.l2writewakeup = NULL; - - st->l3.l3l4 = ll_handler; - st->l1.l1man = cc_l1man; - st->l2.l2man = cc_l2man; - - st->pa = &chanlist[chan].para; - teles_addlist(sp, st); -} - -static void -callc_debug(struct FsmInst *fi, char *s) -{ - char str[80], tm[32]; - struct Channel *chanp = fi->userdata; - - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s); - teles_putstatus(str); -} - -static void -lc_debug(struct FsmInst *fi, char *s) -{ - char str[256], tm[32]; - struct LcFsm *lf = fi->userdata; - - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s); - teles_putstatus(str); -} - -static void -dlc_debug(struct FsmInst *fi, char *s) -{ - char str[256], tm[32]; - struct LcFsm *lf = fi->userdata; - - jiftime(tm, jiffies); - sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s); - teles_putstatus(str); -} - -static void -lccall_d(struct LcFsm *lf, int pr, void *arg) -{ - struct Channel *chanp = lf->ch; - - switch (pr) { - case (LC_ESTABLISH): - FsmEvent(&chanp->fi, EV_DLEST, NULL); - break; - case (LC_RELEASE): - FsmEvent(&chanp->fi, EV_DLRL, NULL); - break; - } -} - -static void -lccall_b(struct LcFsm *lf, int pr, void *arg) -{ - struct Channel *chanp = lf->ch; - - switch (pr) { - case (LC_ESTABLISH): - FsmEvent(&chanp->fi, EV_BC_EST, NULL); - break; - case (LC_RELEASE): - FsmEvent(&chanp->fi, EV_BC_REL, NULL); - break; - } -} - -static void -init_chan(int chan, int cardnr, int hscx, - unsigned int ces) -{ - struct IsdnCard *card = cards + cardnr; - struct Channel *chanp = chanlist + chan; - - chanp->sp = card->sp; - chanp->hscx = hscx; - chanp->chan = chan; - chanp->incoming = 0; - chanp->debug = 0; - init_is(chan, ces); - - chanp->fi.fsm = &callcfsm; - chanp->fi.state = ST_NULL; - chanp->fi.debug = 0; - chanp->fi.userdata = chanp; - chanp->fi.printdebug = callc_debug; - - chanp->lc_d.lcfi.fsm = &lcfsm; - chanp->lc_d.lcfi.state = ST_LC_NULL; - chanp->lc_d.lcfi.debug = 0; - chanp->lc_d.lcfi.userdata = &chanp->lc_d; - chanp->lc_d.lcfi.printdebug = lc_debug; - chanp->lc_d.type = LC_D; - chanp->lc_d.ch = chanp; - chanp->lc_d.st = &chanp->is; - chanp->lc_d.l2_establish = !0; - chanp->lc_d.l2_start = !0; - chanp->lc_d.lccall = lccall_d; - FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer); - - chanp->lc_b.lcfi.fsm = &lcfsm; - chanp->lc_b.lcfi.state = ST_LC_NULL; - chanp->lc_b.lcfi.debug = 0; - chanp->lc_b.lcfi.userdata = &chanp->lc_b; - chanp->lc_b.lcfi.printdebug = dlc_debug; - chanp->lc_b.type = LC_B; - chanp->lc_b.ch = chanp; - chanp->lc_b.st = &chanp->ds; - chanp->lc_b.l2_establish = !0; - chanp->lc_b.l2_start = !0; - chanp->lc_b.lccall = lccall_b; - FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer); - - chanp->outcallref = 64; - chanp->data_open = 0; -} - -int -CallcNewChan(void) -{ - int i, ces, c; - - chancount = 0; - for (i = 0; i < nrcards; i++) - if (cards[i].sp) - chancount += 2; - - chanlist = (struct Channel *) Smalloc(sizeof(struct Channel) * - chancount, GFP_KERNEL, "chanlist"); - - c = 0; - ces = randomces(); - for (i = 0; i < nrcards; i++) - if (cards[i].sp) { - init_chan(c++, i, 1, ces++); - ces %= 0xffff; - init_chan(c++, i, 0, ces++); - ces %= 0xffff; - } - printk(KERN_INFO "channels %d\n", chancount); - return (chancount); - -} - -static void -release_is(int chan) -{ - struct PStack *st = &chanlist[chan].is; - - releasestack_isdnl2(st); - teles_rmlist(st->l1.hardware, st); - BufQueueRelease(&st->l2.i_queue); -} - -void -CallcFreeChan(void) -{ - int i; - - for (i = 0; i < chancount; i++) - release_is(i); - Sfree((void *) chanlist); -} - -static void -lldata_handler(struct PStack *st, int pr, - void *arg) -{ - struct Channel *chanp = (struct Channel *) st->l4.userdata; - byte *ptr; - int size; - struct BufHeader *ibh = arg; - - switch (pr) { - case (DL_DATA): - if (chanp->data_open) { - ptr = DATAPTR(ibh); - ptr += chanp->ds.l2.ihsize; - size = ibh->datasize - chanp->ds.l2.ihsize; - iif.rcvcallb(drid, chanp->chan, ptr, size); - } - BufPoolRelease(ibh); - break; - default: - printk(KERN_WARNING "lldata_handler unknown primitive\n"); - break; - } -} - -static void -lltrans_handler(struct PStack *st, int pr, - struct BufHeader *ibh) -{ - struct Channel *chanp = (struct Channel *) st->l4.userdata; - byte *ptr; - - switch (pr) { - case (PH_DATA): - if (chanp->data_open) { - ptr = DATAPTR(ibh); - iif.rcvcallb(drid, chanp->chan, ptr, ibh->datasize); - } - BufPoolRelease(ibh); - break; - default: - printk(KERN_WARNING "lltrans_handler unknown primitive\n"); - break; - } -} - -static void -ll_writewakeup(struct PStack *st) -{ - struct Channel *chanp = st->l4.userdata; - isdn_ctrl ic; - - ic.driver = drid; - ic.command = ISDN_STAT_BSENT; - ic.arg = chanp->chan; - iif.statcallb(&ic); -} - -static int -init_ds(int chan, int incoming) -{ - struct PStack *st = &(chanlist[chan].ds); - struct IsdnCardState *sp = (struct IsdnCardState *) - chanlist[chan].is.l1.hardware; - struct HscxState *hsp = sp->hs + chanlist[chan].hscx; - char tmp[128]; - - st->l1.hardware = sp; - - hsp->mode = 2; - hsp->transbufsize = 4000; - - if (setstack_hscx(st, hsp)) - return (-1); - - st->l2.extended = 0; - st->l2.laptype = LAPB; - st->l2.orig = !incoming; - st->l2.t200 = 1000; /* 1000 milliseconds */ - st->l2.window = 7; - st->l2.n200 = 4; /* try 4 times */ - st->l2.t203 = 5000; /* 5000 milliseconds */ - - st->l2.debug = 0xff; - st->l3.debug = 0xff; - switch (chanlist[chan].l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - sprintf(tmp, "Channel %d x.75", chan); - setstack_isdnl2(st, tmp); - st->l2.l2l3 = lldata_handler; - st->l1.l1man = dcc_l1man; - st->l2.l2man = dcc_l2man; - st->l4.userdata = chanlist + chan; - st->l4.l1writewakeup = NULL; - st->l4.l2writewakeup = ll_writewakeup; - st->l2.l2m.debug = debugflags & 16; - st->ma.manl2(st, MDL_NOTEIPROC, NULL); - st->l1.hscxmode = 2; /* Packet-Mode ? */ - st->l1.hscxchannel = chanlist[chan].para.bchannel - 1; - break; - case (ISDN_PROTO_L2_HDLC): - st->l1.l1l2 = lltrans_handler; - st->l1.l1man = dcc_l1man; - st->l4.userdata = chanlist + chan; - st->l4.l1writewakeup = ll_writewakeup; - st->l1.hscxmode = 2; - st->l1.hscxchannel = chanlist[chan].para.bchannel - 1; - break; - case (ISDN_PROTO_L2_TRANS): - st->l1.l1l2 = lltrans_handler; - st->l1.l1man = dcc_l1man; - st->l4.userdata = chanlist + chan; - st->l4.l1writewakeup = ll_writewakeup; - st->l1.hscxmode = 1; - st->l1.hscxchannel = chanlist[chan].para.bchannel - 1; - break; - } - - return (0); - -} - -static void -channel_report(int i) -{ -} - -static void -command_debug(struct Channel *chanp, char *s) -{ - char tmp[64], tm[32]; - - jiftime(tm, jiffies); - sprintf(tmp, "%s Channel %d LL->HL %s\n", tm, chanp->chan, s); - teles_putstatus(tmp); -} - -static void -distr_debug(void) -{ - int i; - - for (i = 0; i < chancount; i++) { - chanlist[i].debug = debugflags & 1; - chanlist[i].fi.debug = debugflags & 2; - chanlist[i].is.l2.l2m.debug = debugflags & 8; - chanlist[i].ds.l2.l2m.debug = debugflags & 16; - } - for (i = 0; i < nrcards; i++) - if (cards[i].sp) { - cards[i].sp->dlogflag = debugflags & 4; - cards[i].sp->debug = debugflags & 32; - } -} - -int -teles_command(isdn_ctrl * ic) -{ - struct Channel *chanp; - char tmp[64]; - int i; - unsigned int num; - - switch (ic->command) { - case (ISDN_CMD_SETEAZ): - chanp = chanlist + ic->arg; - if (chanp->debug & 1) - command_debug(chanp, "SETEAZ"); - return (0); - case (ISDN_CMD_DIAL): - chanp = chanlist + (ic->arg & 0xff); - if (chanp->debug & 1) { - sprintf(tmp, "DIAL %s -> %s (%d,%d)", - ic->parm.setup.eazmsn, ic->parm.setup.phone, - ic->parm.setup.si1, ic->parm.setup.si2); - command_debug(chanp, tmp); - } - FsmEvent(&chanp->fi, EV_DIAL, ic); - return (0); - case (ISDN_CMD_ACCEPTB): - chanp = chanlist + ic->arg; - if (chanp->debug & 1) - command_debug(chanp, "ACCEPTB"); - FsmEvent(&chanp->fi, EV_ACCEPTB, NULL); - break; - case (ISDN_CMD_ACCEPTD): - chanp = chanlist + ic->arg; - if (chanp->debug & 1) - command_debug(chanp, "ACCEPTD"); - FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); - break; - case (ISDN_CMD_HANGUP): - chanp = chanlist + ic->arg; - if (chanp->debug & 1) - command_debug(chanp, "HANGUP"); - FsmEvent(&chanp->fi, EV_HANGUP, NULL); - break; - case (ISDN_CMD_SUSPEND): - chanp = chanlist + ic->arg; - if (chanp->debug & 1) { - sprintf(tmp, "SUSPEND %s", ic->parm.num); - command_debug(chanp, tmp); - } - FsmEvent(&chanp->fi, EV_SUSPEND, ic); - break; - case (ISDN_CMD_RESUME): - chanp = chanlist + ic->arg; - if (chanp->debug & 1) { - sprintf(tmp, "RESUME %s", ic->parm.num); - command_debug(chanp, tmp); - } - FsmEvent(&chanp->fi, EV_RESUME, ic); - break; - case (ISDN_CMD_LOCK): - teles_mod_inc_use_count(); - break; - case (ISDN_CMD_UNLOCK): - teles_mod_dec_use_count(); - break; - case (ISDN_CMD_IOCTL): - switch (ic->arg) { - case (0): - for (i = 0; i < nrcards; i++) - if (cards[i].sp) - teles_reportcard(i); - for (i = 0; i < chancount; i++) - channel_report(i); - break; - case (1): - debugflags = *(unsigned int *) ic->parm.num; - distr_debug(); - sprintf(tmp, "debugging flags set to %x\n", debugflags); - teles_putstatus(tmp); - printk(KERN_DEBUG "%s", tmp); - break; - case (2): - num = *(unsigned int *) ic->parm.num; - i = num >> 8; - if (i >= chancount) - break; - chanp = chanlist + i; - chanp->impair = num & 0xff; - if (chanp->debug & 1) { - sprintf(tmp, "IMPAIR %x", chanp->impair); - command_debug(chanp, tmp); - } - break; - } - break; - case (ISDN_CMD_SETL2): - chanp = chanlist + (ic->arg & 0xff); - if (chanp->debug & 1) { - sprintf(tmp, "SETL2 %ld", ic->arg >> 8); - command_debug(chanp, tmp); - } - chanp->l2_protocol = ic->arg >> 8; - break; - default: - break; - } - - return (0); -} - -int -teles_writebuf(int id, int chan, const u_char * buf, int count, int user) -{ - struct Channel *chanp = chanlist + chan; - struct PStack *st = &chanp->ds; - struct BufHeader *ibh; - int err, i; - byte *ptr; - - if (!chanp->data_open) { - printk(KERN_DEBUG "teles_writebuf: channel not open\n"); - return -EIO; - } - - err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21); - if (err) - /* Must return 0 here, since this is not an error - * but a temporary lack of resources. - */ - return 0; - - ptr = DATAPTR(ibh); - if (chanp->lc_b.l2_establish) - i = st->l2.ihsize; - else - i = 0; - - if ((count+i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) { - printk(KERN_WARNING "teles_writebuf: packet too large!\n"); - return (-EINVAL); - } - - ptr += i; - - if (user) - copy_from_user(ptr, buf, count); - else - memcpy(ptr, buf, count); - ibh->datasize = count + i; - - if (chanp->data_open) { - if (chanp->lc_b.l2_establish) - chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, ibh); - else - chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, ibh); - return (count); - } else { - BufPoolRelease(ibh); - return (0); - } - -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c --- v2.1.36/linux/drivers/isdn/teles/card.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/card.c Wed Dec 31 16:00:00 1969 @@ -1,1900 +0,0 @@ -/* $Id: card.c,v 1.16 1996/10/22 23:14:16 fritz Exp $ - * - * card.c low level stuff for the Teles S0 isdn card - * - * Author Jan den Ouden - * - * Beat Doebeli log all D channel traffic - * - * $Log: card.c,v $ - * Revision 1.16 1996/10/22 23:14:16 fritz - * Changes for compatibility to 2.0.X and 2.1.X kernels. - * - * Revision 1.15 1996/09/29 19:41:56 fritz - * Bugfix: ignore unknown frames. - * - * Revision 1.14 1996/09/23 01:53:49 fritz - * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). - * - * Revision 1.13 1996/07/18 11:21:24 jdenoud - * Use small buffers for incoming audio data - * - * Revision 1.12 1996/06/24 17:16:52 fritz - * Added check for misconfigured membase. - * - * Revision 1.11 1996/06/14 03:30:37 fritz - * Added recovery from EXIR 40 interrupt. - * Some cleanup. - * - * Revision 1.10 1996/06/11 14:57:20 hipp - * minor changes to ensure, that SKBs are sent in the right order - * - * Revision 1.9 1996/06/06 14:42:09 fritz - * Bugfix: forgot hsp-> in last change. - * - * Revision 1.7 1996/05/31 01:02:21 fritz - * Cosmetic changes. - * - * Revision 1.6 1996/05/26 14:58:10 fritz - * Bugfix: Did not show port correctly, when no card found. - * - * Revision 1.5 1996/05/17 03:45:02 fritz - * Made error messages more clearly. - * Bugfix: Only 31 bytes of 32-byte audio frames - * have been transfered to upper layers. - * - * Revision 1.4 1996/05/06 10:17:57 fritz - * Added voice-send stuff - * (Not reporting EXIR when in voice-mode, since it's normal). - * - * Revision 1.3 1996/04/30 22:02:40 isdn4dev - * Bugfixes for 16.3 - * -improved IO allocation - * -fix second B channel problem - * -correct ph_command patch - * - * Revision 1.2 1996/04/30 10:00:59 fritz - * Bugfix: Added ph_command(8) for 16.3. - * Bugfix: Ports did not get registered correctly - * when using a 16.3. - * Started voice support. - * Some experimental changes of waitforXFW(). - * - * Revision 1.1 1996/04/13 10:22:42 fritz - * Initial revision - * - * - */ - -#define __NO_VERSION__ -#include "teles.h" -#include "proto.h" - -#define INCLUDE_INLINE_FUNCS -#include -#include - -#undef DCHAN_VERBOSE - -extern void tei_handler(struct PStack *st, byte pr, - struct BufHeader *ibh); -extern struct IsdnCard cards[]; -extern int nrcards; - -#define byteout(addr,val) outb_p(val,addr) -#define bytein(addr) inb_p(addr) - -static inline byte -readisac_0(byte * cardm, byte offset) -{ - return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset); -} - -static inline byte -readisac_3(int iobase, byte offset) -{ - return (bytein(iobase - 0x420 + offset)); -} - -#define READISAC(mbase,ibase,ofs) \ - ((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs)) - -static inline void -writeisac_0(byte * cardm, byte offset, byte value) -{ - writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset); -} - -static inline void -writeisac_3(int iobase, byte offset, byte value) -{ - byteout(iobase - 0x420 + offset, value); -} - -#define WRITEISAC(mbase,ibase,ofs,val) \ - ((mbase)?writeisac_0(mbase,ofs,val):writeisac_3(ibase,ofs,val)) - -static inline void -readisac_s(int iobase, byte offset, byte * dest, int count) -{ - insb(iobase - 0x420 + offset, dest, count); -} - -static inline void -writeisac_s(int iobase, byte offset, byte * src, int count) -{ - outsb(iobase - 0x420 + offset, src, count); -} - -static inline byte -readhscx_0(byte * base, byte hscx, byte offset) -{ - return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) + - ((hscx & 1) ? 0x40 : 0) + offset); -} - -static inline byte -readhscx_3(int iobase, byte hscx, byte offset) -{ - return (bytein(iobase - (hscx ? 0x820 : 0xc20) + offset)); -} - -#define READHSCX(mbase,ibase,hscx,ofs) \ - ((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs)) - -static inline void -writehscx_0(byte * base, byte hscx, byte offset, byte data) -{ - writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) + - ((hscx & 1) ? 0x40 : 0) + offset); -} - -static inline void -writehscx_3(int iobase, byte hscx, byte offset, byte data) -{ - byteout(iobase - (hscx ? 0x820 : 0xc20) + offset, data); -} - -static inline void -readhscx_s(int iobase, byte hscx, byte offset, byte * dest, int count) -{ - insb(iobase - (hscx ? 0x820 : 0xc20) + offset, dest, count); -} - -static inline void -writehscx_s(int iobase, byte hscx, byte offset, byte * src, int count) -{ - outsb(iobase - (hscx ? 0x820 : 0xc20) + offset, src, count); -} - -#define ISAC_MASK 0x20 -#define ISAC_ISTA 0x20 -#define ISAC_STAR 0x21 -#define ISAC_CMDR 0x21 -#define ISAC_EXIR 0x24 - -#define ISAC_RBCH 0x2a - -#define ISAC_ADF2 0x39 -#define ISAC_SPCR 0x30 -#define ISAC_ADF1 0x38 -#define ISAC_CIX0 0x31 -#define ISAC_STCR 0x37 -#define ISAC_MODE 0x22 -#define ISAC_RSTA 0x27 -#define ISAC_RBCL 0x25 -#define ISAC_TIMR 0x23 -#define ISAC_SQXR 0x3b - -#define HSCX_ISTA 0x20 -#define HSCX_CCR1 0x2f -#define HSCX_CCR2 0x2c -#define HSCX_TSAR 0x31 -#define HSCX_TSAX 0x30 -#define HSCX_XCCR 0x32 -#define HSCX_RCCR 0x33 -#define HSCX_MODE 0x22 -#define HSCX_CMDR 0x21 -#define HSCX_EXIR 0x24 -#define HSCX_XAD1 0x24 -#define HSCX_XAD2 0x25 -#define HSCX_RAH2 0x27 -#define HSCX_RSTA 0x27 -#define HSCX_TIMR 0x23 -#define HSCX_STAR 0x21 -#define HSCX_RBCL 0x25 -#define HSCX_XBCH 0x2d -#define HSCX_VSTR 0x2e -#define HSCX_RLCR 0x2e -#define HSCX_MASK 0x20 - -static inline void -waitforCEC_0(byte * base, byte hscx) -{ - long to = 10; - - while ((readhscx_0(base, hscx, HSCX_STAR) & 0x04) && to) { - udelay(5); - to--; - } - if (!to) - printk(KERN_WARNING "waitforCEC timeout\n"); -} - -static inline void -waitforCEC_3(int iobase, byte hscx) -{ - long to = 10; - - while ((readhscx_3(iobase, hscx, HSCX_STAR) & 0x04) && to) { - udelay(5); - to--; - } - if (!to) - printk(KERN_WARNING "waitforCEC timeout\n"); -} - -static inline void -waitforXFW_0(byte * base, byte hscx) -{ - long to = 20; - - while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) { - udelay(5); - to--; - } - if (!to) - printk(KERN_WARNING "waitforXFW timeout\n"); -} - -static inline void -waitforXFW_3(int iobase, byte hscx) -{ - long to = 20; - - while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) { - udelay(5); - to--; - } - if (!to) - printk(KERN_WARNING "waitforXFW timeout\n"); -} - -static inline void -writehscxCMDR_0(byte * base, byte hscx, byte data) -{ - long flags; - - save_flags(flags); - cli(); - waitforCEC_0(base, hscx); - writehscx_0(base, hscx, HSCX_CMDR, data); - restore_flags(flags); -} - -static inline void -writehscxCMDR_3(int iobase, byte hscx, byte data) -{ - long flags; - - save_flags(flags); - cli(); - waitforCEC_3(iobase, hscx); - writehscx_3(iobase, hscx, HSCX_CMDR, data); - restore_flags(flags); -} - -#define WRITEHSCX_CMDR(mbase,ibase,hscx,data) \ - ((mbase)?writehscxCMDR_0(mbase,hscx,data):writehscxCMDR_3(ibase,hscx,data)) - -/* - * fast interrupt here - */ - -#define ISAC_RCVBUFREADY 0 -#define ISAC_XMTBUFREADY 1 -#define ISAC_PHCHANGE 2 - -#define HSCX_RCVBUFREADY 0 -#define HSCX_XMTBUFREADY 1 - -void -teles_hscxreport(struct IsdnCardState *sp, int hscx) -{ - printk(KERN_DEBUG "HSCX %d\n", hscx); - if (sp->membase) { - printk(KERN_DEBUG " ISTA %x\n", readhscx_0(sp->membase, - hscx, HSCX_ISTA)); - printk(KERN_DEBUG " STAR %x\n", readhscx_0(sp->membase, - hscx, HSCX_STAR)); - printk(KERN_DEBUG " EXIR %x\n", readhscx_0(sp->membase, - hscx, HSCX_EXIR)); - } else { - printk(KERN_DEBUG " ISTA %x\n", readhscx_3(sp->iobase, - hscx, HSCX_ISTA)); - printk(KERN_DEBUG " STAR %x\n", readhscx_3(sp->iobase, - hscx, HSCX_STAR)); - printk(KERN_DEBUG " EXIR %x\n", readhscx_3(sp->iobase, - hscx, HSCX_EXIR)); - } -} - -void -teles_report(struct IsdnCardState *sp) -{ - printk(KERN_DEBUG "ISAC\n"); - if (sp->membase) { - printk(KERN_DEBUG " ISTA %x\n", readisac_0(sp->membase, - ISAC_ISTA)); - printk(KERN_DEBUG " STAR %x\n", readisac_0(sp->membase, - ISAC_STAR)); - printk(KERN_DEBUG " EXIR %x\n", readisac_0(sp->membase, - ISAC_EXIR)); - } else { - printk(KERN_DEBUG " ISTA %x\n", readisac_3(sp->iobase, - ISAC_ISTA)); - printk(KERN_DEBUG " STAR %x\n", readisac_3(sp->iobase, - ISAC_STAR)); - printk(KERN_DEBUG " EXIR %x\n", readisac_3(sp->iobase, - ISAC_EXIR)); - } - teles_hscxreport(sp, 0); - teles_hscxreport(sp, 1); -} - -/* - * HSCX stuff goes here - */ - -static void -hscx_sched_event(struct HscxState *hsp, int event) -{ - hsp->event |= 1 << event; - queue_task_irq_off(&hsp->tqueue, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} - -static void -hscx_empty_fifo(struct HscxState *hsp, int count) -{ - byte *ptr; - struct BufHeader *ibh = hsp->rcvibh; - - if (hsp->sp->debug) - printk(KERN_DEBUG "hscx_empty_fifo\n"); - - if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER, - HSCX_RBUF_BPPS)) { - printk(KERN_WARNING - "hscx_empty_fifo: incoming packet too large\n"); - WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, 0x80); - return; - } - ptr = DATAPTR(ibh); - ptr += hsp->rcvptr; - - hsp->rcvptr += count; - if (hsp->membase) { - while (count--) - *ptr++ = readhscx_0(hsp->membase, hsp->hscx, 0x0); - writehscxCMDR_0(hsp->membase, hsp->hscx, 0x80); - } else { - readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count); - writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80); - } -} - -static void -hscx_fill_fifo(struct HscxState *hsp) -{ - struct BufHeader *ibh; - int more, count; - byte *ptr; - - if (hsp->sp->debug) - printk(KERN_DEBUG "hscx_fill_fifo\n"); - - ibh = hsp->xmtibh; - if (!ibh) - return; - - count = ibh->datasize - hsp->sendptr; - if (count <= 0) - return; - - more = (hsp->mode == 1)?1:0; - if (count > 32) { - more = !0; - count = 32; - } - ptr = DATAPTR(ibh); - ptr += hsp->sendptr; - hsp->sendptr += count; - -#ifdef BCHAN_VERBOSE - { - int i; - printk(KERN_DEBUG "hscx_fill_fifo "); - for (i = 0; i < count; i++) - printk(" %2x", ptr[i]); - printk("\n"); - } -#endif - if (hsp->membase) { - waitforXFW_0(hsp->membase, hsp->hscx); - while (count--) - writehscx_0(hsp->membase, hsp->hscx, 0x0, *ptr++); - writehscxCMDR_0(hsp->membase, hsp->hscx, more ? 0x8 : 0xa); - } else { - waitforXFW_3(hsp->iobase, hsp->hscx); - writehscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count); - writehscxCMDR_3(hsp->iobase, hsp->hscx, more ? 0x8 : 0xa); - } -} - -static inline void -hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx) -{ - byte r; - struct HscxState *hsp = sp->hs + hscx; - int count, err; - - if (!hsp->init) - return; - - if (val & 0x80) { /* RME */ - - r = READHSCX(hsp->membase, sp->iobase, hsp->hscx, HSCX_RSTA); - if ((r & 0xf0) != 0xa0) { - if (!r & 0x80) - printk(KERN_WARNING - "Teles: HSCX invalid frame\n"); - if ((r & 0x40) && hsp->mode) - printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode); - if (!r & 0x20) - printk(KERN_WARNING "Teles: HSCX CRC error\n"); - if (hsp->rcvibh) - BufPoolRelease(hsp->rcvibh); - hsp->rcvibh = NULL; - WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, - 0x80); - goto afterRME; - } - if (!hsp->rcvibh) - if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, - GFP_ATOMIC, (void *) 1, 1)) { - printk(KERN_WARNING - "HSCX RME out of buffers at %ld\n", - jiffies); - WRITEHSCX_CMDR(hsp->membase, hsp->iobase, - hsp->hscx, 0x80); - goto afterRME; - } else - hsp->rcvptr = 0; - - count = READHSCX(hsp->membase, sp->iobase, hsp->hscx, - HSCX_RBCL) & 0x1f; - if (count == 0) - count = 32; - hscx_empty_fifo(hsp, count); - hsp->rcvibh->datasize = hsp->rcvptr - 1; - BufQueueLink(&hsp->rq, hsp->rcvibh); - hsp->rcvibh = NULL; - hscx_sched_event(hsp, HSCX_RCVBUFREADY); - } - afterRME: - if (val & 0x40) { /* RPF */ - if (!hsp->rcvibh) { - if (hsp->mode == 1) - err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool, - GFP_ATOMIC, (void *)1, 2); - else - err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool, - GFP_ATOMIC, (void *)1, 2); - - if (err) { - printk(KERN_WARNING - "HSCX RPF out of buffers at %ld\n", - jiffies); - WRITEHSCX_CMDR(hsp->membase, hsp->iobase, - hsp->hscx, 0x80); - goto afterRPF; - } else - hsp->rcvptr = 0; - } - - hscx_empty_fifo(hsp, 32); - if (hsp->mode == 1) { - /* receive audio data */ - hsp->rcvibh->datasize = hsp->rcvptr; - BufQueueLink(&hsp->rq, hsp->rcvibh); - hsp->rcvibh = NULL; - hscx_sched_event(hsp, HSCX_RCVBUFREADY); - } - - } - afterRPF: - if (val & 0x10) { /* XPR */ - if (hsp->xmtibh) - if (hsp->xmtibh->datasize > hsp->sendptr) { - hscx_fill_fifo(hsp); - goto afterXPR; - } else { - if (hsp->releasebuf) - BufPoolRelease(hsp->xmtibh); - hsp->sendptr = 0; - if (hsp->st->l4.l1writewakeup) - hsp->st->l4.l1writewakeup(hsp->st); - hsp->xmtibh = NULL; - } - if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { - hsp->releasebuf = !0; - hscx_fill_fifo(hsp); - } else - hscx_sched_event(hsp, HSCX_XMTBUFREADY); - } - afterXPR: -} - -/* - * ISAC stuff goes here - */ - -static void -isac_sched_event(struct IsdnCardState *sp, int event) -{ - sp->event |= 1 << event; - queue_task_irq_off(&sp->tqueue, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} - -static void -empty_fifo(struct IsdnCardState *sp, int count) -{ - byte *ptr; - struct BufHeader *ibh = sp->rcvibh; - - if (sp->debug) - printk(KERN_DEBUG "empty_fifo\n"); - - if (sp->rcvptr >= 3072) { - printk(KERN_WARNING "empty_fifo rcvptr %d\n", sp->rcvptr); - return; - } - ptr = DATAPTR(ibh); - ptr += sp->rcvptr; - sp->rcvptr += count; - - if (sp->membase) { -#ifdef DCHAN_VERBOSE - printk(KERN_DEBUG "empty_fifo "); - while (count--) { - *ptr = readisac_0(sp->membase, 0x0); - printk("%2x ", *ptr); - ptr++; - } - printk("\n"); -#else - while (count--) - *ptr++ = readisac_0(sp->membase, 0x0); -#endif - writeisac_0(sp->membase, ISAC_CMDR, 0x80); - } else { -#ifdef DCHAN_VERBOSE - int i; - printk(KERN_DEBUG "empty_fifo "); - readisac_s(sp->iobase, 0x3e, ptr, count); - for (i = 0; i < count; i++) - printk("%2x ", ptr[i]); - printk("\n"); -#else - readisac_s(sp->iobase, 0x3e, ptr, count); -#endif - writeisac_3(sp->iobase, ISAC_CMDR, 0x80); - } -} - -static void -fill_fifo(struct IsdnCardState *sp) -{ - struct BufHeader *ibh; - int count, more; - byte *ptr; - - if (sp->debug) - printk(KERN_DEBUG "fill_fifo\n"); - - ibh = sp->xmtibh; - if (!ibh) - return; - - count = ibh->datasize - sp->sendptr; - if (count <= 0) - return; - if (count >= 3072) - return; - - more = 0; - if (count > 32) { - more = !0; - count = 32; - } - ptr = DATAPTR(ibh); - ptr += sp->sendptr; - sp->sendptr += count; - - if (sp->membase) { -#ifdef DCHAN_VERBOSE - printk(KERN_DEBUG "fill_fifo "); - while (count--) { - writeisac_0(sp->membase, 0x0, *ptr); - printk("%2x ", *ptr); - ptr++; - } - printk("\n"); -#else - while (count--) - writeisac_0(sp->membase, 0x0, *ptr++); -#endif - writeisac_0(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa); - } else { -#ifdef DCHAN_VERBOSE - int i; - writeisac_s(sp->iobase, 0x3e, ptr, count); - printk(KERN_DEBUG "fill_fifo "); - for (i = 0; i < count; i++) - printk("%2x ", ptr[i]); - printk("\n"); -#else - writeisac_s(sp->iobase, 0x3e, ptr, count); -#endif - writeisac_3(sp->iobase, ISAC_CMDR, more ? 0x8 : 0xa); - } -} - -static int -act_wanted(struct IsdnCardState *sp) -{ - struct PStack *st; - - st = sp->stlist; - while (st) - if (st->l1.act_state) - return (!0); - else - st = st->next; - return (0); -} - -static void -ph_command(struct IsdnCardState *sp, unsigned int command) -{ - printk(KERN_DEBUG "ph_command %d\n", command); - WRITEISAC(sp->membase, sp->iobase, ISAC_CIX0, (command << 2) | 3); -} - -static void -isac_new_ph(struct IsdnCardState *sp) -{ - int enq; - - enq = act_wanted(sp); - - switch (sp->ph_state) { - case (0): - case (6): - if (enq) - ph_command(sp, 0); - else - ph_command(sp, 15); - break; - case (7): - if (enq) - ph_command(sp, 9); - break; - case (12): - ph_command(sp, 8); - sp->ph_active = 5; - isac_sched_event(sp, ISAC_PHCHANGE); - if (!sp->xmtibh) - if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) - sp->sendptr = 0; - if (sp->xmtibh) - fill_fifo(sp); - break; - case (13): - ph_command(sp, 9); - sp->ph_active = 5; - isac_sched_event(sp, ISAC_PHCHANGE); - if (!sp->xmtibh) - if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) - sp->sendptr = 0; - if (sp->xmtibh) - fill_fifo(sp); - break; - case (4): - case (8): - break; - default: - sp->ph_active = 0; - break; - } -} - -static void -teles_interrupt(int intno, void *dev_id, struct pt_regs *regs) -{ - byte val, r, exval; - struct IsdnCardState *sp; - unsigned int count; - struct HscxState *hsp; - - sp = (struct IsdnCardState *) irq2dev_map[intno]; - - if (!sp) { - printk(KERN_WARNING "Teles: Spurious interrupt!\n"); - return; - } - val = READHSCX(sp->membase, sp->iobase, 1, HSCX_ISTA); - - if (val & 0x01) { - hsp = sp->hs + 1; - exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR); - if (exval == 0x40) { - if (hsp->mode == 1) - hscx_fill_fifo(hsp); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - hsp->sendptr = 0; - WRITEHSCX_CMDR(hsp->membase, hsp->iobase, - hsp->hscx, 0x01); - printk(KERN_DEBUG "HSCX B EXIR %x\n", exval); - } - } else - printk(KERN_WARNING "HSCX B EXIR %x\n", exval); - } - if (val & 0xf8) { - if (sp->debug) - printk(KERN_DEBUG "HSCX B interrupt %x\n", val); - hscx_interrupt(sp, val, 1); - } - if (val & 0x02) { - hsp = sp->hs; - exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR); - if (exval == 0x40) { - if (hsp->mode == 1) - hscx_fill_fifo(hsp); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - hsp->sendptr = 0; - WRITEHSCX_CMDR(hsp->membase, hsp->iobase, - hsp->hscx, 0x01); - printk(KERN_DEBUG "HSCX A EXIR %x\n", exval); - } - } else - printk(KERN_WARNING "HSCX A EXIR %x\n", exval); - } - if (val & 0x04) { - val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA); - if (sp->debug) - printk(KERN_DEBUG "HSCX A interrupt %x\n", - val); - hscx_interrupt(sp, val, 0); - } - - val = READISAC(sp->membase, sp->iobase, ISAC_ISTA); - - if (sp->debug) - printk(KERN_DEBUG "ISAC interrupt %x\n", val); - - if (val & 0x80) { /* RME */ - - r = READISAC(sp->membase, sp->iobase, ISAC_RSTA); - if ((r & 0x70) != 0x20) { - if (r & 0x40) - printk(KERN_WARNING "Teles: ISAC RDO\n"); - if (!r & 0x20) - printk(KERN_WARNING "Teles: ISAC CRC error\n"); - if (sp->rcvibh) - BufPoolRelease(sp->rcvibh); - sp->rcvibh = NULL; - WRITEISAC(sp->membase, sp->iobase, ISAC_CMDR, 0x80); - goto afterRME; - } - if (!sp->rcvibh) - if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), - GFP_ATOMIC, - (void *) 1, 3)) { - printk(KERN_WARNING - "ISAC RME out of buffers!\n"); - WRITEISAC(sp->membase, sp->iobase, - ISAC_CMDR, 0x80); - goto afterRME; - } else - sp->rcvptr = 0; - - count = READISAC(sp->membase, sp->iobase, ISAC_RBCL) & 0x1f; - if (count == 0) - count = 32; - empty_fifo(sp, count); - sp->rcvibh->datasize = sp->rcvptr; - BufQueueLink(&(sp->rq), sp->rcvibh); - sp->rcvibh = NULL; - isac_sched_event(sp, ISAC_RCVBUFREADY); - } - afterRME: - if (val & 0x40) { /* RPF */ - if (!sp->rcvibh) - if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool), - GFP_ATOMIC, - (void *) 1, 4)) { - printk(KERN_WARNING - "ISAC RME out of buffers!\n"); - WRITEISAC(sp->membase, sp->iobase, - ISAC_CMDR, 0x80); - goto afterRPF; - } else - sp->rcvptr = 0; - empty_fifo(sp, 32); - } - afterRPF: - if (val & 0x20) { - } - if (val & 0x10) { /* XPR */ - if (sp->xmtibh) - if (sp->xmtibh->datasize > sp->sendptr) { - fill_fifo(sp); - goto afterXPR; - } else { - if (sp->releasebuf) - BufPoolRelease(sp->xmtibh); - sp->xmtibh = NULL; - sp->sendptr = 0; - } - if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) { - sp->releasebuf = !0; - fill_fifo(sp); - } else - isac_sched_event(sp, ISAC_XMTBUFREADY); - } - afterXPR: - if (val & 0x04) { /* CISQ */ - sp->ph_state = (READISAC(sp->membase, sp->iobase, ISAC_CIX0) - >> 2) & 0xf; - printk(KERN_DEBUG "l1state %d\n", sp->ph_state); - isac_new_ph(sp); - } - if (sp->membase) { - writeisac_0(sp->membase, ISAC_MASK, 0xFF); - writehscx_0(sp->membase, 0, HSCX_MASK, 0xFF); - writehscx_0(sp->membase, 1, HSCX_MASK, 0xFF); - writeisac_0(sp->membase, ISAC_MASK, 0x0); - writehscx_0(sp->membase, 0, HSCX_MASK, 0x0); - writehscx_0(sp->membase, 1, HSCX_MASK, 0x0); - } else { - writeisac_3(sp->iobase, ISAC_MASK, 0xFF); - writehscx_3(sp->iobase, 0, HSCX_MASK, 0xFF); - writehscx_3(sp->iobase, 1, HSCX_MASK, 0xFF); - writeisac_3(sp->iobase, ISAC_MASK, 0x0); - writehscx_3(sp->iobase, 0, HSCX_MASK, 0x0); - writehscx_3(sp->iobase, 1, HSCX_MASK, 0x0); - } -} - -/* - * soft interrupt - */ - -static void -act_ivated(struct IsdnCardState *sp) -{ - struct PStack *st; - - st = sp->stlist; - while (st) { - if (st->l1.act_state == 1) { - st->l1.act_state = 2; - st->l1.l1man(st, PH_ACTIVATE, NULL); - } - st = st->next; - } -} - -static void -process_new_ph(struct IsdnCardState *sp) -{ - if (sp->ph_active == 5) - act_ivated(sp); -} - -static void -process_xmt(struct IsdnCardState *sp) -{ - struct PStack *stptr; - - if (sp->xmtibh) - return; - - stptr = sp->stlist; - while (stptr != NULL) - if (stptr->l1.requestpull) { - stptr->l1.requestpull = 0; - stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL); - break; - } else - stptr = stptr->next; -} - -static void -process_rcv(struct IsdnCardState *sp) -{ - struct BufHeader *ibh, *cibh; - struct PStack *stptr; - byte *ptr; - int found, broadc; - char tmp[64]; - - while (!BufQueueUnlink(&ibh, &sp->rq)) { - stptr = sp->stlist; - ptr = DATAPTR(ibh); - broadc = (ptr[1] >> 1) == 127; - - if (broadc && sp->dlogflag && (!(ptr[0] >> 2))) - dlogframe(sp, ptr + 3, ibh->datasize - 3, - "Q.931 frame network->user broadcast"); - - if (broadc) { - while (stptr != NULL) { - if ((ptr[0] >> 2) == stptr->l2.sap) - if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC, - (void *) 1, 5)) { - memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize); - cibh->datasize = ibh->datasize; - stptr->l1.l1l2(stptr, PH_DATA, cibh); - } else - printk(KERN_WARNING "isdn broadcast buffer shortage\n"); - stptr = stptr->next; - } - BufPoolRelease(ibh); - } else { - found = 0; - while (stptr != NULL) - if (((ptr[0] >> 2) == stptr->l2.sap) && - ((ptr[1] >> 1) == stptr->l2.tei)) { - stptr->l1.l1l2(stptr, PH_DATA, ibh); - found = !0; - break; - } else - stptr = stptr->next; - if (!found) { - /* BD 10.10.95 - * Print out D-Channel msg not processed - * by isdn4linux - */ - - if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) { - sprintf(tmp, "Q.931 frame network->user with tei %d (not for us)", ptr[1] >> 1); - dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp); - } - BufPoolRelease(ibh); - } - } - - } - -} - -static void -isac_bh(struct IsdnCardState *sp) -{ - if (!sp) - return; - - if (clear_bit(ISAC_PHCHANGE, &sp->event)) - process_new_ph(sp); - if (clear_bit(ISAC_RCVBUFREADY, &sp->event)) - process_rcv(sp); - if (clear_bit(ISAC_XMTBUFREADY, &sp->event)) - process_xmt(sp); -} - - -static void -hscx_process_xmt(struct HscxState *hsp) -{ - struct PStack *st = hsp->st; - - if (hsp->xmtibh) - return; - - if (st->l1.requestpull) { - st->l1.requestpull = 0; - st->l1.l1l2(st, PH_PULL_ACK, NULL); - } - if (!hsp->active) - if ((!hsp->xmtibh) && (!hsp->sq.head)) - modehscx(hsp, 0, 0); -} - -static void -hscx_process_rcv(struct HscxState *hsp) -{ - struct BufHeader *ibh; - -#ifdef DEBUG_MAGIC - if (hsp->magic != 301270) { - printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n"); - return; - } -#endif - while (!BufQueueUnlink(&ibh, &hsp->rq)) { - hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh); - } -} - -static void -hscx_bh(struct HscxState *hsp) -{ - - if (!hsp) - return; - - if (clear_bit(HSCX_RCVBUFREADY, &hsp->event)) - hscx_process_rcv(hsp); - if (clear_bit(HSCX_XMTBUFREADY, &hsp->event)) - hscx_process_xmt(hsp); - -} - -/* - * interrupt stuff ends here - */ - -static void -restart_ph(struct IsdnCardState *sp) -{ - switch (sp->ph_active) { - case (0): - if (sp->ph_state == 6) - ph_command(sp, 0); - else - ph_command(sp, 1); - sp->ph_active = 1; - break; - } -} - -static void -initisac(byte * cardmem, int iobase) -{ - if (cardmem) { - writeisac_0(cardmem, ISAC_MASK, 0xff); - writeisac_0(cardmem, ISAC_ADF2, 0x0); - writeisac_0(cardmem, ISAC_SPCR, 0xa); - writeisac_0(cardmem, ISAC_ADF1, 0x2); - writeisac_0(cardmem, ISAC_STCR, 0x70); - writeisac_0(cardmem, ISAC_MODE, 0xc9); - writeisac_0(cardmem, ISAC_CMDR, 0x41); - writeisac_0(cardmem, ISAC_CIX0, (1 << 2) | 3); - } else { - writeisac_3(iobase, ISAC_MASK, 0xff); - writeisac_3(iobase, ISAC_ADF2, 0x80); - writeisac_3(iobase, ISAC_SQXR, 0x2f); - writeisac_3(iobase, ISAC_SPCR, 0x00); - writeisac_3(iobase, ISAC_ADF1, 0x02); - writeisac_3(iobase, ISAC_STCR, 0x70); - writeisac_3(iobase, ISAC_MODE, 0xc9); - writeisac_3(iobase, ISAC_TIMR, 0x00); - writeisac_3(iobase, ISAC_ADF1, 0x00); - writeisac_3(iobase, ISAC_CMDR, 0x41); - writeisac_3(iobase, ISAC_CIX0, (1 << 2) | 3); - } -} - -static int -checkcard(int cardnr) -{ - int timout; - byte cfval, val; - struct IsdnCard *card = cards + cardnr; - - if (card->membase) - if ((unsigned long)card->membase < 0x10000) { - (unsigned long)card->membase <<= 4; - printk(KERN_INFO - "Teles membase configured DOSish, assuming 0x%lx\n", - (unsigned long)card->membase); - } - if (!card->iobase) { - if (card->membase) { - printk(KERN_NOTICE - "Teles 8 assumed, mem: %lx irq: %d proto: %s\n", - (long) card->membase, card->interrupt, - (card->protocol == ISDN_PTYPE_1TR6) ? - "1TR6" : "EDSS1"); - printk(KERN_INFO "HSCX version A:%x B:%x\n", - readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf, - readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf); - } - } else { - switch (card->iobase) { - case 0x180: - case 0x280: - case 0x380: - card->iobase |= 0xc00; - break; - } - if (card->membase) { /* 16.0 */ - if (check_region(card->iobase, 8)) { - printk(KERN_WARNING - "teles: ports %x-%x already in use\n", - card->iobase, - card->iobase + 8 ); - return -1; - } - } else { /* 16.3 */ - if (check_region(card->iobase, 16)) { - printk(KERN_WARNING - "teles: 16.3 ports %x-%x already in use\n", - card->iobase, - card->iobase + 16 ); - return -1; - } - if (check_region((card->iobase - 0xc00) , 32)) { - printk(KERN_WARNING - "teles: 16.3 ports %x-%x already in use\n", - card->iobase - 0xc00, - card->iobase - 0xc00 + 32); - return -1; - } - if (check_region((card->iobase - 0x800) , 32)) { - printk(KERN_WARNING - "teles: 16.3 ports %x-%x already in use\n", - card->iobase - 0x800, - card->iobase - 0x800 + 32); - return -1; - } - if (check_region((card->iobase - 0x400) , 32)) { - printk(KERN_WARNING - "teles: 16.3 ports %x-%x already in use\n", - card->iobase - 0x400, - card->iobase - 0x400 + 32); - return -1; - } - } - switch (card->interrupt) { - case 2: - cfval = 0x00; - break; - case 3: - cfval = 0x02; - break; - case 4: - cfval = 0x04; - break; - case 5: - cfval = 0x06; - break; - case 10: - cfval = 0x08; - break; - case 11: - cfval = 0x0A; - break; - case 12: - cfval = 0x0C; - break; - case 15: - cfval = 0x0E; - break; - default: - cfval = 0x00; - break; - } - if (card->membase) { - cfval |= (((unsigned int) card->membase >> 9) & 0xF0); - } - if (bytein(card->iobase + 0) != 0x51) { - printk(KERN_INFO "XXX Byte at %x is %x\n", - card->iobase + 0, - bytein(card->iobase + 0)); - return -2; - } - if (bytein(card->iobase + 1) != 0x93) { - printk(KERN_INFO "XXX Byte at %x is %x\n", - card->iobase + 1, - bytein(card->iobase + 1)); - return -2; - } - val = bytein(card->iobase + 2); /* 0x1e=without AB - * 0x1f=with AB - * 0x1c 16.3 ??? - */ - if (val != 0x1c && val != 0x1e && val != 0x1f) { - printk(KERN_INFO "XXX Byte at %x is %x\n", - card->iobase + 2, - bytein(card->iobase + 2)); - return -2; - } - if (card->membase) { /* 16.0 */ - request_region(card->iobase, 8, "teles 16.0"); - } else { - request_region(card->iobase, 16, "teles 16.3"); - request_region(card->iobase - 0xC00, 32, "teles HSCX0"); - request_region(card->iobase - 0x800, 32, "teles HSCX1"); - request_region(card->iobase - 0x400, 32, "teles ISAC"); - } - cli(); - timout = jiffies + (HZ / 10) + 1; - byteout(card->iobase + 4, cfval); - sti(); - while (jiffies <= timout); - - cli(); - timout = jiffies + (HZ / 10) + 1; - byteout(card->iobase + 4, cfval | 1); - sti(); - while (jiffies <= timout); - - if (card->membase) - printk(KERN_NOTICE - "Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n", - card->iobase, (long) card->membase, - card->interrupt, - (card->protocol == ISDN_PTYPE_1TR6) ? - "1TR6" : "EDSS1"); - else - printk(KERN_NOTICE - "Teles 16.3 found, io: %x irq: %d proto: %s\n", - card->iobase, card->interrupt, - (card->protocol == ISDN_PTYPE_1TR6) ? - "1TR6" : "EDSS1"); - printk(KERN_INFO "HSCX version A:%x B:%x\n", - READHSCX(card->membase, card->iobase, 0, - HSCX_VSTR) & 0xf, - READHSCX(card->membase, card->iobase, 1, - HSCX_VSTR) & 0xf); - - } - if (card->membase) { - cli(); - timout = jiffies + (HZ / 5) + 1; - writeb(0, card->membase + 0x80); - sti(); - while (jiffies <= timout); - - cli(); - writeb(1, card->membase + 0x80); - timout = jiffies + (HZ / 5) + 1; - sti(); - while (jiffies <= timout); - } - return (0); -} - -void -modehscx(struct HscxState *hs, int mode, - int ichan) -{ - struct IsdnCardState *sp = hs->sp; - int hscx = hs->hscx; - - printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n", - hscx, mode, ichan); - - hs->mode = mode; - if (sp->membase) { - /* What's that ??? KKeil */ - if (hscx == 0) - ichan = 1 - ichan; /* raar maar waar... */ - writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85); - writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF); - writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF); - writehscx_0(sp->membase, hscx, HSCX_RAH2, 0xFF); - writehscx_0(sp->membase, hscx, HSCX_XBCH, 0x0); - - switch (mode) { - case (0): - writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30); - writehscx_0(sp->membase, hscx, HSCX_TSAX, 0xff); - writehscx_0(sp->membase, hscx, HSCX_TSAR, 0xff); - writehscx_0(sp->membase, hscx, HSCX_XCCR, 7); - writehscx_0(sp->membase, hscx, HSCX_RCCR, 7); - writehscx_0(sp->membase, hscx, HSCX_MODE, 0x84); - break; - case (1): - if (ichan == 0) { - writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30); - writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7); - writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7); - writehscx_0(sp->membase, hscx, HSCX_XCCR, 7); - writehscx_0(sp->membase, hscx, HSCX_RCCR, 7); - } else { - writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30); - writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3); - writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3); - writehscx_0(sp->membase, hscx, HSCX_XCCR, 7); - writehscx_0(sp->membase, hscx, HSCX_RCCR, 7); - } - writehscx_0(sp->membase, hscx, HSCX_MODE, 0xe4); - writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41); - break; - case (2): - if (ichan == 0) { - writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30); - writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7); - writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7); - writehscx_0(sp->membase, hscx, HSCX_XCCR, 7); - writehscx_0(sp->membase, hscx, HSCX_RCCR, 7); - } else { - writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30); - writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3); - writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3); - writehscx_0(sp->membase, hscx, HSCX_XCCR, 7); - writehscx_0(sp->membase, hscx, HSCX_RCCR, 7); - } - writehscx_0(sp->membase, hscx, HSCX_MODE, 0x8c); - writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41); - break; - } - writehscx_0(sp->membase, hscx, HSCX_ISTA, 0x00); - } else { - writehscx_3(sp->iobase, hscx, HSCX_CCR1, 0x85); - writehscx_3(sp->iobase, hscx, HSCX_XAD1, 0xFF); - writehscx_3(sp->iobase, hscx, HSCX_XAD2, 0xFF); - writehscx_3(sp->iobase, hscx, HSCX_RAH2, 0xFF); - writehscx_3(sp->iobase, hscx, HSCX_XBCH, 0x00); - writehscx_3(sp->iobase, hscx, HSCX_RLCR, 0x00); - - switch (mode) { - case (0): - writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30); - writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0xff); - writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0xff); - writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7); - writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7); - writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x84); - break; - case (1): - if (ichan == 0) { - writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30); - writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f); - writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f); - writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7); - writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7); - } else { - writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30); - writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3); - writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3); - writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7); - writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7); - } - writehscx_3(sp->iobase, hscx, HSCX_MODE, 0xe4); - writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41); - break; - case (2): - if (ichan == 0) { - writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30); - writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f); - writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f); - writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7); - writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7); - } else { - writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30); - writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3); - writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3); - writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7); - writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7); - } - writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x8c); - writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41); - break; - } - writehscx_3(sp->iobase, hscx, HSCX_ISTA, 0x00); - } -} - -void -teles_addlist(struct IsdnCardState *sp, - struct PStack *st) -{ - st->next = sp->stlist; - sp->stlist = st; -} - -void -teles_rmlist(struct IsdnCardState *sp, - struct PStack *st) -{ - struct PStack *p; - - if (sp->stlist == st) - sp->stlist = st->next; - else { - p = sp->stlist; - while (p) - if (p->next == st) { - p->next = st->next; - return; - } else - p = p->next; - } -} - - -static void -teles_l2l1(struct PStack *st, int pr, - struct BufHeader *ibh) -{ - struct IsdnCardState *sp = (struct IsdnCardState *) - st->l1.hardware; - - - switch (pr) { - case (PH_DATA): - if (sp->xmtibh) - BufQueueLink(&sp->sq, ibh); - else { - sp->xmtibh = ibh; - sp->sendptr = 0; - sp->releasebuf = !0; - fill_fifo(sp); - } - break; - case (PH_DATA_PULLED): - if (sp->xmtibh) { - printk(KERN_DEBUG "teles_l2l1: this shouldn't happen\n"); - break; - } - sp->xmtibh = ibh; - sp->sendptr = 0; - sp->releasebuf = 0; - fill_fifo(sp); - break; - case (PH_REQUEST_PULL): - if (!sp->xmtibh) { - st->l1.requestpull = 0; - st->l1.l1l2(st, PH_PULL_ACK, NULL); - } else - st->l1.requestpull = !0; - break; - } -} - -static void -check_ph_act(struct IsdnCardState *sp) -{ - struct PStack *st = sp->stlist; - - while (st) { - if (st->l1.act_state) - return; - st = st->next; - } - sp->ph_active = 0; -} - -static void -teles_manl1(struct PStack *st, int pr, - void *arg) -{ - struct IsdnCardState *sp = (struct IsdnCardState *) - st->l1.hardware; - long flags; - - switch (pr) { - case (PH_ACTIVATE): - save_flags(flags); - cli(); - if (sp->ph_active == 5) { - st->l1.act_state = 2; - restore_flags(flags); - st->l1.l1man(st, PH_ACTIVATE, NULL); - } else { - st->l1.act_state = 1; - if (sp->ph_active == 0) - restart_ph(sp); - restore_flags(flags); - } - break; - case (PH_DEACTIVATE): - st->l1.act_state = 0; - check_ph_act(sp); - break; - } -} - -static void -teles_l2l1discardq(struct PStack *st, int pr, - void *heldby, int releasetoo) -{ - struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; - -#ifdef DEBUG_MAGIC - if (sp->magic != 301271) { - printk(KERN_DEBUG "isac_discardq magic not 301271\n"); - return; - } -#endif - - BufQueueDiscard(&sp->sq, pr, heldby, releasetoo); -} - -void -setstack_teles(struct PStack *st, struct IsdnCardState *sp) -{ - st->l1.hardware = sp; - st->l1.sbufpool = &(sp->sbufpool); - st->l1.rbufpool = &(sp->rbufpool); - st->l1.smallpool = &(sp->smallpool); - st->protocol = sp->teistack->protocol; - - setstack_tei(st); - - st->l1.stlistp = &(sp->stlist); - st->l1.act_state = 0; - st->l2.l2l1 = teles_l2l1; - st->l2.l2l1discardq = teles_l2l1discardq; - st->ma.manl1 = teles_manl1; - st->l1.requestpull = 0; -} - -void -init_hscxstate(struct IsdnCardState *sp, - int hscx) -{ - struct HscxState *hsp = sp->hs + hscx; - - hsp->sp = sp; - hsp->hscx = hscx; - hsp->membase = sp->membase; - hsp->iobase = sp->iobase; - - hsp->tqueue.next = 0; - hsp->tqueue.sync = 0; - hsp->tqueue.routine = (void *) (void *) hscx_bh; - hsp->tqueue.data = hsp; - - hsp->inuse = 0; - hsp->init = 0; - hsp->active = 0; - -#ifdef DEBUG_MAGIC - hsp->magic = 301270; -#endif -} - -void -initcard(int cardnr) -{ - struct IsdnCardState *sp; - struct IsdnCard *card = cards + cardnr; - - sp = (struct IsdnCardState *) - Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL, - "struct IsdnCardState"); - - sp->membase = card->membase; - sp->iobase = card->iobase; - sp->cardnr = cardnr; - - BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS, - ISAC_SBUF_MAXPAGES); - BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS, - ISAC_RBUF_MAXPAGES); - BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS, - ISAC_SMALLBUF_MAXPAGES); - - sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace"); - - initisac(card->membase, card->iobase); - - sp->rcvibh = NULL; - sp->rcvptr = 0; - sp->xmtibh = NULL; - sp->sendptr = 0; - sp->event = 0; - sp->tqueue.next = 0; - sp->tqueue.sync = 0; - sp->tqueue.routine = (void *) (void *) isac_bh; - sp->tqueue.data = sp; - - BufQueueInit(&sp->rq); - BufQueueInit(&sp->sq); - - sp->stlist = NULL; - - sp->ph_active = 0; - - sp->dlogflag = 0; - sp->debug = 0; - - sp->releasebuf = 0; -#ifdef DEBUG_MAGIC - sp->magic = 301271; -#endif - - cards[sp->cardnr].sp = sp; - - init_hscxstate(sp, 0); - init_hscxstate(sp, 1); - - modehscx(sp->hs, 0, 0); - modehscx(sp->hs + 1, 0, 0); - - WRITEISAC(sp->membase, sp->iobase, ISAC_MASK, 0x0); -} - -static int -get_irq(int cardnr) -{ - struct IsdnCard *card = cards + cardnr; - long flags; - - save_flags(flags); - cli(); - if (request_irq(card->interrupt, &teles_interrupt, - SA_INTERRUPT, "teles", NULL)) { - printk(KERN_WARNING "Teles couldn't get interrupt %d\n", - card->interrupt); - restore_flags(flags); - return (!0); - } - irq2dev_map[card->interrupt] = (void *) card->sp; - restore_flags(flags); - return (0); -} - -static void -release_irq(int cardnr) -{ - struct IsdnCard *card = cards + cardnr; - - irq2dev_map[card->interrupt] = NULL; - free_irq(card->interrupt, NULL); -} - -void -close_hscxstate(struct HscxState *hs) -{ - modehscx(hs, 0, 0); - hs->inuse = 0; - - if (hs->init) { - BufPoolFree(&hs->smallpool); - BufPoolFree(&hs->rbufpool); - BufPoolFree(&hs->sbufpool); - } - hs->init = 0; -} - -void -closecard(int cardnr) -{ - struct IsdnCardState *sp = cards[cardnr].sp; - - cards[cardnr].sp = NULL; - - Sfree(sp->dlogspace); - - BufPoolFree(&sp->smallpool); - BufPoolFree(&sp->rbufpool); - BufPoolFree(&sp->sbufpool); - - close_hscxstate(sp->hs + 1); - close_hscxstate(sp->hs); - - if (cards[cardnr].iobase) - if (cards[cardnr].membase) { /* 16.0 */ - release_region(cards[cardnr].iobase, 8); - } else { - release_region(cards[cardnr].iobase, 16); - release_region(cards[cardnr].iobase - 0xC00, 32); - release_region(cards[cardnr].iobase - 0x800, 32); - release_region(cards[cardnr].iobase - 0x400, 32); - } - - Sfree((void *) sp); -} - -void -teles_shiftcards(int idx) -{ - int i; - - for (i = idx; i < 15; i++) - memcpy(&cards[i],&cards[i+1],sizeof(cards[i])); -} - -int -teles_inithardware(void) -{ - int foundcards = 0; - int i = 0; - - while (i < nrcards) { - if (!cards[i].protocol) - break; - switch (checkcard(i)) { - case (0): - initcard(i); - if (get_irq(i)) { - closecard(i); - teles_shiftcards(i); - } else { - foundcards++; - i++; - } - break; - case (-1): - teles_shiftcards(i); - break; - case (-2): - release_region(cards[i].iobase, 8); - printk(KERN_WARNING "NO Teles card found at 0x%x!\n", cards[i].iobase); - teles_shiftcards(i); - break; - } - } - return foundcards; -} - -void -teles_closehardware(void) -{ - int i; - - for (i = 0; i < nrcards; i++) - if (cards[i].sp) { - release_irq(i); - closecard(i); - } -} - -static void -hscx_l2l1(struct PStack *st, int pr, - struct BufHeader *ibh) -{ - struct IsdnCardState *sp = (struct IsdnCardState *) - st->l1.hardware; - struct HscxState *hsp = sp->hs + st->l1.hscx; - long flags; - - switch (pr) { - case (PH_DATA): - save_flags(flags); - cli(); - if (hsp->xmtibh) { - BufQueueLink(&hsp->sq, ibh); - restore_flags(flags); - } - else { - restore_flags(flags); - hsp->xmtibh = ibh; - hsp->sendptr = 0; - hsp->releasebuf = !0; - hscx_fill_fifo(hsp); - } - break; - case (PH_DATA_PULLED): - if (hsp->xmtibh) { - printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n"); - break; - } - hsp->xmtibh = ibh; - hsp->sendptr = 0; - hsp->releasebuf = 0; - hscx_fill_fifo(hsp); - break; - case (PH_REQUEST_PULL): - if (!hsp->xmtibh) { - st->l1.requestpull = 0; - st->l1.l1l2(st, PH_PULL_ACK, NULL); - } else - st->l1.requestpull = !0; - break; - } - -} - -extern struct IsdnBuffers *tracebuf; - -static void -hscx_l2l1discardq(struct PStack *st, int pr, void *heldby, - int releasetoo) -{ - struct IsdnCardState *sp = (struct IsdnCardState *) - st->l1.hardware; - struct HscxState *hsp = sp->hs + st->l1.hscx; - -#ifdef DEBUG_MAGIC - if (hsp->magic != 301270) { - printk(KERN_DEBUG "hscx_discardq magic not 301270\n"); - return; - } -#endif - - BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo); -} - -static int -open_hscxstate(struct IsdnCardState *sp, - int hscx) -{ - struct HscxState *hsp = sp->hs + hscx; - - if (!hsp->init) { - BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS, - HSCX_SBUF_MAXPAGES); - BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS, - HSCX_RBUF_MAXPAGES); - BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS, - HSCX_SMALLBUF_MAXPAGES); - } - hsp->init = !0; - - BufQueueInit(&hsp->rq); - BufQueueInit(&hsp->sq); - - hsp->releasebuf = 0; - hsp->rcvibh = NULL; - hsp->xmtibh = NULL; - hsp->rcvptr = 0; - hsp->sendptr = 0; - hsp->event = 0; - return (0); -} - -static void -hscx_manl1(struct PStack *st, int pr, - void *arg) -{ - struct IsdnCardState *sp = (struct IsdnCardState *) - st->l1.hardware; - struct HscxState *hsp = sp->hs + st->l1.hscx; - - switch (pr) { - case (PH_ACTIVATE): - hsp->active = !0; - modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel); - st->l1.l1man(st, PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE): - if (!hsp->xmtibh) - modehscx(hsp, 0, 0); - - hsp->active = 0; - break; - } -} - -int -setstack_hscx(struct PStack *st, struct HscxState *hs) -{ - if (open_hscxstate(st->l1.hardware, hs->hscx)) - return (-1); - - st->l1.hscx = hs->hscx; - st->l2.l2l1 = hscx_l2l1; - st->ma.manl1 = hscx_manl1; - st->l2.l2l1discardq = hscx_l2l1discardq; - - st->l1.sbufpool = &hs->sbufpool; - st->l1.rbufpool = &hs->rbufpool; - st->l1.smallpool = &hs->smallpool; - st->l1.act_state = 0; - st->l1.requestpull = 0; - - hs->st = st; - return (0); -} - -void -teles_reportcard(int cardnr) -{ - printk(KERN_DEBUG "teles_reportcard\n"); -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/config.c linux/drivers/isdn/teles/config.c --- v2.1.36/linux/drivers/isdn/teles/config.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/config.c Wed Dec 31 16:00:00 1969 @@ -1,48 +0,0 @@ -/* $Id: config.c,v 1.1 1996/04/13 10:23:11 fritz Exp $ - * - * $Log: config.c,v $ - * Revision 1.1 1996/04/13 10:23:11 fritz - * Initial revision - * - * - */ -#define __NO_VERSION__ -#include -#include -#include -#include "teles.h" - -/* - * This structure array contains one entry per card. An entry looks - * like this: - * - * { membase,irq,portbase,protocol,NULL } - * - * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 - * - * Cards which don't have an io port (Teles 8 bit cards for - * example) can be entered with io port 0x0 - * - * For the Teles 16.3, membase has to be set to 0. - * - */ - -struct IsdnCard cards[] = -{ - {(byte *) 0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL}, /* example */ - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, - {NULL, 0, 0, 0, NULL}, -}; diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/fsm.c linux/drivers/isdn/teles/fsm.c --- v2.1.36/linux/drivers/isdn/teles/fsm.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/fsm.c Wed Dec 31 16:00:00 1969 @@ -1,156 +0,0 @@ -/* $Id: fsm.c,v 1.3 1997/02/16 01:04:12 fritz Exp $ - * - * $Log: fsm.c,v $ - * Revision 1.3 1997/02/16 01:04:12 fritz - * Bugfix: Changed timer handling caused hang with 2.1.X - * - * Revision 1.2 1996/04/29 22:49:57 fritz - * Removed compatibility-macros. - * - * Revision 1.1 1996/04/13 10:23:41 fritz - * Initial revision - * - * - */ -#define __NO_VERSION__ -#include "teles.h" - -void -FsmNew(struct Fsm *fsm, - struct FsmNode *fnlist, int fncount) -{ - int i; - - fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count, - GFP_KERNEL, "Fsm jumpmatrix"); - memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count); - - for (i = 0; i < fncount; i++) - fsm->jumpmatrix[fsm->state_count * fnlist[i].event + - fnlist[i].state] = (int) fnlist[i].routine; -} - -void -FsmFree(struct Fsm *fsm) -{ - Sfree((void *) fsm->jumpmatrix); -} - -int -FsmEvent(struct FsmInst *fi, int event, void *arg) -{ - void (*r) (struct FsmInst *, int, void *); - char str[80]; - - r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; - if (r) { - if (fi->debug) { - sprintf(str, "State %s Event %s", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); - fi->printdebug(fi, str); - } - r(fi, event, arg); - return (0); - } else { - if (fi->debug) { - sprintf(str, "State %s Event %s no routine", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); - fi->printdebug(fi, str); - } - return (!0); - } -} - -void -FsmChangeState(struct FsmInst *fi, int newstate) -{ - char str[80]; - - fi->state = newstate; - if (fi->debug) { - sprintf(str, "ChangeState %s", - fi->fsm->strState[newstate]); - fi->printdebug(fi, str); - } -} - -static void -FsmExpireTimer(struct FsmTimer *ft) -{ - FsmEvent(ft->fi, ft->event, ft->arg); -} - -void -FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) -{ - ft->fi = fi; - ft->tl.function = (void *) FsmExpireTimer; - ft->tl.data = (long) ft; - init_timer(&ft->tl); -} - -void -FsmDelTimer(struct FsmTimer *ft, int where) -{ -#if 0 - if (ft->fi->debug) { - sprintf(str, "FsmDelTimer %lx %d", ft, where); - ft->fi->printdebug(ft->fi, str); - } -#endif - - del_timer(&ft->tl); -} - -int -FsmAddTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if 0 - if (ft->fi->debug) { - sprintf(str, "FsmAddTimer %lx %d %d", ft, millisec, where); - ft->fi->printdebug(ft->fi, str); - } -#endif - - if (ft->tl.next || ft->tl.prev) { - printk(KERN_WARNING "FsmAddTimer: timer already active!\n"); - return -1; - } - init_timer(&ft->tl); - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); - return 0; -} - -int -FsmTimerRunning(struct FsmTimer *ft) -{ - return (ft->tl.next != NULL); -} - -void -jiftime(char *s, long mark) -{ - s += 8; - - *s-- = '\0'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = '.'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 6 + '0'; - mark /= 6; - *s-- = ':'; - *s-- = mark % 10 + '0'; - mark /= 10; - *s-- = mark % 10 + '0'; -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/isdnl2.c linux/drivers/isdn/teles/isdnl2.c --- v2.1.36/linux/drivers/isdn/teles/isdnl2.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/isdnl2.c Wed Dec 31 16:00:00 1969 @@ -1,1320 +0,0 @@ -/* $Id: isdnl2.c,v 1.3 1996/11/23 11:32:57 keil Exp $ - * - * $Log: isdnl2.c,v $ - * Revision 1.3 1996/11/23 11:32:57 keil - * X.75 bugfixies; Thanks to Martin Maurer - * - * Revision 1.2 1996/05/17 03:46:15 fritz - * General cleanup. - * - * Revision 1.1 1996/04/13 10:24:16 fritz - * Initial revision - * - * - */ -#define __NO_VERSION__ -#include "teles.h" - -#define TIMER_1 2000 - -static void l2m_debug(struct FsmInst *fi, char *s); - -struct Fsm l2fsm = -{NULL, 0, 0}; - -enum { - ST_L2_1, - ST_L2_3, - ST_L2_4, - ST_L2_5, - ST_L2_6, - ST_L2_7, - ST_L2_8, -}; - -#define L2_STATE_COUNT (ST_L2_8+1) - -static char *strL2State[] = -{ - "ST_L2_1", - "ST_L2_3", - "ST_L2_4", - "ST_L2_5", - "ST_L2_6", - "ST_L2_7", - "ST_L2_8", -}; - -enum { - EV_L2_UI, - EV_L2_SABMX, - EV_L2_UA, - EV_L2_DISC, - EV_L2_I, - EV_L2_RR, - EV_L2_REJ, - EV_L2_FRMR, - EV_L2_DL_DATA, - EV_L2_DL_ESTABLISH, - EV_L2_MDL_ASSIGN, - EV_L2_DL_UNIT_DATA, - EV_L2_DL_RELEASE, - EV_L2_MDL_NOTEIPROC, - EV_L2_T200, - EV_L2_ACK_PULL, - EV_L2_T203, - EV_L2_RNR, -}; - -#define L2_EVENT_COUNT (EV_L2_RNR+1) - -static char *strL2Event[] = -{ - "EV_L2_UI", - "EV_L2_SABMX", - "EV_L2_UA", - "EV_L2_DISC", - "EV_L2_I", - "EV_L2_RR", - "EV_L2_REJ", - "EV_L2_FRMR", - "EV_L2_DL_DATA", - "EV_L2_DL_ESTABLISH", - "EV_L2_MDL_ASSIGN", - "EV_L2_DL_UNIT_DATA", - "EV_L2_DL_RELEASE", - "EV_L2_MDL_NOTEIPROC", - "EV_L2_T200", - "EV_L2_ACK_PULL", - "EV_L2_T203", - "EV_L2_RNR", -}; - -int errcount = 0; - -static int l2addrsize(struct Layer2 *tsp); - -static int -cansend(struct PStack *st) -{ - int p1; - - p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8); - return (st->l2.vs != p1); -} - -static void -discard_i_queue(struct PStack *st) -{ - struct BufHeader *ibh; - - while (!BufQueueUnlink(&ibh, &st->l2.i_queue)) - BufPoolRelease(ibh); -} - -int -l2headersize(struct Layer2 *tsp, int UI) -{ - return ((tsp->extended && (!UI) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1)); -} - -int -l2addrsize(struct Layer2 *tsp) -{ - return (tsp->laptype == LAPD ? 2 : 1); -} - -static int -sethdraddr(struct Layer2 *tsp, - struct BufHeader *ibh, int rsp) -{ - byte *ptr = DATAPTR(ibh); - int crbit; - - if (tsp->laptype == LAPD) { - crbit = rsp; - if (!tsp->orig) - crbit = !crbit; - *ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0); - *ptr++ = (tsp->tei << 1) | 1; - return (2); - } else { - crbit = rsp; - if (tsp->orig) - crbit = !crbit; - if (crbit) - *ptr++ = 1; - else - *ptr++ = 3; - return (1); - } -} - -static void -enqueue_ui(struct PStack *st, - struct BufHeader *ibh) -{ - st->l2.l2l1(st, PH_DATA, ibh); -} - -static void -enqueue_super(struct PStack *st, - struct BufHeader *ibh) -{ - st->l2.l2l1(st, PH_DATA, ibh); -} - -static int -legalnr(struct PStack *st, int nr) -{ - struct Layer2 *l2 = &st->l2; - int lnr, lvs; - - lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8); - lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8); - return (lnr <= lvs); -} - -static void -setva(struct PStack *st, int nr) -{ - struct Layer2 *l2 = &st->l2; - - if (l2->va != nr) { - while (l2->va != nr) { - l2->va = (l2->va + 1) % (l2->extended ? 128 : 8); - BufPoolRelease(l2->windowar[l2->sow]); - l2->sow = (l2->sow + 1) % l2->window; - } - if (st->l4.l2writewakeup) - st->l4.l2writewakeup(st); - } -} - -static void -l2s1(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l2.l2tei(st, MDL_ASSIGN, (void *)st->l2.ces); - FsmChangeState(fi, ST_L2_3); -} - -static void -l2s2(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - - byte *ptr; - int i; - - i = sethdraddr(&(st->l2), ibh, 0); - ptr = DATAPTR(ibh); - ptr += i; - *ptr = 0x3; - - enqueue_ui(st, ibh); -} - -static void -l2s3(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - - st->l2.l2l3(st, DL_UNIT_DATA, ibh); -} - -static void -establishlink(struct FsmInst *fi) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh; - int i; - byte *ptr; - - FsmChangeState(fi, ST_L2_5); - st->l2.rc = 0; - - if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 1"); - - - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15)) - return; - i = sethdraddr(&st->l2, ibh, 0); - ptr = DATAPTR(ibh); - ptr += i; - if (st->l2.extended) - *ptr = 0x7f; - else - *ptr = 0x3f; - ibh->datasize = i + 1; - - enqueue_super(st, ibh); -} - -static void -l2s11(struct FsmInst *fi, int event, void *arg) -{ - establishlink(fi); -} - -static void -l2s13(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct Channel *chanp = st->l4.userdata; - byte *ptr; - struct BufHeader *ibh; - int i; - - FsmChangeState(fi, ST_L2_6); - - FsmDelTimer(&st->l2.t203_timer, 1); - if (st->l2.t200_running) { - FsmDelTimer(&st->l2.t200_timer, 2); - st->l2.t200_running = 0; - } - st->l2.rc = 0; - if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 2"); - - - if ((chanp->impair == 2) && (st->l2.laptype == LAPB)) - goto nodisc; - - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 9)) - return; - i = sethdraddr(&(st->l2), ibh, 0); - ptr = DATAPTR(ibh); - ptr += i; - *ptr = 0x53; - ibh->datasize = i + 1; - enqueue_super(st, ibh); - - nodisc: - discard_i_queue(st); -} - -static void -l2s12(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - byte *ptr; - int i; - - BufPoolRelease(ibh); - st->l2.vs = 0; - st->l2.va = 0; - st->l2.vr = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 3"); - - st->l2.l2man(st, DL_ESTABLISH, NULL); - - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10)) - return; - i = sethdraddr(&(st->l2), ibh, !0); - ptr = DATAPTR(ibh); - ptr += i; - *ptr = 0x73; - ibh->datasize = i + 1; - enqueue_super(st, ibh); - -} - -static void -l2s14(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - struct Channel *chanp = st->l4.userdata; - byte *ptr; - int i, p; - - ptr = DATAPTR(ibh); - ptr += l2addrsize(&(st->l2)); - p = (*ptr) & 0x10; - BufPoolRelease(ibh); - - FsmChangeState(fi, ST_L2_4); - - FsmDelTimer(&st->l2.t203_timer, 3); - if (st->l2.t200_running) { - FsmDelTimer(&st->l2.t200_timer, 4); - st->l2.t200_running = 0; - } - if ((chanp->impair == 1) && (st->l2.laptype == LAPB)) - goto noresponse; - - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11)) - return; - i = sethdraddr(&(st->l2), ibh, 0); - ptr = DATAPTR(ibh); - ptr += i; - *ptr = 0x63 | (p ? 0x10 : 0x0); - ibh->datasize = i + 1; - enqueue_super(st, ibh); - - noresponse: - st->l2.l2man(st, DL_RELEASE, NULL); - -} - -static void -l2s5(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - int f; - byte *data; - - data = DATAPTR(ibh); - data += l2addrsize(&(st->l2)); - - f = *data & 0x10; - BufPoolRelease(ibh); - - if (f) { - st->l2.vs = 0; - st->l2.va = 0; - st->l2.vr = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - - FsmDelTimer(&st->l2.t200_timer, 5); - if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 4"); - - - st->l2.l2man(st, DL_ESTABLISH, NULL); - } -} - -static void -l2s15(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - int f; - byte *data; - - data = DATAPTR(ibh); - data += l2addrsize(&st->l2); - - f = *data & 0x10; - BufPoolRelease(ibh); - - if (f) { - FsmDelTimer(&st->l2.t200_timer, 6); - FsmChangeState(fi, ST_L2_4); - st->l2.l2man(st, DL_RELEASE, NULL); - } -} - -static void -l2s6(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct Channel *chanp = st->l4.userdata; - struct BufHeader *ibh = arg; - int p, i, seq, rsp; - byte *ptr; - struct Layer2 *l2; - - l2 = &st->l2; - ptr = DATAPTR(ibh); - - if (l2->laptype == LAPD) { - rsp = ptr[0] & 0x2; - if (l2->orig) - rsp = !rsp; - } else { - rsp = ptr[0] == 0x3; - if (l2->orig) - rsp = !rsp; - } - - ptr += l2addrsize(l2); - - if (l2->extended) { - p = (ptr[1] & 0x1) == 0x1; - seq = ptr[1] >> 1; - } else { - p = (ptr[0] & 0x10); - seq = (ptr[0] >> 5) & 0x7; - } - BufPoolRelease(ibh); - - if ((chanp->impair == 4) && (st->l2.laptype == LAPB)) - goto noresp; - - if ((!rsp) && p) { - if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) { - i = sethdraddr(l2, ibh, !0); - ptr = DATAPTR(ibh); - ptr += i; - - if (l2->extended) { - *ptr++ = 0x1; - *ptr++ = (l2->vr << 1) | (p ? 1 : 0); - i += 2; - } else { - *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0); - i += 1; - } - ibh->datasize = i; - enqueue_super(st, ibh); - } - } - noresp: - if (legalnr(st, seq)) - if (seq == st->l2.vs) { - setva(st, seq); - FsmDelTimer(&st->l2.t200_timer, 7); - st->l2.t200_running = 0; - FsmDelTimer(&st->l2.t203_timer, 8); - if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 5)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 5"); - - if (st->l2.i_queue.head) - st->l2.l2l1(st, PH_REQUEST_PULL, NULL); - } else if (st->l2.va != seq) { - setva(st, seq); - FsmDelTimer(&st->l2.t200_timer, 9); - if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 6"); - - if (st->l2.i_queue.head) - st->l2.l2l1(st, PH_REQUEST_PULL, NULL); - } -} - -static void -l2s7(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - int i; - byte *ptr; - struct IsdnCardState *sp = st->l1.hardware; - char str[64]; - - i = sethdraddr(&st->l2, ibh, 0); - ptr = DATAPTR(ibh); - - if (st->l2.laptype == LAPD) - if (sp->dlogflag) { - sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); - dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - str); - } - BufQueueLink(&st->l2.i_queue, ibh); - - st->l2.l2l1(st, PH_REQUEST_PULL, NULL); -} - -static void -l2s8(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct Channel *chanp = st->l4.userdata; - struct BufHeader *ibh = arg; - byte *ptr; - struct BufHeader *ibh2; - struct IsdnCardState *sp = st->l1.hardware; - struct Layer2 *l2 = &(st->l2); - int i, p, seq, nr, wasok; - char str[64]; - - ptr = DATAPTR(ibh); - ptr += l2addrsize(l2); - if (l2->extended) { - p = (ptr[1] & 0x1) == 0x1; - seq = ptr[0] >> 1; - nr = (ptr[1] >> 1) & 0x7f; - } else { - p = (ptr[0] & 0x10); - seq = (ptr[0] >> 1) & 0x7; - nr = (ptr[0] >> 5) & 0x7; - } - - if (l2->vr == seq) { - wasok = !0; - - l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8); - l2->rejexp = 0; - - ptr = DATAPTR(ibh); - if (st->l2.laptype == LAPD) - if (sp->dlogflag) { - sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei); - dlogframe(st->l1.hardware, ptr + l2->ihsize, - ibh->datasize - l2->ihsize, str); - } - label8_1: - if ((chanp->impair == 3) && (st->l2.laptype == LAPB)) - goto noRR; - - if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) { - i = sethdraddr(&(st->l2), ibh2, !0); - ptr = DATAPTR(ibh2); - ptr += i; - - if (l2->extended) { - *ptr++ = 0x1; - *ptr++ = (l2->vr << 1) | (p ? 1 : 0); - i += 2; - } else { - *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0); - i += 1; - } - ibh2->datasize = i; - enqueue_super(st, ibh2); - noRR: - } - } else { - /* n(s)!=v(r) */ - wasok = 0; - BufPoolRelease(ibh); - if (st->l2.rejexp) { - if (p) - goto label8_1; - } else { - st->l2.rejexp = !0; - if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 14)) { - i = sethdraddr(&(st->l2), ibh2, p); - ptr = DATAPTR(ibh2); - ptr += i; - - if (l2->extended) { - *ptr++ = 0x9; - *ptr++ = (l2->vr << 1) | (p ? 1 : 0); - i += 2; - } else { - *ptr++ = (l2->vr << 5) | 0x9 | (p ? 0x10 : 0x0); - i += 1; - } - ibh2->datasize = i; - enqueue_super(st, ibh2); - } - } - } - - if (legalnr(st, nr)) - if (nr == st->l2.vs) { - setva(st, nr); - FsmDelTimer(&st->l2.t200_timer, 10); - st->l2.t200_running = 0; - FsmDelTimer(&st->l2.t203_timer, 11); - if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 5"); - - if (st->l2.i_queue.head) - st->l2.l2l1(st, PH_REQUEST_PULL, NULL); - } else if (nr != st->l2.va) { - setva(st, nr); - FsmDelTimer(&st->l2.t200_timer, 12); - if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 6"); - - if (st->l2.i_queue.head) - st->l2.l2l1(st, PH_REQUEST_PULL, NULL); - } - if (wasok) - st->l2.l2l3(st, DL_DATA, ibh); - -} - -static void -l2s17(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l2.tei = (int) arg; - establishlink(fi); -} - -static void -enquiry_response(struct PStack *st) -{ - struct BufHeader *ibh2; - int i; - byte *ptr; - struct Layer2 *l2; - - l2 = &st->l2; - if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 16)) { - i = sethdraddr(&(st->l2), ibh2, !0); - ptr = DATAPTR(ibh2); - ptr += i; - - if (l2->extended) { - *ptr++ = 0x1; - *ptr++ = (l2->vr << 1) | 0x1; - i += 2; - } else { - *ptr++ = (l2->vr << 5) | 0x1 | 0x10; - i += 1; - } - ibh2->datasize = i; - enqueue_super(st, ibh2); - } -} - -static void -invoke_retransmission(struct PStack *st, int nr) -{ - struct Layer2 *l2 = &st->l2; - int p1; - - if (l2->vs != nr) { - while (l2->vs != nr) { - - l2->vs = l2->vs - 1; - if (l2->vs < 0) - l2->vs += l2->extended ? 128 : 8; - - p1 = l2->vs - l2->va; - if (p1 < 0) - p1 += l2->extended ? 128 : 8; - p1 = (p1 + l2->sow) % l2->window; - - BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]); - } - st->l2.l2l1(st, PH_REQUEST_PULL, NULL); - } -} - -static void -l2s16(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - int p, seq, rsp; - byte *ptr; - struct Layer2 *l2; - - l2 = &(st->l2); - ptr = DATAPTR(ibh); - - if (l2->laptype == LAPD) { - rsp = ptr[0] & 0x2; - if (l2->orig) - rsp = !rsp; - } else { - rsp = ptr[0] == 0x3; - if (l2->orig) - rsp = !rsp; - } - - - ptr += l2addrsize(l2); - - if (l2->extended) { - p = (ptr[1] & 0x1) == 0x1; - seq = ptr[1] >> 1; - } else { - p = (ptr[0] & 0x10); - seq = (ptr[0] >> 5) & 0x7; - } - BufPoolRelease(ibh); - - if ((!rsp) && p) - enquiry_response(st); - - if (!legalnr(st, seq)) - return; - - setva(st, seq); - invoke_retransmission(st, seq); - -} - -static void -l2s19(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L2_4); -} - -static void -l2s20(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - int i; - struct BufHeader *ibh; - byte *ptr; - - if (st->l2.rc == st->l2.n200) { - FsmChangeState(fi, ST_L2_4); - st->l2.l2man(st, DL_RELEASE, NULL); - } else { - st->l2.rc++; - - if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 7"); - - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15)) - return; - - i = sethdraddr(&st->l2, ibh, 0); - ptr = DATAPTR(ibh); - ptr += i; - if (st->l2.extended) - *ptr = 0x7f; - else - *ptr = 0x3f; - ibh->datasize = i + 1; - enqueue_super(st, ibh); - } -} - -static void -l2s21(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct Channel *chanp = st->l4.userdata; - int i; - struct BufHeader *ibh; - byte *ptr; - - if (st->l2.rc == st->l2.n200) { - FsmChangeState(fi, ST_L2_4); - st->l2.l2man(st, DL_RELEASE, NULL); - } else { - st->l2.rc++; - - if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 8"); - - - if ((chanp->impair == 2) && (st->l2.laptype == LAPB)) - goto nodisc; - - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15)) - return; - - i = sethdraddr(&st->l2, ibh, 0); - ptr = DATAPTR(ibh); - ptr += i; - *ptr = 0x53; - ibh->datasize = i + 1; - enqueue_super(st, ibh); - nodisc: - - } -} - -static void -l2s22(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh; - struct Layer2 *l2 = &st->l2; - byte *ptr; - int p1; - - if (!cansend(st)) - return; - - if (BufQueueUnlink(&ibh, &l2->i_queue)) - return; - - - p1 = l2->vs - l2->va; - if (p1 < 0) - p1 += l2->extended ? 128 : 8; - p1 = (p1 + l2->sow) % l2->window; - l2->windowar[p1] = ibh; - - ptr = DATAPTR(ibh); - ptr += l2addrsize(l2); - - if (l2->extended) { - *ptr++ = l2->vs << 1; - *ptr++ = (l2->vr << 1) | 0x1; - l2->vs = (l2->vs + 1) % 128; - } else { - *ptr++ = (l2->vr << 5) | (l2->vs << 1); - l2->vs = (l2->vs + 1) % 8; - } - - st->l2.l2l1(st, PH_DATA_PULLED, ibh); - - if (!st->l2.t200_running) { - FsmDelTimer(&st->l2.t203_timer, 13); - if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 9"); - - st->l2.t200_running = !0; - } - if (l2->i_queue.head && cansend(st)) - st->l2.l2l1(st, PH_REQUEST_PULL, NULL); - -} - -static void -transmit_enquiry(struct PStack *st) -{ - struct BufHeader *ibh; - byte *ptr; - - if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) { - ptr = DATAPTR(ibh); - ptr += sethdraddr(&st->l2, ibh, 0); - - if (st->l2.extended) { - *ptr++ = 0x1; - *ptr++ = (st->l2.vr << 1) | 1; - } else { - *ptr++ = (st->l2.vr << 5) | 0x11; - } - ibh->datasize = ptr - DATAPTR(ibh); - enqueue_super(st, ibh); - if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 10"); - - st->l2.t200_running = !0; - } -} - -static void -l2s23(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l2.t200_running = 0; - - st->l2.rc = 1; - FsmChangeState(fi, ST_L2_8); - transmit_enquiry(st); -} - -static void -l2s24(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - int p, seq, rsp; - byte *ptr; - struct Layer2 *l2; - - l2 = &st->l2; - ptr = DATAPTR(ibh); - - if (l2->laptype == LAPD) { - rsp = ptr[0] & 0x2; - if (l2->orig) - rsp = !rsp; - } else { - rsp = ptr[0] == 0x3; - if (l2->orig) - rsp = !rsp; - } - - - ptr += l2addrsize(l2); - - if (l2->extended) { - p = (ptr[1] & 0x1) == 0x1; - seq = ptr[1] >> 1; - } else { - p = (ptr[0] & 0x10); - seq = (ptr[0] >> 5) & 0x7; - } - BufPoolRelease(ibh); - - if (rsp && p) { - if (legalnr(st, seq)) { - FsmChangeState(fi, ST_L2_7); - setva(st, seq); - if (st->l2.t200_running) { - FsmDelTimer(&st->l2.t200_timer, 14); - st->l2.t200_running = 0; - } - if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 11"); - - invoke_retransmission(st, seq); - } - } else { - if (!rsp && p) - enquiry_response(st); - if (legalnr(st, seq)) { - setva(st, seq); - } - } -} - -static void -l2s25(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l2.rc = 0; - FsmChangeState(fi, ST_L2_8); - transmit_enquiry(st); -} - -static void -l2s26(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (st->l2.rc == st->l2.n200) { - l2s13(fi, event, NULL); - } else { - st->l2.rc++; - transmit_enquiry(st); - } -} - -static void -l2s27(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - byte *ptr; - int i, p, est; - - ptr = DATAPTR(ibh); - ptr += l2addrsize(&st->l2); - - if (st->l2.extended) - p = ptr[1] & 0x1; - else - p = ptr[0] & 0x10; - - BufPoolRelease(ibh); - - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10)) - return; - i = sethdraddr(&st->l2, ibh, 0); - ptr = DATAPTR(ibh); - ptr += i; - *ptr = 0x63 | p; - ibh->datasize = i + 1; - enqueue_super(st, ibh); - - if (st->l2.vs != st->l2.va) { - discard_i_queue(st); - est = !0; - } else - est = 0; - - FsmDelTimer(&st->l2.t200_timer, 15); - st->l2.t200_running = 0; - - if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3)) - if (st->l2.l2m.debug) - l2m_debug(&st->l2.l2m, "FAT 12"); - - st->l2.vs = 0; - st->l2.va = 0; - st->l2.vr = 0; - st->l2.sow = 0; - - - if (est) - st->l2.l2man(st, DL_ESTABLISH, NULL); - -} - -static void -l2s28(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct BufHeader *ibh = arg; - byte *ptr; - char tmp[64]; - - ptr = DATAPTR(ibh); - ptr += l2addrsize(&st->l2); - ptr++; - - if (st->l2.l2m.debug) { - if (st->l2.extended) - sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x", - ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]); - else - sprintf(tmp, "FRMR information %2x %2x %2x", - ptr[0], ptr[1], ptr[2]); - - l2m_debug(&st->l2.l2m, tmp); - } - BufPoolRelease(ibh); -} - -static int -IsUI(byte * data, int ext) -{ - return ((data[0] & 0xef) == 0x3); -} - -static int -IsUA(byte * data, int ext) -{ - return ((data[0] & 0xef) == 0x63); -} - -static int -IsDISC(byte * data, int ext) -{ - return ((data[0] & 0xef) == 0x43); -} - -static int -IsRR(byte * data, int ext) -{ - if (ext) - return (data[0] == 0x1); - else - return ((data[0] & 0xf) == 1); -} - -static int -IsI(byte * data, int ext) -{ - return ((data[0] & 0x1) == 0x0); -} - -static int -IsSABMX(byte * data, int ext) -{ - return (ext ? data[0] == 0x7f : data[0] == 0x3f); -} - -static int -IsREJ(byte * data, int ext) -{ - return (ext ? data[0] == 0x9 : (data[0] & 0xf) == 0x9); -} - -static int -IsFRMR(byte * data, int ext) -{ - return ((data[0] & 0xef) == 0x87); -} - -static int -IsRNR(byte * data, int ext) -{ - if (ext) - return (data[0] == 0x5); - else - return ((data[0] & 0xf) == 5); -} - -static struct FsmNode L2FnList[] = -{ - {ST_L2_1, EV_L2_DL_ESTABLISH, l2s1}, - {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2s19}, - {ST_L2_3, EV_L2_MDL_ASSIGN, l2s17}, - {ST_L2_4, EV_L2_DL_UNIT_DATA, l2s2}, - {ST_L2_4, EV_L2_DL_ESTABLISH, l2s11}, - {ST_L2_7, EV_L2_DL_UNIT_DATA, l2s2}, - {ST_L2_7, EV_L2_DL_DATA, l2s7}, - {ST_L2_7, EV_L2_DL_RELEASE, l2s13}, - {ST_L2_7, EV_L2_ACK_PULL, l2s22}, - {ST_L2_8, EV_L2_DL_RELEASE, l2s13}, - - {ST_L2_1, EV_L2_UI, l2s3}, - {ST_L2_4, EV_L2_UI, l2s3}, - {ST_L2_4, EV_L2_SABMX, l2s12}, - {ST_L2_5, EV_L2_UA, l2s5}, - {ST_L2_6, EV_L2_UA, l2s15}, - {ST_L2_7, EV_L2_UI, l2s3}, - {ST_L2_7, EV_L2_DISC, l2s14}, - {ST_L2_7, EV_L2_I, l2s8}, - {ST_L2_7, EV_L2_RR, l2s6}, - {ST_L2_7, EV_L2_REJ, l2s16}, - {ST_L2_7, EV_L2_SABMX, l2s27}, - {ST_L2_7, EV_L2_FRMR, l2s28}, - {ST_L2_8, EV_L2_RR, l2s24}, - {ST_L2_8, EV_L2_DISC, l2s14}, - {ST_L2_8, EV_L2_FRMR, l2s28}, - - {ST_L2_5, EV_L2_T200, l2s20}, - {ST_L2_6, EV_L2_T200, l2s21}, - {ST_L2_7, EV_L2_T200, l2s23}, - {ST_L2_7, EV_L2_T203, l2s25}, - {ST_L2_8, EV_L2_T200, l2s26}, -}; - -#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode)) - -static void -isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg) -{ - struct BufHeader *ibh; - byte *datap; - int ret = !0; - - switch (pr) { - case (PH_DATA): - - ibh = arg; - datap = DATAPTR(ibh); - datap += l2addrsize(&st->l2); - - if (IsI(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh); - else if (IsRR(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh); - else if (IsUI(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh); - else if (IsSABMX(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh); - else if (IsUA(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh); - else if (IsDISC(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh); - else if (IsREJ(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh); - else if (IsFRMR(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh); - else if (IsRNR(datap, st->l2.extended)) - ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh); - - if (ret) - BufPoolRelease(ibh); - - break; - case (PH_PULL_ACK): - FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); - break; - } -} - -static void -isdnl2_l3l2(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (DL_DATA): - if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) - BufPoolRelease((struct BufHeader *) arg); - break; - case (DL_UNIT_DATA): - if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) - BufPoolRelease((struct BufHeader *) arg); - break; - } -} - -static void -isdnl2_manl2(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (DL_ESTABLISH): - FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg); - break; - case (DL_RELEASE): - FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg); - break; - case (MDL_NOTEIPROC): - FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL); - break; - } -} - -static void -isdnl2_teil2(struct PStack *st, int pr, - void *arg) -{ - switch (pr) { - case (MDL_ASSIGN): - FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg); - break; - } -} - -void -releasestack_isdnl2(struct PStack *st) -{ - FsmDelTimer(&st->l2.t200_timer, 15); - FsmDelTimer(&st->l2.t203_timer, 16); -} - -static void -l2m_debug(struct FsmInst *fi, char *s) -{ - struct PStack *st = fi->userdata; - char tm[32], str[256]; - - jiftime(tm, jiffies); - sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s); - teles_putstatus(str); -} - - -void -setstack_isdnl2(struct PStack *st, char *debug_id) -{ - st->l1.l1l2 = isdnl2_l1l2; - st->l3.l3l2 = isdnl2_l3l2; - st->ma.manl2 = isdnl2_manl2; - st->ma.teil2 = isdnl2_teil2; - - st->l2.uihsize = l2headersize(&st->l2, !0); - st->l2.ihsize = l2headersize(&st->l2, 0); - BufQueueInit(&(st->l2.i_queue)); - st->l2.rejexp = 0; - st->l2.debug = 1; - - st->l2.l2m.fsm = &l2fsm; - st->l2.l2m.state = ST_L2_1; - st->l2.l2m.debug = 0; - st->l2.l2m.userdata = st; - st->l2.l2m.printdebug = l2m_debug; - strcpy(st->l2.debug_id, debug_id); - - FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer); - FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer); - st->l2.t200_running = 0; -} - -void -setstack_transl2(struct PStack *st) -{ -} - -void -releasestack_transl2(struct PStack *st) -{ -} - -void -Isdnl2New(void) -{ - l2fsm.state_count = L2_STATE_COUNT; - l2fsm.event_count = L2_EVENT_COUNT; - l2fsm.strEvent = strL2Event; - l2fsm.strState = strL2State; - FsmNew(&l2fsm, L2FnList, L2_FN_COUNT); -} - -void -Isdnl2Free(void) -{ - FsmFree(&l2fsm); -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/isdnl3.c linux/drivers/isdn/teles/isdnl3.c --- v2.1.36/linux/drivers/isdn/teles/isdnl3.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/isdnl3.c Wed Dec 31 16:00:00 1969 @@ -1,673 +0,0 @@ -/* $Id: isdnl3.c,v 1.13 1997/02/16 12:12:51 fritz Exp $ - * - * $Log: isdnl3.c,v $ - * Revision 1.13 1997/02/16 12:12:51 fritz - * Bugfix: SI2 was nont initialized on incoming calls. - * - * Revision 1.12 1997/02/11 01:39:20 keil - * Changed setup-interface (incoming and outgoing) - * - * Revision 1.11 1996/09/29 19:41:58 fritz - * Bugfix: ignore unknown frames. - * - * Revision 1.10 1996/09/25 18:32:43 keil - * response for STATUS_ENQ message added - * - * Revision 1.9 1996/06/06 14:22:27 fritz - * Changed level of "non-digital call..." message, since - * with audio support, this is quite normal. - * - * Revision 1.8 1996/06/03 20:35:04 fritz - * Fixed typos. - * - * Revision 1.7 1996/06/03 20:03:39 fritz - * Fixed typos. - * - * Revision 1.6 1996/05/21 11:33:50 keil - * Adding SETUP_ACKNOWLEDGE as answer of a SETUP message. - * - * Revision 1.5 1996/05/18 01:37:16 fritz - * Added spelling corrections and some minor changes - * to stay in sync with kernel. - * - * Revision 1.4 1996/05/17 03:46:16 fritz - * General cleanup. - * - * Revision 1.3 1996/04/30 21:57:53 isdn4dev - * remove some debugging code, improve callback Karsten Keil - * - * Revision 1.2 1996/04/20 16:45:05 fritz - * Changed to report all incoming calls to Linklevel, not just those - * with Service 7. - * Misc. typos - * - * Revision 1.1 1996/04/13 10:24:45 fritz - * Initial revision - * - * - */ -#define __NO_VERSION__ -#define P_1TR6 -#include "teles.h" -#include "l3_1TR6.h" -#define DEBUG_1TR6 0 - -static void -i_down(struct PStack *st, - struct BufHeader *ibh) -{ - st->l3.l3l2(st, DL_DATA, ibh); -} - -static void -newl3state(struct PStack *st, int state) -{ - st->l3.state = state; - if (DEBUG_1TR6 > 4) - printk(KERN_INFO "isdnl3: bc:%d cr:%x new state %d\n", - st->pa->bchannel, st->pa->callref, state); - -} - -static void -l3_message(struct PStack *st, int mt) -{ - struct BufHeader *dibh; - byte *p; - int size; - - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18); - p = DATAPTR(dibh); - p += st->l2.ihsize; - size = st->l2.ihsize; - - *p++ = 0x8; - *p++ = 0x1; - *p++ = st->l3.callref; - *p++ = mt; - size += 4; - - dibh->datasize = size; - i_down(st, dibh); -} - -static void -l3s3(struct PStack *st, byte pr, void *arg) -{ - l3_message(st, MT_RELEASE); - newl3state(st, 19); -} - -static void -l3s4(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - newl3state(st, 0); - st->l3.l3l4(st, CC_RELEASE_CNF, NULL); -} - -static void -l3s4_1(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - newl3state(st, 19); - l3_message(st, MT_RELEASE); - st->l3.l3l4(st, CC_RELEASE_CNF, NULL); -} - -static void -l3s5(struct PStack *st, byte pr, - void *arg) -{ - struct BufHeader *dibh; - byte *p; - char *teln; - - st->l3.callref = st->pa->callref; - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19); - p = DATAPTR(dibh); - p += st->l2.ihsize; - - *p++ = 0x8; - *p++ = 0x1; - *p++ = st->l3.callref; - *p++ = MT_SETUP; - *p++ = 0xa1; - - /* - * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 - */ - switch (st->pa->setup.si1) { - case 1: /* Telephony */ - *p++ = 0x4; /* BC-IE-code */ - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. national, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = 0x4; /* BC-IE-code */ - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. nat., unrestr. dig. Inform. */ - *p++ = 0x90; /* Packet-Mode 64kbps */ - break; - } - /* - * What about info2? Mapping to High-Layer-Compatibility? - */ - if (st->pa->setup.eazmsn[0] != '\0') { - *p++ = 0x6c; - *p++ = strlen(st->pa->setup.eazmsn) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - teln = st->pa->setup.eazmsn; - while (*teln) - *p++ = *teln++ & 0x7f; - } - *p++ = 0x70; - *p++ = strlen(st->pa->setup.phone) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - - teln = st->pa->setup.phone; - while (*teln) - *p++ = *teln++ & 0x7f; - - - dibh->datasize = p - DATAPTR(dibh); - - newl3state(st, 1); - i_down(st, dibh); - -} - -static void -l3s6(struct PStack *st, byte pr, void *arg) -{ - byte *p; - struct BufHeader *ibh = arg; - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - 0x18, 0))) { - st->pa->bchannel = p[2] & 0x3; - } else - printk(KERN_WARNING "octect 3 not found\n"); - - BufPoolRelease(ibh); - newl3state(st, 3); - st->l3.l3l4(st, CC_PROCEEDING_IND, NULL); -} - -static void -l3s7(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - newl3state(st, 12); - st->l3.l3l4(st, CC_DISCONNECT_IND, NULL); -} - -static void -l3s8(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - st->l3.l3l4(st, CC_SETUP_CNF, NULL); - newl3state(st, 10); -} - -static void -l3s11(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - newl3state(st, 4); - st->l3.l3l4(st, CC_ALERTING_IND, NULL); -} - -static void -l3s12(struct PStack *st, byte pr, void *arg) -{ - byte *p; - int bcfound = 0; - struct BufHeader *ibh = arg; - - p = DATAPTR(ibh); - p += st->l2.uihsize; - st->pa->callref = getcallref(p); - st->l3.callref = 0x80 + st->pa->callref; - - /* - * Channel Identification - */ - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, - 0x18, 0))) { - st->pa->bchannel = p[2] & 0x3; - bcfound++ ; - } else - printk(KERN_WARNING "l3s12: Channel ident not found\n"); - - p = DATAPTR(ibh); - if (st->protocol == ISDN_PTYPE_1TR6) { - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x01, 6))) { - st->pa->setup.si1 = p[2]; - st->pa->setup.si2 = p[3]; - } else - printk(KERN_WARNING "l3s12(1TR6): ServiceIndicator not found\n"); - } else { - /* - * Bearer Capabilities - */ - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) { - st->pa->setup.si2 = 0; - switch (p[2] & 0x1f) { - case 0x00: - /* Speech */ - case 0x10: - /* 3.1 Khz audio */ - st->pa->setup.si1 = 1; - break; - case 0x08: - /* Unrestricted digital information */ - st->pa->setup.si1 = 7; - break; - case 0x09: - /* Restricted digital information */ - st->pa->setup.si1 = 2; - break; - case 0x11: - /* Unrestr. digital information with tones/announcements */ - st->pa->setup.si1 = 3; - break; - case 0x18: - /* Video */ - st->pa->setup.si1 = 4; - break; - default: - st->pa->setup.si1 = 0; - } - } else - printk(KERN_WARNING "l3s12: Bearer capabilities not found\n"); - } - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, - 0x70, 0))) - iecpy(st->pa->setup.eazmsn, p, 1); - else - strcpy(st->pa->setup.eazmsn, ""); - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, - 0x6c, 0))) { - st->pa->setup.plan = p[2]; - if (st->protocol == ISDN_PTYPE_1TR6) { - iecpy(st->pa->setup.phone, p, 1); - } else { - st->pa->setup.screen = p[3]; - iecpy(st->pa->setup.phone, p, 2); - } - } else - strcpy(st->pa->setup.phone, ""); - BufPoolRelease(ibh); - - if (bcfound) { - if (st->pa->setup.si1 != 7) { - printk(KERN_DEBUG "non-digital call: %s -> %s\n", - st->pa->setup.phone, - st->pa->setup.eazmsn); - } - newl3state(st, 6); - st->l3.l3l4(st, CC_SETUP_IND, NULL); - } -} - -static void -l3s13(struct PStack *st, byte pr, void *arg) -{ - newl3state(st, 0); -} - -static void -l3s16(struct PStack *st, byte pr, - void *arg) -{ - st->l3.callref = 0x80 + st->pa->callref; - l3_message(st, MT_CONNECT); - newl3state(st, 8); -} - -static void -l3s17(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL); - newl3state(st, 10); -} - -static void -l3s18(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *dibh; - byte *p; - int size; - - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); - p = DATAPTR(dibh); - p += st->l2.ihsize; - size = st->l2.ihsize; - - *p++ = 0x8; - *p++ = 0x1; - *p++ = st->l3.callref; - *p++ = MT_DISCONNECT; - size += 4; - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = 0x90; - size += 4; - - dibh->datasize = size; - i_down(st, dibh); - - newl3state(st, 11); -} - -static void -l3s19(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - newl3state(st, 0); - l3_message(st, MT_RELEASE_COMPLETE); - st->l3.l3l4(st, CC_RELEASE_IND, NULL); -} - -static void -l3s20(struct PStack *st, byte pr, - void *arg) -{ - l3_message(st, MT_ALERTING); - newl3state(st, 7); -} - -static void -l3s21(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *dibh=arg; - byte *p; - int size; - - BufPoolRelease(dibh); - - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); - p = DATAPTR(dibh); - p += st->l2.ihsize; - size = st->l2.ihsize; - - *p++ = 0x8; - *p++ = 0x1; - *p++ = st->l3.callref; - *p++ = MT_STATUS; - size += 4; - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = 0x9E; /* answer status enquire */ - size += 4; - - *p++ = 0x14; /* CallState */ - *p++ = 0x1; - *p++ = st->l3.state & 0x3f; /* ISO L3 CallState */ - size += 3; - - dibh->datasize = size; - i_down(st, dibh); - -} - -struct stateentry { - int state; - byte primitive; - void (*rout) (struct PStack *, byte, void *); -}; - -static struct stateentry downstatelist[] = -{ - {0,CC_SETUP_REQ,l3s5}, - {1,CC_DISCONNECT_REQ,l3s18}, - {1,CC_RELEASE_REQ,l3s3}, - {1,CC_DLRL,l3s13}, - {3,CC_DISCONNECT_REQ,l3s18}, - {3,CC_RELEASE_REQ,l3s3}, - {3,CC_DLRL,l3s13}, - {4,CC_RELEASE_REQ,l3s3}, - {4,CC_DISCONNECT_REQ,l3s18}, - {4,CC_DLRL,l3s13}, - {6,CC_RELEASE_REQ,l3s3}, - {6,CC_DISCONNECT_REQ,l3s18}, - {6,CC_ALERTING_REQ,l3s20}, - {6,CC_DLRL,l3s13}, - {7,CC_RELEASE_REQ,l3s3}, - {7,CC_SETUP_RSP,l3s16}, - {7,CC_DLRL,l3s13}, - {8,CC_RELEASE_REQ,l3s3}, - {8,CC_DISCONNECT_REQ,l3s18}, - {8,CC_DLRL,l3s13}, - {10,CC_DISCONNECT_REQ,l3s18}, - {10,CC_RELEASE_REQ,l3s3}, - {10,CC_DLRL,l3s13}, - {11,CC_RELEASE_REQ,l3s3}, - {12,CC_RELEASE_REQ,l3s3}, - {19,CC_DLRL,l3s13}, -}; - -static int downsllen = sizeof(downstatelist) / -sizeof(struct stateentry); - -static struct stateentry datastatelist[] = -{ - {0,MT_STATUS_ENQUIRY,l3s21}, - {0,MT_SETUP,l3s12}, - {1,MT_STATUS_ENQUIRY,l3s21}, - {1,MT_CALL_PROCEEDING,l3s6}, - {1,MT_SETUP_ACKNOWLEDGE,l3s6}, - {1,MT_RELEASE_COMPLETE,l3s4}, - {1,MT_RELEASE,l3s19}, - {1,MT_DISCONNECT,l3s7}, - {3,MT_STATUS_ENQUIRY,l3s21}, - {3,MT_DISCONNECT,l3s7}, - {3,MT_CONNECT,l3s8}, - {3,MT_ALERTING,l3s11}, - {3,MT_RELEASE,l3s19}, - {3,MT_RELEASE_COMPLETE,l3s4}, - {4,MT_STATUS_ENQUIRY,l3s21}, - {4,MT_CONNECT,l3s8}, - {4,MT_DISCONNECT,l3s7}, - {4,MT_RELEASE,l3s19}, - {4,MT_RELEASE_COMPLETE,l3s4}, - {8,MT_STATUS_ENQUIRY,l3s21}, - {6,MT_SETUP,l3s12}, - {8,MT_STATUS_ENQUIRY,l3s21}, - {7,MT_RELEASE,l3s19}, - {7,MT_RELEASE_COMPLETE,l3s4_1}, - {7,MT_DISCONNECT,l3s7}, - {8,MT_STATUS_ENQUIRY,l3s21}, - {8,MT_RELEASE,l3s19}, - {8,MT_CONNECT_ACKNOWLEDGE,l3s17}, - {8,MT_DISCONNECT,l3s7}, - {8,MT_RELEASE_COMPLETE,l3s4_1}, - {10,MT_STATUS_ENQUIRY,l3s21}, - {10,MT_DISCONNECT,l3s7}, - {10,MT_RELEASE,l3s19}, - {10,MT_RELEASE_COMPLETE,l3s4_1}, - {11,MT_STATUS_ENQUIRY,l3s21}, - {11,MT_RELEASE,l3s19}, - {11,MT_RELEASE_COMPLETE,l3s4}, - {19,MT_STATUS_ENQUIRY,l3s21}, - {19,MT_RELEASE_COMPLETE,l3s4}, -}; - -static int datasllen = sizeof(datastatelist) / -sizeof(struct stateentry); - -#ifdef P_1TR6 -#include "l3_1TR6.c" -#endif - -static void -l3up(struct PStack *st, - int pr, void *arg) -{ - int i, mt, size; - byte *ptr; - struct BufHeader *ibh = arg; - - if (pr == DL_DATA) { - ptr = DATAPTR(ibh); - ptr += st->l2.ihsize; - size = ibh->datasize - st->l2.ihsize; - mt = ptr[3]; - switch (ptr[0]) { -#ifdef P_1TR6 - case PROTO_DIS_N0: - BufPoolRelease(ibh); - break; - case PROTO_DIS_N1: - for (i = 0; i < datasl_1tr6t_len; i++) - if ((st->l3.state == datastatelist_1tr6t[i].state) && - (mt == datastatelist_1tr6t[i].primitive)) - break; - if (i == datasl_1tr6t_len) { - BufPoolRelease(ibh); - if (DEBUG_1TR6 > 0) - printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n", - st->l3.state, mt); - } else - datastatelist_1tr6t[i].rout(st, pr, ibh); - break; -#endif - case PROTO_EURO: /* E-DSS1 */ - for (i = 0; i < datasllen; i++) - if ((st->l3.state == datastatelist[i].state) && - (mt == datastatelist[i].primitive)) - break; - if (i == datasllen) { - BufPoolRelease(ibh); - if (DEBUG_1TR6 > 0) - printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n", - st->l3.state, mt); - } else - datastatelist[i].rout(st, pr, ibh); - break; - default: - BufPoolRelease(ibh); - break; - } - } else if (pr == DL_UNIT_DATA) { - ptr = DATAPTR(ibh); - ptr += st->l2.uihsize; - size = ibh->datasize - st->l2.uihsize; - mt = ptr[3]; - switch (ptr[0]) { -#ifdef P_1TR6 - case PROTO_DIS_N0: - BufPoolRelease(ibh); - break; - case PROTO_DIS_N1: - for (i = 0; i < datasl_1tr6t_len; i++) - if ((st->l3.state == datastatelist_1tr6t[i].state) && - (mt == datastatelist_1tr6t[i].primitive)) - break; - if (i == datasl_1tr6t_len) { - if (DEBUG_1TR6 > 0) { - printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n" - ,st->l3.state, mt); - } - BufPoolRelease(ibh); - } else - datastatelist_1tr6t[i].rout(st, pr, ibh); - break; -#endif - case PROTO_EURO: /* E-DSS1 */ - for (i = 0; i < datasllen; i++) - if ((st->l3.state == datastatelist[i].state) && - (mt == datastatelist[i].primitive)) - break; - if (i == datasllen) { - BufPoolRelease(ibh); - if (DEBUG_1TR6 > 0) - printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n", - st->l3.state, mt); - } else - datastatelist[i].rout(st, pr, ibh); - break; - default: - BufPoolRelease(ibh); - break; - } - } -} - -static void -l3down(struct PStack *st, - int pr, void *arg) -{ - int i; - struct BufHeader *ibh = arg; - - switch (st->protocol) { -#ifdef P_1TR6 - case ISDN_PTYPE_1TR6: - for (i = 0; i < downsl_1tr6t_len; i++) - if ((st->l3.state == downstatelist_1tr6t[i].state) && - (pr == downstatelist_1tr6t[i].primitive)) - break; - if (i == downsl_1tr6t_len) { - if (DEBUG_1TR6 > 0) { - printk(KERN_INFO "isdnl3down unhandled 1tr6 state %d primitive %x\n", st->l3.state, pr); - } - } else - downstatelist_1tr6t[i].rout(st, pr, ibh); - break; -#endif - default: - for (i = 0; i < downsllen; i++) - if ((st->l3.state == downstatelist[i].state) && - (pr == downstatelist[i].primitive)) - break; - if (i == downsllen) { - if (DEBUG_1TR6 > 0) { - printk(KERN_INFO "isdnl3down unhandled E-DSS1 state %d primitive %x\n", st->l3.state, pr); - } - } else - downstatelist[i].rout(st, pr, ibh); - } -} - -void -setstack_isdnl3(struct PStack *st) -{ - st->l4.l4l3 = l3down; - st->l2.l2l3 = l3up; - st->l3.state = 0; - st->l3.callref = 0; - st->l3.debug = 0; -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/l3_1TR6.c linux/drivers/isdn/teles/l3_1TR6.c --- v2.1.36/linux/drivers/isdn/teles/l3_1TR6.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/l3_1TR6.c Wed Dec 31 16:00:00 1969 @@ -1,538 +0,0 @@ -/* $Id: l3_1TR6.c,v 1.7 1997/02/11 01:38:55 keil Exp $ - * - * $Log: l3_1TR6.c,v $ - * Revision 1.7 1997/02/11 01:38:55 keil - * Changed setup-interface (incoming and outgoing) - * - * Revision 1.6 1996/09/25 18:34:57 keil - * missing states in 1TR6 Statemachine added - * - * Revision 1.5 1996/09/23 01:53:51 fritz - * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). - * - * Revision 1.4 1996/06/06 14:22:28 fritz - * Changed level of "non-digital call..." message, since - * with audio support, this is quite normal. - * - * Revision 1.3 1996/04/30 21:54:42 isdn4dev - * SPV, callback , remove some debugging code Karsten Keil - * - * Revision 1.2 1996/04/20 16:47:23 fritz - * Changed statemachine to allow reject of an incoming call. - * Report all incoming calls, not just those with Service = 7. - * Misc. typos - * - * Revision 1.1 1996/04/13 10:25:16 fritz - * Initial revision - * - * - */ - -#include "proto.h" - -static void -l3_1TR6_message(struct PStack *st, int mt, int pd) -{ - struct BufHeader *dibh; - byte *p; - - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18); - p = DATAPTR(dibh); - p += st->l2.ihsize; - - *p++ = pd; - *p++ = 0x1; - *p++ = st->l3.callref; - *p++ = mt; - - dibh->datasize = p - DATAPTR(dibh); - i_down(st, dibh); -} - -static void -l3_1tr6_setup(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *dibh; - byte *p; - char *teln; - - st->l3.callref = st->pa->callref; - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19); - p = DATAPTR(dibh); - p += st->l2.ihsize; - - *p++ = PROTO_DIS_N1; - *p++ = 0x1; - *p++ = st->l3.callref; - *p++ = MT_N1_SETUP; - - if ('S' == (st->pa->setup.phone[0] & 0x5f)) { /* SPV ??? */ - /* NSF SPV */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_SPV; /* SPV */ - *p++ = st->pa->setup.si1; /* 0 for all Services */ - *p++ = st->pa->setup.si2; /* 0 for all Services */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_Activate; /* aktiviere SPV (default) */ - *p++ = st->pa->setup.si1; /* 0 for all Services */ - *p++ = st->pa->setup.si2; /* 0 for all Services */ - } - if (st->pa->setup.eazmsn[0]) { - *p++ = WE0_origAddr; - *p++ = strlen(st->pa->setup.eazmsn) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - teln = st->pa->setup.eazmsn; - while (*teln) - *p++ = *teln++ & 0x7f; - } - *p++ = WE0_destAddr; - teln = st->pa->setup.phone; - if ('S' != (st->pa->setup.phone[0] & 0x5f)) { /* Keine SPV ??? */ - *p++ = strlen(st->pa->setup.phone) + 1; - st->pa->spv = 0; - } else { /* SPV */ - *p++ = strlen(st->pa->setup.phone); - teln++; /* skip S */ - st->pa->spv = 1; - } - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*teln) - *p++ = *teln++ & 0x7f; - - *p++ = WE_Shift_F6; - /* Codesatz 6 fuer Service */ - *p++ = WE6_serviceInd; - *p++ = 2; /* len=2 info,info2 */ - *p++ = st->pa->setup.si1; - *p++ = st->pa->setup.si2; - - dibh->datasize = p - DATAPTR(dibh); - - newl3state(st, 1); - i_down(st, dibh); - -} - -static void -l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg) -{ - byte *p; - struct BufHeader *ibh = arg; - - p = DATAPTR(ibh); - p += st->l2.uihsize; - st->pa->callref = getcallref(p); - st->l3.callref = 0x80 + st->pa->callref; - - /* Channel Identification */ - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, - WE0_chanID, 0))) { - st->pa->bchannel = p[2] & 0x3; - } else - printk(KERN_INFO "l3tu_setup: Channel ident not found\n"); - - p = DATAPTR(ibh); - - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) { - st->pa->setup.si1 = p[2]; - st->pa->setup.si2 = p[3]; - } else - printk(KERN_INFO "l3s12(1TR6): ServiceIndicator not found\n"); - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, - WE0_destAddr, 0))) - iecpy(st->pa->setup.eazmsn, p, 1); - else - strcpy(st->pa->setup.eazmsn, ""); - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, - WE0_origAddr, 0))) { - iecpy(st->pa->setup.phone, p, 1); - } else - strcpy(st->pa->setup.phone, ""); - - p = DATAPTR(ibh); - st->pa->spv = 0; - if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, - WE0_netSpecFac, 0))) { - if ((FAC_SPV == p[3]) || (FAC_Activate == p[3])) - st->pa->spv = 1; - } - BufPoolRelease(ibh); - - /* Signal all services, linklevel takes care of Service-Indicator */ - if (st->pa->setup.si1 != 7) { - printk(KERN_DEBUG "non-digital call: %s -> %s\n", - st->pa->setup.phone, - st->pa->setup.eazmsn); - } - newl3state(st, 6); - st->l3.l3l4(st, CC_SETUP_IND, NULL); -} - -static void -l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg) -{ - byte *p; - struct BufHeader *ibh = arg; - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE0_chanID, 0))) { - st->pa->bchannel = p[2] & 0x3; - } else - printk(KERN_INFO "octect 3 not found\n"); - - - BufPoolRelease(ibh); - newl3state(st, 2); -} - -static void -l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg) -{ - byte *p; - struct BufHeader *ibh = arg; - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE0_chanID, 0))) { - st->pa->bchannel = p[2] & 0x3; - } else - printk(KERN_INFO "octect 3 not found\n"); - - BufPoolRelease(ibh); - newl3state(st, 3); - st->l3.l3l4(st, CC_PROCEEDING_IND, NULL); -} - -static void -l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg) -{ - byte *p; - struct BufHeader *ibh = arg; - - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE6_statusCalled, 6))) { - if (DEBUG_1TR6 > 2) - printk(KERN_INFO "status called %x\n", p[2]); - } else if (DEBUG_1TR6 > 0) - printk(KERN_INFO "statusCalled not found\n"); - - BufPoolRelease(ibh); - newl3state(st, 4); - st->l3.l3l4(st, CC_ALERTING_IND, NULL); -} - -static void -l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg) -{ - byte *p; - int i,tmpcharge=0; - char a_charge[8]; - struct BufHeader *ibh = arg; - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE6_chargingInfo, 6))) { - iecpy(a_charge, p, 1); - for (i = 0; i < strlen (a_charge); i++) { - tmpcharge *= 10; - tmpcharge += a_charge[i] & 0xf; - } - if (tmpcharge > st->pa->chargeinfo) { - st->pa->chargeinfo = tmpcharge; - st->l3.l3l4 (st, CC_INFO_CHARGE, NULL); - } - if (DEBUG_1TR6 > 2) - printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo); - } else if (DEBUG_1TR6 > 2) - printk(KERN_INFO "chargingInfo not found\n"); - - BufPoolRelease(ibh); -} - -static void -l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg) -{ - byte *p; - int i; - struct BufHeader *ibh = arg; - - if (DEBUG_1TR6 > 4) { - p = DATAPTR(ibh); - for (i = 0; i < ibh->datasize; i++) { - printk(KERN_INFO "Info DATA %x\n", p[i]); - } - } - BufPoolRelease(ibh); -} - -static void -l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - st->pa->chargeinfo=0; - BufPoolRelease(ibh); - st->l3.l3l4(st, CC_SETUP_CNF, NULL); - newl3state(st, 10); -} - -static void -l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1); - st->l3.l3l4(st, CC_RELEASE_IND, NULL); - newl3state(st, 0); -} - -static void -l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - newl3state(st, 0); - st->l3.l3l4(st, CC_RELEASE_CNF, NULL); -} - -static void -l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - byte *p; - int i,tmpcharge=0; - char a_charge[8]; - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE6_chargingInfo, 6))) { - iecpy(a_charge, p, 1); - for (i = 0; i < strlen (a_charge); i++) { - tmpcharge *= 10; - tmpcharge += a_charge[i] & 0xf; - } - if (tmpcharge > st->pa->chargeinfo) { - st->pa->chargeinfo = tmpcharge; - st->l3.l3l4 (st, CC_INFO_CHARGE, NULL); - } - if (DEBUG_1TR6 > 2) - printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo); - } else if (DEBUG_1TR6 > 2) - printk(KERN_INFO "chargingInfo not found\n"); - - p = DATAPTR(ibh); - if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize, - WE0_cause, 0))) { - if (p[1] > 0) { - st->pa->cause = p[2]; - } else { - st->pa->cause = 0; - } - if (DEBUG_1TR6 > 1) - printk(KERN_INFO "Cause %x\n", st->pa->cause); - } else if (DEBUG_1TR6 > 0) - printk(KERN_INFO "Cause not found\n"); - - BufPoolRelease(ibh); - newl3state(st, 12); - st->l3.l3l4(st, CC_DISCONNECT_IND, NULL); -} - - -static void -l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *ibh = arg; - - BufPoolRelease(ibh); - st->pa->chargeinfo = 0; - st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL); - newl3state(st, 10); -} - -static void -l3_1tr6_alert(struct PStack *st, byte pr, - void *arg) -{ - l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1); - newl3state(st, 7); -} - -static void -l3_1tr6_conn(struct PStack *st, byte pr, - void *arg) -{ - struct BufHeader *dibh; - byte *p; - - st->l3.callref = 0x80 + st->pa->callref; - - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); - p = DATAPTR(dibh); - p += st->l2.ihsize; - - *p++ = PROTO_DIS_N1; - *p++ = 0x1; - *p++ = st->l3.callref; - *p++ = MT_N1_CONN; - - if (st->pa->spv) { /* SPV ??? */ - /* NSF SPV */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_SPV; /* SPV */ - *p++ = st->pa->setup.si1; - *p++ = st->pa->setup.si2; - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_Activate; /* aktiviere SPV */ - *p++ = st->pa->setup.si1; - *p++ = st->pa->setup.si2; - } - dibh->datasize = p - DATAPTR(dibh); - - i_down(st, dibh); - - newl3state(st, 8); -} - -static void -l3_1tr6_reset(struct PStack *st, byte pr, void *arg) -{ - newl3state(st, 0); -} - -static void -l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg) -{ - struct BufHeader *dibh; - byte *p; - byte rejflg; - - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21); - p = DATAPTR(dibh); - p += st->l2.ihsize; - - *p++ = PROTO_DIS_N1; - *p++ = 0x1; - *p++ = st->l3.callref; - *p++ = MT_N1_DISC; - - if (st->l3.state == 7) { - rejflg = 1; - *p++ = WE0_cause; /* Anruf abweisen */ - *p++ = 0x01; /* Laenge = 1 */ - *p++ = CAUSE_CallRejected; - } else { - rejflg = 0; - *p++ = WE0_cause; - *p++ = 0x0; /* Laenge = 0 normales Ausloesen */ - } - - dibh->datasize = p - DATAPTR(dibh); - - i_down(st, dibh); - - newl3state(st, 11); -} - -static void -l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg) -{ - l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1); - newl3state(st, 19); -} - -static struct stateentry downstatelist_1tr6t[] = -{ - {0, CC_SETUP_REQ, l3_1tr6_setup}, - {1, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {1, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {1, CC_DLRL, l3_1tr6_reset}, - {2, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {2, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {2, CC_DLRL, l3_1tr6_reset}, - {3, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {3, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {3, CC_DLRL, l3_1tr6_reset}, - {4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {4, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {4, CC_DLRL, l3_1tr6_reset}, - {6, CC_REJECT_REQ, l3_1tr6_reset}, - {6, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {6, CC_SETUP_RSP, l3_1tr6_conn}, - {6, CC_ALERTING_REQ, l3_1tr6_alert}, - {6, CC_DLRL, l3_1tr6_reset}, - {7, CC_SETUP_RSP, l3_1tr6_conn}, - {7, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {7, CC_DLRL, l3_1tr6_reset}, - {8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {8, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {8, CC_DLRL, l3_1tr6_reset}, - {10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, - {10, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {10, CC_DLRL, l3_1tr6_reset}, - {12, CC_RELEASE_REQ, l3_1tr6_rel_req}, - {12, CC_DLRL, l3_1tr6_reset}, - {19, CC_DLRL, l3_1tr6_reset}, -}; - -static int downsl_1tr6t_len = sizeof(downstatelist_1tr6t) / -sizeof(struct stateentry); - -static struct stateentry datastatelist_1tr6t[] = -{ - {0, MT_N1_SETUP, l3_1tr6_tu_setup}, - {0, MT_N1_REL, l3_1tr6_tu_rel}, - {1, MT_N1_SETUP_ACK, l3_1tr6_tu_setup_ack}, - {1, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent}, - {1, MT_N1_REL, l3_1tr6_tu_rel}, - {1, MT_N1_DISC, l3_1tr6_tu_disc}, - {2, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent}, - {2, MT_N1_ALERT, l3_1tr6_tu_alert}, - {2, MT_N1_CONN, l3_1tr6_tu_connect}, - {2, MT_N1_REL, l3_1tr6_tu_rel}, - {2, MT_N1_DISC, l3_1tr6_tu_disc}, - {2, MT_N1_INFO, l3_1tr6_tu_info_s2}, - {3, MT_N1_ALERT, l3_1tr6_tu_alert}, - {3, MT_N1_CONN, l3_1tr6_tu_connect}, - {3, MT_N1_REL, l3_1tr6_tu_rel}, - {3, MT_N1_DISC, l3_1tr6_tu_disc}, - {4, MT_N1_ALERT, l3_1tr6_tu_alert}, - {4, MT_N1_CONN, l3_1tr6_tu_connect}, - {4, MT_N1_REL, l3_1tr6_tu_rel}, - {4, MT_N1_DISC, l3_1tr6_tu_disc}, - {7, MT_N1_REL, l3_1tr6_tu_rel}, - {7, MT_N1_DISC, l3_1tr6_tu_disc}, - {8, MT_N1_REL, l3_1tr6_tu_rel}, - {8, MT_N1_DISC, l3_1tr6_tu_disc}, - {8, MT_N1_CONN_ACK, l3_1tr6_tu_connect_ack}, - {10, MT_N1_REL, l3_1tr6_tu_rel}, - {10, MT_N1_DISC, l3_1tr6_tu_disc}, - {10, MT_N1_INFO, l3_1tr6_tu_info}, - {11, MT_N1_REL, l3_1tr6_tu_rel}, - {12, MT_N1_REL, l3_1tr6_tu_rel}, - {19, MT_N1_REL_ACK, l3_1tr6_tu_rel_ack} -}; - -static int datasl_1tr6t_len = sizeof(datastatelist_1tr6t) / -sizeof(struct stateentry); diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/l3_1TR6.h linux/drivers/isdn/teles/l3_1TR6.h --- v2.1.36/linux/drivers/isdn/teles/l3_1TR6.h Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/l3_1TR6.h Wed Dec 31 16:00:00 1969 @@ -1,160 +0,0 @@ -/* $Id: l3_1TR6.h,v 1.4 1996/09/23 01:53:52 fritz Exp $ - * - * $Log: l3_1TR6.h,v $ - * Revision 1.4 1996/09/23 01:53:52 fritz - * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). - * - * Revision 1.3 1996/04/30 21:53:48 isdn4dev - * Bugs, SPV, Logging in q931.c Karsten Keil - * - * Revision 1.1 1996/04/13 10:25:42 fritz - * Initial revision - * - * - */ -#ifndef l3_1TR6 -#define l3_1TR6 - -/* - * MsgType N0 - */ -#define MT_N0_REG_IND 0x61 -#define MT_N0_CANC_IND 0x62 -#define MT_N0_FAC_STA 0x63 -#define MT_N0_STA_ACK 0x64 -#define MT_N0_STA_REJ 0x65 -#define MT_N0_FAC_INF 0x66 -#define MT_N0_INF_ACK 0x67 -#define MT_N0_INF_REJ 0x68 -#define MT_N0_CLOSE 0x75 -#define MT_N0_CLO_ACK 0x77 - - -/* - * MsgType N1 - */ - -#define MT_N1_ESC 0x00 -#define MT_N1_ALERT 0x01 -#define MT_N1_CALL_SENT 0x02 -#define MT_N1_CONN 0x07 -#define MT_N1_CONN_ACK 0x0F -#define MT_N1_SETUP 0x05 -#define MT_N1_SETUP_ACK 0x0D -#define MT_N1_RES 0x26 -#define MT_N1_RES_ACK 0x2E -#define MT_N1_RES_REJ 0x22 -#define MT_N1_SUSP 0x25 -#define MT_N1_SUSP_ACK 0x2D -#define MT_N1_SUSP_REJ 0x21 -#define MT_N1_USER_INFO 0x20 -#define MT_N1_DET 0x40 -#define MT_N1_DISC 0x45 -#define MT_N1_REL 0x4D -#define MT_N1_REL_ACK 0x5A -#define MT_N1_CANC_ACK 0x6E -#define MT_N1_CANC_REJ 0x67 -#define MT_N1_CON_CON 0x69 -#define MT_N1_FAC 0x60 -#define MT_N1_FAC_ACK 0x68 -#define MT_N1_FAC_CAN 0x66 -#define MT_N1_FAC_REG 0x64 -#define MT_N1_FAC_REJ 0x65 -#define MT_N1_INFO 0x6D -#define MT_N1_REG_ACK 0x6C -#define MT_N1_REG_REJ 0x6F -#define MT_N1_STAT 0x63 - - - -/* - * W Elemente - */ - -#define WE_Shift_F0 0x90 -#define WE_Shift_F6 0x96 -#define WE_Shift_OF0 0x98 -#define WE_Shift_OF6 0x9E - -#define WE0_cause 0x08 -#define WE0_connAddr 0x0C -#define WE0_callID 0x10 -#define WE0_chanID 0x18 -#define WE0_netSpecFac 0x20 -#define WE0_display 0x28 -#define WE0_keypad 0x2C -#define WE0_origAddr 0x6C -#define WE0_destAddr 0x70 -#define WE0_userInfo 0x7E - -#define WE0_moreData 0xA0 -#define WE0_congestLevel 0xB0 - -#define WE6_serviceInd 0x01 -#define WE6_chargingInfo 0x02 -#define WE6_date 0x03 -#define WE6_facSelect 0x05 -#define WE6_facStatus 0x06 -#define WE6_statusCalled 0x07 -#define WE6_addTransAttr 0x08 - -/* - * FacCodes - */ -#define FAC_Sperre 0x01 -#define FAC_Sperre_All 0x02 -#define FAC_Sperre_Fern 0x03 -#define FAC_Sperre_Intl 0x04 -#define FAC_Sperre_Interk 0x05 - -#define FAC_Forward1 0x02 -#define FAC_Forward2 0x03 -#define FAC_Konferenz 0x06 -#define FAC_GrabBchan 0x0F -#define FAC_Reactivate 0x10 -#define FAC_Konferenz3 0x11 -#define FAC_Dienstwechsel1 0x12 -#define FAC_Dienstwechsel2 0x13 -#define FAC_NummernIdent 0x14 -#define FAC_GBG 0x15 -#define FAC_DisplayUebergeben 0x17 -#define FAC_DisplayUmgeleitet 0x1A -#define FAC_Unterdruecke 0x1B -#define FAC_Deactivate 0x1E -#define FAC_Activate 0x1D -#define FAC_SPV 0x1F -#define FAC_Rueckwechsel 0x23 -#define FAC_Umleitung 0x24 - -/* - * Cause codes - */ -#define CAUSE_InvCRef 0x01 -#define CAUSE_BearerNotImpl 0x03 -#define CAUSE_CIDunknown 0x07 -#define CAUSE_CIDinUse 0x08 -#define CAUSE_NoChans 0x0A -#define CAUSE_FacNotImpl 0x10 -#define CAUSE_FacNotSubscr 0x11 -#define CAUSE_OutgoingBarred 0x20 -#define CAUSE_UserAccessBusy 0x21 -#define CAUSE_NegativeGBG 0x22 -#define CAUSE_UnknownGBG 0x23 -#define CAUSE_NoSPVknown 0x25 -#define CAUSE_DestNotObtain 0x35 -#define CAUSE_NumberChanged 0x38 -#define CAUSE_OutOfOrder 0x39 -#define CAUSE_NoUserResponse 0x3A -#define CAUSE_UserBusy 0x3B -#define CAUSE_IncomingBarred 0x3D -#define CAUSE_CallRejected 0x3E -#define CAUSE_NetworkCongestion 0x59 -#define CAUSE_RemoteUser 0x5A -#define CAUSE_LocalProcErr 0x70 -#define CAUSE_RemoteProcErr 0x71 -#define CAUSE_RemoteUserSuspend 0x72 -#define CAUSE_RemoteUserResumed 0x73 -#define CAUSE_UserInfoDiscarded 0x7F - - -#endif diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/llglue.c linux/drivers/isdn/teles/llglue.c --- v2.1.36/linux/drivers/isdn/teles/llglue.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/llglue.c Wed Dec 31 16:00:00 1969 @@ -1,151 +0,0 @@ -/* $Id: llglue.c,v 1.7 1996/10/22 23:14:17 fritz Exp $ - * - * $Log: llglue.c,v $ - * Revision 1.7 1996/10/22 23:14:17 fritz - * Changes for compatibility to 2.0.X and 2.1.X kernels. - * - * Revision 1.6 1996/06/03 20:03:39 fritz - * Fixed typos. - * - * Revision 1.5 1996/05/31 00:58:47 fritz - * Errata: Reverted change from rev 1.4. - * - * Revision 1.4 1996/05/26 14:59:57 fritz - * Bugfix: maxbufsize had been set without respect to possible X.75 header. - * - * Revision 1.3 1996/05/01 14:19:57 fritz - * Added ISDN_FEATURE_L2_TRANS - * - * Revision 1.2 1996/04/29 23:01:46 fritz - * Added driverId and channel to readstatus(). - * - * Revision 1.1 1996/04/13 10:26:29 fritz - * Initial revision - * - * - */ -#define __NO_VERSION__ -#include "teles.h" -#include -#include - - -extern struct Channel *chanlist; -int drid; -char *teles_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - -isdn_if iif; - -#define TELES_STATUS_BUFSIZE 4096 -static byte *teles_status_buf = NULL; -static byte *teles_status_read = NULL; -static byte *teles_status_write = NULL; -static byte *teles_status_end = NULL; - -int -teles_readstatus(byte * buf, int len, int user, int id, int channel) -{ - int count; - byte *p; - - for (p = buf, count = 0; count < len; p++, count++) { - if (user) - put_user(*teles_status_read++, p); - else - *p++ = *teles_status_read++; - if (teles_status_read > teles_status_end) - teles_status_read = teles_status_buf; - } - return count; -} - -void -teles_putstatus(char *buf) -{ - long flags; - int len, count, i; - byte *p; - isdn_ctrl ic; - - save_flags(flags); - cli(); - count = 0; - len = strlen(buf); - for (p = buf, i = len; i > 0; i--, p++) { - *teles_status_write++ = *p; - if (teles_status_write > teles_status_end) - teles_status_write = teles_status_buf; - count++; - } - restore_flags(flags); - if (count) { - ic.command = ISDN_STAT_STAVAIL; - ic.driver = drid; - ic.arg = count; - iif.statcallb(&ic); - } -} - - -int -ll_init(void) -{ - isdn_ctrl ic; - - teles_status_buf = Smalloc(TELES_STATUS_BUFSIZE, - GFP_KERNEL, "teles_status_buf"); - if (!teles_status_buf) { - printk(KERN_ERR "teles: Could not allocate status-buffer\n"); - return (-EIO); - } else { - teles_status_read = teles_status_buf; - teles_status_write = teles_status_buf; - teles_status_end = teles_status_buf + TELES_STATUS_BUFSIZE - 1; - } - - iif.channels = CallcNewChan(); - iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS); - iif.features = - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_1TR6 | - ISDN_FEATURE_P_EURO; - - iif.command = teles_command; - iif.writebuf = teles_writebuf; - iif.writecmd = NULL; - iif.readstat = teles_readstatus; - strncpy(iif.id, teles_id, sizeof(iif.id) - 1); - - register_isdn(&iif); - drid = iif.channels; - - ic.driver = drid; - ic.command = ISDN_STAT_RUN; - iif.statcallb(&ic); - return 0; -} - -void -ll_stop(void) -{ - isdn_ctrl ic; - - ic.command = ISDN_STAT_STOP; - ic.driver = drid; - iif.statcallb(&ic); - - CallcFreeChan(); -} - -void -ll_unload(void) -{ - isdn_ctrl ic; - - ic.command = ISDN_STAT_UNLOAD; - ic.driver = drid; - iif.statcallb(&ic); -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/mod.c linux/drivers/isdn/teles/mod.c --- v2.1.36/linux/drivers/isdn/teles/mod.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/mod.c Wed Dec 31 16:00:00 1969 @@ -1,160 +0,0 @@ -/* $Id: mod.c,v 1.3 1997/02/14 12:23:31 fritz Exp $ - * - * $Log: mod.c,v $ - * Revision 1.3 1997/02/14 12:23:31 fritz - * Added support for new insmod parameter handling. - * - * Revision 1.2 1997/02/10 11:45:14 fritz - * More changes for Kernel 2.1.X compatibility. - * - * Revision 1.1 1996/04/13 10:27:02 fritz - * Initial revision - * - * - */ -#include "teles.h" - -extern struct IsdnCard cards[]; -extern char *teles_id; - -int nrcards; - -typedef struct { - byte *membase; - int interrupt; - unsigned int iobase; - unsigned int protocol; -} io_type; - -io_type io[] = -{ - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, - {0, 0, 0, 0}, -}; - -#ifdef MODULE -#if (LINUX_VERSION_CODE > 0x020111) -MODULE_PARM(io, "1-64i"); -MODULE_PARM(teles_id, "s"); -#endif -#endif - -void -teles_mod_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - -void -teles_mod_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - -#ifdef MODULE -#define teles_init init_module -#else -void teles_setup(char *str, int *ints) -{ - int i, j, argc; - static char sid[20]; - - argc = ints[0]; - i = 0; - j = 1; - while (argc && (i<16)) { - if (argc) { - io[i].iobase = ints[j]; - j++; argc--; - } - if (argc) { - io[i].interrupt = ints[j]; - j++; argc--; - } - if (argc) { - io[i].membase = (byte *)ints[j]; - j++; argc--; - } - if (argc) { - io[i].protocol = ints[j]; - j++; argc--; - } - i++; - } - if (strlen(str)) { - strcpy(sid,str); - teles_id = sid; - } -} -#endif - -int -teles_init(void) -{ - int i; - - nrcards = 0; - for (i = 0; i < 16; i++) { - if (io[i].protocol) { - cards[i].membase = io[i].membase; - cards[i].interrupt = io[i].interrupt; - cards[i].iobase = io[i].iobase; - cards[i].protocol = io[i].protocol; - } - } - for (i = 0; i < 16; i++) - if (cards[i].protocol) - nrcards++; - printk(KERN_DEBUG "teles: Total %d card%s defined\n", - nrcards, (nrcards > 1) ? "s" : ""); - if (teles_inithardware()) { - /* Install only, if at least one card found */ - Isdnl2New(); - TeiNew(); - CallcNew(); - ll_init(); - - /* No symbols to export, hide all symbols */ - -#ifdef MODULE -#if (LINUX_VERSION_CODE < 0x020111) - register_symtab(NULL); -#else - EXPORT_NO_SYMBOLS; -#endif - printk(KERN_NOTICE "Teles module installed\n"); -#endif - return (0); - } else - return -EIO; -} - -#ifdef MODULE -void -cleanup_module(void) -{ - - ll_stop(); - TeiFree(); - Isdnl2Free(); - CallcFree(); - teles_closehardware(); - ll_unload(); - printk(KERN_NOTICE "Teles module removed\n"); - -} -#endif diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/proto.h linux/drivers/isdn/teles/proto.h --- v2.1.36/linux/drivers/isdn/teles/proto.h Fri Nov 15 02:51:02 1996 +++ linux/drivers/isdn/teles/proto.h Wed Dec 31 16:00:00 1969 @@ -1,18 +0,0 @@ -/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $ - * - * not much now - just the l3 proto discriminator - * - * $Log: proto.h,v $ - * Revision 1.1 1996/09/23 01:53:52 fritz - * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). - * - */ - -#ifndef PROTO_H -#define PROTO_H - -#define PROTO_EURO 0x08 -#define PROTO_DIS_N0 0x40 -#define PROTO_DIS_N1 0x41 - -#endif diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/q931.c linux/drivers/isdn/teles/q931.c --- v2.1.36/linux/drivers/isdn/teles/q931.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/q931.c Wed Dec 31 16:00:00 1969 @@ -1,1155 +0,0 @@ -/* $Id: q931.c,v 1.6 1996/09/23 01:53:53 fritz Exp $ - * - * q931.c code to decode ITU Q.931 call control messages - * - * Author Jan den Ouden - * - * Changelog - * - * Pauline Middelink general improvements - * - * Beat Doebeli cause texts, display information element - * - * Karsten Keil cause texts, display information element for 1TR6 - * - * - * $Log: q931.c,v $ - * Revision 1.6 1996/09/23 01:53:53 fritz - * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6). - * - * Revision 1.5 1996/06/03 20:03:40 fritz - * Fixed typos. - * - * Revision 1.4 1996/05/17 03:46:17 fritz - * General cleanup. - * - * Revision 1.3 1996/04/30 22:06:50 isdn4dev - * logging 1TR6 messages correctly Karsten Keil - * - * Revision 1.2 1996/04/20 16:48:19 fritz - * Misc. typos - * - * Revision 1.1 1996/04/13 10:27:49 fritz - * Initial revision - * - * - */ - - -#define __NO_VERSION__ -#include "teles.h" -#include "proto.h" -#include "l3_1TR6.h" - -byte * -findie(byte * p, int size, byte ie, int wanted_set) -{ - int l, codeset, maincodeset; - byte *pend = p + size; - - /* skip protocol discriminator, callref and message type */ - p++; - l = (*p++) & 0xf; - p += l; - p++; - codeset = 0; - maincodeset = 0; - /* while there are bytes left... */ - while (p < pend) { - if ((*p & 0xf0) == 0x90) { - codeset = *p & 0x07; - if (!(*p & 0x08)) - maincodeset = codeset; - } - if (*p & 0x80) - p++; - else { - if (codeset == wanted_set) { - if (*p == ie) - return (p); - if (*p > ie) - return (NULL); - } - p++; - l = *p++; - p += l; - codeset = maincodeset; - } - } - return (NULL); -} - -void -iecpy(byte * dest, byte * iestart, int ieoffset) -{ - byte *p; - int l; - - p = iestart + ieoffset + 2; - l = iestart[1] - ieoffset; - while (l--) - *dest++ = *p++; - *dest++ = '\0'; -} - -int -getcallref(byte * p) -{ - p++; /* prot discr */ - p++; /* callref length */ - return (*p); /* assuming one-byte callref */ -} - -/* - * According to Table 4-2/Q.931 - */ -static -struct MessageType { - byte nr; - char *descr; -} mtlist[] = { - - { - 0x1, "ALERTING" - }, - { - 0x2, "CALL PROCEEDING" - }, - { - 0x7, "CONNECT" - }, - { - 0xf, "CONNECT ACKNOWLEDGE" - }, - { - 0x3, "PROGRESS" - }, - { - 0x5, "SETUP" - }, - { - 0xd, "SETUP ACKNOWLEDGE" - }, - { - 0x26, "RESUME" - }, - { - 0x2e, "RESUME ACKNOWLEDGE" - }, - { - 0x22, "RESUME REJECT" - }, - { - 0x25, "SUSPEND" - }, - { - 0x2d, "SUSPEND ACKNOWLEDGE" - }, - { - 0x21, "SUSPEND REJECT" - }, - { - 0x20, "USER INFORMATION" - }, - { - 0x45, "DISCONNECT" - }, - { - 0x4d, "RELEASE" - }, - { - 0x5a, "RELEASE COMPLETE" - }, - { - 0x46, "RESTART" - }, - { - 0x4e, "RESTART ACKNOWLEDGE" - }, - { - 0x60, "SEGMENT" - }, - { - 0x79, "CONGESTION CONTROL" - }, - { - 0x7b, "INFORMATION" - }, - { - 0x62, "FACILITY" - }, - { - 0x6e, "NOTIFY" - }, - { - 0x7d, "STATUS" - }, - { - 0x75, "STATUS ENQUIRY" - } -}; - -#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType) - -static -struct MessageType mt_n0[] = -{ - {MT_N0_REG_IND, "REGister INDication"}, - {MT_N0_CANC_IND, "CANCel INDication"}, - {MT_N0_FAC_STA, "FACility STAtus"}, - {MT_N0_STA_ACK, "STAtus ACKnowledge"}, - {MT_N0_STA_REJ, "STAtus REJect"}, - {MT_N0_FAC_INF, "FACility INFormation"}, - {MT_N0_INF_ACK, "INFormation ACKnowledge"}, - {MT_N0_INF_REJ, "INFormation REJect"}, - {MT_N0_CLOSE, "CLOSE"}, - {MT_N0_CLO_ACK, "CLOse ACKnowledge"} -}; - -int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType)); - -static -struct MessageType mt_n1[] = -{ - {MT_N1_ESC, "ESCape"}, - {MT_N1_ALERT, "ALERT"}, - {MT_N1_CALL_SENT, "CALL SENT"}, - {MT_N1_CONN, "CONNect"}, - {MT_N1_CONN_ACK, "CONNect ACKnowledge"}, - {MT_N1_SETUP, "SETUP"}, - {MT_N1_SETUP_ACK, "SETUP ACKnowledge"}, - {MT_N1_RES, "RESume"}, - {MT_N1_RES_ACK, "RESume ACKnowledge"}, - {MT_N1_RES_REJ, "RESume REJect"}, - {MT_N1_SUSP, "SUSPend"}, - {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"}, - {MT_N1_SUSP_REJ, "SUSPend REJect"}, - {MT_N1_USER_INFO, "USER INFO"}, - {MT_N1_DET, "DETach"}, - {MT_N1_DISC, "DISConnect"}, - {MT_N1_REL, "RELease"}, - {MT_N1_REL_ACK, "RELease ACKnowledge"}, - {MT_N1_CANC_ACK, "CANCel ACKnowledge"}, - {MT_N1_CANC_REJ, "CANCel REJect"}, - {MT_N1_CON_CON, "CONgestion CONtrol"}, - {MT_N1_FAC, "FACility"}, - {MT_N1_FAC_ACK, "FACility ACKnowledge"}, - {MT_N1_FAC_CAN, "FACility CANcel"}, - {MT_N1_FAC_REG, "FACility REGister"}, - {MT_N1_FAC_REJ, "FACility REJect"}, - {MT_N1_INFO, "INFOrmation"}, - {MT_N1_REG_ACK, "REGister ACKnowledge"}, - {MT_N1_REG_REJ, "REGister REJect"}, - {MT_N1_STAT, "STATus"} -}; - -int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType)); - -static struct MessageType fac_1tr6[] = -{ - {FAC_Sperre, "Sperre"}, - {FAC_Forward1, "Forward 1"}, - {FAC_Forward2, "Forward 2"}, - {FAC_Konferenz, "Konferenz"}, - {FAC_GrabBchan, "Grab Bchannel"}, - {FAC_Reactivate, "Reactivate"}, - {FAC_Konferenz3, "Dreier Konferenz"}, - {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"}, - {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"}, - {FAC_NummernIdent, "Rufnummer-Identifizierung"}, - {FAC_GBG, "GBG"}, - {FAC_DisplayUebergeben, "Display Uebergeben"}, - {FAC_DisplayUmgeleitet, "Display Umgeleitet"}, - {FAC_Unterdruecke, "Unterdruecke Rufnummer"}, - {FAC_Deactivate, "Deactivate"}, - {FAC_Activate, "Activate"}, - {FAC_SPV, "SPV"}, - {FAC_Rueckwechsel, "Rueckwechsel"}, - {FAC_Umleitung, "Umleitung"} -}; -int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType)); - - - -static int -prbits(char *dest, byte b, int start, int len) -{ - char *dp = dest; - - b = b << (8 - start); - while (len--) { - if (b & 0x80) - *dp++ = '1'; - else - *dp++ = '0'; - b = b << 1; - } - return (dp - dest); -} - -static -byte * -skipext(byte * p) -{ - while (!(*p++ & 0x80)); - return (p); -} - -/* - * Cause Values According to Q.850 - * edescr: English description - * ddescr: German description used by Swissnet II (Swiss Telecom - * not yet written... - */ - -static -struct CauseValue { - byte nr; - char *edescr; - char *ddescr; -} cvlist[] = { - - { - 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt" - }, - { - 0x02, "No route to specified transit network", "" - }, - { - 0x03, "No route to destination", "" - }, - { - 0x04, "Send special information tone", "" - }, - { - 0x05, "Misdialled trunk prefix", "" - }, - { - 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar" - }, - { - 0x07, "Channel awarded and being delivered in an established channel", "" - }, - { - 0x08, "Preemption", "" - }, - { - 0x09, "Preemption - circuit reserved for reuse", "" - }, - { - 0x10, "Normal call clearing", "Normale Ausloesung" - }, - { - 0x11, "User busy", "TNB besetzt" - }, - { - 0x12, "No user responding", "" - }, - { - 0x13, "No answer from user (user alerted)", "" - }, - { - 0x14, "Subscriber absent", "" - }, - { - 0x15, "Call rejected", "" - }, - { - 0x16, "Number changed", "" - }, - { - 0x1a, "non-selected user clearing", "" - }, - { - 0x1b, "Destination out of order", "" - }, - { - 0x1c, "Invalid number format (address incomplete)", "" - }, - { - 0x1d, "Facility rejected", "" - }, - { - 0x1e, "Response to Status enquiry", "" - }, - { - 0x1f, "Normal, unspecified", "" - }, - { - 0x22, "No circuit/channel available", "" - }, - { - 0x26, "Network out of order", "" - }, - { - 0x27, "Permanent frame mode connection out-of-service", "" - }, - { - 0x28, "Permanent frame mode connection operational", "" - }, - { - 0x29, "Temporary failure", "" - }, - { - 0x2a, "Switching equipment congestion", "" - }, - { - 0x2b, "Access information discarded", "" - }, - { - 0x2c, "Requested circuit/channel not available", "" - }, - { - 0x2e, "Precedence call blocked", "" - }, - { - 0x2f, "Resource unavailable, unspecified", "" - }, - { - 0x31, "Quality of service unavailable", "" - }, - { - 0x32, "Requested facility not subscribed", "" - }, - { - 0x35, "Outgoing calls barred within CUG", "" - }, - { - 0x37, "Incoming calls barred within CUG", "" - }, - { - 0x39, "Bearer capability not authorized", "" - }, - { - 0x3a, "Bearer capability not presently available", "" - }, - { - 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " " - }, - { - 0x3f, "Service or option not available, unspecified", "" - }, - { - 0x41, "Bearer capability not implemented", "" - }, - { - 0x42, "Channel type not implemented", "" - }, - { - 0x43, "Requested facility not implemented", "" - }, - { - 0x44, "Only restricted digital information bearer capability is available", "" - }, - { - 0x4f, "Service or option not implemented", "" - }, - { - 0x51, "Invalid call reference value", "" - }, - { - 0x52, "Identified channel does not exist", "" - }, - { - 0x53, "A suspended call exists, but this call identity does not", "" - }, - { - 0x54, "Call identity in use", "" - }, - { - 0x55, "No call suspended", "" - }, - { - 0x56, "Call having the requested call identity has been cleared", "" - }, - { - 0x57, "User not member of CUG", "" - }, - { - 0x58, "Incompatible destination", "" - }, - { - 0x5a, "Non-existent CUG", "" - }, - { - 0x5b, "Invalid transit network selection", "" - }, - { - 0x5f, "Invalid message, unspecified", "" - }, - { - 0x60, "Mandatory information element is missing", "" - }, - { - 0x61, "Message type non-existent or not implemented", "" - }, - { - 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " " - }, - { - 0x63, "Information element/parameter non-existent or not implemented", "" - }, - { - 0x64, "Invalid information element contents", "" - }, - { - 0x65, "Message not compatible with call state", "" - }, - { - 0x66, "Recovery on timer expiry", "" - }, - { - 0x67, "Parameter non-existent or not implemented - passed on", "" - }, - { - 0x6e, "Message with unrecognized parameter discarded", "" - }, - { - 0x6f, "Protocol error, unspecified", "" - }, - { - 0x7f, "Interworking, unspecified", "" - }, -}; - -#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue) - -static -int -prcause(char *dest, byte * p) -{ - byte *end; - char *dp = dest; - int i, cause; - - end = p + p[1] + 1; - p += 2; - dp += sprintf(dp, " coding "); - dp += prbits(dp, *p, 7, 2); - dp += sprintf(dp, " location "); - dp += prbits(dp, *p, 4, 4); - *dp++ = '\n'; - p = skipext(p); - - cause = 0x7f & *p++; - - /* locate cause value */ - for (i = 0; i < CVSIZE; i++) - if (cvlist[i].nr == cause) - break; - - /* display cause value if it exists */ - if (i == CVSIZE) - dp += sprintf(dp, "Unknown cause type %x!\n", cause); - else - dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr); - - while (!0) { - if (p > end) - break; - dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f); - dp += sprintf(dp, " rej %d ", *p & 0x7f); - if (*p & 0x80) { - *dp++ = '\n'; - break; - } else - dp += sprintf(dp, " av %d\n", (*++p) & 0x7f); - } - return (dp - dest); - -} - -static -struct MessageType cause_1tr6[] = -{ - {CAUSE_InvCRef, "Invalid Call Reference"}, - {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"}, - {CAUSE_CIDunknown, "Caller Identity unknown"}, - {CAUSE_CIDinUse, "Caller Identity in Use"}, - {CAUSE_NoChans, "No Channels available"}, - {CAUSE_FacNotImpl, "Facility Not Implemented"}, - {CAUSE_FacNotSubscr, "Facility Not Subscribed"}, - {CAUSE_OutgoingBarred, "Outgoing calls barred"}, - {CAUSE_UserAccessBusy, "User Access Busy"}, - {CAUSE_NegativeGBG, "Negative GBG"}, - {CAUSE_UnknownGBG, "Unknown GBG"}, - {CAUSE_NoSPVknown, "No SPV known"}, - {CAUSE_DestNotObtain, "Destination not obtainable"}, - {CAUSE_NumberChanged, "Number changed"}, - {CAUSE_OutOfOrder, "Out Of Order"}, - {CAUSE_NoUserResponse, "No User Response"}, - {CAUSE_UserBusy, "User Busy"}, - {CAUSE_IncomingBarred, "Incoming Barred"}, - {CAUSE_CallRejected, "Call Rejected"}, - {CAUSE_NetworkCongestion, "Network Congestion"}, - {CAUSE_RemoteUser, "Remote User initiated"}, - {CAUSE_LocalProcErr, "Local Procedure Error"}, - {CAUSE_RemoteProcErr, "Remote Procedure Error"}, - {CAUSE_RemoteUserSuspend, "Remote User Suspend"}, - {CAUSE_RemoteUserResumed, "Remote User Resumed"}, - {CAUSE_UserInfoDiscarded, "User Info Discarded"} -}; - -int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); - -static int -prcause_1tr6(char *dest, byte * p) -{ - char *dp = dest; - int i, cause; - - p++; - if (0 == *p) { - dp += sprintf(dp, " OK (cause length=0)\n"); - return (dp - dest); - } else if (*p > 1) { - dp += sprintf(dp, " coding "); - dp += prbits(dp, p[2], 7, 2); - dp += sprintf(dp, " location "); - dp += prbits(dp, p[2], 4, 4); - *dp++ = '\n'; - } - p++; - cause = 0x7f & *p; - - /* locate cause value */ - for (i = 0; i < cause_1tr6_len; i++) - if (cause_1tr6[i].nr == cause) - break; - - /* display cause value if it exists */ - if (i == cause_1tr6_len) - dp += sprintf(dp, "Unknown cause type %x!\n", cause); - else - dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr); - - return (dp - dest); - -} - -static int -prchident(char *dest, byte * p) { - char *dp = dest; - - p += 2; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - return (dp - dest); -} - -static int -prcalled(char *dest, byte * p) { - int l; - char *dp = dest; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - dp += sprintf(dp, " number digits "); - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} -static int -prcalling(char *dest, byte * p) { - int l; - char *dp = dest; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if (!(*p & 0x80)) { - dp += sprintf(dp, " octet 3a "); - dp += prbits(dp, *++p, 8, 8); - *dp++ = '\n'; - l--; - }; - p++; - - dp += sprintf(dp, " number digits "); - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} - -static -int -prbearer(char *dest, byte * p) -{ - char *dp = dest, ch; - - p += 2; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if ((*p++ & 0x1f) == 0x18) { - dp += sprintf(dp, " octet 4.1 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - /* check for user information layer 1 */ - if ((*p & 0x60) == 0x20) { - ch = ' '; - do { - dp += sprintf(dp, " octet 5%c ", ch); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if (ch == ' ') - ch = 'a'; - else - ch++; - } - while (!(*p++ & 0x80)); - } - /* check for user information layer 2 */ - if ((*p & 0x60) == 0x40) { - dp += sprintf(dp, " octet 6 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - /* check for user information layer 3 */ - if ((*p & 0x60) == 0x60) { - dp += sprintf(dp, " octet 7 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - return (dp - dest); -} - -static int -general(char *dest, byte * p) { - char *dp = dest; - char ch = ' '; - int l, octet = 3; - - p++; - l = *p++; - /* Iterate over all octets in the information element */ - while (l--) { - dp += sprintf(dp, " octet %d%c ", octet, ch); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - - /* last octet in group? */ - if (*p & 0x80) { - octet++; - ch = ' '; - } else if (ch == ' ') - ch = 'a'; - else - ch++; - } - return (dp - dest); -} - -static int -prcharge(char *dest, byte * p) { - char *dp = dest; - int l; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " GEA "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, " Anzahl: "); - /* Iterate over all octets in the * information element */ - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} -static int -prtext(char *dest, byte * p) { - char *dp = dest; - int l; - - p++; - l = *p++; - dp += sprintf(dp, " "); - /* Iterate over all octets in the * information element */ - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} -static int -display(char *dest, byte * p) { - char *dp = dest; - char ch = ' '; - int l, octet = 3; - - p++; - l = *p++; - /* Iterate over all octets in the * display-information element */ - dp += sprintf(dp, " \""); - while (l--) { - dp += sprintf(dp, "%c", *p++); - - /* last octet in group? */ - if (*p & 0x80) { - octet++; - ch = ' '; - } else if (ch == ' ') - ch = 'a'; - - else - ch++; - } - *dp++ = '\"'; - *dp++ = '\n'; - return (dp - dest); -} - -int -prfacility(char *dest, byte * p) -{ - char *dp = dest; - int l, l2; - - p++; - l = *p++; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, "\n"); - l -= 1; - - while (l > 0) { - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, "\n"); - dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f); - l -= 2; - dp += sprintf(dp, " contents "); - while (l2--) { - dp += sprintf(dp, "%2x ", *p++); - l--; - } - dp += sprintf(dp, "\n"); - } - - return (dp - dest); -} - -static -struct InformationElement { - byte nr; - char *descr; - int (*f) (char *, byte *); -} ielist[] = { - - { - 0x00, "Segmented message", general - }, - { - 0x04, "Bearer capability", prbearer - }, - { - 0x08, "Cause", prcause - }, - { - 0x10, "Call identity", general - }, - { - 0x14, "Call state", general - }, - { - 0x18, "Channel identification", prchident - }, - { - 0x1c, "Facility", prfacility - }, - { - 0x1e, "Progress indicator", general - }, - { - 0x20, "Network-specific facilities", general - }, - { - 0x27, "Notification indicator", general - }, - { - 0x28, "Display", display - }, - { - 0x29, "Date/Time", general - }, - { - 0x2c, "Keypad facility", general - }, - { - 0x34, "Signal", general - }, - { - 0x40, "Information rate", general - }, - { - 0x42, "End-to-end delay", general - }, - { - 0x43, "Transit delay selection and indication", general - }, - { - 0x44, "Packet layer binary parameters", general - }, - { - 0x45, "Packet layer window size", general - }, - { - 0x46, "Packet size", general - }, - { - 0x47, "Closed user group", general - }, - { - 0x4a, "Reverse charge indication", general - }, - { - 0x6c, "Calling party number", prcalling - }, - { - 0x6d, "Calling party subaddress", general - }, - { - 0x70, "Called party number", prcalled - }, - { - 0x71, "Called party subaddress", general - }, - { - 0x74, "Redirecting number", general - }, - { - 0x78, "Transit network selection", general - }, - { - 0x79, "Restart indicator", general - }, - { - 0x7c, "Low layer compatibility", general - }, - { - 0x7d, "High layer compatibility", general - }, - { - 0x7e, "User-user", general - }, - { - 0x7f, "Escape for extension", general - }, -}; - - -#define IESIZE sizeof(ielist)/sizeof(struct InformationElement) - -static struct InformationElement we_0[] = -{ - {WE0_cause, "Cause", prcause_1tr6}, - {WE0_connAddr, "Connecting Address", prcalled}, - {WE0_callID, "Call IDentity", general}, - {WE0_chanID, "Channel IDentity", general}, - {WE0_netSpecFac, "Network Specific Facility", general}, - {WE0_display, "Display", general}, - {WE0_keypad, "Keypad", general}, - {WE0_origAddr, "Origination Address", prcalled}, - {WE0_destAddr, "Destination Address", prcalled}, - {WE0_userInfo, "User Info", general} -}; - -static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement)); - -static struct InformationElement we_6[] = -{ - {WE6_serviceInd, "Service Indicator", general}, - {WE6_chargingInfo, "Charging Information", prcharge}, - {WE6_date, "Date", prtext}, - {WE6_facSelect, "Facility Select", general}, - {WE6_facStatus, "Facility Status", general}, - {WE6_statusCalled, "Status Called", general}, - {WE6_addTransAttr, "Additional Transmission Attributes", general} -}; -static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement)); - -void -dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) { - byte *bend = buf + size; - char *dp; - int i, cs = 0, cs_old = 0, cs_fest = 0; - - /* display header */ - dp = sp->dlogspace; - dp += sprintf(dp, "%s\n", comment); - - { - byte *p = buf; - dp += sprintf(dp, "hex: "); - while (p < bend) - dp += sprintf(dp, "%02x ", *p++); - dp += sprintf(dp, "\n"); - teles_putstatus(sp->dlogspace); - dp = sp->dlogspace; - } - if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ - /* locate message type */ - if (buf[0] == PROTO_DIS_N0) { /* N0 */ - for (i = 0; i < mt_n0_len; i++) - if (mt_n0[i].nr == buf[3]) - break; - /* display message type iff it exists */ - if (i == mt_n0_len) - dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]); - else - dp += sprintf(dp, "call reference %d size %d message type %s\n", - buf[2], size, mt_n0[i].descr); - } else { /* N1 */ - for (i = 0; i < mt_n1_len; i++) - if (mt_n1[i].nr == buf[3]) - break; - /* display message type iff it exists */ - if (i == mt_n1_len) - dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]); - else - dp += sprintf(dp, "call reference %d size %d message type %s\n", - buf[2], size, mt_n1[i].descr); - } - - /* display each information element */ - buf += 4; - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - cs_old = cs; - cs = *buf & 7; - cs_fest = *buf & 8; - break; - case 3: - dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); - break; - case 2: - if (*buf == 0xa0) { - dp += sprintf(dp, " More data\n"); - break; - } - if (*buf == 0xa1) { - dp += sprintf(dp, " Sending complete\n"); - } - break; - /* fall through */ - default: - dp += sprintf(dp, " Reserved %x\n", *buf); - break; - } - buf++; - continue; - } - /* No, locate it in the table */ - if (cs == 0) { - for (i = 0; i < we_0_len; i++) - if (*buf == we_0[i].nr) - break; - - /* When found, give appropriate msg */ - if (i != we_0_len) { - dp += sprintf(dp, " %s\n", we_0[i].descr); - dp += we_0[i].f(dp, buf); - } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); - } else if (cs == 6) { - for (i = 0; i < we_6_len; i++) - if (*buf == we_6[i].nr) - break; - - /* When found, give appropriate msg */ - if (i != we_6_len) { - dp += sprintf(dp, " %s\n", we_6[i].descr); - dp += we_6[i].f(dp, buf); - } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); - } else - dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]); - /* Skip to next element */ - if (cs_fest == 8) { - cs = cs_old; - cs_old = 0; - cs_fest = 0; - } - buf += buf[1] + 2; - } - } else if (buf[0]==PROTO_EURO) { /* EURO */ - /* locate message type */ - for (i = 0; i < MTSIZE; i++) - if (mtlist[i].nr == buf[3]) - break; - - /* display message type iff it exists */ - if (i == MTSIZE) - dp += sprintf(dp, "Unknown message type %x!\n", buf[3]); - else - dp += sprintf(dp, "call reference %d size %d message type %s\n", - buf[2], size, mtlist[i].descr); - - /* display each information element */ - buf += 4; - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - break; - case 3: - dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); - break; - case 5: - dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); - break; - case 2: - if (*buf == 0xa0) { - dp += sprintf(dp, " More data\n"); - break; - } - if (*buf == 0xa1) { - dp += sprintf(dp, " Sending complete\n"); - } - break; - /* fall through */ - default: - dp += sprintf(dp, " Reserved %x\n", *buf); - break; - } - buf++; - continue; - } - /* No, locate it in the table */ - for (i = 0; i < IESIZE; i++) - if (*buf == ielist[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE) { - dp += sprintf(dp, " %s\n", ielist[i].descr); - dp += ielist[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - - /* Skip to next element */ - buf += buf[1] + 2; - } - } - else dp += sprintf(dp,"Unnown frame type %.2x, ignored\n",buf[0]); - - dp += sprintf(dp, "\n"); - teles_putstatus(sp->dlogspace); -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/tei.c linux/drivers/isdn/teles/tei.c --- v2.1.36/linux/drivers/isdn/teles/tei.c Sun Apr 21 01:56:15 1996 +++ linux/drivers/isdn/teles/tei.c Wed Dec 31 16:00:00 1969 @@ -1,248 +0,0 @@ -/* $Id: tei.c,v 1.1 1996/04/13 10:28:25 fritz Exp $ - * - * $Log: tei.c,v $ - * Revision 1.1 1996/04/13 10:28:25 fritz - * Initial revision - * - * - */ -#define __NO_VERSION__ -#include "teles.h" - -extern struct IsdnCard cards[]; -extern int nrcards; - -static struct PStack * -findces(struct PStack *st, int ces) -{ - struct PStack *ptr = *(st->l1.stlistp); - - while (ptr) - if (ptr->l2.ces == ces) - return (ptr); - else - ptr = ptr->next; - return (NULL); -} - -static struct PStack * -findtei(struct PStack *st, int tei) -{ - struct PStack *ptr = *(st->l1.stlistp); - - if (tei == 127) - return (NULL); - - while (ptr) - if (ptr->l2.tei == tei) - return (ptr); - else - ptr = ptr->next; - return (NULL); -} - -void -tei_handler(struct PStack *st, - byte pr, struct BufHeader *ibh) -{ - byte *bp; - unsigned int tces; - struct PStack *otsp, *ptr; - unsigned int data; - - if (st->l2.debug) - printk(KERN_DEBUG "teihandler %d\n", pr); - - switch (pr) { - case (MDL_ASSIGN): - data = (unsigned int) ibh; - BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 6); - if (!ibh) - return; - bp = DATAPTR(ibh); - bp += st->l2.uihsize; - bp[0] = 0xf; - bp[1] = data >> 8; - bp[2] = data & 0xff; - bp[3] = 0x1; - bp[4] = 0xff; - ibh->datasize = 8; - st->l3.l3l2(st, DL_UNIT_DATA, ibh); - break; - case (DL_UNIT_DATA): - bp = DATAPTR(ibh); - bp += 3; - if (bp[0] != 0xf) - break; - switch (bp[3]) { - case (2): - tces = (bp[1] << 8) | bp[2]; - BufPoolRelease(ibh); - if (st->l3.debug) - printk(KERN_DEBUG "tei identity assigned for %d=%d\n", tces, - bp[4] >> 1); - if ((otsp = findces(st, tces))) - otsp->ma.teil2(otsp, MDL_ASSIGN, - (void *)(bp[4] >> 1)); - break; - case (4): - if (st->l3.debug) - printk(KERN_DEBUG "checking identity for %d\n", bp[4] >> 1); - if (bp[4] >> 1 == 0x7f) { - BufPoolRelease(ibh); - ptr = *(st->l1.stlistp); - while (ptr) { - if ((ptr->l2.tei & 0x7f) != 0x7f) { - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7)) - break; - bp = DATAPTR(ibh); - bp += 3; - bp[0] = 0xf; - bp[1] = ptr->l2.ces >> 8; - bp[2] = ptr->l2.ces & 0xff; - bp[3] = 0x5; - bp[4] = (ptr->l2.tei << 1) | 1; - ibh->datasize = 8; - st->l3.l3l2(st, DL_UNIT_DATA, ibh); - } - ptr = ptr->next; - } - } else { - otsp = findtei(st, bp[4] >> 1); - BufPoolRelease(ibh); - if (!otsp) - break; - if (st->l3.debug) - printk(KERN_DEBUG "ces is %d\n", otsp->l2.ces); - if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7)) - break; - bp = DATAPTR(ibh); - bp += 3; - bp[0] = 0xf; - bp[1] = otsp->l2.ces >> 8; - bp[2] = otsp->l2.ces & 0xff; - bp[3] = 0x5; - bp[4] = (otsp->l2.tei << 1) | 1; - ibh->datasize = 8; - st->l3.l3l2(st, DL_UNIT_DATA, ibh); - } - break; - default: - BufPoolRelease(ibh); - if (st->l3.debug) - printk(KERN_DEBUG "tei message unknown %d ai %d\n", bp[3], bp[4] >> 1); - } - break; - default: - printk(KERN_WARNING "tei handler unknown primitive %d\n", pr); - break; - } -} - -unsigned int -randomces(void) -{ - int x = jiffies & 0xffff; - - return (x); -} - -static void -tei_man(struct PStack *sp, int i, void *v) -{ - printk(KERN_DEBUG "tei_man\n"); -} - -static void -tei_l2tei(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *sp = st->l1.hardware; - - tei_handler(sp->teistack, pr, arg); -} - -void -setstack_tei(struct PStack *st) -{ - st->l2.l2tei = tei_l2tei; -} - -static void -init_tei(struct IsdnCardState *sp, int protocol) -{ - struct PStack *st; - char tmp[128]; - -#define DIRTY_HACK_AGAINST_SIGSEGV - - st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL, - "struct PStack"); - -#ifdef DIRTY_HACK_AGAINST_SIGSEGV - sp->teistack = st; /* struct is not initialized yet */ - sp->teistack->protocol = protocol; /* struct is not initialized yet */ -#endif /* DIRTY_HACK_AGAINST_SIGSEGV */ - - - setstack_teles(st, sp); - - st->l2.extended = !0; - st->l2.laptype = LAPD; - st->l2.window = 1; - st->l2.orig = !0; - st->protocol = protocol; - -/* - * the following is not necessary for tei mng. (broadcast only) - */ - - st->l2.t200 = 500; /* 500 milliseconds */ - st->l2.n200 = 4; /* try 4 times */ - - st->l2.sap = 63; - st->l2.tei = 127; - - sprintf(tmp, "Card %d tei ", sp->cardnr); - setstack_isdnl2(st, tmp); - st->l2.debug = 0; - st->l3.debug = 0; - - st->ma.manl2(st, MDL_NOTEIPROC, NULL); - - st->l2.l2l3 = (void *) tei_handler; - st->l1.l1man = tei_man; - st->l2.l2man = tei_man; - st->l4.l2writewakeup = NULL; - - teles_addlist(sp, st); - sp->teistack = st; -} - -static void -release_tei(struct IsdnCardState *sp) -{ - struct PStack *st = sp->teistack; - - teles_rmlist(sp, st); - Sfree((void *) st); -} - -void -TeiNew(void) -{ - int i; - - for (i = 0; i < nrcards; i++) - if (cards[i].sp) - init_tei(cards[i].sp, cards[i].protocol); -} - -void -TeiFree(void) -{ - int i; - - for (i = 0; i < nrcards; i++) - if (cards[i].sp) - release_tei(cards[i].sp); -} diff -u --recursive --new-file v2.1.36/linux/drivers/isdn/teles/teles.h linux/drivers/isdn/teles/teles.h --- v2.1.36/linux/drivers/isdn/teles/teles.h Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/teles/teles.h Wed Dec 31 16:00:00 1969 @@ -1,486 +0,0 @@ -/* $Id: teles.h,v 1.3 1997/02/11 01:40:36 keil Exp $ - * - * $Log: teles.h,v $ - * Revision 1.3 1997/02/11 01:40:36 keil - * New Param structure - * - * Revision 1.2 1996/04/30 21:52:04 isdn4dev - * SPV for 1TR6 - Karsten - * - * Revision 1.1 1996/04/13 10:29:00 fritz - * Initial revision - * - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PH_ACTIVATE 1 -#define PH_DATA 2 -#define PH_DEACTIVATE 3 - -#define MDL_ASSIGN 4 -#define DL_UNIT_DATA 5 -#define SC_STARTUP 6 -#define CC_ESTABLISH 7 -#define DL_ESTABLISH 8 -#define DL_DATA 9 -#define CC_S_STATUS_ENQ 10 - -#define CC_CONNECT 15 -#define CC_CONNECT_ACKNOWLEDGE 16 -#define CO_EOF 17 -#define SC_DISCONNECT 18 -#define CO_DTMF 19 -#define DL_RELEASE 20 - -#define CO_ALARM 22 -#define CC_REJECT 23 - -#define CC_SETUP_REQ 24 -#define CC_SETUP_CNF 25 -#define CC_SETUP_IND 26 -#define CC_SETUP_RSP 27 -#define CC_SETUP_COMPLETE_IND 28 - -#define CC_DISCONNECT_REQ 29 -#define CC_DISCONNECT_IND 30 - -#define CC_RELEASE_CNF 31 -#define CC_RELEASE_IND 32 -#define CC_RELEASE_REQ 33 - -#define CC_REJECT_REQ 34 - -#define CC_PROCEEDING_IND 35 - -#define CC_DLRL 36 -#define CC_DLEST 37 - -#define CC_ALERTING_REQ 38 -#define CC_ALERTING_IND 39 - -#define DL_STOP 40 -#define DL_START 41 - -#define MDL_NOTEIPROC 46 - -#define LC_ESTABLISH 47 -#define LC_RELEASE 48 - -#define PH_REQUEST_PULL 49 -#define PH_PULL_ACK 50 -#define PH_DATA_PULLED 51 -#define CC_INFO_CHARGE 52 - -/* - * Message-Types - */ - -#define MT_ALERTING 0x01 -#define MT_CALL_PROCEEDING 0x02 -#define MT_CONNECT 0x07 -#define MT_CONNECT_ACKNOWLEDGE 0x0f -#define MT_PROGRESS 0x03 -#define MT_SETUP 0x05 -#define MT_SETUP_ACKNOWLEDGE 0x0d -#define MT_RESUME 0x26 -#define MT_RESUME_ACKNOWLEDGE 0x2e -#define MT_RESUME_REJECT 0x22 -#define MT_SUSPEND 0x25 -#define MT_SUSPEND_ACKNOWLEDGE 0x2d -#define MT_SUSPEND_REJECT 0x21 -#define MT_USER_INFORMATION 0x20 -#define MT_DISCONNECT 0x45 -#define MT_RELEASE 0x4d -#define MT_RELEASE_COMPLETE 0x5a -#define MT_RESTART 0x46 -#define MT_RESTART_ACKNOWLEDGE 0x4e -#define MT_SEGMENT 0x60 -#define MT_CONGESTION_CONTROL 0x79 -#define MT_INFORMATION 0x7b -#define MT_FACILITY 0x62 -#define MT_NOTIFY 0x6e -#define MT_STATUS 0x7d -#define MT_STATUS_ENQUIRY 0x75 - -#define IE_CAUSE 0x08 - -struct HscxIoctlArg { - int channel; - int mode; - int transbufsize; -}; - -#ifdef __KERNEL__ - -#undef DEBUG_MAGIC - -#define HSCX_SBUF_ORDER 1 -#define HSCX_SBUF_BPPS 2 -#define HSCX_SBUF_MAXPAGES 3 - -#define HSCX_RBUF_ORDER 1 -#define HSCX_RBUF_BPPS 2 -#define HSCX_RBUF_MAXPAGES 3 - -#define HSCX_SMALLBUF_ORDER 0 -#define HSCX_SMALLBUF_BPPS 40 -#define HSCX_SMALLBUF_MAXPAGES 1 - -#define ISAC_SBUF_ORDER 0 -#define ISAC_SBUF_BPPS 16 -#define ISAC_SBUF_MAXPAGES 1 - -#define ISAC_RBUF_ORDER 0 -#define ISAC_RBUF_BPPS 16 -#define ISAC_RBUF_MAXPAGES 1 - -#define ISAC_SMALLBUF_ORDER 0 -#define ISAC_SMALLBUF_BPPS 40 -#define ISAC_SMALLBUF_MAXPAGES 1 - -#define byte unsigned char - -#define MAX_WINDOW 8 - -byte *Smalloc(int size, int pr, char *why); -void Sfree(byte * ptr); - -/* - * Statemachine - */ -struct Fsm { - int *jumpmatrix; - int state_count, event_count; - char **strEvent, **strState; -}; - -struct FsmInst { - struct Fsm *fsm; - int state; - int debug; - void *userdata; - int userint; - void (*printdebug) (struct FsmInst *, char *); -}; - -struct FsmNode { - int state, event; - void (*routine) (struct FsmInst *, int, void *); -}; - -struct FsmTimer { - struct FsmInst *fi; - struct timer_list tl; - int event; - void *arg; -}; - -struct BufHeader { -#ifdef DEBUG_MAGIC - int magic; -#endif - struct BufHeader *next; - struct BufPool *bp; - int datasize; - byte primitive, where; - void *heldby; -}; - -struct Pages { - struct Pages *next; -}; - -struct BufPool { -#ifdef DEBUG_MAGIC - int magic; -#endif - struct BufHeader *freelist; - struct Pages *pageslist; - int pageorder; - int pagescount; - int bpps; - int bufsize; - int maxpages; -}; - -struct BufQueue { -#ifdef DEBUG_MAGIC - int magic; -#endif - struct BufHeader *head, *tail; -}; - -struct Layer1 { - void *hardware; - int hscx; - struct BufPool *sbufpool, *rbufpool, *smallpool; - struct PStack **stlistp; - int act_state; - void (*l1l2) (struct PStack *, int, struct BufHeader *); - void (*l1man) (struct PStack *, int, void *); - int hscxmode, hscxchannel, requestpull; -}; - -struct Layer2 { - int sap, tei, ces; - int extended, laptype; - int uihsize, ihsize; - int vs, va, vr; - struct BufQueue i_queue; - int window, orig; - int rejexp; - int debug; - struct BufHeader *windowar[MAX_WINDOW]; - int sow; - struct FsmInst l2m; - void (*l2l1) (struct PStack *, int, struct BufHeader *); - void (*l2l1discardq) (struct PStack *, int, void *, int); - void (*l2man) (struct PStack *, int, void *); - void (*l2l3) (struct PStack *, int, void *); - void (*l2tei) (struct PStack *, int, void *); - struct FsmTimer t200_timer, t203_timer; - int t200, n200, t203; - int rc, t200_running; - char debug_id[32]; -}; - -struct Layer3 { - void (*l3l4) (struct PStack *, int, struct BufHeader *); - void (*l3l2) (struct PStack *, int, void *); - int state, callref; - int debug; -}; - -struct Layer4 { - void (*l4l3) (struct PStack *, int, void *); - void *userdata; - void (*l1writewakeup) (struct PStack *); - void (*l2writewakeup) (struct PStack *); -}; - -struct Management { - void (*manl1) (struct PStack *, int, void *); - void (*manl2) (struct PStack *, int, void *); - void (*teil2) (struct PStack *, int, void *); -}; - -struct Param { - int cause; - int bchannel; - int callref; /* TEI-Number */ - setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - int chargeinfo; /* Charge Info - only for 1tr6 in - * the moment - */ - int spv; /* SPV Flag */ -}; - -struct PStack { - struct PStack *next; - struct Layer1 l1; - struct Layer2 l2; - struct Layer3 l3; - struct Layer4 l4; - struct Management ma; - struct Param *pa; - int protocol; /* EDSS1 or 1TR6 */ -}; - -struct HscxState { - byte *membase; - int iobase; - int inuse, init, active; - struct BufPool sbufpool, rbufpool, smallpool; - struct IsdnCardState *sp; - int hscx, mode; - int transbufsize, receive; - struct BufHeader *rcvibh, *xmtibh; - int rcvptr, sendptr; - struct PStack *st; - struct tq_struct tqueue; - int event; - struct BufQueue rq, sq; - int releasebuf; -#ifdef DEBUG_MAGIC - int magic; /* 301270 */ -#endif -}; - -struct IsdnCardState { -#ifdef DEBUG_MAGIC - int magic; -#endif - byte *membase; - int iobase; - struct BufPool sbufpool, rbufpool, smallpool; - struct PStack *stlist; - struct BufHeader *xmtibh, *rcvibh; - int rcvptr, sendptr; - int event; - struct tq_struct tqueue; - int ph_active; - struct BufQueue rq, sq; - - int cardnr, ph_state; - struct PStack *teistack; - struct HscxState hs[2]; - - int dlogflag; - char *dlogspace; - int debug; - int releasebuf; -}; - -struct IsdnCard { - byte *membase; - int interrupt; - unsigned int iobase; - int protocol; /* EDSS1 or 1TR6 */ - struct IsdnCardState *sp; -}; - -#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader)) - -#define LAPD 0 -#define LAPB 1 - -void BufPoolInit(struct BufPool *bp, int order, int bpps, - int maxpages); -int BufPoolAdd(struct BufPool *bp, int priority); -void BufPoolFree(struct BufPool *bp); -int BufPoolGet(struct BufHeader **bh, - struct BufPool *bp, int priority, void *heldby, int where); -void BufPoolRelease(struct BufHeader *bh); -void BufQueueLink(struct BufQueue *bq, - struct BufHeader *bh); -int BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq); -void BufQueueInit(struct BufQueue *bq); -void BufQueueRelease(struct BufQueue *bq); -void BufQueueDiscard(struct BufQueue *q, int pr, void *heldby, - int releasetoo); -int BufQueueLength(struct BufQueue *bq); -void BufQueueLinkFront(struct BufQueue *bq, - struct BufHeader *bh); - -void l2down(struct PStack *st, - byte pr, struct BufHeader *ibh); -void l2up(struct PStack *st, - byte pr, struct BufHeader *ibh); -void acceptph(struct PStack *st, - struct BufHeader *ibh); -void setstack_isdnl2(struct PStack *st, char *debug_id); -int teles_inithardware(void); -void teles_closehardware(void); - -void setstack_teles(struct PStack *st, struct IsdnCardState *sp); -unsigned int randomces(void); -void setstack_isdnl3(struct PStack *st); -void teles_addlist(struct IsdnCardState *sp, - struct PStack *st); -void releasestack_isdnl2(struct PStack *st); -void teles_rmlist(struct IsdnCardState *sp, - struct PStack *st); -void newcallref(struct PStack *st); - -int ll_init(void); -void ll_stop(void), ll_unload(void); -int setstack_hscx(struct PStack *st, struct HscxState *hs); -void modehscx(struct HscxState *hs, int mode, int ichan); -byte *findie(byte * p, int size, byte ie, int wanted_set); -int getcallref(byte * p); - -void FsmNew(struct Fsm *fsm, - struct FsmNode *fnlist, int fncount); -void FsmFree(struct Fsm *fsm); -int FsmEvent(struct FsmInst *fi, - int event, void *arg); -void FsmChangeState(struct FsmInst *fi, - int newstate); -void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft); -int FsmAddTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where); -void FsmDelTimer(struct FsmTimer *ft, int where); -int FsmTimerRunning(struct FsmTimer *ft); -void jiftime(char *s, long mark); - -void CallcNew(void); -void CallcFree(void); -int CallcNewChan(void); -void CallcFreeChan(void); -int teles_command(isdn_ctrl * ic); -int teles_writebuf(int id, int chan, const u_char * buf, int count, int user); -void teles_putstatus(char *buf); -void teles_reportcard(int cardnr); -int ListLength(struct BufHeader *ibh); -void dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment); -void iecpy(byte * dest, byte * iestart, int ieoffset); -void setstack_transl2(struct PStack *st); -void releasestack_transl2(struct PStack *st); -void close_hscxstate(struct HscxState *); -void setstack_tei(struct PStack *st); - -struct LcFsm { - struct FsmInst lcfi; - int type; - struct Channel *ch; - void (*lccall) (struct LcFsm *, int, void *); - struct PStack *st; - int l2_establish; - int l2_start; - struct FsmTimer act_timer; - char debug_id[32]; -}; - -struct Channel { - struct PStack ds, is; - struct IsdnCardState *sp; - int hscx; - int chan; - int incoming; - struct FsmInst fi; - struct LcFsm lc_d, lc_b; - struct Param para; - int debug; -#ifdef DEBUG_MAGIC - int magic; /* 301272 */ -#endif - int l2_protocol, l2_active_protocol; - int l2_primitive, l2_headersize; - int data_open; - int outcallref; - int impair; -}; - -#define PART_SIZE(order,bpps) (( (PAGE_SIZE<tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { restore_flags(flags); printk("%s: Transmitter access conflict.\n", dev->name); diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.1.36/linux/drivers/net/3c505.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/3c505.c Mon May 12 10:35:40 1997 @@ -412,7 +412,7 @@ return FALSE; /* Avoid contention */ - if (set_bit(1, &adapter->send_pcb_semaphore)) { + if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) { if (elp_debug >= 3) { printk("%s: send_pcb entered while threaded\n", dev->name); } @@ -545,7 +545,7 @@ } if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) { - if (set_bit(0, (void *) &adapter->busy)) { + if (test_and_set_bit(0, (void *) &adapter->busy)) { if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) { set_hsf(dev, HSF_PCB_NAK); printk("%s: PCB rejected, transfer in progress and backlog full\n", dev->name); @@ -621,7 +621,7 @@ } /* if this happens, we die */ - if (set_bit(0, (void *) &adapter->dmaing)) + if (test_and_set_bit(0, (void *) &adapter->dmaing)) printk("%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction); skb->dev = dev; @@ -1031,7 +1031,7 @@ */ unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1); - if (set_bit(0, (void *) &adapter->busy)) { + if (test_and_set_bit(0, (void *) &adapter->busy)) { if (elp_debug >= 2) printk("%s: transmit blocked\n", dev->name); return FALSE; @@ -1054,7 +1054,7 @@ return FALSE; } /* if this happens, we die */ - if (set_bit(0, (void *) &adapter->dmaing)) + if (test_and_set_bit(0, (void *) &adapter->dmaing)) printk("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction); adapter->current_dma.direction = 1; @@ -1119,7 +1119,7 @@ if (elp_debug >= 3) printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len); - if (set_bit(0, (void *) &dev->tbusy)) { + if (test_and_set_bit(0, (void *) &dev->tbusy)) { printk("%s: transmitter access conflict\n", dev->name); return 1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.1.36/linux/drivers/net/3c507.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/3c507.c Mon May 12 10:35:40 1997 @@ -479,7 +479,7 @@ } /* Block a timer-based transmit from overlapping. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.1.36/linux/drivers/net/3c509.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/3c509.c Mon May 12 10:35:40 1997 @@ -468,7 +468,7 @@ #endif #endif /* Avoid timer-based retransmission conflicts. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { lp->stats.tx_bytes+=skb->len; diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.1.36/linux/drivers/net/3c523.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/3c523.c Mon May 12 10:35:40 1997 @@ -1137,7 +1137,7 @@ return 0; } - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); } else { memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); diff -u --recursive --new-file v2.1.36/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.36/linux/drivers/net/3c59x.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/3c59x.c Mon May 12 10:35:40 1997 @@ -799,7 +799,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. If this ever occurs the queue layer is doing something evil! */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.1.36/linux/drivers/net/a2065.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/a2065.c Mon May 12 10:35:40 1997 @@ -599,7 +599,7 @@ #ifdef OLD_METHOD dev->tbusy = 1; #else - if (set_bit (0, (void *) &dev->tbusy) != 0) { + if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) { printk ("Transmitter access conflict.\n"); return -1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/apricot.c linux/drivers/net/apricot.c --- v2.1.36/linux/drivers/net/apricot.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/apricot.c Mon May 12 10:35:40 1997 @@ -616,7 +616,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { diff -u --recursive --new-file v2.1.36/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v2.1.36/linux/drivers/net/arcnet.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/arcnet.c Mon May 12 10:35:40 1997 @@ -1588,7 +1588,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n", ARCSTATUS,lp->intx,jiffies-dev->trans_start); diff -u --recursive --new-file v2.1.36/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.1.36/linux/drivers/net/ariadne.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/ariadne.c Mon May 12 10:35:40 1997 @@ -593,12 +593,12 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return(1); } - if (set_bit(0, (void*)&priv->lock) != 0) { + if (test_and_set_bit(0, (void*)&priv->lock) != 0) { if (ariadne_debug > 0) printk("%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v2.1.36/linux/drivers/net/at1700.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/at1700.c Mon May 12 10:35:40 1997 @@ -395,7 +395,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff -u --recursive --new-file v2.1.36/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c --- v2.1.36/linux/drivers/net/atarilance.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/atarilance.c Mon May 12 10:35:40 1997 @@ -776,12 +776,12 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit( 0, (void*)&dev->tbusy ) != 0) { + if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) { DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name )); return 1; } - if (set_bit( 0, (void*)&lp->lock ) != 0) { + if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name )); /* don't clear dev->tbusy flag. */ return 1; diff -u --recursive --new-file v2.1.36/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.1.36/linux/drivers/net/atp.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/atp.c Mon May 12 10:35:40 1997 @@ -437,7 +437,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff -u --recursive --new-file v2.1.36/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.1.36/linux/drivers/net/cs89x0.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/cs89x0.c Mon May 12 10:35:40 1997 @@ -752,7 +752,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { struct net_local *lp = (struct net_local *)dev->priv; diff -u --recursive --new-file v2.1.36/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.36/linux/drivers/net/de4x5.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/de4x5.c Mon May 12 10:35:41 1997 @@ -3,8 +3,30 @@ Copyright 1994, 1995 Digital Equipment Corporation. - This software may be used and distributed according to the terms of - the GNU Public License, incorporated herein by reference. + Testing resources for this driver have been made available + in part by NASA Ames Research Center (mjacob@nas.nasa.gov). + + The author may be reached at davies@maniac.ultranet.com. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 675 Mass Ave, Cambridge, MA 02139, USA. Originally, this driver was written for the Digital Equipment Corporation series of EtherWORKS ethernet cards: @@ -15,8 +37,8 @@ DE450 TP/COAX/AUI PCI DE500 10/100 PCI Fasternet - but it will now attempt to support all cards which conform to the - Digital Semiconductor SROM Specification. The driver currently + but it will now attempt to support all cards which conform to the + Digital Semiconductor SROM Specification. The driver currently recognises the following chips: DC21040 (no SROM) @@ -32,6 +54,7 @@ SMC8432 SMC9332 (w/new SROM) ZNYX31[45] + ZNYX346 10/100 4 port (can act as a 10/100 bridge!) The driver has been tested on a relatively busy network using the DE425, DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred @@ -48,13 +71,11 @@ measurement. Their error is +/-20k on a quiet (private) network and also depend on what load the CPU has. - The author may be reached at davies@maniac.ultranet.com. - ========================================================================= - This driver has been written substantially from scratch, although its + This driver has been written substantially from scratch, although its inheritance of style and stack interface from 'ewrk3.c' and in turn from Donald Becker's 'lance.c' should be obvious. With the module autoload of - every usable DECchip board, I pinched Donald's 'next_module' field to + every usable DECchip board, I pinched Donald's 'next_module' field to link my modules together. Upto 15 EISA cards can be supported under this driver, limited primarily @@ -80,7 +101,7 @@ 1) copy de4x5.c from the /linux/drivers/net directory to your favourite temporary directory. 2) for fixed autoprobes (not recommended), edit the source code near - line 4927 to reflect the I/O address you're using, or assign these when + line 5005 to reflect the I/O address you're using, or assign these when loading by: insmod de4x5 io=0xghh where g = bus number @@ -113,7 +134,7 @@ By default, the driver will now autodetect any DECchip based card. Should you have a need to restrict the driver to DIGITAL only cards, you can compile with a DEC_ONLY define, or if loading as a module, use the - 'dec_only=1' parameter. + 'dec_only=1' parameter. I've changed the timing routines to use the kernel timer and scheduling functions so that the hangs and other assorted problems that occurred @@ -145,6 +166,19 @@ (quad 21041 MAC) cards also appear to work despite their incorrectly wired IRQs. + I have added a temporary fix for interrupt problems when some SCSI cards + share the same interrupt as the DECchip based cards. The problem occurs + because the SCSI card wants to grab the interrupt as a fast interrupt + (runs the service routine with interrupts turned off) vs. this card + which really needs to run the service routine with interrupts turned on. + This driver will now add the interrupt service routine as a fast + interrupt if it is bounced from the slow interrupt. THIS IS NOT A + RECOMMENDED WAY TO RUN THE DRIVER and has been done for a limited time + until people sort out their compatibility issues and the kernel + interrupt service code is fixed. YOU SHOULD SEPARATE OUT THE FAST + INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not + run on the same interrupt. PCMCIA/CardBus is another can of worms... + TO DO: ------ @@ -234,7 +268,7 @@ 0.442 9-Sep-96 Include AUI in dc21041 media printout. Bug reported by 0.45 8-Dec-96 Include endian functions for PPC use, from work - by . + by and . 0.451 28-Dec-96 Added fix to allow autoprobe for modules after suggestion from . 0.5 30-Jan-97 Added SROM decoding functions. @@ -247,11 +281,30 @@ Added attempt to use an SMC9332 with broken SROM. Added fix for ZYNX multi-mac cards that didn't get their IRQs wired correctly. + 0.51 13-Feb-97 Added endian fixes for the SROM accesses from + + Fix init_connection() to remove extra device reset. + Fix MAC/PHY reset ordering in dc21140m_autoconf(). + Fix initialisation problem with lp->timeout in + typeX_infoblock() from . + Fix MII PHY reset problem from work done by + . + 0.52 26-Apr-97 Some changes may not credit the right people - + a disk crash meant I lost some mail. + Change RX interrupt routine to drop rather than + defer packets to avoid hang reported by + . + Fix srom_exec() to return for COMPACT and type 1 + infoblocks. + Added DC21142 and DC21143 functions. + Added byte counters from + Added SA_INTERRUPT temporary fix from + . ========================================================================= */ -static const char *version = "de4x5.c:V0.5 97/1/30 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com\n"; #include @@ -270,8 +323,8 @@ #include #include #include -#include #include +#include #include #include @@ -286,14 +339,37 @@ #define c_char const char +#include +#if LINUX_VERSION_CODE < ((2 << 16) | (1 << 8)) +#define net_device_stats enet_statistics +#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) +#define copy_from_user(a,b,c) memcpy_fromfs(a,b,c) +#define le16_to_cpu(a) cpu_to_le16(a) +#define le32_to_cpu(a) cpu_to_le32(a) +#ifdef __powerpc__ +#define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8)) +#define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\ + (((a) & 0x0000ff00U) << 8) |\ + (((a) & 0x00ff0000U) >> 8) |\ + (((a) & 0xff000000U) >> 24)) +#else +#define cpu_to_le16(a) (a) +#define cpu_to_le32(a) (a) +#endif /* __powerpc__ */ +#include +#else +#include +#endif /* LINUX_VERSION_CODE */ +#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a))) + /* ** MII Information */ struct phy_table { - int reset; /* Hard reset required? */ - int id; /* IEEE OUI */ + int reset; /* Hard reset required? */ + int id; /* IEEE OUI */ int ta; /* One cycle TA time - 802.3u is confusing here */ - struct { /* Non autonegotiation (parallel) speed det. */ + struct { /* Non autonegotiation (parallel) speed det. */ int reg; int mask; int value; @@ -301,25 +377,35 @@ }; struct mii_phy { - int reset; /* Hard reset required? */ - int id; /* IEEE OUI */ - int ta; /* One cycle TA time */ + int reset; /* Hard reset required? */ + int id; /* IEEE OUI */ + int ta; /* One cycle TA time */ struct { /* Non autonegotiation (parallel) speed det. */ int reg; int mask; int value; } spd; - int addr; /* MII address for the PHY */ - u_char *gep; /* Start of GEP sequence block in SROM */ - u_char *rst; /* Start of reset sequence in SROM */ - u_int mc; /* Media Capabilities */ - u_int ana; /* NWay Advertisement */ - u_int fdx; /* Full DupleX capabilites for each media */ - u_int ttm; /* Transmit Threshold Mode for each media */ + int addr; /* MII address for the PHY */ + u_char *gep; /* Start of GEP sequence block in SROM */ + u_char *rst; /* Start of reset sequence in SROM */ + u_int mc; /* Media Capabilities */ + u_int ana; /* NWay Advertisement */ + u_int fdx; /* Full DupleX capabilites for each media */ + u_int ttm; /* Transmit Threshold Mode for each media */ }; #define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */ +struct sia_phy { + u_char mc; /* Media Code */ + u_char ext; /* csr13-15 valid when set */ + int csr13; /* SIA Connectivity Register */ + int csr14; /* SIA TX/RX Register */ + int csr15; /* SIA General Register */ + int gepc; /* SIA GEP Control Information */ + int gep; /* SIA GEP Data */ +}; + /* ** Define the know universe of PHY devices that can be ** recognised by this driver @@ -327,8 +413,8 @@ static struct phy_table phy_info[] = { {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}}, /* National TX */ {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}}, /* Broadcom T4 */ - {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */ - {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */ + {0, SEEQ_T4 , 1, {0x12, 0x10, 0x10}}, /* SEEQ T4 */ + {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}} /* Cypress T4 */ }; /* @@ -354,7 +440,6 @@ 0x00,0x18,} }; -#undef DE4X5_VERBOSE /* define to get more verbose startup messages */ #ifdef DE4X5_DEBUG static int de4x5_debug = DE4X5_DEBUG; @@ -581,6 +666,7 @@ int setup_f; /* Setup frame filtering type */ int local_state; /* State within a 'media' state */ struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */ + struct sia_phy sia; /* SIA PHY Information */ int active; /* Index to active PHY device */ int mii_cnt; /* Number of attached PHY's */ int timeout; /* Scheduling counter */ @@ -770,9 +856,6 @@ static void yawn(struct device *dev, int state); static int de4x5_dev_index(char *s); static void link_modules(struct device *dev, struct device *tmp); -#ifdef MODULE -static struct device *unlink_modules(struct device *p); -#endif static void de4x5_dbg_open(struct device *dev); static void de4x5_dbg_mii(struct device *dev, int k); static void de4x5_dbg_media(struct device *dev); @@ -794,6 +877,7 @@ #ifdef MODULE int init_module(void); void cleanup_module(void); +static struct device *unlink_modules(struct device *p); static int autoprobed = 0, loading_module = 1; # else static int autoprobed = 0, loading_module = 0; @@ -898,7 +982,7 @@ PCI_CFDA_PSM, WAKEUP); } de4x5_ms_delay(10); - + RESET_DE4X5; if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) { @@ -964,6 +1048,9 @@ lp->chipset = bus.chipset; lp->cache.priv = tmp; lp->cache.gepc = GEP_INIT; + lp->asBit = GEP_SLNK; + lp->asPolarity = GEP_SLNK; + lp->asBitValid = TRUE; lp->timeout = -1; lp->useSROM = useSROM; memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom)); @@ -1071,11 +1158,6 @@ printk(" and requires IRQ%d (provided by %s).\n", dev->irq, ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); - -#ifdef DE4X5_VERBOSE - printk("%s: INFOLEAF_SIZE: %ld, COMPACT: %ld\n", dev->name, - INFOLEAF_SIZE, COMPACT); -#endif } if (de4x5_debug & DEBUG_VERSION) { @@ -1133,18 +1215,29 @@ if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, lp->adapter_name, dev)) { - printk("de4x5_open(): Requested IRQ%d is busy\n",dev->irq); - status = -EAGAIN; - } else { - dev->tbusy = 0; - dev->start = 1; - dev->interrupt = UNMASK_INTERRUPTS; - dev->trans_start = jiffies; - - START_DE4X5; - - de4x5_setup_intr(dev); + printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq); + if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ, + lp->adapter_name, dev)) { + printk("\n Cannot get IRQ- reconfigure your hardware.\n"); + disable_ast(dev); + de4x5_free_rx_buffs(dev); + de4x5_free_tx_buffs(dev); + yawn(dev, SLEEP); + lp->state = CLOSED; + return -EAGAIN; + } else { + printk("\n Succeeded, but you should reconfigure your hardware to avoid this.\n"); + printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n"); + } } + dev->tbusy = 0; + dev->start = 1; + dev->interrupt = UNMASK_INTERRUPTS; + dev->trans_start = jiffies; + + START_DE4X5; + + de4x5_setup_intr(dev); if (de4x5_debug & DEBUG_OPEN) { printk("\tsts: 0x%08x\n", inl(DE4X5_STS)); @@ -1287,7 +1380,7 @@ sti(); /* Test if cache is already locked - requeue skb if so */ - if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1; + if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1; /* Transmit descriptor ring full or stale skb */ if (dev->tbusy || lp->tx_skb[lp->tx_new]) { @@ -1300,9 +1393,6 @@ printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO")); } } else if (skb->len > 0) { - /* Update the byte counter */ - lp->stats.tx_bytes += skb->len; - /* If we already have stuff queued locally, use that first */ if (lp->cache.skb && !dev->interrupt) { de4x5_put_cache(dev, skb); @@ -1313,6 +1403,9 @@ cli(); set_bit(0, (void*)&dev->tbusy); load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); +#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) + lp->stats.tx_bytes += skb->len; +#endif outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ lp->tx_new = (++lp->tx_new) % lp->txRingSize; @@ -1326,7 +1419,7 @@ } if (skb) de4x5_putb_cache(dev, skb); } - + lp->cache.lock = 0; return status; @@ -1360,9 +1453,11 @@ if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); - + DISABLE_IRQs; /* Ensure non re-entrancy */ +#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) synchronize_irq(); +#endif dev->interrupt = MASK_INTERRUPTS; for (limit=0; limit<8; limit++) { @@ -1394,8 +1489,8 @@ } /* Load the TX ring with any locally stored packets */ - if (!set_bit(0, (void *)&lp->cache.lock)) { - if (lp->cache.skb && !dev->tbusy && lp->tx_enable) { + if (!test_and_set_bit(0, (void *)&lp->cache.lock)) { + while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { de4x5_queue_pkt(de4x5_get_cache(dev), dev); } lp->cache.lock = 0; @@ -1450,19 +1545,21 @@ if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) { printk("%s: Insufficient memory; nuking packet.\n", dev->name); - lp->stats.rx_dropped++; /* Really, deferred. */ - break; - } - de4x5_dbg_rx(skb, pkt_len); + lp->stats.rx_dropped++; + } else { + de4x5_dbg_rx(skb, pkt_len); - /* Push up the protocol stack */ - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); + /* Push up the protocol stack */ + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); - /* Update stats */ - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; - de4x5_local_stats(dev, skb->data, pkt_len); + /* Update stats */ + lp->stats.rx_packets++; +#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) + lp->stats.rx_bytes += pkt_len; +#endif + de4x5_local_stats(dev, skb->data, pkt_len); + } } /* Change buffer ownership for this frame, back to the adapter */ @@ -1575,10 +1672,7 @@ if ((omr & OMR_TR) < OMR_TR) { omr += 0x4000; } else { - if (omr & OMR_TTM) - omr &= ~OMR_TTM; - else - omr |= OMR_SF; + omr |= OMR_SF; } outl(omr | OMR_ST | OMR_SR, DE4X5_OMR); } @@ -1645,7 +1739,8 @@ return 0; } -static struct net_device_stats *de4x5_get_stats(struct device *dev) +static struct net_device_stats * +de4x5_get_stats(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -1880,7 +1975,7 @@ { u_char irq; u_char pb, pbus, dev_num, dnum, dev_fn; - u_short vendor, index, status; + u_short dev_id, vendor, index, status; u_int class = DE4X5_CLASS_CODE; u_int device, iobase; struct bus_type *lp = &bus; @@ -1908,7 +2003,8 @@ if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { device = 0; pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, (u_short *)&device); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); + device = dev_id; device <<= 8; if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { continue; @@ -2091,31 +2187,6 @@ return; } -#ifdef MODULE -static struct device * -unlink_modules(struct device *p) -{ - struct device *next = NULL; - - if (p->priv) { /* Private areas allocated? */ - struct de4x5_private *lp = (struct de4x5_private *)p->priv; - - next = lp->next_module; - if (lp->cache.buf) { /* MAC buffers allocated? */ - kfree(lp->cache.buf); /* Free the MAC buffers */ - } - kfree(lp->cache.priv); /* Free the private area */ - release_region(p->base_addr, (lp->bus == PCI ? - DE4X5_PCI_TOTAL_SIZE : - DE4X5_EISA_TOTAL_SIZE)); - } - unregister_netdev(p); - kfree(p); /* Free the device structure */ - - return next; -} -#endif - /* ** Auto configure the media here rather than setting the port at compile ** time. This routine is called by de4x5_init() and when a loss of media is @@ -2300,6 +2371,7 @@ lp->media = prev_state; } else { lp->media = INIT; + lp->tcount++; } } @@ -2527,16 +2599,22 @@ switch(lp->media) { case INIT: - DISABLE_IRQs; - lp->tx_enable = FALSE; - lp->linkOK = 0; -/* lp->timeout = -1;*/ + if (lp->timeout < 0) { + DISABLE_IRQs; + lp->tx_enable = FALSE; + lp->linkOK = 0; + de4x5_save_skbs(dev); /* Save non transmitted skb's */ + } if ((next_tick = de4x5_reset_phy(dev)) < 0) { next_tick &= ~TIMER_CB; } else { - de4x5_save_skbs(dev); /* Save non transmitted skb's */ if (lp->useSROM) { srom_map_media(dev); + srom_exec(dev, lp->phy[lp->active].gep); + if (lp->infoblock_media == ANS) { + ana = lp->phy[lp->active].ana | MII_ANA_CSMA; + mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + } } else { lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */ SET_10Mb; @@ -2752,9 +2830,9 @@ de4x5_dbg_media(dev); lp->c_media = lp->media; /* Stop scrolling media messages */ } - de4x5_restore_skbs(dev); + cli(); - de4x5_rx(dev); + de4x5_restore_skbs(dev); de4x5_setup_intr(dev); lp->tx_enable = YES; dev->tbusy = 0; @@ -2766,7 +2844,9 @@ } /* -** General PHY reset function. +** General PHY reset function. Some MII devices don't reset correctly +** since their MII address pins can float at voltages that are dependent +** on the signal pin use. Do a double reset to ensure a reset. */ static int de4x5_reset_phy(struct device *dev) @@ -2780,8 +2860,10 @@ if (lp->useSROM) { if (lp->phy[lp->active].rst) { /* MII device specific reset */ srom_exec(dev, lp->phy[lp->active].rst); + srom_exec(dev, lp->phy[lp->active].rst); } else if (lp->rst) { /* Type 5 infoblock reset */ srom_exec(dev, lp->rst); + srom_exec(dev, lp->rst); } } else { PHY_HARD_RESET; @@ -3151,13 +3233,26 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; + int i; s32 omr; if (lp->cache.save_cnt) { STOP_DE4X5; - de4x5_cache_state(dev, DE4X5_SAVE_STATE); - de4x5_sw_reset(dev); - de4x5_cache_state(dev, DE4X5_RESTORE_STATE); + outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); + outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); + + lp->rx_new = lp->rx_old = 0; + lp->tx_new = lp->tx_old = 0; + + for (i = 0; i < lp->rxRingSize; i++) { + lp->rx_ring[i].status = cpu_to_le32(R_OWN); + } + + for (i = 0; i < lp->txRingSize; i++) { + lp->tx_ring[i].status = cpu_to_le32(0); + } + + barrier(); lp->cache.save_cnt--; START_DE4X5; } @@ -3446,9 +3541,10 @@ if (lp->chipset == DC21040) { outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ } else { /* Read new srom */ - short *p = (short *)&lp->srom; + u_short tmp, *p = (short *)&lp->srom; for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) { - *p++ = srom_rd(aprom_addr, i); + tmp = srom_rd(aprom_addr, i); + *p++ = le16_to_cpu(tmp); } de4x5_dbg_srom((struct de4x5_srom *)&lp->srom); } @@ -3756,7 +3852,7 @@ } } - lp->infoleaf_offset = (u_short)*((u_short *)(p+1)); + lp->infoleaf_offset = TWIDDLE(p+1); return 0; } @@ -3776,14 +3872,10 @@ u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; u_char count; + p+=2; if (lp->chipset == DC21140) { - p+=2; lp->cache.gepc = (*p++ | GEP_CTRL); outl(lp->cache.gepc, DE4X5_GEP); - } else if (lp->chipset == DC21142) { - p+=2; - } else if (lp->chipset == DC21143) { - p+=2; } /* Block count */ @@ -3815,7 +3907,7 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - u_char count = *p++; + u_char count = (p ? *p++ : 0); while (count--) { if (lp->chipset == DC21140) { @@ -3910,7 +4002,7 @@ } } - if (lp->media == INIT) { + if ((lp->media == INIT) && (lp->timeout < 0)) { outl(lp->cache.gepc, DE4X5_GEP); lp->infoblock_media = (*p++) & COMPACT_MC; lp->cache.gep = *p++; @@ -3949,7 +4041,7 @@ } } - if (lp->media == INIT) { + if ((lp->media == INIT) && (lp->timeout < 0)) { outl(lp->cache.gepc, DE4X5_GEP); p+=2; lp->infoblock_media = (*p++) & BLOCK0_MC; @@ -3976,9 +4068,7 @@ type1_infoblock(struct device *dev, u_char count, u_char *p) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; u_char len = (*p & BLOCK_LEN)+1; - int ana; /* Recursively figure out the info blocks */ if (--count > lp->tcount) { @@ -3989,22 +4079,20 @@ } } + p += 2; if (lp->state == INITIALISED) { - lp->ibn = 1; p += 2; + lp->ibn = 1; lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); - lp->phy[lp->active].mc = *(u_short *)p; p += 2; - lp->phy[lp->active].ana = *(u_short *)p; p += 2; - lp->phy[lp->active].fdx = *(u_short *)p; p += 2; - lp->phy[lp->active].ttm = *(u_short *)p; + lp->phy[lp->active].mc = TWIDDLE(p); p += 2; + lp->phy[lp->active].ana = TWIDDLE(p); p += 2; + lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; + lp->phy[lp->active].ttm = TWIDDLE(p); return 0; - } else if (lp->media == INIT) { - if (lp->phy[lp->active].gep) { - srom_exec(dev, lp->phy[lp->active].gep); - } - ana = lp->phy[lp->active].ana | MII_ANA_CSMA; - mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); + } else if ((lp->media == INIT) && (lp->timeout < 0)) { + lp->ibn = 1; + lp->active = *p; lp->infoblock_csr6 = OMR_PS | OMR_HBD; lp->useMII = TRUE; lp->infoblock_media = ANS; @@ -4040,10 +4128,10 @@ lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); - lp->phy[lp->active].mc = *(u_short *)p; p += 2; - lp->phy[lp->active].ana = *(u_short *)p; p += 2; - lp->phy[lp->active].fdx = *(u_short *)p; p += 2; - lp->phy[lp->active].ttm = *(u_short *)p; + lp->phy[lp->active].mc = TWIDDLE(p); p += 2; + lp->phy[lp->active].ana = TWIDDLE(p); p += 2; + lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; + lp->phy[lp->active].ttm = TWIDDLE(p); return 0; } else if (lp->media == INIT) { p+=2; @@ -4672,18 +4760,12 @@ u_long iobase = dev->base_addr; int i, j, status = 0; s32 omr; - struct { - u8 *addr; - u16 *sval; - u32 *lval; + union { + u8 addr[144]; + u16 sval[72]; + u32 lval[36]; } tmp; - - tmp.addr = tmp.sval = tmp.lval = kmalloc(HASH_TABLE_LEN * ETH_ALEN, GFP_KERNEL); - if (!tmp.addr){ - printk("%s ioctl: memory squeeze.\n", dev->name); - return -ENOMEM; - } - + switch(ioc->cmd) { case DE4X5_GET_HWADDR: /* Get the hardware address */ ioc->len = ETH_ALEN; @@ -4710,7 +4792,7 @@ } build_setup_frame(dev, PHYS_ADDR_ONLY); /* Set up the descriptor and give ownership to the card */ - while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/ + while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/ load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | SETUP_FRAME_LEN, NULL); lp->tx_new = (++lp->tx_new) % lp->txRingSize; @@ -4743,39 +4825,12 @@ break; case DE4X5_GET_MCA: /* Get the multicast address table */ - ioc->len = (HASH_TABLE_LEN >> 3); - status = verify_area(VERIFY_WRITE, ioc->data, ioc->len); - if (!status) { - copy_to_user(ioc->data, lp->setup_frame, ioc->len); - } - break; case DE4X5_SET_MCA: /* Set a multicast address */ - if (suser()) { - /******* FIX ME! ********/ - if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */ - if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) { - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); - set_multicast_list(dev); - } - } else { - set_multicast_list(dev); - } - } else { - status = -EPERM; - } - break; case DE4X5_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { - /******* FIX ME! ********/ - set_multicast_list(dev); - } else { - status = -EPERM; - } - break; - case DE4X5_MCA_EN: /* Enable pass all multicast addressing */ + case DE4X5_MCA_EN: /* Enable pass all multicast addresses*/ if (suser()) { omr = inl(DE4X5_OMR); omr |= OMR_PM; @@ -4840,7 +4895,8 @@ } break; -#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */ +/* +#define DE4X5_DUMP 0x0f / * Dump the DE4X5 Status * / case DE4X5_DUMP: j = 0; @@ -4931,12 +4987,11 @@ } break; +*/ default: status = -EOPNOTSUPP; } - - kfree(tmp.addr); - + return status; } @@ -4975,6 +5030,30 @@ return; } + +static struct device * +unlink_modules(struct device *p) +{ + struct device *next = NULL; + + if (p->priv) { /* Private areas allocated? */ + struct de4x5_private *lp = (struct de4x5_private *)p->priv; + + next = lp->next_module; + if (lp->cache.buf) { /* MAC buffers allocated? */ + kfree(lp->cache.buf); /* Free the MAC buffers */ + } + kfree(lp->cache.priv); /* Free the private area */ + release_region(p->base_addr, (lp->bus == PCI ? + DE4X5_PCI_TOTAL_SIZE : + DE4X5_EISA_TOTAL_SIZE)); + } + unregister_netdev(p); + kfree(p); /* Free the device structure */ + + return next; +} + #endif /* MODULE */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h --- v2.1.36/linux/drivers/net/de4x5.h Sun Feb 2 05:02:05 1997 +++ linux/drivers/net/de4x5.h Mon May 12 10:35:41 1997 @@ -139,7 +139,7 @@ #define CFCS_DST 0x06000000 /* DEVSEL Timing (S) */ #define CFCS_DPR 0x01000000 /* Data Parity Report (S) */ #define CFCS_FBB 0x00800000 /* Fast Back-To-Back (S) */ -#define CFCS_SLE 0x00000100 /* System Error Enable (C) */ +#define CFCS_SEE 0x00000100 /* System Error Enable (C) */ #define CFCS_PER 0x00000040 /* Parity Error Response (C) */ #define CFCS_MO 0x00000004 /* Master Operation (C) */ #define CFCS_MSA 0x00000002 /* Memory Space Access (C) */ @@ -150,8 +150,8 @@ */ #define CFRV_BC 0xff000000 /* Base Class */ #define CFRV_SC 0x00ff0000 /* Subclass */ -#define CFRV_SN 0x000000f0 /* Step Number */ -#define CFRV_RN 0x0000000f /* Revision Number */ +#define CFRV_RN 0x000000f0 /* Revision Number */ +#define CFRV_SN 0x0000000f /* Step Number */ #define BASE_CLASS 0x02000000 /* Indicates Network Controller */ #define SUB_CLASS 0x00000000 /* Indicates Ethernet Controller */ #define STEP_NUMBER 0x00000020 /* Increments for future chips */ @@ -170,12 +170,33 @@ #define CBIO_IOSI 0x00000001 /* I/O Space Indicator (RO, value is 1) */ /* +** PCI Configuration Card Information Structure Register (PCI_CCIS) +*/ +#define CCIS_ROMI 0xf0000000 /* ROM Image */ +#define CCIS_ASO 0x0ffffff8 /* Address Space Offset */ +#define CCIS_ASI 0x00000007 /* Address Space Indicator */ + +/* +** PCI Configuration Subsystem ID Register (PCI_SSID) +*/ +#define SSID_SSID 0xffff0000 /* Subsystem ID */ +#define SSID_SVID 0x0000ffff /* Subsystem Vendor ID */ + +/* ** PCI Configuration Expansion ROM Base Address Register (PCI_CBER) */ #define CBER_MASK 0xfffffc00 /* Expansion ROM Base Address Mask */ #define CBER_ROME 0x00000001 /* ROM Enable */ /* +** PCI Configuration Interrupt Register (PCI_CFIT) +*/ +#define CFIT_MXLT 0xff000000 /* MAX_LAT Value (0.25us periods) */ +#define CFIT_MNGT 0x00ff0000 /* MIN_GNT Value (0.25us periods) */ +#define CFIT_IRQP 0x0000ff00 /* Interrupt Pin */ +#define CFIT_IRQL 0x000000ff /* Interrupt Line */ + +/* ** PCI Configuration Power Management Area Register (PCI_CFPM) */ #define SLEEP 0x80 /* Power Saving Sleep Mode */ @@ -188,6 +209,7 @@ /* ** DC21040 Bus Mode Register (DE4X5_BMR) */ +#define BMR_RML 0x00200000 /* [Memory] Read Multiple */ #define BMR_DBO 0x00100000 /* Descriptor Byte Ordering (Endian) */ #define BMR_TAP 0x000e0000 /* Transmit Automatic Polling */ #define BMR_DAS 0x00010000 /* Diagnostic Address Space */ @@ -198,6 +220,7 @@ #define BMR_BAR 0x00000002 /* Bus ARbitration */ #define BMR_SWR 0x00000001 /* Software Reset */ + /* Timings here are for 10BASE-T/AUI only*/ #define TAP_NOPOLL 0x00000000 /* No automatic polling */ #define TAP_200US 0x00020000 /* TX automatic polling every 200us */ #define TAP_800US 0x00040000 /* TX automatic polling every 800us */ @@ -249,18 +272,21 @@ #define TRBA 0xfffffffc /* TX Descriptor List Start Address */ /* -** DC21040 Status Register (DE4X5_STS) +** Status Register (DE4X5_STS) */ +#define STS_GPI 0x04000000 /* General Purpose Port Interrupt */ #define STS_BE 0x03800000 /* Bus Error Bits */ #define STS_TS 0x00700000 /* Transmit Process State */ #define STS_RS 0x000e0000 /* Receive Process State */ #define STS_NIS 0x00010000 /* Normal Interrupt Summary */ #define STS_AIS 0x00008000 /* Abnormal Interrupt Summary */ #define STS_ER 0x00004000 /* Early Receive */ +#define STS_FBE 0x00002000 /* Fatal Bus Error */ #define STS_SE 0x00002000 /* System Error */ #define STS_LNF 0x00001000 /* Link Fail */ #define STS_FD 0x00000800 /* Full-Duplex Short Frame Received */ #define STS_TM 0x00000800 /* Timer Expired (DC21041) */ +#define STS_ETI 0x00000400 /* Early Transmit Interupt */ #define STS_AT 0x00000400 /* AUI/TP Pin */ #define STS_RWT 0x00000200 /* Receive Watchdog Time-Out */ #define STS_RPS 0x00000100 /* Receive Process Stopped */ @@ -268,6 +294,7 @@ #define STS_RI 0x00000040 /* Receive Interrupt */ #define STS_UNF 0x00000020 /* Transmit Underflow */ #define STS_LNP 0x00000010 /* Link Pass */ +#define STS_ANC 0x00000010 /* Autonegotiation Complete */ #define STS_TJT 0x00000008 /* Transmit Jabber Time-Out */ #define STS_TU 0x00000004 /* Transmit Buffer Unavailable */ #define STS_TPS 0x00000002 /* Transmit Process Stopped */ @@ -300,8 +327,10 @@ #define INT_CANCEL 0x0001ffff /* For zeroing all interrupt sources */ /* -** DC21040 Operation Mode Register (DE4X5_OMR) +** Operation Mode Register (DE4X5_OMR) */ +#define OMR_SC 0x80000000 /* Special Capture Effect Enable */ +#define OMR_RA 0x40000000 /* Receive All */ #define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */ #define OMR_SCR 0x01000000 /* Scrambler Mode */ #define OMR_PCS 0x00800000 /* PCS Function */ @@ -326,27 +355,31 @@ #define OMR_SR 0x00000002 /* Start/Stop Receive */ #define OMR_HP 0x00000001 /* Hash/Perfect Receive Filtering Mode */ -#define TR_72 0x00000000 /* Threshold set to 72 bytes */ -#define TR_96 0x00004000 /* Threshold set to 96 bytes */ -#define TR_128 0x00008000 /* Threshold set to 128 bytes */ -#define TR_160 0x0000c000 /* Threshold set to 160 bytes */ +#define TR_72 0x00000000 /* Threshold set to 72 (128) bytes */ +#define TR_96 0x00004000 /* Threshold set to 96 (256) bytes */ +#define TR_128 0x00008000 /* Threshold set to 128 (512) bytes */ +#define TR_160 0x0000c000 /* Threshold set to 160 (1024) bytes */ /* ** DC21040 Interrupt Mask Register (DE4X5_IMR) */ +#define IMR_GPM 0x04000000 /* General Purpose Port Mask */ #define IMR_NIM 0x00010000 /* Normal Interrupt Summary Mask */ #define IMR_AIM 0x00008000 /* Abnormal Interrupt Summary Mask */ #define IMR_ERM 0x00004000 /* Early Receive Mask */ +#define IMR_FBM 0x00002000 /* Fatal Bus Error Mask */ #define IMR_SEM 0x00002000 /* System Error Mask */ #define IMR_LFM 0x00001000 /* Link Fail Mask */ #define IMR_FDM 0x00000800 /* Full-Duplex (Short Frame) Mask */ #define IMR_TMM 0x00000800 /* Timer Expired Mask (DC21041) */ +#define IMR_ETM 0x00000400 /* Early Transmit Interrupt Mask */ #define IMR_ATM 0x00000400 /* AUI/TP Switch Mask */ #define IMR_RWM 0x00000200 /* Receive Watchdog Time-Out Mask */ #define IMR_RSM 0x00000100 /* Receive Stopped Mask */ #define IMR_RUM 0x00000080 /* Receive Buffer Unavailable Mask */ #define IMR_RIM 0x00000040 /* Receive Interrupt Mask */ #define IMR_UNM 0x00000020 /* Underflow Interrupt Mask */ +#define IMR_ANM 0x00000010 /* Autonegotiation Complete Mask */ #define IMR_LPM 0x00000010 /* Link Pass */ #define IMR_TJM 0x00000008 /* Transmit Time-Out Jabber Mask */ #define IMR_TUM 0x00000004 /* Transmit Buffer Unavailable Mask */ @@ -354,13 +387,7 @@ #define IMR_TIM 0x00000001 /* Transmit Interrupt Mask */ /* -** DC21040 Missed Frames Counter (DE4X5_MFC) -*/ -#define MFC_OVFL 0x00010000 /* Missed Frames Counter Overflow Bit */ -#define MFC_CNTR 0x0000ffff /* Missed Frames Counter Bits */ - -/* -** DC21140 Missed Frames and FIFO Overflow Counters (DE4X5_MFC) +** Missed Frames and FIFO Overflow Counters (DE4X5_MFC) */ #define MFC_FOCO 0x10000000 /* FIFO Overflow Counter Overflow Bit */ #define MFC_FOC 0x0ffe0000 /* FIFO Overflow Counter Bits */ @@ -461,7 +488,7 @@ ** MII Management Auto Negotiation Advertisement Register */ #define MII_ANA_TAF 0x03e0 /* Technology Ability Field */ -#define MII_ANA_T4AM 0x0400 /* T4 Technology Ability Mask */ +#define MII_ANA_T4AM 0x0200 /* T4 Technology Ability Mask */ #define MII_ANA_TXAM 0x0180 /* TX Technology Ability Mask */ #define MII_ANA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ #define MII_ANA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ @@ -476,7 +503,7 @@ #define MII_ANLPA_ACK 0x4000 /* Remote Acknowledge */ #define MII_ANLPA_RF 0x2000 /* Remote Fault */ #define MII_ANLPA_TAF 0x03e0 /* Technology Ability Field */ -#define MII_ANLPA_T4AM 0x0400 /* T4 Technology Ability Mask */ +#define MII_ANLPA_T4AM 0x0200 /* T4 Technology Ability Mask */ #define MII_ANLPA_TXAM 0x0180 /* TX Technology Ability Mask */ #define MII_ANLPA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ #define MII_ANLPA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ @@ -547,6 +574,8 @@ #define SROM_100BASEFF 0x0008 /* 100BASE-FX full duplex */ #define BLOCK_LEN 0x7f /* Extended blocks length mask */ +#define EXT_FIELD 0x40 /* Extended blocks extension field bit */ +#define MEDIA_CODE 0x3f /* Extended blocks media code mask */ /* ** SROM Compact Format Block Masks @@ -589,14 +618,18 @@ #define GEP_CTRL 0x00000100 /* GEP control bit */ /* -** DC21040 SIA Status Register (DE4X5_SISR) +** SIA Status Register (DE4X5_SISR) */ #define SISR_LPC 0xffff0000 /* Link Partner's Code Word */ #define SISR_LPN 0x00008000 /* Link Partner Negotiable */ #define SISR_ANS 0x00007000 /* Auto Negotiation Arbitration State */ -#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected */ +#define SISR_NSN 0x00000800 /* Non Stable NLPs Detected (DC21041) */ +#define SISR_TRF 0x00000800 /* Transmit Remote Fault */ +#define SISR_NSND 0x00000400 /* Non Stable NLPs Detected (DC21142) */ #define SISR_ANR_FDS 0x00000400 /* Auto Negotiate Restart/Full Duplex Sel.*/ +#define SISR_TRA 0x00000200 /* 10BASE-T Receive Port Activity */ #define SISR_NRA 0x00000200 /* Non Selected Port Receive Activity */ +#define SISR_ARA 0x00000100 /* AUI Receive Port Activity */ #define SISR_SRA 0x00000100 /* Selected Port Receive Activity */ #define SISR_DAO 0x00000080 /* PLL All One */ #define SISR_DAZ 0x00000040 /* PLL All Zero */ @@ -606,7 +639,7 @@ #define SISR_LKF 0x00000004 /* Link Fail Status */ #define SISR_NCR 0x00000002 /* Network Connection Error */ #define SISR_PAUI 0x00000001 /* AUI_TP Indication */ -#define SIA_RESET 0x00000000 /* SIA Reset */ +#define SISR_MRA 0x00000001 /* MII Receive Port Activity */ #define ANS_NDIS 0x00000000 /* Nway disable */ #define ANS_TDIS 0x00001000 /* Transmit Disable */ @@ -617,7 +650,7 @@ #define ANS_LCHK 0x00006000 /* Link Check */ /* -** DC21040 SIA Connectivity Register (DE4X5_SICR) +** SIA Connectivity Register (DE4X5_SICR) */ #define SICR_SDM 0xffff0000 /* SIA Diagnostics Mode */ #define SICR_OE57 0x00008000 /* Output Enable 5 6 7 */ @@ -636,14 +669,14 @@ #define SICR_SIM 0x00000040 /* Serial Interface Input Multiplexer */ #define SICR_ENI 0x00000020 /* Encoder Input Multiplexer */ #define SICR_EDP 0x00000010 /* SIA PLL External Input Enable */ -#define SICR_AUI 0x00000008 /* 10Base-T or AUI */ +#define SICR_AUI 0x00000008 /* 10Base-T (0) or AUI (1) */ #define SICR_CAC 0x00000004 /* CSR Auto Configuration */ #define SICR_PS 0x00000002 /* Pin AUI/TP Selection */ #define SICR_SRL 0x00000001 /* SIA Reset */ -#define SICR_RESET 0xffff0000 /* Reset value for SICR */ +#define SIA_RESET 0x00000000 /* SIA Reset Value */ /* -** DC21040 SIA Transmit and Receive Register (DE4X5_STRR) +** SIA Transmit and Receive Register (DE4X5_STRR) */ #define STRR_TAS 0x00008000 /* 10Base-T/AUI Autosensing Enable */ #define STRR_SPP 0x00004000 /* Set Polarity Plus */ @@ -663,8 +696,20 @@ #define STRR_RESET 0xffffffff /* Reset value for STRR */ /* -** DC21040 SIA General Register (DE4X5_SIGR) +** SIA General Register (DE4X5_SIGR) */ +#define SIGR_RMI 0x40000000 /* Receive Match Interrupt */ +#define SIGR_GI1 0x20000000 /* General Port Interrupt 1 */ +#define SIGR_GI0 0x10000000 /* General Port Interrupt 0 */ +#define SIGR_CWE 0x08000000 /* Control Write Enable */ +#define SIGR_RME 0x04000000 /* Receive Match Enable */ +#define SIGR_GEI1 0x02000000 /* GEP Interrupt Enable on Port 1 */ +#define SIGR_GEI0 0x01000000 /* GEP Interrupt Enable on Port 0 */ +#define SIGR_LGS3 0x00800000 /* LED/GEP3 Select */ +#define SIGR_LGS2 0x00400000 /* LED/GEP2 Select */ +#define SIGR_LGS1 0x00200000 /* LED/GEP1 Select */ +#define SIGR_LGS0 0x00100000 /* LED/GEP0 Select */ +#define SIGR_MD 0x000f0000 /* General Purpose Mode and Data */ #define SIGR_LV2 0x00008000 /* General Purpose LED2 value */ #define SIGR_LE2 0x00004000 /* General Purpose LED2 enable */ #define SIGR_FRL 0x00002000 /* Force Receiver Low */ @@ -687,7 +732,8 @@ ** Receive Descriptor Bit Summary */ #define R_OWN 0x80000000 /* Own Bit */ -#define RD_FL 0x7fff0000 /* Frame Length */ +#define RD_FF 0x40000000 /* Filtering Fail */ +#define RD_FL 0x3fff0000 /* Frame Length */ #define RD_ES 0x00008000 /* Error Summary */ #define RD_LE 0x00004000 /* Length Error */ #define RD_DT 0x00003000 /* Data Type */ @@ -699,6 +745,7 @@ #define RD_CS 0x00000040 /* Collision Seen */ #define RD_FT 0x00000020 /* Frame Type */ #define RD_RJ 0x00000010 /* Receive Watchdog */ +#define RD_RE 0x00000008 /* Report on MII Error */ #define RD_DB 0x00000004 /* Dribbling Bit */ #define RD_CE 0x00000002 /* CRC Error */ #define RD_OF 0x00000001 /* Overflow */ @@ -734,40 +781,39 @@ #define TD_TCH 0x01000000 /* Second Address Chained */ #define TD_DPD 0x00800000 /* Disabled Padding */ #define TD_FT0 0x00400000 /* Filtering Type */ -#define TD_RBS2 0x003ff800 /* Buffer 2 Size */ -#define TD_RBS1 0x000007ff /* Buffer 1 Size */ +#define TD_TBS2 0x003ff800 /* Buffer 2 Size */ +#define TD_TBS1 0x000007ff /* Buffer 1 Size */ #define PERFECT_F 0x00000000 #define HASH_F TD_FT0 #define INVERSE_F TD_FT1 -#define HASH_O_F TD_FT1| TD_F0 +#define HASH_O_F (TD_FT1 | TD_F0) /* ** Media / mode state machine definitions */ -#define NC 0x0000 /* No Connection */ -#define TP 0x0001 /* 10Base-T */ -#define TP_NW 0x0002 /* 10Base-T with Nway */ -#define BNC 0x0004 /* Thinwire */ -#define AUI 0x0008 /* Thickwire */ +#define NC 0x0000 /* No Connection */ +#define TP 0x0001 /* 10Base-T */ +#define TP_NW 0x0002 /* 10Base-T with Nway */ +#define BNC 0x0004 /* Thinwire */ +#define AUI 0x0008 /* Thickwire */ #define BNC_AUI 0x0010 /* BNC/AUI on DC21040 indistinguishable */ -#define ANS 0x0020 /* Intermediate AutoNegotiation State */ -#define ANS_1 0x0021 /* Intermediate AutoNegotiation State */ - -#define _10Mb 0x0040 /* 10Mb/s Ethernet */ -#define _100Mb 0x0080 /* 100Mb/s Ethernet */ -#define SPD_DET 0x0100 /* Parallel speed detection */ -#define INIT 0x0200 /* Initial state */ -#define EXT_SIA 0x0400 /* External SIA for motherboard chip */ -#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */ -#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */ -#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */ -#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */ -#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */ -#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */ +#define ANS 0x0020 /* Intermediate AutoNegotiation State */ +#define _10Mb 0x0040 /* 10Mb/s Ethernet */ +#define _100Mb 0x0080 /* 100Mb/s Ethernet */ +#define SPD_DET 0x0100 /* Parallel speed detection */ +#define INIT 0x0200 /* Initial state */ +#define EXT_SIA 0x0400 /* External SIA for motherboard chip */ +#define ANS_SUSPECT 0x0802 /* Suspect the ANS (TP) port is down */ +#define TP_SUSPECT 0x0803 /* Suspect the TP port is down */ +#define BNC_AUI_SUSPECT 0x0804 /* Suspect the BNC or AUI port is down */ +#define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */ +#define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */ +#define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */ +#define MII 0x1000 /* MII on the 21143 */ -#define AUTO 0x4000 /* Auto sense the media or speed */ -#define TIMER_CB 0x80000000 /* Timer callback detection */ +#define AUTO 0x4000 /* Auto sense the media or speed */ +#define TIMER_CB 0x80000000 /* Timer callback detection */ /* ** DE4X5 DEBUG Options @@ -798,7 +844,6 @@ #define POLL_DEMAND 1 #define LOST_MEDIA_THRESHOLD 3 -#define LOST_MEDIA (lp->lostMedia > LOST_MEDIA_THRESHOLD) #define MASK_INTERRUPTS 1 #define UNMASK_INTERRUPTS 0 @@ -859,7 +904,7 @@ }\ omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\ outl(omr, DE4X5_OMR);\ - lp->cache.gep = 0;\ + if (!lp->useSROM) lp->cache.gep = 0;\ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ omr |= (lp->fdx ? OMR_FDX : 0);\ @@ -887,7 +932,7 @@ }\ if (fdx) omr |= OMR_FDX;\ outl(omr, DE4X5_OMR);\ - lp->cache.gep = 0;\ + if (!lp->useSROM) lp->cache.gep = 0;\ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ omr |= (lp->fdx ? OMR_FDX : 0);\ @@ -906,7 +951,6 @@ mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\ omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ outl(omr, DE4X5_OMR);\ - lp->cache.gep = 0;\ } else if (lp->useSROM && !lp->useMII) {\ omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\ outl(omr, DE4X5_OMR);\ @@ -934,7 +978,7 @@ ** Recognised commands for the driver */ #define DE4X5_GET_HWADDR 0x01 /* Get the hardware address */ -#define DE4X5_SET_HWADDR 0x02 /* Get the hardware address */ +#define DE4X5_SET_HWADDR 0x02 /* Set the hardware address */ #define DE4X5_SET_PROM 0x03 /* Set Promiscuous Mode */ #define DE4X5_CLR_PROM 0x04 /* Clear Promiscuous Mode */ #define DE4X5_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v2.1.36/linux/drivers/net/depca.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/depca.c Mon May 12 10:35:41 1997 @@ -804,7 +804,7 @@ dev_tint(dev); } else if (skb->len > 0) { /* Enforce 1 process per h/w access */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); status = -1; } else { diff -u --recursive --new-file v2.1.36/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.1.36/linux/drivers/net/dlci.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/dlci.c Mon May 12 10:35:41 1997 @@ -248,7 +248,7 @@ dlp = dev->priv; - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name); else { diff -u --recursive --new-file v2.1.36/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.1.36/linux/drivers/net/eepro.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/eepro.c Mon May 12 10:35:41 1997 @@ -714,7 +714,7 @@ } /* Block a timer-based transmit from overlapping. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff -u --recursive --new-file v2.1.36/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.1.36/linux/drivers/net/eepro100.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/eepro100.c Mon May 12 10:35:41 1997 @@ -1033,7 +1033,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. If this ever occurs the queue layer is doing something evil! */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < TX_TIMEOUT - 2) return 1; diff -u --recursive --new-file v2.1.36/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v2.1.36/linux/drivers/net/eexpress.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/eexpress.c Mon May 12 10:35:41 1997 @@ -94,6 +94,7 @@ #include #include #include +#include #include #include @@ -301,7 +302,7 @@ * checks for presence of EtherExpress card */ -int express_probe(struct device *dev) +__initfunc(int express_probe(struct device *dev)) { unsigned short *port; static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 }; @@ -525,7 +526,7 @@ } } - if (set_bit(0,(void *)&dev->tbusy)) + if (test_and_set_bit(0,(void *)&dev->tbusy)) { lp->stats.tx_dropped++; } @@ -913,7 +914,7 @@ * than one card in a machine. */ -static int eexp_hw_probe(struct device *dev, unsigned short ioaddr) +__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)) { unsigned short hw_addr[3]; unsigned char buswidth; @@ -1034,8 +1035,8 @@ * Read a word from the EtherExpress on-board serial EEPROM. * The EEPROM contains 64 words of 16 bits. */ -static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, - unsigned char location) +__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, + unsigned char location)) { unsigned short cmd = 0x180|(location&0x7f); unsigned short rval = 0,wval = EC_CS|i586_RST; diff -u --recursive --new-file v2.1.36/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.1.36/linux/drivers/net/eth16i.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/eth16i.c Mon May 12 10:35:41 1997 @@ -932,7 +932,7 @@ /* Turn off TX interrupts */ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); - if(set_bit(0, (void *)&dev->tbusy) != 0) + if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff -u --recursive --new-file v2.1.36/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.1.36/linux/drivers/net/ewrk3.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/ewrk3.c Mon May 12 10:35:41 1997 @@ -767,7 +767,7 @@ ** Block a timer-based transmit from overlapping. This could better be ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); DISABLE_IRQs; /* So that the page # remains correct */ @@ -783,7 +783,7 @@ /* ** Set up shared memory window and pointer into the window */ - while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ + while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { outb(page, EWRK3_IOPR); } else if (lp->shmem_length == SHMEM_2K) { @@ -953,7 +953,7 @@ ** Preempt any process using the current page register. Check for ** an existing lock to reduce time taken in I/O transactions. */ - if ((tmpLock = set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */ + if ((tmpLock = test_and_set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */ if (lp->shmem_length == IO_ONLY) { /* Get existing page */ tmpPage = inb(EWRK3_IOPR); } else { @@ -1217,7 +1217,7 @@ u16 hashcode; s32 crc, poly = CRC_POLYNOMIAL_LE; - while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ + while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { outb(0, EWRK3_IOPR); @@ -1723,7 +1723,7 @@ break; case EWRK3_GET_MCA: /* Get the multicast address table */ if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) { - while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ + while (test_and_set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ if (lp->shmem_length == IO_ONLY) { outb(0, EWRK3_IOPR); outw(PAGE0_HTE, EWRK3_PIR1); diff -u --recursive --new-file v2.1.36/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c --- v2.1.36/linux/drivers/net/fmv18x.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/fmv18x.c Mon May 12 10:35:41 1997 @@ -348,7 +348,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff -u --recursive --new-file v2.1.36/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c --- v2.1.36/linux/drivers/net/hdlcdrv.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/hdlcdrv.c Mon May 12 10:35:41 1997 @@ -288,7 +288,7 @@ if (!s || s->magic != HDLCDRV_MAGIC) return; - if (set_bit(0, &s->hdlcrx.in_hdlc_rx)) + if (test_and_set_bit(0, &s->hdlcrx.in_hdlc_rx)) return; while (!hdlcdrv_hbuf_empty(&s->hdlcrx.hbuf)) { @@ -387,7 +387,7 @@ if (!s || s->magic != HDLCDRV_MAGIC) return; - if (set_bit(0, &s->hdlctx.in_hdlc_tx)) + if (test_and_set_bit(0, &s->hdlctx.in_hdlc_tx)) return; for (;;) { if (s->hdlctx.numbits >= 16) { diff -u --recursive --new-file v2.1.36/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.1.36/linux/drivers/net/ibmtr.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/ibmtr.c Mon May 12 10:35:41 1997 @@ -1495,7 +1495,7 @@ return 0; } - if (set_bit(0,(void *)&dev->tbusy)!=0) + if (test_and_set_bit(0,(void *)&dev->tbusy)!=0) DPRINTK("Transmitter access conflict\n"); else { /* Save skb; we'll need it when the adapter asks for the data */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.1.36/linux/drivers/net/lance.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/lance.c Mon May 12 10:35:41 1997 @@ -834,12 +834,12 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } - if (set_bit(0, (void*)&lp->lock) != 0) { + if (test_and_set_bit(0, (void*)&lp->lock) != 0) { if (lance_debug > 0) printk("%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.1.36/linux/drivers/net/ltpc.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/ltpc.c Mon May 12 10:35:41 1997 @@ -1259,7 +1259,7 @@ if(debug&DEBUG_VERBOSE) printk("waiting\n"); /* if it's in process, wait a bit for it to finish */ timeout = jiffies+HZ; - add_timer(<pc_timer) + add_timer(<pc_timer); while(del_timer(<pc_timer) && (timeout > jiffies)) { add_timer(<pc_timer); diff -u --recursive --new-file v2.1.36/linux/drivers/net/mkiss.c linux/drivers/net/mkiss.c --- v2.1.36/linux/drivers/net/mkiss.c Wed Apr 23 19:01:19 1997 +++ linux/drivers/net/mkiss.c Mon May 12 10:35:41 1997 @@ -109,7 +109,7 @@ break; /* Not in use ? */ - if (!set_bit(AXF_INUSE, &axp->ctrl.flags)) + if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags)) break; } @@ -165,7 +165,7 @@ if (ax->xbuff) kfree(ax->xbuff); ax->xbuff = NULL; - if (!clear_bit(AXF_INUSE, &ax->flags)) + if (!test_and_clear_bit(AXF_INUSE, &ax->flags)) printk(KERN_ERR "%s: ax_free for already free unit.\n", ax->dev->name); } @@ -244,7 +244,7 @@ /* Set the "sending" flag. This must be atomic, hence the ASM. */ static inline void ax_lock(struct ax_disp *ax) { - if (set_bit(0, (void *)&ax->dev->tbusy)) + if (test_and_set_bit(0, (void *)&ax->dev->tbusy)) printk(KERN_ERR "%s: trying to lock already locked device!\n", ax->dev->name); } @@ -252,7 +252,7 @@ /* Clear the "sending" flag. This must be atomic, hence the ASM. */ static inline void ax_unlock(struct ax_disp *ax) { - if (!clear_bit(0, (void *)&ax->dev->tbusy)) + if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy)) printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", ax->dev->name); } @@ -551,7 +551,7 @@ /* Read the characters out of the buffer */ while (count--) { if (fp != NULL && *fp++) { - if (!set_bit(AXF_ERROR, &ax->flags)) + if (!test_and_set_bit(AXF_ERROR, &ax->flags)) ax->rx_errors++; cp++; continue; @@ -709,7 +709,7 @@ if (test_bit(AXF_KEEPTEST, &ax->flags)) clear_bit(AXF_KEEPTEST, &ax->flags); - if (!clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) + if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) ax_bump(ax); clear_bit(AXF_ESCAPE, &ax->flags); @@ -720,11 +720,11 @@ set_bit(AXF_ESCAPE, &ax->flags); return; case ESC_ESC: - if (clear_bit(AXF_ESCAPE, &ax->flags)) + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) s = ESC; break; case ESC_END: - if (clear_bit(AXF_ESCAPE, &ax->flags)) + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) s = END; break; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.1.36/linux/drivers/net/myri_sbus.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/myri_sbus.c Mon May 12 10:35:41 1997 @@ -584,7 +584,7 @@ return 0; } - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { DTX(("tbusy, maybe a race? returning 1\n")); printk("%s: Transmitter access conflict.\n", dev->name); return 1; diff -u --recursive --new-file v2.1.36/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.1.36/linux/drivers/net/ni52.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/ni52.c Mon May 12 10:35:41 1997 @@ -1171,12 +1171,12 @@ return 0; } - if (set_bit(0, (void*)&dev->tbusy)) { + if (test_and_set_bit(0, (void*)&dev->tbusy)) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } #if(NUM_XMIT_BUFFS > 1) - else if(set_bit(0,(void *) &p->lock)) { + else if(test_and_set_bit(0,(void *) &p->lock)) { printk("%s: Queue was locked\n",dev->name); return 1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/ni65.c linux/drivers/net/ni65.c --- v2.1.36/linux/drivers/net/ni65.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/ni65.c Mon May 12 10:35:41 1997 @@ -804,7 +804,7 @@ return; } - if(set_bit(0,(int *) &dev->interrupt)) { + if(test_and_set_bit(0,(int *) &dev->interrupt)) { printk("ni65: oops .. interrupt while proceeding interrupt\n"); return; } @@ -1087,11 +1087,11 @@ dev->trans_start = jiffies; } - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name); return 1; } - if (set_bit(0, (void*)&p->lock)) { + if (test_and_set_bit(0, (void*)&p->lock)) { printk(KERN_ERR "%s: Queue was locked.\n", dev->name); return 1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c --- v2.1.36/linux/drivers/net/pcnet32.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/pcnet32.c Mon May 12 10:35:41 1997 @@ -594,12 +594,12 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } - if (set_bit(0, (void*)&lp->lock) != 0) { + if (test_and_set_bit(0, (void*)&lp->lock) != 0) { if (pcnet32_debug > 0) printk("%s: tx queue lock!.\n", dev->name); /* don't clear dev->tbusy flag. */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.1.36/linux/drivers/net/plip.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/plip.c Mon May 12 10:35:41 1997 @@ -910,7 +910,7 @@ return 0; } - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.1.36/linux/drivers/net/ppp.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/ppp.c Mon May 12 10:35:41 1997 @@ -1291,7 +1291,7 @@ * The total length includes the protocol data. * Lock the user information buffer. */ - if (set_bit (0, &ppp->ubuf->locked)) { + if (test_and_set_bit (0, &ppp->ubuf->locked)) { if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_us_queue: can't get lock\n"); @@ -1698,7 +1698,7 @@ if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) return 0; - if (set_bit (0, &ppp->ubuf->locked) != 0) { + if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) { if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_read: sleeping(ubuf)\n"); @@ -2584,7 +2584,7 @@ poll_wait(&ppp->write_wait, wait); /* Must lock the user buffer area while checking. */ - if(set_bit(0, &ppp->ubuf->locked) == 0) { + if(test_and_set_bit(0, &ppp->ubuf->locked) == 0) { if(ppp->ubuf->head != ppp->ubuf->tail) mask |= POLLIN | POLLRDNORM; clear_bit(0, &ppp->ubuf->locked); @@ -3130,7 +3130,7 @@ while (ctl) { ppp = ctl2ppp (ctl); - if (!set_bit(0, &ppp->inuse)) { + if (!test_and_set_bit(0, &ppp->inuse)) { if (ppp->sc_xfer == pid_value) { ppp->sc_xfer = 0; return (ppp); @@ -3160,7 +3160,7 @@ while (ctl) { ppp = ctl2ppp (ctl); - if (!set_bit(0, &ppp->inuse)) + if (!test_and_set_bit(0, &ppp->inuse)) return (ppp); ctl = ctl->next; if (++if_num == max_dev) diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.1.36/linux/drivers/net/sdla.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/sdla.c Mon May 12 10:35:41 1997 @@ -657,7 +657,7 @@ if (skb == NULL) return(0); - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name); else { diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.36/linux/drivers/net/sdla_fr.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/sdla_fr.c Mon May 12 10:35:41 1997 @@ -440,7 +440,7 @@ if (dev->start) return -EBUSY /* only one open is allowed */ ; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; if (!card->open_cnt) @@ -489,7 +489,7 @@ fr_channel_t* chan = dev->priv; sdla_t* card = chan->card; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; dev->start = 0; @@ -574,7 +574,7 @@ sdla_t* card = chan->card; int retry = 0; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", @@ -584,7 +584,7 @@ return 1; } - if (set_bit(0, (void*)&dev->tbusy)) + if (test_and_set_bit(0, (void*)&dev->tbusy)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: Tx collision on interface %s!\n", diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.36/linux/drivers/net/sdla_ppp.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/sdla_ppp.c Mon May 12 10:35:41 1997 @@ -286,7 +286,7 @@ if (dev->start) return -EBUSY /* only one open is allowed */ ; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) @@ -365,7 +365,7 @@ { sdla_t* card = dev->priv; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; dev->start = 0; @@ -441,7 +441,7 @@ sdla_t* card = dev->priv; int retry = 0; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", @@ -451,7 +451,7 @@ return 1; } - if (set_bit(0, (void*)&dev->tbusy)) + if (test_and_set_bit(0, (void*)&dev->tbusy)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: Tx collision on interface %s!\n", diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c --- v2.1.36/linux/drivers/net/sdla_x25.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/sdla_x25.c Mon May 12 10:35:41 1997 @@ -476,7 +476,7 @@ if (dev->start) return -EBUSY /* only one open is allowed */ ; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; @@ -503,7 +503,7 @@ x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; ; dev->start = 0; @@ -590,7 +590,7 @@ sdla_t* card = chan->card; int retry = 0, queued = 0; - if (set_bit(0, (void*)&card->wandev.critical)) + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: if_send() hit critical section!\n", @@ -600,7 +600,7 @@ return 1; } - if (set_bit(0, (void*)&dev->tbusy)) + if (test_and_set_bit(0, (void*)&dev->tbusy)) { #ifdef _DEBUG_ printk(KERN_INFO "%s: Tx collision on interface %s!\n", diff -u --recursive --new-file v2.1.36/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c --- v2.1.36/linux/drivers/net/sdlamain.c Sun Feb 2 05:18:41 1997 +++ linux/drivers/net/sdlamain.c Mon May 12 10:35:41 1997 @@ -332,7 +332,7 @@ if (wandev->state == WAN_UNCONFIGURED) return 0 ; - if (set_bit(0, (void*)&wandev->critical)) + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN ; card = wandev->private; @@ -364,7 +364,7 @@ if (wandev->state == WAN_UNCONFIGURED) return -ENODEV ; - if (set_bit(0, (void*)&wandev->critical)) + if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN ; switch (cmd) @@ -514,7 +514,7 @@ sdla_t* card = &card_array[i]; if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && - !set_bit(0, (void*)&card->wandev.critical)) + !test_and_set_bit(0, (void*)&card->wandev.critical)) { card->poll(card); card->wandev.critical = 0; diff -u --recursive --new-file v2.1.36/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.1.36/linux/drivers/net/seeq8005.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/seeq8005.c Mon May 12 10:35:41 1997 @@ -392,7 +392,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff -u --recursive --new-file v2.1.36/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.1.36/linux/drivers/net/sk_g16.c Fri Apr 4 08:52:21 1997 +++ linux/drivers/net/sk_g16.c Mon May 12 10:35:41 1997 @@ -68,6 +68,7 @@ #include #include #include +#include #include #include @@ -532,7 +533,7 @@ * (detachable devices only). */ -int SK_init(struct device *dev) +__initfunc(int SK_init(struct device *dev)) { int ioaddr = 0; /* I/O port address used for POS regs */ int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ @@ -616,7 +617,7 @@ * 94/06/30 pwe SK_ADDR now checked and at the correct place -*/ -int SK_probe(struct device *dev, short ioaddr) +__initfunc(int SK_probe(struct device *dev, short ioaddr)) { int i,j; /* Counters */ int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ @@ -1210,7 +1211,7 @@ * This means check if we are already in. */ - if (set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ + if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ { printk("%s: Transmitter access conflict.\n", dev->name); } @@ -1740,7 +1741,7 @@ * YY/MM/DD uid Description -*/ -unsigned int SK_rom_addr(void) +__initfunc(unsigned int SK_rom_addr(void)) { int i,j; int rom_found = 0; diff -u --recursive --new-file v2.1.36/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c --- v2.1.36/linux/drivers/net/skeleton.c Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/skeleton.c Mon May 12 10:35:41 1997 @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -70,7 +71,7 @@ /* First, a few definitions that the brave might change. */ /* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int netcard_portlist[] = +static unsigned int netcard_portlist[] __initdata = { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0}; /* use 0 for production, 1 for verification, >2 for debug */ @@ -126,8 +127,8 @@ struct netdev_entry netcard_drv = {cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist}; #else -int -netcard_probe(struct device *dev) +__initfunc(int +netcard_probe(struct device *dev)) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -154,7 +155,7 @@ * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */ -static int netcard_probe1(struct device *dev, int ioaddr) +__initfunc(static int netcard_probe1(struct device *dev, int ioaddr)) { static unsigned version_printed = 0; int i; @@ -365,7 +366,7 @@ * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff -u --recursive --new-file v2.1.36/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v2.1.36/linux/drivers/net/slip.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/slip.c Mon May 12 10:35:41 1997 @@ -123,7 +123,7 @@ if (slp == NULL) break; /* Not in use ? */ - if (!set_bit(SLF_INUSE, &slp->ctrl.flags)) + if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags)) break; } /* SLP is set.. */ @@ -207,7 +207,7 @@ sl->slcomp = NULL; #endif - if (!clear_bit(SLF_INUSE, &sl->flags)) { + if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { printk("%s: sl_free for already free unit.\n", sl->dev->name); } } @@ -317,7 +317,7 @@ static inline void sl_lock(struct slip *sl) { - if (set_bit(0, (void *) &sl->dev->tbusy)) { + if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) { printk("%s: trying to lock already locked device!\n", sl->dev->name); } } @@ -327,7 +327,7 @@ static inline void sl_unlock(struct slip *sl) { - if (!clear_bit(0, (void *)&sl->dev->tbusy)) { + if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) { printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); } } @@ -661,7 +661,7 @@ /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { - if (!set_bit(SLF_ERROR, &sl->flags)) { + if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { sl->rx_errors++; } cp++; @@ -843,7 +843,7 @@ if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags); - if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { sl_bump(sl); } clear_bit(SLF_ESCAPE, &sl->flags); @@ -854,12 +854,12 @@ set_bit(SLF_ESCAPE, &sl->flags); return; case ESC_ESC: - if (clear_bit(SLF_ESCAPE, &sl->flags)) { + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) { s = ESC; } break; case ESC_END: - if (clear_bit(SLF_ESCAPE, &sl->flags)) { + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) { s = END; } break; @@ -928,7 +928,7 @@ if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags); - if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { sl_bump(sl); } sl->rcount = 0; diff -u --recursive --new-file v2.1.36/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.1.36/linux/drivers/net/smc9194.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/smc9194.c Mon May 12 10:35:41 1997 @@ -1245,7 +1245,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n"); dev_kfree_skb (skb, FREE_WRITE); } else { diff -u --recursive --new-file v2.1.36/linux/drivers/net/soundmodem/sm.c linux/drivers/net/soundmodem/sm.c --- v2.1.36/linux/drivers/net/soundmodem/sm.c Fri Apr 4 08:52:22 1997 +++ linux/drivers/net/soundmodem/sm.c Mon May 12 10:35:41 1997 @@ -56,6 +56,7 @@ #include #include #include +#include #include "sm.h" /* --------------------------------------------------------------------- */ @@ -662,10 +663,7 @@ /* --------------------------------------------------------------------- */ -#ifdef MODULE -static -#endif /* MODULE */ -int sm_init(void) +__initfunc(int sm_init(void)) { int i, j, found = 0; char set_hw = 1; @@ -800,7 +798,7 @@ * modem: afsk1200, fsk9600 */ -void sm_setup(char *str, int *ints) +__initfunc(void sm_setup(char *str, int *ints)) { int i; diff -u --recursive --new-file v2.1.36/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.1.36/linux/drivers/net/strip.c Thu Feb 27 10:57:31 1997 +++ linux/drivers/net/strip.c Mon May 12 10:35:41 1997 @@ -891,7 +891,7 @@ */ strip_info->idle_timer.expires = jiffies + HZ; add_timer(&strip_info->idle_timer); - if (!clear_bit(0, (void *)&strip_info->dev.tbusy)) + if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy)) printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", strip_info->dev.name); } @@ -1745,7 +1745,7 @@ printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); return(1); } - if (set_bit(0, (void *) &strip_info->dev.tbusy)) return(1); + if (test_and_set_bit(0, (void *) &strip_info->dev.tbusy)) return(1); del_timer(&strip_info->idle_timer); /* See if someone has been ifconfigging */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.1.36/linux/drivers/net/sunhme.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/sunhme.c Mon May 12 10:35:41 1997 @@ -1898,7 +1898,7 @@ } } - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("happy meal: Transmitter access conflict.\n"); return 1; } @@ -1955,7 +1955,7 @@ return 0; } - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("happy meal: Transmitter access conflict.\n"); return 1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.1.36/linux/drivers/net/sunlance.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/sunlance.c Mon May 12 10:35:41 1997 @@ -800,7 +800,7 @@ } /* Block a timer-based transmit from overlapping. */ - if (set_bit (0, (void *) &dev->tbusy) != 0) { + if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) { printk ("Transmitter access conflict.\n"); return -1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.1.36/linux/drivers/net/sunqe.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/sunqe.c Mon May 12 10:35:41 1997 @@ -720,7 +720,7 @@ if(dev->tbusy) return 1; - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } @@ -762,7 +762,7 @@ if(dev->tbusy) return 1; - if(set_bit(0, (void *) &dev->tbusy) != 0) { + if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.1.36/linux/drivers/net/tulip.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/tulip.c Mon May 12 10:35:41 1997 @@ -863,7 +863,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. If this ever occurs the queue layer is doing something evil! */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.1.36/linux/drivers/net/wavelan.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/wavelan.c Mon May 12 10:35:41 1997 @@ -64,8 +64,8 @@ /* * Translate PSA irq parameter to irq number */ -static int -wv_psa_to_irq(u_char irqval) +__initfunc(static int +wv_psa_to_irq(u_char irqval)) { int irq; @@ -895,7 +895,7 @@ net_local * lp = (net_local *)dev->priv; /* Check if we can do it now ! */ - if(!(dev->start) || (set_bit(0, (void *)&dev->tbusy) != 0)) + if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0)) { lp->reconfig_82586 = 1; #ifdef DEBUG_CONFIG_INFO @@ -2799,7 +2799,7 @@ * Block a timer-based transmit from overlapping. * In other words, prevent reentering this routine. */ - if(set_bit(0, (void *)&dev->tbusy) != 0) + if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) #ifdef DEBUG_TX_ERROR printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name); #endif @@ -3999,8 +3999,8 @@ * device structure * (called by wavelan_probe() & via init_module()) */ -static int -wavelan_config(device * dev) +__initfunc(static int +wavelan_config(device * dev)) { u_long ioaddr = dev->base_addr; u_char irq_mask; @@ -4112,11 +4112,9 @@ * the initial value of dev->base_addr. * We follow the example in drivers/net/ne.c.) * (called in "Space.c") - * As this function is called outside the wavelan module, it should be - * declared extern, but it seem to cause troubles... */ -/* extern */ int -wavelan_probe(device * dev) +__initfunc(int +wavelan_probe(device * dev)) { short base_addr; mac_addr mac; /* Mac address (check wavelan existence) */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h --- v2.1.36/linux/drivers/net/wavelan.p.h Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/wavelan.p.h Mon May 12 10:35:41 1997 @@ -305,6 +305,7 @@ #include #include #include +#include #include /* Wireless extensions */ diff -u --recursive --new-file v2.1.36/linux/drivers/net/x25_asy.c linux/drivers/net/x25_asy.c --- v2.1.36/linux/drivers/net/x25_asy.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/x25_asy.c Mon May 12 10:35:41 1997 @@ -59,7 +59,7 @@ if (slp == NULL) break; /* Not in use ? */ - if (!set_bit(SLF_INUSE, &slp->ctrl.flags)) + if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags)) break; } /* SLP is set.. */ @@ -124,7 +124,7 @@ } sl->xbuff = NULL; - if (!clear_bit(SLF_INUSE, &sl->flags)) { + if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { printk("%s: x25_asy_free for already free unit.\n", sl->dev->name); } } @@ -201,7 +201,7 @@ static inline void x25_asy_lock(struct x25_asy *sl) { - if (set_bit(0, (void *) &sl->dev->tbusy)) + if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) printk("%s: trying to lock already locked device!\n", sl->dev->name); } @@ -210,7 +210,7 @@ static inline void x25_asy_unlock(struct x25_asy *sl) { - if (!clear_bit(0, (void *)&sl->dev->tbusy)) + if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); } @@ -587,7 +587,7 @@ /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { - if (!set_bit(SLF_ERROR, &sl->flags)) { + if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { sl->rx_errors++; } cp++; @@ -736,7 +736,7 @@ switch(s) { case X25_END: - if (!clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { x25_asy_bump(sl); } @@ -750,7 +750,7 @@ case X25_ESCAPE(X25_ESC): case X25_ESCAPE(X25_END): - if (clear_bit(SLF_ESCAPE, &sl->flags)) + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) s = X25_UNESCAPE(s); break; } diff -u --recursive --new-file v2.1.36/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v2.1.36/linux/drivers/net/znet.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/znet.c Mon May 12 10:35:41 1997 @@ -351,7 +351,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (set_bit(0, (void*)&dev->tbusy) != 0) + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; diff -u --recursive --new-file v2.1.36/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.1.36/linux/drivers/pci/pci.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/pci/pci.c Mon May 12 10:35:42 1997 @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -576,8 +577,8 @@ /* * Turn on/off PCI bridge optimization. This should allow benchmarking. */ -static void burst_bridge(unsigned char bus, unsigned char devfn, - unsigned char pos, int turn_on) +__initfunc(static void burst_bridge(unsigned char bus, unsigned char devfn, + unsigned char pos, int turn_on)) { #ifdef CONFIG_PCI_OPTIMIZE struct bridge_mapping_type *bmap; @@ -791,7 +792,7 @@ * pci_malloc() returns initialized memory of size SIZE. Can be * used only while pci_init() is active. */ -static void *pci_malloc(long size, unsigned long *mem_startp) +__initfunc(static void *pci_malloc(long size, unsigned long *mem_startp)) { void *mem; @@ -805,7 +806,7 @@ } -static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp) +__initfunc(static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)) { unsigned int devfn, l, max; unsigned char cmd, tmp, hdr_type = 0; @@ -980,12 +981,12 @@ } -unsigned long pci_init (unsigned long mem_start, unsigned long mem_end) +__initfunc(unsigned long pci_init (unsigned long mem_start, unsigned long mem_end)) { mem_start = pcibios_init(mem_start, mem_end); if (!pcibios_present()) { - printk("pci_init: no BIOS32 detected\n"); + printk("pci_init: no PCI BIOS detected\n"); return mem_start; } diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c --- v2.1.36/linux/drivers/sbus/audio/amd7930.c Mon Mar 17 14:54:27 1997 +++ linux/drivers/sbus/audio/amd7930.c Mon May 12 10:35:42 1997 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.1.36/linux/drivers/sbus/audio/cs4231.c Mon Mar 17 14:54:28 1997 +++ linux/drivers/sbus/audio/cs4231.c Mon May 12 10:35:42 1997 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c --- v2.1.36/linux/drivers/sbus/char/creator.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/creator.c Mon May 12 10:35:42 1997 @@ -47,52 +47,3 @@ fb->unblank = 0; fb->type.fb_depth = 8; } -/* - * creator.c: Linux/Sun Ultra Creator console support. - * - * Copyright (C) 1997 MIguel de Icaza (miguel@nuclecu.unam.mx) - * - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../../char/vt_kern.h" -#include "../../char/selection.h" -#include "../../char/console_struct.h" -#include "fb.h" - -__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io)) -{ - uint bases [2]; - unsigned long *p; - - if (!creator) { - prom_getproperty (con_node, "address", (char *) &bases[0], 4); - prom_printf ("Bases: %x %x\n", bases [0], bases [1]); - p = (unsigned long *) creator = bases[0]; - fb->base = creator; - fb->base = 0xff168000; - } - - fb->type.fb_cmsize = 256; - fb->mmap = 0; - fb->loadcmap = 0; - fb->setcursor = 0; - fb->setcursormap = 0; - fb->setcurshape = 0; - fb->ioctl = 0; - fb->switch_from_graph = 0; - fb->postsetup = sun_cg_postsetup; - fb->reset = 0; - fb->blank = 0; - fb->unblank = 0; - fb->type.fb_depth = 8; -} diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.1.36/linux/drivers/sbus/char/sunkbd.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/sunkbd.c Mon May 12 17:39:50 1997 @@ -487,7 +487,7 @@ add_timer (&auto_repeat_timer); } } - rep = set_bit(keycode, key_down); + rep = test_and_set_bit(keycode, key_down); } if(raw_mode) diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.1.36/linux/drivers/sbus/char/sunserial.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/sbus/char/sunserial.c Mon May 12 17:39:50 1997 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.38 1997/04/14 17:05:00 jj Exp $ +/* $Id: sunserial.c,v 1.39 1997/04/23 07:45:26 ecd Exp $ * serial.c: Serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -687,7 +687,7 @@ if (!tty) return; - if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); @@ -866,10 +866,10 @@ i = cflag & CBAUD; if (cflag & CBAUDEX) { i &= ~CBAUDEX; - if (i != 1) + if (i != 5) info->tty->termios->c_cflag &= ~CBAUDEX; else - i += 15; + i = 16; } if (i == 15) { if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_HI) @@ -1857,7 +1857,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.38 $"; + char *revision = "$Revision: 1.39 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/vfc.h linux/drivers/sbus/char/vfc.h --- v2.1.36/linux/drivers/sbus/char/vfc.h Mon Apr 14 16:28:14 1997 +++ linux/drivers/sbus/char/vfc.h Mon May 12 10:35:42 1997 @@ -157,10 +157,16 @@ #define VFC_STATUS_CAPTURE 0x08000000 -#ifdef VFC_DEBUG -#define VFC_DEBUG_PRINTK(a) printk a +#ifdef VFC_IOCTL_DEBUG +#define VFC_IOCTL_DEBUG_PRINTK(a) printk a #else -#define VFC_DEBUG_PRINTK(a) +#define VFC_IOCTL_DEBUG_PRINTK(a) +#endif + +#ifdef VFC_I2C_DEBUG +#define VFC_I2C_DEBUG_PRINTK(a) printk a +#else +#define VFC_I2C_DEBUG_PRINTK(a) #endif #endif /* _LINUX_VFC_H_ */ diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.1.36/linux/drivers/sbus/char/vfc_dev.c Mon Apr 14 16:28:14 1997 +++ linux/drivers/sbus/char/vfc_dev.c Mon May 12 10:35:42 1997 @@ -3,11 +3,11 @@ * * Driver for the Videopix Frame Grabber. * - * In order to use the VFC you need to progeam the video controller + * In order to use the VFC you need to program the video controller * chip. This chip is the Phillips SAA9051. You need to call their * documentation ordering line to get the docs. * - * Their is very little documentation on the VFC itself. There is + * There is very little documentation on the VFC itself. There is * some useful info that can be found in the manuals that come with * the card. I will hopefully write some better docs at a later date. * @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -30,12 +31,11 @@ #include #include #include -#include #define VFC_MAJOR (60) #if 0 -#define VFC_DEBUG +#define VFC_IOCTL_DEBUG #endif #include "vfc.h" @@ -133,30 +133,27 @@ dev->control_reg=0; dev->poll_wait=NULL; dev->busy=0; - /* initialize the timer struct */ return 0; } int init_vfc_device(struct linux_sbus_device *sdev,struct vfc_dev *dev, int instance) { - struct linux_prom_registers reg; if(!dev) { printk(KERN_ERR "VFC: Bogus pointer passed\n"); return -ENOMEM; } printk("Initializing vfc%d\n",instance); dev->regs=NULL; - memcpy(®,&sdev->reg_addrs[0],sizeof(struct linux_prom_registers)); - prom_apply_sbus_ranges(sdev->my_bus, ®, sdev->num_registers, sdev); - dev->regs=sparc_alloc_io(reg.phys_addr, 0, + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers, sdev); + dev->regs=sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, sizeof(struct vfc_regs), vfcstr, - reg.which_io, 0x0); - dev->which_io=reg.which_io; - dev->phys_regs=(struct vfc_regs *)reg.phys_addr; + sdev->reg_addrs[0].which_io, 0x0); + dev->which_io=sdev->reg_addrs[0].which_io; + dev->phys_regs=(struct vfc_regs *)sdev->reg_addrs[0].phys_addr; if(!dev->regs) return -EIO; printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", - instance,(unsigned long)reg.phys_addr,(unsigned long)dev->regs); + instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs); if(init_vfc_devstruct(dev,instance)) return -EINVAL; if(init_vfc_hw(dev)) return -EIO; @@ -191,52 +188,58 @@ return 0; } -static int vfc_release(struct inode *inode,struct file *file) +static void vfc_release(struct inode *inode,struct file *file) { struct vfc_dev *dev; dev=vfc_get_dev_ptr(MINOR(inode->i_rdev)); - if(!dev) return -EINVAL; - if(!dev->busy) return 0; + if(!dev) return; + if(!dev->busy) return; dev->busy=0; MOD_DEC_USE_COUNT; - return 0; + return; } static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) { struct vfc_debug_inout inout; unsigned char *buffer; + int ret; + + if(!suser()) return -EPERM; switch(cmd) { case VFC_I2C_SEND: - if(copy_from_user(&inout, (void *)arg, sizeof(inout))) + if(copy_from_user(&inout, (void *)arg, sizeof(inout))) { return -EFAULT; + } buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL); if (!buffer) return -ENOMEM; - if(copy_from_user(buffer, inout.buffer, inout.len*sizeof(char))) { - kfree_s(buffer,inout.len); + + if(copy_from_user(buffer, inout.buffer, + inout.len*sizeof(char));) { + kfree_s(buffer,inout.len*sizeof(char)); return -EFAULT; } + vfc_lock_device(dev); inout.ret= vfc_i2c_sendbuf(dev,inout.addr & 0xff, inout.buffer,inout.len); - if(copy_to_user((void *)arg,&inout,sizeof(inout))) { - kfree_s(buffer,inout.len); + + if (copy_to_user((void *)arg,&inout,sizeof(inout))) { + kfree_s(buffer, inout.len); return -EFAULT; } vfc_unlock_device(dev); - kfree_s(buffer, inout.len); - break; case VFC_I2C_RECV: - - if(copy_from_user(&inout, (void *)arg, sizeof(inout))) + if (copy_from_user(&inout, (void *)arg, sizeof(inout))) { return -EFAULT; + } buffer = kmalloc(inout.len, GFP_KERNEL); if (!buffer) @@ -248,11 +251,11 @@ ,buffer,inout.len); vfc_unlock_device(dev); - if(copy_to_user(inout.buffer, buffer, inout.len)) { + if (copy_to_user(inout.buffer, buffer, inout.len)) { kfree_s(buffer,inout.len); return -EFAULT; } - if(copy_to_user((void *)arg,&inout,sizeof(inout))) { + if (copy_to_user((void *)arg,&inout,sizeof(inout))) { kfree_s(buffer,inout.len); return -EFAULT; } @@ -306,12 +309,10 @@ struct vfc_dev *dev, unsigned long arg) { int setcmd,ret=0; - if(copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int))) + if (copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int))) return -EFAULT; -#if 0 - VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n", - dev->instance,setcmd)); -#endif + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n", + dev->instance,setcmd)); switch(setcmd) { case MEMPRST: vfc_lock_device(dev); @@ -359,13 +360,14 @@ { int ret=0; int cmd; + if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) { - VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " "vfc_port_change_ioctl\n",dev->instance)); return -EFAULT; } - VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n", + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n", dev->instance,cmd)); switch(cmd) { @@ -424,12 +426,12 @@ int ret=0; int cmd; if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) { - VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " "vfc_set_video_ioctl\n",dev->instance)); - return -EFAULT; + return ret; } - VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n", + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n", dev->instance,cmd)); switch(cmd) { @@ -490,12 +492,12 @@ else status=PAL_NOCOLOR; } - VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance, + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance, status,buf[0])); - if(copy_to_user((void *)arg,&status,sizeof(unsigned int))) { - VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " + if (copy_to_user((void *)arg,&status,sizeof(unsigned int))) { + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " "vfc_get_video_ioctl\n",dev->instance)); - return -EFAULT; + return ret; } return ret; } @@ -513,11 +515,13 @@ switch(cmd & 0x0000ffff) { case VFCGCTRL: #if 0 - VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance)); + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance)); #endif tmp=dev->regs->control; - if(copy_to_user((void *)arg,&tmp,sizeof(unsigned int))) - return -EFAULT; + if(copy_to_user((void *)arg,&tmp, sizeof(unsigned int))) { + ret=-EFAULT; + break; + } ret=0; break; case VFCSCTRL: @@ -530,12 +534,9 @@ ret=vfc_set_video_ioctl(inode,file,dev,arg); break; case VFCHUE: -#if 0 - VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance)); -#endif - + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance)); if(copy_from_user(&tmp,(void *)arg,sizeof(unsigned int))) { - VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer " + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer " "to IOCTL(VFCHUE)",dev->instance)); ret=-EFAULT; } else { @@ -549,7 +550,7 @@ break; case VFCRDINFO: ret=-EINVAL; - VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance)); + VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance)); break; default: ret=vfc_debug(vfc_get_dev_ptr(MINOR(inode->i_rdev)), @@ -584,8 +585,9 @@ return 0; } -static long long vfc_lseek(struct inode *inode, struct file *file, - long long offset, int origin) + +static int vfc_lseek(struct inode *inode, struct file *file, + off_t offset, int origin) { return -ESPIPE; } @@ -595,13 +597,12 @@ NULL, /* vfc_write */ NULL, /* vfc_read */ NULL, /* vfc_readdir */ - NULL, /* vfc_poll */ + NULL, /* vfc_select */ vfc_ioctl, vfc_mmap, vfc_open, vfc_release, }; - static int vfc_probe(void) { diff -u --recursive --new-file v2.1.36/linux/drivers/sbus/char/vfc_i2c.c linux/drivers/sbus/char/vfc_i2c.c --- v2.1.36/linux/drivers/sbus/char/vfc_i2c.c Mon Apr 14 16:28:14 1997 +++ linux/drivers/sbus/char/vfc_i2c.c Mon May 12 10:35:42 1997 @@ -31,8 +31,8 @@ #include #include -#if 0 -#define VFC_DEBUG +#if 0 +#define VFC_I2C_DEBUG #endif #include "vfc.h" @@ -72,6 +72,8 @@ void vfc_i2c_delay_wakeup(struct vfc_dev *dev) { + /* Used to profile code and eliminate too many delays */ + VFC_I2C_DEBUG_PRINTK(("vfc%d: Delaying\n",dev->instance)); wake_up(&dev->poll_wait); } @@ -95,14 +97,14 @@ int vfc_init_i2c_bus(struct vfc_dev *dev) { - dev->regs->i2c_s1= ENABLE_SERIAL | ACK; + dev->regs->i2c_s1= ENABLE_SERIAL | SELECT(S0) | ACK; vfc_i2c_reset_bus(dev); return 0; } int vfc_i2c_reset_bus(struct vfc_dev *dev) { - VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n", + VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n", dev->instance)); if(!dev) return -EINVAL; if(!dev->regs) return -EINVAL; @@ -110,7 +112,7 @@ dev->regs->i2c_s1=SEND_I2C_STOP | ACK; vfc_i2c_delay(dev); dev->regs->i2c_s1=CLEAR_I2C_BUS; - VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n", + VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n", dev->instance, dev->regs->i2c_s1)); return 0; } @@ -146,7 +148,7 @@ { int ret,raddr; #if 1 - dev->regs->i2c_s1=SEND_I2C_STOP; + dev->regs->i2c_s1=SEND_I2C_STOP | ACK; dev->regs->i2c_s1=SELECT(S0) | ENABLE_SERIAL; vfc_i2c_delay(dev); #endif @@ -154,12 +156,12 @@ switch(mode) { case VFC_I2C_READ: dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr | 0x1); - VFC_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n", + VFC_I2C_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n", dev->instance,addr | 0x1)); break; case VFC_I2C_WRITE: dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr & ~0x1); - VFC_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n", + VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n", dev->instance,addr & ~0x1)); break; default: @@ -215,7 +217,7 @@ int ret; if(last) { dev->regs->i2c_reg=NEGATIVE_ACK; - VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: sending negative ack\n", + VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n", dev->instance)); } else { dev->regs->i2c_s1=ACK; @@ -255,6 +257,8 @@ printk(KERN_ERR "vfc%d: " "VFC error while recieving byte\n", dev->instance); + dev->regs->i2c_s1=SEND_I2C_STOP; + ret=-EINVAL; } buf++; } @@ -286,7 +290,7 @@ ret=vfc_i2c_xmit_byte(dev,buf); switch(ret) { case XMIT_LAST_BYTE: - VFC_DEBUG_PRINTK(("vfc%d: " + VFC_I2C_DEBUG_PRINTK(("vfc%d: " "Reciever ended transmission with " " %d bytes remaining\n", dev->instance,count)); diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.1.36/linux/drivers/scsi/53c7,8xx.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/scsi/53c7,8xx.c Mon May 12 17:39:50 1997 @@ -254,7 +254,6 @@ #include #include #include -#undef current #include "scsi.h" #include "hosts.h" @@ -783,7 +782,7 @@ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata; int i, j; - u32 *current; + u32 *curr; for (i = 0; i < 16; ++i) { hostdata->request_sense[i] = 0; for (j = 0; j < 8; ++j) @@ -792,14 +791,14 @@ } hostdata->issue_queue = NULL; hostdata->running_list = hostdata->finished_queue = - hostdata->current = NULL; - for (i = 0, current = (u32 *) hostdata->schedule; - i < host->can_queue; ++i, current += 2) { - current[0] = hostdata->NOP_insn; - current[1] = 0xdeadbeef; + hostdata->curr = NULL; + for (i = 0, curr = (u32 *) hostdata->schedule; + i < host->can_queue; ++i, curr += 2) { + curr[0] = hostdata->NOP_insn; + curr[1] = 0xdeadbeef; } - current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE; - current[1] = (u32) virt_to_bus (hostdata->script) + + curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE; + curr[1] = (u32) virt_to_bus (hostdata->script) + hostdata->E_wait_reselect; hostdata->reconnect_dsa_head = 0; hostdata->addr_reconnect_dsa_head = (u32) @@ -2104,7 +2103,7 @@ int left, found; volatile struct NCR53c7x0_cmd * linux_search; volatile struct NCR53c7x0_cmd * volatile *linux_prev; - volatile u32 *ncr_prev, *current, ncr_search; + volatile u32 *ncr_prev, *curr, ncr_search; #if 0 printk ("scsi%d: abnormal finished\n", host->host_no); @@ -2120,13 +2119,13 @@ */ - for (found = 0, left = host->can_queue, current = hostdata->schedule; - left > 0; --left, current += 2) + for (found = 0, left = host->can_queue, curr = hostdata->schedule; + left > 0; --left, curr += 2) { - if (issue_to_cmd (host, hostdata, (u32 *) current) == cmd) + if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd) { - current[0] = hostdata->NOP_insn; - current[1] = 0xdeadbeef; + curr[0] = hostdata->NOP_insn; + curr[1] = 0xdeadbeef; ++found; break; } @@ -3964,7 +3963,7 @@ Scsi_Cmnd *tmp = cmd->cmd; unsigned long flags; /* dsa start is negative, so subtraction is used */ - volatile u32 *current; + volatile u32 *curr; int i; NCR53c7x0_local_setup(host); @@ -3991,9 +3990,9 @@ return; } - for (i = host->can_queue, current = hostdata->schedule; - i > 0 && current[0] != hostdata->NOP_insn; - --i, current += 2 /* JUMP instructions are two words */); + for (i = host->can_queue, curr = hostdata->schedule; + i > 0 && curr[0] != hostdata->NOP_insn; + --i, curr += 2 /* JUMP instructions are two words */); if (i > 0) { ++hostdata->busy[tmp->target][tmp->lun]; @@ -4002,13 +4001,13 @@ /* Restore this instruction to a NOP once the command starts */ cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) / - sizeof(u32)] = (u32) virt_to_bus ((void *)current); + sizeof(u32)] = (u32) virt_to_bus ((void *)curr); /* Replace the current jump operand. */ - current[1] = + curr[1] = virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template; /* Replace the NOP instruction with a JUMP */ - current[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | + curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE; } else { printk ("scsi%d: no free slot\n", host->host_no); @@ -4510,8 +4509,8 @@ /* * NCR53c700 and NCR53c700-66 change the current SCSI - * process, hostdata->current, in the Linux driver so - * cmd = hostdata->current. + * process, hostdata->curr, in the Linux driver so + * cmd = hostdata->curr. * * With other chips, we must look through the commands * executing and find the command structure which @@ -4519,7 +4518,7 @@ */ if (hostdata->options & OPTION_700) { - cmd = (struct NCR53c7x0_cmd *) hostdata->current; + cmd = (struct NCR53c7x0_cmd *) hostdata->curr; } else { dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG)); for (cmd = (struct NCR53c7x0_cmd *) @@ -5872,7 +5871,7 @@ struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata; u32 *dsa, *next_dsa; - volatile u32 *current; + volatile u32 *curr; int left; Scsi_Cmnd *cmd, *next_cmd; unsigned long flags; @@ -5914,11 +5913,11 @@ */ printk ("scsi%d : schedule dsa array :\n", host->host_no); - for (left = host->can_queue, current = hostdata->schedule; - left > 0; current += 2, --left) - if (current[0] != hostdata->NOP_insn) + for (left = host->can_queue, curr = hostdata->schedule; + left > 0; curr += 2, --left) + if (curr[0] != hostdata->NOP_insn) /* FIXME : convert pointer to dsa_begin to pointer to dsa. */ - print_dsa (host, bus_to_virt (current[1] - + print_dsa (host, bus_to_virt (curr[1] - (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template)), ""); printk ("scsi%d : end schedule dsa array\n", host->host_no); @@ -6108,7 +6107,7 @@ host->hostdata; struct NCR53c7x0_cmd *c; int i; - u32 *current; + u32 *curr; Scsi_Cmnd *list = NULL, *tmp; for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c; c = (struct NCR53c7x0_cmd *) c->next) { @@ -6129,12 +6128,12 @@ } if (free) { - for (i = 0, current = (u32 *) hostdata->schedule; - i < host->can_queue; ++i, current += 2) { - current[0] = hostdata->NOP_insn; - current[1] = 0xdeadbeef; + for (i = 0, curr = (u32 *) hostdata->schedule; + i < host->can_queue; ++i, curr += 2) { + curr[0] = hostdata->NOP_insn; + curr[1] = 0xdeadbeef; } - hostdata->current = NULL; + hostdata->curr = NULL; } if (issue) { diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h --- v2.1.36/linux/drivers/scsi/53c7,8xx.h Mon Jun 3 20:06:37 1996 +++ linux/drivers/scsi/53c7,8xx.h Tue May 13 21:58:42 1997 @@ -1394,7 +1394,7 @@ /* commands running, maintained by Linux driver */ - volatile struct NCR53c7x0_cmd *current; /* currently connected + volatile struct NCR53c7x0_cmd *curr; /* currently connected nexus, ONLY valid for NCR53c700/NCR53c700-66 */ diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.1.36/linux/drivers/scsi/ChangeLog.ncr53c8xx Sun Apr 13 10:18:21 1997 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Mon May 12 20:45:35 1997 @@ -1,3 +1,75 @@ +Sun May 11 22:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.1b + - Cosmetic changes. + - Some heavy testings under pre-linux-2.1.37-6 + +Sun May 4 22:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.1a + - PFEN wrongly used for PREFETCH feature bit testing. + Changed to _F_PFEN. + - 2 SCR_COPY that need NO FLUSH bit to be removed had been missed + in tp->getscr[] script (loads SXFER and SCNTL3 on reselection). + +Sat May 3 22:30 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.1 + - Use the NO FLUSH option for MOVE MEMORY (COPY) each time it is + possible. More than 100 COPY with NO FLUSH and 6 with FLUSH for + my configuration (max queued command / device = 8). + This option bit is removed from the script instance for chips + that donnot support prefetching. + - Rewrite the ncr_exception() routine more simple (I think) and + remove useless code. + - Change the data_in and data_out script management. + Use the bottom part of these scripts instead of the beginning. + That avoids to zero the scatter/gather array when a command is + queued (1k) and to deal with some weird IID on MOVE 0 bytes when + a target wants to transfer more bytes than expected. + - Misc. improvements in the init code. + - Remove IOMAPPED/MMIO automatic switching option. + Was useless and reported not reliable. + - Fix a double read of DSTAT and remove DFE testing in the + Phase mismatch service routine. + - Etc... + +Fri Apr 26 20:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.0a + - Add support if the Diamond FirePort 40 (SYM53C875J chip) + +Mon Apr 22 22:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 2.0 + - incorporate __initdata and __initfunc directives in order to + allow 'init' to free unused memory after driver initialisations. + Patch sent by Roberto Fichera. + - rewrite the init code of the driver. Now a feature descriptor + is used for each real chip types. The code is a lot more clean, + since the driver uses device and revision ids only in the + detection procedure. + - add 'pcifix' boot command line. This command allows to fix up PCI + config space for new chips which support features based on the + cache line size and 'write and invalidate'. + - incorporate in the driver, the code used for error recovery + testing. This code is normally not compiled; have to define + SCSI_NCR_DEBUG_ERROR_RECOVERY in order to compile it. + - take into account actual SCSI bus mode for 53C895 LVD/SE controller. + In single ended mode only fast20 is supported. + (Just to not be late since such controllers are not yet available) + + +Sat Apr 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 1.18f + - fix an old bug included in the initial port (version 0.0). + The driver allocated 10 bytes of static data and uses 12 bytes. + No danger, since data are generally aligned on 4 bytes boundary + and so byte 10 and 11 are free (I hope ...) + +Wed Apr 16 12:00 1997 Gerard Roudier (groudier@club-internet.fr) + * revision 1.18e + - reset all when an unexpected data cycle is detected while + disconnecting. + - make changes to abort() ans reset() functions according to + Leonard's documentation. + - small fix in some message for hard errors. + Sat Apr 5 13:00 1997 Gerard Roudier (groudier@club-internet.fr) * revision 1.18d - Probe NCR pci device ids in reverse order if asked by user from diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.36/linux/drivers/scsi/Config.in Mon Apr 14 16:28:15 1997 +++ linux/drivers/scsi/Config.in Mon May 12 10:35:42 1997 @@ -86,6 +86,9 @@ dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI +if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then + dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI +fi dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI if [ "$CONFIG_SCSI_U14_34F" != "n" ]; then diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.1.36/linux/drivers/scsi/Makefile Mon Apr 14 16:28:15 1997 +++ linux/drivers/scsi/Makefile Mon May 12 10:35:42 1997 @@ -185,6 +185,14 @@ endif endif +ifeq ($(CONFIG_SCSI_DC390T),y) +L_OBJS += tmscsim.o +else + ifeq ($(CONFIG_SCSI_DC390T),m) + M_OBJS += tmscsim.o + endif +endif + ifeq ($(CONFIG_SCSI_AM53C974),y) L_OBJS += AM53C974.o else diff -u --recursive --new-file v2.1.36/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.1.36/linux/drivers/scsi/README.ncr53c8xx Sun Apr 13 10:18:21 1997 +++ linux/drivers/scsi/README.ncr53c8xx Mon May 12 20:45:35 1997 @@ -1,10 +1,10 @@ -The linux NCR53C8XX driver README file +The Linux NCR53C8XX driver README file Written by Gerard Roudier 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -6 April 1997 +9 May 1997 =============================================================================== 1. Introduction @@ -22,6 +22,7 @@ 8.5 Set debug mode 8.6 Clear profile counters 8.7 Set flag (no_sync) + 8.8 Debug error recovery 9. Configuration parameters 10. Boot setup commands 10.1 Syntax @@ -203,7 +204,6 @@ IO port address 0x6000, IRQ number 10 Using memory mapped IO at virtual address 0x282c000 Synchronous transfer period 25, max commands per lun 4 - Profiling information: num_trans = 18014 num_kbytes = 671314 @@ -390,6 +390,57 @@ - setflag all will allow disconnection for all devices on the SCSI bus. + +8.8 Debug error recovery + + debug_error_recovery + + Available error type to trigger: + sge: SCSI gross error + abort: abort command from the middle-level driver + reset: reset command from the middle-level driver + parity: scsi parity detected in DATA IN phase + none: restore driver normal behaviour + + The code corresponding to this feature is normally not compiled. + Its purpose is driver testing only. In order to compile the code + that allows to trigger error recovery you must define at compile time + SCSI_NCR_DEBUG_ERROR_RECOVERY. + If you have compiled the driver with this option, nothing will happen + as long as you donnot use the control command 'debug_error_recovery' + with sge, abort, reset or parity as argument. + If you select an error type, it will be triggered by the driver every + 30 seconds. + +8.9 PCI configuration fix-up + + pcifix