diff -u --recursive --new-file v2.1.28/linux/CREDITS linux/CREDITS --- v2.1.28/linux/CREDITS Thu Feb 6 04:57:24 1997 +++ linux/CREDITS Wed Mar 5 17:04:29 1997 @@ -667,6 +667,7 @@ N: Jakub Jelinek E: jj@sunsite.mff.cuni.cz W: http://sunsite.mff.cuni.cz/~jj +P: 1024/0F7623C5 53 95 71 3C EB 73 99 97 02 49 40 47 F9 19 68 20 D: Sparc hacker, SILO, mc D: Maintain sunsite.mff.cuni.cz S: Na Orechovce 7 diff -u --recursive --new-file v2.1.28/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.28/linux/Documentation/Configure.help Tue Mar 4 10:25:22 1997 +++ linux/Documentation/Configure.help Tue Mar 4 13:22:49 1997 @@ -1774,10 +1774,11 @@ use normal IO CONFIG_SCSI_NCR53C8XX_IOMAPPED - Warning! Under linux/Alpha only normal io has been currently tested. This option allows you to force the driver to use normal IO. Memory mapped IO has less latency than normal IO and works for most Intel-based hardware. + Under Linux/Alpha only normal IO is currently supported by the driver + and so, this option has no effect. The normal answer therefore is N. not allow targets to disconnect @@ -1809,6 +1810,21 @@ that can be queued to a device, when tagged command queuing is possible. The default value is 4. Minimum is 2, maximum is 12. The normal answer therefore is the default one. + +assume boards are SYMBIOS compatible +CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + This option allows you to enable some features depending on GPIO wiring. + These general purpose input/output pins can be used for vendor specific + features or implementation of the standard SYMBIOS features. + Genuine SYMBIOS boards use GPIO0 in output for controller LED and GPIO3 + bit as a flag indicating singled-ended/differential interface. + If all the boards of your system are genuine SYMBIOS boards or use + BIOS and drivers from SYMBIOS, you would want to enable this option, + obviously at your own risks. + The driver behaves correctly on my system with this option enabled. + (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev 0x12). + This option must be set to N if your system has at least one 53C8XX based + scsi board with a vendor-specific BIOS (example: Tekram DC-390/U/W/F). IBMMCA SCSI support CONFIG_SCSI_IBMMCA diff -u --recursive --new-file v2.1.28/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v2.1.28/linux/Documentation/devices.tex Sat Dec 21 00:40:58 1996 +++ linux/Documentation/devices.tex Tue Mar 4 10:07:24 1997 @@ -34,15 +34,19 @@ \newcommand{\link}[4]{{\file #1} \> {\file #2} \> #3 \> #4 \\} \newcommand{\vlink}[4]{{\file #1} \> {\em #2 \/} \> #3 \> #4 \\} \newcommand{\node}[3]{{\file #1} \> #2 \> #3 \\} +\newcommand{\tum}{$''$} \newenvironment{nodelist}% {\begin{tabbing}% {\file /dev/crambamboli} \= {\file /proc/self/fd/99} \= symbolicxxx \= foo \kill}% {\end{tabbing}} % +% If you reformat this document, *please* make sure this information +% gets included! +% \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: December 20, 1996} +\date{Last revised: March 3, 1997} \maketitle % \noindent @@ -153,7 +157,6 @@ \major{34}{}{char }{Z8530 HDLC driver} \major{ }{}{block}{Fourth IDE hard disk/CD-ROM interface} \major{35}{}{char }{tclmidi MIDI driver} -\major{ }{}{block}{Modular RAM disk} \major{36}{}{char }{Netlink support} \major{ }{}{block}{MCA ESDI hard disk} \major{37}{}{char }{IDE tape} @@ -189,7 +192,14 @@ \major{65}{}{char }{Sundance ``plink'' Transputer boards} \major{66}{}{char }{YARC PowerPC PCI coprocessor card} \major{67}{}{char }{Coda network filesystem} -\major{68}{--119}{}{Unallocated} +\major{68}{}{char }{CAPI 2.0 interface} +\major{69}{}{char }{MA16 numeric accelerator card} +\major{70}{}{char }{SpellCaster Protocol Services Interface} +\major{71}{}{char }{Computone IntelliPort II serial card} +\major{72}{}{char }{Computone IntelliPort II serial card -- alternate devices} +\major{73}{}{char }{Computone IntelliPort II serial card -- control devices} +\major{74}{}{char }{SCI bridge} +\major{75}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} \major{128}{--239}{}{Unallocated} \major{240}{--254}{}{Local/experimental use} @@ -198,7 +208,6 @@ \section{Minor numbers} - \begin{devicelist} \major{0}{}{}{Unnamed devices (e.g. non-device mounts)} \minor{0}{}{reserved as null device number} @@ -258,37 +267,38 @@ \\ \major{}{}{}{To specify format, add to the autodetect device number} \minor{ 0}{/dev/fd?}{Autodetect format} - \minor{ 4}{/dev/fd?d360}{5.25" \num{4}{360}K in a \num{4}{360}K drive\1} - \minor{ 20}{/dev/fd?h360}{5.25" \num{4}{360}K in a 1200K drive\1} - \minor{ 48}{/dev/fd?h410}{5.25" \num{4}{410}K in a 1200K drive} - \minor{ 64}{/dev/fd?h420}{5.25" \num{4}{420}K in a 1200K drive} - \minor{ 24}{/dev/fd?h720}{5.25" \num{4}{720}K in a 1200K drive} - \minor{ 80}{/dev/fd?h880}{5.25" \num{4}{880}K in a 1200K drive\1} - \minor{ 8}{/dev/fd?h1200}{5.25" 1200K in a 1200K drive\1} - \minor{ 40}{/dev/fd?h1440}{5.25" 1440K in a 1200K drive\1} - \minor{ 56}{/dev/fd?h1476}{5.25" 1476K in a 1200K drive} - \minor{ 72}{/dev/fd?h1494}{5.25" 1494K in a 1200K drive} - \minor{ 92}{/dev/fd?h1600}{5.25" 1600K in a 1200K drive\1} \minor{}{}{} - \minor{ 12}{/dev/fd?u360}{3.5" \num{4}{360}K Double Density} - \minor{ 16}{/dev/fd?u720}{3.5" \num{4}{720}K Double Density\1} - \minor{120}{/dev/fd?u800}{3.5" \num{4}{800}K Double Density\2} - \minor{ 52}{/dev/fd?u820}{3.5" \num{4}{820}K Double Density} - \minor{ 68}{/dev/fd?u830}{3.5" \num{4}{830}K Double Density} - \minor{ 84}{/dev/fd?u1040}{3.5" 1040K Double Density\1} - \minor{ 88}{/dev/fd?u1120}{3.5" 1120K Double Density\1} - \minor{ 28}{/dev/fd?u1440}{3.5" 1440K High Density\1} - \minor{124}{/dev/fd?u1600}{3.5" 1600K High Density\1} - \minor{ 44}{/dev/fd?u1680}{3.5" 1680K High Density\3} - \minor{ 60}{/dev/fd?u1722}{3.5" 1722K High Density} - \minor{ 76}{/dev/fd?u1743}{3.5" 1743K High Density} - \minor{ 96}{/dev/fd?u1760}{3.5" 1760K High Density} - \minor{116}{/dev/fd?u1840}{3.5" 1840K High Density\3} - \minor{100}{/dev/fd?u1920}{3.5" 1920K High Density\1} - \minor{ 32}{/dev/fd?u2880}{3.5" 2880K Extra Density\1} - \minor{104}{/dev/fd?u3200}{3.5" 3200K Extra Density} - \minor{108}{/dev/fd?u3520}{3.5" 3520K Extra Density} - \minor{112}{/dev/fd?u3840}{3.5" 3840K Extra Density\1} + \minor{ 4}{/dev/fd?d360}{5.25\tum\ \num{4}{360}K in a \num{4}{360}K drive\1} + \minor{ 20}{/dev/fd?h360}{5.25\tum\ \num{4}{360}K in a 1200K drive\1} + \minor{ 48}{/dev/fd?h410}{5.25\tum\ \num{4}{410}K in a 1200K drive} + \minor{ 64}{/dev/fd?h420}{5.25\tum\ \num{4}{420}K in a 1200K drive} + \minor{ 24}{/dev/fd?h720}{5.25\tum\ \num{4}{720}K in a 1200K drive} + \minor{ 80}{/dev/fd?h880}{5.25\tum\ \num{4}{880}K in a 1200K drive\1} + \minor{ 8}{/dev/fd?h1200}{5.25\tum\ 1200K in a 1200K drive\1} + \minor{ 40}{/dev/fd?h1440}{5.25\tum\ 1440K in a 1200K drive\1} + \minor{ 56}{/dev/fd?h1476}{5.25\tum\ 1476K in a 1200K drive} + \minor{ 72}{/dev/fd?h1494}{5.25\tum\ 1494K in a 1200K drive} + \minor{ 92}{/dev/fd?h1600}{5.25\tum\ 1600K in a 1200K drive\1} + \minor{}{}{} + \minor{ 12}{/dev/fd?u360}{3.5\tum\ \num{4}{360}K Double Density} + \minor{ 16}{/dev/fd?u720}{3.5\tum\ \num{4}{720}K Double Density\1} + \minor{120}{/dev/fd?u800}{3.5\tum\ \num{4}{800}K Double Density\2} + \minor{ 52}{/dev/fd?u820}{3.5\tum\ \num{4}{820}K Double Density} + \minor{ 68}{/dev/fd?u830}{3.5\tum\ \num{4}{830}K Double Density} + \minor{ 84}{/dev/fd?u1040}{3.5\tum\ 1040K Double Density\1} + \minor{ 88}{/dev/fd?u1120}{3.5\tum\ 1120K Double Density\1} + \minor{ 28}{/dev/fd?u1440}{3.5\tum\ 1440K High Density\1} + \minor{124}{/dev/fd?u1600}{3.5\tum\ 1600K High Density\1} + \minor{ 44}{/dev/fd?u1680}{3.5\tum\ 1680K High Density\3} + \minor{ 60}{/dev/fd?u1722}{3.5\tum\ 1722K High Density} + \minor{ 76}{/dev/fd?u1743}{3.5\tum\ 1743K High Density} + \minor{ 96}{/dev/fd?u1760}{3.5\tum\ 1760K High Density} + \minor{116}{/dev/fd?u1840}{3.5\tum\ 1840K High Density\3} + \minor{100}{/dev/fd?u1920}{3.5\tum\ 1920K High Density\1} + \minor{ 32}{/dev/fd?u2880}{3.5\tum\ 2880K Extra Density\1} + \minor{104}{/dev/fd?u3200}{3.5\tum\ 3200K Extra Density} + \minor{108}{/dev/fd?u3520}{3.5\tum\ 3520K Extra Density} + \minor{112}{/dev/fd?u3840}{3.5\tum\ 3840K Extra Density\1} \minor{}{}{} \minor{36}{/dev/fd?CompaQ}{Compaq 2880K drive; probably obsolete} \\ @@ -298,11 +308,12 @@ \end{devicelist} NOTE: The letter in the device name ({\file d}, {\file q}, {\file h} -or {\file u}) signifies the type of drive supported: 5.25" Double -Density ({\file d}), 5.25" Quad Density ({\file q}), 5.25" High -Density ({\file h}) or 3.5" (any type, {\file u}). The capital -letters {\file D}, {\file H}, or {\file E} for the 3.5" models have -been deprecated, since the drive type is insignificant for these devices. +or {\file u}) signifies the type of drive supported: 5.25\tum\ Double +Density ({\file d}), 5.25\tum\ Quad Density ({\file q}), 5.25\tum\ +High Density ({\file h}) or 3.5\tum\ (any type, {\file u}). The +capital letters {\file D}, {\file H}, or {\file E} for the 3.5\tum\ +models have been deprecated, since the drive type is insignificant for +these devices. \begin{devicelist} \major{3}{}{char}{Pseudo-TTY slaves} @@ -324,9 +335,10 @@ \end{devicelist} \noindent -For Linux/i386, partitions 1-4 are the primary partitions, partitions -5 and up are logical partitions. Other versions of Linux use -partitioning schemes appropriate to their respective architectures. +For MS-DOS style partition tables (typically used by Linux/i386), +partitions 1-4 are the primary partitions, partitions 5 and up are +logical partitions. For other partitioning schemes, the meaning of +the numbers vary. \begin{devicelist} \major{ 4}{}{char }{TTY devices} @@ -481,6 +493,7 @@ \minor{139}{/dev/openprom}{SPARC OpenBoot PROM} \minor{140}{/dev/relay8}{Berkshire Products Octal relay card} \minor{141}{/dev/relay16}{Berkshire Products ISO-16 relay card} + \minor{142}{/dev/msr}{x86 model specific registers} \end{devicelist} \begin{devicelist} @@ -913,15 +926,8 @@ \minor{129}{/dev/smpte1}{Second MIDI port, SMPTE timed} \minor{130}{/dev/smpte2}{Third MIDI port, SMPTE timed} \minor{131}{/dev/smpte3}{Fourth MIDI port, SMPTE timed} -\\ -\major{ }{}{block}{Modular RAM disk} \end{devicelist} -\noindent -This device number is provided for older kernels which did not have -the modular RAM disk in the standard distribution. See major number -1. This assignment will be removed when the 2.0 kernel is released. - \begin{devicelist} \major{36}{}{char }{Netlink support} \minor{0}{/dev/route}{Routing, device updates (kernel to user)} @@ -1213,7 +1219,98 @@ See {\em http://www.coda.cs.cmu.edu\/} for information about Coda. \begin{devicelist} -\major{68}{--119}{}{Unallocated} +\major{68}{}{char }{CAPI 2.0 interface} + \minor{0}{/dev/capi20}{Control device} + \minor{1}{/dev/capi20.00}{First CAPI 2.0 application} + \minor{2}{/dev/capi20.01}{Second CAPI 2.0 application} + \minordots + \minor{20}{/dev/capi20.19}{19th CAPI 2.0 application} +\end{devicelist} + +\noindent +ISDN CAPI 2.0 driver for use with CAPI 2.0 applications; currently +supports the AVM B1 card. + +\begin{devicelist} +\major{69}{}{char }{MA16 numeric accelerator card} + \minor{0}{/dev/ma16}{Board memory access} +\end{devicelist} + +\begin{devicelist} +\major{70}{}{char }{SpellCaster Protocol Services Interface} + \minor{0}{/dev/apscfg}{Configuration interface} + \minor{1}{/dev/apsauth}{Authentication interface} + \minor{2}{/dev/apslog}{Logging interface} + \minor{3}{/dev/apsdbg}{Debugging interface} + \minor{64}{/dev/apsisdn}{ISDN command interface} + \minor{65}{/dev/apsasync}{Async command interface} + \minor{128}{/dev/apsmon}{Monitor interface} +\end{devicelist} + +\begin{devicelist} +\major{71}{}{char }{Computone IntelliPort II serial card} + \minor{0}{/dev/ttyF0}{IntelliPort II board 0, port 0} + \minor{1}{/dev/ttyF1}{IntelliPort II board 0, port 1} + \minordots + \minor{63}{/dev/ttyF63}{IntelliPort II board 0, port 63} + \minor{64}{/dev/ttyF64}{IntelliPort II board 1, port 0} + \minor{65}{/dev/ttyF65}{IntelliPort II board 1, port 1} + \minordots + \minor{127}{/dev/ttyF127}{IntelliPort II board 1, port 63} + \minor{128}{/dev/ttyF128}{IntelliPort II board 2, port 0} + \minor{129}{/dev/ttyF129}{IntelliPort II board 2, port 1} + \minordots + \minor{191}{/dev/ttyF191}{IntelliPort II board 2, port 63} + \minor{192}{/dev/ttyF192}{IntelliPort II board 3, port 0} + \minor{193}{/dev/ttyF193}{IntelliPort II board 3, port 1} + \minordots + \minor{255}{/dev/ttyF255}{IntelliPort II board 3, port 63} +\end{devicelist} + +\begin{devicelist} +\major{72}{}{char }{Computone IntelliPort II serial card -- alternate devices} + \minor{0}{/dev/cuf0}{Callout device corresponding to {\file ttyF0}} + \minor{1}{/dev/cuf1}{Callout device corresponding to {\file ttyF1}} + \minordots + \minor{63}{/dev/cuf63}{Callout device corresponding to {\file ttyF63}} + \minor{64}{/dev/cuf64}{Callout device corresponding to {\file ttyF64}} + \minor{65}{/dev/cuf65}{Callout device corresponding to {\file ttyF65}} + \minordots + \minor{127}{/dev/cuf127}{Callout device corresponding to {\file ttyF127}} + \minor{128}{/dev/cuf128}{Callout device corresponding to {\file ttyF128}} + \minor{129}{/dev/cuf129}{Callout device corresponding to {\file ttyF129}} + \minordots + \minor{191}{/dev/cuf191}{Callout device corresponding to {\file ttyF191}} + \minor{192}{/dev/cuf192}{Callout device corresponding to {\file ttyF192}} + \minor{193}{/dev/cuf193}{Callout device corresponding to {\file ttyF193}} + \minordots + \minor{255}{/dev/cuf255}{Callout device corresponding to {\file ttyF255}} +\end{devicelist} + +\begin{devicelist} +\major{73}{}{char }{Computone IntelliPort II serial card -- control devices} + \minor{0}{/dev/ip2ipl0}{Loadware device for board 0} + \minor{1}{/dev/ip2stat0}{Status device for board 0} + \minor{4}{/dev/ip2ipl1}{Loadware device for board 1} + \minor{5}{/dev/ip2stat1}{Status device for board 1} + \minor{8}{/dev/ip2ipl2}{Loadware device for board 2} + \minor{9}{/dev/ip2stat2}{Status device for board 2} + \minor{12}{/dev/ip2ipl3}{Loadware device for board 3} + \minor{13}{/dev/ip2stat3}{Status device for board 3} +\end{devicelist} + +\begin{devicelist} +\major{74}{}{char }{SCI bridge} + \minor{0}{/dev/SCI/0}{SCI device 0} + \minor{1}{/dev/SCI/1}{SCI device 1} + \minordots +\end{devicelist} + +\noindent +Currently for Dolphin Interconnect Solutions' PCI-SCI bridge. + +\begin{devicelist} +\major{75}{--119}{}{Unallocated} \end{devicelist} \begin{devicelist} @@ -1317,5 +1414,108 @@ \node{/dev/gpmdata}{socket}{{\file gpm} mouse multiplexer} \end{nodelist} -\end{document} +\section{Terminal devices} +Terminal, or TTY devices are a special class of character devices. A +terminal device is any device that could act as a controlling terminal +for a session; this includes virtual consoles, serial ports, and +pseudoterminals (PTYs). + +All terminal devices share a common set of capabilities known as line +diciplines; these include the common terminal line dicipline as well +as SLIP and PPP modes. + +All terminal devices are named similarly; this section explains the +naming and use of the various types of TTYs. Note that the naming +conventions include several historical warts; some of these are +Linux-specific, some were inherited from other systems, and some +reflect Linux outgrowing a borrowed convention. + +A hash mark ($\#$) in a device name is used here to indicate a decimal +number without leading zeroes. + +\subsection{Virtual consoles and the console device} + +Virtual consoles are full-screen terminal displays on the system video +monitor. Virtual consoles are named {\file /dev/tty$\#$}, with +numbering starting at {\file /dev/tty1}; {\file /dev/tty0} is the +current virtual console. {\file /dev/tty0} is the device that should +be used to access the system video card on those architectures for +which the frame buffer devices ({\file /dev/fb*}) do not exist +(including the x86). Do not use {\file /dev/console} for this +purpose. + +The {\em console device\/}, {\file /dev/console}, is the device to +which system messages should be sent, and on which logins should be +permitted in single-user mode. {\file /dev/console} should be a +symbolic link to either {\file /dev/tty0}, a specific virtual console +such as {\file /dev/tty1}, or to a serial port primary ({\file tty}) +device, depending on the configuration of the system. + +\subsection{Serial ports} + +Serial ports are RS-232 serial ports and any device which simulates +one, either in hardware (such as internal modems) or in software (such +as the ISDN driver.) Under Linux, each serial ports has two device +names, the primary or callin device and the alternate or callout one. +Each kind of device is indicated by a different letter. For any +letter $X$, the names of the devices are {\file /dev/tty${X\#}$} and +{\file /dev/cu${x\#}$}, respectively; for historical reasons, {\file +/dev/ttyS$\#$} and {\file /dev/ttyC$\#$} correspond to {\file +/dev/cua$\#$} and {\file /dev/cub$\#$}. In the future, it should be +expected that multiple letters will be used; all letters will be upper +case for the {\file tty} device and lower case for the {\file cu} +device. + +The alternate devices provide for kernel-based exclusion and somewhat +different defaults than the primary devices. Their main purpose is to +allow the use of serial ports with programs with no inherent or broken +support for serial ports. For programs with proper knowledge of +serial port operation, their use should probably be avoided. + +Arbitration of serial ports is provided by the use of lock files with +the names {\file /var/lock/LCK..tty${X\#}$}. The contents of the lock +file should be the PID of the locking process as an ASCII number. + +It is common practice to install links such as {\file /dev/modem\/} +which point to serial ports. In order to ensure proper locking in the +presence of these links, it is recommended that software chase +symlinks and lock all possible names; additionally, it is recommended +that a lock file be installed with the corresponding alternate +device. In order to avoid deadlocks, it is recommended that the locks +are acquired in the following order, and released in the reverse: +\begin{itemize} +\item{The symbolic link name, if any ({\file /var/lock/LCK..modem})} +\item{The {\file tty} name ({\file /var/lock/LCK..ttyS2})} +\item{The alternate device name ({\file /var/lock/LCK..cua2})} +\end{itemize} +In the case of nested symbolic links, the lock files should be +installed in the order the symlinks are resolved. + +Under no circumstances should an application hold a lock while waiting +for another to be released. In addition, applications which attempt +to create lock files for the corresponding alternate device names +should take into account the possibility of being used on a non-serial +port TTY, for which no alternate device would exist. + +\subsection{Pseudoterminals (PTYs)} + +Pseudoterminals, or PTYs, are used to create login sessions or provide +other capabilities requiring a TTY line dicipline (including SLIP or +PPP capability) to arbitrary data-generation processes. Each PTY has +a {\em master\/} side, named {\file /dev/pty[p-za-e][0-9a-f]\/}, and a +{\em slave\/} side, named {\file /dev/tty[p-za-e][0-9a-f]\/}. The +kernel arbitrates the use of PTYs by allowing each master side to be +opened only once. + +Once the master side has been opened, the corresponding slave device +can be used in the same manner as any TTY device. The master and +slave devices are connected by the kernel, generating the equivalent +of a bidirectional pipe with TTY capabilities. + +The entire namespace {\file /dev/[pt]ty[p-za-o][0-9a-z]\/} should be +considered reserved for the future use of PTYs. Should more than 936 +PTYs ever become a necessity, we will likely adopt a System V-like +scheme by which PTYs use a subdirectory of {\file /dev}. + +\end{document} diff -u --recursive --new-file v2.1.28/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.1.28/linux/Documentation/devices.txt Sat Dec 21 00:40:58 1996 +++ linux/Documentation/devices.txt Tue Mar 4 10:07:24 1997 @@ -2,7 +2,7 @@ Maintained by H. Peter Anvin - Last revised: December 20, 1996 + Last revised: March 3, 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 @@ -628,12 +628,6 @@ 129 = /dev/smpte1 Second MIDI port, SMPTE timed 130 = /dev/smpte2 Third MIDI port, SMPTE timed 131 = /dev/smpte3 Fourth MIDI port, SMPTE timed - block Modular RAM disk device - - This device number is provided for older kernels which - did not have the modular RAM disk in the standard - distribution. See major number 1. This assignment - will be removed when the 2.0 kernel is released. 36 char Netlink support 0 = /dev/route Routing, device updates, kernel to user @@ -850,7 +844,83 @@ See http://www.coda.cs.cmu.edu for information about Coda. - 68-119 UNALLOCATED + 68 char CAPI 2.0 interface + 0 = /dev/capi20 Control device + 1 = /dev/capi20.00 First CAPI 2.0 application + 2 = /dev/capi20.01 Second CAPI 2.0 application + ... + 20 = /dev/capi20.19 19th CAPI 2.0 application + + ISDN CAPI 2.0 driver for use with CAPI 2.0 + applications; currently supports the AVM B1 card. + + 69 char MA16 numeric accelerator card + 0 = /dev/ma16 Board memory access + + 70 char SpellCaster Protocol Services Interface + 0 = /dev/apscfg Configuration interface + 1 = /dev/apsauth Authentication interface + 2 = /dev/apslog Logging interface + 3 = /dev/apsdbg Debugging interface + 64 = /dev/apsisdn ISDN command interface + 65 = /dev/apsasync Async command interface + 128 = /dev/apsmon Monitor interface + + 71 char Computone IntelliPort II serial card + 0 = /dev/ttyF0 IntelliPort II board 0, port 0 + 1 = /dev/ttyF1 IntelliPort II board 0, port 1 + ... + 63 = /dev/ttyF63 IntelliPort II board 0, port 63 + 64 = /dev/ttyF64 IntelliPort II board 1, port 0 + 65 = /dev/ttyF65 IntelliPort II board 1, port 1 + ... + 127 = /dev/ttyF127 IntelliPort II board 1, port 63 + 128 = /dev/ttyF128 IntelliPort II board 2, port 0 + 129 = /dev/ttyF129 IntelliPort II board 2, port 1 + ... + 191 = /dev/ttyF191 IntelliPort II board 2, port 63 + 192 = /dev/ttyF192 IntelliPort II board 3, port 0 + 193 = /dev/ttyF193 IntelliPort II board 3, port 1 + ... + 255 = /dev/ttyF255 IntelliPort II board 3, port 63 + + 72 char Computone IntelliPort II serial card - alternate devices + 0 = /dev/cuf0 Callout device corresponding to ttyF0 + 1 = /dev/cuf1 Callout device corresponding to ttyF1 + ... + 63 = /dev/cuf63 Callout device corresponding to ttyF63 + 64 = /dev/cuf64 Callout device corresponding to ttyF64 + 65 = /dev/cuf65 Callout device corresponding to ttyF65 + ... + 127 = /dev/cuf127 Callout device corresponding to ttyF127 + 128 = /dev/cuf128 Callout device corresponding to ttyF128 + 129 = /dev/cuf129 Callout device corresponding to ttyF129 + ... + 191 = /dev/cuf191 Callout device corresponding to ttyF191 + 192 = /dev/cuf192 Callout device corresponding to ttyF192 + 193 = /dev/cuf193 Callout device corresponding to ttyF193 + ... + 255 = /dev/cuf255 Callout device corresponding to ttyF255 + + 73 char Computone IntelliPort II serial card - control devices + 0 = /dev/ip2ipl0 Loadware device for board 0 + 1 = /dev/ip2stat0 Status device for board 0 + 4 = /dev/ip2ipl1 Loadware device for board 1 + 5 = /dev/ip2stat1 Status device for board 1 + 8 = /dev/ip2ipl2 Loadware device for board 2 + 9 = /dev/ip2stat2 Status device for board 2 + 12 = /dev/ip2ipl3 Loadware device for board 3 + 13 = /dev/ip2stat3 Status device for board 3 + + 74 char SCI bridge + 0 = /dev/SCI/0 SCI device 0 + 1 = /dev/SCI/1 SCI device 1 + ... + + Currently for Dolphin Interconnect Solutions' PCI-SCI + bridge. + + 75-119 UNALLOCATED 120-127 LOCAL/EXPERIMENTAL USE @@ -864,7 +934,7 @@ - ADDITIONAL /dev DIRECTORY ENTRIES + **** ADDITIONAL /dev DIRECTORY ENTRIES This section details additional entries that should or may exist in the /dev directory. It is preferred that symbolic links use the same @@ -932,3 +1002,104 @@ /dev/printer socket lpd local socket /dev/log socket syslog local socket /dev/gpmdata socket gpm mouse multiplexer + + + **** TERMINAL DEVICES + +Terminal, or TTY devices are a special class of character devices. A +terminal device is any device that could act as a controlling terminal +for a session; this includes virtual consoles, serial ports, and +pseudoterminals (PTYs). + +All terminal devices share a common set of capabilities known as line +diciplines; these include the common terminal line dicipline as well +as SLIP and PPP modes. + +All terminal devices are named similarly; this section explains the +naming and use of the various types of TTYs. Note that the naming +conventions include several historical warts; some of these are +Linux-specific, some were inherited from other systems, and some +reflect Linux outgrowing a borrowed convention. + +A hash mark (#) in a device name is used here to indicate a decimal +number without leading zeroes. + + Virtual consoles and the console device + +Virtual consoles are full-screen terminal displays on the system video +monitor. Virtual consoles are named /dev/tty#, with numbering +starting at /dev/tty1; /dev/tty0 is the current virtual console. +/dev/tty0 is the device that should be used to access the system video +card on those architectures for which the frame buffer devices +(/dev/fb*) do not exist (including the x86). Do not use /dev/console +for this purpose. + +The console device, /dev/console, is the device to which system +messages should be sent, and on which logins should be permitted in +single-user mode. /dev/console should be a symbolic link to either +/dev/tty0, a specific virtual console such as /dev/tty1, or to a +serial port primary (tty*, not cu*) device, depending on the +configuration of the system. + + Serial ports + +Serial ports are RS-232 serial ports and any device which simulates +one, either in hardware (such as internal modems) or in software (such +as the ISDN driver.) Under Linux, each serial ports has two device +names, the primary or callin device and the alternate or callout one. +Each kind of device is indicated by a different letter. For any +letter X, the names of the devices are /dev/ttyX# and /dev/cux#, +respectively; for historical reasons, /dev/ttyS# and /dev/ttyC# +correspond to /dev/cua# and /dev/cub#. In the future, it should be +expected that multiple letters will be used; all letters will be upper +case for the "tty" device and lower case for the "cu" device. + +The alternate devices provide for kernel-based exclusion and somewhat +different defaults than the primary devices. Their main purpose is to +allow the use of serial ports with programs with no inherent or broken +support for serial ports. For programs with proper knowledge of +serial port operation, their use should probably be avoided. + +Arbitration of serial ports is provided by the use of lock files with +the names /var/lock/LCK..ttyX#. The contents of the lock file should +be the PID of the locking process as an ASCII number. + +It is common practice to install links such as /dev/modem +which point to serial ports. In order to ensure proper locking in the +presence of these links, it is recommended that software chase +symlinks and lock all possible names; additionally, it is recommended +that a lock file be installed with the corresponding alternate +device. In order to avoid deadlocks, it is recommended that the locks +are acquired in the following order, and released in the reverse: + + 1. The symbolic link name, if any (/var/lock/LCK..modem) + 2. The "tty" name (/var/lock/LCK..ttyS2) + 3. The alternate device name (/var/lock/LCK..cua2) + +In the case of nested symbolic links, the lock files should be +installed in the order the symlinks are resolved. + +Under no circumstances should an application hold a lock while waiting +for another to be released. In addition, applications which attempt +to create lock files for the corresponding alternate device names +should take into account the possibility of being used on a non-serial +port TTY, for which no alternate device would exist. + + Pseudoterminals (PTYs) + +Pseudoterminals, or PTYs, are used to create login sessions or provide +other capabilities requiring a TTY line dicipline (including SLIP or +PPP capability) to arbitrary data-generation processes. Each PTY has +a master side, named /dev/pty[p-za-e][0-9a-f], and a slave side, named +/dev/tty[p-za-e][0-9a-f]. The kernel arbitrates the use of PTYs by +allowing each master side to be opened only once. + +Once the master side has been opened, the corresponding slave device +can be used in the same manner as any TTY device. The master and +slave devices are connected by the kernel, generating the equivalent +of a bidirectional pipe with TTY capabilities. + +The entire namespace /dev/[pt]ty[p-za-o][0-9a-z] should be considered +reserved for the future use of PTYs. Should more than 936 PTYs ever +become a necessity, we will likely adopt a System V-like scheme by +which PTYs use a subdirectory of /dev. diff -u --recursive --new-file v2.1.28/linux/Documentation/stallion.txt linux/Documentation/stallion.txt --- v2.1.28/linux/Documentation/stallion.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/stallion.txt Tue Mar 4 13:33:21 1997 @@ -0,0 +1,293 @@ + +Stallion Multiport Serial Driver Readme +--------------------------------------- + +Copyright (C) 1994-1997, Stallion Technologies (support@stallion.oz.au). + +Version: 5.3.2 +Date: 11FEB97 + + + +1. INTRODUCTION + +There are two drivers that work with the different families of Stallion +multiport serial boards. One is for the Stallion smart boards - that is +EasyIO and EasyConnection 8/32, the other for the true Stallion intelligent +multiport boards - EasyConnection 8/64, ONboard and Brumby. + +If you are using any of the Stallion intelligent multiport boards (Brumby, +ONboard, EasyConnection 8/64) with Linux you will need to get the driver +utility package. This package is available at most of the Linux archive +sites (and on CD's that contain these archives). The file will be called +stallion-X.X.X.tar.gz where X.X.X will be the version number. In particular +this package contains the board embedded executable images that are +required for these boards. It also contains the downloader program. +These boards cannot be used without this. + +The following ftp sites (and their mirrors) definitely have the stallion +driver utility package: ftp.stallion.com, tsx-11.mit.edu, sunsite.unc.edu. + +ftp.stallion.com:/drivers/ata5/Linux/stallion-5.3.1.tar.gz +tsx-11.mit.edu:/pub/linux/BETA/serial/stallion/stallion-5.3.1.tar.gz +sunsite.unc.edu:/pub/Linux/kernel/patches/serial/stallion-5.3.1.tar.gz + +As of the printing of this document the latest version of the driver +utility package is 5.3.1. If a later version is now available then you +should use the latest version. + +If you are using the EasyIO or EasyConnection 8/32 boards then you don't +need this package. Although it does have a handy script to create the +/dev device nodes for these boards, and a serial stats display program. + +If you require DIP switch settings, EISA/MCA configuration files, or any +other information related to Stallion boards then have a look at Stallion's +web pages at http://www.stallion.com. + + + +2. INSTALLATION + +The drivers can be used as loadable modules or compiled into the kernel. +You can choose which when doing a "config" on the kernel. + +All ISA, EISA and MCA boards that you want to use need to be entered into +the driver(s) configuration structures. All PCI boards will be automatically +detected when you load the driver - so they do not need to be entered into +the driver(s) configuration structure. (Note that kernel PCI BIOS32 support +is required to use PCI boards.) + +Entering ISA, EISA and MCA boards into the driver(s) configuration structure +involves editing the driver(s) source file. It's pretty easy if you follow +the instructions below. Both drivers can support up to 4 boards. The smart +card driver (the stallion.c driver) supports any combination of EasyIO and +EasyConnection 8/32 boards (up to a total of 4). The intelligent driver +supports any combination of ONboards, Brumbys, Stallions and EasyConnection +8/64 boards (up to a total of 4). + +To set up the driver(s) for the boards that you want to use you need to +edit the appropriate driver file and add configuration entries. + +If using EasyIO or EasyConnection 8/32 ISA or MCA boards, do: + vi /usr/src/linux/drivers/char/stallion.c + - find the definition of the stl_brdconf array (of structures) + near the top of the file + - modify this to match the boards you are going to install + (the comments before this structure should help) + - save and exit + +If using ONboard, Brumby, Stallion or EasyConnection 8/64 boards then do: + vi /usr/src/linux/drivers/char/istallion.c + - find the definition of the stli_brdconf array (of structures) + near the top of the file + - modify this to match the boards you are going to install + (the comments before this structure should help) + - save and exit + +Once you have set up the board configurations then you are ready to build +the kernel or modules. + +When the new kernel is booted, or the loadable module loaded then the +driver will emit some kernel trace messages about whether the configured +boards where detected or not. Depending on how your system logger is set +up these may come out on the console, or just be logged to +/var/adm/messages. You should check the messages to confirm that all is well. + + +2.1 SHARING INTERRUPTS + +It is possible to share interrupts between multiple EasyIO and +EasyConnection 8/32 boards in an EISA system. To do this you will need to +do a couple of things: + +1. When entering the board resources into the stallion.c file you need to + mark the boards as using level triggered interrupts. Do this by replacing + the "0" entry at field position 6 (the last field) in the board + configuration structure with a "1". (This is the structure that defines + the board type, I/O locations, etc. for each board). All boards that are + sharing an interrupt must be set this way, and each board should have the + same interrupt number specified here as well. Now build the module or + kernel as you would normally. + +2. When physically installing the boards into the system you must enter + the system EISA configuration utility. You will need to install the EISA + configuration files for *all* the EasyIO and EasyConnection 8/32 boards + that are sharing interrupts. The Stallion EasyIO and EasyConnection 8/32 + EISA configuration files required are supplied by Stallion Technologies + on the EASY Utilities floppy (usually supplied in the box with the board + when purchased. If not, you can pick it up from Stallion's FTP site, + ftp.stallion.com). You will need to edit the board resources to choose + level triggered interrupts, and make sure to set each board's interrupt + to the same IRQ number. + +You must complete both the above steps for this to work. When you reboot +or load the driver your EasyIO and EasyConnection 8/32 boards will be +sharing interrupts. + + +2.2 USING HIGH SHARED MEMORY + +The EasyConnection 8/64-EI, ONboard and Stallion boards are capable of +using shared memory addresses above the usual 640K - 1Mb range. The ONboard +ISA and the Stallion boards can be programmed to use memory addresses up to +16Mb (the ISA bus addressing limit), and the EasyConnection 8/64-EI and +ONboard/E can be programmed for memory addresses up to 4Gb (the EISA bus +addressing limit). + +The higher than 1Mb memory addresses are fully supported by this driver. +Just enter the address as you normally would for a lower than 1Mb address +(in the drivers board configuration structure). + + + +2.3 TROUBLE SHOOTING + +If a board is not found by the driver but is actually in the system then the +most likely problem is that the I/O address is wrong. Change it in the driver +stallion.c or istallion.c configuration structure and rebuild the kernel or +modules, or change it on the board. On EasyIO and EasyConnection 8/32 boards +the IRQ is software programmable, so if there is a conflict you may need to +change the IRQ used for a board in the stallion.c configuration structure. +There are no interrupts to worry about for ONboard, Brumby or EasyConnection +8/64 boards. The memory region on EasyConnection 8/64 and ONboard boards is +software programmable, but not on the Brumby boards. + + + +3. USING THE DRIVERS + +3.1 INTELLIGENT DRIVER OPERATION + +The intelligent boards also need to have their "firmware" code downloaded +to them. This is done via a user level application supplied in the driver +utility package called "stlload". Compile this program where ever you dropped +the package files, by typing "make". In its simplest form you can then type + ./stlload -i cdk.sys +in this directory and that will download board 0 (assuming board 0 is an +EasyConnection 8/64 board). To download to an ONboard, Brumby or Stallion do: + ./stlload -i 2681.sys + +Normally you would want all boards to be downloaded as part of the standard +system startup. To achieve this, add one of the lines above into the +/etc/rc.d/rc.S or /etc/rc.d/rc.serial file. To download each board just add +the "-b " option to the line. You will need to download code for +every board. You should probably move the stlload program into a system +directory, such as /usr/sbin. Also, the default location of the cdk.sys image +file in the stlload down-loader is /usr/lib/stallion. Create that directory +and put the cdk.sys and 2681.sys files in it. (It's a convenient place to put +them anyway). As an example your /etc/rc.d/rc.S file might have the +following lines added to it (if you had 3 boards): + /usr/sbin/stlload -b 0 -i /usr/lib/stallion/cdk.sys + /usr/sbin/stlload -b 1 -i /usr/lib/stallion/2681.sys + /usr/sbin/stlload -b 2 -i /usr/lib/stallion/2681.sys + +The image files cdk.sys and 2681.sys are specific to the board types. The +cdk.sys will only function correctly on an EasyConnection 8/64 board. Similarly +the 2681.sys image fill only operate on ONboard, Brumby and Stallion boards. +If you load the wrong image file into a board it will fail to start up, and +of course the ports will not be operational! + +If you are using the modularized version of the driver you might want to put +the insmod calls in the startup script as well (before the download lines +obviously). + + +3.2 USING THE SERIAL PORTS + +Once the driver is installed you will need to setup some device nodes to +access the serial ports. The simplest method is to use the stallion utility +"mkdevnods" script. It will automatically create device entries for Stallion +boards. This will create the normal serial port devices as /dev/ttyE# where +# is the port number starting from 0. A bank of 64 minor device numbers is +allocated to each board, so the first port on the second board is port 64, +etc. A set of callout type devices is also created. They are created as the +devices /dev/cue# where # is the same as for the ttyE devices. + +For the most part the Stallion driver tries to emulate the standard PC system +COM ports and the standard Linux serial driver. The idea is that you should +be able to use Stallion board ports and COM ports interchangeably without +modifying anything but the device name. Anything that doesn't work like that +should be considered a bug in this driver! + +If you look at the driver code you will notice that it is fairly closely +based on the Linux serial driver (linux/drivers/char/serial.c). This is +intentional, obviously this is the easiest way to emulate its behavior! + +Since this driver tries to emulate the standard serial ports as much as +possible, most system utilities should work as they do for the standard +COM ports. Most importantly "stty" works as expected and "setserial" can be +also be used (excepting the ability to auto-configure the I/O and IRQ +addresses of boards). Higher baud rates are supported in the usual fashion +through setserial or using the CBAUDEX extensions. Note that the EasyIO and +EasyConnection (all types) support at least 57600 and 115200 baud. The newer +EasyConnection XP modules and new EasyIO boards support 230400 and 460800 +baud as well. The older boards including ONboard and Brumby support a +maximum baud rate of 38400. + +If you are unfamiliar with how to use serial ports, then get the Serial-HOWTO +by Greg Hankins. It will explain everything you need to know! + + + +4. NOTES + +You can use both drivers at once if you have a mix of board types installed +in a system. However to do this you will need to change the major numbers +used by one of the drivers. Currently both drivers use major numbers 24, 25 +and 28 for their devices. Change one driver to use some other major numbers, +and then modify the mkdevnods script to make device nodes based on those new +major numbers. For example, you could change the istallion.c driver to use +major numbers 60, 61 and 62. You will also need to create device nodes with +different names for the ports, for example ttyF# and cuf#. + +The original Stallion board is no longer supported by Stallion Technologies. +Although it is known to work with the istallion driver. + +Finding a free physical memory address range can be a problem. The older +boards like the Stallion and ONboard need large areas (64K or even 128K), so +they can be very difficult to get into a system. If you have 16 Mb of RAM +then you have no choice but to put them somewhere in the 640K -> 1Mb range. +ONboards require 64K, so typically 0xd0000 is good, or 0xe0000 on some +systems. If you have an original Stallion board, "V4.0" or Rev.O, then you +need a 64K memory address space, so again 0xd0000 and 0xe0000 are good. +Older Stallion boards are a much bigger problem. They need 128K of address +space and must be on a 128K boundary. If you don't have a VGA card then +0xc0000 might be usable - there is really no other place you can put them +below 1Mb. + +Both the ONboard and old Stallion boards can use higher memory addresses as +well, but you must have less than 16Mb of RAM to be able to use them. Usual +high memory addresses used include 0xec0000 and 0xf00000. + +The Brumby boards only require 16Kb of address space, so you can usually +squeeze them in somewhere. Common addresses are 0xc8000, 0xcc000, or in +the 0xd0000 range. EasyConnection 8/64 boards are even better, they only +require 4Kb of address space, again usually 0xc8000, 0xcc000 or 0xd0000 +are good. + +If you are using an EasyConnection 8/64-EI or ONboard/E then usually the +0xd0000 or 0xe0000 ranges are the best options below 1Mb. If neither of +them can be used then the high memory support to use the really high address +ranges is the best option. Typically the 2Gb range is convenient for them, +and gets them well out of the way. + +The ports of the EasyIO-8M board do not have DCD or DTR signals. So these +ports cannot be used as real modem devices. Generally, when using these +ports you should only use the cueX devices. + +The driver utility package contains a couple of very useful programs. One +is a serial port statistics collection and display program - very handy +for solving serial port problems. The other is an extended option setting +program that works with the intelligent boards. + + + +5. DISCLAIMER + +The information contained in this document is believed to be accurate and +reliable. However, no responsibility is assumed by Stallion Technologies +Pty. Ltd. for its use, nor any infringements of patents or other rights +of third parties resulting from its use. Stallion Technologies reserves +the right to modify the design of its products and will endeavour to change +the information in manuals and accompanying documentation accordingly. + diff -u --recursive --new-file v2.1.28/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.28/linux/MAINTAINERS Tue Mar 4 10:25:22 1997 +++ linux/MAINTAINERS Tue Mar 4 13:19:06 1997 @@ -102,6 +102,11 @@ W: http://www.dgii.com/linux/ S: Maintained +WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS +P: Jean Tourrilhes +M: jt@hplb.hpl.hp.com +S: Maintained + APM DRIVER P: Rik Faith & Stephen Rothwell M: faith@cs.unc.edu, Stephen.Rothwell@canb.auug.org.au diff -u --recursive --new-file v2.1.28/linux/Makefile linux/Makefile --- v2.1.28/linux/Makefile Tue Mar 4 10:25:22 1997 +++ linux/Makefile Wed Mar 5 16:21:54 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 28 +SUBLEVEL = 29 ARCH = i386 Binary files v2.1.28/linux/arch/i386/boot/map and linux/arch/i386/boot/map differ diff -u --recursive --new-file v2.1.28/linux/arch/sparc/Makefile linux/arch/sparc/Makefile --- v2.1.28/linux/arch/sparc/Makefile Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/Makefile Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.23 1997/01/02 14:14:17 jj Exp $ +# $Id: Makefile,v 1.26 1997/03/04 16:26:50 jj Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -15,8 +15,8 @@ # Uncomment the first CFLAGS if you are doing kgdb source level # debugging of the kernel to get the proper debugging information. -#CFLAGS := $(CFLAGS) -g -pipe -CFLAGS := $(CFLAGS) -pipe +#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 +CFLAGS := $(CFLAGS) -pipe -fcall-used-g5 -fcall-used-g7 #LINKFLAGS = -N -Ttext 0xf0004000 LINKFLAGS = -T arch/sparc/vmlinux.lds @@ -41,3 +41,6 @@ archclean: archdep: + +check_asm: + $(MAKE) -C arch/sparc/kernel check_asm diff -u --recursive --new-file v2.1.28/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.1.28/linux/arch/sparc/config.in Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/config.in Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.32 1997/01/25 23:10:12 ecd Exp $ +# $Id: config.in,v 1.33 1997/02/05 14:25:01 tdyas Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -41,6 +41,7 @@ define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y source drivers/sbus/char/Config.in + source drivers/sbus/audio/Config.in fi tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS diff -u --recursive --new-file v2.1.28/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.1.28/linux/arch/sparc/defconfig Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/defconfig Wed Mar 5 17:04:30 1997 @@ -40,16 +40,20 @@ SUN_FB_BWTWO=y SUN_FB_LEO=y TADPOLE_FB_WEITEK=y -SUN_FB_FAST_ONE=y -SUN_FB_FAST_TWO=y -SUN_FB_FAST_MONO=y -SUN_FB_GENERIC=y # # Misc Linux/SPARC drivers # CONFIG_SUN_OPENPROMIO=m CONFIG_SUN_MOSTEK_RTC=y +# CONFIG_SUN_BPP is not set + +# +# Linux/SPARC audio subsystem (EXPERIMENTAL) +# +# CONFIG_SPARCAUDIO is not set +# CONFIG_SPARCAUDIO_AMD7930 is not set +# CONFIG_SPARCAUDIO_CS4231 is not set CONFIG_SUN_OPENPROMFS=m CONFIG_NET=y CONFIG_SYSVIPC=y @@ -76,7 +80,6 @@ CONFIG_FIREWALL=y CONFIG_NET_ALIAS=y CONFIG_INET=y -CONFIG_IP_FORWARD=y CONFIG_IP_MULTICAST=y CONFIG_IP_FIREWALL=y # CONFIG_IP_FIREWALL_NETLINK is not set @@ -90,7 +93,7 @@ # CONFIG_IP_ALWAYS_DEFRAG is not set # CONFIG_IP_ACCT is not set # CONFIG_IP_ROUTER is not set -CONFIG_NET_IPIP=m +# CONFIG_NET_IPIP is not set # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=m # CONFIG_ARPD is not set @@ -112,11 +115,13 @@ # CONFIG_IPX_INTERN is not set # CONFIG_IPX_PPROP_ROUTING is not set CONFIG_ATALK=m +# CONFIG_IPDDP is not set # CONFIG_AX25 is not set CONFIG_X25=m # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set # CONFIG_LLC is not set +# CONFIG_WAN_ROUTER is not set # # SCSI support diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v2.1.28/linux/arch/sparc/kernel/Makefile Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/kernel/Makefile Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.37 1997/01/06 06:52:15 davem Exp $ +# $Id: Makefile,v 1.38 1997/03/04 16:26:29 jj Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -59,5 +59,20 @@ $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o endif + +check_asm: dummy + @echo "#include " > tmp.c + $(CC) -E tmp.c -o tmp.i + @echo "/* Automatically generated. Do not edit. */" > check_asm.c; echo "#include " >> check_asm.c; echo 'struct task_struct _task; struct mm_struct _mm; struct thread_struct _thread; int main(void) { printf ("/* Automatically generated. Do not edit. */\n#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n\n");' >> check_asm.c + $(SH) ./check_asm.sh task tmp.i check_asm.c + $(SH) ./check_asm.sh mm tmp.i check_asm.c + $(SH) ./check_asm.sh thread tmp.i check_asm.c + @echo 'printf ("\n#endif /* __ASM_OFFSETS_H__ */\n"); return 0; }' >> check_asm.c + @rm -f tmp.[ci] + $(CC) -o check_asm check_asm.c + ./check_asm > asm_offsets.h + @if test -r $(HPATH)/asm/asm_offsets.h; then if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then echo $(HPATH)/asm/asm_offsets.h is unchanged; rm -f asm_offsets.h; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi + @rm -f check_asm check_asm.c + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/auxio.c linux/arch/sparc/kernel/auxio.c --- v2.1.28/linux/arch/sparc/kernel/auxio.c Fri Dec 13 01:37:30 1996 +++ linux/arch/sparc/kernel/auxio.c Wed Mar 5 17:04:30 1997 @@ -3,6 +3,7 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include #include @@ -49,4 +50,34 @@ auxio_register = (unsigned char *) ((int)auxio_register | 3); TURN_ON_LED; +} + + +/* sun4m power control register (AUXIO2) */ + +volatile unsigned char * auxio_power_register = NULL; + +__initfunc(void auxio_power_probe(void)) +{ + struct linux_prom_registers regs; + int node; + + /* Attempt to find the sun4m power control node. */ + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "obio"); + node = prom_getchild(node); + node = prom_searchsiblings(node, "power"); + if (node == 0 || node == -1) + return; + + /* Map the power control register. */ + prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); + prom_apply_obio_ranges(®s, 1); + auxio_power_register = (volatile unsigned char *) + sparc_alloc_io(regs.phys_addr, 0, regs.reg_size, + "power off control", regs.which_io, 0); + + /* Display a quick message on the console. */ + if (auxio_power_register) + printk(KERN_INFO "Power off control detected.\n"); } diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/check_asm.sh linux/arch/sparc/kernel/check_asm.sh --- v2.1.28/linux/arch/sparc/kernel/check_asm.sh Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc/kernel/check_asm.sh Wed Mar 5 17:04:30 1997 @@ -0,0 +1,3 @@ +#!/bin/sh +sed -n -e '/struct[ ]*'$1'_struct[ ]*{/,/};/p' < $2 | sed '/struct[ ]*'$1'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ +/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$1'_\0 0x%08x\\n#define ASIZ_'$1'_\0 0x%08x\\n", ((char *)\&_'$1'.\0) - ((char *)\&_'$1'), sizeof(_'$1'.\0));/' >> $3 diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c --- v2.1.28/linux/arch/sparc/kernel/devices.c Thu Dec 19 01:03:32 1996 +++ linux/arch/sparc/kernel/devices.c Wed Mar 5 17:04:30 1997 @@ -64,10 +64,12 @@ linux_num_cpus = cpu_ctr; cpu_probe(); -#if CONFIG_SUN_AUXIO +#ifdef CONFIG_SUN_AUXIO { - extern void auxio_probe(void); - auxio_probe(); + extern void auxio_probe(void); + extern void auxio_power_probe(void); + auxio_probe(); + auxio_power_probe(); } #endif clock_stop_probe(); diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v2.1.28/linux/arch/sparc/kernel/entry.S Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/kernel/entry.S Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.131 1997/01/12 09:06:55 davem Exp $ +/* $Id: entry.S,v 1.133 1997/03/04 16:26:22 jj Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -888,11 +888,11 @@ ! Flush segment from the cache. sethi %hi((64 * 1024)), %l7 -1: +9: C_LABEL(vac_hwflush_patch1): C_LABEL(vac_linesize_patch): subcc %l7, 16, %l7 - bg 1b + bg 9b C_LABEL(vac_hwflush_patch2): sta %g0, [%l3 + %l7] ASI_FLUSHSEG @@ -1209,7 +1209,7 @@ rd %wim, %g5 WRITE_PAUSE mov %fp, %o1 ! arg1: usp - std %g4, [%curptr + THREAD_FORK_KPSR] + std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr] add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr call C_LABEL(do_fork) mov %l5, %o7 @@ -1231,7 +1231,7 @@ mov %fp, %o1 ! yes, use callers usp andn %o1, 7, %o1 ! no, align to 8 bytes 1: - std %g4, [%curptr + THREAD_FORK_KPSR] + std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr] add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr call C_LABEL(do_fork) mov %l5, %o7 @@ -1652,7 +1652,7 @@ * traps with the old method of just doing flush_user_windows(). */ C_LABEL(kill_user_windows): - ld [%g6 + THREAD_UMASK], %o0 ! get current umask + ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], %o0 ! get current umask orcc %g0, %o0, %g0 ! if no bits set, we are done be 3f ! nothing to do rd %psr, %o5 ! must clear interrupts @@ -1660,7 +1660,7 @@ wr %o4, 0x0, %psr ! the uwinmask state WRITE_PAUSE ! burn them cycles 1: - ld [%g6 + THREAD_UMASK], %o0 ! get consistant state + ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], %o0 ! get consistant state orcc %g0, %o0, %g0 ! did an interrupt come in? be 4f ! yep, we are done rd %wim, %o3 ! get current wim @@ -1672,12 +1672,12 @@ bne kuw_patch1 ! not done yet srl %o3, 1, %o4 ! begin another save simulation wr %o3, 0x0, %wim ! set the new wim - st %g0, [%g6 + THREAD_UMASK] ! clear uwinmask + st %g0, [%g6 + AOFF_task_tss + AOFF_thread_uwinmask] ! clear uwinmask 4: wr %o5, 0x0, %psr ! re-enable interrupts WRITE_PAUSE ! burn baby burn 3: retl ! return - st %g0, [%g6 + THREAD_W_SAVED] ! no windows saved + st %g0, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] ! no windows saved /* End of entry.S */ diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S --- v2.1.28/linux/arch/sparc/kernel/etrap.S Fri Dec 13 01:37:30 1996 +++ linux/arch/sparc/kernel/etrap.S Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.22 1996/12/03 08:44:33 jj Exp $ +/* $Id: etrap.S,v 1.23 1997/03/04 16:26:25 jj Exp $ * etrap.S: Sparc trap window preparation for entry into the * Linux kernel. * @@ -100,7 +100,7 @@ mov %t_kstack, %sp ! jump onto new stack trap_setup_kernel_spill: - ld [%curptr + THREAD_UMASK], %g1 + ld [%curptr + AOFF_task_tss + AOFF_thread_uwinmask], %g1 orcc %g0, %g1, %g0 bne trap_setup_user_spill ! there are some user windows, yuck /* Spill from kernel, but only kernel windows, adjust @@ -130,7 +130,7 @@ /* We can't use %curptr yet. */ LOAD_CURRENT(t_kstack, t_twinmask) mov 1, %t_twinmask - ld [%t_kstack + TASK_SAVED_KSTACK], %t_kstack + 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. */ @@ -138,7 +138,7 @@ /* Clear current->tss.w_saved */ LOAD_CURRENT(curptr, g1) - st %g0, [%curptr + THREAD_W_SAVED] + st %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved] /* See if we are in the trap window. */ andcc %t_twinmask, %t_wim, %g0 @@ -169,7 +169,7 @@ andn %g2, %t_twinmask, %g2 tsetup_patch3: and %g2, 0xff, %g2 ! patched on 7win Sparcs - st %g2, [%curptr + THREAD_UMASK] ! store new umask + st %g2, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] ! store new umask jmpl %t_retpc + 0x8, %g0 ! return to caller mov %t_kstack, %sp ! and onto kernel stack @@ -190,7 +190,7 @@ tsetup_patch6: and %g2, 0xff, %g2 ! patched on 7win Sparcs andn %g1, %g2, %g1 ! clear this bit in %g1 - st %g1, [%curptr + THREAD_UMASK] + st %g1, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] save %g0, %g0, %g0 diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S --- v2.1.28/linux/arch/sparc/kernel/head.S Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/kernel/head.S Wed Mar 5 17:04:30 1997 @@ -1,9 +1,10 @@ -/* $Id: head.S,v 1.78 1997/01/06 06:52:20 davem Exp $ +/* $Id: head.S,v 1.79 1997/03/04 16:26:31 jj Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Peter Zaitcev (Zaitcev@ipmce.su) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -67,10 +68,6 @@ .asciz "Sparc-Linux sun4e support does not exist\n\n" .align 4 -sun4u_notsup: - .asciz "Sparc-Linux sun4u support does not exist\n\n" - .align 4 - /* The Sparc trap table, bootloader gives us control at _start. */ .text .globl start, _stext, _start, __stext @@ -477,8 +474,11 @@ 1: mov %o7, %g3 -got_pc: - mov %g4, %o7 /* Previous %o7. */ +#ifndef CONFIG_AP1000 + tst %o0 + be no_sun4u_here +#endif + mov %g4, %o7 /* Previous %o7. */ mov %o0, %l0 ! stash away romvec mov %o0, %g7 ! put it here too @@ -991,8 +991,8 @@ st %g6, [%g2] set C_LABEL(bootup_kernel_stack), %g3 - st %g3, [%g6 + TASK_KSTACK_PG] - st %g0, [%g6 + THREAD_UMASK] + 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 * in the V8 manual. Ok, this method seems to work, Sparc is cool... @@ -1133,14 +1133,90 @@ b halt_me nop + __INITDATA + +sun4u_1: + .asciz "finddevice" + .align 4 +sun4u_2: + .asciz "/chosen" + .align 4 +sun4u_3: + .asciz "getprop" + .align 4 +sun4u_4: + .asciz "stdout" + .align 4 +sun4u_5: + .asciz "write" + .align 4 +sun4u_6: + .asciz "\n\rOn sun4u you have to use UltraLinux (64bit) kernel\n\rand not a 32bit sun4[cdem] version\n\r\n\r" +sun4u_6e: + .align 4 +sun4u_7: + .asciz "exit" + .align 8 +sun4u_a1: + .word 0, sun4u_1, 0, 1, 0, 1, 0, sun4u_2, 0 +sun4u_r1: + .word 0 +sun4u_a2: + .word 0, sun4u_3, 0, 4, 0, 1, 0 +sun4u_i2: + .word 0, 0, sun4u_4, 0, sun4u_1, 0, 8, 0 +sun4u_r2: + .word 0 +sun4u_a3: + .word 0, sun4u_5, 0, 3, 0, 1, 0 +sun4u_i3: + .word 0, 0, sun4u_6, 0, sun4u_6e - sun4u_6 - 1, 0 +sun4u_r3: + .word 0 +sun4u_a4: + .word 0, sun4u_7, 0, 0, 0, 0 +sun4u_r4: + + __INIT no_sun4u_here: - ld [%g7 + 0x68], %o1 - set sun4u_notsup, %o0 - call %o1 - nop - b halt_me - nop + set sun4u_a1, %o0 + set current_pc, %l2 + cmp %l2, %g3 + be 1f + mov %o4, %l0 + sub %g3, %l2, %l6 + add %o0, %l6, %o0 + mov %o0, %l4 + mov sun4u_r4 - sun4u_a1, %l3 + ld [%l4], %l5 +2: + add %l4, 4, %l4 + cmp %l5, %l2 + add %l5, %l6, %l5 + bgeu,a 3f + st %l5, [%l4 - 4] +3: + subcc %l3, 4, %l3 + bne 2b + ld [%l4], %l5 +1: + call %l0 + mov %o0, %l1 + + ld [%l1 + (sun4u_r1 - sun4u_a1)], %o1 + add %l1, (sun4u_a2 - sun4u_a1), %o0 + call %l0 + st %o1, [%o0 + (sun4u_i2 - sun4u_a2)] + + ld [%l1 + (sun4u_1 - sun4u_a1)], %o1 + add %l1, (sun4u_a3 - sun4u_a1), %o0 + call %l0 + st %o1, [%o0 + (sun4u_i3 - sun4u_a3)] + + call %l0 + add %l1, (sun4u_a4 - sun4u_a1), %o0 + /* Not reached */ halt_me: ld [%g7 + 0x74], %o0 call %o0 ! Get us out of here... diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.1.28/linux/arch/sparc/kernel/process.c Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/kernel/process.c Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.89 1997/01/06 06:52:23 davem Exp $ +/* $Id: process.c,v 1.90 1997/01/31 23:26:16 tdyas Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -154,7 +155,7 @@ extern int serial_console; #endif -void halt_now(void) +void machine_halt(void) { sti(); udelay(8000); @@ -167,7 +168,7 @@ panic("Halt failed!"); } -void hard_reset_now(void) +void machine_restart(char * cmd) { char *p; @@ -181,10 +182,19 @@ if (!serial_console) console_restore_palette (); #endif + if (cmd) + prom_reboot(cmd); if (*reboot_command) - prom_reboot (reboot_command); + prom_reboot(reboot_command); prom_feval ("reset"); panic("Reboot failed!"); +} + +void machine_power_off(void) +{ + if (auxio_power_register) + *auxio_power_register |= AUXIO_POWER_OFF; + machine_halt(); } void show_regwindow(struct reg_window *rw) diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.1.28/linux/arch/sparc/kernel/ptrace.c Sun Jan 26 02:07:06 1997 +++ linux/arch/sparc/kernel/ptrace.c Wed Mar 5 17:04:30 1997 @@ -741,7 +741,7 @@ pt_error_return(regs, -i); goto out; } - copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (32 * 4)); + copy_from_user(&child->tss.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); __get_user(child->tss.fsr, (&fps->fsr)); __get_user(child->tss.fpqdepth, (&fps->fpqd)); for(i = 0; i < 16; i++) { diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S --- v2.1.28/linux/arch/sparc/kernel/rtrap.S Sun Jan 26 02:07:07 1997 +++ linux/arch/sparc/kernel/rtrap.S Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.44 1997/01/14 05:56:17 davem Exp $ +/* $Id: rtrap.S,v 1.45 1997/03/04 16:26:27 jj Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -84,8 +84,8 @@ nop signal_p: - ld [%curptr + TASK_SIGNAL], %g2 - ld [%curptr + TASK_BLOCKED], %o0 + ld [%curptr + AOFF_task_signal], %g2 + ld [%curptr + AOFF_task_blocked], %o0 andncc %g2, %o0, %g0 be,a ret_trap_continue ld [%sp + REGWIN_SZ + PT_PSR], %t_psr @@ -102,7 +102,7 @@ wr %t_psr, 0x0, %psr WRITE_PAUSE - ld [%curptr + THREAD_W_SAVED], %twin_tmp1 + ld [%curptr + AOFF_task_tss + AOFF_thread_w_saved], %twin_tmp1 orcc %g0, %twin_tmp1, %g0 be ret_trap_nobufwins nop @@ -125,7 +125,7 @@ /* If there are already live user windows in the * set we can return from trap safely. */ - ld [%curptr + THREAD_UMASK], %twin_tmp1 + ld [%curptr + AOFF_task_tss + AOFF_thread_uwinmask], %twin_tmp1 orcc %g0, %twin_tmp1, %g0 bne ret_trap_userwins_ok nop diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/sclow.S linux/arch/sparc/kernel/sclow.S --- v2.1.28/linux/arch/sparc/kernel/sclow.S Sat Nov 9 00:11:43 1996 +++ linux/arch/sparc/kernel/sclow.S Wed Mar 5 17:04:30 1997 @@ -34,27 +34,34 @@ LABEL(sunosnop): CC_AND_RETT +#if 0 +/* Not SMP safe */ .globl LABEL(sunosgetpid) LABEL(sunosgetpid): LOAD_CURRENT(l4, l5) - ld [%l4 + 108], %i0 - ld [%l4 + 256], %l5 - ld [%l5 + 108], %i1 + ld [%l4 + AOFF_task_pid], %i0 + ld [%l4 + AOFF_task_p_opptr], %l5 + ld [%l5 + AOFF_task_pid], %i1 CC_AND_RETT +#endif +#if (ASIZ_task_uid == 2 && ASIZ_task_euid == 2) .globl LABEL(sunosgetuid) LABEL(sunosgetuid): LOAD_CURRENT(l4, l5) - lduh [%l4 + 280], %i0 - lduh [%l4 + 282], %i1 + lduh [%l4 + AOFF_task_uid], %i0 + lduh [%l4 + AOFF_task_euid], %i1 CC_AND_RETT +#endif +#if (ASIZ_task_gid == 2 && ASIZ_task_egid == 2) .globl LABEL(sunosgetgid) LABEL(sunosgetgid): LOAD_CURRENT(l4, l5) - lduh [%l4 + 288], %i0 - lduh [%l4 + 290], %i1 + lduh [%l4 + AOFF_task_gid], %i0 + lduh [%l4 + AOFF_task_egid], %i1 CC_AND_RETT +#endif .globl LABEL(sunosmctl) LABEL(sunosmctl): @@ -71,9 +78,9 @@ LOAD_CURRENT(l4, l5) set -65793, %l5 and %i0, %l5, %l5 - ld [%l4 + TASK_BLOCKED], %i0 + ld [%l4 + AOFF_task_blocked], %i0 or %i0, %l5, %l5 - st %l5, [%l4 + TASK_BLOCKED] + st %l5, [%l4 + AOFF_task_blocked] CC_AND_RETT .globl LABEL(sunossmask) @@ -81,102 +88,14 @@ LOAD_CURRENT(l4, l5) set -65793, %l5 and %i0, %l5, %l5 - ld [%l4 + TASK_BLOCKED], %i0 - st %l5, [%l4 + TASK_BLOCKED] + ld [%l4 + AOFF_task_blocked], %i0 + st %l5, [%l4 + AOFF_task_blocked] CC_AND_RETT .globl LABEL(getpagesize) LABEL(getpagesize): set 4096, %i0 CC_AND_RETT - - .globl LABEL(umask) -LABEL(umask): - LOAD_CURRENT(l4, l5) - ld [%l4 + 1560], %l5 - and %i0, 511, %l4 - lduh [%l5 + 4], %i0 - sth %l4, [%l5 + 4] - CC_AND_RETT - -#if 0 - .globl LABEL(write) -LABEL(write): - cmp %i0, 255 /* fd >= NR_OPEN */ - bgu,a write_error_return - mov EBADF, %i0 - - LOAD_CURRENT(l4, l5) - ld [%l4 + 1564], %l5 - sll %i0, 2, %l6 - add %l5, %l6, %l5 - ld [%l5 + 36], %l6 - cmp %l6, 0 /* !(file=current->files->fd[fd]) */ - be,a write_error_return - mov EBADF, %i0 - - ld [%l6 + 36], %l5 - cmp %l5, 0 /* !(inode=file->f_inode) */ - be,a write_error_return - mov EBADF, %i0 - - lduh [%l6], %l5 /* !(file->f_mode & 2) */ - andcc %l5, 2, %g0 - be,a write_error_return - mov EBADF, %i0 - - ld [%l6 + 40], %l5 - cmp %l5, 0 /* !file->f_op */ - be,a write_error_return - mov EINVAL, %i0 - - ld [%l5 + 8], %l5 /* !file->f_op->write */ - cmp %l5, 0 - be,a write_error_return - mov EINVAL, %i0 - - cmp %i2, 0 /* count == 0 */ - bne 1f - nop - - mov 0, %i0 - CC_AND_RETT - -1: - /* See if we can do the optimization... */ - ld [%l6 + 36], %l5 - lduh [%l5 + 16], %l5 - srl %l5, 8, %l6 - cmp %l6, 1 /* MEM_MAJOR */ - bne,a write_is_too_hard - sethi %hi(C_LABEL(quick_sys_write)), %l7 - - and %l5, 0xff, %l5 - cmp %l5, 3 /* NULL_MINOR */ - bne,a write_is_too_hard - sethi %hi(C_LABEL(quick_sys_write)), %l7 - - /* We only optimize for the /dev/null case currently, - * however to stay POSIX4 compliant we must check the - * validity of the passed buffer. Blowlaris2.x does not - * do this and is therefore not POSIX4 compliant! - * If you are going to optimize for benchmarks, fine, - * but to break behavior of a system call in the process - * is complete brain damage... - */ - - /* XXX write verify_area thingy for full POSIX conformance! XXX */ - - mov %i2, %i0 - CC_AND_RETT - -write_is_too_hard: - b syscall_is_too_hard - or %l7, %lo(C_LABEL(quick_sys_write)), %l7 - -write_error_return: - SC_AND_RETT -#endif /* XXX sys_nice() XXX */ /* XXX sys_setpriority() XXX */ diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.1.28/linux/arch/sparc/kernel/setup.c Sun Jan 26 02:07:07 1997 +++ linux/arch/sparc/kernel/setup.c Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.80 1997/01/25 02:39:54 miguel Exp $ +/* $Id: setup.c,v 1.81 1997/01/29 10:32:55 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -395,6 +395,7 @@ init_task.mm->mmap->vm_page_prot = PAGE_SHARED; init_task.mm->mmap->vm_start = KERNBASE; init_task.mm->mmap->vm_end = *memory_end_p; + init_task.mm->context = (unsigned long) NO_CONTEXT; init_task.tss.kregs = &fake_swapper_regs; #ifdef CONFIG_SUN_SERIAL diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.1.28/linux/arch/sparc/kernel/signal.c Sun Jan 26 02:07:07 1997 +++ linux/arch/sparc/kernel/signal.c Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.71 1997/01/19 22:32:21 ecd Exp $ +/* $Id: signal.c,v 1.72 1997/03/03 16:51:43 jj Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -144,7 +144,7 @@ current->flags &= ~PF_USEDFPU; copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0], - (sizeof(unsigned long) * 64)); + (sizeof(unsigned long) * 32)); __get_user(current->tss.fsr, &fpu->si_fsr); __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth); if (current->tss.fpqdepth != 0) @@ -343,7 +343,7 @@ } #endif copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], - (sizeof(unsigned long) * 64)); + (sizeof(unsigned long) * 32)); __put_user(current->tss.fsr, &fpu->si_fsr); __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); if (current->tss.fpqdepth != 0) diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.1.28/linux/arch/sparc/kernel/sparc_ksyms.c Sun Jan 26 02:07:07 1997 +++ linux/arch/sparc/kernel/sparc_ksyms.c Wed Mar 5 17:04:30 1997 @@ -1,10 +1,12 @@ -/* $Id: sparc_ksyms.c,v 1.43 1997/01/26 07:12:30 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.47 1997/03/03 16:51:41 jj Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) */ +#define PROMLIB_INTERNAL + #include #include #include @@ -43,19 +45,14 @@ unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); extern void __copy_1page(void *, const void *); -extern void __memcpy(void *, const void *, __kernel_size_t); extern void __memmove(void *, const void *, __kernel_size_t); -extern void *__memset(void *, int, __kernel_size_t); extern void *bzero_1page(void *); extern void *__bzero(void *, size_t); extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); extern int __strncmp(const char *, const char *, __kernel_size_t); - -extern int __copy_user(unsigned long to, unsigned long from, int size); -extern int __clear_user(unsigned long addr, int size); -extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count); +extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *); extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); @@ -144,7 +141,6 @@ EXPORT_SYMBOL(prom_getproperty); EXPORT_SYMBOL(prom_node_has_property); EXPORT_SYMBOL(prom_setprop); -EXPORT_SYMBOL(prom_nodeops); EXPORT_SYMBOL(prom_getbootargs); EXPORT_SYMBOL(prom_apply_obio_ranges); EXPORT_SYMBOL(prom_getname); @@ -154,6 +150,8 @@ EXPORT_SYMBOL(prom_getint); EXPORT_SYMBOL(prom_getintdefault); EXPORT_SYMBOL(romvec); +EXPORT_SYMBOL(__prom_getchild); +EXPORT_SYMBOL(__prom_getsibling); /* sparc library symbols */ EXPORT_SYMBOL(bcopy); @@ -185,9 +183,10 @@ EXPORT_SYMBOL(__strncmp); EXPORT_SYMBOL(__memmove); +EXPORT_SYMBOL(__csum_partial_copy_sparc_generic); + /* Moving data to/from userspace. */ EXPORT_SYMBOL(__copy_user); -EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__strncpy_from_user); /* No version information on this, heavily used in inline asm, diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c --- v2.1.28/linux/arch/sparc/kernel/sunos_ioctl.c Sun Jan 26 02:07:08 1997 +++ linux/arch/sparc/kernel/sunos_ioctl.c Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl.c,v 1.27 1997/01/06 06:52:33 davem Exp $ +/* $Id: sunos_ioctl.c,v 1.28 1997/02/15 01:17:05 davem Exp $ * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -28,6 +28,9 @@ extern char sunkbd_layout; #endif +/* NR_OPEN is now larger and dynamic in recent kernels. */ +#define SUNOS_NR_OPEN 256 + extern asmlinkage int sys_ioctl(unsigned int, unsigned int, unsigned long); extern asmlinkage int sys_setsid(void); @@ -37,7 +40,7 @@ int ret = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(filp = current->files->fd [fd])) + if (fd >= SUNOS_NR_OPEN || !(filp = current->files->fd [fd])) goto out; /* First handle an easy compat. case for tty ldisc. */ diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.1.28/linux/arch/sparc/kernel/sys_sunos.c Sun Jan 26 02:07:08 1997 +++ linux/arch/sparc/kernel/sys_sunos.c Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.75 1997/01/26 07:12:31 davem Exp $ +/* $Id: sys_sunos.c,v 1.77 1997/02/15 01:17:04 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -55,6 +55,9 @@ #include #include +/* NR_OPEN is now larger and dynamic in recent kernels. */ +#define SUNOS_NR_OPEN 256 + extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); /* We use the SunOS mmap() semantics. */ @@ -74,7 +77,7 @@ } retval = -EBADF; if(!(flags & MAP_ANONYMOUS)) - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd])) goto out; retval = -ENOMEM; if(!(flags & MAP_FIXED) && !addr) { @@ -340,7 +343,7 @@ */ asmlinkage long sunos_getdtablesize(void) { - return NR_OPEN; + return SUNOS_NR_OPEN; } #define _S(nr) (1<<((nr)-1)) @@ -429,7 +432,7 @@ int error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd])) goto out; error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) @@ -504,7 +507,7 @@ int error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd])) goto out; error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) @@ -927,6 +930,16 @@ unlock_kernel(); return ret; } + +/* sysconf options, for SunOS compatibility */ +#define _SC_ARG_MAX 1 +#define _SC_CHILD_MAX 2 +#define _SC_CLK_TCK 3 +#define _SC_NGROUPS_MAX 4 +#define _SC_OPEN_MAX 5 +#define _SC_JOB_CONTROL 6 +#define _SC_SAVED_IDS 7 +#define _SC_VERSION 8 extern asmlinkage long sunos_sysconf (int name) { diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v2.1.28/linux/arch/sparc/kernel/systbls.S Sun Jan 26 02:07:08 1997 +++ linux/arch/sparc/kernel/systbls.S Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.58 1997/01/26 07:12:31 davem Exp $ +/* $Id: systbls.S,v 1.59 1997/02/14 03:12:54 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -42,7 +42,7 @@ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink) .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot) .long C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_vfork), C_LABEL(sys_nis_syscall) + .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) .long C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap) .long C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup) diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S --- v2.1.28/linux/arch/sparc/kernel/wof.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/kernel/wof.S Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: wof.S,v 1.32 1997/01/06 06:52:43 davem Exp $ +/* $Id: wof.S,v 1.33 1997/03/04 16:26:35 jj Exp $ * wof.S: Sparc window overflow handler. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -96,7 +96,7 @@ save %g0, %g0, %g0 ! Go where saving will occur /* See if any user windows are active in the set. */ - ld [%curptr + THREAD_UMASK], %twin_tmp ! grab win mask + ld [%curptr + AOFF_task_tss + AOFF_thread_uwinmask], %twin_tmp ! grab win mask orcc %g0, %twin_tmp, %g0 ! check for set bits bne spwin_exist_uwins ! yep, there are some andn %twin_tmp, %glob_tmp, %twin_tmp ! compute new umask @@ -139,7 +139,7 @@ * But first, store the new user window mask calculated * above. */ - st %twin_tmp, [%curptr + THREAD_UMASK] + st %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] save %g0, %g0, %g0 ! Go to where the saving will occur spwin_fromuser: @@ -212,15 +212,15 @@ /* Oh well, throw this one window into the per-task window * buffer, the first one. */ - st %sp, [%curptr + THREAD_STACK_PTRS] - STORE_WINDOW(curptr + THREAD_REG_WINDOW) + st %sp, [%curptr + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] + STORE_WINDOW(curptr + AOFF_task_tss + AOFF_thread_reg_window) restore %g0, %g0, %g0 /* LOCATION: Trap Window */ /* Back in the trap window, update winbuffer save count. */ mov 1, %glob_tmp - st %glob_tmp, [%curptr + THREAD_W_SAVED] + st %glob_tmp, [%curptr + AOFF_task_tss + AOFF_thread_w_saved] /* Compute new user window mask. What we are basically * doing is taking two windows, the invalid one at trap @@ -232,10 +232,10 @@ or %twin_tmp, %t_wim, %twin_tmp not %twin_tmp spnwin_patch3: and %twin_tmp, 0xff, %twin_tmp ! patched on 7win Sparcs - st %twin_tmp, [%curptr + THREAD_UMASK] + st %twin_tmp, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] /* Jump onto kernel stack for this process... */ - ld [%curptr + TASK_SAVED_KSTACK], %sp + ld [%curptr + AOFF_task_saved_kernel_stack], %sp /* Restore the saved globals and build a pt_regs frame. */ mov %saved_g5, %g5 diff -u --recursive --new-file v2.1.28/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S --- v2.1.28/linux/arch/sparc/kernel/wuf.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/kernel/wuf.S Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: wuf.S,v 1.30 1997/01/06 06:52:44 davem Exp $ +/* $Id: wuf.S,v 1.31 1997/03/04 16:26:37 jj Exp $ * wuf.S: Window underflow trap handler for the Sparc. * * Copyright (C) 1995 David S. Miller @@ -145,7 +145,7 @@ * to the trap window and call c-code to deal with this. */ LOAD_CURRENT(l4, l5) - ld [%l4 + TASK_SAVED_KSTACK], %l5 + ld [%l4 + AOFF_task_saved_kernel_stack], %l5 /* Store globals into pt_regs frame. */ STORE_PT_GLOBALS(l5) @@ -178,8 +178,8 @@ /* Fix users window mask and buffer save count. */ mov 0x1, %g5 sll %g5, %g3, %g5 - st %g5, [%curptr + THREAD_UMASK] ! one live user window still - st %g0, [%curptr + THREAD_W_SAVED] ! no windows in the buffer + st %g5, [%curptr + AOFF_task_tss + AOFF_thread_uwinmask] ! one live user window still + st %g0, [%curptr + AOFF_task_tss + AOFF_thread_w_saved] ! no windows in the buffer wr %t_psr, PSR_ET, %psr ! enable traps nop diff -u --recursive --new-file v2.1.28/linux/arch/sparc/lib/checksum.S linux/arch/sparc/lib/checksum.S --- v2.1.28/linux/arch/sparc/lib/checksum.S Sat Nov 9 00:12:01 1996 +++ linux/arch/sparc/lib/checksum.S Wed Mar 5 17:04:30 1997 @@ -3,6 +3,7 @@ * Copyright(C) 1995 Linus Torvalds * Copyright(C) 1995 Miguel de Icaza * Copyright(C) 1996 David S. Miller + * Copyright(C) 1997 Jakub Jelinek * * derived from: * Linux/Alpha checksum c-code @@ -12,7 +13,8 @@ * BSD4.4 portable checksum routine */ -#include +#include +#include #define CSUM_BIGCHUNK(buf, offset, sum, t0, t1, t2, t3, t4, t5) \ ldd [buf + offset + 0x00], t0; \ @@ -140,9 +142,49 @@ cpout: retl ! get outta here mov %o2, %o0 ! return computed csum + .globl C_LABEL(__csum_partial_copy_start), C_LABEL(__csum_partial_copy_end) +C_LABEL(__csum_partial_copy_start): + +#define EX(x,y,a,b,z) \ +98: x,y; \ + .section .fixup,z##alloc,z##execinstr; \ + .align 4; \ +99: ba 30f; \ + a, b, %o3; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4 + +#define EX2(x,y,z) \ +98: x,y; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 30f; \ + .text; \ + .align 4 + +#define EX3(x,y,z) \ +98: x,y; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 96f; \ + .text; \ + .align 4 + +#define EXT(start,end,handler,z) \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word start, 0, end, handler; \ + .text; \ + .align 4 + /* This aligned version executes typically in 8.5 superscalar cycles, this * is the best I can do. I say 8.5 because the final add will pair with * the next ldd in the main unrolled loop. Thus the pipe is always full. + * If you change these macros (including order of instructions), + * please check the fixup code below as well. */ #define CSUMCOPY_BIGCHUNK_ALIGNED(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7) \ ldd [src + off + 0x00], t0; \ @@ -205,38 +247,38 @@ cc_end_cruft: be 1f andcc %o3, 4, %g0 - ldd [%o0 + 0x00], %g2 + EX(ldd [%o0 + 0x00], %g2, and %o3, 0xf,#) add %o1, 8, %o1 addcc %g2, %g7, %g7 add %o0, 8, %o0 addxcc %g3, %g7, %g7 - st %g2, [%o1 - 0x08] + EX2(st %g2, [%o1 - 0x08],#) addx %g0, %g7, %g7 andcc %o3, 4, %g0 - st %g3, [%o1 - 0x04] + EX2(st %g3, [%o1 - 0x04],#) 1: be 1f andcc %o3, 3, %o3 - ld [%o0 + 0x00], %g2 + EX(ld [%o0 + 0x00], %g2, add %o3, 4,#) add %o1, 4, %o1 addcc %g2, %g7, %g7 - st %g2, [%o1 - 0x04] + EX2(st %g2, [%o1 - 0x04],#) addx %g0, %g7, %g7 - add %o0, 4, %o0 andcc %o3, 3, %g0 + add %o0, 4, %o0 1: be 1f addcc %o3, -1, %g0 bne 2f subcc %o3, 2, %o3 b 4f or %g0, %g0, %o4 -2: lduh [%o0 + 0x00], %o4 +2: EX(lduh [%o0 + 0x00], %o4, add %o3, 2,#) add %o0, 2, %o0 - sth %o4, [%o1 + 0x00] + EX2(sth %o4, [%o1 + 0x00],#) be 6f add %o1, 2, %o1 sll %o4, 16, %o4 -4: ldub [%o0 + 0x00], %o5 - stb %o5, [%o1 + 0x00] +4: EX(ldub [%o0 + 0x00], %o5, add %g0, 1,#) + EX2(stb %o5, [%o1 + 0x00],#) sll %o5, 8, %o5 or %o5, %o4, %o4 6: addcc %o4, %g7, %g7 @@ -253,27 +295,27 @@ andcc %o0, 0x2, %g0 be 1f andcc %o0, 0x4, %g0 - lduh [%o0 + 0x00], %g2 + EX(lduh [%o0 + 0x00], %g4, add %g1, 0,#) sub %g1, 2, %g1 - sth %g2, [%o1 + 0x00] + EX2(sth %g4, [%o1 + 0x00],#) add %o0, 2, %o0 - sll %g2, 16, %g2 - addcc %g2, %g7, %g7 + sll %g4, 16, %g4 + addcc %g4, %g7, %g7 add %o1, 2, %o1 srl %g7, 16, %g3 - addx %g0, %g3, %g2 + addx %g0, %g3, %g4 sll %g7, 16, %g7 - sll %g2, 16, %g3 + sll %g4, 16, %g3 srl %g7, 16, %g7 andcc %o0, 0x4, %g0 or %g3, %g7, %g7 1: be 3f andcc %g1, 0xffffff80, %g0 - ld [%o0 + 0x00], %g2 + EX(ld [%o0 + 0x00], %g4, add %g1, 0,#) sub %g1, 4, %g1 - st %g2, [%o1 + 0x00] + EX2(st %g4, [%o1 + 0x00],#) add %o0, 4, %o0 - addcc %g2, %g7, %g7 + addcc %g4, %g7, %g7 add %o1, 4, %o1 addx %g0, %g7, %g7 b 3f @@ -284,14 +326,13 @@ * out of you, game over, lights out. */ .align 8 - .globl C_LABEL(csum_partial_copy) -C_LABEL(csum_partial_copy): /* %o0=src, %o1=dest, %o2=len, %o3=sum */ + .globl C_LABEL(__csum_partial_copy_sparc_generic) +C_LABEL(__csum_partial_copy_sparc_generic): + /* %o0=src, %o1=dest, %g1=len, %g7=sum */ xor %o0, %o1, %o4 ! get changing bits - mov %o2, %g1 ! free up %o2 andcc %o4, 3, %g0 ! check for mismatched alignment bne ccslow ! better this than unaligned/fixups andcc %o0, 7, %g0 ! need to align things? - mov %o3, %g7 ! free up %o3 bne cc_dword_align ! yes, we check for short lengths there andcc %g1, 0xffffff80, %g0 ! can we use unrolled loop? 3: be 3f ! nope, less than one loop remains @@ -301,6 +342,7 @@ CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) +10: EXT(5b, 10b, 20f,#) ! note for exception handling sub %g1, 128, %g1 ! detract from length addx %g0, %g7, %g7 ! add in last carry bit andcc %g1, 0xffffff80, %g0 ! more to csum? @@ -311,12 +353,12 @@ ccmerge:be ccte ! nope, go and check for end cruft andcc %g1, 0xf, %o3 ! get low bits of length (clears carry btw) srl %o2, 1, %o4 ! begin negative offset computation - sethi %hi(ccte - 8), %o5 ! set up table ptr end + sethi %hi(12f), %o5 ! set up table ptr end add %o0, %o2, %o0 ! advance src ptr sub %o5, %o4, %o5 ! continue table calculation sll %o2, 1, %g2 ! constant multiplies are fun... sub %o5, %g2, %o5 ! some more adjustments - jmp %o5 + %lo(ccte - 8) ! jump into it, duff style, wheee... + jmp %o5 + %lo(12f) ! jump into it, duff style, wheee... add %o1, %o2, %o1 ! advance dest ptr (carry is clear btw) cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5) CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3,%g4,%g5) @@ -325,6 +367,7 @@ CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3,%g4,%g5) CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3,%g4,%g5) CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5) +12: EXT(cctbl, 12b, 22f,#) ! note for exception table handling addx %g0, %g7, %g7 andcc %o3, 0xf, %g0 ! check for low bits set ccte: bne cc_end_cruft ! something left, handle it out of band @@ -335,6 +378,7 @@ CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) +11: EXT(ccdbl, 11b, 21f,#) ! note for exception table handling sub %g1, 128, %g1 ! detract from length addx %g0, %g7, %g7 ! add in last carry bit andcc %g1, 0xffffff80, %g0 ! more to csum? @@ -344,96 +388,194 @@ b ccmerge ! finish it off, above andcc %g1, 0x70, %o2 ! can use table? (clears carry btw) -ccslow: +ccslow: cmp %g1, 0 + mov 0, %g5 + bleu 4f + andcc %o0, 1, %o5 + be,a 1f + srl %g1, 1, %g4 + sub %g1, 1, %g1 + EX(ldub [%o0], %g5, add %g1, 1,#) + add %o0, 1, %o0 + EX2(stb %g5, [%o1],#) + srl %g1, 1, %g4 + add %o1, 1, %o1 +1: cmp %g4, 0 + be,a 3f + andcc %g1, 1, %g0 + andcc %o0, 2, %g0 + be,a 1f + srl %g4, 1, %g4 + EX(lduh [%o0], %o4, add %g1, 0,#) + sub %g1, 2, %g1 + srl %o4, 8, %g2 + sub %g4, 1, %g4 + EX2(stb %g2, [%o1],#) + add %o4, %g5, %g5 + EX2(stb %o4, [%o1 + 1],#) + add %o0, 2, %o0 + srl %g4, 1, %g4 + add %o1, 2, %o1 +1: cmp %g4, 0 + be,a 2f + andcc %g1, 2, %g0 + EX3(ld [%o0], %o4,#) +5: srl %o4, 24, %g2 + srl %o4, 16, %g3 + EX2(stb %g2, [%o1],#) + srl %o4, 8, %g2 + EX2(stb %g3, [%o1 + 1],#) + add %o0, 4, %o0 + EX2(stb %g2, [%o1 + 2],#) + addcc %o4, %g5, %g5 + EX2(stb %o4, [%o1 + 3],#) + addx %g5, %g0, %g5 ! I am now to lazy to optimize this (question it + add %o1, 4, %o1 ! is worthy). Maybe some day - with the sll/srl + subcc %g4, 1, %g4 ! tricks + bne,a 5b + EX3(ld [%o0], %o4,#) + sll %g5, 16, %g2 + srl %g5, 16, %g5 + srl %g2, 16, %g2 + andcc %g1, 2, %g0 + add %g2, %g5, %g5 +2: be,a 3f + andcc %g1, 1, %g0 + EX(lduh [%o0], %o4, and %g1, 3,#) + andcc %g1, 1, %g0 + srl %o4, 8, %g2 + add %o0, 2, %o0 + EX2(stb %g2, [%o1],#) + add %g5, %o4, %g5 + EX2(stb %o4, [%o1 + 1],#) + add %o1, 2, %o1 +3: be,a 1f + sll %g5, 16, %o4 + EX(ldub [%o0], %g2, add %g0, 1,#) + sll %g2, 8, %o4 + EX2(stb %g2, [%o1],#) + add %g5, %o4, %g5 + sll %g5, 16, %o4 +1: addcc %o4, %g5, %g5 + srl %g5, 16, %o4 + addx %g0, %o4, %g5 + orcc %o5, %g0, %g0 + be 4f + srl %g5, 8, %o4 + and %g5, 0xff, %g2 + and %o4, 0xff, %o4 + sll %g2, 8, %g2 + or %g2, %o4, %g5 +4: addcc %g7, %g5, %g7 + retl + addx %g0, %g7, %o0 +C_LABEL(__csum_partial_copy_end): + + .section .fixup,#alloc,#execinstr + .align 4 +/* We do these strange calculations for the csum_*_from_user case only, ie. + * we only bother with faults on loads... */ + +/* o2 = ((g2%20)&3)*8 + * o3 = g1 - (g2/20)*32 - o2 */ +20: + cmp %g2, 20 + blu,a 1f + and %g2, 3, %o2 + sub %g1, 32, %g1 + b 20b + sub %g2, 20, %g2 +1: + sll %o2, 3, %o2 + b 31f + sub %g1, %o2, %o3 + +/* o2 = (!(g2 & 15) ? 0 : (((g2 & 15) + 1) & ~1)*8) + * o3 = g1 - (g2/16)*32 - o2 */ +21: + andcc %g2, 15, %o3 + srl %g2, 4, %g2 + be,a 1f + clr %o2 + add %o3, 1, %o3 + and %o3, 14, %o3 + sll %o3, 3, %o2 +1: + sll %g2, 5, %g2 + sub %g1, %g2, %o3 + b 31f + sub %o3, %o2, %o3 + +/* o0 += (g2/10)*16 - 0x70 + * 01 += (g2/10)*16 - 0x70 + * o2 = (g2 % 10) ? 8 : 0 + * o3 += 0x70 - (g2/10)*16 - o2 */ +22: + cmp %g2, 10 + blu,a 1f + sub %o0, 0x70, %o0 + add %o0, 16, %o0 + add %o1, 16, %o1 + sub %o3, 16, %o3 + b 22b + sub %g2, 10, %g2 +1: + sub %o1, 0x70, %o1 + add %o3, 0x70, %o3 + clr %o2 + tst %g2 + bne,a 1f + mov 8, %o2 +1: + b 31f + sub %o3, %o2, %o3 +96: + and %g1, 3, %g1 + sll %g4, 2, %g4 + add %g1, %g4, %o3 +30: +/* %o1 is dst + * %o3 is # bytes to zero out + * %o4 is faulting address + * %o5 is %pc where fault occured */ + clr %o2 +31: +/* %o0 is src + * %o1 is dst + * %o2 is # of bytes to copy from src to dst + * %o3 is # bytes to zero out + * %o4 is faulting address + * %o5 is %pc where fault occured */ save %sp, -104, %sp - mov %i0, %g2 - mov %g2, %o4 - orcc %i2, %g0, %o5 - ble .LL37 - mov 0, %o3 - andcc %g2, 1, %g3 - be .LL50 - sra %o5, 1, %o1 - ldub [%g2], %o3 - add %i2, -1, %o5 - add %g2, 1, %o4 - sra %o5, 1, %o1 -.LL50: - cmp %o1, 0 - be .LL39 - andcc %o4, 2, %g0 - be,a .LL51 - sra %o1, 1, %o1 - add %o1, -1, %o1 - lduh [%o4], %o0 - add %o5, -2, %o5 - add %o3, %o0, %o3 - add %o4, 2, %o4 - sra %o1, 1, %o1 -.LL51: - cmp %o1, 0 - be .LL41 - mov 0, %o2 -.LL42: - ld [%o4], %o0 - add %o3, %o2, %o3 - add %o3, %o0, %o3 - cmp %o3, %o0 - addx %g0, 0, %o2 - addcc %o1, -1, %o1 - bne .LL42 - add %o4, 4, %o4 - add %o3, %o2, %o3 - sethi %hi(65535), %o0 - or %o0, %lo(65535), %o0 - and %o3, %o0, %o0 - srl %o3, 16, %o1 - add %o0, %o1, %o3 -.LL41: - andcc %o5, 2, %g0 - be .LL52 - andcc %o5, 1, %g0 - lduh [%o4], %o0 - add %o3, %o0, %o3 - add %o4, 2, %o4 -.LL39: - andcc %o5, 1, %g0 -.LL52: - be .LL53 - sethi %hi(65535), %o0 - ldub [%o4], %o0 - sll %o0, 8, %o0 - add %o3, %o0, %o3 - sethi %hi(65535), %o0 -.LL53: - or %o0, %lo(65535), %o0 - and %o3, %o0, %o2 - srl %o3, 16, %o1 - add %o2, %o1, %o1 - and %o1, %o0, %o2 - srl %o1, 16, %o1 - add %o2, %o1, %o1 - and %o1, %o0, %o0 - srl %o1, 16, %o1 - add %o0, %o1, %o1 - sll %o1, 16, %o0 - cmp %g3, 0 - be .LL37 - srl %o0, 16, %o3 - srl %o0, 24, %o1 - and %o3, 255, %o0 - sll %o0, 8, %o0 - or %o1, %o0, %o3 -.LL37: - add %o3, %i3, %o1 - sethi %hi(65535), %o0 - or %o0, %lo(65535), %o0 - and %o1, %o0, %o0 - srl %o1, 16, %o1 - add %o0, %o1, %i0 + mov %i5, %o0 + mov %i7, %o1 + mov %i4, %o2 + call C_LABEL(lookup_fault) + mov %g7, %i4 + cmp %o0, 2 + bne 1f + add %g0, -EFAULT, %i5 + tst %i2 + be 2f + mov %i0, %o1 mov %i1, %o0 - mov %g2, %o1 +5: call C_LABEL(__memcpy) mov %i2, %o2 + tst %o0 + bne,a 2f + add %i3, %i2, %i3 + add %i1, %i2, %i1 +2: + mov %i1, %o0 + call C_LABEL(__bzero) + mov %i3, %o1 +1: + ld [%sp + 168], %o2 ! struct_ptr of parent + st %i5, [%o2] ret restore + + .section __ex_table,#alloc + .align 4 + .word 5b,2 diff -u --recursive --new-file v2.1.28/linux/arch/sparc/lib/locks.S linux/arch/sparc/lib/locks.S --- v2.1.28/linux/arch/sparc/lib/locks.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/lib/locks.S Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: locks.S,v 1.3 1997/01/12 11:36:44 davem Exp $ +/* $Id: locks.S,v 1.4 1997/03/04 16:26:41 jj Exp $ * locks.S: SMP low-level lock primitives on Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -64,7 +64,7 @@ ___lock_kernel: addcc %g2, -1, %g2 bcs,a 9f - st %g2, [%g6 + TASK_LOCK_DEPTH] + st %g2, [%g6 + AOFF_task_lock_depth] rd %psr, %g3 or %g3, PSR_PIL, %g2 wr %g2, 0x0, %psr @@ -86,7 +86,7 @@ st %g7, [%g2] #endif 2: mov -1, %g2 - st %g2, [%g6 + TASK_LOCK_DEPTH] + st %g2, [%g6 + AOFF_task_lock_depth] wr %g3, 0x0, %psr nop; nop; nop 9: jmpl %o7 + 0x8, %g0 @@ -99,7 +99,7 @@ ___unlock_kernel: addcc %g2, 1, %g2 bne,a 1f - st %g2, [%g6 + TASK_LOCK_DEPTH] + st %g2, [%g6 + AOFF_task_lock_depth] rd %psr, %g3 or %g3, PSR_PIL, %g2 wr %g2, 0x0, %psr @@ -107,7 +107,7 @@ mov NO_PROC_ID, %g2 stb %g2, [%g1 + 1] stb %g0, [%g1 + 0] - st %g0, [%g6 + TASK_LOCK_DEPTH] + st %g0, [%g6 + AOFF_task_lock_depth] wr %g3, 0x0, %psr nop; nop; nop; 1: jmpl %o7 + 0x8, %g0 diff -u --recursive --new-file v2.1.28/linux/arch/sparc/lib/memset.S linux/arch/sparc/lib/memset.S --- v2.1.28/linux/arch/sparc/lib/memset.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/lib/memset.S Wed Mar 5 17:04:30 1997 @@ -1,14 +1,37 @@ -/* linux/arch/sparc/lib/memset.S: Sparc optimized memset and bzero code - * Hand optimized from GNU libc's memset +/* linux/arch/sparc/lib/memset.S: Sparc optimized memset, bzero and clear_user code * Copyright (C) 1991,1996 Free Software Foundation * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * + * Returns 0, if ok, and number of bytes not yet set if exception + * occurs and we were called as clear_user. */ #include #include - /* Store 64 bytes at (BASE + OFFSET) using value SOURCE. */ +#define EX(x,y,a,b,z) \ +98: x,y; \ + .section .fixup,z##alloc,z##execinstr; \ + .align 4; \ +99: ba 30f; \ + a, b, %o0; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4 + +#define EXT(start,end,handler,z) \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word start, 0, end, handler; \ + .text; \ + .align 4 + +/* Please don't change these macros, unless you change the logic + * in the .fixup section below as well. + * Store 64 bytes at (BASE + OFFSET) using value SOURCE. */ #define ZERO_BIG_BLOCK(base, offset, source) \ std source, [base + offset + 0x00]; \ std source, [base + offset + 0x08]; \ @@ -32,7 +55,10 @@ .text .align 4 - .globl C_LABEL(__bzero), C_LABEL(__memset), C_LABEL(memset) + .globl C_LABEL(__bzero), C_LABEL(__memset), + .globl C_LABEL(memset) + .globl C_LABEL(__memset_start), C_LABEL(__memset_end) +C_LABEL(__memset_start): C_LABEL(__memset): C_LABEL(memset): and %o1, 0xff, %g3 @@ -45,13 +71,13 @@ 3: cmp %o2, 3 be 2f - stb %g3, [%o0] + EX(stb %g3, [%o0], sub %o1, 0,#) cmp %o2, 2 be 2f - stb %g3, [%o0 + 0x01] + EX(stb %g3, [%o0 + 0x01], sub %o1, 1,#) - stb %g3, [%o0 + 0x02] + EX(stb %g3, [%o0 + 0x02], sub %o1, 2,#) 2: sub %o2, 4, %o2 add %o1, %o2, %o1 @@ -61,7 +87,6 @@ C_LABEL(__bzero): mov %g0, %g3 1: - mov %o0, %g1 cmp %o1, 7 bleu 7f andcc %o0, 3, %o2 @@ -73,57 +98,59 @@ be 2f mov %g3, %g2 - st %g3, [%o0] + EX(st %g3, [%o0], sub %o1, 0,#) sub %o1, 4, %o1 add %o0, 4, %o0 2: andcc %o1, 0xffffff80, %o3 ! Now everything is 8 aligned and o1 is len to run be 9f andcc %o1, 0x78, %o2 -4: +10: ZERO_BIG_BLOCK(%o0, 0x00, %g2) subcc %o3, 128, %o3 ZERO_BIG_BLOCK(%o0, 0x40, %g2) - bne 4b +11: + EXT(10b, 11b, 20f,#) + bne 10b add %o0, 128, %o0 orcc %o2, %g0, %g0 9: - be 6f + be 13f andcc %o1, 7, %o1 srl %o2, 1, %o3 - set bzero_table + 64, %o4 + set 13f, %o4 sub %o4, %o3, %o4 jmp %o4 add %o0, %o2, %o0 -bzero_table: +12: ZERO_LAST_BLOCKS(%o0, 0x48, %g2) ZERO_LAST_BLOCKS(%o0, 0x08, %g2) -6: +13: be 8f andcc %o1, 4, %g0 be 1f andcc %o1, 2, %g0 - st %g3, [%o0] + EX(st %g3, [%o0], and %o1, 7,#) add %o0, 4, %o0 1: be 1f andcc %o1, 1, %g0 - sth %g3, [%o0] + EX(sth %g3, [%o0], and %o1, 3,#) add %o0, 2, %o0 1: bne,a 8f - stb %g3, [%o0] + EX(stb %g3, [%o0], and %o1, 1,#) 8: retl - mov %g1, %o0 + clr %o0 7: - be 6b + be 13b orcc %o1, 0, %g0 be 0f @@ -131,7 +158,38 @@ add %o0, 1, %o0 subcc %o1, 1, %o1 bne,a 8b - stb %g3, [%o0 - 1] + EX(stb %g3, [%o0 - 1], add %o1, 1,#) 0: retl - mov %g1, %o0 + clr %o0 +C_LABEL(__memset_end): + + .section .fixup,#alloc,#execinstr + .align 4 +20: + cmp %g2, 8 + bleu 1f + and %o1, 0x7f, %o1 + sub %g2, 9, %g2 + add %o3, 64, %o3 +1: + sll %g2, 3, %g2 + add %o3, %o1, %o0 + b 30f + sub %o0, %g2, %o0 +21: + mov 8, %o0 + and %o1, 7, %o1 + sub %o0, %g2, %o0 + sll %o0, 3, %o0 + b 30f + add %o0, %o1, %o0 +30: +/* %o4 is faulting address, %o5 is %pc where fault occured */ + save %sp, -104, %sp + mov %i5, %o0 + mov %i7, %o1 + call C_LABEL(lookup_fault) + mov %i4, %o2 + ret + restore diff -u --recursive --new-file v2.1.28/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.1.28/linux/arch/sparc/mm/fault.c Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/mm/fault.c Wed Mar 5 17:04:30 1997 @@ -1,8 +1,9 @@ -/* $Id: fault.c,v 1.86 1997/01/06 06:52:52 davem Exp $ +/* $Id: fault.c,v 1.89 1997/03/04 16:26:46 jj Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -133,6 +134,58 @@ prom_halt(); } +void unhandled_fault(unsigned long address, struct task_struct *tsk, + struct pt_regs *regs) +{ + if((unsigned long) address < PAGE_SIZE) { + printk(KERN_ALERT "Unable to handle kernel NULL " + "pointer dereference"); + } else { + printk(KERN_ALERT "Unable to handle kernel paging request " + "at virtual address %08lx\n", address); + } + printk(KERN_ALERT "tsk->mm->context = %08lx\n", + (unsigned long) tsk->mm->context); + printk(KERN_ALERT "tsk->mm->pgd = %08lx\n", + (unsigned long) tsk->mm->pgd); + die_if_kernel("Oops", regs); +} + +asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, + unsigned long address) +{ + unsigned long g2; + int i; + unsigned insn; + struct pt_regs regs; + + i = search_exception_table (ret_pc, &g2); + switch (i) { + /* load & store will be handled by fixup */ + case 3: return 3; + /* store will be handled by fixup, load will bump out */ + /* for _to_ macros */ + case 1: insn = (unsigned *)pc; if ((insn >> 21) & 1) return 1; break; + /* load will be handled by fixup, store will bump out */ + /* for _from_ macros */ + case 2: insn = (unsigned *)pc; + if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; + break; + default: break; + } + memset (®s, 0, sizeof (regs)); + regs.pc = pc; + regs.npc = pc + 4; + __asm__ __volatile__ (" + rd %%psr, %0 + nop + nop + nop" : "=r" (regs.psr)); + unhandled_fault (address, current, ®s); + /* Not reached */ + return 0; +} + asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, unsigned long address) { @@ -142,34 +195,11 @@ unsigned int fixup; unsigned long g2; int from_user = !(regs->psr & PSR_PS); -#if 0 - static unsigned long last_one; -#endif lock_kernel(); down(&mm->mmap_sem); if(text_fault) address = regs->pc; -#if 0 - if(current->tss.ex.count) { - printk("f\n", - tsk->pid, text_fault, write, address, regs->pc); - printk("EX: count<%d> pc<%08lx> expc<%08lx> address<%08lx>\n", - (int) current->tss.ex.count, current->tss.ex.pc, - current->tss.ex.expc, current->tss.ex.address); -#if 0 - if(last_one == address) { - printk("Twice in a row, AIEEE. Spinning so you can see the dump.\n"); - show_regs(regs); - sti(); - while(1) - barrier(); - } - last_one = address; -#endif - } -#endif - /* The kernel referencing a bad kernel pointer can lock up * a sun4c machine completely, so we must attempt recovery. */ @@ -211,32 +241,25 @@ g2 = regs->u_regs[UREG_G2]; if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) { - printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address); - printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n", - regs->pc, fixup, g2); - regs->pc = fixup; - regs->npc = regs->pc + 4; - regs->u_regs[UREG_G2] = g2; - goto out; - } - /* Did we have an exception handler installed? */ - if(current->tss.ex.count == 1) { - if(from_user) { - printk("Yieee, exception signalled from user mode.\n"); - } else { - /* Set pc to %g1, set %g1 to -EFAULT and %g2 to - * the faulting address so we can cleanup. - */ + if (fixup > 10) { /* Values below are reserved for other things */ + extern const unsigned __memset_start[]; + extern const unsigned __memset_end[]; + extern const unsigned __csum_partial_copy_start[]; + extern const unsigned __csum_partial_copy_end[]; + printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address); - printk("EX: count<%d> pc<%08lx> expc<%08lx> address<%08lx>\n", - (int) current->tss.ex.count, current->tss.ex.pc, - current->tss.ex.expc, current->tss.ex.address); - current->tss.ex.count = 0; - regs->pc = current->tss.ex.expc; + printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n", + regs->pc, fixup, g2); + if ((regs->pc >= (unsigned long)__memset_start && + regs->pc < (unsigned long)__memset_end) || + (regs->pc >= (unsigned long)__csum_partial_copy_start && + regs->pc < (unsigned long)__csum_partial_copy_end)) { + regs->u_regs[UREG_I4] = address; + regs->u_regs[UREG_I5] = regs->pc; + } + regs->u_regs[UREG_G2] = g2; + regs->pc = fixup; regs->npc = regs->pc + 4; - regs->u_regs[UREG_G1] = -EFAULT; - regs->u_regs[UREG_G2] = address - current->tss.ex.address; - regs->u_regs[UREG_G3] = current->tss.ex.pc; goto out; } } @@ -250,18 +273,7 @@ send_sig(SIGSEGV, tsk, 1); goto out; } - if((unsigned long) address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL " - "pointer dereference"); - } else { - printk(KERN_ALERT "Unable to handle kernel paging request " - "at virtual address %08lx\n", address); - } - printk(KERN_ALERT "tsk->mm->context = %08lx\n", - (unsigned long) tsk->mm->context); - printk(KERN_ALERT "tsk->mm->pgd = %08lx\n", - (unsigned long) tsk->mm->pgd); - die_if_kernel("Oops", regs); + unhandled_fault (address, tsk, regs); out: unlock_kernel(); } diff -u --recursive --new-file v2.1.28/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.1.28/linux/arch/sparc/mm/srmmu.c Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/mm/srmmu.c Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.128 1997/01/12 12:07:00 davem Exp $ +/* $Id: srmmu.c,v 1.130 1997/02/10 23:33:49 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -2795,7 +2795,7 @@ tally = 0; for(entry = 0; sp_banks[entry].num_bytes; entry++) tally += sp_banks[entry].num_bytes; - if(tally >= (0xfd000000 - KERNBASE)) + if(tally > (0xfd000000 - KERNBASE)) lots_of_ram = 1; else lots_of_ram = 0; @@ -2846,7 +2846,7 @@ MKTRACE(("<%d> base=%08lx bs=%08lx ", entry, sp_banks[entry].base_addr, bank_size)); if(!bank_size) break; - if(((vaddr + bank_size) >= 0xfd000000) || + if(((vaddr + bank_size) > 0xfd000000) || ((vaddr + bank_size) < KERNBASE)) { unsigned long orig_base = sp_banks[entry].base_addr; unsigned long orig_len = sp_banks[entry].num_bytes; @@ -3104,7 +3104,7 @@ if((pte_val(*ptep) & SRMMU_ET_MASK) == SRMMU_VALID) { #if 1 - printk("Fixing USER/USER alias [%d:%08lx]\n", + printk("Fixing USER/USER alias [%ld:%08lx]\n", vmaring->vm_mm->context, start); #endif flush_cache_page(vmaring, start); diff -u --recursive --new-file v2.1.28/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.1.28/linux/arch/sparc/mm/sun4c.c Mon Dec 30 01:59:58 1996 +++ linux/arch/sparc/mm/sun4c.c Wed Mar 5 17:04:30 1997 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.137 1996/12/30 06:16:36 davem Exp $ +/* $Id: sun4c.c,v 1.139 1997/01/31 08:05:59 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -1878,6 +1878,7 @@ { if(address >= SUN4C_LOCK_VADDR) return NULL; + address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1); if (sun4c_pmd_none(*pmd)) panic("sun4c_pmd_none for kernel pmd, can't happen..."); if (sun4c_pmd_bad(*pmd)) { @@ -2007,7 +2008,7 @@ if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) { #if 1 - printk("Fixing USER/USER alias [%d:%08lx]\n", + printk("Fixing USER/USER alias [%ld:%08lx]\n", vmaring->vm_mm->context, start); #endif sun4c_flush_cache_page(vmaring, start); diff -u --recursive --new-file v2.1.28/linux/arch/sparc/prom/ranges.c linux/arch/sparc/prom/ranges.c --- v2.1.28/linux/arch/sparc/prom/ranges.c Fri Dec 13 01:37:32 1996 +++ linux/arch/sparc/prom/ranges.c Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -/* $Id: ranges.c,v 1.7 1996/11/13 05:10:12 davem Exp $ +/* $Id: ranges.c,v 1.8 1997/02/04 07:28:29 davem Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -57,11 +57,21 @@ } /* Apply probed sbus ranges to registers passed, if no ranges return. */ -void -prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs, int nregs) +void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs, + int nregs, struct linux_sbus_device *sdev) { - if(sbus->num_sbus_ranges) - prom_adjust_regs(regs, nregs, sbus->sbus_ranges, sbus->num_sbus_ranges); + if(sbus->num_sbus_ranges) { + if(sdev && (sdev->ranges_applied == 0)) { + sdev->ranges_applied = 1; + prom_adjust_regs(regs, nregs, sbus->sbus_ranges, + sbus->num_sbus_ranges); + } else if(!sdev) { + printk("PROMLIB: Aieee, old SBUS driver, update it to use new " + "prom_apply_sbus_ranges interface now!\n"); + prom_adjust_regs(regs, nregs, sbus->sbus_ranges, + sbus->num_sbus_ranges); + } + } } __initfunc(void prom_ranges_init(void)) diff -u --recursive --new-file v2.1.28/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c --- v2.1.28/linux/arch/sparc/prom/tree.c Mon Dec 30 01:59:58 1996 +++ linux/arch/sparc/prom/tree.c Wed Mar 5 17:04:31 1997 @@ -1,10 +1,12 @@ -/* $Id: tree.c,v 1.14 1996/12/29 20:46:12 davem Exp $ +/* $Id: tree.c,v 1.15 1997/01/31 00:17:04 tdyas Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#define PROMLIB_INTERNAL + #include #include #include @@ -13,67 +15,80 @@ #include #include + +/* Macro to restore "current" to the g6 register. */ +#define restore_current() __asm__ __volatile__("ld [%0], %%g6\n\t" : : \ + "r" (¤t_set[smp_processor_id()]) : \ + "memory") + static char promlib_buf[128]; +/* Internal version of prom_getchild that does not alter return values. */ +int __prom_getchild(int node) +{ + unsigned long flags; + int cnode; + + save_and_cli(flags); + cnode = prom_nodeops->no_child(node); + restore_current(); + restore_flags(flags); + + return cnode; +} + /* Return the child of node 'node' or zero if no this node has no * direct descendent. */ -int -prom_getchild(int node) +int prom_getchild(int node) { - int cnode, ret; - unsigned long flags; + int cnode; - save_flags(flags); cli(); + if (node == -1) + return 0; - if(node == -1) { - ret = 0; - } else { - cnode = prom_nodeops->no_child(node); - if((cnode == 0) || (cnode == -1)) - ret = 0; - else - ret = cnode; - } - __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : - "memory"); + cnode = __prom_getchild(node); + if (cnode == 0 || cnode == -1) + return 0; + + return cnode; +} + +/* Internal version of prom_getsibling that does not alter return values. */ +int __prom_getsibling(int node) +{ + unsigned long flags; + int cnode; + + save_and_cli(flags); + cnode = prom_nodeops->no_nextnode(node); + restore_current(); restore_flags(flags); - return ret; + + return cnode; } /* Return the next sibling of node 'node' or zero if no more siblings * at this level of depth in the tree. */ -int -prom_getsibling(int node) +int prom_getsibling(int node) { - int sibnode, ret; - unsigned long flags; + int sibnode; - save_flags(flags); cli(); + if (node == -1) + return 0; - if(node == -1) { - ret = 0; - } else { - sibnode = prom_nodeops->no_nextnode(node); - if((sibnode == 0) || (sibnode == -1)) - ret = 0; - else - ret = sibnode; - } - __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : - "memory"); - restore_flags(flags); - return ret; + sibnode = __prom_getsibling(node); + if (sibnode == 0 || sibnode == -1) + return 0; + + return sibnode; } /* Return the length in bytes of property 'prop' at node 'node'. * Return -1 on error. */ -int -prom_getproplen(int node, char *prop) +int prom_getproplen(int node, char *prop) { int ret; unsigned long flags; @@ -84,9 +99,7 @@ ret = -1; else ret = prom_nodeops->no_proplen(node, prop); - __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : - "memory"); + restore_current(); restore_flags(flags); return ret; } @@ -95,8 +108,7 @@ * 'buffer' which has a size of 'bufsize'. If the acquisition * was successful the length will be returned, else -1 is returned. */ -int -prom_getproperty(int node, char *prop, char *buffer, int bufsize) +int prom_getproperty(int node, char *prop, char *buffer, int bufsize) { int plen, ret; unsigned long flags; @@ -110,9 +122,7 @@ /* Ok, things seem all right. */ ret = prom_nodeops->no_getprop(node, prop, buffer); } - __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : - "memory"); + restore_current(); restore_flags(flags); return ret; } @@ -120,8 +130,7 @@ /* Acquire an integer property and return its value. Returns -1 * on failure. */ -int -prom_getint(int node, char *prop) +int prom_getint(int node, char *prop) { static int intprop; @@ -134,9 +143,7 @@ /* Acquire an integer property, upon error return the passed default * integer. */ - -int -prom_getintdefault(int node, char *property, int deflt) +int prom_getintdefault(int node, char *property, int deflt) { int retval; @@ -147,8 +154,7 @@ } /* Acquire a boolean property, 1=TRUE 0=FALSE. */ -int -prom_getbool(int node, char *prop) +int prom_getbool(int node, char *prop) { int retval; @@ -161,8 +167,7 @@ * string on error. The char pointer is the user supplied string * buffer. */ -void -prom_getstring(int node, char *prop, char *user_buf, int ubuf_size) +void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size) { int len; @@ -176,8 +181,7 @@ /* Does the device at node 'node' have name 'name'? * YES = 1 NO = 0 */ -int -prom_nodematch(int node, char *name) +int prom_nodematch(int node, char *name) { static char namebuf[128]; prom_getproperty(node, "name", namebuf, sizeof(namebuf)); @@ -188,8 +192,7 @@ /* Search siblings at 'node_start' for a node with name * 'nodename'. Return node if successful, zero if not. */ -int -prom_searchsiblings(int node_start, char *nodename) +int prom_searchsiblings(int node_start, char *nodename) { int thisnode, error; @@ -207,8 +210,7 @@ } /* Gets name in the form prom v2+ uses it (name@x,yyyyy or name (if no reg)) */ -int -prom_getname (int node, char *buffer, int len) +int prom_getname (int node, char *buffer, int len) { int i; struct linux_prom_registers reg[PROMREG_MAX]; @@ -227,8 +229,7 @@ /* Return the first property type for node 'node'. */ -char * -prom_firstprop(int node) +char * prom_firstprop(int node) { unsigned long flags; char *ret; @@ -236,9 +237,7 @@ if(node == -1) return ""; save_flags(flags); cli(); ret = prom_nodeops->no_nextprop(node, (char *) 0x0); - __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : - "memory"); + restore_current(); restore_flags(flags); return ret; } @@ -247,8 +246,7 @@ * at node 'node' . Returns NULL string if no more * property types for this node. */ -char * -prom_nextprop(int node, char *oprop) +char * prom_nextprop(int node, char *oprop) { char *ret; unsigned long flags; @@ -256,15 +254,12 @@ if(node == -1) return ""; save_flags(flags); cli(); ret = prom_nodeops->no_nextprop(node, oprop); - __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : - "memory"); + restore_current(); restore_flags(flags); return ret; } -int -prom_node_has_property(int node, char *prop) +int prom_node_has_property(int node, char *prop) { char *current_property = ""; @@ -279,8 +274,7 @@ /* Set property 'pname' at node 'node' to value 'value' which has a length * of 'size' bytes. Return the number of bytes the prom accepted. */ -int -prom_setprop(int node, char *pname, char *value, int size) +int prom_setprop(int node, char *pname, char *value, int size) { unsigned long flags; int ret; @@ -289,24 +283,19 @@ if((pname == 0) || (value == 0)) return 0; save_flags(flags); cli(); ret = prom_nodeops->no_setprop(node, pname, value, size); - __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : - "memory"); + restore_current(); restore_flags(flags); return ret; } -int -prom_inst2pkg(int inst) +int prom_inst2pkg(int inst) { int node; unsigned long flags; save_flags(flags); cli(); node = (*romvec->pv_v2devops.v2_inst2pkg)(inst); - __asm__ __volatile__("ld [%0], %%g6\n\t" : : - "r" (¤t_set[smp_processor_id()]) : - "memory"); + restore_current(); restore_flags(flags); if (node == -1) return 0; return node; @@ -315,8 +304,7 @@ /* Return 'node' assigned to a particular prom 'path' * FIXME: Should work for v0 as well */ -int -prom_pathtoinode(char *path) +int prom_pathtoinode(char *path) { int node, inst; diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile --- v2.1.28/linux/arch/sparc64/Makefile Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc64/Makefile Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 1997/01/02 14:14:35 jj Exp $ +# $Id: Makefile,v 1.6 1997/03/04 16:27:18 jj Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -22,8 +22,8 @@ # Uncomment the first CFLAGS if you are doing kgdb source level # debugging of the kernel to get the proper debugging information. -#CFLAGS := $(CFLAGS) -g -pipe -CFLAGS := $(CFLAGS) -pipe +#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 +CFLAGS := $(CFLAGS) -pipe -fcall-used-g5 -fcall-used-g7 LINKFLAGS = -T arch/sparc64/vmlinux.lds @@ -40,3 +40,16 @@ archclean: archdep: + +# Temporary hack, until we get a clean compile of everything... +vmlinux64: $(CONFIGURATION) init/main.o init/version.o + set -e; for i in arch/sparc64/kernel arch/sparc64/lib arch/sparc64/prom lib; do $(MAKE) -C $$i; done + $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ + arch/sparc64/kernel/kernel.o \ + lib/lib.a arch/sparc64/prom/promlib.a arch/sparc64/lib/lib.a \ + -o vmlinux + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)\|\(\.\.ng$$\)' | sort > System.map +# + +check_asm: + $(MAKE) -C arch/sparc64/kernel check_asm diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.1.28/linux/arch/sparc64/kernel/Makefile Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/kernel/Makefile Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 1996/12/26 10:16:41 davem Exp $ +# $Id: Makefile,v 1.5 1997/03/04 16:26:54 jj Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -13,20 +13,33 @@ .S.o: $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o -all: kernel.o head.o initobj.o finitobj.o +all: kernel.o head.o O_TARGET := kernel.o -O_OBJS := etrap.o rtrap.o signal32.o +O_OBJS := etrap.o rtrap.o hack.o process.o # signal32.o OX_OBJS := sparc64_ksyms.o head.o: head.S $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o -initobj.o: initobj.S - $(CC) -D__ASSEMBLY__ -ansi -c initobj.S -o initobj.o - -finitobj.o: initobj.S - $(CC) -D__ASSEMBLY__ -ansi -c finitobj.S -o finitobj.o +check_asm: dummy + @echo "#include " > tmp.c + $(CC) -E tmp.c -o tmp.i + @echo "/* Automatically generated. Do not edit. */" > check_asm.c; echo "#include " >> check_asm.c; echo 'struct task_struct _task; struct mm_struct _mm; struct thread_struct _thread; int main(void) { printf ("/* Automatically generated. Do not edit. */\n#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n\n");' >> check_asm.c + $(SH) ./check_asm.sh task tmp.i check_asm.c + $(SH) ./check_asm.sh mm tmp.i check_asm.c + $(SH) ./check_asm.sh thread tmp.i check_asm.c + @echo 'printf ("\n#endif /* __ASM_OFFSETS_H__ */\n"); return 0; }' >> check_asm.c + @rm -f tmp.[ci] + #$(CC) -o check_asm check_asm.c + # Until we can do this natively, a hack has to take place + $(CC) -mmedlow -S -o check_asm.s check_asm.c + $(HOSTCC) -o check_asm check_asm.s + @rm -f check_asm.s + # + ./check_asm > asm_offsets.h + @if test -r $(HPATH)/asm/asm_offsets.h; then if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then echo $(HPATH)/asm/asm_offsets.h is unchanged; rm -f asm_offsets.h; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi + @rm -f check_asm check_asm.c include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/check_asm.sh linux/arch/sparc64/kernel/check_asm.sh --- v2.1.28/linux/arch/sparc64/kernel/check_asm.sh Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/check_asm.sh Wed Mar 5 17:04:31 1997 @@ -0,0 +1,3 @@ +#!/bin/sh +sed -n -e '/struct[ ]*'$1'_struct[ ]*{/,/};/p' < $2 | sed '/struct[ ]*'$1'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ +/g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$1'_\0 0x%08x\\n#define ASIZ_'$1'_\0 0x%08x\\n", ((char *)\&_'$1'.\0) - ((char *)\&_'$1'), sizeof(_'$1'.\0));/' >> $3 diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/dtlb_miss.S linux/arch/sparc64/kernel/dtlb_miss.S --- v2.1.28/linux/arch/sparc64/kernel/dtlb_miss.S Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/kernel/dtlb_miss.S Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -/* $Id: dtlb_miss.S,v 1.4 1996/12/28 18:39:40 davem Exp $ +/* $Id: dtlb_miss.S,v 1.5 1997/02/25 20:00:02 jj Exp $ * dtlb_miss.S: Data TLB miss code, this is included directly * into the trap table. * @@ -45,10 +45,9 @@ * XXX I think I can knock off two more instructions here... */ -dtlb_miss: /* I-cache line 0 */ ldxa [%g0] ASI_DMMU, %g1 ! grab Tag Target either way - brlz,pnt %g1, 3f ! special kernel processing + brlz,pn %g1, 3f ! special kernel processing srlx %g1, 8, %g3 ! put high vaddr bits in place 1: @@ -68,15 +67,15 @@ 2: retry ! return from trap -#define KTTE_HIGH_BITS (_PAGE_VALID | _PAGE_SZ4MB) -#define KTTE_LOW_BITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G) +#define KTTE_HIGH_BITS _PAGE_VALID | _PAGE_SZ4MB +#define KTTE_LOW_BITS _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G nop ! align next insn on cache line 3: /* I-cache line 2 */ srax %g1, 19, %g5 ! mask down high bits cmp %g5, -1 ! if -1 this is VMALLOC area - be,pnt %xcc, 1b ! yep + be,pn %xcc, 1b ! yep sethi %uhi(KTTE_HIGH_BITS), %g4 ! begin pte formation sllx %g1, 23, %g1 ! begin masking for physpage diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S --- v2.1.28/linux/arch/sparc64/kernel/dtlb_prot.S Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/kernel/dtlb_prot.S Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -/* $Id: dtlb_prot.S,v 1.3 1996/12/28 18:39:41 davem Exp $ +/* $Id: dtlb_prot.S,v 1.5 1997/02/26 11:09:26 jj Exp $ * dtlb_prot.S: Fast TLB protection trap processing. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -35,7 +35,6 @@ * from the miss handlers probing the page tables. */ -dtlb_prot: /* I-cache line 0 */ ldxa [%g0] ASI_DMMU, %g1 srlx %g1, 8, %g3 @@ -49,11 +48,11 @@ srlx %g1, 1, %g1 ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 andcc %g3, _PAGE_WRITE, %g0 - be,pnt %xcc, sparc64_dtlb_fault + be,pn %xcc, sparc64_dtlb_fault or %g3, (_PAGE_WRITE|_PAGE_W|_PAGE_MODIFIED|_PAGE_ACCESSED), %g3 /* Blamo... */ - stxa %g3, [%g4 + %g1] %asi + stxa %g3, [%g4 + %g1] ASI_DMMU stxa %g3, [%g0] ASI_DTLB_DATA_IN retry diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S --- v2.1.28/linux/arch/sparc64/kernel/etrap.S Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/kernel/etrap.S Wed Mar 5 17:04:31 1997 @@ -1,7 +1,8 @@ -/* $Id: etrap.S,v 1.1 1996/12/26 10:16:42 davem Exp $ +/* $Id: etrap.S,v 1.4 1997/03/04 16:26:58 jj Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include @@ -11,42 +12,52 @@ .align 4 .globl etrap etrap: + rdpr %wstate, %g2 sethi %uhi(current_set), %g6 - rd %tstate, %g1 - or %g6, %ulo(current_set), %g6 - rd %tpc, %g2 - sllx %g6, 32, %g6 - rd %tnpc, %g3 + andcc %g2, 7, %g2 + rdpr %tstate, %g1 + be,pn %xcc, 1f /* What happens more often? etrap when already in priv or from userland? */ + sllx %g6, 32, %g6 + sll %g2, 3, %g2 + wrpr %g2, %wstate +1: sethi %hi(current_set), %g4 or %g4, %lo(current_set), %g4 - or %g6, %g4, %g6 + rdpr %tpc, %g2 + rdpr %canrestore, %g5 + rdpr %tnpc, %g3 + wrpr %g5, 0, %otherwin + wrpr %g0, 0, %canrestore + ldx [%g6 + %g4], %g6 +#ifdef __SMP__ +/* FIXME: Fix the above insn for SMP */ +#endif rd %y, %g4 - ldx [%g6 + THREAD_KSTACK], %g5 + ldx [%g6 + AOFF_task_tss + AOFF_thread_ksp], %g5 stx %g1, [%g5 + REGWIN_SZ + PT_TSTATE] stx %g2, [%g5 + REGWIN_SZ + PT_TPC] stx %g3, [%g5 + REGWIN_SZ + PT_TNPC] stx %g4, [%g5 + REGWIN_SZ + PT_Y] - rd %pstate, %g1 - andn %g1, (PSTATE_IG | PSTATE_MG | PSTATE_AG), %g2 - save %g5, 0x0, %sp - mov %g2, %l1 - wr %g0, 0x0, %tl + rdpr %pstate, %g1 + save %g5, -STACK_BIAS, %sp + andn %g1, (PSTATE_IG | PSTATE_MG | PSTATE_AG), %l1 + wrpr %g0, 0x0, %tl mov %g7, %l2 - wr %l1, 0x0, %pstate - stx %g1, [%sp + REGWIN_SZ + PT_G1] - stx %g2, [%sp + REGWIN_SZ + PT_G2] - stx %g3, [%sp + REGWIN_SZ + PT_G3] - stx %g4, [%sp + REGWIN_SZ + PT_G4] - stx %g5, [%sp + REGWIN_SZ + PT_G5] - stx %g6, [%sp + REGWIN_SZ + PT_G6] - stx %g7, [%sp + REGWIN_SZ + PT_G7] - stx %i0, [%sp + REGWIN_SZ + PT_I0] - stx %i1, [%sp + REGWIN_SZ + PT_I1] - stx %i2, [%sp + REGWIN_SZ + PT_I2] - stx %i3, [%sp + REGWIN_SZ + PT_I3] - stx %i4, [%sp + REGWIN_SZ + PT_I4] - stx %i5, [%sp + REGWIN_SZ + PT_I5] - stx %i6, [%sp + REGWIN_SZ + PT_I6] - stx %i7, [%sp + REGWIN_SZ + PT_I7] + wrpr %l1, 0x0, %pstate + stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_G1] + stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_G2] + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_G3] + stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_G4] + stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_G5] + stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_G6] + stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_G7] + stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0] + stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_I1] + stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_I2] + stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_I3] + stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_I4] + stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_I5] + stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_I6] + stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_I7] jmpl %l2 + 0x4, %g0 - wr %l1, PSTATE_IE, %pstate + wrpr %l1, PSTATE_IE, %pstate diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/hack.S linux/arch/sparc64/kernel/hack.S --- v2.1.28/linux/arch/sparc64/kernel/hack.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/hack.S Wed Mar 5 17:04:31 1997 @@ -0,0 +1,398 @@ +/* + This is just a huge ugly hack to get things compiled. + Hopefully will disappear quickly, once we get everything + to compile... */ + .text + .globl ROOT_DEV +ROOT_DEV: + nop + .globl ___lock_kernel +___lock_kernel: + nop + .globl ___unlock_kernel +___unlock_kernel: + nop + .globl __memcpy +__memcpy: + nop + .globl __strncmp +__strncmp: + nop + .globl _ctype +_ctype: + nop + .globl _stext +_stext: + nop + .globl bad_trap +bad_trap: + nop + .globl bad_trap_tl1 +bad_trap_tl1: + nop + .globl bdflush +bdflush: + nop + .globl breakpoint_trap +breakpoint_trap: + nop + .globl buff_setup +buff_setup: + nop + .globl buffer_init +buffer_init: + nop + .globl change_root +change_root: + nop + .globl console_init +console_init: + nop + .globl console_loglevel +console_loglevel: + nop + .globl console_restore_palette +console_restore_palette: + nop + .globl current_set +current_set: + nop + .globl do_cee +do_cee: + nop + .globl do_cee_tl1 +do_cee_tl1: + nop + .globl do_dae +do_dae: + nop + .globl do_dae_tl1 +do_dae_tl1: + nop + .globl do_dax +do_dax: + nop + .globl do_dax_tl1 +do_dax_tl1: + nop + .globl do_div0 +do_div0: + nop + .globl do_div0_tl1 +do_div0_tl1: + nop + .globl do_fpdis +do_fpdis: + nop + .globl do_fpdis_tl1 +do_fpdis_tl1: + nop + .globl do_fpieee +do_fpieee: + nop + .globl do_fpieee_tl1 +do_fpieee_tl1: + nop + .globl do_fpother +do_fpother: + nop + .globl do_fpother_tl1 +do_fpother_tl1: + nop + .globl do_iae +do_iae: + nop + .globl do_iae_tl1 +do_iae_tl1: + nop + .globl do_iax +do_iax: + nop + .globl do_iax_tl1 +do_iax_tl1: + nop + .globl do_ill +do_ill: + nop + .globl do_ill_tl1 +do_ill_tl1: + nop + .globl do_irq +do_irq: + nop + .globl do_irq_tl1 +do_irq_tl1: + nop + .globl do_ivec +do_ivec: + nop + .globl do_ivec_tl1 +do_ivec_tl1: + nop + .globl do_lddfmna +do_lddfmna: + nop + .globl do_lddfmna_tl1 +do_lddfmna_tl1: + nop + .globl do_mna +do_mna: + nop + .globl do_mna_tl1 +do_mna_tl1: + nop + .globl do_paw +do_paw: + nop + .globl do_paw_tl1 +do_paw_tl1: + nop + .globl do_privact +do_privact: + nop + .globl do_privop +do_privop: + nop + .globl do_stdfmna +do_stdfmna: + nop + .globl do_stdfmna_tl1 +do_stdfmna_tl1: + nop + .globl do_tof +do_tof: + nop + .globl do_tof_tl1 +do_tof_tl1: + nop + .globl do_vaw +do_vaw: + nop + .globl do_vaw_tl1 +do_vaw_tl1: + nop + .globl dquot_init +dquot_init: + nop + .globl errno +errno: + nop + .globl eth_setup +eth_setup: + nop + .globl file_table_init +file_table_init: + nop + .globl floppy_setup +floppy_setup: + nop + .globl getcc +getcc: + nop + .globl indirect_syscall +indirect_syscall: + nop + .globl init_IRQ +init_IRQ: + nop + .globl init_task +init_task: + nop + .globl initrd_below_start_ok +initrd_below_start_ok: + nop + .globl initrd_start +initrd_start: + nop + .globl inode_init +inode_init: + nop + .globl install_linux_ticker +install_linux_ticker: + nop + .globl install_obp_ticker +install_obp_ticker: + nop + .globl ipc_init +ipc_init: + nop + .globl jiffies +jiffies: + nop + .globl kernel_enter_debugger +kernel_enter_debugger: + nop + .globl kmalloc_init +kmalloc_init: + nop + .globl kmem_cache_init +kmem_cache_init: + nop + .globl kmem_cache_sizes_init +kmem_cache_sizes_init: + nop + .globl kswapd +kswapd: + nop + .globl linux32_syscall +linux32_syscall: + nop + .globl linux64_syscall +linux64_syscall: + nop + .globl lookup_fault +lookup_fault: + nop + .globl mem_init +mem_init: + nop + .globl memcpy +memcpy: + nop + .globl mount_initrd +mount_initrd: + nop + .globl name_cache_init +name_cache_init: + nop + .globl netbsd_syscall +netbsd_syscall: + nop + .globl no_scroll +no_scroll: + nop + .globl paging_init +paging_init: + nop + .globl panic +panic: + nop + .globl panic_setup +panic_setup: + nop + .globl printk +printk: + nop + .globl prof_buffer +prof_buffer: + nop + .globl prof_len +prof_len: + nop + .globl prof_shift +prof_shift: + nop + .globl pseudo_root +pseudo_root: + nop + .globl rd_doload +rd_doload: + nop + .globl rd_image_start +rd_image_start: + nop + .globl rd_prompt +rd_prompt: + nop + .globl rd_size +rd_size: + nop + .globl reboot_command +reboot_command: + nop + .globl reserve_setup +reserve_setup: + nop + .globl sbus_init +sbus_init: + nop + .globl sched_init +sched_init: + nop + .globl scsi_luns_setup +scsi_luns_setup: + nop + .globl serial_console +serial_console: + nop + .globl set_palette +set_palette: + nop + .globl setcc +setcc: + nop + .globl setup_arch +setup_arch: + nop + .globl simple_strtoul +simple_strtoul: + nop + .globl sock_init +sock_init: + nop + .globl solaris_syscall +solaris_syscall: + nop + .globl sparc64_dtlb_fault +sparc64_dtlb_fault: + nop + .globl sparc64_dtlb_refbit_catch +sparc64_dtlb_refbit_catch: + nop + .globl sparc64_itlb_refbit_catch +sparc64_itlb_refbit_catch: + nop + .globl sprintf +sprintf: + nop + .globl st_setup +st_setup: + nop + .globl strchr +strchr: + nop + .globl strcmp +strcmp: + nop + .globl strcpy +strcpy: + nop + .globl strlen +strlen: + nop + .globl strncpy +strncpy: + nop + .globl sunos_syscall +sunos_syscall: + nop + .globl swap_setup +swap_setup: + nop + .globl sysctl_init +sysctl_init: + nop + .globl time_init +time_init: + nop + .globl trap_init +trap_init: + nop + .globl vma_init +vma_init: + nop + .globl vsprintf +vsprintf: + nop + .globl schedule +schedule: + nop + .globl getname +getname: + nop + .globl do_execve +do_execve: + nop + .globl putname +putname: + nop diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S --- v2.1.28/linux/arch/sparc64/kernel/head.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc64/kernel/head.S Wed Mar 5 17:04:31 1997 @@ -1,21 +1,53 @@ -/* $Id: head.S,v 1.6 1997/01/06 20:32:44 jj Exp $ +/* $Id: head.S,v 1.9 1997/02/26 11:09:25 jj Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include #include +#include #include +#include #include #include - .text +/* This section from from _start to sparc64_boot_end should fit into + 0xfffff80000004000 to 0xfffff80000008000 and will be sharing space + with bootup_user_stack, which is from 0xfffff80000004000 to + 0xfffff80000006000 and bootup_kernel_stack, which is from + 0xfffff80000006000 to 0xfffff80000008000. */ -#include "ttable.S" + .text + .globl start, _start +_start: +start: +bootup_user_stack: +! 0xfffff80000004000 + b sparc64_boot + rdpr %ver, %g1 /* Get VERSION register. */ + +/* This stuff has to be in sync with SILO and other potential boot loaders + * Fields should be kept upward compatible and whenever any change is made, + * HdrS version should be incremented. + */ + .ascii "HdrS" + .word LINUX_VERSION_CODE + .half 0x0201 /* HdrS version */ +root_flags: + .half 1 +root_dev: + .half 0 +ram_flags: + .half 0 +ramdisk_image: + .word 0 +ramdisk_size: + .word 0 + .word reboot_command sparc64_boot: - rdpr %ver, %g1 /* Get VERSION register. */ - /* We must be careful, 32-bit OpenBOOT will get confused if it * tries to save away a register window to a 64-bit kernel * stack address. Flush all windows, disable interrupts, @@ -26,22 +58,19 @@ wrpr %g0, 0xf, %pil /* Interrupts off. */ /* Remap ourselves to upper 64-bit addresses if necessary. - * SILO64 will have loaded us to the right location already. */ - mov %o7, %g4 + sethi %uhi(PAGE_OFFSET), %g4 current_pc: - call 1f - mov %o7, %g3 -1: - mov %g4, %o7 - - set current_pc, %g7 - cmp %g3, %g7 + rd %pc, %g2 + sllx %g4, 32, %g4 + sethi %hi(current_pc), %g3 + or %g3, %lo(current_pc), %g3 + add %g4, %g3, %g3 + cmp %g3, %g2 be go_to_highmem nop /* Remap ourselves into high addresses. */ - set PAGE_OFFSET, %g4 sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5 sllx %g5, 32, %g5 or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G | _PAGE_L), %g5 @@ -63,44 +92,84 @@ membar #Sync flush %g4 +/* FIXME: Should clean here the page @ phys. 0 and map one page @ */ + go_to_highmem: - set execute_in_high_mem, %g7 - jmpl %g7, %g0 + jmpl %g3 + (execute_in_high_mem - current_pc), %g0 nop execute_in_high_mem: - set nwindows, %g7 + /* Remap our prom interface code */ + sethi %hi(__p1275_loc), %g7 + or %g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G | _PAGE_L), %g7 + /* The lock bit has to be removed from this page later on, + but before firing up init we will use PROM a lot, so we + lock it there now... */ + sethi %uhi(_PAGE_VALID), %g5 + sethi %hi(0x8000), %g3 + sllx %g5, 32, %g5 + mov TLB_TAG_ACCESS, %g6 + or %g5, %g7, %g5 + stxa %g3, [%g6] ASI_IMMU + stxa %g5, [%g0] ASI_ITLB_DATA_IN + membar #Sync + flush %g3 + stxa %g3, [%g6] ASI_DMMU + stxa %g5, [%g0] ASI_DTLB_DATA_IN + membar #Sync + flush %g3 + + sethi %hi(nwindows), %g7 and %g1, VERS_MAXWIN, %g5 - add %g5, 1, %g4 - stx %g4, [%g7] - set nwindowsm1, %g6 - stx %g5, [%g6] + add %g7, %lo(nwindows), %g7 + add %g5, 1, %g6 + add %g7, (nwindows - nwindowsm1), %g3 + stx %g6, [%g7 + %g4] + stx %g5, [%g3 + %g4] mov %sp, %o1 ! second argument to prom_init - set swapper_pg_dir, %g6 - set PAGE_OFFSET, %g4 ! this stays here for a long time - sub %g6, %g4, %g5 - set init_task, %g6 ! g6 usage is fixed as well + sethi %hi(init_task), %g6 + or %g6, %lo(init_task), %g6 + add %g6, %g4, %g6 ! g6 usage is fixed as well - set sparc64_ttable_tl0, %g5 +/* FIXME: Initialize MMU globals??? */ + + sethi %hi(sparc64_ttable_tl0), %g5 + add %g5, %g4, %g5 wrpr %g5, %tba - set bootup_kernel_stack, %sp + sethi %hi(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5 + or %g5, %lo(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5 + add %g5, %g4, %sp mov 0, %fp - wrpr %g0, PSTATE_KERNEL, %pstate - wrpr %g0, WSTATE_KERNEL, %wstate + wrpr %g0, PSTATE_PEF | PSTATE_PRIV, %pstate + wrpr %g0, 0, %wstate wrpr %g0, 0x0, %tl - /* XXX Map in PROM 32-bit trampoline code. */ - call prom_init mov %o4, %o0 ! OpenPROM cif handler /* Off we go.... */ call start_kernel nop - /* Not reached... */ + +sparc64_boot_end: + .skip 0x2000 + _start - sparc64_boot_end +bootup_user_stack_end: + +bootup_kernel_stack: + .skip 0x2000 + +! 0xfffff80000008000 + +#include "ttable.S" + + .global root_flags + .global ram_flags + .global root_dev + .global ramdisk_image + .global ramdisk_size .data .align 8 diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/itlb_miss.S linux/arch/sparc64/kernel/itlb_miss.S --- v2.1.28/linux/arch/sparc64/kernel/itlb_miss.S Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/kernel/itlb_miss.S Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -/* $Id: itlb_miss.S,v 1.4 1996/12/28 18:39:42 davem Exp $ +/* $Id: itlb_miss.S,v 1.5 1997/02/25 20:00:05 jj Exp $ * itlb_miss.S: Instruction TLB miss code, this is included directly * into the trap table. * @@ -45,7 +45,6 @@ * processes startup when the TSB is cold. */ -itlb_miss: /* I-cache line 0 */ ldxa [%g0] ASI_IMMU, %g1 ! grab Tag Target srlx %g1, 8, %g3 ! put high vaddr bits in place diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.1.28/linux/arch/sparc64/kernel/process.c Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/kernel/process.c Wed Mar 5 17:04:31 1997 @@ -1,8 +1,9 @@ -/* $Id: process.c,v 1.1 1996/12/28 18:39:39 davem Exp $ +/* $Id: process.c,v 1.3 1997/03/04 16:26:56 jj Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ /* @@ -23,6 +24,7 @@ #include #include #include +#include #include #include @@ -56,7 +58,7 @@ #else /* - * the idle loop on a SparcMultiPenguin... + * the idle loop on a UltraMultiPenguin... */ asmlinkage int sys_idle(void) { @@ -105,7 +107,7 @@ extern int serial_console; #endif -void halt_now(void) +void machine_halt(void) { sti(); udelay(8000); @@ -118,7 +120,7 @@ panic("Halt failed!"); } -void hard_reset_now(void) +void machine_restart(char * cmd) { char *p; @@ -132,12 +134,19 @@ if (!serial_console) console_restore_palette (); #endif + if (cmd) + prom_reboot(cmd); if (*reboot_command) - prom_reboot (reboot_command); + prom_reboot(reboot_command); prom_feval ("reset"); panic("Reboot failed!"); } +void machine_power_off(void) +{ + machine_halt(); +} + void show_regwindow(struct reg_window *rw) { printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n" @@ -152,12 +161,12 @@ void show_regwindow32(struct reg_window32 *rw) { - printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx\n" - "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n", + printk("l0: %08x l1: %08x l2: %08x l3: %08x\n" + "l4: %08x l5: %08x l6: %08x l7: %08x\n", rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); - printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx\n" - "i4: %08lx i5: %08lx i6: %08lx i7: %08lx\n", + printk("i0: %08x i1: %08x i2: %08x i3: %08x\n" + "i4: %08x i5: %08x i6: %08x i7: %08x\n", rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } @@ -193,29 +202,29 @@ void show_stackframe32(struct sparc_stackf32 *sf) { unsigned long size; - unsigned long *stk; + unsigned *stk; int i; - printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx\n" - "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n", + printk("l0: %08x l1: %08x l2: %08x l3: %08x\n" + "l4: %08x l5: %08x l6: %08x l7: %08x\n", sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3], sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]); - printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx\n" - "i4: %08lx i5: %08lx fp: %08lx ret_pc: %08lx\n", + printk("i0: %08x i1: %08x i2: %08x i3: %08x\n" + "i4: %08x i5: %08x fp: %08x ret_pc: %08x\n", sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3], - sf->ins[4], sf->ins[5], (unsigned long)sf->fp, sf->callers_pc); - printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx\n" - "x3: %08lx x4: %08lx x5: %08lx xx: %08lx\n", - (unsigned long)sf->structptr, sf->xargs[0], sf->xargs[1], + sf->ins[4], sf->ins[5], sf->fp, sf->callers_pc); + printk("sp: %08x x0: %08x x1: %08x x2: %08x\n" + "x3: %08x x4: %08x x5: %08x xx: %08x\n", + sf->structptr, sf->xargs[0], sf->xargs[1], sf->xargs[2], sf->xargs[3], sf->xargs[4], sf->xargs[5], sf->xxargs[0]); size = ((unsigned long)sf->fp) - ((unsigned long)sf); - size -= STACKFRAME_SZ; - stk = (unsigned long *)((unsigned long)sf + STACKFRAME_SZ); + size -= STACKFRAME32_SZ; + stk = (unsigned *)((unsigned long)sf + STACKFRAME32_SZ); i = 0; do { - printk("s%d: %08lx\n", i++, *stk++); - } while ((size -= sizeof(unsigned long))); + printk("s%d: %08x\n", i++, *stk++); + } while ((size -= sizeof(unsigned))); } void show_regs(struct pt_regs * regs) @@ -245,29 +254,31 @@ #if __MPP__ printk("CID: %d\n",mpp_cid()); #endif - printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx\n", regs->psr, + printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr, regs->pc, regs->npc, regs->y); - printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx\n", + printk("g0: %08x g1: %08x g2: %08x g3: %08x\n", regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], regs->u_regs[3]); - printk("g4: %08lx g5: %08lx g6: %08lx g7: %08lx\n", + printk("g4: %08x g5: %08x g6: %08x g7: %08x\n", regs->u_regs[4], regs->u_regs[5], regs->u_regs[6], regs->u_regs[7]); - printk("o0: %08lx o1: %08lx o2: %08lx o3: %08lx\n", + printk("o0: %08x o1: %08x o2: %08x o3: %08x\n", regs->u_regs[8], regs->u_regs[9], regs->u_regs[10], regs->u_regs[11]); - printk("o4: %08lx o5: %08lx sp: %08lx ret_pc: %08lx\n", + printk("o4: %08x o5: %08x sp: %08x ret_pc: %08x\n", regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], regs->u_regs[15]); - show_regwindow32((struct reg_window32 *)regs->u_regs[14]); + show_regwindow32((struct reg_window32 *)((unsigned long)regs->u_regs[14])); } void show_thread(struct thread_struct *tss) { int i; +#if 0 printk("kregs: 0x%016lx\n", (unsigned long)tss->kregs); show_regs(tss->kregs); +#endif printk("sig_address: 0x%016lx\n", tss->sig_address); printk("sig_desc: 0x%016lx\n", tss->sig_desc); printk("ksp: 0x%016lx\n", tss->ksp); @@ -292,7 +303,7 @@ printk("sstk_info.status: 0x%016lx\n", (unsigned long)tss->sstk_info.cur_status); printk("flags: 0x%016lx\n", tss->flags); - printk("current_ds: 0x%016lx\n", tss->current_ds); + printk("current_ds: 0x%016x\n", tss->current_ds); /* XXX missing: core_exec */ } @@ -302,6 +313,7 @@ */ void exit_thread(void) { +#if 0 kill_user_windows(); #ifndef __SMP__ if(last_task_used_math == current) { @@ -319,10 +331,12 @@ #endif } mmu_exit_hook(); +#endif } void flush_thread(void) { +#if 0 kill_user_windows(); current->tss.w_saved = 0; current->tss.uwinmask = 0; @@ -346,8 +360,8 @@ current->flags &= ~PF_USEDFPU; #endif } - mmu_flush_hook(); +#endif /* Now, this task is no longer a kernel thread. */ current->tss.flags &= ~SPARC_FLAG_KTHREAD; current->tss.current_ds = USER_DS; @@ -407,6 +421,7 @@ unsigned long size; struct sparc_stackf *sp; +#if 0 size = ((unsigned long)src->fp) - ((unsigned long)src); sp = (struct sparc_stackf *)(((unsigned long)dst) - size); @@ -414,6 +429,7 @@ return 0; if (put_user(dst, &sp->fp)) return 0; +#endif return sp; } @@ -439,6 +455,7 @@ struct reg_window *new_stack; unsigned long stack_offset; +#if 0 #ifndef __SMP__ if(last_task_used_math == current) { #else @@ -451,23 +468,29 @@ current->flags &= ~PF_USEDFPU; #endif } +#endif /* Calculate offset to stack_frame & pt_regs */ stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ); +#if 0 if(regs->psr & PSR_PS) stack_offset -= REGWIN_SZ; +#endif childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset)); copy_regs(childregs, regs); new_stack = (((struct reg_window *) childregs) - 1); copy_regwin(new_stack, (((struct reg_window *) regs) - 1)); +#if 0 p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack; p->tss.kpc = (((unsigned long) ret_from_syscall) - 0x8); p->tss.kpsr = current->tss.fork_kpsr; p->tss.kwim = current->tss.fork_kwim; p->tss.kregs = childregs; +#endif +#if 0 if(regs->psr & PSR_PS) { childregs->u_regs[UREG_FP] = p->tss.ksp; p->tss.flags |= SPARC_FLAG_KTHREAD; @@ -507,6 +530,7 @@ childregs->u_regs[UREG_FP] = (unsigned long)childstack; } } +#endif /* Set the return value for the child. */ childregs->u_regs[UREG_I0] = current->pid; @@ -514,7 +538,6 @@ /* Set the return value for the parent. */ regs->u_regs[UREG_I1] = 0; - return 0; } @@ -524,7 +547,7 @@ void dump_thread(struct pt_regs * regs, struct user * dump) { unsigned long first_stack_page; - +#if 0 dump->magic = SUNOS_CORE_MAGIC; dump->len = sizeof(struct user); dump->regs.psr = regs->psr; @@ -548,6 +571,7 @@ memcpy(&dump->fpu.fpstatus.fpq[0], ¤t->tss.fpqueue[0], ((sizeof(unsigned long) * 2) * 16)); dump->sigcode = current->tss.sig_desc; +#endif } /* diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.1.28/linux/arch/sparc64/kernel/rtrap.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/rtrap.S Wed Mar 5 17:04:31 1997 @@ -0,0 +1,14 @@ +/* $Id: rtrap.S,v 1.2 1997/02/26 11:09:25 jj Exp $ + * rtrap.S: Preparing for entry into the kernel on Sparc V9. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include + + .text + .align 4 + .globl rtrap +rtrap: + /*not*/ done /*yet*/ diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.1.28/linux/arch/sparc64/kernel/signal32.c Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc64/kernel/signal32.c Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.3 1997/01/19 22:32:30 ecd Exp $ +/* $Id: signal32.c,v 1.4 1997/03/03 16:51:46 jj Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -53,12 +53,12 @@ * ---------------------------------- <-- New %sp */ struct signal_sframe32 { - struct reg_window_32 sig_window; + struct reg_window32 sig_window; int sig_num; int sig_code; - struct sigcontext_32 *sig_scptr; + struct sigcontext32 *sig_scptr; int sig_address; - struct sigcontext_32 sig_context; + struct sigcontext32 sig_context; }; /* @@ -68,7 +68,7 @@ */ struct new_signal_frame32 { - struct sparc_stackf_32 ss; + struct sparc_stackf32 ss; __siginfo32_t info; __siginfo_fpu32_t *fpu_save; unsigned int insns [2]; @@ -123,23 +123,23 @@ static inline void -restore_fpu_state(struct pt_regs *regs, __siginfo_fpu32_t *fpu) +restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu) { #ifdef __SMP__ if (current->flags & PF_USEDFPU) - regs->psr &= ~(TSTATE_PEF); + regs->tstate &= ~(TSTATE_PEF); #else if (current == last_task_used_math) { last_task_used_math = 0; - regs->psr &= ~(TSTATE_PEF); + regs->tstate &= ~(TSTATE_PEF); } #endif current->used_math = 1; current->flags &= ~PF_USEDFPU; copy_32bit_to_kernel_fpuregs(¤t->tss.float_regs[0], - &sf->info.si_float_regs[0], - (sizeof(unsigned int) * 64)); + &fpu->si_float_regs[0], + (sizeof(unsigned int) * 32)); __get_user(current->tss.fsr, &fpu->si_fsr); __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth); if (current->tss.fpqdepth != 0) @@ -160,7 +160,7 @@ do_exit (SIGSEGV); return; } - if (((uint) sf) & 3){ + if (((unsigned long) sf) & 3){ do_exit (SIGSEGV); return; } @@ -179,23 +179,23 @@ regs->tstate |= (sf->info.si_regs.psr & PSR_EF); if (sf->fpu_save) - restore_fpu_state(regs, sf->fpu_state); + restore_fpu_state32(regs, sf->fpu_state); current->blocked = sf->info.si_mask & _BLOCKABLE; } asmlinkage void do_sigreturn32(struct pt_regs *regs) { - struct sigcontext *scptr; + struct sigcontext32 *scptr; unsigned long pc, npc, psr; synchronize_user_stack(); if (current->tss.new_signal) return do_new_sigreturn32(regs); - scptr = (struct sigcontext *) regs->u_regs[UREG_I0]; + scptr = (struct sigcontext32 *) regs->u_regs[UREG_I0]; /* Check sanity of the user arg. */ - if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext)) || + if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) || (((unsigned long) scptr) & 3)) { printk("%s [%d]: do_sigreturn, scptr is invalid at " "pc<%08lx> scptr<%p>\n", @@ -236,7 +236,7 @@ struct pt_regs *regs, int signr, unsigned long oldmask) { struct signal_sframe32 *sframep; - struct sigcontext *sc; + struct sigcontext32 *sc; int window = 0; int old_status = current->tss.sstk_info.cur_status; @@ -302,7 +302,7 @@ static inline void -save_fpu_state(struct pt_regs *regs, __siginfo_fpu32_t *fpu) +save_fpu_state32(struct pt_regs *regs, __siginfo_fpu32_t *fpu) { #ifdef __SMP__ if (current->flags & PF_USEDFPU) { @@ -322,7 +322,7 @@ } #endif copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], - (sizeof(unsigned long) * 64)); + (sizeof(unsigned int) * 32)); __put_user(current->tss.fsr, &fpu->si_fsr); __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); if (current->tss.fpqdepth != 0) @@ -363,7 +363,7 @@ memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs)); if (current->used_math) { - save_fpu_state(regs, &sf->fpu_state); + save_fpu_state32(regs, &sf->fpu_state); sf->fpu_save = &sf->fpu_state; } else { sf->fpu_save = NULL; diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.1.28/linux/arch/sparc64/kernel/sparc64_ksyms.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Wed Mar 5 17:04:31 1997 @@ -0,0 +1,179 @@ +/* $Id: sparc64_ksyms.c,v 1.1 1997/03/03 16:51:45 jj Exp $ + * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + */ + +#define PROMLIB_INTERNAL + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SBUS +#include +#include +#endif +#include + +struct poll { + int fd; + short events; + short revents; +}; + +extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *); +extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *); +extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long); +void _sigpause_common (unsigned int set, struct pt_regs *); +extern void __copy_1page(void *, const void *); +extern void *bzero_1page(void *); +extern void *__bzero(void *, size_t); +extern void *__memscan_zero(void *, size_t); +extern void *__memscan_generic(void *, int, size_t); +extern int __memcmp(const void *, const void *, __kernel_size_t); +extern int __strncmp(const char *, const char *, __kernel_size_t); +extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *); + +extern void bcopy (const char *, char *, int); +extern int __ashrdi3(int, int); + +extern void dump_thread(struct pt_regs *, struct user *); + +/* One thing to note is that the way the symbols of the mul/div + * support routines are named is a mess, they all start with + * a '.' which makes it a bitch to export, here is the trick: + */ + +#define EXPORT_SYMBOL_PRIVATE(sym) \ +extern int __sparc_priv_ ## sym (int) __asm__("__" ## #sym); \ +const struct module_symbol __export_priv_##sym \ +__attribute__((section("__ksymtab"))) = \ +{ (unsigned long) &__sparc_priv_ ## sym, "__" ## #sym } + +/* used by various drivers */ +#ifdef __SMP__ +EXPORT_SYMBOL(klock_info); +#endif +EXPORT_SYMBOL_PRIVATE(_lock_kernel); +EXPORT_SYMBOL_PRIVATE(_unlock_kernel); +EXPORT_SYMBOL(page_offset); +EXPORT_SYMBOL(stack_top); + +EXPORT_SYMBOL(mstk48t02_regs); +EXPORT_SYMBOL(request_fast_irq); +EXPORT_SYMBOL(sparc_alloc_io); +EXPORT_SYMBOL(sparc_free_io); +EXPORT_SYMBOL(io_remap_page_range); +EXPORT_SYMBOL(mmu_v2p); +EXPORT_SYMBOL(mmu_unlockarea); +EXPORT_SYMBOL(mmu_lockarea); +EXPORT_SYMBOL(mmu_get_scsi_sgl); +EXPORT_SYMBOL(mmu_get_scsi_one); +EXPORT_SYMBOL(mmu_release_scsi_sgl); +EXPORT_SYMBOL(mmu_release_scsi_one); +EXPORT_SYMBOL(sparc_dvma_malloc); +EXPORT_SYMBOL(sun4c_unmapioaddr); +EXPORT_SYMBOL(srmmu_unmapioaddr); +#if CONFIG_SBUS +EXPORT_SYMBOL(SBus_chain); +EXPORT_SYMBOL(dma_chain); +#endif + +/* Solaris/SunOS binary compatibility */ +EXPORT_SYMBOL(svr4_setcontext); +EXPORT_SYMBOL(svr4_getcontext); +EXPORT_SYMBOL(_sigpause_common); +EXPORT_SYMBOL(sunos_mmap); + +/* Should really be in linux/kernel/ksyms.c */ +EXPORT_SYMBOL(dump_thread); + +/* prom symbols */ +EXPORT_SYMBOL(idprom); +EXPORT_SYMBOL(prom_root_node); +EXPORT_SYMBOL(prom_getchild); +EXPORT_SYMBOL(prom_getsibling); +EXPORT_SYMBOL(prom_searchsiblings); +EXPORT_SYMBOL(prom_firstprop); +EXPORT_SYMBOL(prom_nextprop); +EXPORT_SYMBOL(prom_getproplen); +EXPORT_SYMBOL(prom_getproperty); +EXPORT_SYMBOL(prom_node_has_property); +EXPORT_SYMBOL(prom_setprop); +EXPORT_SYMBOL(prom_getbootargs); +EXPORT_SYMBOL(prom_apply_obio_ranges); +EXPORT_SYMBOL(prom_getname); +EXPORT_SYMBOL(prom_feval); +EXPORT_SYMBOL(prom_getstring); +EXPORT_SYMBOL(prom_apply_sbus_ranges); +EXPORT_SYMBOL(prom_getint); +EXPORT_SYMBOL(prom_getintdefault); +EXPORT_SYMBOL(romvec); +EXPORT_SYMBOL(__prom_getchild); +EXPORT_SYMBOL(__prom_getsibling); + +/* sparc library symbols */ +EXPORT_SYMBOL(bcopy); +EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strncpy); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strspn); + +/* Special internal versions of library functions. */ +EXPORT_SYMBOL(__copy_1page); +EXPORT_SYMBOL(__memcpy); +EXPORT_SYMBOL(__memset); +EXPORT_SYMBOL(bzero_1page); +EXPORT_SYMBOL(__bzero); +EXPORT_SYMBOL(__memscan_zero); +EXPORT_SYMBOL(__memscan_generic); +EXPORT_SYMBOL(__memcmp); +EXPORT_SYMBOL(__strncmp); +EXPORT_SYMBOL(__memmove); + +EXPORT_SYMBOL(__csum_partial_copy_sparc_generic); + +/* Moving data to/from userspace. */ +EXPORT_SYMBOL(__copy_user); +EXPORT_SYMBOL(__strncpy_from_user); + +/* No version information on this, heavily used in inline asm, + * and will always be 'void __ret_efault(void)'. + */ +EXPORT_SYMBOL_NOVERS(__ret_efault); + +/* No version information on these, as gcc produces such symbols. */ +EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(__ashrdi3); diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S --- v2.1.28/linux/arch/sparc64/kernel/ttable.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc64/kernel/ttable.S Wed Mar 5 17:04:31 1997 @@ -1,13 +1,11 @@ -/* $Id: ttable.S,v 1.4 1997/01/16 13:43:24 jj Exp $ +/* $Id: ttable.S,v 1.5 1997/02/25 12:40:09 jj Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ - .globl start, _start .globl sparc64_ttable_tl0, sparc64_ttable_tl1 -_start: -start: + sparc64_ttable_tl0: tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) @@ -127,6 +125,15 @@ tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177) tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c) tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f) +#define BTRAPS(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) BTRAP(x+4) BTRAP(x+5) BTRAP(x+6) BTRAP(x+7) +tl0_resv180: BTRAPS(0x180) +tl0_resv190: BTRAPS(0x190) +tl0_resv1a0: BTRAPS(0x1a0) +tl0_resv1b0: BTRAPS(0x1b0) +tl0_resv1c0: BTRAPS(0x1c0) +tl0_resv1d0: BTRAPS(0x1d0) +tl0_resv1e0: BTRAPS(0x1e0) +tl0_resv1f0: BTRAPS(0x1f0) sparc64_ttable_tl1: tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3) @@ -136,7 +143,7 @@ tl1_iae: TRAP(do_iae_tl1) tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf) tl1_ill: TRAP(do_ill_tl1) -tl1_privop: BAD_TRAP(0x11) +tl1_privop: BTRAPTL1(0x11) tl1_resv012: BTRAPTL1(0x12) BTRAPTL1(0x13) BTRAPTL1(0x14) BTRAPTL1(0x15) tl1_resv016: BTRAPTL1(0x16) BTRAPTL1(0x17) BTRAPTL1(0x18) BTRAPTL1(0x19) tl1_resv01a: BTRAPTL1(0x1a) BTRAPTL1(0x1b) BTRAPTL1(0x1c) BTRAPTL1(0x1d) @@ -184,38 +191,38 @@ tl1_resv074: BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77) tl1_resv078: BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b) tl1_resv07c: BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f) -tl1_s0n: SPILL_0_NORMAL_TL1 -tl1_s1n: SPILL_1_NORMAL_TL1 -tl1_s2n: SPILL_2_NORMAL_TL1 -tl1_s3n: SPILL_3_NORMAL_TL1 -tl1_s4n: SPILL_4_NORMAL_TL1 -tl1_s5n: SPILL_5_NORMAL_TL1 -tl1_s6n: SPILL_6_NORMAL_TL1 -tl1_s7n: SPILL_7_NORMAL_TL1 -tl1_s0o: SPILL_0_OTHER_TL1 -tl1_s1o: SPILL_1_OTHER_TL1 -tl1_s2o: SPILL_2_OTHER_TL1 -tl1_s3o: SPILL_3_OTHER_TL1 -tl1_s4o: SPILL_4_OTHER_TL1 -tl1_s5o: SPILL_5_OTHER_TL1 -tl1_s6o: SPILL_6_OTHER_TL1 -tl1_s7o: SPILL_7_OTHER_TL1 -tl1_f0n: FILL_0_NORMAL_TL1 -tl1_f1n: FILL_1_NORMAL_TL1 -tl1_f2n: FILL_2_NORMAL_TL1 -tl1_f3n: FILL_3_NORMAL_TL1 -tl1_f4n: FILL_4_NORMAL_TL1 -tl1_f5n: FILL_5_NORMAL_TL1 -tl1_f6n: FILL_6_NORMAL_TL1 -tl1_f7n: FILL_7_NORMAL_TL1 -tl1_f0o: FILL_0_OTHER_TL1 -tl1_f1o: FILL_1_OTHER_TL1 -tl1_f2o: FILL_2_OTHER_TL1 -tl1_f3o: FILL_3_OTHER_TL1 -tl1_f4o: FILL_4_OTHER_TL1 -tl1_f5o: FILL_5_OTHER_TL1 -tl1_f6o: FILL_6_OTHER_TL1 -tl1_f7o: FILL_7_OTHER_TL1 +tl1_s0n: SPILL_0_NORMAL +tl1_s1n: SPILL_1_NORMAL +tl1_s2n: SPILL_2_NORMAL +tl1_s3n: SPILL_3_NORMAL +tl1_s4n: SPILL_4_NORMAL +tl1_s5n: SPILL_5_NORMAL +tl1_s6n: SPILL_6_NORMAL +tl1_s7n: SPILL_7_NORMAL +tl1_s0o: SPILL_0_OTHER +tl1_s1o: SPILL_1_OTHER +tl1_s2o: SPILL_2_OTHER +tl1_s3o: SPILL_3_OTHER +tl1_s4o: SPILL_4_OTHER +tl1_s5o: SPILL_5_OTHER +tl1_s6o: SPILL_6_OTHER +tl1_s7o: SPILL_7_OTHER +tl1_f0n: FILL_0_NORMAL +tl1_f1n: FILL_1_NORMAL +tl1_f2n: FILL_2_NORMAL +tl1_f3n: FILL_3_NORMAL +tl1_f4n: FILL_4_NORMAL +tl1_f5n: FILL_5_NORMAL +tl1_f6n: FILL_6_NORMAL +tl1_f7n: FILL_7_NORMAL +tl1_f0o: FILL_0_OTHER +tl1_f1o: FILL_1_OTHER +tl1_f2o: FILL_2_OTHER +tl1_f3o: FILL_3_OTHER +tl1_f4o: FILL_4_OTHER +tl1_f5o: FILL_5_OTHER +tl1_f6o: FILL_6_OTHER +tl1_f7o: FILL_7_OTHER #if 0 /* Unless we are going to have software trap insns in the kernel code, we diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S --- v2.1.28/linux/arch/sparc64/lib/blockops.S Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/lib/blockops.S Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.1 1996/12/22 07:42:15 davem Exp $ +/* $Id: blockops.S,v 1.3 1997/02/25 20:00:10 jj Exp $ * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -6,16 +6,15 @@ #include - /* Zero out 64 bytes of memory at (buf + offset). */ +/* FIXME: Write this. */ +#define BZERO_TEST + + /* Zero out 256 bytes of memory at (buf + offset). */ #define BLAST_BLOCK(buf, offset) \ - stx %g0, [buf + offset + 0x38]; \ - stx %g0, [buf + offset + 0x30]; \ - stx %g0, [buf + offset + 0x28]; \ - stx %g0, [buf + offset + 0x20]; \ - stx %g0, [buf + offset + 0x18]; \ - stx %g0, [buf + offset + 0x10]; \ - stx %g0, [buf + offset + 0x08]; \ - stx %g0, [buf + offset + 0x00]; + stda %f48, [buf + offset + 0x00] %asi; \ + stda %f48, [buf + offset + 0x40] %asi; \ + stda %f48, [buf + offset + 0x80] %asi; \ + stda %f48, [buf + offset + 0xc0] %asi; \ /* Copy 32 bytes of memory at (src + offset) to * (dst + offset). @@ -33,41 +32,45 @@ .text .align 4 - .globl C_LABEL(bzero_2page), C_LABEL(bzero_1page) -C_LABEL(bzero_2page): + .globl bzero_2page, bzero_1page +bzero_2page: /* %o0 = buf */ - or %o0, %g0, %o1 - or %g0, 0x40, %g2 + mov %o0, %o1 + wr %g0, ASI_BLK_P, %asi + mov 0x10, %g2 + BZERO_TEST 1: - BLAST_BLOCK(%o0, 0x00) - BLAST_BLOCK(%o0, 0x40) - BLAST_BLOCK(%o0, 0x80) - BLAST_BLOCK(%o0, 0xc0) + BLAST_BLOCK(%o0, 0x000) + BLAST_BLOCK(%o0, 0x100) + BLAST_BLOCK(%o0, 0x200) + BLAST_BLOCK(%o0, 0x300) subcc %g2, 1, %g2 bne,pt %icc, 1b - add %o0, 0x100, %o0 + add %o0, 0x400, %o0 retl mov %o1, %o0 -C_LABEL(bzero_1page): +bzero_1page: /* %o0 = buf */ - or %o0, %g0, %o1 - or %g0, 0x20, %g2 + mov %o0, %o1 + wr %g0, ASI_BLK_P, %asi + mov 0x08, %g2 + BZERO_TEST 1: - BLAST_BLOCK(%o0, 0x00) - BLAST_BLOCK(%o0, 0x40) - BLAST_BLOCK(%o0, 0x80) - BLAST_BLOCK(%o0, 0xc0) + BLAST_BLOCK(%o0, 0x000) + BLAST_BLOCK(%o0, 0x100) + BLAST_BLOCK(%o0, 0x200) + BLAST_BLOCK(%o0, 0x300) subcc %g2, 1, %g2 bne,pt %icc, 1b - add %o0, 0x100, %o0 + add %o0, 0x400, %o0 retl mov %o1, %o0 - .globl C_LABEL(__copy_1page) -C_LABEL(__copy_1page): + .globl __copy_1page +__copy_1page: /* %o0 = dst, %o1 = src */ or %g0, 0x10, %g1 1: diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/lib/memset.S linux/arch/sparc64/lib/memset.S --- v2.1.28/linux/arch/sparc64/lib/memset.S Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/lib/memset.S Wed Mar 5 17:04:31 1997 @@ -1,12 +1,36 @@ -/* $Id: memset.S,v 1.1 1996/12/22 07:42:16 davem Exp $ - * arch/sparc64/lib/memset.S: UltraSparc optimized memset and bzero code - * +/* linux/arch/sparc64/lib/memset.S: Sparc optimized memset, bzero and clear_user code + * Copyright (C) 1991,1996 Free Software Foundation * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * Returns 0, if ok, and number of bytes not yet set if exception + * occurs and we were called as clear_user. */ -#include +#include - /* Store 64 bytes at (BASE + OFFSET) using value SOURCE. */ +#define EX(x,y,a,b,z) \ +98: x,y; \ + .section .fixup,z##alloc,z##execinstr; \ + .align 4; \ +99: ba,pt %xcc, 30f; \ + a, b, %o0; \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4 + +#define EXT(start,end,handler,z) \ + .section __ex_table,z##alloc; \ + .align 4; \ + .word start, 0, end, handler; \ + .text; \ + .align 4 + +/* Please don't change these macros, unless you change the logic + * in the .fixup section below as well. + * Store 64 bytes at (BASE + OFFSET) using value SOURCE. */ #define ZERO_BIG_BLOCK(base, offset, source) \ stx source, [base + offset + 0x00]; \ stx source, [base + offset + 0x08]; \ @@ -30,104 +54,139 @@ .text .align 4 - .globl C_LABEL(__bzero), C_LABEL(__memset), C_LABEL(memset) -C_LABEL(__memset): -C_LABEL(memset): - and %o1, 0xff, %g3 - sll %g3, 8, %g2 - or %g3, %g2, %g3 - sll %g3, 16, %g2 - or %g3, %g2, %g3 - sllx %g3, 32, %g2 - or %g3, %g2, %g3 - b 1f - mov %o2, %o1 - -3: - cmp %o2, 3 - be 2f - stb %g3, [%o0] - - cmp %o2, 2 - be 2f - stb %g3, [%o0 + 0x01] - - stb %g3, [%o0 + 0x02] -2: - sub %o2, 4, %o2 - add %o1, %o2, %o1 - b 4f - sub %o0, %o2, %o0 - -C_LABEL(__bzero): - mov %g0, %g3 + .globl __bzero, __memset, + .globl memset, __memset_start, __memset_end +__memset_start: +__memset: +memset: + and %o1, 0xff, %g3 + sll %g3, 8, %g2 + or %g3, %g2, %g3 + sll %g3, 16, %g2 + or %g3, %g2, %g3 + mov %o2, %o1 + sllx %g3, 32, %g2 + ba,pt %xcc, 1f + or %g3, %g2, %g3 +__bzero: + mov %g0, %g3 1: - cmp %o1, 7 - bleu,pnt %icc, 7f - mov %o0, %g1 + cmp %o1, 7 + bleu,pn %xcc, 7f + andcc %o0, 3, %o2 + + be,a,pt %icc, 4f + andcc %o0, 4, %g0 + + cmp %o2, 3 + be,pn %icc, 2f + EX(stb %g3, [%o0], sub %o1, 0,#) + + cmp %o2, 2 + be,pt %icc, 2f + EX(stb %g3, [%o0 + 0x01], sub %o1, 1,#) - andcc %o0, 3, %o2 - bne,pnt %icc, 3b + EX(stb %g3, [%o0 + 0x02], sub %o1, 2,#) +2: + sub %o2, 4, %o2 + sub %o0, %o2, %o0 + add %o1, %o2, %o1 + andcc %o0, 4, %g0 4: - andcc %o0, 4, %g0 + be,a,pt %icc, 2f + andncc %o1, 0x7f, %o3 - be,a,pt %icc, 2f - andcc %o1, 0xffffff80, %o3 ! everything 8 aligned, o1 is len to run - - stw %g3, [%o0] - sub %o1, 4, %o1 - add %o0, 4, %o0 - andcc %o1, 0xffffff80, %o3 ! everything 8 aligned, o1 is len to run + EX(st %g3, [%o0], sub %o1, 0,#) + sub %o1, 4, %o1 + add %o0, 4, %o0 + andncc %o1, 0x7f, %o3 ! Now everything is 8 aligned and o1 is len to run 2: - be 9f - andcc %o1, 0x78, %o2 -4: - ZERO_BIG_BLOCK(%o0, 0x00, %g2) - subcc %o3, 128, %o3 - ZERO_BIG_BLOCK(%o0, 0x40, %g2) - bne,pt %icc, 4b - add %o0, 128, %o0 + be,pn %xcc, 9f + andcc %o1, 0x78, %o2 +10: + ZERO_BIG_BLOCK(%o0, 0x00, %g3) + subcc %o3, 128, %o3 + ZERO_BIG_BLOCK(%o0, 0x40, %g3) +11: + EXT(10b, 11b, 20f,#) + bne,pt %xcc, 10b + add %o0, 128, %o0 - orcc %o2, %g0, %g0 + tst %o2 9: - be,pnt %icc, 6f - andcc %o1, 7, %o1 + be,pn %xcc, 13f + andcc %o1, 7, %o1 +14: + rd %pc, %o4 + srl %o2, 1, %o3 + sub %o4, %o3, %o4 + jmpl %o4 + (13f - 14b), %g0 + add %o0, %o2, %o0 +12: + ZERO_LAST_BLOCKS(%o0, 0x48, %g3) + ZERO_LAST_BLOCKS(%o0, 0x08, %g3) +13: + be,pn %icc, 8f + andcc %o1, 4, %g0 - srl %o2, 1, %o3 - set bzero_table + 64, %o4 - sub %o4, %o3, %o4 - jmp %o4 - add %o0, %o2, %o0 - -bzero_table: - ZERO_LAST_BLOCKS(%o0, 0x48, %g2) - ZERO_LAST_BLOCKS(%o0, 0x08, %g2) - -6: - be,pt %icc, 8f - andcc %o1, 4, %g0 + be,pn %icc, 1f + andcc %o1, 2, %g0 - be,pnt %icc, 1f - andcc %o1, 2, %g0 - - stw %g3, [%o0] - add %o0, 4, %o0 + EX(st %g3, [%o0], and %o1, 7,#) + add %o0, 4, %o0 1: - be,pt %icc, 1f - andcc %o1, 1, %g0 + be,pn %icc, 1f + andcc %o1, 1, %g0 - sth %g3, [%o0] - add %o0, 2, %o0 + EX(sth %g3, [%o0], and %o1, 3,#) + add %o0, 2, %o0 1: - bne,a,pnt %icc, 8f - stb %g3, [%o0] + bne,a,pn %icc, 8f + EX(stb %g3, [%o0], and %o1, 1,#) 8: retl - mov %g1, %o0 - -/* Don't care about alignment here. It is highly - * unprobable and at most two traps may happen - */ + clr %o0 7: - ba,pt %xcc, 6b - orcc %o1, 0, %g0 + be,pn %icc, 13b + orcc %o1, 0, %g0 + + be,pn %icc, 0f +8: + add %o0, 1, %o0 + subcc %o1, 1, %o1 + bne,a,pt %icc, 8b + EX(stb %g3, [%o0 - 1], add %o1, 1,#) +0: + retl + clr %o0 +__memset_end: + + .section .fixup,#alloc,#execinstr + .align 4 +20: + cmp %g2, 8 + bleu,pn %xcc, 1f + and %o1, 0x7f, %o1 + sub %g2, 9, %g2 + add %o3, 64, %o3 +1: + sll %g2, 3, %g2 + add %o3, %o1, %o0 + ba,pt %xcc, 30f + sub %o0, %g2, %o0 +21: + mov 8, %o0 + and %o1, 7, %o1 + sub %o0, %g2, %o0 + sll %o0, 3, %o0 + ba,pt %xcc, 30f + add %o0, %o1, %o0 +30: +/* %o4 is faulting address, %o5 is %pc where fault occured */ + save %sp, -160, %sp + mov %i5, %o0 + mov %i7, %o1 + call lookup_fault + mov %i4, %o2 + ret + restore diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.1.28/linux/arch/sparc64/mm/fault.c Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/mm/fault.c Wed Mar 5 17:04:31 1997 @@ -1,7 +1,8 @@ -/* $Id: fault.c,v 1.2 1996/12/26 18:03:04 davem Exp $ +/* $Id: fault.c,v 1.3 1997/03/04 16:27:02 jj Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0])) @@ -70,6 +71,54 @@ return total; } +void unhandled_fault(unsigned long address, struct task_struct *tsk, + struct pt_regs *regs) +{ + if((unsigned long) address < PAGE_SIZE) { + printk(KERN_ALERT "Unable to handle kernel NULL " + "pointer dereference"); + } else { + printk(KERN_ALERT "Unable to handle kernel paging request " + "at virtual address %016lx\n", (unsigned long)address); + } + printk(KERN_ALERT "tsk->mm->context = %016lx\n", + (unsigned long) tsk->mm->context); + printk(KERN_ALERT "tsk->mm->pgd = %016lx\n", + (unsigned long) tsk->mm->pgd); + die_if_kernel("Oops", regs); +} + +asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, + unsigned long address) +{ + unsigned long g2; + int i; + unsigned insn; + struct pt_regs regs; + + i = search_exception_table (ret_pc, &g2); + switch (i) { + /* load & store will be handled by fixup */ + case 3: return 3; + /* store will be handled by fixup, load will bump out */ + /* for _to_ macros */ + case 1: insn = (unsigned *)pc; if ((insn >> 21) & 1) return 1; break; + /* load will be handled by fixup, store will bump out */ + /* for _from_ macros */ + case 2: insn = (unsigned *)pc; + if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; + break; + default: break; + } + memset (®s, 0, sizeof (regs)); + regs.pc = pc; + regs.npc = pc + 4; + /* FIXME: Should set up regs->tstate? */ + unhandled_fault (address, current, ®s); + /* Not reached */ + return 0; +} + asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write, unsigned long address) { @@ -80,6 +129,7 @@ unsigned long g2; int from_user = !(regs->tstate & TSTATE_PRIV); + lock_kernel (); down(&mm->mmap_sem); vma = find_vma(mm, address); if(!vma) @@ -105,33 +155,7 @@ } handle_mm_fault(vma, address, write); up(&mm->mmap_sem); - return; - - vma = find_vma(mm, address); - if(!vma) - goto bad_area; - if(vma->vm_start <= address) - goto good_area; - if(!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if(expand_stack(vma, address)) - goto bad_area; - /* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: - if(write) { - if(!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } else { - /* Allow reads even for write-only mappings */ - if(!(vma->vm_flags & (VM_READ | VM_EXEC))) - goto bad_area; - } - handle_mm_fault(vma, address, write); - up(&mm->mmap_sem); - return; + goto out; /* * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first.. @@ -142,34 +166,13 @@ g2 = regs->u_regs[UREG_G2]; if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) { - printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address); - printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n", + printk("Exception: PC<%016lx> faddr<%016lx>\n", regs->pc, address); + printk("EX_TABLE: insn<%016lx> fixup<%016lx> g2<%016lx>\n", regs->pc, fixup, g2); regs->pc = fixup; regs->npc = regs->pc + 4; regs->u_regs[UREG_G2] = g2; - return; - } - /* Did we have an exception handler installed? */ - if(current->tss.ex.count == 1) { - if(from_user) { - printk("Yieee, exception signalled from user mode.\n"); - } else { - /* Set pc to %g1, set %g1 to -EFAULT and %g2 to - * the faulting address so we can cleanup. - */ - printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address); - printk("EX: count<%d> pc<%08lx> expc<%08lx> address<%08lx>\n", - (int) current->tss.ex.count, current->tss.ex.pc, - current->tss.ex.expc, current->tss.ex.address); - current->tss.ex.count = 0; - regs->pc = current->tss.ex.expc; - regs->npc = regs->pc + 4; - regs->u_regs[UREG_G1] = -EFAULT; - regs->u_regs[UREG_G2] = address - current->tss.ex.address; - regs->u_regs[UREG_G3] = current->tss.ex.pc; - return; - } + goto out; } if(from_user) { #if 0 @@ -179,18 +182,9 @@ tsk->tss.sig_address = address; tsk->tss.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, tsk, 1); - return; + goto out; } - if((unsigned long) address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL " - "pointer dereference"); - } else { - printk(KERN_ALERT "Unable to handle kernel paging request " - "at virtual address %08lx\n", address); - } - printk(KERN_ALERT "tsk->mm->context = %08lx\n", - (unsigned long) tsk->mm->context); - printk(KERN_ALERT "tsk->mm->pgd = %08lx\n", - (unsigned long) tsk->mm->pgd); - die_if_kernel("Oops", regs); + unhandled_fault (address, tsk, regs); +out: + unlock_kernel(); } diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/Makefile linux/arch/sparc64/prom/Makefile --- v2.1.28/linux/arch/sparc64/prom/Makefile Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/prom/Makefile Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 1996/12/27 08:49:10 jj Exp $ +# $Id: Makefile,v 1.2 1997/02/25 12:40:25 jj Exp $ # Makefile for the Sun Boot PROM interface library under # Linux. # @@ -8,8 +8,8 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -OBJS = bootstr.o devops.o init.o memory.o misc.o mp.o \ - ranges.o tree.o console.o printf.o +OBJS = bootstr.o devops.o init.o memory.o misc.o \ + ranges.o tree.o console.o printf.o p1275.o all: promlib.a diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/bootstr.c linux/arch/sparc64/prom/bootstr.c --- v2.1.28/linux/arch/sparc64/prom/bootstr.c Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/prom/bootstr.c Wed Mar 5 17:04:31 1997 @@ -1,11 +1,10 @@ -/* $Id: bootstr.c,v 1.1 1996/12/27 08:49:10 jj Exp $ +/* $Id: bootstr.c,v 1.3 1997/03/04 16:27:06 jj Exp $ * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright(C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include #include #include @@ -18,7 +17,7 @@ { /* This check saves us from a panic when bootfd patches args. */ if (fetched) return barg_buf; - prom_getstring(prom_finddevice ("/chosen"), "bootargs", barg_buf, BARG_LEN); + prom_getstring(prom_chosen_node, "bootargs", barg_buf, BARG_LEN); fetched = 1; return barg_buf; } diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/console.c linux/arch/sparc64/prom/console.c --- v2.1.28/linux/arch/sparc64/prom/console.c Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/prom/console.c Wed Mar 5 17:04:31 1997 @@ -1,12 +1,11 @@ -/* $Id: console.c,v 1.1 1996/12/27 08:49:11 jj Exp $ +/* $Id: console.c,v 1.4 1997/03/04 16:27:07 jj Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include #include #include #include @@ -25,9 +24,9 @@ { char inc; - if ((*prom_command)("read", P1275_ARG(1,P1275_ARG_IN_BUF)| - P1275_INOUT(3,1), - prom_stdin, &inc, P1275_SIZE(1)) == 1) + if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)| + P1275_INOUT(3,1), + prom_stdin, &inc, P1275_SIZE(1)) == 1) return inc; else return -1; @@ -42,9 +41,9 @@ char outc; outc = c; - if ((*prom_command)("write", P1275_ARG(1,P1275_ARG_IN_BUF)| - P1275_INOUT(3,1), - prom_stdin, &inc, P1275_SIZE(1)) == 1) + if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| + P1275_INOUT(3,1), + prom_stdin, &outc, P1275_SIZE(1)) == 1) return 0; else return -1; @@ -73,7 +72,6 @@ { int st_p; char propb[64]; - char *p; st_p = prom_inst2pkg(prom_stdin); if(prom_node_has_property(st_p, "keyboard")) @@ -100,7 +98,6 @@ { int st_p; char propb[64]; - char *p; int propl; st_p = prom_inst2pkg(prom_stdout); diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/devops.c linux/arch/sparc64/prom/devops.c --- v2.1.28/linux/arch/sparc64/prom/devops.c Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/prom/devops.c Wed Mar 5 17:04:31 1997 @@ -1,8 +1,8 @@ -/* $Id: devops.c,v 1.1 1996/12/27 08:49:11 jj Exp $ +/* $Id: devops.c,v 1.2 1997/02/25 12:40:20 jj Exp $ * devops.c: Device operations using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include #include @@ -18,16 +18,16 @@ int prom_devopen(char *dstr) { - return (*prom_command)("open", P1275_ARG(0,P1275_ARG_IN_STRING)| - P1275_INOUT(1,1), - dstr); + return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)| + P1275_INOUT(1,1), + dstr); } /* Close the device described by device handle 'dhandle'. */ int prom_devclose(int dhandle) { - (*prom_command)("close", P1275_INOUT(1,0), dhandle); + p1275_cmd ("close", P1275_INOUT(1,0), dhandle); return 0; } @@ -37,5 +37,5 @@ void prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) { - (*prom_command)("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo); + p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo); } diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/init.c linux/arch/sparc64/prom/init.c --- v2.1.28/linux/arch/sparc64/prom/init.c Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/prom/init.c Wed Mar 5 17:04:31 1997 @@ -1,14 +1,14 @@ -/* $Id: init.c,v 1.1 1996/12/27 08:49:11 jj Exp $ +/* $Id: init.c,v 1.4 1997/03/04 16:27:09 jj Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include #include #include +#include #include #include @@ -19,7 +19,7 @@ /* The root node of the prom device tree. */ int prom_root_node; int prom_stdin, prom_stdout; -(long)(*prom_command)(char *, long, ...); +int prom_chosen_node; /* You must call prom_init() before you attempt to use any of the * routines in the prom library. It returns 0 on success, 1 on @@ -43,18 +43,18 @@ if((prom_root_node == 0) || (prom_root_node == -1)) prom_halt(); - node = prom_finddevice("/chosen"); - if (!node || node == -1) + prom_chosen_node = prom_finddevice("/chosen"); + if (!prom_chosen_node || prom_chosen_node == -1) prom_halt(); - prom_stdin = prom_getint (node, "stdin"); - prom_stdout = prom_getint (node, "stdout"); + prom_stdin = prom_getint (prom_chosen_node, "stdin"); + prom_stdout = prom_getint (prom_chosen_node, "stdout"); node = prom_finddevice("/openprom"); if (!node || node == -1) prom_halt(); - prom_getstring (openprom_node, "version", buffer, sizeof (buffer)); + prom_getstring (node, "version", buffer, sizeof (buffer)); if (strncmp (buffer, "OPB ", 4) || buffer[5] != '.' || buffer[7] != '.') { prom_printf ("Strange OPB version.\n"); prom_halt (); diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/k1275d.c linux/arch/sparc64/prom/k1275d.c --- v2.1.28/linux/arch/sparc64/prom/k1275d.c Sun Jan 26 02:07:10 1997 +++ linux/arch/sparc64/prom/k1275d.c Wed Mar 5 17:04:31 1997 @@ -1,123 +0,0 @@ -/* $Id: k1275d.c,v 1.2 1997/01/02 14:14:44 jj Exp $ - * k1275d.c: Sun IEEE 1275 PROM kernel daemon - * - * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -#include -#include -#include - -#include -#include - -#define p1275sect __attribute__ ((__section__ (".p1275"))) - -static void (*prom_cif_handler)(long *) p1275sect; -static long prom_cif_stack; -static void (*prom_do_it)(void); -static long prom_args [23] p1275sect; -static char prom_buffer [4096] p1275sect; - -static void prom_doit (void) p1275sect; - -static void prom_doit (void) -{ - /* FIXME: The PROM stack is grossly misaligned. - * It needs some special way of handling spills/fills. - * Either using %otherwin or doing flushw; wrpr somevalue, %wstate - * should be done here to make difference between PROM stack - * saving (32bit, misaligned stack) and kernel fill/spill). - */ - __asm__ __volatile__ (" - save %%sp, -0xc0, %%sp; - mov %%sp, %%l1; - mov %0, %%sp; - call %1; - mov %0, %%o0; - mov %%l1, %%sp; - restore; - " : : "r" (prom_cif_stack), "r" (prom_cif_handler)); -} - -long prom_handle_command(char *service, long fmt, ...) -{ - char *p = prom_buffer; - unsigned long flags; - int nargs, nrets, i; - va_list list; - long attrs, x; - - save_and_cli(flags); - prom_args[0] = p; /* service */ - strcpy (p, function); - p = strchr (p, 0) + 1; - prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ - prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ - attrs = (fmt & (~0xff)); - va_start(list, fmt); - for (i = 0; i < nargs; i++, attrs >>= 3) { - switch (attrs & 0x7) { - case P1275_ARG_NUMBER: - prom_args[i + 3] = va_arg(list, long); break; - case P1275_ARG_IN_STRING: - strcpy (p, va_arg(list, char *)); - prom_args[i + 3] = p; - p = strchr (p, 0) + 1; - break; - case P1275_ARG_OUT_BUF: - va_arg(list, char *); - prom_args[i + 3] = p; - x = va_arg(list, long); - i++; attrs >>= 3; - p += (int)x; - prom_args[i + 3] = x; - break; - case P1275_ARG_OUT_32B: - va_arg(list, char *); - prom_args[i + 3] = p; - p += 32; - break; - case P1275_ARG_IN_FUNCTION: - /* FIXME: This should make a function in our <4G - * section, which will call the argument, - * so that PROM can call it. - */ - prom_args[i + 3] = va_arg(list, long); break; - } - } - va_end(list); - (*prom_do_it)(); - attrs = fmt & (~0xff); - va_start(list, fmt); - for (i = 0; i < nargs; i++, attrs >>= 3) { - switch (attrs & 0x7) { - case P1275_ARG_NUMBER: - case P1275_ARG_IN_STRING: - case P1275_ARG_IN_FUNCTION: - break; - case P1275_ARG_OUT_BUF: - p = va_arg(list, char *); - x = va_arg(list, long); - memcpy (p, (char *)prom_args[i + 3], (int)x); - i++; attrs >>= 3; - break; - case P1275_ARG_OUT_32B: - p = va_arg(list, char *); - memcpy (p, (char *)prom_args[i + 3], 32); - break; - } - } - va_end(list); - x = prom_args [nargs + 3]; - restore_flags(flags); - return x; -} - -void prom_cif_init(void *cif_handler, void *cif_stack) -{ - prom_cif_handler = (void (*)(long *))cif_handler; - prom_cif_stack = cif_stack; - prom_command = prom_handle_command; - prom_do_it = prom_doit; -} diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/memory.c linux/arch/sparc64/prom/memory.c --- v2.1.28/linux/arch/sparc64/prom/memory.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/prom/memory.c Wed Mar 5 17:04:31 1997 @@ -0,0 +1,152 @@ +/* $Id: memory.c,v 1.3 1997/03/04 16:27:10 jj Exp $ + * memory.c: Prom routine for acquiring various bits of information + * about RAM on the machine, both virtual and physical. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include + +#include +#include + +/* This routine, for consistency, returns the ram parameters in the + * V0 prom memory descriptor format. I choose this format because I + * think it was the easiest to work with. I feel the religious + * arguments now... ;) Also, I return the linked lists sorted to + * prevent paging_init() upset stomach as I have not yet written + * the pepto-bismol kernel module yet. + */ + +struct linux_prom64_registers prom_reg_memlist[64]; +struct linux_prom64_registers prom_reg_tmp[64]; + +struct linux_mlist_p1275 prom_phys_total[64]; +struct linux_mlist_p1275 prom_prom_taken[64]; +struct linux_mlist_p1275 prom_phys_avail[64]; + +struct linux_mlist_p1275 *prom_ptot_ptr = prom_phys_total; +struct linux_mlist_p1275 *prom_ptak_ptr = prom_prom_taken; +struct linux_mlist_p1275 *prom_pavl_ptr = prom_phys_avail; + +struct linux_mem_p1275 prom_memlist; + + +/* Internal Prom library routine to sort a linux_mlist_p1275 memory + * list. Used below in initialization. + */ +__initfunc(static void +prom_sortmemlist(struct linux_mlist_p1275 *thislist)) +{ + int swapi = 0; + int i, mitr, tmpsize; + unsigned long tmpaddr; + unsigned long lowest; + + for(i=0; thislist[i].theres_more != 0; i++) { + lowest = thislist[i].start_adr; + for(mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++) + if(thislist[mitr].start_adr < lowest) { + lowest = thislist[mitr].start_adr; + swapi = mitr; + } + if(lowest == thislist[i].start_adr) continue; + tmpaddr = thislist[swapi].start_adr; + tmpsize = thislist[swapi].num_bytes; + for(mitr = swapi; mitr > i; mitr--) { + thislist[mitr].start_adr = thislist[mitr-1].start_adr; + thislist[mitr].num_bytes = thislist[mitr-1].num_bytes; + } + thislist[i].start_adr = tmpaddr; + thislist[i].num_bytes = tmpsize; + } +} + +/* Initialize the memory lists based upon the prom version. */ +__initfunc(void prom_meminit(void)) +{ + int node = 0; + unsigned int iter, num_regs; + + node = prom_finddevice("/memory"); + num_regs = prom_getproperty(node, "available", + (char *) prom_reg_memlist, + sizeof(prom_reg_memlist)); + num_regs = (num_regs/sizeof(struct linux_prom64_registers)); + for(iter=0; iter #include #include #include @@ -17,8 +16,8 @@ void prom_reboot(char *bcommand) { - (*prom_command)("boot", P1275_ARG(0,P1275_ARG_IN_STRING)| - P1275_INOUT(1,0), bcommand); + p1275_cmd ("boot", P1275_ARG(0,P1275_ARG_IN_STRING)| + P1275_INOUT(1,0), bcommand); } /* Forth evaluate the expression contained in 'fstring'. */ @@ -27,8 +26,8 @@ { if(!fstring || fstring[0] == 0) return; - (*prom_command)("interpret", P1275_ARG(0,P1275_ARG_IN_STRING)| - P1275_INOUT(1,1), fstring); + p1275_cmd ("interpret", P1275_ARG(0,P1275_ARG_IN_STRING)| + P1275_INOUT(1,1), fstring); } /* We want to do this more nicely some day. */ @@ -56,7 +55,7 @@ #endif install_obp_ticker(); save_flags(flags); cli(); - (*prom_command)("enter", P1275_INOUT(0,0)); + p1275_cmd ("enter", P1275_INOUT(0,0)); restore_flags(flags); install_linux_ticker(); #ifdef CONFIG_SUN_CONSOLE @@ -71,18 +70,16 @@ void prom_halt(void) { - (*prom_command)("exit", P1275_INOUT(0,0)); + p1275_cmd ("exit", P1275_INOUT(0,0)); } -typedef void (*sfunc_t)(void); - /* Set prom sync handler to call function 'funcp'. */ void -prom_setsync(sfunc_t funcp) +prom_setsync(sync_func_t funcp) { if(!funcp) return; - (*prom_command)("set-callback", P1275_ARG(0,P1275_IN_FUNCTION)| - P1275_INOUT(1,1), funcp); + p1275_cmd ("set-callback", P1275_ARG(0,P1275_ARG_IN_FUNCTION)| + P1275_INOUT(1,1), funcp); } /* Get the idprom and stuff it into buffer 'idbuf'. Returns the diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c --- v2.1.28/linux/arch/sparc64/prom/p1275.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/prom/p1275.c Wed Mar 5 17:04:31 1997 @@ -0,0 +1,149 @@ +/* $Id: p1275.c,v 1.4 1997/03/04 16:27:12 jj Exp $ + * p1275.c: Sun IEEE 1275 PROM low level interface routines + * + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include +#include + +#include +#include +#include +#include + +/* If you change layout of this structure, please change the prom_doit + function below as well. */ +typedef struct { + unsigned prom_doit_code [16]; + void (*prom_cif_handler)(long *); + unsigned long prom_cif_stack; + unsigned long prom_args [23]; + char prom_buffer [7928]; +} at0x8000; + +static void (*prom_do_it)(void); + +void prom_cif_interface (void) __attribute__ ((__section__ (".p1275"))); + +/* At most 16 insns (including the retl; nop; afterwards) */ +void prom_cif_interface (void) +{ + __asm__ __volatile__ (" + sethi %hi(0x8000), %o0 + ldx [%o0 + 0x048], %o1 ! prom_cif_stack + save %o1, -0xc0, %sp + ldx [%i0 + 0x040], %l2 ! prom_cif_handler + mov %g4, %l0 + mov %g6, %l1 + call %l2 + or %i0, 0x050, %o0 ! prom_args + mov %l0, %g4 + mov %l1, %g6 + restore + "); +} + +long p1275_cmd (char *service, long fmt, ...) +{ + char *p, *q; + unsigned long flags; + int nargs, nrets, i; + va_list list; + long attrs, x; + long ctx = 0; + at0x8000 *low = (at0x8000 *)(0x8000); + + p = low->prom_buffer; + save_and_cli(flags); + ctx = spitfire_get_primary_context (); + if (ctx) { + flushw_user (); + spitfire_set_primary_context (0); + } + low->prom_args[0] = (unsigned long)p; /* service */ + strcpy (p, service); + p = strchr (p, 0) + 1; + low->prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ + low->prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ + attrs = (fmt & (~0xff)); + va_start(list, fmt); + for (i = 0; i < nargs; i++, attrs >>= 3) { + switch (attrs & 0x7) { + case P1275_ARG_NUMBER: + low->prom_args[i + 3] = va_arg(list, long); break; + case P1275_ARG_IN_STRING: + strcpy (p, va_arg(list, char *)); + low->prom_args[i + 3] = (unsigned long)p; + p = strchr (p, 0) + 1; + break; + case P1275_ARG_OUT_BUF: + (void) va_arg(list, char *); + low->prom_args[i + 3] = (unsigned long)p; + x = va_arg(list, long); + i++; attrs >>= 3; + p += (int)x; + low->prom_args[i + 3] = x; + break; + case P1275_ARG_IN_BUF: + q = va_arg(list, char *); + low->prom_args[i + 3] = (unsigned long)p; + x = va_arg(list, long); + i++; attrs >>= 3; + p += (int)x; + memcpy (p, q, (int)x); + low->prom_args[i + 3] = x; + break; + case P1275_ARG_OUT_32B: + (void) va_arg(list, char *); + low->prom_args[i + 3] = (unsigned long)p; + p += 32; + break; + case P1275_ARG_IN_FUNCTION: + /* FIXME: This should make a function in our <4G + * section, which will call the argument, + * so that PROM can call it. + */ + low->prom_args[i + 3] = va_arg(list, long); break; + } + } + va_end(list); + (*prom_do_it)(); + attrs = fmt & (~0xff); + va_start(list, fmt); + for (i = 0; i < nargs; i++, attrs >>= 3) { + switch (attrs & 0x7) { + case P1275_ARG_NUMBER: + case P1275_ARG_IN_STRING: + case P1275_ARG_IN_FUNCTION: + case P1275_ARG_IN_BUF: + break; + case P1275_ARG_OUT_BUF: + p = va_arg(list, char *); + x = va_arg(list, long); + memcpy (p, (char *)(low->prom_args[i + 3]), (int)x); + i++; attrs >>= 3; + break; + case P1275_ARG_OUT_32B: + p = va_arg(list, char *); + memcpy (p, (char *)(low->prom_args[i + 3]), 32); + break; + } + } + va_end(list); + x = low->prom_args [nargs + 3]; + if (ctx) + spitfire_set_primary_context (ctx); + restore_flags(flags); + return x; +} + +void prom_cif_init(void *cif_handler, void *cif_stack) +{ + at0x8000 *low = (at0x8000 *)(0x8000); + + low->prom_cif_handler = (void (*)(long *))cif_handler; + low->prom_cif_stack = (unsigned long)cif_stack; + prom_do_it = (void (*)(void))(0x8000); +} diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/printf.c linux/arch/sparc64/prom/printf.c --- v2.1.28/linux/arch/sparc64/prom/printf.c Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/prom/printf.c Wed Mar 5 17:04:31 1997 @@ -1,4 +1,4 @@ -/* $Id: printf.c,v 1.1 1996/12/27 08:49:13 jj Exp $ +/* $Id: printf.c,v 1.2 1997/03/04 16:27:13 jj Exp $ * printf.c: Internal prom library printf facility. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -8,7 +8,6 @@ * about or use it! It's simple and smelly anyway.... */ -#include #include #include diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/ranges.c linux/arch/sparc64/prom/ranges.c --- v2.1.28/linux/arch/sparc64/prom/ranges.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/prom/ranges.c Wed Mar 5 17:04:31 1997 @@ -0,0 +1,107 @@ +/* $Id: ranges.c,v 1.1 1997/02/25 12:40:28 jj Exp $ + * ranges.c: Handle ranges in newer proms for obio/sbus. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include +#include +#include +#include + +struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX]; +int num_obio_ranges; + +/* Adjust register values based upon the ranges parameters. */ +inline void +prom_adjust_regs(struct linux_prom_registers *regp, int nregs, + struct linux_prom_ranges *rangep, int nranges) +{ + int regc, rngc; + + for(regc=0; regc < nregs; regc++) { + for(rngc=0; rngc < nranges; rngc++) + if(regp[regc].which_io == rangep[rngc].ot_child_space) + break; /* Fount it */ + if(rngc==nranges) /* oops */ + prom_printf("adjust_regs: Could not find range with matching bus type...\n"); + regp[regc].which_io = rangep[rngc].ot_parent_space; + regp[regc].phys_addr += rangep[rngc].ot_parent_base; + } +} + +inline void +prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1, + struct linux_prom_ranges *ranges2, int nranges2) +{ + int rng1c, rng2c; + + for(rng1c=0; rng1c < nranges1; rng1c++) { + for(rng2c=0; rng2c < nranges2; rng2c++) + if(ranges1[rng1c].ot_child_space == + ranges2[rng2c].ot_child_space) break; + if(rng2c == nranges2) /* oops */ + prom_printf("adjust_ranges: Could not find matching bus type...\n"); + ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space; + ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base; + } +} + +/* Apply probed sbus ranges to registers passed, if no ranges return. */ +void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers *regs, + int nregs, struct linux_sbus_device *sdev) +{ + if(sbus->num_sbus_ranges) { + if(sdev && (sdev->ranges_applied == 0)) { + sdev->ranges_applied = 1; + prom_adjust_regs(regs, nregs, sbus->sbus_ranges, + sbus->num_sbus_ranges); + } + } +} + +__initfunc(void prom_ranges_init(void)) +{ +} + +__initfunc(void prom_sbus_ranges_init(int parentnd, struct linux_sbus *sbus)) +{ + int success; + + sbus->num_sbus_ranges = 0; + success = prom_getproperty(sbus->prom_node, "ranges", + (char *) sbus->sbus_ranges, + sizeof (sbus->sbus_ranges)); + if (success != -1) + sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); +} + +void +prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs) +{ + int success; + int num_ranges; + struct linux_prom_ranges ranges[PROMREG_MAX]; + + success = prom_getproperty(node, "ranges", + (char *) ranges, + sizeof (ranges)); + if (success != -1) { + num_ranges = (success/sizeof(struct linux_prom_ranges)); + if (parent) { + struct linux_prom_ranges parent_ranges[PROMREG_MAX]; + int num_parent_ranges; + + success = prom_getproperty(parent, "ranges", + (char *) parent_ranges, + sizeof (parent_ranges)); + if (success != -1) { + num_parent_ranges = (success/sizeof(struct linux_prom_ranges)); + prom_adjust_ranges (ranges, num_ranges, parent_ranges, num_parent_ranges); + } + } + prom_adjust_regs(regs, nregs, ranges, num_ranges); + } +} diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/prom/tree.c linux/arch/sparc64/prom/tree.c --- v2.1.28/linux/arch/sparc64/prom/tree.c Mon Dec 30 01:59:59 1996 +++ linux/arch/sparc64/prom/tree.c Wed Mar 5 17:04:31 1997 @@ -1,12 +1,11 @@ -/* $Id: tree.c,v 1.1 1996/12/27 08:49:13 jj Exp $ +/* $Id: tree.c,v 1.4 1997/03/04 16:27:14 jj Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include #include #include #include @@ -24,7 +23,18 @@ long cnode; if(node == -1) return 0; - cnode = (*prom_command)("child", P1275_INOUT(1, 1), node); + cnode = p1275_cmd ("child", P1275_INOUT(1, 1), node); + if(cnode == -1) return 0; + return (int)cnode; +} + +__inline__ int +prom_getparent(int node) +{ + long cnode; + + if(node == -1) return 0; + cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node); if(cnode == -1) return 0; return (int)cnode; } @@ -38,8 +48,8 @@ long sibnode; if(node == -1) return 0; - sibnode = (*prom_command)("peer", P1275_INOUT(1, 1), node); - if(cnode == -1) return 0; + sibnode = p1275_cmd ("peer", P1275_INOUT(1, 1), node); + if(sibnode == -1) return 0; return (int)sibnode; } @@ -50,10 +60,10 @@ prom_getproplen(int node, char *prop) { if((!node) || (!prop)) return -1; - return (*prom_command)("getproplen", - P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_INOUT(2, 1), - node, prop); + return p1275_cmd ("getproplen", + P1275_ARG(1,P1275_ARG_IN_STRING)| + P1275_INOUT(2, 1), + node, prop); } /* Acquire a property 'prop' at node 'node' and place it in @@ -70,11 +80,11 @@ return -1; else { /* Ok, things seem all right. */ - return (*prom_command)("getprop", - P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_ARG(2,P1275_ARG_OUT_BUF)| - P1275_INOUT(4, 1), - node, prop, buffer, P1275_SIZE(plen)); + return p1275_cmd ("getprop", + P1275_ARG(1,P1275_ARG_IN_STRING)| + P1275_ARG(2,P1275_ARG_OUT_BUF)| + P1275_INOUT(4, 1), + node, prop, buffer, P1275_SIZE(plen)); } } @@ -172,18 +182,35 @@ int prom_getname (int node, char *buffer, int len) { - int i; - struct linux_prom_registers reg[PROMREG_MAX]; + int i, sbus = 0; + struct linux_prom_registers *reg; + struct linux_prom64_registers reg64[PROMREG_MAX]; + for (sbus = prom_getparent (node); sbus; sbus = prom_getparent (sbus)) { + i = prom_getproperty (sbus, "name", buffer, len); + if (i > 0) { + buffer [i] = 0; + if (!strcmp (buffer, "sbus")) + break; + } + } i = prom_getproperty (node, "name", buffer, len); - if (i <= 0) return -1; + if (i <= 0) { + buffer [0] = 0; + return -1; + } buffer [i] = 0; len -= i; - i = prom_getproperty (node, "reg", (char *)reg, sizeof (reg)); + i = prom_getproperty (node, "reg", (char *)reg64, sizeof (reg64)); if (i <= 0) return 0; - if (len < 11) return -1; + if (len < 16) return -1; buffer = strchr (buffer, 0); - sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr); + if (sbus) { + reg = (struct linux_prom_registers *)reg64; + sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr); + } else { + sprintf (buffer, "@%x,%x", (unsigned int)(reg64[0].phys_addr >> 36), (unsigned int)(reg64[0].phys_addr)); + } return 0; } @@ -193,11 +220,11 @@ __inline__ char * prom_firstprop(int node, char *buffer) { - if(node == -1) return ""; *buffer = 0; - (*prom_command)("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)| - P1275_INOUT(3, 0), - node, (char *) 0x0, buffer); + if(node == -1) return buffer; + p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)| + P1275_INOUT(3, 0), + node, (char *) 0x0, buffer); return buffer; } @@ -210,14 +237,18 @@ { char buf[32]; - if(node == -1) return ""; - *buffer = 0; - (*prom_command)("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)| + if(node == -1) { + *buffer = 0; + return buffer; + } + if (oprop == buffer) { + strcpy (buf, oprop); + oprop = buf; + } + p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)| P1275_ARG(2,P1275_ARG_OUT_32B)| P1275_INOUT(3, 0), - node, oprop, (oprop == buffer) ? - buf : buffer); - if (oprop == buffer) strcpy (buffer, buf); + node, oprop, buffer); return buffer; } @@ -225,42 +256,35 @@ prom_finddevice(char *name) { if(!name) return 0; - *buffer = 0; - (*prom_command)("finddevice", P1275_ARG(0,P1275_ARG_IN_STRING)| - P1275_INOUT(1, 1), - name); - return buffer; + return p1275_cmd ("finddevice", P1275_ARG(0,P1275_ARG_IN_STRING)| + P1275_INOUT(1, 1), + name); } -int -prom_node_has_property(int node, char *prop) +int prom_node_has_property(int node, char *prop) { - char buf[32]; - char *current_property = buf; - + char buf [32]; + *buf = 0; do { - current_property = prom_nextprop(node, current_property, buf); - if(!strcmp(current_property, prop)) + prom_nextprop(node, buf, buf); + if(!strcmp(buf, prop)) return 1; - } while (*current_property); + } while (*buf); return 0; } - + /* Set property 'pname' at node 'node' to value 'value' which has a length * of 'size' bytes. Return the number of bytes the prom accepted. */ int prom_setprop(int node, char *pname, char *value, int size) { - unsigned long flags; - int ret; - if(size == 0) return 0; if((pname == 0) || (value == 0)) return 0; - return (*prom_command)("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_ARG(2,P1275_ARG_OUT_BUF)| + return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| + P1275_ARG(2,P1275_ARG_IN_BUF)| P1275_INOUT(4, 1), node, pname, value, P1275_SIZE(size)); } @@ -270,7 +294,7 @@ { int node; - node = (*prom_command)("instance-to-package", P1275_INOUT(1, 1), inst); + node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst); if (node == -1) return 0; return node; } diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds --- v2.1.28/linux/arch/sparc64/vmlinux.lds Sun Jan 26 02:07:10 1997 +++ linux/arch/sparc64/vmlinux.lds Wed Mar 5 17:04:31 1997 @@ -2,10 +2,11 @@ OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", "elf64-sparc") OUTPUT_ARCH(sparc:v9) ENTRY(_start) + SECTIONS { - . = 0x100200 + SIZEOF_HEADERS; - .text 0xfffff80000008000 : + . = 0x4000; + .text 0xfffff80000004000 : { *(.text) *(.gnu.warning) @@ -35,6 +36,12 @@ .data.init : { *(.data.init) } . = ALIGN(8192); __init_end = .; + __p1275_loc = .; + .p1275 : + { + *(.p1275) + . = ALIGN(8192); + } __bss_start = .; .sbss : { *(.sbss) *(.scommon) } .bss : @@ -45,12 +52,6 @@ } _end = . ; PROVIDE (end = .); - __p1275_loc = .; - .p1275 0x0000000000008000 : - { - *(.p1275) - } - __p1275_end = .; /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } diff -u --recursive --new-file v2.1.28/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.28/linux/drivers/block/floppy.c Tue Jan 28 00:02:45 1997 +++ linux/drivers/block/floppy.c Tue Mar 4 13:58:37 1997 @@ -3924,10 +3924,12 @@ DPRINT("Read linux/drivers/block/README.fd\n"); } +static int have_no_fdc= -EIO; + int floppy_init(void) { int i,unit,drive; - int have_no_fdc= -EIO; + raw_cmd = 0; @@ -4237,6 +4239,8 @@ void floppy_eject(void) { int dummy; + if(have_no_fdc) + return; floppy_grab_irq_and_dma(); lock_fdc(MAXTIMEOUT,0); dummy=fd_eject(0); diff -u --recursive --new-file v2.1.28/linux/drivers/char/README.stallion linux/drivers/char/README.stallion --- v2.1.28/linux/drivers/char/README.stallion Wed Apr 24 02:48:04 1996 +++ linux/drivers/char/README.stallion Wed Dec 31 16:00:00 1969 @@ -1,283 +0,0 @@ - -Stallion Multiport Serial Drivers ---------------------------------- - -Version: 1.1.3 -Date: 23APR96 -Author: Greg Ungerer (gerg@stallion.oz.au) - - -1. INTRODUCTION - -There are two drivers that work with the different families of Stallion -multiport serial boards. One is for the Stallion smart boards - that is -EasyIO and EasyConnection 8/32, the other for the true Stallion intelligent -multiport boards - EasyConnection 8/64, ONboard, Brumby and Stallion. - -If you are using any of the Stallion intelligent multiport boards (Brumby, -ONboard, Stallion, EasyConnection 8/64) with Linux you will need to get the -driver utility package. This package is available at most of the Linux -archive sites (and on CD's that contain these archives). The file will be -called stallion-X.X.X.tar.gz where X.X.X will be the version number. In -particular this package contains the board embedded executable images that -are required for these boards. It also contains the downloader program. -These boards cannot be used without this. - -The following ftp sites (and their mirrors) definitely have the stallion -driver utility package: ftp.stallion.com, tsx-11.mit.edu, sunsite.unc.edu. - -ftp.stallion.com:/drivers/ata5/Linux/stallion-1.1.2.tar.gz -tsx-11.mit.edu:/pub/linux/BETA/serial/stallion/stallion-1.1.2.tar.gz -sunsite.unc.edu:/pub/Linux/kernel/patches/serial/stallion-1.1.2.tar.gz - -If you are using the EasyIO or EasyConnection 8/32 boards then you don't -need this package. Although it does have a handy script to create the -/dev device nodes for these boards, and a serial stats display program. - -If you require DIP switch settings, EISA/MCA configuration files, or any -other information related to Stallion boards then have a look at Stallion's -web pages at http://www.stallion.com. - - - -2. INSTALLATION - -The drivers can be used as loadable modules or compiled into the kernel. -You can choose which when doing a "make config" on the kernel. - -All ISA, EISA and MCA boards that you want to use need to be entered into -the driver(s) configuration structures. All PCI boards will be automatically -detected when you load the driver - so they do not need to be entered into -the driver(s) configuration structure. (Note that kernel PCI BIOS32 support -is required to use PCI boards.) - -Entering ISA, EISA and MCA boards into the driver(s) configuration structure -involves editing the driver(s) source file. It's pretty easy if you follow -the instructions below. Both drivers can support up to 4 boards. The smart -card driver (the stallion.c driver) supports any combination of EasyIO and -EasyConnection 8/32 boards (up to a total of 4). The intelligent driver -supports any combination of ONboards, Brumbys, Stallions and EasyConnection -8/64 boards (up to a total of 4). - -To set up the driver(s) for the boards that you want to use you need to -edit the appropriate driver file and add configuration entries. - -If using EasyIO or EasyConnection 8/32 ISA or MCA boards, do: - vi stallion.c - - find the definition of the stl_brdconf array (of structures) - near the top of the file - - modify this to match the boards you are going to install - (the comments before this structure should help) - - save and exit - -If using ONboard, Brumby, Stallion or EasyConnection 8/64 boards then do: - vi istallion.c - - find the definition of the stli_brdconf array (of structures) - near the top of the file - - modify this to match the boards you are going to install - (the comments before this structure should help) - - save and exit - -Once you have set up the board configurations then you are ready to build -the kernel or modules. - -When the new kernel is booted, or the loadable module loaded then the -driver will emit some kernel trace messages about whether the configured -boards where detected or not. Depending on how your system logger is set -up these may come out on the console, or just be logged to -/var/adm/messages. You should check the messages to confirm that all is well. - - -2.1 SHARING INTERRUPTS - -It is possible to share interrupts between multiple EasyIO and -EasyConnection 8/32 boards in an EISA system. To do this you will need to -do a couple of things: - -1. When entering the board resources into the stallion.c file you need to - mark the boards as using level triggered interrupts. Do this by replacing - the "0" entry at field position 6 (the last field) in the board - configuration structure with a "1". (This is the structure that defines - the board type, I/O locations, etc. for each board). All boards that are - sharing an interrupt must be set this way, and each board should have the - same interrupt number specified here as well. Now build the module or - kernel as you would normally. - -2. When physically installing the boards into the system you must enter - the system EISA configuration utility. You will need to install the EISA - configuration files for *all* the EasyIO and EasyConnection 8/32 boards - that are sharing interrupts. The Stallion EasyIO and EasyConnection 8/32 - EISA configuration files required are supplied by Stallion Technologies - on the DOS Utilities floppy (usually supplied in the box with the board - when purchased. If not, you can pick it up from Stallion's FTP site, - ftp.stallion.com). You will need to edit the board resources to choose - level triggered interrupts, and make sure to set each board's interrupt - to the same IRQ number. - -You must complete both the above steps for this to work. When you reboot -or load the driver your EasyIO and EasyConnection 8/32 boards will be -sharing interrupts. - - -2.2 USING HIGH SHARED MEMORY - -The EasyConnection 8/64-EI, ONboard and Stallion boards are capable of -using shared memory addresses above the usual 640K - 1Mb range. The ONboard -ISA and the Stallion boards can be programmed to use memory addresses up to -16Mb (the ISA bus addressing limit), and the EasyConnection 8/64-EI and -ONboard/E can be programmed for memory addresses up to 4Gb (the EISA bus -addressing limit). - -The higher than 1Mb memory addresses are fully supported by this driver. -Just enter the address as you normally would for a lower than 1Mb address -(in the drivers board configuration structure). - - - -2.3 TROUBLE SHOOTING - -If a board is not found by the driver but is actually in the system then the -most likely problem is that the I/O address is wrong. Change it in the driver -stallion.c or istallion.c configuration structure and rebuild the kernel or -modules, or change it on the board. On EasyIO and EasyConnection 8/32 boards -the IRQ is software programmable, so if there is a conflict you may need to -change the IRQ used for a board in the stallion.c configuration structure. -There are no interrupts to worry about for ONboard, Brumby, Stallion or -EasyConnection 8/64 boards. The memory region on EasyConnection 8/64 and -ONboard boards is software programmable, but not on the Brumbys or Stallions. - - - -3. USING THE DRIVERS - -3.1 INTELLIGENT DRIVER OPERATION - -The intelligent boards also need to have their "firmware" code downloaded -to them. This is done via a user level application supplied in the driver -package called "stlload". Compile this program where ever you dropped the -package files, by typing "make". In its simplest form you can then type - ./stlload -i cdk.sys -in this directory and that will download board 0 (assuming board 0 is an -EasyConnection 8/64 board). To download to an ONboard, Brumby or Stallion do: - ./stlload -i 2681.sys - -Normally you would want all boards to be downloaded as part of the standard -system startup. To achieve this, add one of the lines above into the -/etc/rc.d/rc.S or /etc/rc.d/rc.serial file. To download each board just add -the "-b " option to the line. You will need to download code for -every board. You should probably move the stlload program into a system -directory, such as /usr/sbin. Also, the default location of the cdk.sys image -file in the stlload down-loader is /usr/lib/stallion. Create that directory -and put the cdk.sys and 2681.sys files in it. (It's a convenient place to put -them anyway). As an example your /etc/rc.d/rc.S file might have the -following lines added to it (if you had 3 boards): - /usr/sbin/stlload -b 0 -i /usr/lib/stallion/cdk.sys - /usr/sbin/stlload -b 1 -i /usr/lib/stallion/2681.sys - /usr/sbin/stlload -b 2 -i /usr/lib/stallion/2681.sys - -The image files cdk.sys and 2681.sys are specific to the board types. The -cdk.sys will only function correctly on an EasyConnection 8/64 board. Similarly -the 2681.sys image fill only operate on ONboard, Brumby and Stallion boards. -If you load the wrong image file into a board it will fail to start up, and -of course the ports will not be operational! - -If you are using the modularized version of the driver you might want to put -the insmod calls in the startup script as well (before the download lines -obviously). - - -3.2 USING THE SERIAL PORTS - -Once the driver is installed you will need to setup some device nodes to -access the serial ports. The simplest method is to use the stallion utility -"mkdevnods" script. It will automatically create all possible device entries -required for all 4 boards. This will create the normal serial port devices as -/dev/ttyE# where # is the port number starting from 0. A bank of 64 minor -device numbers is allocated to each board, so the first port on the second -board is port 64, etc. A set of callout type devices is also created. They -are created as the devices /dev/cue# where # is the same as for the ttyE -devices. - -For the most part the Stallion driver tries to emulate the standard PC system -COM ports and the standard Linux serial driver. The idea is that you should -be able to use Stallion board ports and COM ports interchangeably without -modifying anything but the device name. Anything that doesn't work like that -should be considered a bug in this driver! - -If you look at the driver code you will notice that it is fairly closely -based on the Linux serial driver (linux/drivers/char/serial.c). This is -intentional, obviously this is the easiest way to emulate its behavior! - -Since this driver tries to emulate the standard serial ports as much as -possible, most system utilities should work as they do for the standard -COM ports. Most importantly "stty" works as expected and "setserial" can be -also be used (excepting the ability to auto-configure the I/O and IRQ -addresses of boards). Higher baud rates are supported in the usual fashion -through setserial or using the CBAUDEX extensions. Note that the EasyIO and -EasyConnection (all types) support 57600 and 115200 baud. The older boards -including ONboard, Brumby and the original Stallion support a maximum baud -rate of 38400. - -If you are unfamiliar with how to use serial ports, then get the Serial-HOWTO -by Greg Hankins. It will explain everything you need to know! - - - -4. NOTES - -You can use both drivers at once if you have a mix of board types installed -in a system. However to do this you will need to change the major numbers -used by one of the drivers. Currently both drivers use major numbers 24, 25 -and 28 for their devices. Change one driver to use some other major numbers, -and then modify the mkdevnods script to make device nodes based on those new -major numbers. For example, you could change the istallion.c driver to use -major numbers 60, 61 and 62. You will also need to create device nodes with -different names for the ports, for example ttyF# and cuf#. - -The original Stallion board is no longer supported by Stallion Technologies. -Although it is known to work with the istallion driver. - -Finding a free physical memory address range can be a problem. The older -boards like the Stallion and ONboard need large areas (64K or even 128K), so -they can be very difficult to get into a system. If you have 16 Mb of RAM -then you have no choice but to put them somewhere in the 640K -> 1Mb range. -ONboards require 64K, so typically 0xd0000 is good, or 0xe0000 on some -systems. If you have an original Stallion board, "V4.0" or Rev.O, then you -need a 64K memory address space, so again 0xd0000 and 0xe0000 are good. -Older Stallion boards are a much bigger problem. They need 128K of address -space and must be on a 128K boundary. If you don't have a VGA card then -0xc0000 might be usable - there is really no other place you can put them -below 1Mb. - -Both the ONboard and old Stallion boards can use higher memory addresses as -well, but you must have less than 16Mb of RAM to be able to use them. Usual -high memory addresses used include 0xec0000 and 0xf00000. - -The Brumby boards only require 16Kb of address space, so you can usually -squeeze them in somewhere. Common addresses are 0xc8000, 0xcc000, or in -the 0xd0000 range. EasyConnection 8/64 boards are even better, they only -require 4Kb of address space, again usually 0xc8000, 0xcc000 or 0xd0000 -are good. - -If you are using an EasyConnection 8/64-EI or ONboard/E then usually the -0xd0000 or 0xe0000 ranges are the best options below 1Mb. If neither of -them can be used then the high memory support to use the really high address -ranges is the best option. Typically the 2Gb range is convenient for them, -and gets them well out of the way. - -The ports of the EasyIO-8M board do not have DCD or DTR signals. So these -ports cannot be used as real modem devices. Generally, when using these -ports you should only use the cueX devices. - -The driver utility package contains a couple of very useful programs. One -is a serial port statistics collection and display program - very handy -for solving serial port problems. The other is an extended option setting -program that works with the intelligent boards. - - - -5. DISCLAIMER - -I do not speak for Stallion Technologies in any capacity, officially or -unofficially. - diff -u --recursive --new-file v2.1.28/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c --- v2.1.28/linux/drivers/char/apm_bios.c Wed Jan 29 03:32:58 1997 +++ linux/drivers/char/apm_bios.c Fri Mar 7 12:51:45 1997 @@ -375,12 +375,6 @@ &apm_bios_fops }; -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry apm_proc_entry = { - 0, 3, "apm", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, apm_get_info -}; -#endif - typedef struct callback_list_t { int (* callback)(apm_event_t); struct callback_list_t * next; @@ -1072,6 +1066,7 @@ unsigned short error; char * power_stat; char * bat_stat; + static struct proc_dir_entry *ent; if (apm_bios_info.version == 0) { printk("APM BIOS not found.\n"); @@ -1196,7 +1191,8 @@ add_timer(&apm_timer); #ifdef CONFIG_PROC_FS - proc_register_dynamic(&proc_root, &apm_proc_entry); + ent = create_proc_entry("apm", 0, 0); + ent->get_info = apm_get_info; #endif misc_register(&apm_device); diff -u --recursive --new-file v2.1.28/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.1.28/linux/drivers/char/istallion.c Sat Nov 30 00:48:33 1996 +++ linux/drivers/char/istallion.c Tue Mar 4 13:33:21 1997 @@ -3,6 +3,7 @@ /* * istallion.c -- stallion intelligent multiport serial driver. * + * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This code is loosely based on the Linux serial driver, written by @@ -92,6 +93,12 @@ * boards can share the same shared memory address space. No interrupt * is required for this board type. * Another example: + * { BRD_ECPE, 0x5000, 0, 0x80000000, 0, 0 }, + * This line will configure an EasyConnection 8/64 EISA in slot 5 and + * shared memory address of 0x80000000 (2 GByte). Multiple + * EasyConnection 8/64 EISA boards can share the same shared memory + * address space. No interrupt is required for this board type. + * Another example: * { BRD_ONBOARD, 0x240, 0, 0xd0000, 0, 0 }, * This line will configure an ONboard (ISA type) at io address 240, * and shared memory address of d0000. Multiple ONboards can share @@ -121,7 +128,8 @@ } stlconf_t; static stlconf_t stli_brdconf[] = { - { BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 }, + /*{ BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 },*/ + { BRD_ECP, 0x2b0, 0, 0xcc000, 0, 0 }, }; static int stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t); @@ -159,7 +167,7 @@ * all the local structures required by a serial tty driver. */ static char *stli_drvname = "Stallion Intelligent Multiport Serial Driver"; -static char *stli_drvversion = "1.1.4"; +static char *stli_drvversion = "5.3.2"; static char *stli_serialname = "ttyE"; static char *stli_calloutname = "cue"; @@ -475,7 +483,7 @@ /* * Define the maximal baud rate, and the default baud base for ports. */ -#define STL_MAXBAUD 230400 +#define STL_MAXBAUD 921600 #define STL_BAUDBASE 115200 #define STL_CLOSEDELAY 50 @@ -494,7 +502,7 @@ */ static unsigned int stli_baudrates[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400 + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 }; /*****************************************************************************/ @@ -543,8 +551,9 @@ static long stli_memread(struct inode *ip, struct file *fp, char *buf, unsigned long count); static long stli_memwrite(struct inode *ip, struct file *fp, const char *buf, unsigned long count); static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); +static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp); static void stli_poll(unsigned long arg); -static int stli_hostcmd(stlibrd_t *brdp, int channr); +static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp); static int stli_initopen(stlibrd_t *brdp, stliport_t *portp); static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait); @@ -722,8 +731,7 @@ } } - if (brdp->memaddr >= 0x100000) - iounmap(brdp->membase); + iounmap(brdp->membase); if ((brdp->brdtype == BRD_ECP) || (brdp->brdtype == BRD_ECPE) || (brdp->brdtype == BRD_ECPMC)) release_region(brdp->iobase, ECP_IOSIZE); else @@ -1056,7 +1064,6 @@ cp->openarg = arg; cp->open = 1; hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - hdrp->slavereq |= portp->reqbit; bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; EBRDDISABLE(brdp); @@ -1131,7 +1138,6 @@ cp->closearg = arg; cp->close = 1; hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - hdrp->slavereq |= portp->reqbit; bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; EBRDDISABLE(brdp); @@ -1432,7 +1438,6 @@ ap->changed.data &= ~DT_TXEMPTY; } hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - hdrp->slavereq |= portp->reqbit; bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; set_bit(ST_TXBUSY, &portp->state); @@ -1564,7 +1569,6 @@ ap->changed.data &= ~DT_TXEMPTY; } hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - hdrp->slavereq |= portp->reqbit; bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; set_bit(ST_TXBUSY, &portp->state); @@ -1753,7 +1757,8 @@ { stliport_t *portp; stlibrd_t *brdp; - unsigned long val; + unsigned long lval; + unsigned int ival; int rc; #if DEBUG @@ -1771,6 +1776,12 @@ if (brdp == (stlibrd_t *) NULL) return(0); + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return(-EIO); + } + rc = 0; switch (cmd) { @@ -1778,16 +1789,16 @@ if ((rc = tty_check_change(tty)) == 0) { tty_wait_until_sent(tty, 0); if (! arg) { - val = 250; - rc = stli_cmdwait(brdp, portp, A_BREAK, &val, sizeof(unsigned long), 0); + lval = 250; + rc = stli_cmdwait(brdp, portp, A_BREAK, &lval, sizeof(unsigned long), 0); } } break; case TCSBRKP: if ((rc = tty_check_change(tty)) == 0) { tty_wait_until_sent(tty, 0); - val = (arg ? (arg * 100) : 250); - rc = stli_cmdwait(brdp, portp, A_BREAK, &val, sizeof(unsigned long), 0); + lval = (arg ? (arg * 100) : 250); + rc = stli_cmdwait(brdp, portp, A_BREAK, &lval, sizeof(unsigned long), 0); } break; case TIOCGSOFTCAR: @@ -1796,40 +1807,36 @@ break; case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int value; - get_user(value, (unsigned int *) arg); - tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0); + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0); } break; case TIOCMGET: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) { if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0) return(rc); - val = stli_mktiocm(portp->asig.sigvalue); - put_user(val, (unsigned int *) arg); + lval = stli_mktiocm(portp->asig.sigvalue); + put_user(lval, (unsigned int *) arg); } break; case TIOCMBIS: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int value; - get_user(value, (unsigned int *) arg); - stli_mkasysigs(&portp->asig, ((value & TIOCM_DTR) ? 1 : -1), ((value & TIOCM_RTS) ? 1 : -1)); + get_user(ival, (unsigned int *) arg); + stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 1 : -1), ((ival & TIOCM_RTS) ? 1 : -1)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } break; case TIOCMBIC: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int value; - get_user(value, (unsigned int *) arg); - stli_mkasysigs(&portp->asig, ((value & TIOCM_DTR) ? 0 : -1), ((value & TIOCM_RTS) ? 0 : -1)); + get_user(ival, (unsigned int *) arg); + stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 0 : -1), ((ival & TIOCM_RTS) ? 0 : -1)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } break; case TIOCMSET: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int value; - get_user(value, (unsigned int *) arg); - stli_mkasysigs(&portp->asig, ((value & TIOCM_DTR) ? 1 : 0), ((value & TIOCM_RTS) ? 1 : 0)); + get_user(ival, (unsigned int *) arg); + stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 1 : 0), ((ival & TIOCM_RTS) ? 1 : 0)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } break; @@ -2223,7 +2230,6 @@ cp->status = 0; cp->cmd = cmd; hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - hdrp->slavereq |= portp->reqbit; bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; set_bit(ST_CMDING, &portp->state); @@ -2348,15 +2354,17 @@ * enabled and interrupts off when called. Notice that by servicing the * read data last we don't need to change the shared memory pointer * during processing (which is a slow IO operation). + * Return value indicates if this port is still awaiting actions from + * the slave (like open, command, or even TX data being sent). If 0 + * then port is still busy, otherwise no longer busy. */ -static inline int stli_hostcmd(stlibrd_t *brdp, int channr) +static inline int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) { volatile cdkasy_t *ap; volatile cdkctrl_t *cp; struct tty_struct *tty; asynotify_t nt; - stliport_t *portp; unsigned long oldsigs; int rc, donerx; @@ -2364,7 +2372,6 @@ printk("stli_hostcmd(brdp=%x,channr=%d)\n", (int) brdp, channr); #endif - portp = brdp->ports[(channr - 1)]; ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); cp = &ap->ctrl; @@ -2496,7 +2503,73 @@ stli_read(brdp, portp); } - return(0); + return((test_bit(ST_OPENING, &portp->state) || + test_bit(ST_CLOSING, &portp->state) || + test_bit(ST_CMDING, &portp->state) || + test_bit(ST_TXBUSY, &portp->state) || + test_bit(ST_RXING, &portp->state)) ? 0 : 1); +} + +/*****************************************************************************/ + +/* + * Service all ports on a particular board. Assumes that the boards + * shared memory is enabled, and that the page pointer is pointed + * at the cdk header structure. + */ + +static inline void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp) +{ + stliport_t *portp; + unsigned char hostbits[(STL_MAXCHANS / 8) + 1]; + unsigned char slavebits[(STL_MAXCHANS / 8) + 1]; + unsigned char *slavep; + int bitpos, bitat, bitsize; + int channr, nrdevs, slavebitchange; + + bitsize = brdp->bitsize; + nrdevs = brdp->nrdevs; + +/* + * Check if slave wants any service. Basically we try to do as + * little work as possible here. There are 2 levels of service + * bits. So if there is nothing to do we bail early. We check + * 8 service bits at a time in the inner loop, so we can bypass + * the lot if none of them want service. + */ + memcpy(&hostbits[0], (((unsigned char *) hdrp) + brdp->hostoffset), bitsize); + + memset(&slavebits[0], 0, bitsize); + slavebitchange = 0; + + for (bitpos = 0; (bitpos < bitsize); bitpos++) { + if (hostbits[bitpos] == 0) + continue; + channr = bitpos * 8; + for (bitat = 0x1; (channr < nrdevs); channr++, bitat <<= 1) { + if (hostbits[bitpos] & bitat) { + portp = brdp->ports[(channr - 1)]; + if (stli_hostcmd(brdp, portp)) { + slavebitchange++; + slavebits[bitpos] |= bitat; + } + } + } + } + +/* + * If any of the ports are no longer busy then update them in the + * slave request bits. We need to do this after, since a host port + * service may initiate more slave requests. + */ + if (slavebitchange) { + hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); + slavep = ((unsigned char *) hdrp) + brdp->slaveoffset; + for (bitpos = 0; (bitpos < bitsize); bitpos++) { + if (slavebits[bitpos]) + slavep[bitpos] &= ~slavebits[bitpos]; + } + } } /*****************************************************************************/ @@ -2513,12 +2586,8 @@ static void stli_poll(unsigned long arg) { volatile cdkhdr_t *hdrp; - unsigned char bits[(STL_MAXCHANS / 8) + 1]; - unsigned char hostreq, slavereq; - stliport_t *portp; stlibrd_t *brdp; - int bitpos, bitat, bitsize; - int brdnr, channr, nrdevs; + int brdnr; stli_timerlist.expires = STLI_TIMEOUT; add_timer(&stli_timerlist); @@ -2535,67 +2604,8 @@ EBRDENABLE(brdp); hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - hostreq = hdrp->hostreq; - slavereq = hdrp->slavereq; - bitsize = brdp->bitsize; - nrdevs = brdp->nrdevs; - -/* - * Check if slave wants any service. Basically we try to do as - * little work as possible here. There are 2 levels of service - * bits. So if there is nothing to do we bail early. We check - * 8 service bits at a time in the inner loop, so we can bypass - * the lot if none of them want service. - */ - if (hostreq) { - memcpy(&bits[0], (((unsigned char *) hdrp) + brdp->hostoffset), bitsize); - - for (bitpos = 0; (bitpos < bitsize); bitpos++) { - if (bits[bitpos] == 0) - continue; - channr = bitpos * 8; - for (bitat = 0x1; (channr < nrdevs); channr++, bitat <<= 1) { - if (bits[bitpos] & bitat) { - stli_hostcmd(brdp, channr); - } - } - } - } - -/* - * Check if any of the out-standing host commands have completed. - * It is a bit unfortunate that we need to check stuff that we - * initiated! This ain't pretty, but it needs to be fast. - */ - if (slavereq) { - slavereq = 0; - hostreq = 0; - memcpy(&bits[0], (((unsigned char *) hdrp) + brdp->slaveoffset), bitsize); - - for (bitpos = 0; (bitpos < bitsize); bitpos++) { - if (bits[bitpos] == 0) - continue; - channr = bitpos * 8; - for (bitat = 0x1; (channr < nrdevs); channr++, bitat <<= 1) { - if (bits[bitpos] & bitat) { - portp = brdp->ports[(channr - 1)]; - if (test_bit(ST_OPENING, &portp->state) || - test_bit(ST_CLOSING, &portp->state) || - test_bit(ST_CMDING, &portp->state) || - test_bit(ST_TXBUSY, &portp->state)) { - slavereq |= portp->reqbit; - } else { - bits[bitpos] &= ~bitat; - hostreq++; - } - } - } - } - hdrp->slavereq = slavereq; - if (hostreq) - memcpy((((unsigned char *) hdrp) + brdp->slaveoffset), &bits[0], bitsize); - } - + if (hdrp->hostreq) + stli_brdpoll(brdp, hdrp); EBRDDISABLE(brdp); } } @@ -2621,7 +2631,7 @@ pp->baudout = tiosp->c_cflag & CBAUD; if (pp->baudout & CBAUDEX) { pp->baudout &= ~CBAUDEX; - if ((pp->baudout < 1) || (pp->baudout > 2)) + if ((pp->baudout < 1) || (pp->baudout > 5)) tiosp->c_cflag &= ~CBAUDEX; else pp->baudout += 15; @@ -3342,6 +3352,11 @@ if ((brdp->iobase == 0) || (brdp->memaddr == 0)) return(-ENODEV); + if (check_region(brdp->iobase, ECP_IOSIZE)) { + printk("STALLION: Warning, unit %d I/O address %x conflicts with another device\n", + brdp->brdnr, brdp->iobase); + } + /* * Based on the specific board type setup the common vars to access * and enable shared memory. Set all board specific information now @@ -3394,16 +3409,14 @@ /* * The per-board operations structure is all set up, so now let's go * and get the board operational. Firstly initialize board configuration - * registers. Then if we are using the higher 1Mb support then set up - * the memory mapping info so we can get at the boards shared memory. + * registers. Set the memory mapping info so we can get at the boards + * shared memory. */ EBRDINIT(brdp); - if (brdp->memaddr > 0x100000) { - brdp->membase = ioremap(brdp->memaddr, brdp->memsize); - if (brdp->membase == (void *) NULL) - return(-ENOMEM); - } + brdp->membase = ioremap(brdp->memaddr, brdp->memsize); + if (brdp->membase == (void *) NULL) + return(-ENOMEM); /* * Now that all specific code is set up, enable the shared memory and @@ -3475,6 +3488,11 @@ if ((brdp->iobase == 0) || (brdp->memaddr == 0)) return(-ENODEV); + if (check_region(brdp->iobase, ONB_IOSIZE)) { + printk("STALLION: Warning, unit %d I/O address %x conflicts with another device\n", + brdp->brdnr, brdp->iobase); + } + /* * Based on the specific board type setup the common vars to access * and enable shared memory. Set all board specific information now @@ -3550,16 +3568,14 @@ /* * The per-board operations structure is all set up, so now let's go * and get the board operational. Firstly initialize board configuration - * registers. Then if we are using the higher 1Mb support then set up - * the memory mapping info so we can get at the boards shared memory. + * registers. Set the memory mapping info so we can get at the boards + * shared memory. */ EBRDINIT(brdp); - if (brdp->memaddr > 0x100000) { - brdp->membase = ioremap(brdp->memaddr, brdp->memsize); - if (brdp->membase == (void *) NULL) - return(-ENOMEM); - } + brdp->membase = ioremap(brdp->memaddr, brdp->memsize); + if (brdp->membase == (void *) NULL) + return(-ENOMEM); /* * Now that all specific code is set up, enable the shared memory and @@ -3677,6 +3693,8 @@ portp->portbit = (unsigned char) (0x1 << (i % 8)); } + hdrp->slavereq = 0xff; + /* * For each port setup a local copy of the RX and TX buffer offsets * and sizes. We do this separate from the above, because we need to @@ -3820,11 +3838,10 @@ for (i = 0; (i < stli_eisamempsize); i++) { brdp->memaddr = stli_eisamemprobeaddrs[i]; brdp->membase = (void *) brdp->memaddr; - if (brdp->memaddr > 0x100000) { - brdp->membase = ioremap(brdp->memaddr, brdp->memsize); - if (brdp->membase == (void *) NULL) - continue; - } + brdp->membase = ioremap(brdp->memaddr, brdp->memsize); + if (brdp->membase == (void *) NULL) + continue; + if (brdp->brdtype == BRD_ECPE) { ecpsigp = (cdkecpsig_t *) stli_ecpeigetmemptr(brdp, CDK_SIGADDR, __LINE__); memcpy(&ecpsig, ecpsigp, sizeof(cdkecpsig_t)); @@ -3837,8 +3854,8 @@ (onbsig.magic2 == ONB_MAGIC2) && (onbsig.magic3 == ONB_MAGIC3)) foundit = 1; } - if (brdp->memaddr >= 0x100000) - iounmap(brdp->membase); + + iounmap(brdp->membase); if (foundit) break; } @@ -4051,8 +4068,7 @@ * the slave image (and debugging :-) */ -static long stli_memread(struct inode *ip, struct file *fp, - char *buf, unsigned long count) +static long stli_memread(struct inode *ip, struct file *fp, char *buf, unsigned long count) { unsigned long flags; void *memptr; @@ -4101,8 +4117,7 @@ * the slave image (and debugging :-) */ -static long stli_memwrite(struct inode *ip, struct file *fp, - const char *buf, unsigned long count) +static long stli_memwrite(struct inode *ip, struct file *fp, const char *buf, unsigned long count) { unsigned long flags; void *memptr; @@ -4111,7 +4126,7 @@ int brdnr, size, n; #if DEBUG - printk("stli_memwrite(ip=%x,fp=%x,buf=%x,count=%lx)\n", (int) ip, (int) fp, (int) buf, count); + printk("stli_memwrite(ip=%x,fp=%x,buf=%x,count=%lu)\n", (int) ip, (int) fp, (int) buf, count); #endif brdnr = MINOR(ip->i_rdev); diff -u --recursive --new-file v2.1.28/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.1.28/linux/drivers/char/keyboard.c Tue Nov 12 03:08:43 1996 +++ linux/drivers/char/keyboard.c Wed Mar 5 11:10:36 1997 @@ -1,3 +1,4 @@ +extern void allow_interrupts(void); /* * linux/drivers/char/keyboard.c * @@ -1080,6 +1081,7 @@ reply_expected = 1; outb_p(data, 0x60); for(i=0; i<0x200000; i++) { + allow_interrupts(); inb_p(0x64); /* just as a delay */ if (acknowledge) return 1; diff -u --recursive --new-file v2.1.28/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.28/linux/drivers/char/misc.c Sun Jan 26 02:07:16 1997 +++ linux/drivers/char/misc.c Fri Mar 7 12:51:45 1997 @@ -74,7 +74,8 @@ extern int rtc_init(void); #ifdef CONFIG_PROC_FS -static int proc_misc_read(char *buf, char **start, off_t offset, int len, int unused) +static int misc_read_proc(char *buf, char **start, off_t offset, + int len, int *eof, void *private) { struct miscdevice *p; @@ -183,19 +184,16 @@ #endif #if defined(CONFIG_PROC_FS) && !defined(MODULE) -static struct proc_dir_entry proc_misc = { - 0, 4, "misc", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, NULL /* ops -- default to array */, - &proc_misc_read /* get_info */, -}; +static struct proc_dir_entry *proc_misc; #endif int misc_init(void) { #ifndef MODULE #ifdef CONFIG_PROC_FS - proc_register_dynamic(&proc_root, &proc_misc); + proc_misc = create_proc_entry("misc", 0, 0); + if (proc_misc) + proc_misc->read_proc = misc_read_proc; #endif /* PROC_FS */ #ifdef CONFIG_BUSMOUSE bus_mouse_init(); diff -u --recursive --new-file v2.1.28/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.1.28/linux/drivers/char/serial.c Tue Mar 4 10:25:23 1997 +++ linux/drivers/char/serial.c Fri Mar 7 12:51:45 1997 @@ -52,7 +52,7 @@ #include static char *serial_name = "Serial driver"; -static char *serial_version = "4.23"; +static char *serial_version = "4.24"; static DECLARE_TASK_QUEUE(tq_serial); @@ -1053,7 +1053,7 @@ static int startup(struct async_struct * info) { unsigned long flags; - int retval; + int retval=0; void (*handler)(int, void *, struct pt_regs *); struct serial_state *state= info->state; unsigned long page; @@ -1070,16 +1070,14 @@ if (info->flags & ASYNC_INITIALIZED) { free_page(page); - restore_flags(flags); - return 0; + goto errout; } if (!state->port || !state->type) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); free_page(page); - restore_flags(flags); - return 0; + goto errout; } if (info->xmit_buf) free_page(page); @@ -1118,13 +1116,12 @@ * here. */ if (serial_inp(info, UART_LSR) == 0xff) { - restore_flags(flags); if (suser()) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - return 0; } else - return -ENODEV; + retval = -ENODEV; + goto errout; } /* @@ -1142,7 +1139,8 @@ #endif handler = rs_interrupt; #else - return -EBUSY; + retval = -EBUSY; + goto errout; #endif /* CONFIG_SERIAL_SHARE_IRQ */ } else handler = rs_interrupt_single; @@ -1150,14 +1148,13 @@ retval = request_irq(state->irq, handler, IRQ_T(info), "serial", NULL); if (retval) { - restore_flags(flags); if (suser()) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - return 0; - } else - return retval; + retval = 0; + } + goto errout; } } @@ -1246,6 +1243,10 @@ info->flags |= ASYNC_INITIALIZED; restore_flags(flags); return 0; + +errout: + restore_flags(flags); + return retval; } /* @@ -2879,8 +2880,8 @@ return ret; } -int rs_read_proc(char *page, char **start, off_t off, int count, void - *data) +int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) { int i, len = 0; off_t begin = 0; @@ -2889,12 +2890,14 @@ for (i = 0; i < NR_PORTS && len < 4000; i++) { len += line_info(page + len, &rs_table[i]); if (len+begin > off+count) - break; + goto done; if (len+begin < off) { begin += len; len = 0; } } + *eof = 1; +done: if (off >= len+begin) return 0; *start = page + (begin-off); @@ -2919,6 +2922,18 @@ printk(KERN_INFO "%s version %s with", serial_name, serial_version); #ifdef CONFIG_HUB6 printk(" HUB-6"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_MANY_PORTS + printk(" MANY_PORTS"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_MULTIPORT + printk(" MULTIPORT"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_SHARE_IRQ + printk(" SHARE_IRQ"); #define SERIAL_OPT #endif #ifdef SERIAL_OPT diff -u --recursive --new-file v2.1.28/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.1.28/linux/drivers/char/stallion.c Sat Nov 30 00:48:34 1996 +++ linux/drivers/char/stallion.c Tue Mar 4 13:33:21 1997 @@ -3,6 +3,7 @@ /* * stallion.c -- stallion multiport serial driver. * + * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This code is loosely based on the Linux serial driver, written by @@ -37,12 +38,13 @@ #include #include #include +#include #include #include #include #include #include -#include /* for CONFIG_PCI */ +#include #include #include #include @@ -55,11 +57,9 @@ /*****************************************************************************/ /* - * Define different board types. At the moment I have only declared - * those boards that this driver supports. But I will use the standard - * "assigned" board numbers. In the future this driver will support - * some of the other Stallion boards. Currently supported boards are - * abbreviated as EIO = EasyIO and ECH = EasyConnection 8/32. + * Define different board types. Use the standard Stallion "assigned" + * board numbers. Boards supported in this driver are abbreviated as + * EIO = EasyIO and ECH = EasyConnection 8/32. */ #define BRD_EASYIO 20 #define BRD_ECH 21 @@ -101,7 +101,8 @@ } stlconf_t; static stlconf_t stl_brdconf[] = { - { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 }, + /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/ + { BRD_ECH, 0x2a0, 0x280, 0, 15, 0 }, }; static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t); @@ -126,12 +127,11 @@ #define STL_DRVTYPCALLOUT 2 /* - * I haven't really decided (or measured) what TX buffer size gives - * a good balance between performance and memory usage. These seem - * to work pretty well... + * Set the TX buffer size. Bigger is better, but we don't want + * to chew too much memory with buffers! */ -#define STL_TXBUFLOW 256 -#define STL_TXBUFSIZE 2048 +#define STL_TXBUFLOW 512 +#define STL_TXBUFSIZE 4096 /*****************************************************************************/ @@ -140,7 +140,7 @@ * all the local structures required by a serial tty driver. */ static char *stl_drvname = "Stallion Multiport Serial Driver"; -static char *stl_drvversion = "1.1.4"; +static char *stl_drvversion = "5.3.2"; static char *stl_serialname = "ttyE"; static char *stl_calloutname = "cue"; @@ -185,6 +185,11 @@ static stlport_t stl_dummyport; /* + * Define global place to put buffer overflow characters. + */ +static char stl_unwanted[SC26198_RXFIFOSIZE]; + +/* * Keep track of what interrupts we have requested for us. * We don't need to request an interrupt twice if it is being * shared with another Stallion board. @@ -198,7 +203,7 @@ /* * Per board state flags. Used with the state field of the board struct. - * Not really much here yet! + * Not really much here! */ #define BRD_FOUND 0x1 @@ -210,6 +215,7 @@ #define ASYI_TXBUSY 1 #define ASYI_TXLOW 2 #define ASYI_DCDCHANGE 3 +#define ASYI_TXFLOWED 4 /* * Define an array of board names as printable strings. Handy for @@ -249,14 +255,21 @@ /* * Hardware ID bits for the EasyIO and ECH boards. These defines apply - * to the directly accessible io ports of these boards (not the cd1400 - * uarts - they are in cd1400.h). + * to the directly accessible io ports of these boards (not the uarts - + * they are in cd1400.h and sc26198.h). */ #define EIO_8PORTRS 0x04 #define EIO_4PORTRS 0x05 #define EIO_8PORTDI 0x00 #define EIO_8PORTM 0x06 +#define EIO_MK3 0x03 #define EIO_IDBITMASK 0x07 + +#define EIO_BRDMASK 0xf0 +#define ID_BRD4 0x10 +#define ID_BRD8 0x20 +#define ID_BRD16 0x30 + #define EIO_INTRPEND 0x08 #define EIO_INTEDGE 0x00 #define EIO_INTLEVEL 0x08 @@ -278,24 +291,16 @@ #define ECH_PNLSTATUS 2 #define ECH_PNL16PORT 0x20 #define ECH_PNLIDMASK 0x07 +#define ECH_PNLXPID 0x40 #define ECH_PNLINTRPEND 0x80 -#define ECH_ADDR2MASK 0x1e0 -#define EIO_CLK 25000000 -#define EIO_CLK8M 20000000 -#define ECH_CLK EIO_CLK +#define ECH_ADDR2MASK 0x1e0 /* - * Define the offsets within the register bank for all io registers. - * These io address offsets are common to both the EIO and ECH. + * Define real Stallion PCI vemdor and device ID. */ -#define EREG_ADDR 0 -#define EREG_DATA 4 -#define EREG_RXACK 5 -#define EREG_TXACK 6 -#define EREG_MDACK 7 - -#define EREG_BANKSIZE 8 +#define PCI_VENDOR_ID_STALLION 0x124d +#define PCI_DEVICE_ID_ECHPCI832 0x0000 /* * Define the vector mapping bits for the programmable interrupt board @@ -326,16 +331,7 @@ outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE), \ stl_brds[(brdnr)]->ioctrl); -/* - * Define the cd1400 baud rate clocks. These are used when calculating - * what clock and divisor to use for the required baud rate. Also - * define the maximum baud rate allowed, and the default base baud. - */ -static int stl_cd1400clkdivs[] = { - CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4 -}; - -#define STL_MAXBAUD 230400 +#define STL_MAXBAUD 921600 #define STL_BAUDBASE 115200 #define STL_CLOSEDELAY 50 @@ -349,16 +345,14 @@ /* * Define a baud rate table that converts termios baud rate selector - * into the actual baud rate value. All baud rate calculates are based - * on the actual baud rate required. + * into the actual baud rate value. All baud rate calculations are + * based on the actual baud rate required. */ static unsigned int stl_baudrates[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400 + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 }; -/*****************************************************************************/ - /* * Define some handy local macros... */ @@ -408,20 +402,13 @@ static int stl_clrportstats(stlport_t *portp, comstats_t *cp); static int stl_getportstruct(unsigned long arg); static int stl_getbrdstruct(unsigned long arg); -static void stl_setreg(stlport_t *portp, int regnr, int value); -static int stl_getreg(stlport_t *portp, int regnr); -static int stl_updatereg(stlport_t *portp, int regnr, int value); -static void stl_setport(stlport_t *portp, struct termios *tiosp); -static int stl_getsignals(stlport_t *portp); -static void stl_setsignals(stlport_t *portp, int dtr, int rts); -static void stl_ccrwait(stlport_t *portp); -static void stl_enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_startrxtx(stlport_t *portp, int rx, int tx); -static void stl_disableintrs(stlport_t *portp); -static void stl_sendbreak(stlport_t *portp, long len); static int stl_waitcarrier(stlport_t *portp, struct file *filp); static void stl_delay(int len); static void stl_intr(int irq, void *dev_id, struct pt_regs *regs); +static void stl_eiointr(stlbrd_t *brdp); +static void stl_echatintr(stlbrd_t *brdp); +static void stl_echmcaintr(stlbrd_t *brdp); +static void stl_echpciintr(stlbrd_t *brdp); static void stl_offintr(void *private); static void *stl_memalloc(int len); static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); @@ -430,6 +417,177 @@ static int stl_findpcibrds(void); #endif +/* + * CD1400 uart specific handling functions. + */ +static void stl_cd1400setreg(stlport_t *portp, int regnr, int value); +static int stl_cd1400getreg(stlport_t *portp, int regnr); +static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value); +static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp); +static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); +static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp); +static int stl_cd1400getsignals(stlport_t *portp); +static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts); +static void stl_cd1400ccrwait(stlport_t *portp); +static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx); +static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx); +static void stl_cd1400disableintrs(stlport_t *portp); +static void stl_cd1400sendbreak(stlport_t *portp, long len); +static void stl_cd1400flowctrl(stlport_t *portp, int state); +static void stl_cd1400flush(stlport_t *portp); +static void stl_cd1400intr(stlpanel_t *panelp, unsigned int iobase); +static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr); +static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr); +static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr); + +/* + * SC26198 uart specific handling functions. + */ +static void stl_sc26198setreg(stlport_t *portp, int regnr, int value); +static int stl_sc26198getreg(stlport_t *portp, int regnr); +static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value); +static int stl_sc26198getglobreg(stlport_t *portp, int regnr); +static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp); +static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); +static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp); +static int stl_sc26198getsignals(stlport_t *portp); +static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts); +static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx); +static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx); +static void stl_sc26198disableintrs(stlport_t *portp); +static void stl_sc26198sendbreak(stlport_t *portp, long len); +static void stl_sc26198flowctrl(stlport_t *portp, int state); +static void stl_sc26198flush(stlport_t *portp); +static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty); +static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase); +static void stl_sc26198txisr(stlport_t *port); +static void stl_sc26198rxisr(stlport_t *port, unsigned int iack); +static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch); +static void stl_sc26198rxbadchars(stlport_t *portp); +static void stl_sc26198otherisr(stlport_t *port, unsigned int iack); + +/*****************************************************************************/ + +/* + * Generic UART support structure. + */ +typedef struct uart { + int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp); + void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp); + void (*setport)(stlport_t *portp, struct termios *tiosp); + int (*getsignals)(stlport_t *portp); + void (*setsignals)(stlport_t *portp, int dtr, int rts); + void (*enablerxtx)(stlport_t *portp, int rx, int tx); + void (*startrxtx)(stlport_t *portp, int rx, int tx); + void (*disableintrs)(stlport_t *portp); + void (*sendbreak)(stlport_t *portp, long len); + void (*flowctrl)(stlport_t *portp, int state); + void (*flush)(stlport_t *portp); + void (*intr)(stlpanel_t *panelp, unsigned int iobase); +} uart_t; + +/* + * Define some macros to make calling these functions nice and clean. + */ +#define stl_panelinit (* ((uart_t *) panelp->uartp)->panelinit) +#define stl_portinit (* ((uart_t *) portp->uartp)->portinit) +#define stl_setport (* ((uart_t *) portp->uartp)->setport) +#define stl_getsignals (* ((uart_t *) portp->uartp)->getsignals) +#define stl_setsignals (* ((uart_t *) portp->uartp)->setsignals) +#define stl_enablerxtx (* ((uart_t *) portp->uartp)->enablerxtx) +#define stl_startrxtx (* ((uart_t *) portp->uartp)->startrxtx) +#define stl_disableintrs (* ((uart_t *) portp->uartp)->disableintrs) +#define stl_sendbreak (* ((uart_t *) portp->uartp)->sendbreak) +#define stl_flowctrl (* ((uart_t *) portp->uartp)->flowctrl) +#define stl_flush (* ((uart_t *) portp->uartp)->flush) + +/*****************************************************************************/ + +/* + * CD1400 UART specific data initialization. + */ +static uart_t stl_cd1400uart = { + stl_cd1400panelinit, + stl_cd1400portinit, + stl_cd1400setport, + stl_cd1400getsignals, + stl_cd1400setsignals, + stl_cd1400enablerxtx, + stl_cd1400startrxtx, + stl_cd1400disableintrs, + stl_cd1400sendbreak, + stl_cd1400flowctrl, + stl_cd1400flush, + stl_cd1400intr +}; + +/* + * Define the offsets within the register bank of a cd1400 based panel. + * These io address offsets are common to the EasyIO board as well. + */ +#define EREG_ADDR 0 +#define EREG_DATA 4 +#define EREG_RXACK 5 +#define EREG_TXACK 6 +#define EREG_MDACK 7 + +#define EREG_BANKSIZE 8 + +#define CD1400_CLK 25000000 +#define CD1400_CLK8M 20000000 + +/* + * Define the cd1400 baud rate clocks. These are used when calculating + * what clock and divisor to use for the required baud rate. Also + * define the maximum baud rate allowed, and the default base baud. + */ +static int stl_cd1400clkdivs[] = { + CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4 +}; + +/*****************************************************************************/ + +/* + * SC26198 UART specific data initization. + */ +static uart_t stl_sc26198uart = { + stl_sc26198panelinit, + stl_sc26198portinit, + stl_sc26198setport, + stl_sc26198getsignals, + stl_sc26198setsignals, + stl_sc26198enablerxtx, + stl_sc26198startrxtx, + stl_sc26198disableintrs, + stl_sc26198sendbreak, + stl_sc26198flowctrl, + stl_sc26198flush, + stl_sc26198intr +}; + +/* + * Define the offsets within the register bank of a sc26198 based panel. + */ +#define XP_DATA 0 +#define XP_ADDR 1 +#define XP_MODID 2 +#define XP_STATUS 2 +#define XP_IACK 3 + +#define XP_BANKSIZE 4 + +/* + * Define the sc26198 baud rate table. Offsets within the table + * represent the actual baud rate selector of sc26198 registers. + */ +static unsigned int sc26198_baudtable[] = { + 50, 75, 150, 200, 300, 450, 600, 900, 1200, 1800, 2400, 3600, + 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, + 230400, 460800, 921600 +}; + +#define SC26198_NRBAUDS (sizeof(sc26198_baudtable) / sizeof(unsigned int)) + /*****************************************************************************/ /* @@ -1066,7 +1224,6 @@ #endif memset(&sio, 0, sizeof(struct serial_struct)); - sio.type = PORT_CIRRUS; sio.line = portp->portnr; sio.port = portp->ioaddr; sio.flags = portp->flags; @@ -1074,8 +1231,14 @@ sio.close_delay = portp->close_delay; sio.closing_wait = portp->closing_wait; sio.custom_divisor = portp->custom_divisor; - sio.xmit_fifo_size = CD1400_TXFIFOSIZE; sio.hub6 = 0; + if (portp->uartp == &stl_cd1400uart) { + sio.type = PORT_CIRRUS; + sio.xmit_fifo_size = CD1400_TXFIFOSIZE; + } else { + sio.type = PORT_UNKNOWN; + sio.xmit_fifo_size = SC26198_TXFIFOSIZE; + } brdp = stl_brds[portp->brdnr]; if (brdp != (stlbrd_t *) NULL) @@ -1122,6 +1285,7 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { stlport_t *portp; + unsigned int ival; int rc; #if DEBUG @@ -1134,6 +1298,12 @@ if (portp == (stlport_t *) NULL) return(-ENODEV); + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return(-EIO); + } + rc = 0; switch (cmd) { @@ -1156,37 +1326,32 @@ break; case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int val; - get_user(val, (unsigned int *) arg); - tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0); + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0); } break; case TIOCMGET: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int val; - val = stl_getsignals(portp); - put_user(val, (unsigned int *) arg); + ival = stl_getsignals(portp); + put_user(ival, (unsigned int *) arg); } break; case TIOCMBIS: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int val; - get_user(val, (unsigned int *) arg); - stl_setsignals(portp, ((val & TIOCM_DTR) ? 1 : -1), ((val & TIOCM_RTS) ? 1 : -1)); + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : -1), ((ival & TIOCM_RTS) ? 1 : -1)); } break; case TIOCMBIC: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int val; - get_user(val, (unsigned int *) arg); - stl_setsignals(portp, ((val & TIOCM_DTR) ? 0 : -1), ((val & TIOCM_RTS) ? 0 : -1)); + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 0 : -1), ((ival & TIOCM_RTS) ? 0 : -1)); } break; case TIOCMSET: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { - unsigned int val; - get_user(val, (unsigned int *) arg); - stl_setsignals(portp, ((val & TIOCM_DTR) ? 1 : 0), ((val & TIOCM_RTS) ? 1 : 0)); + get_user(ival, (unsigned int *) arg); + stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : 0), ((ival & TIOCM_RTS) ? 1 : 0)); } break; case TIOCGSERIAL: @@ -1261,7 +1426,6 @@ static void stl_throttle(struct tty_struct *tty) { stlport_t *portp; - unsigned long flags; #if DEBUG printk("stl_throttle(tty=%x)\n", (int) tty); @@ -1272,24 +1436,7 @@ portp = tty->driver_data; if (portp == (stlport_t *) NULL) return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - if (tty->termios->c_iflag & IXOFF) { - stl_ccrwait(portp); - stl_setreg(portp, CCR, CCR_SENDSCHR2); - portp->stats.rxxoff++; - stl_ccrwait(portp); - } - if (tty->termios->c_cflag & CRTSCTS) { - stl_setreg(portp, MCOR1, (stl_getreg(portp, MCOR1) & 0xf0)); - stl_setreg(portp, MSVR2, 0); - portp->stats.rxrtsoff++; - } - BRDDISABLE(portp->brdnr); - restore_flags(flags); + stl_flowctrl(portp, 0); } /*****************************************************************************/ @@ -1301,7 +1448,6 @@ static void stl_unthrottle(struct tty_struct *tty) { stlport_t *portp; - unsigned long flags; #if DEBUG printk("stl_unthrottle(tty=%x)\n", (int) tty); @@ -1312,30 +1458,7 @@ portp = tty->driver_data; if (portp == (stlport_t *) NULL) return; - - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - if (tty->termios->c_iflag & IXOFF) { - stl_ccrwait(portp); - stl_setreg(portp, CCR, CCR_SENDSCHR1); - portp->stats.rxxon++; - stl_ccrwait(portp); - } -/* - * Question: should we return RTS to what it was before? It may have - * been set by an ioctl... Suppose not, since if you have hardware - * flow control set then it is pretty silly to go and set the RTS line - * by hand. - */ - if (tty->termios->c_cflag & CRTSCTS) { - stl_setreg(portp, MCOR1, (stl_getreg(portp, MCOR1) | FIFO_RTSTHRESHOLD)); - stl_setreg(portp, MSVR2, MSVR2_RTS); - portp->stats.rxrtson++; - } - BRDDISABLE(portp->brdnr); - restore_flags(flags); + stl_flowctrl(portp, 1); } /*****************************************************************************/ @@ -1358,7 +1481,6 @@ portp = tty->driver_data; if (portp == (stlport_t *) NULL) return; - stl_startrxtx(portp, -1, 0); } @@ -1381,7 +1503,6 @@ portp = tty->driver_data; if (portp == (stlport_t *) NULL) return; - stl_startrxtx(portp, -1, 1); } @@ -1433,7 +1554,6 @@ static void stl_flushbuffer(struct tty_struct *tty) { stlport_t *portp; - unsigned long flags; #if DEBUG printk("stl_flushbuffer(tty=%x)\n", (int) tty); @@ -1445,17 +1565,7 @@ if (portp == (stlport_t *) NULL) return; - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - stl_ccrwait(portp); - stl_setreg(portp, CCR, CCR_TXFLUSHFIFO); - stl_ccrwait(portp); - portp->tx.tail = portp->tx.head; - BRDDISABLE(portp->brdnr); - restore_flags(flags); - + stl_flush(portp); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); @@ -1464,646 +1574,1308 @@ /*****************************************************************************/ /* - * These functions get/set/update the registers of the cd1400 UARTs. - * Access to the cd1400 registers is via an address/data io port pair. - * (Maybe should make this inline...) + * All board interrupts are vectored through here first. This code then + * calls off to the approrpriate board interrupt handlers. */ -static int stl_getreg(stlport_t *portp, int regnr) +static void stl_intr(int irq, void *dev_id, struct pt_regs *regs) { - outb((regnr + portp->uartaddr), portp->ioaddr); - return(inb(portp->ioaddr + EREG_DATA)); -} + stlbrd_t *brdp; + int i; -static void stl_setreg(stlport_t *portp, int regnr, int value) -{ - outb((regnr + portp->uartaddr), portp->ioaddr); - outb(value, portp->ioaddr + EREG_DATA); +#if DEBUG + printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); +#endif + + for (i = 0; (i < stl_nrbrds); i++) { + if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) + continue; + if (brdp->state == 0) + continue; + (* brdp->isr)(brdp); + } } -static int stl_updatereg(stlport_t *portp, int regnr, int value) +/*****************************************************************************/ + +/* + * Interrupt service routine for EasyIO board types. + */ + +static void stl_eiointr(stlbrd_t *brdp) { - outb((regnr + portp->uartaddr), portp->ioaddr); - if (inb(portp->ioaddr + EREG_DATA) != value) { - outb(value, portp->ioaddr + EREG_DATA); - return(1); - } - return(0); + stlpanel_t *panelp; + unsigned int iobase; + + panelp = brdp->panels[0]; + iobase = panelp->iobase; + while (inb(brdp->iostatus) & EIO_INTRPEND) + (* panelp->isr)(panelp, iobase); } /*****************************************************************************/ /* - * Transmit interrupt handler. This has gotta be fast! Handling TX - * chars is pretty simple, stuff as many as possible from the TX buffer - * into the cd1400 FIFO. Must also handle TX breaks here, since they - * are embedded as commands in the data stream. Oh no, had to use a goto! - * This could be optimized more, will do when I get time... - * In practice it is possible that interrupts are enabled but that the - * port has been hung up. Need to handle not having any TX buffer here, - * this is done by using the side effect that head and tail will also - * be NULL if the buffer has been freed. + * Interrupt service routine for ECH-AT board types. */ -static inline void stl_txisr(stlpanel_t *panelp, int ioaddr) +static void stl_echatintr(stlbrd_t *brdp) { - stlport_t *portp; - int len, stlen; - char *head, *tail; - unsigned char ioack, srer; + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr; -#if DEBUG - printk("stl_txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif + outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); - ioack = inb(ioaddr + EREG_TXACK); - if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPTX)) { - printk("STALLION: bad TX interrupt ack value=%x\n", ioack); - return; + while (inb(brdp->iostatus) & ECH_INTRPEND) { + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + } + } } - portp = panelp->ports[(ioack >> 3)]; + + outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); +} + +/*****************************************************************************/ /* - * Unfortunately we need to handle breaks in the data stream, since - * this is the only way to generate them on the cd1400. Do it now if - * a break is to be sent. + * Interrupt service routine for ECH-MCA board types. */ - if (portp->brklen != 0) { - if (portp->brklen > 0) { - outb((TDR + portp->uartaddr), ioaddr); - outb(ETC_CMD, (ioaddr + EREG_DATA)); - outb(ETC_STARTBREAK, (ioaddr + EREG_DATA)); - outb(ETC_CMD, (ioaddr + EREG_DATA)); - outb(ETC_DELAY, (ioaddr + EREG_DATA)); - outb(portp->brklen, (ioaddr + EREG_DATA)); - outb(ETC_CMD, (ioaddr + EREG_DATA)); - outb(ETC_STOPBREAK, (ioaddr + EREG_DATA)); - portp->brklen = -1; - goto stl_txalldone; - } else { - outb((COR2 + portp->uartaddr), ioaddr); - outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), (ioaddr + EREG_DATA)); - portp->brklen = 0; + +static void stl_echmcaintr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr; + + while (inb(brdp->iostatus) & ECH_INTRPEND) { + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + } } } +} - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); - if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { - set_bit(ASYI_TXLOW, &portp->istate); - queue_task_irq_off(&portp->tqueue, &tq_scheduler); - } +/*****************************************************************************/ - if (len == 0) { - outb((SRER + portp->uartaddr), ioaddr); - srer = inb(ioaddr + EREG_DATA); - if (srer & SRER_TXDATA) { - srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY; - } else { - srer &= ~(SRER_TXDATA | SRER_TXEMPTY); - clear_bit(ASYI_TXBUSY, &portp->istate); - } - outb(srer, (ioaddr + EREG_DATA)); - } else { - len = MIN(len, CD1400_TXFIFOSIZE); - portp->stats.txtotal += len; - stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); - outb((TDR + portp->uartaddr), ioaddr); - outsb((ioaddr + EREG_DATA), tail, stlen); - len -= stlen; - tail += stlen; - if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) - tail = portp->tx.buf; - if (len > 0) { - outsb((ioaddr + EREG_DATA), tail, len); - tail += len; +/* + * Interrupt service routine for ECH-PCI board types. + */ + +static void stl_echpciintr(stlbrd_t *brdp) +{ + stlpanel_t *panelp; + unsigned int ioaddr; + int bnknr, recheck; + + while (1) { + recheck = 0; + for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { + outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl); + ioaddr = brdp->bnkstataddr[bnknr]; + if (inb(ioaddr) & ECH_PNLINTRPEND) { + panelp = brdp->bnk2panel[bnknr]; + (* panelp->isr)(panelp, (ioaddr & 0xfffc)); + recheck++; + } } - portp->tx.tail = tail; + if (! recheck) + break; } - -stl_txalldone: - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); } /*****************************************************************************/ /* - * Receive character interrupt handler. Determine if we have good chars - * or bad chars and then process appropriately. Good chars are easy - * just shove the lot into the RX buffer and set all status byte to 0. - * If a bad RX char then process as required. This routine needs to be - * fast! In practice it is possible that we get an interrupt on a port - * that is closed. This can happen on hangups - since they completely - * shutdown a port not in user context. Need to handle this case. + * Service an off-level request for some channel. */ -static inline void stl_rxisr(stlpanel_t *panelp, int ioaddr) +static void stl_offintr(void *private) { stlport_t *portp; struct tty_struct *tty; - unsigned int ioack, len, buflen; - unsigned char status; - char ch; - static char unwanted[CD1400_RXFIFOSIZE]; + unsigned int oldsigs; + + portp = private; #if DEBUG - printk("stl_rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); + printk("stl_offintr(portp=%x)\n", (int) portp); #endif - ioack = inb(ioaddr + EREG_RXACK); - if ((ioack & panelp->ackmask) != 0) { - printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + if (portp == (stlport_t *) NULL) return; - } - portp = panelp->ports[(ioack >> 3)]; tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; - if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { - outb((RDCR + portp->uartaddr), ioaddr); - len = inb(ioaddr + EREG_DATA); - if ((tty == (struct tty_struct *) NULL) || (tty->flip.char_buf_ptr == (char *) NULL) || - ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { - outb((RDSR + portp->uartaddr), ioaddr); - insb((ioaddr + EREG_DATA), &unwanted[0], len); - portp->stats.rxlost += len; - portp->stats.rxtotal += len; - } else { - len = MIN(len, buflen); - if (len > 0) { - outb((RDSR + portp->uartaddr), ioaddr); - insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len); - memset(tty->flip.flag_buf_ptr, 0, len); - tty->flip.flag_buf_ptr += len; - tty->flip.char_buf_ptr += len; - tty->flip.count += len; - tty_schedule_flip(tty); - portp->stats.rxtotal += len; - } - } - } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) { - outb((RDSR + portp->uartaddr), ioaddr); - status = inb(ioaddr + EREG_DATA); - ch = inb(ioaddr + EREG_DATA); - if (status & ST_PARITY) - portp->stats.rxparity++; - if (status & ST_FRAMING) - portp->stats.rxframing++; - if (status & ST_OVERRUN) - portp->stats.rxoverrun++; - if (status & ST_BREAK) - portp->stats.rxbreaks++; - if (status & ST_SCHARMASK) { - if ((status & ST_SCHARMASK) == ST_SCHAR1) - portp->stats.txxon++; - if ((status & ST_SCHARMASK) == ST_SCHAR2) - portp->stats.txxoff++; - goto stl_rxalldone; - } - if ((tty != (struct tty_struct *) NULL) && ((portp->rxignoremsk & status) == 0)) { - if (portp->rxmarkmsk & status) { - if (status & ST_BREAK) { - status = TTY_BREAK; -#ifndef MODULE - if (portp->flags & ASYNC_SAK) { - do_SAK(tty); - BRDENABLE(portp->brdnr, portp->pagenr); - } -#endif - } else if (status & ST_PARITY) { - status = TTY_PARITY; - } else if (status & ST_FRAMING) { - status = TTY_FRAME; - } else if(status & ST_OVERRUN) { - status = TTY_OVERRUN; - } else { - status = 0; - } - } else { - status = 0; - } - if (tty->flip.char_buf_ptr != (char *) NULL) { - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - *tty->flip.flag_buf_ptr++ = status; - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; + if (test_bit(ASYI_TXLOW, &portp->istate)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { + clear_bit(ASYI_DCDCHANGE, &portp->istate); + oldsigs = portp->sigs; + portp->sigs = stl_getsignals(portp); + if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) + wake_up_interruptible(&portp->open_wait); + if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { + if (portp->flags & ASYNC_CHECK_CD) { + if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && + (portp->flags & ASYNC_CALLOUT_NOHUP))) { + tty_hangup(tty); } - tty_schedule_flip(tty); } } - } else { - printk("STALLION: bad RX interrupt ack value=%x\n", ioack); - return; } - -stl_rxalldone: - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); } /*****************************************************************************/ /* - * Modem interrupt handler. The is called when the modem signal line - * (DCD) has changed state. Leave most of the work to the off-level - * processing routine. + * Map in interrupt vector to this driver. Check that we don't + * already have this vector mapped, we might be sharing this + * interrupt across multiple boards. */ -static inline void stl_mdmisr(stlpanel_t *panelp, int ioaddr) +static int stl_mapirq(int irq) { - stlport_t *portp; - unsigned int ioack; - unsigned char misr; + int rc, i; #if DEBUG - printk("stl_mdmisr(panelp=%x)\n", (int) panelp); + printk("stl_mapirq(irq=%d)\n", irq); #endif - ioack = inb(ioaddr + EREG_MDACK); - if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) { - printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack); - return; + rc = 0; + for (i = 0; (i < stl_numintrs); i++) { + if (stl_gotintrs[i] == irq) + break; } - portp = panelp->ports[(ioack >> 3)]; - - outb((MISR + portp->uartaddr), ioaddr); - misr = inb(ioaddr + EREG_DATA); - if (misr & MISR_DCD) { - set_bit(ASYI_DCDCHANGE, &portp->istate); - queue_task_irq_off(&portp->tqueue, &tq_scheduler); - portp->stats.modem++; + if (i >= stl_numintrs) { + if (request_irq(irq, stl_intr, SA_INTERRUPT, stl_drvname, NULL) != 0) { + printk("STALLION: failed to register interrupt routine for irq=%d\n", irq); + rc = -ENODEV; + } else { + stl_gotintrs[stl_numintrs++] = irq; + } } - - outb((EOSRR + portp->uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); + return(rc); } /*****************************************************************************/ /* - * Interrupt handler for EIO and ECH boards. This code ain't all that - * pretty, but the idea is to make it as fast as possible. This code is - * well suited to be assemblerized :-) We don't use the general purpose - * register access functions here, for speed we will go strait to the - * io region. + * Initialize all the ports on a panel. */ -static void stl_intr(int irq, void *dev_id, struct pt_regs *regs) +static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) { - stlbrd_t *brdp; - stlpanel_t *panelp; - unsigned char svrtype; - int i, panelnr, iobase; + stlport_t *portp; + int chipmask, i; #if DEBUG - printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); + printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); #endif - panelp = (stlpanel_t *) NULL; - for (i = 0; (i < stl_nrbrds); ) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) { - i++; - continue; - } - if (brdp->state == 0) { - i++; - continue; - } -/* - * The following section of code handles the subtle differences - * between board types. It is sort of similar, but different - * enough to handle each separately. - */ - if (brdp->brdtype == BRD_EASYIO) { - if ((inb(brdp->iostatus) & EIO_INTRPEND) == 0) { - i++; - continue; - } - panelp = brdp->panels[0]; - iobase = panelp->iobase; - outb(SVRR, iobase); - svrtype = inb(iobase + EREG_DATA); - if (brdp->nrports > 4) { - outb((SVRR + 0x80), iobase); - svrtype |= inb(iobase + EREG_DATA); - } - } else if (brdp->brdtype == BRD_ECH) { - if ((inb(brdp->iostatus) & ECH_INTRPEND) == 0) { - i++; - continue; - } - outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { - panelp = brdp->panels[panelnr]; - iobase = panelp->iobase; - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - if (panelp->nrports > 8) { - iobase += 0x8; - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - } - } - if (panelnr >= brdp->nrpanels) { - i++; - continue; - } - outb(SVRR, iobase); - svrtype = inb(iobase + EREG_DATA); - outb((SVRR + 0x80), iobase); - svrtype |= inb(iobase + EREG_DATA); - } else if (brdp->brdtype == BRD_ECHPCI) { - iobase = brdp->ioaddr2; - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { - panelp = brdp->panels[panelnr]; - outb(panelp->pagenr, brdp->ioctrl); - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - if (panelp->nrports > 8) { - outb((panelp->pagenr + 1), brdp->ioctrl); - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - } - } - if (panelnr >= brdp->nrpanels) { - i++; - continue; - } - outb(SVRR, iobase); - svrtype = inb(iobase + EREG_DATA); - outb((SVRR + 0x80), iobase); - svrtype |= inb(iobase + EREG_DATA); - } else if (brdp->brdtype == BRD_ECHMC) { - if ((inb(brdp->iostatus) & ECH_INTRPEND) == 0) { - i++; - continue; - } - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { - panelp = brdp->panels[panelnr]; - iobase = panelp->iobase; - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - if (panelp->nrports > 8) { - iobase += 0x8; - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - } - } - if (panelnr >= brdp->nrpanels) { - i++; - continue; - } - outb(SVRR, iobase); - svrtype = inb(iobase + EREG_DATA); - outb((SVRR + 0x80), iobase); - svrtype |= inb(iobase + EREG_DATA); - } else { - printk("STALLION: unknown board type=%x\n", brdp->brdtype); - i++; - continue; - } + chipmask = stl_panelinit(brdp, panelp); /* - * We have determined what type of service is required for a - * port. From here on in the service of a port is the same no - * matter what the board type... - */ - if (svrtype & SVRR_RX) - stl_rxisr(panelp, iobase); - if (svrtype & SVRR_TX) - stl_txisr(panelp, iobase); - if (svrtype & SVRR_MDM) - stl_mdmisr(panelp, iobase); + * All UART's are initialized (if found!). Now go through and setup + * each ports data structures. + */ + for (i = 0; (i < panelp->nrports); i++) { + portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); + if (portp == (stlport_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlport_t)); + break; + } + memset(portp, 0, sizeof(stlport_t)); - if (brdp->brdtype == BRD_ECH) - outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); + portp->magic = STL_PORTMAGIC; + portp->portnr = i; + portp->brdnr = panelp->brdnr; + portp->panelnr = panelp->panelnr; + portp->uartp = panelp->uartp; + portp->clk = brdp->clk; + portp->baud_base = STL_BAUDBASE; + portp->close_delay = STL_CLOSEDELAY; + portp->closing_wait = 30 * HZ; + portp->normaltermios = stl_deftermios; + portp->callouttermios = stl_deftermios; + portp->tqueue.routine = stl_offintr; + portp->tqueue.data = portp; + portp->stats.brd = portp->brdnr; + portp->stats.panel = portp->panelnr; + portp->stats.port = portp->portnr; + panelp->ports[i] = portp; + stl_portinit(brdp, panelp, portp); } + + return(0); } /*****************************************************************************/ /* - * Service an off-level request for some channel. + * Try to find and initialize an EasyIO board. */ -static void stl_offintr(void *private) +static int stl_initeio(stlbrd_t *brdp) { - stlport_t *portp; - struct tty_struct *tty; - unsigned int oldsigs; + stlpanel_t *panelp; + unsigned int status; + int rc; - portp = private; #if DEBUG - printk("stl_offintr(portp=%x)\n", (int) portp); + printk("stl_initeio(brdp=%x)\n", (int) brdp); #endif - if (portp == (stlport_t *) NULL) - return; - tty = portp->tty; - if (tty == (struct tty_struct *) NULL) - return; - - if (test_bit(ASYI_TXLOW, &portp->istate)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + if (check_region(brdp->ioaddr1, 8)) { + printk("STALLION: Warning, unit %d I/O address %x conflicts with another device\n", + brdp->brdnr, brdp->ioaddr1); } - if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { - clear_bit(ASYI_DCDCHANGE, &portp->istate); - oldsigs = portp->sigs; - portp->sigs = stl_getsignals(portp); - if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) - wake_up_interruptible(&portp->open_wait); - if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { - if (portp->flags & ASYNC_CHECK_CD) { - if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && - (portp->flags & ASYNC_CALLOUT_NOHUP))) { - tty_hangup(tty); - } - } + + brdp->ioctrl = brdp->ioaddr1 + 1; + brdp->iostatus = brdp->ioaddr1 + 2; + brdp->clk = CD1400_CLK; + brdp->isr = stl_eiointr; + + status = inb(brdp->iostatus); + switch (status & EIO_IDBITMASK) { + case EIO_8PORTM: + brdp->clk = CD1400_CLK8M; + /* fall thru */ + case EIO_8PORTRS: + case EIO_8PORTDI: + brdp->nrports = 8; + break; + case EIO_4PORTRS: + brdp->nrports = 4; + break; + case EIO_MK3: + switch (status & EIO_BRDMASK) { + case ID_BRD4: + brdp->nrports = 4; + break; + case ID_BRD8: + brdp->nrports = 8; + break; + case ID_BRD16: + brdp->nrports = 16; + break; + default: + return(-ENODEV); } + brdp->ioctrl++; + break; + default: + return(-ENODEV); } -} -/*****************************************************************************/ + request_region(brdp->ioaddr1, 8, "serial(EIO)"); /* - * Wait for the command register to be ready. We will poll this, - * since it won't usually take too long to be ready. + * Check that the supplied IRQ is good and then use it to setup the + * programmable interrupt bits on EIO board. Also set the edge/level + * triggered interrupt bit. */ - -static void stl_ccrwait(stlport_t *portp) -{ - int i; - - for (i = 0; (i < CCR_MAXWAIT); i++) { - if (stl_getreg(portp, CCR) == 0) { - return; - } + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); + return(-EINVAL); } + outb((stl_vecmap[brdp->irq] | ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), brdp->ioctrl); - printk("STALLION: cd1400 device not responding, port=%d panel=%d brd=%d\n", portp->portnr, portp->panelnr, portp->brdnr); + panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); + if (panelp == (stlpanel_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t)); + return(-ENOMEM); + } + memset(panelp, 0, sizeof(stlpanel_t)); + + panelp->magic = STL_PANELMAGIC; + panelp->brdnr = brdp->brdnr; + panelp->panelnr = 0; + panelp->nrports = brdp->nrports; + panelp->iobase = brdp->ioaddr1; + panelp->hwid = status; + if ((status & EIO_IDBITMASK) == EIO_MK3) { + panelp->uartp = (void *) &stl_sc26198uart; + panelp->isr = stl_sc26198intr; + } else { + panelp->uartp = (void *) &stl_cd1400uart; + panelp->isr = stl_cd1400intr; + } + + brdp->panels[0] = panelp; + brdp->nrpanels = 1; + brdp->state |= BRD_FOUND; + brdp->hwid = status; + rc = stl_mapirq(brdp->irq); + return(rc); } /*****************************************************************************/ /* - * Set up the cd1400 registers for a port based on the termios port - * settings. + * Try to find an ECH board and initialize it. This code is capable of + * dealing with all types of ECH board. */ -static void stl_setport(stlport_t *portp, struct termios *tiosp) +static int stl_initech(stlbrd_t *brdp) { - stlbrd_t *brdp; - unsigned long flags; - unsigned int clkdiv, baudrate; - unsigned char cor1, cor2, cor3; - unsigned char cor4, cor5, ccr; - unsigned char srer, sreron, sreroff; - unsigned char mcor1, mcor2, rtpr; - unsigned char clk, div; + stlpanel_t *panelp; + unsigned int status, nxtid, ioaddr, conflict; + int panelnr, banknr, i; - cor1 = 0; - cor2 = 0; - cor3 = 0; - cor4 = 0; - cor5 = 0; - ccr = 0; - rtpr = 0; - clk = 0; - div = 0; - mcor1 = 0; - mcor2 = 0; - sreron = 0; - sreroff = 0; +#if DEBUG + printk("stl_initech(brdp=%x)\n", (int) brdp); +#endif - brdp = stl_brds[portp->brdnr]; - if (brdp == (stlbrd_t *) NULL) - return; + status = 0; + conflict = 0; /* - * Set up the RX char ignore mask with those RX error types we - * can ignore. We can get the cd1400 to help us out a little here, - * it will ignore parity errors and breaks for us. + * Set up the initial board register contents for boards. This varies a + * bit between the different board types. So we need to handle each + * separately. Also do a check that the supplied IRQ is good. */ - portp->rxignoremsk = 0; - if (tiosp->c_iflag & IGNPAR) { - portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN); - cor1 |= COR1_PARIGNORE; - } - if (tiosp->c_iflag & IGNBRK) { - portp->rxignoremsk |= ST_BREAK; - cor4 |= COR4_IGNBRK; - } + if (brdp->brdtype == BRD_ECH) { + brdp->isr = stl_echatintr; + brdp->ioctrl = brdp->ioaddr1 + 1; + brdp->iostatus = brdp->ioaddr1 + 1; + status = inb(brdp->iostatus); + if ((status & ECH_IDBITMASK) != ECH_ID) + return(-ENODEV); - portp->rxmarkmsk = ST_OVERRUN; - if (tiosp->c_iflag & (INPCK | PARMRK)) - portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING); - if (tiosp->c_iflag & BRKINT) - portp->rxmarkmsk |= ST_BREAK; + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); + return(-EINVAL); + } + status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); + status |= (stl_vecmap[brdp->irq] << 1); + outb((status | ECH_BRDRESET), brdp->ioaddr1); + brdp->ioctrlval = ECH_INTENABLE | ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); + outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); + conflict = check_region(brdp->ioaddr1, 2) ? brdp->ioaddr1 : 0; + if (conflict == 0) + conflict = check_region(brdp->ioaddr2, 32) ? brdp->ioaddr2 : 0; + request_region(brdp->ioaddr1, 2, "serial(EC8/32)"); + request_region(brdp->ioaddr2, 32, "serial(EC8/32-secondary)"); + outb(status, brdp->ioaddr1); + } else if (brdp->brdtype == BRD_ECHMC) { + brdp->isr = stl_echmcaintr; + brdp->ioctrl = brdp->ioaddr1 + 0x20; + brdp->iostatus = brdp->ioctrl; + status = inb(brdp->iostatus); + if ((status & ECH_IDBITMASK) != ECH_ID) + return(-ENODEV); -/* - * Go through the char size, parity and stop bits and set all the - * option register appropriately. - */ - switch (tiosp->c_cflag & CSIZE) { - case CS5: - cor1 |= COR1_CHL5; - break; - case CS6: - cor1 |= COR1_CHL6; - break; - case CS7: - cor1 |= COR1_CHL7; - break; - default: - cor1 |= COR1_CHL8; - break; + if ((brdp->irq < 0) || (brdp->irq > 15) || + (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { + printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); + return(-EINVAL); + } + outb(ECHMC_BRDRESET, brdp->ioctrl); + outb(ECHMC_INTENABLE, brdp->ioctrl); + conflict = check_region(brdp->ioaddr1, 64) ? brdp->ioaddr1 : 0; + request_region(brdp->ioaddr1, 64, "serial(EC8/32-MC)"); + } else if (brdp->brdtype == BRD_ECHPCI) { + brdp->isr = stl_echpciintr; + brdp->ioctrl = brdp->ioaddr1 + 2; + conflict = check_region(brdp->ioaddr1, 4) ? brdp->ioaddr1 : 0; + if (conflict == 0) + conflict = check_region(brdp->ioaddr2, 8) ? brdp->ioaddr2 : 0; + request_region(brdp->ioaddr1, 4, "serial(EC8/32-PCI)"); + request_region(brdp->ioaddr2, 8, "serial(EC8/32-PCI-secondary)"); } - if (tiosp->c_cflag & CSTOPB) - cor1 |= COR1_STOP2; - else - cor1 |= COR1_STOP1; - - if (tiosp->c_cflag & PARENB) { - if (tiosp->c_cflag & PARODD) - cor1 |= (COR1_PARENB | COR1_PARODD); - else - cor1 |= (COR1_PARENB | COR1_PAREVEN); - } else { - cor1 |= COR1_PARNONE; + if (conflict) { + printk("STALLION: Warning, unit %d I/O address %x conflicts with another device\n", + brdp->brdnr, conflict); } -/* - * Set the RX FIFO threshold at 6 chars. This gives a bit of breathing - * space for hardware flow control and the like. This should be set to - * VMIN. Also here we will set the RX data timeout to 10ms - this should - * really be based on VTIME. - */ - cor3 |= FIFO_RXTHRESHOLD; - rtpr = 2; + brdp->clk = CD1400_CLK; + brdp->hwid = status; /* - * Calculate the baud rate timers. For now we will just assume that - * the input and output baud are the same. Could have used a baud - * table here, but this way we can generate virtually any baud rate - * we like! + * Scan through the secondary io address space looking for panels. + * As we find'em allocate and initialize panel structures for each. */ - baudrate = tiosp->c_cflag & CBAUD; - if (baudrate & CBAUDEX) { - baudrate &= ~CBAUDEX; - if ((baudrate < 1) || (baudrate > 2)) - tiosp->c_cflag &= ~CBAUDEX; - else - baudrate += 15; - } - baudrate = stl_baudrates[baudrate]; - if ((tiosp->c_cflag & CBAUD) == B38400) { - if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baudrate = 57600; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baudrate = 115200; - else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) - baudrate = (portp->baud_base / portp->custom_divisor); - } - if (baudrate > STL_MAXBAUD) - baudrate = STL_MAXBAUD; + ioaddr = brdp->ioaddr2; + banknr = 0; + panelnr = 0; + nxtid = 0; - if (baudrate > 0) { - for (clk = 0; (clk < CD1400_NUMCLKS); clk++) { - clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate); - if (clkdiv < 0x100) - break; + for (i = 0; (i < STL_MAXPANELS); i++) { + if (brdp->brdtype == BRD_ECHPCI) { + outb(nxtid, brdp->ioctrl); + ioaddr = brdp->ioaddr2; + } + status = inb(ioaddr + ECH_PNLSTATUS); + if ((status & ECH_PNLIDMASK) != nxtid) + break; + panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); + if (panelp == (stlpanel_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t)); + break; + } + memset(panelp, 0, sizeof(stlpanel_t)); + panelp->magic = STL_PANELMAGIC; + panelp->brdnr = brdp->brdnr; + panelp->panelnr = panelnr; + panelp->iobase = ioaddr; + panelp->pagenr = nxtid; + panelp->hwid = status; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; + + if (status & ECH_PNLXPID) { + panelp->uartp = (void *) &stl_sc26198uart; + panelp->isr = stl_sc26198intr; + if (status & ECH_PNL16PORT) { + panelp->nrports = 16; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + 4 + ECH_PNLSTATUS; + } else { + panelp->nrports = 8; + } + } else { + panelp->uartp = (void *) &stl_cd1400uart; + panelp->isr = stl_cd1400intr; + if (status & ECH_PNL16PORT) { + if ((brdp->nrports + 16) > 32) + break; + panelp->nrports = 16; + panelp->ackmask = 0x80; + if (brdp->brdtype != BRD_ECHPCI) + ioaddr += EREG_BANKSIZE; + brdp->bnk2panel[banknr] = panelp; + brdp->bnkpageaddr[banknr] = ++nxtid; + brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; + } else { + panelp->nrports = 8; + panelp->ackmask = 0xc0; + } } - div = (unsigned char) clkdiv; - } -/* - * Check what form of modem signaling is required and set it up. - */ - if ((tiosp->c_cflag & CLOCAL) == 0) { - mcor1 |= MCOR1_DCD; - mcor2 |= MCOR2_DCD; - sreron |= SRER_MODEM; - portp->flags |= ASYNC_CHECK_CD; - } else { - portp->flags &= ~ASYNC_CHECK_CD; + nxtid++; + ioaddr += EREG_BANKSIZE; + brdp->nrports += panelp->nrports; + brdp->panels[panelnr++] = panelp; + if (ioaddr >= (brdp->ioaddr2 + 0x20)) + break; } + brdp->nrpanels = panelnr; + brdp->nrbnks = banknr; + if (brdp->brdtype == BRD_ECH) + outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); + + brdp->state |= BRD_FOUND; + i = stl_mapirq(brdp->irq); + return(i); +} + +/*****************************************************************************/ + /* - * Setup cd1400 enhanced modes if we can. In particular we want to - * handle as much of the flow control as possible automatically. As - * well as saving a few CPU cycles it will also greatly improve flow - * control reliability. + * Initialize and configure the specified board. + * Scan through all the boards in the configuration and see what we + * can find. Handle EIO and the ECH boards a little differently here + * since the initial search and setup is very different. */ - if (tiosp->c_iflag & IXON) { - cor2 |= COR2_TXIBE; - cor3 |= COR3_SCD12; - if (tiosp->c_iflag & IXANY) - cor2 |= COR2_IXM; - } + +static int stl_brdinit(stlbrd_t *brdp) +{ + int i; + +#if DEBUG + printk("stl_brdinit(brdp=%x)\n", (int) brdp); +#endif + + switch (brdp->brdtype) { + case BRD_EASYIO: + stl_initeio(brdp); + break; + case BRD_ECH: + case BRD_ECHMC: + case BRD_ECHPCI: + stl_initech(brdp); + break; + default: + printk("STALLION: unit=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype); + return(ENODEV); + } + + stl_brds[brdp->brdnr] = brdp; + if ((brdp->state & BRD_FOUND) == 0) { + printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq); + return(ENODEV); + } + + for (i = 0; (i < STL_MAXPANELS); i++) + if (brdp->panels[i] != (stlpanel_t *) NULL) + stl_initports(brdp, brdp->panels[i]); + + printk("STALLION: %s found, unit=%d io=%x irq=%d nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, brdp->nrports); + return(0); +} + +/*****************************************************************************/ + +/* + * Find any ECH-PCI boards that might be installed. Initialize each + * one as it is found. + */ + +#ifdef CONFIG_PCI + +static int stl_findpcibrds() +{ + stlbrd_t *brdp; + unsigned char busnr, devnr, irq; + unsigned short class; + unsigned int ioaddr; + int i, rc; + +#if DEBUG + printk("stl_findpcibrds()\n"); +#endif + + if (pcibios_present()) { + for (i = 0; (i < STL_MAXBRDS); i++) { + if (pcibios_find_device(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, i, &busnr, &devnr)) + if (pcibios_find_device(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, i, &busnr, &devnr)) + break; + +/* + * Found a device on the PCI bus that has our vendor and + * device ID. Need to check now that it is really us. + */ + if ((rc = pcibios_read_config_word(busnr, devnr, PCI_CLASS_DEVICE, &class))) { + printk("STALLION: failed to read class type from PCI board, errno=%x\n", rc); + continue; + } + if (class == PCI_CLASS_STORAGE_IDE) + continue; + + if (stl_nrbrds >= STL_MAXBRDS) { + printk("STALLION: too many boards found, maximum supported %d\n", STL_MAXBRDS); + break; + } + +/* + * We have a Stallion board. Allocate a board structure + * and initialize it. Read its IO and IRQ resources + * from conf space. + */ + brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); + if (brdp == (stlbrd_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t)); + return(-ENOMEM); + } + memset(brdp, 0, sizeof(stlbrd_t)); + brdp->magic = STL_BOARDMAGIC; + brdp->brdnr = stl_nrbrds++; + brdp->brdtype = BRD_ECHPCI; + + if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_0, &ioaddr))) { + printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc); + continue; + } + brdp->ioaddr2 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK); + + if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_1, &ioaddr))) { + printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc); + continue; + } + brdp->ioaddr1 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK); +#if DEBUG + printk("%s(%d): BAR0=%x BAR1=%x\n", __FILE__, __LINE__, brdp->ioaddr2, brdp->ioaddr1); +#endif + + if ((rc = pcibios_read_config_byte(busnr, devnr, PCI_INTERRUPT_LINE, &irq))) { + printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc); + continue; + } + brdp->irq = irq; + + stl_brdinit(brdp); + } + } + + return(0); +} + +#endif + +/*****************************************************************************/ + +/* + * Scan through all the boards in the configuration and see what we + * can find. Handle EIO and the ECH boards a little differently here + * since the initial search and setup is too different. + */ + +static int stl_initbrds() +{ + stlbrd_t *brdp; + stlconf_t *confp; + int i; + +#if DEBUG + printk("stl_initbrds()\n"); +#endif + + if (stl_nrbrds > STL_MAXBRDS) { + printk("STALLION: too many boards in configuration table, truncating to %d\n", STL_MAXBRDS); + stl_nrbrds = STL_MAXBRDS; + } + +/* + * Firstly scan the list of static boards configured. Allocate + * resources and initialize the boards as found. + */ + for (i = 0; (i < stl_nrbrds); i++) { + confp = &stl_brdconf[i]; + brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); + if (brdp == (stlbrd_t *) NULL) { + printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t)); + return(-ENOMEM); + } + memset(brdp, 0, sizeof(stlbrd_t)); + + brdp->magic = STL_BOARDMAGIC; + brdp->brdnr = i; + brdp->brdtype = confp->brdtype; + brdp->ioaddr1 = confp->ioaddr1; + brdp->ioaddr2 = confp->ioaddr2; + brdp->irq = confp->irq; + brdp->irqtype = confp->irqtype; + stl_brdinit(brdp); + } + +#ifdef CONFIG_PCI +/* + * If the PCI BIOS support is compiled in then let's go looking for + * ECH-PCI boards. + */ + stl_findpcibrds(); +#endif + + return(0); +} + +/*****************************************************************************/ + +/* + * Return the board stats structure to user app. + */ + +static int stl_getbrdstats(combrd_t *bp) +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + int i; + + copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)); + if (stl_brdstats.brd >= STL_MAXBRDS) + return(-ENODEV); + brdp = stl_brds[stl_brdstats.brd]; + if (brdp == (stlbrd_t *) NULL) + return(-ENODEV); + + memset(&stl_brdstats, 0, sizeof(combrd_t)); + stl_brdstats.brd = brdp->brdnr; + stl_brdstats.type = brdp->brdtype; + stl_brdstats.hwid = brdp->hwid; + stl_brdstats.state = brdp->state; + stl_brdstats.ioaddr = brdp->ioaddr1; + stl_brdstats.ioaddr2 = brdp->ioaddr2; + stl_brdstats.irq = brdp->irq; + stl_brdstats.nrpanels = brdp->nrpanels; + stl_brdstats.nrports = brdp->nrports; + for (i = 0; (i < brdp->nrpanels); i++) { + panelp = brdp->panels[i]; + stl_brdstats.panels[i].panel = i; + stl_brdstats.panels[i].hwid = panelp->hwid; + stl_brdstats.panels[i].nrports = panelp->nrports; + } + + copy_to_user(bp, &stl_brdstats, sizeof(combrd_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Resolve the referenced port number into a port struct pointer. + */ + +static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) +{ + stlbrd_t *brdp; + stlpanel_t *panelp; + + if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) + return((stlport_t *) NULL); + brdp = stl_brds[brdnr]; + if (brdp == (stlbrd_t *) NULL) + return((stlport_t *) NULL); + if ((panelnr < 0) || (panelnr >= brdp->nrpanels)) + return((stlport_t *) NULL); + panelp = brdp->panels[panelnr]; + if (panelp == (stlpanel_t *) NULL) + return((stlport_t *) NULL); + if ((portnr < 0) || (portnr >= panelp->nrports)) + return((stlport_t *) NULL); + return(panelp->ports[portnr]); +} + +/*****************************************************************************/ + +/* + * Return the port stats structure to user app. A NULL port struct + * pointer passed in means that we need to find out from the app + * what port to get stats for (used through board control device). + */ + +static int stl_getportstats(stlport_t *portp, comstats_t *cp) +{ + unsigned char *head, *tail; + unsigned long flags; + + if (portp == (stlport_t *) NULL) { + copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); + portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + } + + portp->stats.state = portp->istate; + portp->stats.flags = portp->flags; + portp->stats.hwid = portp->hwid; + + portp->stats.ttystate = 0; + portp->stats.cflags = 0; + portp->stats.iflags = 0; + portp->stats.oflags = 0; + portp->stats.lflags = 0; + portp->stats.rxbuffered = 0; + + save_flags(flags); + cli(); + if (portp->tty != (struct tty_struct *) NULL) { + if (portp->tty->driver_data == portp) { + portp->stats.ttystate = portp->tty->flags; + portp->stats.rxbuffered = portp->tty->flip.count; + if (portp->tty->termios != (struct termios *) NULL) { + portp->stats.cflags = portp->tty->termios->c_cflag; + portp->stats.iflags = portp->tty->termios->c_iflag; + portp->stats.oflags = portp->tty->termios->c_oflag; + portp->stats.lflags = portp->tty->termios->c_lflag; + } + } + } + restore_flags(flags); + + head = portp->tx.head; + tail = portp->tx.tail; + portp->stats.txbuffered = ((head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head))); + + portp->stats.signals = (unsigned long) stl_getsignals(portp); + + copy_to_user(cp, &portp->stats, sizeof(comstats_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Clear the port stats structure. We also return it zeroed out... + */ + +static int stl_clrportstats(stlport_t *portp, comstats_t *cp) +{ + if (portp == (stlport_t *) NULL) { + copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); + portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + } + + memset(&portp->stats, 0, sizeof(comstats_t)); + portp->stats.brd = portp->brdnr; + portp->stats.panel = portp->panelnr; + portp->stats.port = portp->portnr; + copy_to_user(cp, &portp->stats, sizeof(comstats_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Return the entire driver ports structure to a user app. + */ + +static int stl_getportstruct(unsigned long arg) +{ + stlport_t *portp; + + copy_from_user(&stl_dummyport, (void *) arg, sizeof(stlport_t)); + portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr, + stl_dummyport.portnr); + if (portp == (stlport_t *) NULL) + return(-ENODEV); + copy_to_user((void *) arg, portp, sizeof(stlport_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * Return the entire driver board structure to a user app. + */ + +static int stl_getbrdstruct(unsigned long arg) +{ + stlbrd_t *brdp; + + copy_from_user(&stl_dummybrd, (void *) arg, sizeof(stlbrd_t)); + if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) + return(-ENODEV); + brdp = stl_brds[stl_dummybrd.brdnr]; + if (brdp == (stlbrd_t *) NULL) + return(-ENODEV); + copy_to_user((void *) arg, brdp, sizeof(stlbrd_t)); + return(0); +} + +/*****************************************************************************/ + +/* + * The "staliomem" device is also required to do some special operations + * on the board and/or ports. In this driver it is mostly used for stats + * collection. + */ + +static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) +{ + int brdnr, rc; + +#if DEBUG + printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, (int) fp, cmd, (int) arg); +#endif + + brdnr = MINOR(ip->i_rdev); + if (brdnr >= STL_MAXBRDS) + return(-ENODEV); + rc = 0; + + switch (cmd) { + case COM_GETPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0) + rc = stl_getportstats((stlport_t *) NULL, (comstats_t *) arg); + break; + case COM_CLRPORTSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0) + rc = stl_clrportstats((stlport_t *) NULL, (comstats_t *) arg); + break; + case COM_GETBRDSTATS: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(combrd_t))) == 0) + rc = stl_getbrdstats((combrd_t *) arg); + break; + case COM_READPORT: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlport_t))) == 0) + rc = stl_getportstruct(arg); + break; + case COM_READBOARD: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlbrd_t))) == 0) + rc = stl_getbrdstruct(arg); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + + return(rc); +} + +/*****************************************************************************/ + +int stl_init(void) +{ + printk(KERN_INFO "%s: version %s\n", stl_drvname, stl_drvversion); + + stl_initbrds(); + +/* + * Allocate a temporary write buffer. + */ + stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE); + if (stl_tmpwritebuf == (char *) NULL) + printk("STALLION: failed to allocate memory (size=%d)\n", STL_TXBUFSIZE); + +/* + * Set up a character driver for per board stuff. This is mainly used + * to do stats ioctls on the ports. + */ + if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) + printk("STALLION: failed to register serial board device\n"); + +/* + * Set up the tty driver structure and register us as a driver. + * Also setup the callout tty device. + */ + memset(&stl_serial, 0, sizeof(struct tty_driver)); + stl_serial.magic = TTY_DRIVER_MAGIC; + stl_serial.name = stl_serialname; + stl_serial.major = STL_SERIALMAJOR; + stl_serial.minor_start = 0; + stl_serial.num = STL_MAXBRDS * STL_MAXPORTS; + stl_serial.type = TTY_DRIVER_TYPE_SERIAL; + stl_serial.subtype = STL_DRVTYPSERIAL; + stl_serial.init_termios = stl_deftermios; + stl_serial.flags = TTY_DRIVER_REAL_RAW; + stl_serial.refcount = &stl_refcount; + stl_serial.table = stl_ttys; + stl_serial.termios = stl_termios; + stl_serial.termios_locked = stl_termioslocked; + + stl_serial.open = stl_open; + stl_serial.close = stl_close; + stl_serial.write = stl_write; + stl_serial.put_char = stl_putchar; + stl_serial.flush_chars = stl_flushchars; + stl_serial.write_room = stl_writeroom; + stl_serial.chars_in_buffer = stl_charsinbuffer; + stl_serial.ioctl = stl_ioctl; + stl_serial.set_termios = stl_settermios; + stl_serial.throttle = stl_throttle; + stl_serial.unthrottle = stl_unthrottle; + stl_serial.stop = stl_stop; + stl_serial.start = stl_start; + stl_serial.hangup = stl_hangup; + stl_serial.flush_buffer = stl_flushbuffer; + + stl_callout = stl_serial; + stl_callout.name = stl_calloutname; + stl_callout.major = STL_CALLOUTMAJOR; + stl_callout.subtype = STL_DRVTYPCALLOUT; + + if (tty_register_driver(&stl_serial)) + printk("STALLION: failed to register serial driver\n"); + if (tty_register_driver(&stl_callout)) + printk("STALLION: failed to register callout driver\n"); + + return(0); +} + +/*****************************************************************************/ +/* CD1400 HARDWARE FUNCTIONS */ +/*****************************************************************************/ + +/* + * These functions get/set/update the registers of the cd1400 UARTs. + * Access to the cd1400 registers is via an address/data io port pair. + * (Maybe should make this inline...) + */ + +static int stl_cd1400getreg(stlport_t *portp, int regnr) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + return(inb(portp->ioaddr + EREG_DATA)); +} + +static void stl_cd1400setreg(stlport_t *portp, int regnr, int value) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + outb(value, portp->ioaddr + EREG_DATA); +} + +static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value) +{ + outb((regnr + portp->uartaddr), portp->ioaddr); + if (inb(portp->ioaddr + EREG_DATA) != value) { + outb(value, portp->ioaddr + EREG_DATA); + return(1); + } + return(0); +} + +/*****************************************************************************/ + +/* + * Inbitialize the UARTs in a panel. We don't care what sort of board + * these ports are on - since the port io registers are almost + * identical when dealing with ports. + */ + +static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) +{ + unsigned int gfrcr; + int chipmask, i, j; + int nrchips, uartaddr, ioaddr; + +#if DEBUG + printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); +#endif + + BRDENABLE(panelp->brdnr, panelp->pagenr); + +/* + * Check that each chip is present and started up OK. + */ + chipmask = 0; + nrchips = panelp->nrports / CD1400_PORTS; + for (i = 0; (i < nrchips); i++) { + if (brdp->brdtype == BRD_ECHPCI) { + outb((panelp->pagenr + (i >> 1)), brdp->ioctrl); + ioaddr = panelp->iobase; + } else { + ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1)); + } + uartaddr = (i & 0x01) ? 0x080 : 0; + outb((GFRCR + uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); + outb((CCR + uartaddr), ioaddr); + outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); + outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); + outb((GFRCR + uartaddr), ioaddr); + for (j = 0; (j < CCR_MAXWAIT); j++) { + if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0) + break; + } + if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) { + printk("STALLION: cd1400 not responding, brd=%d panel=%d chip=%d\n", panelp->brdnr, panelp->panelnr, i); + continue; + } + chipmask |= (0x1 << i); + outb((PPR + uartaddr), ioaddr); + outb(PPR_SCALAR, (ioaddr + EREG_DATA)); + } + + BRDDISABLE(panelp->brdnr); + return(chipmask); +} + +/*****************************************************************************/ + +/* + * Initialize hardware specific port registers. + */ + +static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) +{ +#if DEBUG + printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", + (int) brdp, (int) panelp, (int) portp); +#endif + + if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || (portp == (stlport_t *) NULL)) + return; + + portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || + (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); + portp->uartaddr = (portp->portnr & 0x04) << 5; + portp->pagenr = panelp->pagenr + (portp->portnr >> 3); + + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); + portp->hwid = stl_cd1400getreg(portp, GFRCR); + BRDDISABLE(portp->brdnr); +} + +/*****************************************************************************/ + +/* + * Wait for the command register to be ready. We will poll this, + * since it won't usually take too long to be ready. + */ + +static void stl_cd1400ccrwait(stlport_t *portp) +{ + int i; + + for (i = 0; (i < CCR_MAXWAIT); i++) { + if (stl_cd1400getreg(portp, CCR) == 0) { + return; + } + } + + printk("STALLION: cd1400 device not responding, port=%d panel=%d brd=%d\n", portp->portnr, portp->panelnr, portp->brdnr); +} + +/*****************************************************************************/ + +/* + * Set up the cd1400 registers for a port based on the termios port + * settings. + */ + +static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) +{ + stlbrd_t *brdp; + unsigned long flags; + unsigned int clkdiv, baudrate; + unsigned char cor1, cor2, cor3; + unsigned char cor4, cor5, ccr; + unsigned char srer, sreron, sreroff; + unsigned char mcor1, mcor2, rtpr; + unsigned char clk, div; + + cor1 = 0; + cor2 = 0; + cor3 = 0; + cor4 = 0; + cor5 = 0; + ccr = 0; + rtpr = 0; + clk = 0; + div = 0; + mcor1 = 0; + mcor2 = 0; + sreron = 0; + sreroff = 0; + + brdp = stl_brds[portp->brdnr]; + if (brdp == (stlbrd_t *) NULL) + return; + +/* + * Set up the RX char ignore mask with those RX error types we + * can ignore. We can get the cd1400 to help us out a little here, + * it will ignore parity errors and breaks for us. + */ + portp->rxignoremsk = 0; + if (tiosp->c_iflag & IGNPAR) { + portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN); + cor1 |= COR1_PARIGNORE; + } + if (tiosp->c_iflag & IGNBRK) { + portp->rxignoremsk |= ST_BREAK; + cor4 |= COR4_IGNBRK; + } + + portp->rxmarkmsk = ST_OVERRUN; + if (tiosp->c_iflag & (INPCK | PARMRK)) + portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING); + if (tiosp->c_iflag & BRKINT) + portp->rxmarkmsk |= ST_BREAK; + +/* + * Go through the char size, parity and stop bits and set all the + * option register appropriately. + */ + switch (tiosp->c_cflag & CSIZE) { + case CS5: + cor1 |= COR1_CHL5; + break; + case CS6: + cor1 |= COR1_CHL6; + break; + case CS7: + cor1 |= COR1_CHL7; + break; + default: + cor1 |= COR1_CHL8; + break; + } + + if (tiosp->c_cflag & CSTOPB) + cor1 |= COR1_STOP2; + else + cor1 |= COR1_STOP1; + + if (tiosp->c_cflag & PARENB) { + if (tiosp->c_cflag & PARODD) + cor1 |= (COR1_PARENB | COR1_PARODD); + else + cor1 |= (COR1_PARENB | COR1_PAREVEN); + } else { + cor1 |= COR1_PARNONE; + } + +/* + * Set the RX FIFO threshold at 6 chars. This gives a bit of breathing + * space for hardware flow control and the like. This should be set to + * VMIN. Also here we will set the RX data timeout to 10ms - this should + * really be based on VTIME. + */ + cor3 |= FIFO_RXTHRESHOLD; + rtpr = 2; + +/* + * Calculate the baud rate timers. For now we will just assume that + * the input and output baud are the same. Could have used a baud + * table here, but this way we can generate virtually any baud rate + * we like! + */ + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 2)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + baudrate = stl_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (portp->baud_base / portp->custom_divisor); + } + if (baudrate > STL_MAXBAUD) + baudrate = STL_MAXBAUD; + + if (baudrate > 0) { + for (clk = 0; (clk < CD1400_NUMCLKS); clk++) { + clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate); + if (clkdiv < 0x100) + break; + } + div = (unsigned char) clkdiv; + } + +/* + * Check what form of modem signaling is required and set it up. + */ + if ((tiosp->c_cflag & CLOCAL) == 0) { + mcor1 |= MCOR1_DCD; + mcor2 |= MCOR2_DCD; + sreron |= SRER_MODEM; + portp->flags |= ASYNC_CHECK_CD; + } else { + portp->flags &= ~ASYNC_CHECK_CD; + } + +/* + * Setup cd1400 enhanced modes if we can. In particular we want to + * handle as much of the flow control as possible automatically. As + * well as saving a few CPU cycles it will also greatly improve flow + * control reliability. + */ + if (tiosp->c_iflag & IXON) { + cor2 |= COR2_TXIBE; + cor3 |= COR3_SCD12; + if (tiosp->c_iflag & IXANY) + cor2 |= COR2_IXM; + } if (tiosp->c_cflag & CRTSCTS) { cor2 |= COR2_CTSAE; @@ -2111,89 +2883,332 @@ } /* - * All register cd1400 register values calculated so go through and set + * All cd1400 register values calculated so go through and set * them all up. */ #if DEBUG - printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr); - printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", cor1, cor2, cor3, cor4, cor5); - printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", mcor1, mcor2, rtpr, sreron, sreroff); - printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); - printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); + printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr); + printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", cor1, cor2, cor3, cor4, cor5); + printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", mcor1, mcor2, rtpr, sreron, sreroff); + printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); + printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); + srer = stl_cd1400getreg(portp, SRER); + stl_cd1400setreg(portp, SRER, 0); + if (stl_cd1400updatereg(portp, COR1, cor1)) + ccr = 1; + if (stl_cd1400updatereg(portp, COR2, cor2)) + ccr = 1; + if (stl_cd1400updatereg(portp, COR3, cor3)) + ccr = 1; + if (ccr) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_CORCHANGE); + } + stl_cd1400setreg(portp, COR4, cor4); + stl_cd1400setreg(portp, COR5, cor5); + stl_cd1400setreg(portp, MCOR1, mcor1); + stl_cd1400setreg(portp, MCOR2, mcor2); + if (baudrate > 0) { + stl_cd1400setreg(portp, TCOR, clk); + stl_cd1400setreg(portp, TBPR, div); + stl_cd1400setreg(portp, RCOR, clk); + stl_cd1400setreg(portp, RBPR, div); + } + stl_cd1400setreg(portp, SCHR1, tiosp->c_cc[VSTART]); + stl_cd1400setreg(portp, SCHR2, tiosp->c_cc[VSTOP]); + stl_cd1400setreg(portp, SCHR3, tiosp->c_cc[VSTART]); + stl_cd1400setreg(portp, SCHR4, tiosp->c_cc[VSTOP]); + stl_cd1400setreg(portp, RTPR, rtpr); + mcor1 = stl_cd1400getreg(portp, MSVR1); + if (mcor1 & MSVR1_DCD) + portp->sigs |= TIOCM_CD; + else + portp->sigs &= ~TIOCM_CD; + stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Set the state of the DTR and RTS signals. + */ + +static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) +{ + unsigned char msvr1, msvr2; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n", (int) portp, dtr, rts); +#endif + + msvr1 = 0; + msvr2 = 0; + if (dtr > 0) + msvr1 = MSVR1_DTR; + if (rts > 0) + msvr2 = MSVR2_RTS; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + if (rts >= 0) + stl_cd1400setreg(portp, MSVR2, msvr2); + if (dtr >= 0) + stl_cd1400setreg(portp, MSVR1, msvr1); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Return the state of the signals. + */ + +static int stl_cd1400getsignals(stlport_t *portp) +{ + unsigned char msvr1, msvr2; + unsigned long flags; + int sigs; + +#if DEBUG + printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + msvr1 = stl_cd1400getreg(portp, MSVR1); + msvr2 = stl_cd1400getreg(portp, MSVR2); + BRDDISABLE(portp->brdnr); + restore_flags(flags); + + sigs = 0; + sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; + sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0; + sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0; + sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0; + sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0; + sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0; + return(sigs); +} + +/*****************************************************************************/ + +/* + * Enable/Disable the Transmitter and/or Receiver. + */ + +static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char ccr; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx); +#endif + ccr = 0; + + if (tx == 0) + ccr |= CCR_TXDISABLE; + else if (tx > 0) + ccr |= CCR_TXENABLE; + if (rx == 0) + ccr |= CCR_RXDISABLE; + else if (rx > 0) + ccr |= CCR_RXENABLE; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, ccr); + stl_cd1400ccrwait(portp); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Start/stop the Transmitter and/or Receiver. + */ + +static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char sreron, sreroff; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, + rx, tx); +#endif + + sreron = 0; + sreroff = 0; + if (tx == 0) + sreroff |= (SRER_TXDATA | SRER_TXEMPTY); + else if (tx == 1) + sreron |= SRER_TXDATA; + else if (tx >= 2) + sreron |= SRER_TXEMPTY; + if (rx == 0) + sreroff |= SRER_RXDATA; + else if (rx > 0) + sreron |= SRER_RXDATA; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, SRER, ((stl_cd1400getreg(portp, SRER) & ~sreroff) | sreron)); + BRDDISABLE(portp->brdnr); + if (tx > 0) + set_bit(ASYI_TXBUSY, &portp->istate); + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Disable all interrupts from this port. + */ + +static void stl_cd1400disableintrs(stlport_t *portp) +{ + unsigned long flags; + +#if DEBUG + printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); +#endif + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, SRER, 0); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} + +/*****************************************************************************/ + +static void stl_cd1400sendbreak(stlport_t *portp, long len) +{ + unsigned long flags; + +#if DEBUG + printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, (int) len); +#endif + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400setreg(portp, COR2, (stl_cd1400getreg(portp, COR2) | COR2_ETC)); + stl_cd1400setreg(portp, SRER, ((stl_cd1400getreg(portp, SRER) & ~SRER_TXDATA) | SRER_TXEMPTY)); + BRDDISABLE(portp->brdnr); + len = len / 5; + portp->brklen = (len > 255) ? 255 : len; + portp->stats.txbreaks++; + restore_flags(flags); +} + +/*****************************************************************************/ + +/* + * Take flow control actions... + */ + +static void stl_cd1400flowctrl(stlport_t *portp, int state) +{ + struct tty_struct *tty; + unsigned long flags; + +#if DEBUG + printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state); #endif + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; + save_flags(flags); cli(); BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x3)); - srer = stl_getreg(portp, SRER); - stl_setreg(portp, SRER, 0); - if (stl_updatereg(portp, COR1, cor1)) - ccr = 1; - if (stl_updatereg(portp, COR2, cor2)) - ccr = 1; - if (stl_updatereg(portp, COR3, cor3)) - ccr = 1; - if (ccr) { - stl_ccrwait(portp); - stl_setreg(portp, CCR, CCR_CORCHANGE); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + + if (state) { + if (tty->termios->c_iflag & IXOFF) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1); + portp->stats.rxxon++; + stl_cd1400ccrwait(portp); + } +/* + * Question: should we return RTS to what it was before? It may + * have been set by an ioctl... Suppose not, since if you have + * hardware flow control set then it is pretty silly to go and + * set the RTS line by hand. + */ + if (tty->termios->c_cflag & CRTSCTS) { + stl_cd1400setreg(portp, MCOR1, (stl_cd1400getreg(portp, MCOR1) | FIFO_RTSTHRESHOLD)); + stl_cd1400setreg(portp, MSVR2, MSVR2_RTS); + portp->stats.rxrtson++; + } + } else { + if (tty->termios->c_iflag & IXOFF) { + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2); + portp->stats.rxxoff++; + stl_cd1400ccrwait(portp); + } + if (tty->termios->c_cflag & CRTSCTS) { + stl_cd1400setreg(portp, MCOR1, (stl_cd1400getreg(portp, MCOR1) & 0xf0)); + stl_cd1400setreg(portp, MSVR2, 0); + portp->stats.rxrtsoff++; + } } - stl_setreg(portp, COR4, cor4); - stl_setreg(portp, COR5, cor5); - stl_setreg(portp, MCOR1, mcor1); - stl_setreg(portp, MCOR2, mcor2); - if (baudrate > 0) { - stl_setreg(portp, TCOR, clk); - stl_setreg(portp, TBPR, div); - stl_setreg(portp, RCOR, clk); - stl_setreg(portp, RBPR, div); - } - stl_setreg(portp, SCHR1, tiosp->c_cc[VSTART]); - stl_setreg(portp, SCHR2, tiosp->c_cc[VSTOP]); - stl_setreg(portp, SCHR3, tiosp->c_cc[VSTART]); - stl_setreg(portp, SCHR4, tiosp->c_cc[VSTOP]); - stl_setreg(portp, RTPR, rtpr); - mcor1 = stl_getreg(portp, MSVR1); - if (mcor1 & MSVR1_DCD) - portp->sigs |= TIOCM_CD; - else - portp->sigs &= ~TIOCM_CD; - stl_setreg(portp, SRER, ((srer & ~sreroff) | sreron)); + BRDDISABLE(portp->brdnr); restore_flags(flags); } /*****************************************************************************/ -/* - * Set the state of the DTR and RTS signals. - */ - -static void stl_setsignals(stlport_t *portp, int dtr, int rts) +static void stl_cd1400flush(stlport_t *portp) { - unsigned char msvr1, msvr2; unsigned long flags; #if DEBUG - printk("stl_setsignals(portp=%x,dtr=%d,rts=%d)\n", (int) portp, dtr, rts); + printk("stl_cd1400flush(portp=%x)\n", (int) portp); #endif - msvr1 = 0; - msvr2 = 0; - if (dtr > 0) - msvr1 = MSVR1_DTR; - if (rts > 0) - msvr2 = MSVR2_RTS; + if (portp == (stlport_t *) NULL) + return; save_flags(flags); cli(); BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - if (rts >= 0) - stl_setreg(portp, MSVR2, msvr2); - if (dtr >= 0) - stl_setreg(portp, MSVR1, msvr1); + stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); + stl_cd1400ccrwait(portp); + stl_cd1400setreg(portp, CCR, CCR_TXFLUSHFIFO); + stl_cd1400ccrwait(portp); + portp->tx.tail = portp->tx.head; BRDDISABLE(portp->brdnr); restore_flags(flags); } @@ -2201,982 +3216,1189 @@ /*****************************************************************************/ /* - * Return the state of the signals. + * Interrupt service routine for cd1400 panels. + */ + +static void stl_cd1400intr(stlpanel_t *panelp, unsigned int iobase) +{ + unsigned char svrtype; + +#if DEBUG + printk("stl_cd1400intr(panelp=%x,iobase=%x)\n", (int) panelp, iobase); +#endif + + outb(SVRR, iobase); + svrtype = inb(iobase + EREG_DATA); + outb((SVRR + 0x80), iobase); + svrtype |= inb(iobase + EREG_DATA); + if (svrtype & SVRR_RX) + stl_cd1400rxisr(panelp, iobase); + if (svrtype & SVRR_TX) + stl_cd1400txisr(panelp, iobase); + if (svrtype & SVRR_MDM) + stl_cd1400mdmisr(panelp, iobase); +} + +/*****************************************************************************/ + +/* + * Transmit interrupt handler. This has gotta be fast! Handling TX + * chars is pretty simple, stuff as many as possible from the TX buffer + * into the cd1400 FIFO. Must also handle TX breaks here, since they + * are embedded as commands in the data stream. Oh no, had to use a goto! + * This could be optimized more, will do when I get time... + * In practice it is possible that interrupts are enabled but that the + * port has been hung up. Need to handle not having any TX buffer here, + * this is done by using the side effect that head and tail will also + * be NULL if the buffer has been freed. + */ + +static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr) +{ + stlport_t *portp; + int len, stlen; + char *head, *tail; + unsigned char ioack, srer; + +#if DEBUG + printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); +#endif + + ioack = inb(ioaddr + EREG_TXACK); + if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPTX)) { + printk("STALLION: bad TX interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + +/* + * Unfortunately we need to handle breaks in the data stream, since + * this is the only way to generate them on the cd1400. Do it now if + * a break is to be sent. + */ + if (portp->brklen != 0) { + if (portp->brklen > 0) { + outb((TDR + portp->uartaddr), ioaddr); + outb(ETC_CMD, (ioaddr + EREG_DATA)); + outb(ETC_STARTBREAK, (ioaddr + EREG_DATA)); + outb(ETC_CMD, (ioaddr + EREG_DATA)); + outb(ETC_DELAY, (ioaddr + EREG_DATA)); + outb(portp->brklen, (ioaddr + EREG_DATA)); + outb(ETC_CMD, (ioaddr + EREG_DATA)); + outb(ETC_STOPBREAK, (ioaddr + EREG_DATA)); + portp->brklen = -1; + goto stl_txalldone; + } else { + outb((COR2 + portp->uartaddr), ioaddr); + outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), (ioaddr + EREG_DATA)); + portp->brklen = 0; + } + } + + head = portp->tx.head; + tail = portp->tx.tail; + len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); + if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { + set_bit(ASYI_TXLOW, &portp->istate); + queue_task_irq_off(&portp->tqueue, &tq_scheduler); + } + + if (len == 0) { + outb((SRER + portp->uartaddr), ioaddr); + srer = inb(ioaddr + EREG_DATA); + if (srer & SRER_TXDATA) { + srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY; + } else { + srer &= ~(SRER_TXDATA | SRER_TXEMPTY); + clear_bit(ASYI_TXBUSY, &portp->istate); + } + outb(srer, (ioaddr + EREG_DATA)); + } else { + len = MIN(len, CD1400_TXFIFOSIZE); + portp->stats.txtotal += len; + stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + outb((TDR + portp->uartaddr), ioaddr); + outsb((ioaddr + EREG_DATA), tail, stlen); + len -= stlen; + tail += stlen; + if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) + tail = portp->tx.buf; + if (len > 0) { + outsb((ioaddr + EREG_DATA), tail, len); + tail += len; + } + portp->tx.tail = tail; + } + +stl_txalldone: + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); +} + +/*****************************************************************************/ + +/* + * Receive character interrupt handler. Determine if we have good chars + * or bad chars and then process appropriately. Good chars are easy + * just shove the lot into the RX buffer and set all status byte to 0. + * If a bad RX char then process as required. This routine needs to be + * fast! In practice it is possible that we get an interrupt on a port + * that is closed. This can happen on hangups - since they completely + * shutdown a port not in user context. Need to handle this case. + */ + +static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr) +{ + stlport_t *portp; + struct tty_struct *tty; + unsigned int ioack, len, buflen; + unsigned char status; + char ch; + +#if DEBUG + printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); +#endif + + ioack = inb(ioaddr + EREG_RXACK); + if ((ioack & panelp->ackmask) != 0) { + printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + tty = portp->tty; + + if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { + outb((RDCR + portp->uartaddr), ioaddr); + len = inb(ioaddr + EREG_DATA); + if ((tty == (struct tty_struct *) NULL) || (tty->flip.char_buf_ptr == (char *) NULL) || + ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + outb((RDSR + portp->uartaddr), ioaddr); + insb((ioaddr + EREG_DATA), &stl_unwanted[0], len); + portp->stats.rxlost += len; + portp->stats.rxtotal += len; + } else { + len = MIN(len, buflen); + if (len > 0) { + outb((RDSR + portp->uartaddr), ioaddr); + insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len); + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + tty->flip.char_buf_ptr += len; + tty->flip.count += len; + tty_schedule_flip(tty); + portp->stats.rxtotal += len; + } + } + } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) { + outb((RDSR + portp->uartaddr), ioaddr); + status = inb(ioaddr + EREG_DATA); + ch = inb(ioaddr + EREG_DATA); + if (status & ST_PARITY) + portp->stats.rxparity++; + if (status & ST_FRAMING) + portp->stats.rxframing++; + if (status & ST_OVERRUN) + portp->stats.rxoverrun++; + if (status & ST_BREAK) + portp->stats.rxbreaks++; + if (status & ST_SCHARMASK) { + if ((status & ST_SCHARMASK) == ST_SCHAR1) + portp->stats.txxon++; + if ((status & ST_SCHARMASK) == ST_SCHAR2) + portp->stats.txxoff++; + goto stl_rxalldone; + } + if ((tty != (struct tty_struct *) NULL) && ((portp->rxignoremsk & status) == 0)) { + if (portp->rxmarkmsk & status) { + if (status & ST_BREAK) { + status = TTY_BREAK; +#ifndef MODULE + if (portp->flags & ASYNC_SAK) { + do_SAK(tty); + BRDENABLE(portp->brdnr, portp->pagenr); + } +#endif + } else if (status & ST_PARITY) { + status = TTY_PARITY; + } else if (status & ST_FRAMING) { + status = TTY_FRAME; + } else if(status & ST_OVERRUN) { + status = TTY_OVERRUN; + } else { + status = 0; + } + } else { + status = 0; + } + if (tty->flip.char_buf_ptr != (char *) NULL) { + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.flag_buf_ptr++ = status; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + } + tty_schedule_flip(tty); + } + } + } else { + printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + return; + } + +stl_rxalldone: + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); +} + +/*****************************************************************************/ + +/* + * Modem interrupt handler. The is called when the modem signal line + * (DCD) has changed state. Leave most of the work to the off-level + * processing routine. */ -static int stl_getsignals(stlport_t *portp) +static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr) { - unsigned char msvr1, msvr2; - unsigned long flags; - int sigs; + stlport_t *portp; + unsigned int ioack; + unsigned char misr; #if DEBUG - printk("stl_getsignals(portp=%x)\n", (int) portp); + printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp); #endif - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - msvr1 = stl_getreg(portp, MSVR1); - msvr2 = stl_getreg(portp, MSVR2); - BRDDISABLE(portp->brdnr); - sigs = 0; - sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; - sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0; - sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0; - sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0; - sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0; - sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0; - restore_flags(flags); - return(sigs); + ioack = inb(ioaddr + EREG_MDACK); + if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) { + printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack); + return; + } + portp = panelp->ports[(ioack >> 3)]; + + outb((MISR + portp->uartaddr), ioaddr); + misr = inb(ioaddr + EREG_DATA); + if (misr & MISR_DCD) { + set_bit(ASYI_DCDCHANGE, &portp->istate); + queue_task_irq_off(&portp->tqueue, &tq_scheduler); + portp->stats.modem++; + } + + outb((EOSRR + portp->uartaddr), ioaddr); + outb(0, (ioaddr + EREG_DATA)); } /*****************************************************************************/ +/* SC26198 HARDWARE FUNCTIONS */ +/*****************************************************************************/ /* - * Enable/Disable the Transmitter and/or Receiver. + * These functions get/set/update the registers of the sc26198 UARTs. + * Access to the sc26198 registers is via an address/data io port pair. + * (Maybe should make this inline...) */ -static void stl_enablerxtx(stlport_t *portp, int rx, int tx) +static int stl_sc26198getreg(stlport_t *portp, int regnr) { - unsigned char ccr; - unsigned long flags; - -#if DEBUG - printk("stl_enablerxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx); -#endif - ccr = 0; + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + return(inb(portp->ioaddr + XP_DATA)); +} - if (tx == 0) - ccr |= CCR_TXDISABLE; - else if (tx > 0) - ccr |= CCR_TXENABLE; - if (rx == 0) - ccr |= CCR_RXDISABLE; - else if (rx > 0) - ccr |= CCR_RXENABLE; +static void stl_sc26198setreg(stlport_t *portp, int regnr, int value) +{ + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + outb(value, (portp->ioaddr + XP_DATA)); +} - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - stl_ccrwait(portp); - stl_setreg(portp, CCR, ccr); - stl_ccrwait(portp); - BRDDISABLE(portp->brdnr); - restore_flags(flags); +static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value) +{ + outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR)); + if (inb(portp->ioaddr + XP_DATA) != value) { + outb(value, (portp->ioaddr + XP_DATA)); + return(1); + } + return(0); } /*****************************************************************************/ /* - * Start/stop the Transmitter and/or Receiver. + * Functions to get and set the sc26198 global registers. */ -static void stl_startrxtx(stlport_t *portp, int rx, int tx) +static int stl_sc26198getglobreg(stlport_t *portp, int regnr) { - unsigned char sreron, sreroff; - unsigned long flags; - -#if DEBUG - printk("stl_startrxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx); -#endif - - sreron = 0; - sreroff = 0; - if (tx == 0) - sreroff |= (SRER_TXDATA | SRER_TXEMPTY); - else if (tx == 1) - sreron |= SRER_TXDATA; - else if (tx >= 2) - sreron |= SRER_TXEMPTY; - if (rx == 0) - sreroff |= SRER_RXDATA; - else if (rx > 0) - sreron |= SRER_RXDATA; + outb(regnr, (portp->ioaddr + XP_ADDR)); + return(inb(portp->ioaddr + XP_DATA)); +} - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - stl_setreg(portp, SRER, ((stl_getreg(portp, SRER) & ~sreroff) | sreron)); - BRDDISABLE(portp->brdnr); - if (tx > 0) - set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); +#if 0 +static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value) +{ + outb(regnr, (portp->ioaddr + XP_ADDR)); + outb(value, (portp->ioaddr + XP_DATA)); } +#endif /*****************************************************************************/ /* - * Disable all interrupts from this port. + * Inbitialize the UARTs in a panel. We don't care what sort of board + * these ports are on - since the port io registers are almost + * identical when dealing with ports. */ -static void stl_disableintrs(stlport_t *portp) +static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp) { - unsigned long flags; + int chipmask, i; + int nrchips, ioaddr; #if DEBUG - printk("stl_disableintrs(portp=%x)\n", (int) portp); + printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); #endif - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - stl_setreg(portp, SRER, 0); - BRDDISABLE(portp->brdnr); - restore_flags(flags); -} -/*****************************************************************************/ + BRDENABLE(panelp->brdnr, panelp->pagenr); -static void stl_sendbreak(stlport_t *portp, long len) -{ - unsigned long flags; +/* + * Check that each chip is present and started up OK. + */ + chipmask = 0; + nrchips = panelp->nrports / SC26198_PORTS; + if (brdp->brdtype == BRD_ECHPCI) + outb(panelp->pagenr, brdp->ioctrl); -#if DEBUG - printk("stl_sendbreak(portp=%x,len=%d)\n", (int) portp, (int) len); -#endif + for (i = 0; (i < nrchips); i++) { + ioaddr = panelp->iobase + (i * 4); + outb(SCCR, (ioaddr + XP_ADDR)); + outb(CR_RESETALL, (ioaddr + XP_DATA)); + outb(TSTR, (ioaddr + XP_ADDR)); + if (inb(ioaddr + XP_DATA) != 0) { + printk("STALLION: sc26198 not responding, brd=%d panel=%d chip=%d\n", panelp->brdnr, panelp->panelnr, i); + continue; + } + chipmask |= (0x1 << i); + outb(GCCR, (ioaddr + XP_ADDR)); + outb(GCCR_IVRTYPCHANACK, (ioaddr + XP_DATA)); + outb(WDTRCR, (ioaddr + XP_ADDR)); + outb(0xff, (ioaddr + XP_DATA)); + } - save_flags(flags); - cli(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - stl_setreg(portp, COR2, (stl_getreg(portp, COR2) | COR2_ETC)); - stl_setreg(portp, SRER, ((stl_getreg(portp, SRER) & ~SRER_TXDATA) | SRER_TXEMPTY)); - BRDDISABLE(portp->brdnr); - len = len / 5; - portp->brklen = (len > 255) ? 255 : len; - portp->stats.txbreaks++; - restore_flags(flags); + BRDDISABLE(panelp->brdnr); + return(chipmask); } /*****************************************************************************/ /* - * Map in interrupt vector to this driver. Check that we don't - * already have this vector mapped, we might be sharing this - * interrupt across multiple boards. + * Initialize hardware specific port registers. */ -static int stl_mapirq(int irq) +static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) { - int rc, i; - #if DEBUG - printk("stl_mapirq(irq=%d)\n", irq); + printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n", + (int) brdp, (int) panelp, (int) portp); #endif - rc = 0; - for (i = 0; (i < stl_numintrs); i++) { - if (stl_gotintrs[i] == irq) - break; - } - if (i >= stl_numintrs) { - if (request_irq(irq, stl_intr, SA_INTERRUPT, stl_drvname, NULL) != 0) { - printk("STALLION: failed to register interrupt routine for irq=%d\n", irq); - rc = -ENODEV; - } else { - stl_gotintrs[stl_numintrs++] = irq; - } - } - return(rc); + if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || (portp == (stlport_t *) NULL)) + return; + + portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4); + portp->uartaddr = (portp->portnr & 0x07) << 4; + portp->pagenr = panelp->pagenr; + portp->hwid = 0x1; + + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IOPCR, IOPCR_SETSIGS); + BRDDISABLE(portp->brdnr); } /*****************************************************************************/ /* - * Try to find and initialize all the ports on a panel. We don't care - * what sort of board these ports are on - since the port io registers - * are almost identical when dealing with ports. + * Set up the sc26198 registers for a port based on the termios port + * settings. */ -static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) +static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) { - stlport_t *portp; - unsigned int chipmask; - unsigned int gfrcr; - int nrchips, uartaddr, ioaddr; - int i, j; - -#if DEBUG - printk("stl_initports(panelp=%x)\n", (int) panelp); -#endif + stlbrd_t *brdp; + unsigned long flags; + unsigned int baudrate; + unsigned char mr0, mr1, mr2, clk; + unsigned char imron, imroff, iopr, ipr; + + mr0 = 0; + mr1 = 0; + mr2 = 0; + clk = 0; + iopr = 0; + imron = 0; + imroff = 0; - BRDENABLE(panelp->brdnr, panelp->pagenr); + brdp = stl_brds[portp->brdnr]; + if (brdp == (stlbrd_t *) NULL) + return; /* - * Check that each chip is present and started up OK. + * Set up the RX char ignore mask with those RX error types we + * can ignore. */ - chipmask = 0; - nrchips = panelp->nrports / CD1400_PORTS; - for (i = 0; (i < nrchips); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb((panelp->pagenr + (i >> 1)), brdp->ioctrl); - ioaddr = panelp->iobase; - } else { - ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1)); - } - uartaddr = (i & 0x01) ? 0x080 : 0; - outb((GFRCR + uartaddr), ioaddr); - outb(0, (ioaddr + EREG_DATA)); - outb((CCR + uartaddr), ioaddr); - outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); - outb(CCR_RESETFULL, (ioaddr + EREG_DATA)); - outb((GFRCR + uartaddr), ioaddr); - for (j = 0; (j < CCR_MAXWAIT); j++) { - if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0) - break; - } - if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) { - printk("STALLION: cd1400 not responding, brd=%d panel=%d chip=%d\n", panelp->brdnr, panelp->panelnr, i); - continue; - } - chipmask |= (0x1 << i); - outb((PPR + uartaddr), ioaddr); - outb(PPR_SCALAR, (ioaddr + EREG_DATA)); - } + portp->rxignoremsk = 0; + if (tiosp->c_iflag & IGNPAR) + portp->rxignoremsk |= (SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN); + if (tiosp->c_iflag & IGNBRK) + portp->rxignoremsk |= SR_RXBREAK; + + portp->rxmarkmsk = SR_RXOVERRUN; + if (tiosp->c_iflag & (INPCK | PARMRK)) + portp->rxmarkmsk |= (SR_RXPARITY | SR_RXFRAMING); + if (tiosp->c_iflag & BRKINT) + portp->rxmarkmsk |= SR_RXBREAK; /* - * All cd1400's are initialized (if found!). Now go through and setup - * each ports data structures. Also init the LIVR register of cd1400 - * for each port. + * Go through the char size, parity and stop bits and set all the + * option register appropriately. */ - ioaddr = panelp->iobase; - for (i = 0; (i < panelp->nrports); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb((panelp->pagenr + (i >> 3)), brdp->ioctrl); - ioaddr = panelp->iobase; - } else { - ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 3)); - } - if ((chipmask & (0x1 << (i / 4))) == 0) - continue; - portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); - if (portp == (stlport_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlport_t)); - break; - } - memset(portp, 0, sizeof(stlport_t)); - portp->magic = STL_PORTMAGIC; - portp->portnr = i; - portp->brdnr = panelp->brdnr; - portp->panelnr = panelp->panelnr; - portp->ioaddr = ioaddr; - portp->uartaddr = (i & 0x04) << 5; - portp->pagenr = panelp->pagenr + (i >> 3); - portp->clk = brdp->clk; - portp->baud_base = STL_BAUDBASE; - portp->close_delay = STL_CLOSEDELAY; - portp->closing_wait = 30 * HZ; - portp->normaltermios = stl_deftermios; - portp->callouttermios = stl_deftermios; - portp->tqueue.routine = stl_offintr; - portp->tqueue.data = portp; - portp->stats.brd = portp->brdnr; - portp->stats.panel = portp->panelnr; - portp->stats.port = portp->portnr; - stl_setreg(portp, CAR, (i & 0x03)); - stl_setreg(portp, LIVR, (i << 3)); - portp->hwid = stl_getreg(portp, GFRCR); - panelp->ports[i] = portp; + switch (tiosp->c_cflag & CSIZE) { + case CS5: + mr1 |= MR1_CS5; + break; + case CS6: + mr1 |= MR1_CS6; + break; + case CS7: + mr1 |= MR1_CS7; + break; + default: + mr1 |= MR1_CS8; + break; + } + + if (tiosp->c_cflag & CSTOPB) + mr2 |= MR2_STOP2; + else + mr2 |= MR2_STOP1; + + if (tiosp->c_cflag & PARENB) { + if (tiosp->c_cflag & PARODD) + mr1 |= (MR1_PARENB | MR1_PARODD); + else + mr1 |= (MR1_PARENB | MR1_PAREVEN); + } else { + mr1 |= MR1_PARNONE; } - BRDDISABLE(panelp->brdnr); - return(0); -} - -/*****************************************************************************/ + mr1 |= MR1_ERRBLOCK; /* - * Try to find and initialize an EasyIO board. + * Set the RX FIFO threshold at 8 chars. This gives a bit of breathing + * space for hardware flow control and the like. This should be set to + * VMIN. */ + mr2 |= MR2_RXFIFOHALF; -static int stl_initeio(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int status; - int rc; - -#if DEBUG - printk("stl_initeio(brdp=%x)\n", (int) brdp); -#endif - - brdp->ioctrl = brdp->ioaddr1 + 1; - brdp->iostatus = brdp->ioaddr1 + 2; - brdp->clk = EIO_CLK; - - status = inb(brdp->iostatus); - switch (status & EIO_IDBITMASK) { - case EIO_8PORTM: - brdp->clk = EIO_CLK8M; - /* fall thru */ - case EIO_8PORTRS: - case EIO_8PORTDI: - brdp->nrports = 8; - break; - case EIO_4PORTRS: - brdp->nrports = 4; - break; - default: - return(-ENODEV); +/* + * Calculate the baud rate timers. For now we will just assume that + * the input and output baud are the same. The sc26198 has a fixed + * baud rate table, so only discrete baud rates possible. + */ + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 5)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + baudrate = stl_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (portp->baud_base / portp->custom_divisor); } + if (baudrate > STL_MAXBAUD) + baudrate = STL_MAXBAUD; - request_region(brdp->ioaddr1, 8, "serial(EIO)"); + if (baudrate > 0) { + for (clk = 0; (clk < SC26198_NRBAUDS); clk++) { + if (baudrate <= sc26198_baudtable[clk]) + break; + } + } /* - * Check that the supplied IRQ is good and then use it to setup the - * programmable interrupt bits on EIO board. Also set the edge/level - * triggered interrupt bit. + * Check what form of modem signaling is required and set it up. */ - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); - return(-EINVAL); + if (tiosp->c_cflag & CLOCAL) { + portp->flags &= ~ASYNC_CHECK_CD; + } else { + iopr |= IOPR_DCDCOS; + imron |= IR_IOPORT; + portp->flags |= ASYNC_CHECK_CD; } - outb((stl_vecmap[brdp->irq] | ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), brdp->ioctrl); - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t)); - return(-ENOMEM); +/* + * Setup sc26198 enhanced modes if we can. In particular we want to + * handle as much of the flow control as possible automatically. As + * well as saving a few CPU cycles it will also greatly improve flow + * control reliability. + */ + if (tiosp->c_iflag & IXON) { + mr0 |= MR0_SWFTX | MR0_SWFT; + imron |= IR_XONXOFF; + } else { + imroff |= IR_XONXOFF; } - memset(panelp, 0, sizeof(stlpanel_t)); - - panelp->magic = STL_PANELMAGIC; - panelp->brdnr = brdp->brdnr; - panelp->panelnr = 0; - panelp->nrports = brdp->nrports; - panelp->iobase = brdp->ioaddr1; - panelp->hwid = status; - brdp->panels[0] = panelp; - brdp->nrpanels = 1; - brdp->state |= BRD_FOUND; - brdp->hwid = status; - rc = stl_mapirq(brdp->irq); - return(rc); -} + if (tiosp->c_iflag & IXOFF) + mr0 |= MR0_SWFRX; -/*****************************************************************************/ + if (tiosp->c_cflag & CRTSCTS) { + mr2 |= MR2_AUTOCTS; + mr1 |= MR1_AUTORTS; + } /* - * Try to find an ECH board and initialize it. This code is capable of - * dealing with all types of ECH board. + * All sc26198 register values calculated so go through and set + * them all up. */ -static int stl_initech(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int status, nxtid; - int panelnr, ioaddr, i; - #if DEBUG - printk("stl_initech(brdp=%x)\n", (int) brdp); + printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr); + printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk); + printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff); + printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); #endif - status = 0; - -/* - * Set up the initial board register contents for boards. This varies a - * bit between the different board types. So we need to handle each - * separately. Also do a check that the supplied IRQ is good. - */ - if (brdp->brdtype == BRD_ECH) { - brdp->ioctrl = brdp->ioaddr1 + 1; - brdp->iostatus = brdp->ioaddr1 + 1; - status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(-ENODEV); + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IMR, 0); + stl_sc26198updatereg(portp, MR0, mr0); + stl_sc26198updatereg(portp, MR1, mr1); + stl_sc26198setreg(portp, CCR, CR_RXERRBLOCK); + stl_sc26198updatereg(portp, MR2, mr2); + stl_sc26198updatereg(portp, IOPIOR, + ((stl_sc26198getreg(portp, IOPIOR) & ~IPR_CHANGEMASK) | iopr)); - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); - return(-EINVAL); - } - status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); - status |= (stl_vecmap[brdp->irq] << 1); - outb((status | ECH_BRDRESET), brdp->ioaddr1); - brdp->ioctrlval = ECH_INTENABLE | ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); - outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); - outb(status, brdp->ioaddr1); + if (baudrate > 0) { + stl_sc26198setreg(portp, TXCSR, clk); + stl_sc26198setreg(portp, RXCSR, clk); + } - request_region(brdp->ioaddr1, 2, "serial(EC8/32)"); - request_region(brdp->ioaddr2, 32, "serial(EC8/32-secondary)"); - } else if (brdp->brdtype == BRD_ECHMC) { - brdp->ioctrl = brdp->ioaddr1 + 0x20; - brdp->iostatus = brdp->ioctrl; - status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(-ENODEV); + stl_sc26198setreg(portp, XONCR, tiosp->c_cc[VSTART]); + stl_sc26198setreg(portp, XOFFCR, tiosp->c_cc[VSTOP]); - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); - return(-EINVAL); - } - outb(ECHMC_BRDRESET, brdp->ioctrl); - outb(ECHMC_INTENABLE, brdp->ioctrl); + ipr = stl_sc26198getreg(portp, IPR); + if (ipr & MSVR1_DCD) + portp->sigs &= ~TIOCM_CD; + else + portp->sigs |= TIOCM_CD; - request_region(brdp->ioaddr1, 64, "serial(EC8/32-MC)"); - } else if (brdp->brdtype == BRD_ECHPCI) { - brdp->ioctrl = brdp->ioaddr1 + 2; - request_region(brdp->ioaddr1, 4, "serial(EC8/32-PCI)"); - request_region(brdp->ioaddr2, 8, "serial(EC8/32-PCI-secondary)"); - } + portp->imr = (portp->imr & ~imroff) | imron; + stl_sc26198setreg(portp, IMR, portp->imr); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} - brdp->clk = ECH_CLK; - brdp->hwid = status; +/*****************************************************************************/ /* - * Scan through the secondary io address space looking for panels. - * As we find'em allocate and initialize panel structures for each. + * Set the state of the DTR and RTS signals. */ - ioaddr = brdp->ioaddr2; - panelnr = 0; - nxtid = 0; - for (i = 0; (i < STL_MAXPANELS); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb(nxtid, brdp->ioctrl); - ioaddr = brdp->ioaddr2; - } - status = inb(ioaddr + ECH_PNLSTATUS); - if ((status & ECH_PNLIDMASK) != nxtid) - break; - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t)); - break; - } - memset(panelp, 0, sizeof(stlpanel_t)); - panelp->magic = STL_PANELMAGIC; - panelp->brdnr = brdp->brdnr; - panelp->panelnr = panelnr; - panelp->iobase = ioaddr; - panelp->pagenr = nxtid; - panelp->hwid = status; - if (status & ECH_PNL16PORT) { - if ((brdp->nrports + 16) > 32) - break; - panelp->nrports = 16; - panelp->ackmask = 0x80; - brdp->nrports += 16; - ioaddr += (EREG_BANKSIZE * 2); - nxtid += 2; - } else { - panelp->nrports = 8; - panelp->ackmask = 0xc0; - brdp->nrports += 8; - ioaddr += EREG_BANKSIZE; - nxtid++; - } - brdp->panels[panelnr++] = panelp; - brdp->nrpanels++; - if (ioaddr >= (brdp->ioaddr2 + 0x20)) - break; - } +static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) +{ + unsigned char iopioron, iopioroff; + unsigned long flags; - if (brdp->brdtype == BRD_ECH) - outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); +#if DEBUG + printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n", (int) portp, dtr, rts); +#endif - brdp->state |= BRD_FOUND; - i = stl_mapirq(brdp->irq); - return(i); + iopioron = 0; + iopioroff = 0; + if (dtr == 0) + iopioroff |= IPR_DTR; + else if (dtr > 0) + iopioron |= IPR_DTR; + if (rts == 0) + iopioroff |= IPR_RTS; + else if (rts > 0) + iopioron |= IPR_RTS; + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IOPIOR, + ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); + BRDDISABLE(portp->brdnr); + restore_flags(flags); } /*****************************************************************************/ /* - * Initialize and configure the specified board. - * Scan through all the boards in the configuration and see what we - * can find. Handle EIO and the ECH boards a little differently here - * since the initial search and setup is too different. + * Return the state of the signals. */ -static int stl_brdinit(stlbrd_t *brdp) +static int stl_sc26198getsignals(stlport_t *portp) { - int i; + unsigned char ipr; + unsigned long flags; + int sigs; #if DEBUG - printk("stl_brdinit(brdp=%x)\n", (int) brdp); + printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); #endif - switch (brdp->brdtype) { - case BRD_EASYIO: - stl_initeio(brdp); - break; - case BRD_ECH: - case BRD_ECHMC: - case BRD_ECHPCI: - stl_initech(brdp); - break; - default: - printk("STALLION: unit=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype); - return(ENODEV); - } - - stl_brds[brdp->brdnr] = brdp; - if ((brdp->state & BRD_FOUND) == 0) { - printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq); - return(ENODEV); - } - - for (i = 0; (i < STL_MAXPANELS); i++) - if (brdp->panels[i] != (stlpanel_t *) NULL) - stl_initports(brdp, brdp->panels[i]); + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + ipr = stl_sc26198getreg(portp, IPR); + BRDDISABLE(portp->brdnr); + restore_flags(flags); - printk("STALLION: %s found, unit=%d io=%x irq=%d nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, brdp->nrports); - return(0); + sigs = 0; + sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; + sigs |= (ipr & IPR_CTS) ? 0 : TIOCM_CTS; + sigs |= (ipr & IPR_DTR) ? 0: TIOCM_DTR; + sigs |= (ipr & IPR_RTS) ? 0: TIOCM_RTS; + return(sigs); } /*****************************************************************************/ /* - * Find any ECH-PCI boards that might be installed. Initialize each - * one as it is found. + * Enable/Disable the Transmitter and/or Receiver. */ -#ifdef CONFIG_PCI - -static int stl_findpcibrds() +static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) { - stlbrd_t *brdp; - unsigned char busnr, devnr, irq; - unsigned short class; - unsigned int ioaddr; - int i, rc; + unsigned char ccr; + unsigned long flags; #if DEBUG - printk("stl_findpcibrds()\n"); + printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx); #endif - if (pcibios_present()) { - for (i = 0; (i < STL_MAXBRDS); i++) { - if (pcibios_find_device(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, i, &busnr, &devnr)) - break; + ccr = portp->crenable; + if (tx == 0) + ccr &= ~CR_TXENABLE; + else if (tx > 0) + ccr |= CR_TXENABLE; + if (rx == 0) + ccr &= ~CR_RXENABLE; + else if (rx > 0) + ccr |= CR_RXENABLE; -/* - * Found a device on the PCI bus that has our vendor and - * device ID. Need to check now that it is really us. - */ - if ((rc = pcibios_read_config_word(busnr, devnr, PCI_CLASS_DEVICE, &class))) { - printk("STALLION: failed to read class type from PCI board, errno=%x\n", rc); - continue; - } - if (class == PCI_CLASS_STORAGE_IDE) - continue; + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, SCCR, ccr); + BRDDISABLE(portp->brdnr); + portp->crenable = ccr; + restore_flags(flags); +} - if (stl_nrbrds >= STL_MAXBRDS) { - printk("STALLION: too many boards found, maximum supported %d\n", STL_MAXBRDS); - break; - } +/*****************************************************************************/ /* - * We have a Stallion board. Allocate a board structure - * and initialize it. Read its IO and IRQ resources - * from conf space. + * Start/stop the Transmitter and/or Receiver. */ - brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); - if (brdp == (stlbrd_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t)); - return(-ENOMEM); - } - memset(brdp, 0, sizeof(stlbrd_t)); - brdp->magic = STL_BOARDMAGIC; - brdp->brdnr = stl_nrbrds++; - brdp->brdtype = BRD_ECHPCI; - if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_0, &ioaddr))) { - printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc); - continue; - } - brdp->ioaddr2 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK); +static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) +{ + unsigned char imr; + unsigned long flags; - if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_1, &ioaddr))) { - printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc); - continue; - } - brdp->ioaddr1 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK); #if DEBUG - printk("%s(%d): BAR0=%x BAR1=%x\n", __FILE__, __LINE__, brdp->ioaddr2, brdp->ioaddr1); + printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, + rx, tx); #endif - if ((rc = pcibios_read_config_byte(busnr, devnr, PCI_INTERRUPT_LINE, &irq))) { - printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc); - continue; - } - brdp->irq = irq; - - stl_brdinit(brdp); - } - } + imr = portp->imr; + if (tx == 0) + imr &= ~IR_TXRDY; + else if (tx == 1) + imr |= IR_TXRDY; + if (rx == 0) + imr &= ~(IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG); + else if (rx > 0) + imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; - return(0); + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, IMR, imr); + BRDDISABLE(portp->brdnr); + portp->imr = imr; + if (tx > 0) + set_bit(ASYI_TXBUSY, &portp->istate); + restore_flags(flags); } -#endif - /*****************************************************************************/ /* - * Scan through all the boards in the configuration and see what we - * can find. Handle EIO and the ECH boards a little differently here - * since the initial search and setup is too different. + * Disable all interrupts from this port. */ -static int stl_initbrds() +static void stl_sc26198disableintrs(stlport_t *portp) { - stlbrd_t *brdp; - stlconf_t *confp; - int i; + unsigned long flags; #if DEBUG - printk("stl_initbrds()\n"); + printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); #endif - if (stl_nrbrds > STL_MAXBRDS) { - printk("STALLION: too many boards in configuration table, truncating to %d\n", STL_MAXBRDS); - stl_nrbrds = STL_MAXBRDS; - } + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + portp->imr = 0; + stl_sc26198setreg(portp, IMR, 0); + BRDDISABLE(portp->brdnr); + restore_flags(flags); +} -/* - * Firstly scan the list of static boards configured. Allocate - * resources and initialize the boards as found. - */ - for (i = 0; (i < stl_nrbrds); i++) { - confp = &stl_brdconf[i]; - brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); - if (brdp == (stlbrd_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t)); - return(-ENOMEM); - } - memset(brdp, 0, sizeof(stlbrd_t)); +/*****************************************************************************/ - brdp->magic = STL_BOARDMAGIC; - brdp->brdnr = i; - brdp->brdtype = confp->brdtype; - brdp->ioaddr1 = confp->ioaddr1; - brdp->ioaddr2 = confp->ioaddr2; - brdp->irq = confp->irq; - brdp->irqtype = confp->irqtype; - stl_brdinit(brdp); - } +static void stl_sc26198sendbreak(stlport_t *portp, long len) +{ + unsigned long flags; -#ifdef CONFIG_PCI -/* - * If the PCI BIOS support is compiled in then let's go looking for - * ECH-PCI boards. - */ - stl_findpcibrds(); +#if DEBUG + printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, (int) len); #endif - return(0); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + (len / (1000 / HZ)); + + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); + BRDDISABLE(portp->brdnr); + portp->stats.txbreaks++; + + schedule(); + + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); + BRDDISABLE(portp->brdnr); + restore_flags(flags); } /*****************************************************************************/ /* - * Return the board stats structure to user app. + * Take flow control actions... */ -static int stl_getbrdstats(combrd_t *bp) +static void stl_sc26198flowctrl(stlport_t *portp, int state) { - stlbrd_t *brdp; - stlpanel_t *panelp; - int i; - - copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)); - if (stl_brdstats.brd >= STL_MAXBRDS) - return(-ENODEV); - brdp = stl_brds[stl_brdstats.brd]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - - memset(&stl_brdstats, 0, sizeof(combrd_t)); - stl_brdstats.brd = brdp->brdnr; - stl_brdstats.type = brdp->brdtype; - stl_brdstats.hwid = brdp->hwid; - stl_brdstats.state = brdp->state; - stl_brdstats.ioaddr = brdp->ioaddr1; - stl_brdstats.ioaddr2 = brdp->ioaddr2; - stl_brdstats.irq = brdp->irq; - stl_brdstats.nrpanels = brdp->nrpanels; - stl_brdstats.nrports = brdp->nrports; - for (i = 0; (i < brdp->nrpanels); i++) { - panelp = brdp->panels[i]; - stl_brdstats.panels[i].panel = i; - stl_brdstats.panels[i].hwid = panelp->hwid; - stl_brdstats.panels[i].nrports = panelp->nrports; - } + struct tty_struct *tty; + unsigned long flags; + unsigned char mr0; - copy_to_user(bp, &stl_brdstats, sizeof(combrd_t)); - return(0); -} +#if DEBUG + printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state); +#endif -/*****************************************************************************/ + if (portp == (stlport_t *) NULL) + return; + tty = portp->tty; + if (tty == (struct tty_struct *) NULL) + return; -/* - * Resolve the referenced port number into a port struct pointer. - */ + save_flags(flags); + cli(); + BRDENABLE(portp->brdnr, portp->pagenr); -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; + if (state) { + if (tty->termios->c_iflag & IXOFF) { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXON); + mr0 |= MR0_SWFRX; + portp->stats.rxxon++; + stl_sc26198setreg(portp, MR0, mr0); + } +/* + * Question: should we return RTS to what it was before? It may + * have been set by an ioctl... Suppose not, since if you have + * hardware flow control set then it is pretty silly to go and + * set the RTS line by hand. + */ + if (tty->termios->c_cflag & CRTSCTS) { + stl_sc26198setreg(portp, MR1, + (stl_sc26198getreg(portp, MR1) | MR1_AUTORTS)); + stl_sc26198setreg(portp, IOPIOR, + (stl_sc26198getreg(portp, IOPIOR) | IOPR_RTS)); + portp->stats.rxrtson++; + } + } else { + if (tty->termios->c_iflag & IXOFF) { + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF); + mr0 &= ~MR0_SWFRX; + portp->stats.rxxoff++; + stl_sc26198setreg(portp, MR0, mr0); + } + if (tty->termios->c_cflag & CRTSCTS) { + stl_sc26198setreg(portp, MR1, + (stl_sc26198getreg(portp, MR1) & ~MR1_AUTORTS)); + stl_sc26198setreg(portp, IOPIOR, + (stl_sc26198getreg(portp, IOPIOR) & ~IOPR_RTS)); + portp->stats.rxrtsoff++; + } + } - if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) - return((stlport_t *) NULL); - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return((stlport_t *) NULL); - if ((panelnr < 0) || (panelnr >= brdp->nrpanels)) - return((stlport_t *) NULL); - panelp = brdp->panels[panelnr]; - if (panelp == (stlpanel_t *) NULL) - return((stlport_t *) NULL); - if ((portnr < 0) || (portnr >= panelp->nrports)) - return((stlport_t *) NULL); - return(panelp->ports[portnr]); + BRDDISABLE(portp->brdnr); + restore_flags(flags); } /*****************************************************************************/ -/* - * Return the port stats structure to user app. A NULL port struct - * pointer passed in means that we need to find out from the app - * what port to get stats for (used through board control device). - */ - -static int stl_getportstats(stlport_t *portp, comstats_t *cp) +static void stl_sc26198flush(stlport_t *portp) { - unsigned char *head, *tail; unsigned long flags; - if (portp == (stlport_t *) NULL) { - copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); - portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - } - - portp->stats.state = portp->istate; - portp->stats.flags = portp->flags; - portp->stats.hwid = portp->hwid; +#if DEBUG + printk("stl_sc26198flush(portp=%x)\n", (int) portp); +#endif - portp->stats.ttystate = 0; - portp->stats.cflags = 0; - portp->stats.iflags = 0; - portp->stats.oflags = 0; - portp->stats.lflags = 0; - portp->stats.rxbuffered = 0; + if (portp == (stlport_t *) NULL) + return; save_flags(flags); cli(); - if (portp->tty != (struct tty_struct *) NULL) { - if (portp->tty->driver_data == portp) { - portp->stats.ttystate = portp->tty->flags; - portp->stats.rxbuffered = portp->tty->flip.count; - if (portp->tty->termios != (struct termios *) NULL) { - portp->stats.cflags = portp->tty->termios->c_cflag; - portp->stats.iflags = portp->tty->termios->c_iflag; - portp->stats.oflags = portp->tty->termios->c_oflag; - portp->stats.lflags = portp->tty->termios->c_lflag; - } - } - } + BRDENABLE(portp->brdnr, portp->pagenr); + stl_sc26198setreg(portp, SCCR, CR_TXRESET); + stl_sc26198setreg(portp, SCCR, portp->crenable); + BRDDISABLE(portp->brdnr); + portp->tx.tail = portp->tx.head; restore_flags(flags); +} - head = portp->tx.head; - tail = portp->tx.tail; - portp->stats.txbuffered = ((head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head))); +/*****************************************************************************/ - portp->stats.signals = (unsigned long) stl_getsignals(portp); +/* + * If we are TX flow controlled and in IXANY mode then we may + * need to unflow control here. We gotta do this because of the + * automatic flow control modes of the sc26198. + */ +static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty) +{ + unsigned char mr0; - copy_to_user(cp, &portp->stats, sizeof(comstats_t)); - return(0); + mr0 = stl_sc26198getreg(portp, MR0); + stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX)); + stl_sc26198setreg(portp, SCCR, CR_HOSTXON); + stl_sc26198setreg(portp, MR0, mr0); + clear_bit(ASYI_TXFLOWED, &portp->istate); } /*****************************************************************************/ /* - * Clear the port stats structure. We also return it zeroed out... + * Interrupt service routine for sc26198 panels. */ -static int stl_clrportstats(stlport_t *portp, comstats_t *cp) +static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) { - if (portp == (stlport_t *) NULL) { - copy_from_user(&stl_comstats, cp, sizeof(comstats_t)); - portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - } + stlport_t *portp; + unsigned int iack; - memset(&portp->stats, 0, sizeof(comstats_t)); - portp->stats.brd = portp->brdnr; - portp->stats.panel = portp->panelnr; - portp->stats.port = portp->portnr; - copy_to_user(cp, &portp->stats, sizeof(comstats_t)); - return(0); +/* + * Work around bug in sc26198 chip... Cannot have A6 address + * line of UART high, else iack will be returned as 0. + */ + outb(0, (iobase + 1)); + + iack = inb(iobase + XP_IACK); + portp = panelp->ports[(iack & IVR_CHANMASK)]; + + if (iack & IVR_RXDATA) + stl_sc26198rxisr(portp, iack); + else if (iack & IVR_TXDATA) + stl_sc26198txisr(portp); + else + stl_sc26198otherisr(portp, iack); } /*****************************************************************************/ /* - * Return the entire driver ports structure to a user app. + * Transmit interrupt handler. This has gotta be fast! Handling TX + * chars is pretty simple, stuff as many as possible from the TX buffer + * into the sc26198 FIFO. + * In practice it is possible that interrupts are enabled but that the + * port has been hung up. Need to handle not having any TX buffer here, + * this is done by using the side effect that head and tail will also + * be NULL if the buffer has been freed. */ -static int stl_getportstruct(unsigned long arg) +static void stl_sc26198txisr(stlport_t *portp) { - stlport_t *portp; + unsigned int ioaddr; + unsigned char mr0; + int len, stlen; + char *head, *tail; - copy_from_user(&stl_dummyport, (void *) arg, sizeof(stlport_t)); - portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr, - stl_dummyport.portnr); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - copy_to_user((void *) arg, portp, sizeof(stlport_t)); - return(0); +#if DEBUG + printk("stl_sc26198txisr(portp=%x)\n", (int) portp); +#endif + + ioaddr = portp->ioaddr; + head = portp->tx.head; + tail = portp->tx.tail; + len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); + if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { + set_bit(ASYI_TXLOW, &portp->istate); + queue_task_irq_off(&portp->tqueue, &tq_scheduler); + } + + if (len == 0) { + outb((MR0 | portp->uartaddr), (ioaddr + XP_ADDR)); + mr0 = inb(ioaddr + XP_DATA); + if ((mr0 & MR0_TXMASK) == MR0_TXEMPTY) { + portp->imr &= ~IR_TXRDY; + outb((IMR | portp->uartaddr), (ioaddr + XP_ADDR)); + outb(portp->imr, (ioaddr + XP_DATA)); + clear_bit(ASYI_TXBUSY, &portp->istate); + } else { + mr0 |= ((mr0 & ~MR0_TXMASK) | MR0_TXEMPTY); + outb(mr0, (ioaddr + XP_DATA)); + } + } else { + len = MIN(len, SC26198_TXFIFOSIZE); + portp->stats.txtotal += len; + stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail)); + outb((GTXFIFO | portp->uartaddr), (ioaddr + XP_ADDR)); + outsb((ioaddr + XP_DATA), tail, stlen); + len -= stlen; + tail += stlen; + if (tail >= (portp->tx.buf + STL_TXBUFSIZE)) + tail = portp->tx.buf; + if (len > 0) { + outsb((ioaddr + XP_DATA), tail, len); + tail += len; + } + portp->tx.tail = tail; + } } /*****************************************************************************/ /* - * Return the entire driver board structure to a user app. + * Receive character interrupt handler. Determine if we have good chars + * or bad chars and then process appropriately. Good chars are easy + * just shove the lot into the RX buffer and set all status byte to 0. + * If a bad RX char then process as required. This routine needs to be + * fast! In practice it is possible that we get an interrupt on a port + * that is closed. This can happen on hangups - since they completely + * shutdown a port not in user context. Need to handle this case. */ -static int stl_getbrdstruct(unsigned long arg) +static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack) { - stlbrd_t *brdp; + struct tty_struct *tty; + unsigned int len, buflen, ioaddr; - copy_from_user(&stl_dummybrd, (void *) arg, sizeof(stlbrd_t)); - if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS)) - return(-ENODEV); - brdp = stl_brds[stl_dummybrd.brdnr]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - copy_to_user((void *) arg, brdp, sizeof(stlbrd_t)); - return(0); +#if DEBUG + printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack); +#endif + + tty = portp->tty; + ioaddr = portp->ioaddr; + outb((GIBCR | portp->uartaddr), (ioaddr + XP_ADDR)); + len = inb(ioaddr + XP_DATA) + 1; + + if ((iack & IVR_TYPEMASK) == IVR_RXDATA) { + if ((tty == (struct tty_struct *) NULL) || + (tty->flip.char_buf_ptr == (char *) NULL) || + ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) { + outb((GRXFIFO | portp->uartaddr), (ioaddr + XP_ADDR)); + insb((ioaddr + XP_DATA), &stl_unwanted[0], len); + portp->stats.rxlost += len; + portp->stats.rxtotal += len; + } else { + len = MIN(len, buflen); + if (len > 0) { + outb((GRXFIFO | portp->uartaddr), (ioaddr + XP_ADDR)); + insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len); + memset(tty->flip.flag_buf_ptr, 0, len); + tty->flip.flag_buf_ptr += len; + tty->flip.char_buf_ptr += len; + tty->flip.count += len; + tty_schedule_flip(tty); + portp->stats.rxtotal += len; + } + } + } else { + stl_sc26198rxbadchars(portp); + } + +/* + * If we are TX flow controlled and in IXANY mode then we may need + * to unflow control here. We gotta do this because of the automatic + * flow control modes of the sc26198. + */ + if (test_bit(ASYI_TXFLOWED, &portp->istate)) { + if ((tty != (struct tty_struct *) NULL) && + (tty->termios != (struct termios *) NULL) && + (tty->termios->c_iflag & IXANY)) { + stl_sc26198txunflow(portp, tty); + } + } } /*****************************************************************************/ /* - * The "staliomem" device is also required to do some special operations - * on the board and/or ports. In this driver it is mostly used for stats - * collection. + * Process an RX bad character. */ -static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) +static void inline stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch) { - int brdnr, rc; + struct tty_struct *tty; + unsigned int ioaddr; -#if DEBUG - printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, (int) fp, cmd, (int) arg); + tty = portp->tty; + ioaddr = portp->ioaddr; + + if (status & SR_RXPARITY) + portp->stats.rxparity++; + if (status & SR_RXFRAMING) + portp->stats.rxframing++; + if (status & SR_RXOVERRUN) + portp->stats.rxoverrun++; + if (status & SR_RXBREAK) + portp->stats.rxbreaks++; + + if ((tty != (struct tty_struct *) NULL) && + ((portp->rxignoremsk & status) == 0)) { + if (portp->rxmarkmsk & status) { + if (status & SR_RXBREAK) { + status = TTY_BREAK; +#ifndef MODULE + if (portp->flags & ASYNC_SAK) { + do_SAK(tty); + BRDENABLE(portp->brdnr, portp->pagenr); + } #endif + } else if (status & SR_RXPARITY) { + status = TTY_PARITY; + } else if (status & SR_RXFRAMING) { + status = TTY_FRAME; + } else if(status & SR_RXOVERRUN) { + status = TTY_OVERRUN; + } else { + status = 0; + } + } else { + status = 0; + } - brdnr = MINOR(ip->i_rdev); - if (brdnr >= STL_MAXBRDS) - return(-ENODEV); - rc = 0; + if (tty->flip.char_buf_ptr != (char *) NULL) { + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.flag_buf_ptr++ = status; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + } + tty_schedule_flip(tty); + } - switch (cmd) { - case COM_GETPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0) - rc = stl_getportstats((stlport_t *) NULL, (comstats_t *) arg); - break; - case COM_CLRPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0) - rc = stl_clrportstats((stlport_t *) NULL, (comstats_t *) arg); - break; - case COM_GETBRDSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(combrd_t))) == 0) - rc = stl_getbrdstats((combrd_t *) arg); - break; - case COM_READPORT: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlport_t))) == 0) - rc = stl_getportstruct(arg); - break; - case COM_READBOARD: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlbrd_t))) == 0) - rc = stl_getbrdstruct(arg); - break; - default: - rc = -ENOIOCTLCMD; - break; + if (status == 0) + portp->stats.rxtotal++; } - - return(rc); } /*****************************************************************************/ -int stl_init(void) -{ - printk(KERN_INFO "%s: version %s\n", stl_drvname, stl_drvversion); +/* + * Process all characters in the RX FIFO of the UART. Check all char + * status bytes as well, and process as required. We need to check + * all bytes in the FIFO, in case some more enter the FIFO while we + * are here. To get the exact character error type we need to switch + * into CHAR error mode (that is why we need to make sure we empty + * the FIFO). + */ - stl_initbrds(); +static void stl_sc26198rxbadchars(stlport_t *portp) +{ + unsigned char status, mr1; + char ch; /* - * Allocate a temporary write buffer. + * To get the precise error type for each character we must switch + * back into CHAR error mode. */ - stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (stl_tmpwritebuf == (char *) NULL) - printk("STALLION: failed to allocate memory (size=%d)\n", STL_TXBUFSIZE); + mr1 = stl_sc26198getreg(portp, MR1); + stl_sc26198setreg(portp, MR1, (mr1 & ~MR1_ERRBLOCK)); + + while ((status = stl_sc26198getreg(portp, SR)) & SR_RXRDY) { + stl_sc26198setreg(portp, CCR, CR_CLEARRXERR); + ch = stl_sc26198getreg(portp, RXFIFO); + stl_sc26198rxbadch(portp, status, ch); + } /* - * Set up a character driver for per board stuff. This is mainly used - * to do stats ioctls on the ports. + * To get correct interrupt class we must switch back into BLOCK + * error mode. */ - if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) - printk("STALLION: failed to register serial board device\n"); + stl_sc26198setreg(portp, MR1, mr1); +} + +/*****************************************************************************/ /* - * Set up the tty driver structure and register us as a driver. - * Also setup the callout tty device. + * Other interrupt handler. This includes modem signals, flow + * control actions, etc. Most stuff is left to off-level interrupt + * processing time. */ - memset(&stl_serial, 0, sizeof(struct tty_driver)); - stl_serial.magic = TTY_DRIVER_MAGIC; - stl_serial.name = stl_serialname; - stl_serial.major = STL_SERIALMAJOR; - stl_serial.minor_start = 0; - stl_serial.num = STL_MAXBRDS * STL_MAXPORTS; - stl_serial.type = TTY_DRIVER_TYPE_SERIAL; - stl_serial.subtype = STL_DRVTYPSERIAL; - stl_serial.init_termios = stl_deftermios; - stl_serial.flags = TTY_DRIVER_REAL_RAW; - stl_serial.refcount = &stl_refcount; - stl_serial.table = stl_ttys; - stl_serial.termios = stl_termios; - stl_serial.termios_locked = stl_termioslocked; - - stl_serial.open = stl_open; - stl_serial.close = stl_close; - stl_serial.write = stl_write; - stl_serial.put_char = stl_putchar; - stl_serial.flush_chars = stl_flushchars; - stl_serial.write_room = stl_writeroom; - stl_serial.chars_in_buffer = stl_charsinbuffer; - stl_serial.ioctl = stl_ioctl; - stl_serial.set_termios = stl_settermios; - stl_serial.throttle = stl_throttle; - stl_serial.unthrottle = stl_unthrottle; - stl_serial.stop = stl_stop; - stl_serial.start = stl_start; - stl_serial.hangup = stl_hangup; - stl_serial.flush_buffer = stl_flushbuffer; - stl_callout = stl_serial; - stl_callout.name = stl_calloutname; - stl_callout.major = STL_CALLOUTMAJOR; - stl_callout.subtype = STL_DRVTYPCALLOUT; +static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack) +{ + unsigned char cir, ipr, xisr; - if (tty_register_driver(&stl_serial)) - printk("STALLION: failed to register serial driver\n"); - if (tty_register_driver(&stl_callout)) - printk("STALLION: failed to register callout driver\n"); +#if DEBUG + printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack); +#endif - return(0); + cir = stl_sc26198getglobreg(portp, CIR); + + switch (cir & CIR_SUBTYPEMASK) { + case CIR_SUBCOS: + ipr = stl_sc26198getreg(portp, IPR); + if (ipr & IPR_DCDCHANGE) { + set_bit(ASYI_DCDCHANGE, &portp->istate); + queue_task_irq_off(&portp->tqueue, &tq_scheduler); + portp->stats.modem++; + } + break; + case CIR_SUBXONXOFF: + xisr = stl_sc26198getreg(portp, XISR); + if (xisr & XISR_RXXONGOT) { + set_bit(ASYI_TXFLOWED, &portp->istate); + portp->stats.txxoff++; + } + if (xisr & XISR_RXXOFFGOT) { + clear_bit(ASYI_TXFLOWED, &portp->istate); + portp->stats.txxon++; + } + break; + case CIR_SUBBREAK: + stl_sc26198setreg(portp, SCCR, CR_BREAKRESET); + stl_sc26198rxbadchars(portp); + break; + default: + /*printk("%s(%d): unknown other intr cir=%x, iack=%x!\n", __FILE__, __LINE__, cir, iack);*/ + break; + } } /*****************************************************************************/ diff -u --recursive --new-file v2.1.28/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c --- v2.1.28/linux/drivers/char/tty_ioctl.c Tue Mar 4 10:25:23 1997 +++ linux/drivers/char/tty_ioctl.c Wed Mar 5 17:04:31 1997 @@ -237,7 +237,6 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb) { - int retval; struct sgttyb tmp; tmp.sg_ispeed = 0; @@ -298,7 +297,6 @@ #ifdef TIOCGETC static int get_tchars(struct tty_struct * tty, struct tchars * tchars) { - int retval; struct tchars tmp; tmp.t_intrc = tty->termios->c_cc[VINTR]; @@ -314,7 +312,6 @@ static int set_tchars(struct tty_struct * tty, struct tchars * tchars) { - int retval; struct tchars tmp; if (copy_from_user(&tmp, tchars, sizeof(tmp))) @@ -332,7 +329,6 @@ #ifdef TIOCGLTC static int get_ltchars(struct tty_struct * tty, struct ltchars * ltchars) { - int retval; struct ltchars tmp; tmp.t_suspc = tty->termios->c_cc[VSUSP]; @@ -348,7 +344,6 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars * ltchars) { - int retval; struct ltchars tmp; if (copy_from_user(&tmp, ltchars, sizeof(tmp))) @@ -503,13 +498,16 @@ (real_tty->termios_locked, (struct termios *) arg); case TIOCPKT: + { + int pktmode; + if (tty->driver.type != TTY_DRIVER_TYPE_PTY || tty->driver.subtype != PTY_TYPE_MASTER) return -ENOTTY; - retval = get_user(retval, (int *) arg); + retval = get_user(pktmode, (int *) arg); if (retval) return retval; - if (retval) { + if (pktmode) { if (!tty->packet) { tty->packet = 1; tty->link->ctrl_status = 0; @@ -517,6 +515,7 @@ } else tty->packet = 0; return 0; + } /* These two ioctl's always return success; even if */ /* the driver doesn't support them. */ case TCSBRK: case TCSBRKP: diff -u --recursive --new-file v2.1.28/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.1.28/linux/drivers/net/myri_sbus.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/net/myri_sbus.c Wed Mar 5 17:04:32 1997 @@ -998,7 +998,8 @@ determine_reg_space_size(mp); /* Map in the MyriCOM register/localram set. */ - prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers); + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], + sdev->num_registers, sdev); if(mp->eeprom.cpuvers < CPUVERS_4_0) { /* XXX Makes no sense, if control reg is non-existant this * XXX driver cannot function at all... maybe pre-4.0 is diff -u --recursive --new-file v2.1.28/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.1.28/linux/drivers/net/sunhme.c Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/sunhme.c Wed Mar 5 17:04:32 1997 @@ -6,7 +6,7 @@ */ static char *version = - "sunhme.c:v1.1 10/Oct/96 David S. Miller (davem@caipfs.rutgers.edu)\n"; + "sunhme.c:v1.2 10/Oct/96 David S. Miller (davem@caipfs.rutgers.edu)\n"; #include @@ -279,17 +279,9 @@ { hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); - /* Downgrade duplex if full. */ - if(hp->sw_bmcr & BMCR_FULLDPLX) { - hp->sw_bmcr &= ~(BMCR_FULLDPLX); - happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); - return 0; - } - /* Downgrade from 100 to 10. */ if(hp->sw_bmcr & BMCR_SPEED100) { hp->sw_bmcr &= ~(BMCR_SPEED100); - hp->sw_bmcr |= (BMCR_FULLDPLX); happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); return 0; } @@ -346,14 +338,20 @@ /* All we care about is making sure the bigmac tx_cfg has a * proper duplex setting. */ - if(hp->timer_state == lupwait) { + if(hp->timer_state == arbwait) { hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA); - if((hp->sw_lpa & LPA_100FULL) || - (!(hp->sw_lpa & LPA_100HALF) && (hp->sw_lpa & LPA_10FULL))) + if(!(hp->sw_lpa & (LPA_10HALF | LPA_10FULL | LPA_100HALF | LPA_100FULL))) + goto no_response; + if(hp->sw_lpa & LPA_100FULL) + full = 1; + else if(hp->sw_lpa & LPA_100HALF) + full = 0; + else if(hp->sw_lpa & LPA_10FULL) full = 1; else full = 0; } else { + /* Forcing a link mode. */ hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); if(hp->sw_bmcr & BMCR_FULLDPLX) full = 1; @@ -370,6 +368,8 @@ hp->bigmacregs->tx_cfg &= ~(BIGMAC_TXCFG_FULLDPLX); return 0; +no_response: + return 1; } static int happy_meal_init(struct happy_meal *hp, int from_irq); @@ -390,11 +390,19 @@ /* Enter force mode. */ do_force_mode: hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR); - printk("%s: Auto-Negotiation timeout, trying force link " - "mode BMCR=0x%04x.\n", hp->dev->name, hp->sw_bmcr); - hp->sw_bmcr &= ~(BMCR_ANRESTART | BMCR_ANENABLE); - hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_ANENABLE); + printk("%s: Auto-Negotiation unsuccessful, trying force link mode\n", + hp->dev->name); + hp->sw_bmcr = BMCR_SPEED100; happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); + + /* OK, seems we need do disable the transceiver for the first + * tick to make sure we get an accurate link state at the + * second tick. + */ + hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); + hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); + happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); + hp->timer_state = ltrywait; hp->timer_ticks = 0; restart_timer = 1; @@ -409,6 +417,9 @@ if(ret) { /* Ooops, something bad happened, go to force * mode. + * + * XXX Broken hubs which don't support 802.3u + * XXX auto-negotiation make this happen as well. */ goto do_force_mode; } @@ -455,6 +466,21 @@ * error recovery code for the most part. */ hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR); + hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); + if(hp->timer_ticks == 1) { + /* Re-enable transceiver, we'll re-enable the transceiver next + * tick, then check link state on the following tick. */ + hp->sw_csconfig |= CSCONFIG_TCVDISAB; + happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); + restart_timer = 1; + break; + } + if(hp->timer_ticks == 2) { + hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); + happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); + restart_timer = 1; + break; + } if(hp->sw_bmsr & BMSR_LSTATUS) { /* Force mode selection success. */ display_forced_link_mode(hp, tregs); @@ -462,7 +488,7 @@ hp->timer_state = asleep; restart_timer = 0; } else { - if(hp->timer_ticks >= 3) { /* 6 seconds or so... */ + if(hp->timer_ticks >= 4) { /* 6 seconds or so... */ int ret; ret = try_next_permutation(hp, tregs); @@ -483,6 +509,9 @@ } return; } + hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); + hp->sw_csconfig |= CSCONFIG_TCVDISAB; + happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); hp->timer_ticks = 0; restart_timer = 1; } else { @@ -1033,9 +1062,19 @@ * XXX Should probably reset the DP83840 first * XXX as this is a gross fatal error... */ - hp->sw_bmcr &= ~(BMCR_ANRESTART | BMCR_ANENABLE); - hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_SPEED100); + hp->sw_bmcr = BMCR_SPEED100; happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr); + + /* OK, seems we need do disable the transceiver for the first + * tick to make sure we get an accurate link state at the + * second tick. + */ + hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); + printk("%s: CSCONFIG [%04x], disabling transceiver\n", hp->dev->name, + hp->sw_csconfig); + hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); + happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); + hp->timer_state = ltrywait; } else { hp->timer_state = arbwait; @@ -1379,9 +1418,11 @@ /* Defer-timer expired. Probably means the happy meal needed * to back off too much before it could transmit one frame. */ +#if 0 /* XXX This isn't worth reporting and is in fact a normal condition. */ printk("%s: Transmit defer timer expired, subnet congested?\n", hp->dev->name); reset = 1; +#endif } if(status & GREG_STAT_NORXD) { @@ -2050,7 +2091,8 @@ return ENODEV; } - prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers); + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], + sdev->num_registers, sdev); hp->gregs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, sizeof(struct hmeal_gregs), "Happy Meal Global Regs", @@ -2196,10 +2238,16 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_happy_dev) { + struct happy_meal *hp = root_happy_dev; sunshine = root_happy_dev->next_module; - unregister_netdev(root_happy_dev->dev); - kfree(root_happy_dev->dev); + sparc_free_io(hp->gregs, sizeof(struct hmeal_gregs)); + sparc_free_io(hp->etxregs, sizeof(struct hmeal_etxregs)); + sparc_free_io(hp->erxregs, sizeof(struct hmeal_erxregs)); + sparc_free_io(hp->bigmacregs, sizeof(struct hmeal_bigmacregs)); + sparc_free_io(hp->tcvregs, sizeof(struct hmeal_tcvregs)); + unregister_netdev(hp->dev); + kfree(hp->dev); root_happy_dev = sunshine; } } diff -u --recursive --new-file v2.1.28/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h --- v2.1.28/linux/drivers/net/sunhme.h Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/sunhme.h Wed Mar 5 17:04:32 1997 @@ -370,7 +370,7 @@ #define CSCONFIG_LED4 0x0002 /* Pin for full-dplx LED4 */ #define CSCONFIG_LED1 0x0004 /* Pin for conn-status LED1 */ #define CSCONFIG_RESV2 0x0008 /* Unused... */ -#define CSCONFIG_TXDISAB 0x0010 /* Turns off the transceiver */ +#define CSCONFIG_TCVDISAB 0x0010 /* Turns off the transceiver */ #define CSCONFIG_DFBYPASS 0x0020 /* Bypass disconnect function */ #define CSCONFIG_GLFORCE 0x0040 /* Good link force for 100mbps */ #define CSCONFIG_CLKTRISTATE 0x0080 /* Tristate 25m clock */ @@ -528,6 +528,7 @@ unsigned short sw_advertise; /* SW copy of ADVERTISE */ unsigned short sw_lpa; /* SW copy of LPA */ unsigned short sw_expansion; /* SW copy of EXPANSION */ + unsigned short sw_csconfig; /* SW copy of CSCONFIG */ unsigned int auto_speed; /* Auto-nego link speed */ unsigned int forced_speed; /* Force mode link speed */ unsigned int poll_data; /* MIF poll data */ @@ -540,7 +541,7 @@ enum happy_timer_state timer_state; /* State of the auto-neg timer. */ unsigned int timer_ticks; /* Number of clicks at each state. */ - struct net_device_stats enet_stats; /* Statistical counters */ + struct net_device_stats net_stats; /* Statistical counters */ struct linux_sbus_device *happy_sbus_dev; /* ;-) */ struct device *dev; /* Backpointer */ struct happy_meal *next_module; diff -u --recursive --new-file v2.1.28/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.1.28/linux/drivers/net/sunlance.c Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/sunlance.c Wed Mar 5 17:04:32 1997 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.52 1997/01/25 23:29:56 ecd Exp $ +/* $Id: sunlance.c,v 1.55 1997/02/07 09:41:07 ecd Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -477,6 +477,8 @@ return 0; } + lp->stats.rx_bytes += len; + skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align */ skb_put (skb, len); /* make room */ @@ -803,7 +805,7 @@ len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; - lp->stats.tx_bytes+=len; + lp->stats.tx_bytes += len; entry = lp->tx_new & TX_RING_MOD_MASK; ib->btx_ring [entry].length = (-len) | 0xf000; @@ -958,7 +960,7 @@ /* Get the IO region */ prom_apply_sbus_ranges (sdev->my_bus, &sdev->reg_addrs [0], - sdev->num_registers); + sdev->num_registers, sdev); ll = sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, sizeof (struct lance_regs), lancestr, sdev->reg_addrs[0].which_io, 0x0); @@ -970,7 +972,8 @@ if (lebuffer){ prom_apply_sbus_ranges (lebuffer->my_bus, &lebuffer->reg_addrs [0], - lebuffer->num_registers); + lebuffer->num_registers, + lebuffer); lp->init_block = (void *) sparc_alloc_io (lebuffer->reg_addrs [0].phys_addr, 0, sizeof (struct lance_init_block), "lebuffer", diff -u --recursive --new-file v2.1.28/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.1.28/linux/drivers/net/sunqe.c Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/sunqe.c Wed Mar 5 17:04:32 1997 @@ -777,7 +777,7 @@ /* Get it going. */ qep->qcregs->ctrl = CREG_CTRL_TWAKEUP; - qep->stats.tx_bytes+=skb->len; + qep->net_stats.tx_bytes+=skb->len; dev_kfree_skb(skb, FREE_WRITE); @@ -980,11 +980,13 @@ qesdevs[i]->reg_addrs[j].phys_addr += qranges[k].ot_parent_base; } - prom_apply_sbus_ranges(qesdevs[i]->my_bus, &qesdevs[i]->reg_addrs[0], 2); + prom_apply_sbus_ranges(qesdevs[i]->my_bus, &qesdevs[i]->reg_addrs[0], + 2, qesdevs[i]); } /* Now map in the registers, QEC globals first. */ - prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers); + prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], + sdev->num_registers, sdev); qecp->gregs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, sizeof(struct qe_globreg), "QEC Global Registers", diff -u --recursive --new-file v2.1.28/linux/drivers/net/sunqe.h linux/drivers/net/sunqe.h --- v2.1.28/linux/drivers/net/sunqe.h Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/sunqe.h Wed Mar 5 17:04:32 1997 @@ -360,7 +360,7 @@ struct sunqec *parent; - struct net_device_stats enet_stats; /* Statistical counters */ + struct net_device_stats net_stats; /* Statistical counters */ struct linux_sbus_device *qe_sbusdev; /* QE's SBUS device struct */ struct device *dev; /* QE's netdevice struct */ int channel; /* Who am I? */ diff -u --recursive --new-file v2.1.28/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.1.28/linux/drivers/net/wavelan.c Sun Jan 19 05:47:25 1997 +++ linux/drivers/net/wavelan.c Tue Mar 4 13:19:06 1997 @@ -1009,8 +1009,10 @@ mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m)); mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); +#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ /* Don't forget to update statistics */ lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; +#endif /* WIRELESS_EXT */ printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED @@ -1548,7 +1550,7 @@ } /* Setting by channel (same as wfreqsel) */ - /* Warning : each channel is 22MHz wide, so some of the channels + /* Warning : each channel is 11MHz wide, so some of the channels * will interfere... */ if((frequency->e == 0) && (frequency->m >= 0) && (frequency->m < BAND_NUM)) @@ -1931,6 +1933,23 @@ } break; + case SIOCSIWSENS: + /* Set the level threshold */ + if(!suser()) + return -EPERM; + psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; + psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); + break; + + case SIOCGIWSENS: + /* Read the level threshold */ + psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; + break; + case SIOCGIWRANGE: /* Basic checking... */ if(wrq->u.data.pointer != (caddr_t) 0) @@ -1962,6 +1981,7 @@ else range.num_channels = range.num_frequency = 0; + range.sensitivity = 0x3F; range.max_qual.qual = MMR_SGNL_QUAL; range.max_qual.level = MMR_SIGNAL_LVL; range.max_qual.noise = MMR_SILENCE_LVL; @@ -1980,8 +2000,6 @@ { /* cmd, set_args, get_args, name */ { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, - { SIOCSIPLTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setlevelthr" }, - { SIOCGIPLTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getlevelthr" }, { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, @@ -1994,7 +2012,7 @@ break; /* Set the number of ioctl available */ - wrq->u.data.length = 6; + wrq->u.data.length = 4; /* Copy structure to the user buffer */ copy_to_user(wrq->u.data.pointer, (u_char *) priv, @@ -2115,21 +2133,6 @@ *(wrq->u.name) = psa.psa_quality_thr & 0x0F; break; - case SIOCSIPLTHR: - if(!suser()) - return -EPERM; - psa.psa_thr_pre_set = *(wrq->u.name) & 0x3F; - psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *)&psa.psa_thr_pre_set, 1); - mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); - break; - - case SIOCGIPLTHR: - psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *)&psa.psa_thr_pre_set, 1); - *(wrq->u.name) = psa.psa_thr_pre_set & 0x3F; - break; - #ifdef HISTOGRAM case SIOCSIPHISTO: /* Verif if the user is root */ @@ -4016,9 +4019,11 @@ * 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... */ - -int wavelan_probe(device * dev) +/* extern */ int +wavelan_probe(device * dev) { short base_addr; mac_addr mac; /* Mac address (check wavelan existence) */ diff -u --recursive --new-file v2.1.28/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h --- v2.1.28/linux/drivers/net/wavelan.h Thu Dec 19 07:10:25 1996 +++ linux/drivers/net/wavelan.h Tue Mar 4 13:19:06 1997 @@ -225,7 +225,7 @@ unsigned char mmw_jam_time; /* jamming time (after collision) */ unsigned char mmw_unused2[1]; /* unused */ unsigned char mmw_thr_pre_set; /* level threshold preset */ - /* Discard all packet with signal < this value (0) */ + /* Discard all packet with signal < this value (4) */ unsigned char mmw_decay_prm; /* decay parameters */ unsigned char mmw_decay_updat_prm; /* decay update parameterz */ unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ diff -u --recursive --new-file v2.1.28/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h --- v2.1.28/linux/drivers/net/wavelan.p.h Sun Feb 2 05:18:42 1997 +++ linux/drivers/net/wavelan.p.h Tue Mar 4 13:19:06 1997 @@ -139,11 +139,6 @@ * the code * Loeke Brederveld from Lucent has given me * much needed informations on the Wavelan hardware. - * - * Yongguang Zhang send me a patch for enabling - * multicast in the old pcmcia driver. I tried to do the same (with - * some minor changes) in this driver, but without any luck (I don't - * know how to enable multicast in the chip...). */ /* The original copyrights and litteratures mention others names and @@ -173,6 +168,7 @@ * Robert Morris (rtm@das.harvard.edu), * Jean Tourrilhes (jt@hplb.hpl.hp.com), * Girish Welling (welling@paul.rutgers.edu), + * Clark Woodworth * Yongguang Zhang ... * * Thanks go also to: @@ -258,6 +254,13 @@ * - Update to wireless extensions changes * - Silly bug in card initial configuration (psa_conf_status) * + * Changes made for release in 2.1.27 : + * ---------------------------------- + * - Small bug in debug code (probably not the last one...) + * - Remove extern kerword for wavelan_probe() + * - Level threshold is now a standard wireless extension (version 4 !) + * - modules parameters types (new module interface) + * * Wishes & dreams : * --------------- * - Encryption stuff @@ -344,7 +347,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v12 (wireless extensions) 1/12/96\n"; +static const char *version = "wavelan.c : v15 (wireless extensions) 12/2/97\n"; #endif /* Watchdog temporisation */ @@ -608,13 +611,13 @@ }; #ifdef MODULE -/* Name of the devices (memory allocation) */ -static char devname[4][IFNAMSIZ] = { "", "", "", "" }; - /* Parameters set by insmod */ static int io[4] = { 0, 0, 0, 0 }; static int irq[4] = { 0, 0, 0, 0 }; -static char * name[4] = { devname[0], devname[1], devname[2], devname[3] }; +static char name[4][IFNAMSIZ] = { "", "", "", "" }; +MODULE_PARM(io, "1-4i"); +MODULE_PARM(irq, "1-4i"); +MODULE_PARM(name, "1-4c" __MODULE_STRING(IFNAMSIZ)); #endif /* MODULE */ #endif /* WAVELAN_P_H */ diff -u --recursive --new-file v2.1.28/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.1.28/linux/drivers/pci/pci.c Tue Mar 4 10:25:23 1997 +++ linux/drivers/pci/pci.c Tue Mar 4 13:24:05 1997 @@ -47,6 +47,11 @@ DEVICE( NCR, NCR_53C820, "53c820"), DEVICE( NCR, NCR_53C825, "53c825"), DEVICE( NCR, NCR_53C815, "53c815"), + DEVICE( NCR, NCR_53C860, "53c860"), + DEVICE( NCR, NCR_53C896, "53c896"), + DEVICE( NCR, NCR_53C895, "53c895"), + DEVICE( NCR, NCR_53C885, "53c885"), + DEVICE( NCR, NCR_53C875, "53c875"), DEVICE( ATI, ATI_68800, "68800AX"), DEVICE( ATI, ATI_215CT222, "215CT222"), DEVICE( ATI, ATI_210888CX, "210888CX"), diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/Makefile linux/drivers/sbus/Makefile --- v2.1.28/linux/drivers/sbus/Makefile Fri Dec 13 01:37:32 1996 +++ linux/drivers/sbus/Makefile Wed Mar 5 17:04:32 1997 @@ -8,8 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile... SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) char -ALL_SUB_DIRS := $(SUB_DIRS) char +MOD_SUB_DIRS := $(SUB_DIRS) char audio +ALL_SUB_DIRS := $(SUB_DIRS) char audio L_OBJS := sbus.o dvma.o L_TARGET := sbus.a @@ -19,6 +19,13 @@ ifeq ($(CONFIG_SBUSCHAR),y) SUB_DIRS += char L_OBJS += char/sunchar.o +endif + +# Audio devices for SBUS-based machines. +# +ifeq ($(CONFIG_SPARCAUDIO),y) +SUB_DIRS += audio +L_OBJS += audio/sparcaudio.o endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/audio/Config.in linux/drivers/sbus/audio/Config.in --- v2.1.28/linux/drivers/sbus/audio/Config.in Sun Jan 26 02:07:17 1997 +++ linux/drivers/sbus/audio/Config.in Wed Mar 5 17:04:32 1997 @@ -2,10 +2,11 @@ # Configuration script for sparcaudio subsystem # -if [ "x$CONFIG_EXPERIMENTAL" = "xy" ]; then +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - comment 'Linux/SPARC audio subsystem' + comment 'Linux/SPARC audio subsystem (EXPERIMENTAL)' - tristate 'Audio support' CONFIG_SPARCAUDIO + tristate 'Audio support (EXPERIMENTAL)' CONFIG_SPARCAUDIO dep_tristate ' AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO + dep_tristate ' CS4231 Lowlevel Driver' CONFIG_SPARCAUDIO_CS4231 $CONFIG_SPARCAUDIO fi diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/audio/Makefile linux/drivers/sbus/audio/Makefile --- v2.1.28/linux/drivers/sbus/audio/Makefile Sun Jan 26 02:07:17 1997 +++ linux/drivers/sbus/audio/Makefile Wed Mar 5 17:04:32 1997 @@ -15,6 +15,14 @@ O_OBJS := M_OBJS := +ifeq ($(CONFIG_SPARCAUDIO),y) +M=y +else + ifeq ($(CONFIG_SPARCAUDIO),m) + MM=y + endif +endif + ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y) M=y O_OBJS += amd7930.o @@ -25,11 +33,21 @@ endif endif +ifeq ($(CONFIG_SPARCAUDIO_CS4231),y) +M=y +O_OBJS += cs4231.o +else + ifeq ($(CONFIG_SPARCAUDIO_CS4231),m) + MM=y + M_OBJS += cs4231.o + endif +endif + ifdef M -O_OBJS += audio.o +OX_OBJS += audio.o else ifdef MM - M_OBJS += audio.o + MX_OBJS += audio.o endif endif diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c --- v2.1.28/linux/drivers/sbus/audio/amd7930.c Sun Jan 26 02:07:17 1997 +++ linux/drivers/sbus/audio/amd7930.c Wed Mar 5 17:04:32 1997 @@ -15,35 +15,42 @@ #include #include #include +#include #include #include #include #include #include +#include + #include "audio.h" #include "amd7930.h" -/* - * Chip interface - */ -struct mapreg { - u_short mr_x[8]; - u_short mr_r[8]; - u_short mr_gx; - u_short mr_gr; - u_short mr_ger; - u_short mr_stgr; - u_short mr_ftgr; - u_short mr_atgr; - u_char mr_mmr1; - u_char mr_mmr2; -} map; +#define MAX_DRIVERS 1 +/* Private information we store for each amd7930 chip. */ +struct amd7930_info { + /* Current buffer that the driver is playing. */ + volatile __u8 * output_ptr; + volatile unsigned long output_count; + + /* Current record buffer. */ + volatile __u8 * input_ptr; + volatile unsigned long input_count; + + /* Device registers information. */ + struct amd7930 *regs; + unsigned long regs_size; + struct amd7930_map map; + + /* Device interrupt information. */ + int irq; + volatile int ints_on; +}; -/* Write 16 bits of data from variable v to the data port of the audio chip */ -#define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8) +/* Output a 16-bit quantity in the order that the amd7930 expects. */ +#define amd7930_out16(regs,v) ({ regs->dr = v & 0xFF; regs->dr = (v >> 8) & 0xFF; }) -/* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */ /* * gx, gr & stg gains. this table must contain 256 elements with @@ -51,7 +58,7 @@ * elements match sun's gain curve (but with higher resolution): * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps. */ -static const u_short gx_coeff[256] = { +static __const__ __u16 gx_coeff[256] = { 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33, 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22, 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b, @@ -86,10 +93,7 @@ 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e, }; -/* - * second stage play gain. - */ -static const u_short ger_coeff[] = { +static __const__ __u16 ger_coeff[] = { 0x431f, /* 5. dB */ 0x331f, /* 5.5 dB */ 0x40dd, /* 6. dB */ @@ -111,262 +115,362 @@ 0x2200, /* 15.9 dB */ 0x000b, /* 16.9 dB */ 0x000f /* 18. dB */ -#define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) }; - -#if 0 -int -amd7930_commit_settings(addr) - void *addr; -{ - register struct amd7930_softc *sc = addr; - register struct mapreg *map; - register volatile struct amd7930 *amd; - register int s, level; - - DPRINTF(("sa_commit.\n")); - - map = &sc->sc_map; - amd = sc->sc_au.au_amd; - - map->mr_gx = gx_coeff[sc->sc_rlevel]; - map->mr_stgr = gx_coeff[sc->sc_mlevel]; - - level = (sc->sc_plevel * (256 + NGER)) >> 8; - if (level >= 256) { - map->mr_ger = ger_coeff[level - 256]; - map->mr_gr = gx_coeff[255]; - } else { - map->mr_ger = ger_coeff[0]; - map->mr_gr = gx_coeff[level]; - } - - if (sc->sc_out_port == SUNAUDIO_SPEAKER) - map->mr_mmr2 |= AMD_MMR2_LS; - else - map->mr_mmr2 &= ~AMD_MMR2_LS; - - s = splaudio(); - - amd->cr = AMDR_MAP_MMR1; - amd->dr = map->mr_mmr1; - amd->cr = AMDR_MAP_GX; - WAMD16(amd, map->mr_gx); - amd->cr = AMDR_MAP_STG; - WAMD16(amd, map->mr_stgr); - amd->cr = AMDR_MAP_GR; - WAMD16(amd, map->mr_gr); - amd->cr = AMDR_MAP_GER; - WAMD16(amd, map->mr_ger); - amd->cr = AMDR_MAP_MMR2; - amd->dr = map->mr_mmr2; - - splx(s); - return(0); -} -#endif - -static int amd7930_node, amd7930_irq, amd7930_regs_size, amd7930_ints_on = 0; -static struct amd7930 *amd7930_regs = NULL; -static __u8 * ptr; -static size_t count; +#define NR_GER_COEFFS (sizeof(ger_coeff) / sizeof(ger_coeff[0])) /* Enable amd7930 interrupts atomically. */ -static __inline__ void amd7930_enable_ints(void) +static __inline__ void amd7930_enable_ints(struct sparcaudio_driver *drv) { + struct amd7930_info *info = (struct amd7930_info *)drv->private; register unsigned long flags; - if (amd7930_ints_on) + if (info->ints_on) return; save_and_cli(flags); - amd7930_regs->cr = AMR_INIT; - amd7930_regs->dr = AM_INIT_ACTIVE; + info->regs->cr = AMR_INIT; + info->regs->dr = AM_INIT_ACTIVE; restore_flags(flags); - amd7930_ints_on = 1; + info->ints_on = 1; } /* Disable amd7930 interrupts atomically. */ -static __inline__ void amd7930_disable_ints(void) +static __inline__ void amd7930_disable_ints(struct sparcaudio_driver *drv) { + struct amd7930_info *info = (struct amd7930_info *)drv->private; register unsigned long flags; - if (!amd7930_ints_on) + if (!info->ints_on) return; save_and_cli(flags); - amd7930_regs->cr = AMR_INIT; - amd7930_regs->dr = AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS; + info->regs->cr = AMR_INIT; + info->regs->dr = AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS; restore_flags(flags); - amd7930_ints_on = 0; + info->ints_on = 0; } +/* Commit the local copy of the MAP registers to the amd7930. */ +static void amd7930_commit_map(struct sparcaudio_driver *drv) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + struct amd7930 *regs = info->regs; + struct amd7930_map *map = &info->map; + unsigned long flags; + + save_and_cli(flags); + + regs->cr = AMR_MAP_GX; + amd7930_out16(regs, map->gx); + + regs->cr = AMR_MAP_GR; + amd7930_out16(regs, map->gr); + + regs->cr = AMR_MAP_STGR; + amd7930_out16(regs, map->stgr); + + regs->cr = AMR_MAP_GER; + amd7930_out16(regs, map->ger); + + regs->cr = AMR_MAP_MMR1; + regs->dr = map->mmr1; + + regs->cr = AMR_MAP_MMR2; + regs->dr = map->mmr2; -/* Audio interrupt handler. */ -static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *regs) + restore_flags(flags); +} + +/* Interrupt handler (The chip takes only one byte per interrupt. Grrr!) */ +static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *intr_regs) { + struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; + struct amd7930_info *info = (struct amd7930_info *)drv->private; + struct amd7930 *regs = info->regs; __u8 dummy; /* Clear the interrupt. */ - dummy = amd7930_regs->ir; + dummy = regs->ir; /* Send the next byte of outgoing data. */ - if (ptr && count > 0) { - /* Send the next byte and advance the head pointer. */ - amd7930_regs->bbtb = *ptr; - ptr++; - count--; - - /* Empty buffer? Notify the midlevel driver. */ - if (count == 0) - sparcaudio_output_done(); + if (info->output_ptr && info->output_count > 0) { + /* Send the next byte and advance buffer pointer. */ + regs->bbtb = *(info->output_ptr); + info->output_ptr++; + info->output_count--; + + /* Done with the buffer? Notify the midlevel driver. */ + if (info->output_count == 0) { + info->output_ptr = NULL; + info->output_count = 0; + sparcaudio_output_done(drv); + } + } + + /* Read the next byte of incoming data. */ + if (info->input_ptr && info->input_count > 0) { + /* Get the next byte and advance buffer pointer. */ + *(info->input_ptr) = regs->bbrb; + info->input_ptr++; + info->input_count--; + + /* Done with the buffer? Notify the midlevel driver. */ + if (info->input_count == 0) { + info->input_ptr = NULL; + info->input_count = 0; + sparcaudio_input_done(drv); + } } } -static int amd7930_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) + +static int amd7930_open(struct inode * inode, struct file * file, + struct sparcaudio_driver *drv) { + struct amd7930_info *info = (struct amd7930_info *)drv->private; int level; /* Set the default audio parameters. */ - map.mr_gx = gx_coeff[128]; - map.mr_stgr = gx_coeff[0]; + info->map.gx = gx_coeff[128]; + info->map.stgr = gx_coeff[0]; - level = (128 * (256 + NGER)) >> 8; + level = (128 * (256 + NR_GER_COEFFS)) >> 8; if (level >= 256) { - map.mr_ger = ger_coeff[level-256]; - map.mr_gr = gx_coeff[255]; + info->map.ger = ger_coeff[level-256]; + info->map.gr = gx_coeff[255]; } else { - map.mr_ger = ger_coeff[0]; - map.mr_gr = gx_coeff[level]; + info->map.ger = ger_coeff[0]; + info->map.gr = gx_coeff[level]; } - map.mr_mmr2 |= AM_MAP_MMR2_LS; + info->map.mmr2 |= AM_MAP_MMR2_LS; - cli(); - - amd7930_regs->cr = AMR_MAP_MMR1; - amd7930_regs->dr = map.mr_mmr1; - amd7930_regs->cr = AMR_MAP_GX; - WAMD16(amd7930_regs,map.mr_gx); - amd7930_regs->cr = AMR_MAP_STG; - WAMD16(amd7930_regs,map.mr_stgr); - amd7930_regs->cr = AMR_MAP_GR; - WAMD16(amd7930_regs,map.mr_gr); - amd7930_regs->cr = AMR_MAP_GER; - WAMD16(amd7930_regs,map.mr_ger); - amd7930_regs->cr = AMR_MAP_MMR2; - amd7930_regs->dr = map.mr_mmr2; - - sti(); + amd7930_commit_map(drv); MOD_INC_USE_COUNT; return 0; } -static void amd7930_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +static void amd7930_release(struct inode * inode, struct file * file, + struct sparcaudio_driver *drv) { - amd7930_disable_ints(); + amd7930_disable_ints(drv); MOD_DEC_USE_COUNT; } -static void amd7930_start_output(struct sparcaudio_driver *drv, __u8 * buffer, size_t the_count) +static void amd7930_start_output(struct sparcaudio_driver *drv, + __u8 * buffer, unsigned long count) { - count = the_count; - ptr = buffer; - amd7930_enable_ints(); + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + info->output_ptr = buffer; + info->output_count = count; + amd7930_enable_ints(drv); } static void amd7930_stop_output(struct sparcaudio_driver *drv) { - amd7930_disable_ints(); - ptr = NULL; - count = 0; + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + info->output_ptr = NULL; + info->output_count = 0; + + if (!info->input_ptr) + amd7930_disable_ints(drv); +} + +static void amd7930_start_input(struct sparcaudio_driver *drv, + __u8 * buffer, unsigned long count) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + info->input_ptr = buffer; + info->input_count = count; + amd7930_enable_ints(drv); +} + +static void amd7930_stop_input(struct sparcaudio_driver *drv) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + info->input_ptr = NULL; + info->input_count = 0; + + if (!info->output_ptr) + amd7930_disable_ints(drv); +} + +static void amd7930_sunaudio_getdev(struct sparcaudio_driver *drv, + audio_device_t * audinfo) +{ + strncpy(audinfo->name, "amd7930", sizeof(audinfo->name) - 1); + strncpy(audinfo->version, "x", sizeof(audinfo->version) - 1); + strncpy(audinfo->config, "audio", sizeof(audinfo->config) - 1); } +/* + * Device detection and initialization. + */ + +static struct sparcaudio_driver drivers[MAX_DRIVERS]; +static int num_drivers; + static struct sparcaudio_operations amd7930_ops = { amd7930_open, amd7930_release, NULL, /* amd7930_ioctl */ amd7930_start_output, amd7930_stop_output, + amd7930_start_input, + amd7930_stop_input, + amd7930_sunaudio_getdev, }; -static struct sparcaudio_driver amd7930_drv = { - "amd7930", - &amd7930_ops, -}; - -/* Probe for the amd7930 chip and then attach the driver. */ -#ifdef MODULE -int init_module(void) -#else -__initfunc(int amd7930_init(void)) -#endif +/* Attach to an amd7930 chip given its PROM node. */ +static int amd7930_attach(struct sparcaudio_driver *drv, int node, + struct linux_sbus *sbus, struct linux_sbus_device *sdev) { - struct linux_prom_registers regs[1]; + struct linux_prom_registers regs; struct linux_prom_irqs irq; + struct amd7930_info *info; int err; -#ifdef MODULE - register_symtab(0); -#endif - - /* Find the PROM "audio" node. */ - amd7930_node = prom_getchild(prom_root_node); - amd7930_node = prom_searchsiblings(amd7930_node, "audio"); - if (!amd7930_node) - return -EIO; + /* Allocate our private information structure. */ + drv->private = kmalloc(sizeof(struct amd7930_info), GFP_KERNEL); + if (!drv->private) + return -ENOMEM; + + /* Point at the information structure and initialize it. */ + drv->ops = &amd7930_ops; + info = (struct amd7930_info *)drv->private; + info->output_ptr = info->input_ptr = NULL; + info->output_count = info->input_count = 0; + info->ints_on = 1; /* force disable below */ /* Map the registers into memory. */ - prom_getproperty(amd7930_node, "reg", (char *)regs, sizeof(regs)); - amd7930_regs_size = regs[0].reg_size; - amd7930_regs = sparc_alloc_io(regs[0].phys_addr, 0, regs[0].reg_size, - "amd7930", regs[0].which_io, 0); - if (!amd7930_regs) { + prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); + if (sbus && sdev) + prom_apply_sbus_ranges(sbus, ®s, 1, sdev); + info->regs_size = regs.reg_size; + info->regs = sparc_alloc_io(regs.phys_addr, 0, regs.reg_size, + "amd7930", regs.which_io, 0); + if (!info->regs) { printk(KERN_ERR "amd7930: could not allocate registers\n"); + kfree(drv->private); return -EIO; } /* Disable amd7930 interrupt generation. */ - amd7930_disable_ints(); + amd7930_disable_ints(drv); /* Initialize the MUX unit to connect the MAP to the CPU. */ - amd7930_regs->cr = AMR_MUX_1_4; - amd7930_regs->dr = (AM_MUX_CHANNEL_Bb << 4) | AM_MUX_CHANNEL_Ba; - amd7930_regs->dr = 0; - amd7930_regs->dr = 0; - amd7930_regs->dr = AM_MUX_MCR4_ENABLE_INTS; + info->regs->cr = AMR_MUX_1_4; + info->regs->dr = (AM_MUX_CHANNEL_Bb << 4) | AM_MUX_CHANNEL_Ba; + info->regs->dr = 0; + info->regs->dr = 0; + info->regs->dr = AM_MUX_MCR4_ENABLE_INTS; /* Attach the interrupt handler to the audio interrupt. */ - prom_getproperty(amd7930_node, "intr", (char *)&irq, sizeof(irq)); - amd7930_irq = irq.pri; - request_irq(amd7930_irq, amd7930_interrupt, SA_INTERRUPT, "amd7930", NULL); - enable_irq(amd7930_irq); - - memset(&map, 0, sizeof(map)); - map.mr_mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER | AM_MAP_MMR1_GR | AM_MAP_MMR1_STG; + prom_getproperty(node, "intr", (char *)&irq, sizeof(irq)); + info->irq = irq.pri; + request_irq(info->irq, amd7930_interrupt, + SA_INTERRUPT, "amd7930", drv); + enable_irq(info->irq); + + /* Initalize the local copy of the MAP registers. */ + memset(&info->map, 0, sizeof(info->map)); + info->map.mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER + | AM_MAP_MMR1_GR | AM_MAP_MMR1_STG; - /* Register ourselves with the midlevel audio driver. */ - err = register_sparcaudio_driver(&amd7930_drv); + /* Register the amd7930 with the midlevel audio driver. */ + err = register_sparcaudio_driver(drv); if (err < 0) { - /* XXX We should do something. Complain for now. */ - printk(KERN_ERR "amd7930: really screwed now\n"); + printk(KERN_ERR "amd7930: unable to register\n"); + disable_irq(info->irq); + free_irq(info->irq, drv); + sparc_free_io(info->regs, info->regs_size); + kfree(drv->private); return -EIO; } + /* Announce the hardware to the user. */ + printk(KERN_INFO "amd7930 at 0x%lx irq %d\n", + (unsigned long)info->regs, info->irq); + + /* Success! */ return 0; } #ifdef MODULE +/* Detach from an amd7930 chip given the device structure. */ +static void amd7930_detach(struct sparcaudio_driver *drv) +{ + struct amd7930_info *info = (struct amd7930_info *)drv->private; + + unregister_sparcaudio_driver(drv); + amd7930_disable_ints(drv); + disable_irq(info->irq); + free_irq(info->irq, drv); + sparc_free_io(info->regs, info->regs_size); + kfree(drv->private); +} +#endif + + +/* Probe for the amd7930 chip and then attach the driver. */ +#ifdef MODULE +int init_module(void) +#else +__initfunc(int amd7930_init(void)) +#endif +{ + struct linux_sbus *bus; + struct linux_sbus_device *sdev; + int node; + +#if 0 +#ifdef MODULE + register_symtab(0); +#endif +#endif + + /* Try to find the sun4c "audio" node first. */ + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "audio"); + if (node && amd7930_attach(&drivers[0], node, NULL, NULL) == 0) + num_drivers = 1; + else + num_drivers = 0; + + /* Probe each SBUS for amd7930 chips. */ + for_all_sbusdev(sdev,bus) { + if (!strcmp(sdev->prom_name, "audio")) { + /* Don't go over the max number of drivers. */ + if (num_drivers >= MAX_DRIVERS) + continue; + + if (amd7930_attach(&drivers[num_drivers], + sdev->prom_node, sdev->my_bus, sdev) == 0) + num_drivers++; + } + } + + /* Only return success if we found some amd7930 chips. */ + return (num_drivers > 0) ? 0 : -EIO; +} + +#ifdef MODULE void cleanup_module(void) { - amd7930_disable_ints(); - disable_irq(amd7930_irq); - free_irq(amd7930_irq, NULL); - sparc_free_io(amd7930_regs, amd7930_regs_size); + register int i; + + for (i = 0; i < num_drivers; i++) { + amd7930_detach(&drivers[i]); + num_drivers--; + } } #endif diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/audio/amd7930.h linux/drivers/sbus/audio/amd7930.h --- v2.1.28/linux/drivers/sbus/audio/amd7930.h Thu Dec 19 01:03:35 1996 +++ linux/drivers/sbus/audio/amd7930.h Wed Mar 5 17:04:32 1997 @@ -16,7 +16,6 @@ #include /* Register interface presented to the CPU by the amd7930. */ - struct amd7930 { __volatile__ __u8 cr; /* Command Register (W) */ @@ -33,6 +32,22 @@ __volatile__ __u8 dsr2; /* D-channel Status Register 2 (R) */ }; + +/* Indirect registers in the Main Audio Processor. */ +struct amd7930_map { + __u16 x[8]; + __u16 r[8]; + __u16 gx; + __u16 gr; + __u16 ger; + __u16 stgr; + __u16 ftgr; + __u16 atgr; + __u8 mmr1; + __u8 mmr2; +}; + + /* The amd7930 has "indirect registers" which are accessed by writing * the register number into the Command Register and then reading or * writing values from the Data Register as appropriate. We define the @@ -84,7 +99,7 @@ #define AMR_MAP_GX 0x63 #define AMR_MAP_GR 0x64 #define AMR_MAP_GER 0x65 -#define AMR_MAP_STG 0x66 +#define AMR_MAP_STGR 0x66 #define AMR_MAP_FTGR_1_2 0x67 #define AMR_MAP_ATGR_1_2 0x68 #define AMR_MAP_MMR1 0x69 diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.1.28/linux/drivers/sbus/audio/audio.c Sun Jan 26 02:07:17 1997 +++ linux/drivers/sbus/audio/audio.c Wed Mar 5 17:04:32 1997 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "audio.h" @@ -26,15 +27,53 @@ * Low-level driver interface. */ -/* We only support one low-level audio driver. */ -static struct sparcaudio_driver *driver; +/* We only support one low-level audio driver currently. */ +static struct sparcaudio_driver *driver = NULL; int register_sparcaudio_driver(struct sparcaudio_driver *drv) { - /* If a driver is already present, don't allow it to register. */ + int i; + + /* If a driver is already present, don't allow the register. */ if (driver) return -EIO; + /* Ensure that the driver has a proper operations structure. */ + if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output) + return -EINVAL; + + /* Setup the circular queue of output buffers. */ + drv->num_output_buffers = 32; + drv->output_front = 0; + drv->output_rear = 0; + drv->output_count = 0; + drv->output_active = 0; + drv->output_buffers = kmalloc(32 * sizeof(__u8 *), GFP_KERNEL); + drv->output_sizes = kmalloc(32 * sizeof(size_t), GFP_KERNEL); + if (!drv->output_buffers || !drv->output_sizes) { + if (drv->output_buffers) + kfree(drv->output_buffers); + if (drv->output_sizes) + kfree(drv->output_sizes); + return -ENOMEM; + } + + /* Allocate the pages for each output buffer. */ + for (i = 0; i < drv->num_output_buffers; i++) { + drv->output_buffers[i] = (void *) __get_free_page(GFP_KERNEL); + if (!drv->output_buffers[i]) { + int j; + for (j = 0; j < i; j++) + free_page((unsigned long) drv->output_buffers[j]); + kfree(drv->output_buffers); + kfree(drv->output_sizes); + return -ENOMEM; + } + } + + /* Ensure that the driver is marked as not being open. */ + drv->flags = 0; + MOD_INC_USE_COUNT; driver = drv; @@ -43,53 +82,76 @@ int unregister_sparcaudio_driver(struct sparcaudio_driver *drv) { + int i; + /* Make sure that the current driver is unregistering. */ if (driver != drv) return -EIO; + /* Deallocate the queue of output buffers. */ + for (i = 0; i < driver->num_output_buffers; i++) + free_page((unsigned long) driver->output_buffers[i]); + kfree(driver->output_buffers); + kfree(driver->output_sizes); + MOD_DEC_USE_COUNT; driver = NULL; return 0; } -static void sparcaudio_output_done_task(void * unused) +static void sparcaudio_output_done_task(void * arg) { + struct sparcaudio_driver *drv = (struct sparcaudio_driver *)arg; unsigned long flags; + printk(KERN_DEBUG "sparcaudio: next buffer (of=%d)\n",drv->output_front); save_and_cli(flags); - printk(KERN_DEBUG "sparcaudio: next buffer\n"); - driver->ops->start_output(driver, driver->output_buffers[driver->output_front], - driver->output_sizes[driver->output_front]); - driver->output_active = 1; + drv->ops->start_output(drv, + drv->output_buffers[drv->output_front], + drv->output_sizes[drv->output_front]); + drv->output_active = 1; restore_flags(flags); } -static struct tq_struct sparcaudio_output_tqueue = { - 0, 0, sparcaudio_output_done_task, 0 }; - -void sparcaudio_output_done(void) +void sparcaudio_output_done(struct sparcaudio_driver * drv) { /* Point the queue after the "done" buffer. */ - driver->output_front++; - driver->output_count--; + drv->output_front = (drv->output_front + 1) % drv->num_output_buffers; + drv->output_count--; /* If the output queue is empty, shutdown the driver. */ - if (driver->output_count == 0) { + if (drv->output_count == 0) { /* Stop the lowlevel driver from outputing. */ - printk(KERN_DEBUG "sparcaudio: lowlevel driver shutdown\n"); - driver->ops->stop_output(driver); - driver->output_active = 0; + printk("sparcaudio: lowlevel driver shutdown\n"); + drv->ops->stop_output(drv); + drv->output_active = 0; + + /* Wake up any waiting writers or syncers and return. */ + wake_up_interruptible(&drv->output_write_wait); + wake_up_interruptible(&drv->output_drain_wait); return; } /* Otherwise, queue a task to give the driver the next buffer. */ - queue_task(&sparcaudio_output_tqueue, &tq_immediate); + drv->tqueue.next = NULL; + drv->tqueue.sync = 0; + drv->tqueue.routine = sparcaudio_output_done_task; + drv->tqueue.data = drv; + + queue_task(&drv->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); /* Wake up any tasks that are waiting. */ - wake_up_interruptible(&driver->output_write_wait); + wake_up_interruptible(&drv->output_write_wait); } +void sparcaudio_input_done(struct sparcaudio_driver * drv) +{ + /* XXX Implement! */ +} + + /* * VFS layer interface @@ -104,6 +166,7 @@ static int sparcaudio_read(struct inode * inode, struct file * file, char *buf, int count) { + /* XXX Implement me! */ return -EINVAL; } @@ -127,18 +190,20 @@ return bytes_written > 0 ? bytes_written : -EINTR; } - /* Determine how much we can copy in this run. */ + /* Determine how much we can copy in this iteration. */ bytes_to_copy = count; if (bytes_to_copy > PAGE_SIZE) bytes_to_copy = PAGE_SIZE; - err = verify_area(VERIFY_READ, buf, bytes_to_copy); - if (err) - return err; + copy_from_user_ret(driver->output_buffers[driver->output_rear], + buf, bytes_to_copy, -EFAULT); - memcpy_fromfs(driver->output_buffers[driver->output_rear], buf, bytes_to_copy); + printk(KERN_DEBUG "Stuffing %d in %d\n", + bytes_to_copy, driver->output_rear); /* Update the queue pointers. */ + buf += bytes_to_copy; + count -= bytes_to_copy; bytes_written += bytes_to_copy; driver->output_sizes[driver->output_rear] = bytes_to_copy; driver->output_rear = (driver->output_rear + 1) % driver->num_output_buffers; @@ -162,76 +227,117 @@ static int sparcaudio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { + int retval = 0; + switch (cmd) { + case AUDIO_DRAIN: + if (driver->output_count > 0) { + interruptible_sleep_on(&driver->output_drain_wait); + retval = (current->signal & ~current->blocked) ? -EINTR : 0; + } + break; + + case AUDIO_GETDEV: + if (driver->ops->sunaudio_getdev) { + audio_device_t tmp; + + driver->ops->sunaudio_getdev(driver, &tmp); + + copy_to_user_ret((audio_device_t *)arg, &tmp, sizeof(tmp), -EFAULT); + } else + retval = -EINVAL; + break; + default: if (driver->ops->ioctl) - return driver->ops->ioctl(inode,file,cmd,arg,driver); + retval = driver->ops->ioctl(inode,file,cmd,arg,driver); else - return -EINVAL; + retval = -EINVAL; } - return 0; + + return retval; } static int sparcaudio_open(struct inode * inode, struct file * file) { - unsigned int minor = MINOR(inode->i_rdev); - int i; + int err; - /* We only support minor #4 (/dev/audio right now. */ - if (minor != 4) - return -ENXIO; + /* A low-level audio driver must exist. */ + if (!driver) + return -ENODEV; - /* Make sure that the driver is not busy. */ - if (driver->busy) - return -EBUSY; - - /* Setup the queue of output buffers. */ - driver->num_output_buffers = 32; - driver->output_front = 0; - driver->output_rear = 0; - driver->output_count = 0; - driver->output_active = 0; - driver->output_buffers = kmalloc(32 * sizeof(__u8 *), GFP_KERNEL); - driver->output_sizes = kmalloc(32 * sizeof(__u8 *), GFP_KERNEL); - if (!driver->output_buffers || !driver->output_sizes) - return -ENOMEM; + /* We only support minor #4 (/dev/audio) right now. */ + if (MINOR(inode->i_rdev) != 4) + return -ENXIO; - /* Allocate space for the output buffers. */ - for (i = 0; i < driver->num_output_buffers; i++) { - driver->output_buffers[i] = (void *) __get_free_page(GFP_KERNEL); - if (!driver->output_buffers[i]) - return -ENOMEM; + /* If the driver is busy, then wait to get through. */ + retry_open: + if (file->f_mode & FMODE_READ && driver->flags & SDF_OPEN_READ) { + if (file->f_flags & O_NONBLOCK) + return -EBUSY; + + interruptible_sleep_on(&driver->open_wait); + if (current->signal & ~current->blocked) + return -EINTR; + goto retry_open; + } + if (file->f_mode & FMODE_WRITE && driver->flags & SDF_OPEN_WRITE) { + if (file->f_flags & O_NONBLOCK) + return -EBUSY; + + interruptible_sleep_on(&driver->open_wait); + if (current->signal & ~current->blocked) + return -EINTR; + goto retry_open; } - /* Allow the low-level driver to initialize itself. */ - if (driver->ops->open) - driver->ops->open(inode,file,driver); - + /* Mark the driver as locked for read and/or write. */ + if (file->f_mode & FMODE_READ) + driver->flags |= SDF_OPEN_READ; + if (file->f_mode & FMODE_WRITE) { + driver->output_front = 0; + driver->output_rear = 0; + driver->output_count = 0; + driver->output_active = 0; + driver->flags |= SDF_OPEN_WRITE; + } - /* Mark the driver as busy. */ - driver->busy = 1; + /* Allow the low-level driver to initialize itself. */ + if (driver->ops->open) { + err = driver->ops->open(inode,file,driver); + if (err < 0) + return err; + } MOD_INC_USE_COUNT; - /* Success return. */ + /* Success! */ return 0; } static void sparcaudio_release(struct inode * inode, struct file * file) { - int i; + /* Wait for any output still in the queue to be played. */ + if (driver->output_count > 0) + interruptible_sleep_on(&driver->output_drain_wait); + /* Force any output to be stopped. */ + driver->ops->stop_output(driver); + driver->output_active = 0; + + /* Let the low-level driver do any release processing. */ if (driver->ops->release) driver->ops->release(inode,file,driver); - MOD_DEC_USE_COUNT; + if (file->f_mode & FMODE_READ) + driver->flags &= ~(SDF_OPEN_READ); - driver->busy = 0; + if (file->f_mode & FMODE_WRITE) + driver->flags &= ~(SDF_OPEN_WRITE); - for (i = 0; i < driver->num_output_buffers; i++) - kfree(driver->output_buffers[i]); - kfree(driver->output_buffers); - kfree(driver->output_sizes); + MOD_DEC_USE_COUNT; + + wake_up_interruptible(&driver->open_wait); } static struct file_operations sparcaudio_fops = { @@ -239,13 +345,17 @@ sparcaudio_read, sparcaudio_write, NULL, /* sparcaudio_readdir */ - NULL, /* sparcaudio_poll */ + NULL, /* sparcaudio_select */ sparcaudio_ioctl, NULL, /* sparcaudio_mmap */ sparcaudio_open, sparcaudio_release }; +EXPORT_SYMBOL(register_sparcaudio_driver); +EXPORT_SYMBOL(unregister_sparcaudio_driver); +EXPORT_SYMBOL(sparcaudio_output_done); +EXPORT_SYMBOL(sparcaudio_input_done); #ifdef MODULE int init_module(void) @@ -261,11 +371,16 @@ amd7930_init(); #endif +#ifdef CONFIG_SPARCAUDIO_CS4231 + cs4231_init(); +#endif + return 0; } #ifdef MODULE void cleanup_module(void) { + unregister_chrdev(SOUND_MAJOR, "sparcaudio"); } #endif diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/audio/audio.h linux/drivers/sbus/audio/audio.h --- v2.1.28/linux/drivers/sbus/audio/audio.h Sun Jan 26 02:07:17 1997 +++ linux/drivers/sbus/audio/audio.h Wed Mar 5 17:04:32 1997 @@ -8,29 +8,246 @@ #ifndef _AUDIO_H_ #define _AUDIO_H_ +/* + * SunOS/Solaris /dev/audio interface + */ + +#include +#include +#include + +/* + * This structure contains state information for audio device IO streams. + */ +typedef struct audio_prinfo { + /* + * The following values describe the audio data encoding. + */ + unsigned int sample_rate; /* samples per second */ + unsigned int channels; /* number of interleaved channels */ + unsigned int precision; /* bit-width of each sample */ + unsigned int encoding; /* data encoding method */ + + /* + * The following values control audio device configuration + */ + unsigned int gain; /* gain level: 0 - 255 */ + unsigned int port; /* selected I/O port (see below) */ + unsigned int avail_ports; /* available I/O ports (see below) */ + unsigned int _xxx[2]; /* Reserved for future use */ + + unsigned int buffer_size; /* I/O buffer size */ + + /* + * The following values describe driver state + */ + unsigned int samples; /* number of samples converted */ + unsigned int eof; /* End Of File counter (play only) */ + + unsigned char pause; /* non-zero for pause, zero to resume */ + unsigned char error; /* non-zero if overflow/underflow */ + unsigned char waiting; /* non-zero if a process wants access */ + unsigned char balance; /* stereo channel balance */ + + unsigned short minordev; + + /* + * The following values are read-only state flags + */ + unsigned char open; /* non-zero if open access permitted */ + unsigned char active; /* non-zero if I/O is active */ +} audio_prinfo_t; + + +/* + * This structure describes the current state of the audio device. + */ +typedef struct audio_info { + /* + * Per-stream information + */ + audio_prinfo_t play; /* output status information */ + audio_prinfo_t record; /* input status information */ + + /* + * Per-unit/channel information + */ + unsigned int monitor_gain; /* input to output mix: 0 - 255 */ + unsigned char output_muted; /* non-zero if output is muted */ + unsigned char _xxx[3]; /* Reserved for future use */ + unsigned int _yyy[3]; /* Reserved for future use */ +} audio_info_t; + + +/* + * Audio encoding types + */ +#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */ +#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */ +#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */ +#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */ +#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */ +#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */ + +/* + * These ranges apply to record, play, and monitor gain values + */ +#define AUDIO_MIN_GAIN (0) /* minimum gain value */ +#define AUDIO_MAX_GAIN (255) /* maximum gain value */ + +/* + * These values apply to the balance field to adjust channel gain values + */ +#define AUDIO_LEFT_BALANCE (0) /* left channel only */ +#define AUDIO_MID_BALANCE (32) /* equal left/right channel */ +#define AUDIO_RIGHT_BALANCE (64) /* right channel only */ +#define AUDIO_BALANCE_SHIFT (3) + +/* + * Generic minimum/maximum limits for number of channels, both modes + */ +#define AUDIO_MIN_PLAY_CHANNELS (1) +#define AUDIO_MAX_PLAY_CHANNELS (4) +#define AUDIO_MIN_REC_CHANNELS (1) +#define AUDIO_MAX_REC_CHANNELS (4) + +/* + * Generic minimum/maximum limits for sample precision + */ +#define AUDIO_MIN_PLAY_PRECISION (8) +#define AUDIO_MAX_PLAY_PRECISION (32) +#define AUDIO_MIN_REC_PRECISION (8) +#define AUDIO_MAX_REC_PRECISION (32) + +/* + * Define some convenient names for typical audio ports + */ +/* + * output ports (several may be enabled simultaneously) + */ +#define AUDIO_SPEAKER 0x01 /* output to built-in speaker */ +#define AUDIO_HEADPHONE 0x02 /* output to headphone jack */ +#define AUDIO_LINE_OUT 0x04 /* output to line out */ + +/* + * input ports (usually only one at a time) + */ +#define AUDIO_MICROPHONE 0x01 /* input from microphone */ +#define AUDIO_LINE_IN 0x02 /* input from line in */ +#define AUDIO_CD 0x04 /* input from on-board CD inputs */ +#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* input from internal CDROM */ + + +/* + * This macro initializes an audio_info structure to 'harmless' values. + * Note that (~0) might not be a harmless value for a flag that was + * a signed int. + */ +#define AUDIO_INITINFO(i) { \ + unsigned int *__x__; \ + for (__x__ = (unsigned int *)(i); \ + (char *) __x__ < (((char *)(i)) + sizeof (audio_info_t)); \ + *__x__++ = ~0); \ +} + + +/* + * Parameter for the AUDIO_GETDEV ioctl to determine current + * audio devices. + */ +#define MAX_AUDIO_DEV_LEN (16) +typedef struct audio_device { + char name[MAX_AUDIO_DEV_LEN]; + char version[MAX_AUDIO_DEV_LEN]; + char config[MAX_AUDIO_DEV_LEN]; +} audio_device_t; + + +/* + * Ioctl calls for the audio device. + */ + +/* + * AUDIO_GETINFO retrieves the current state of the audio device. + * + * AUDIO_SETINFO copies all fields of the audio_info structure whose + * values are not set to the initialized value (-1) to the device state. + * It performs an implicit AUDIO_GETINFO to return the new state of the + * device. Note that the record.samples and play.samples fields are set + * to the last value before the AUDIO_SETINFO took effect. This allows + * an application to reset the counters while atomically retrieving the + * last value. + * + * AUDIO_DRAIN suspends the calling process until the write buffers are + * empty. + * + * AUDIO_GETDEV returns a structure of type audio_device_t which contains + * three strings. The string "name" is a short identifying string (for + * example, the SBus Fcode name string), the string "version" identifies + * the current version of the device, and the "config" string identifies + * the specific configuration of the audio stream. All fields are + * device-dependent -- see the device specific manual pages for details. + */ +#define AUDIO_GETINFO _IOR('A', 1, audio_info_t) +#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t) +#define AUDIO_DRAIN _IO('A', 3) +#define AUDIO_GETDEV _IOR('A', 4, audio_device_t) + +/* + * The following ioctl sets the audio device into an internal loopback mode, + * if the hardware supports this. The argument is TRUE to set loopback, + * FALSE to reset to normal operation. If the hardware does not support + * internal loopback, the ioctl should fail with EINVAL. + */ +#define AUDIO_DIAG_LOOPBACK _IOW('A', 101, int) + +#ifdef notneeded +/* + * Structure sent up as a M_PROTO message on trace streams + */ +typedef struct audtrace_hdr audtrace_hdr_t; +struct audtrace_hdr { + unsigned int seq; /* Sequence number (per-aud_stream) */ + int type; /* device-dependent */ + struct timeval timestamp; + char _f[8]; /* filler */ +}; +#endif + + + +/* + * Linux kernel internal implementation. + */ + #ifdef __KERNEL__ #include #include +#include #include - -#define NR_SPARCAUDIO_DRIVERS 1 - +#define SDF_OPEN_WRITE 0x00000001 +#define SDF_OPEN_READ 0x00000002 struct sparcaudio_driver { const char * name; struct sparcaudio_operations *ops; void *private; + unsigned long flags; - /* Nonzero if the driver is busy. */ - int busy; + /* Processes blocked on open() sit here. */ + struct wait_queue *open_wait; + + /* Task queue for this driver's bottom half. */ + struct tq_struct tqueue; /* Support for a circular queue of output buffers. */ __u8 **output_buffers; size_t *output_sizes; - int num_output_buffers, output_front, output_rear, output_count, output_active; + int num_output_buffers, output_front, output_rear; + int output_count, output_active; struct wait_queue *output_write_wait, *output_drain_wait; }; @@ -42,33 +259,28 @@ struct sparcaudio_driver *); /* Ask driver to begin playing a buffer. */ - void (*start_output)(struct sparcaudio_driver *, __u8 * buffer, size_t count); + void (*start_output)(struct sparcaudio_driver *, __u8 *, unsigned long); /* Ask driver to stop playing a buffer. */ void (*stop_output)(struct sparcaudio_driver *); - /* Set and get the audio encoding method. */ - int (*set_encoding)(int encoding); - int (*get_encoding)(void); - - /* Set and get the audio sampling rate (samples per second). */ - int (*set_sampling_rate)(int sampling_rate); - int (*get_sampling_rate)(void); - - /* Set and get the audio output port. */ - int (*set_output_port)(int output_port); - int (*get_output_port)(void); - - /* Set and get the audio input port. */ - int (*set_input_port)(int input_port); - int (*get_input_port)(void); + /* Ask driver to begin recording into a buffer. */ + void (*start_input)(struct sparcaudio_driver *, __u8 *, unsigned long); + + /* Ask driver to stop recording. */ + void (*stop_input)(struct sparcaudio_driver *); + + /* Return driver name/version to caller. (/dev/audio specific) */ + void (*sunaudio_getdev)(struct sparcaudio_driver *, audio_device_t *); }; extern int register_sparcaudio_driver(struct sparcaudio_driver *); extern int unregister_sparcaudio_driver(struct sparcaudio_driver *); -extern void sparcaudio_output_done(void); +extern void sparcaudio_output_done(struct sparcaudio_driver *); +extern void sparcaudio_input_done(struct sparcaudio_driver *); extern int sparcaudio_init(void); extern int amd7930_init(void); +extern int cs4231_init(void); #endif diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.1.28/linux/drivers/sbus/audio/cs4231.c Sun Jan 26 02:07:17 1997 +++ linux/drivers/sbus/audio/cs4231.c Wed Mar 5 17:04:32 1997 @@ -14,13 +14,15 @@ #include #include #include +#include #include #include #include #include #include -#include #include +#include + #include "audio.h" #include "cs4231.h" @@ -32,219 +34,215 @@ #define MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) #endif -static int cs4231_node, cs4231_irq, cs4231_is_revision_a, cs4231_ints_on = 0; -static unsigned int cs4231_monitor_gain_value; -cs4231_regs_size - -static int cs4231_output_muted_value; - -static struct cs4231_stream_info cs4231_input; -static struct cs4231_stream_info cs4231_output; - -static int cs4231_busy = 0, cs4231_need_init = 0; +#define MAX_DRIVERS 1 +static struct sparcaudio_driver drivers[MAX_DRIVERS]; +static int num_drivers; + +static int cs4231_playintr(struct sparcaudio_driver *drv); +static int cs4231_recintr(struct sparcaudio_driver *drv); +static void cs4231_output_muted(struct sparcaudio_driver *drv, unsigned int value); +static void cs4231_mute(struct sparcaudio_driver *drv); +static void cs4231_pollinput(struct sparcaudio_driver *drv); +static int cs4231_attach(struct sparcaudio_driver *drv, int node, + struct linux_sbus *sbus); + +#define CHIP_BUG udelay(100); cs4231_ready(drv); udelay(1000); -static volatile struct cs4231_chip *cs4231_chip = NULL; - -static __u8 * ptr; -static size_t count; - -#define CHIP_BUG udelay(100); cs4231_ready(); udelay(1000); - -static void cs4231_ready(void) +/* Disable mode change, let chip auto-calibrate */ +static void cs4231_ready(struct sparcaudio_driver *drv) { - register unsigned int x = 0; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + unsigned int x = 0; - cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END; - while (cs4231_chip->pioregs.iar == IAR_NOT_READY && x <= CS_TIMEOUT) { + cs4231_chip->pioregs->iar = (u_char)IAR_AUTOCAL_END; + while (cs4231_chip->pioregs->iar == IAR_NOT_READY && x <= CS_TIMEOUT) { x++; } x = 0; - - cs4231_chip->pioregs.iar = 0x0b; - - while (cs4231_chip->pioregs.idr == AUTOCAL_IN_PROGRESS && x <= CS_TIMEOUT) { + cs4231_chip->pioregs->iar = 0x0b; + while (cs4231_chip->pioregs->idr == AUTOCAL_IN_PROGRESS && x <= CS_TIMEOUT) { x++; } } -/* Enable cs4231 interrupts atomically. */ -static __inline__ void cs4231_enable_ints(void) -{ - register unsigned long flags; - - if (cs4231_ints_on) - return; - - save_and_cli(flags); - /* do init here - amd7930_regs->cr = AMR_INIT; - amd7930_regs->dr = AM_INIT_ACTIVE; - */ - restore_flags(flags); - - cs4231_ints_on = 1; -} - -/* Disable cs4231 interrupts atomically. */ -static __inline__ void cs4231_disable_ints(void) -{ - register unsigned long flags; - - if (!cs4231_ints_on) - return; - - save_and_cli(flags); -/* - amd7930_regs->cr = AMR_INIT; - amd7930_regs->dr = AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS; -*/ - restore_flags(flags); - - cs4231_ints_on = 0; -} - - /* Audio interrupt handler. */ static void cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - __u8 dummy; - - /* Clear the interrupt. */ - dummy = cs4231_chip->dmaregs.dmacsr; - - cs4231_chip->dmaregs.dmacsr = dummy; - + struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + __u8 dummy; + int ic = 1; + + /* Clear the interrupt. */ + dummy = cs4231_chip->dmaregs.dmacsr; + cs4231_chip->dmaregs.dmacsr = dummy; + + /* now go through and figure out what gets to claim the interrupt */ + if (dummy & CS_PLAY_INT) { + if (dummy & CS_XINT_PNVA) { + /* recalculate number of samples */ + cs4231_playintr(drv); + } + ic = 0; + } + if (dummy & CS_CAPT_INT) { + if (dummy & CS_XINT_CNVA) { + /* recalculate number of samples */ + cs4231_recintr(drv); + } + ic = 0; + } + if ((dummy & CS_XINT_CEMP) + && (cs4231_chip->perchip_info.record.active == 0)) + { + ic = 0; + } + if ((dummy & CS_XINT_EMPT) && (cs4231_chip->perchip_info.play.active == 0)) { + cs4231_chip->dmaregs.dmacsr |= (CS_PPAUSE); + cs4231_chip->pioregs->iar = 0x9; + cs4231_chip->pioregs->idr &= PEN_DISABLE; + + cs4231_mute(drv); + + /* recalculate number of samples */ + /* cleanup DMA */ + ic = 0; + } + if (dummy & CS_GENL_INT) { + ic = 0; + } } -static unsigned int cs4231_output_muted(unsigned int value) +/* Set output mute */ +static void cs4231_output_muted(struct sparcaudio_driver *drv, unsigned int value) { + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; if (!value) { - cs4231_chip->pioregs.iar = 0x7; - cs4231_chip->pioregs.idr &= OUTCR_UNMUTE; - cs4231_chip->pioregs.iar = 0x6; - cs4231_chip->pioregs.idr &= OUTCR_UNMUTE; - cs4231_output_muted_value = 0; + cs4231_chip->pioregs->iar = 0x7; + cs4231_chip->pioregs->idr &= OUTCR_UNMUTE; + cs4231_chip->pioregs->iar = 0x6; + cs4231_chip->pioregs->idr &= OUTCR_UNMUTE; + cs4231_chip->perchip_info.output_muted = 0; } else { - cs4231_chip->pioregs.iar = 0x7; - cs4231_chip->pioregs.idr |= OUTCR_MUTE; - cs4231_chip->pioregs.iar = 0x6; - cs4231_chip->pioregs.idr |= OUTCR_MUTE; - cs4231_output_muted_value = 1; + cs4231_chip->pioregs->iar = 0x7; + cs4231_chip->pioregs->idr |= OUTCR_MUTE; + cs4231_chip->pioregs->iar = 0x6; + cs4231_chip->pioregs->idr |= OUTCR_MUTE; + cs4231_chip->perchip_info.output_muted = 1; } - return (cs4231_output_muted_value); + return /*(cs4231_chip->perchip_info.output_muted)*/; } -static unsigned int cs4231_out_port(unsigned int value) +/* Set chip "output" port */ +static unsigned int cs4231_out_port(struct sparcaudio_driver *drv, unsigned int value) { + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; unsigned int r = 0; /* You can have any combo you want. Just don't tell anyone. */ - cs4231_chip->pioregs.iar = 0x1a; - cs4231_chip->pioregs.idr |= MONO_IOCR_MUTE; - cs4231_chip->pioregs.iar = 0x0a; - cs4231_chip->pioregs.idr |= PINCR_LINE_MUTE; - cs4231_chip->pioregs.idr |= PINCR_HDPH_MUTE; + cs4231_chip->pioregs->iar = 0x1a; + cs4231_chip->pioregs->idr |= MONO_IOCR_MUTE; + cs4231_chip->pioregs->iar = 0x0a; + cs4231_chip->pioregs->idr |= PINCR_LINE_MUTE; + cs4231_chip->pioregs->idr |= PINCR_HDPH_MUTE; if (value & AUDIO_SPEAKER) { - cs4231_chip->pioregs.iar = 0x1a; - cs4231_chip->pioregs.idr &= ~MONO_IOCR_MUTE; + cs4231_chip->pioregs->iar = 0x1a; + cs4231_chip->pioregs->idr &= ~MONO_IOCR_MUTE; r |= AUDIO_SPEAKER; } if (value & AUDIO_HEADPHONE) { - cs4231_chip->pioregs.iar = 0x0a; - cs4231_chip->pioregs.idr &= ~PINCR_HDPH_MUTE; + cs4231_chip->pioregs->iar = 0x0a; + cs4231_chip->pioregs->idr &= ~PINCR_HDPH_MUTE; r |= AUDIO_HEADPHONE; } if (value & AUDIO_LINE_OUT) { - cs4231_chip->pioregs.iar = 0x0a; - cs4231_chip->pioregs.idr &= ~PINCR_LINE_MUTE; + cs4231_chip->pioregs->iar = 0x0a; + cs4231_chip->pioregs->idr &= ~PINCR_LINE_MUTE; r |= AUDIO_LINE_OUT; } return (r); } -static unsigned int cs4231_in_port(unsigned int value) +/* Set chip "input" port */ +static unsigned int cs4231_in_port(struct sparcaudio_driver *drv, unsigned int value) { + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; unsigned int r = 0; /* The order of these seems to matter. Can't tell yet why. */ - if (value & AUDIO_INTERNAL_CD_IN) { - cs4231_chip->pioregs.iar = 0x1; - cs4231_chip->pioregs.idr = CDROM_ENABLE(cs4231_chip->pioregs.idr); - cs4231_chip->pioregs.iar = 0x0; - cs4231_chip->pioregs.idr = CDROM_ENABLE(cs4231_chip->pioregs.idr); + cs4231_chip->pioregs->iar = 0x1; + cs4231_chip->pioregs->idr = CDROM_ENABLE(cs4231_chip->pioregs->idr); + cs4231_chip->pioregs->iar = 0x0; + cs4231_chip->pioregs->idr = CDROM_ENABLE(cs4231_chip->pioregs->idr); r = AUDIO_INTERNAL_CD_IN; } if ((value & AUDIO_LINE_IN)) { - cs4231_chip->pioregs.iar = 0x1; - cs4231_chip->pioregs.idr = LINE_ENABLE(cs4231_chip->pioregs.idr); - cs4231_chip->pioregs.iar = 0x0; - cs4231_chip->pioregs.idr = LINE_ENABLE(cs4231_chip->pioregs.idr); + cs4231_chip->pioregs->iar = 0x1; + cs4231_chip->pioregs->idr = LINE_ENABLE(cs4231_chip->pioregs->idr); + cs4231_chip->pioregs->iar = 0x0; + cs4231_chip->pioregs->idr = LINE_ENABLE(cs4231_chip->pioregs->idr); r = AUDIO_LINE_IN; } else if (value & AUDIO_MICROPHONE) { - cs4231_chip->pioregs.iar = 0x1; - cs4231_chip->pioregs.idr = MIC_ENABLE(cs4231_chip->pioregs.idr); - cs4231_chip->pioregs.iar = 0x0; - cs4231_chip->pioregs.idr = MIC_ENABLE(cs4231_chip->pioregs.idr); + cs4231_chip->pioregs->iar = 0x1; + cs4231_chip->pioregs->idr = MIC_ENABLE(cs4231_chip->pioregs->idr); + cs4231_chip->pioregs->iar = 0x0; + cs4231_chip->pioregs->idr = MIC_ENABLE(cs4231_chip->pioregs->idr); r = AUDIO_MICROPHONE; } return (r); } -static unsigned int cs4231_monitor_gain(unsigned int value) +/* Set chip "monitor" gain */ +static unsigned int cs4231_monitor_gain(struct sparcaudio_driver *drv, unsigned int value) { + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int a = 0; - a = CS4231_MON_MAX_ATEN - (value * (CS4231_MON_MAX_ATEN + 1) / - (AUDIO_MAX_GAIN + 1)); + a = CS4231_MON_MAX_ATEN - (value * (CS4231_MON_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1)); - cs4231_chip->pioregs.iar = 0x0d; + cs4231_chip->pioregs->iar = 0x0d; if (a >= CS4231_MON_MAX_ATEN) - cs4231_chip->pioregs.idr = LOOPB_OFF; + cs4231_chip->pioregs->idr = LOOPB_OFF; else - cs4231_chip->pioregs.idr = ((a << 2) | LOOPB_ON); - + cs4231_chip->pioregs->idr = ((a << 2) | LOOPB_ON); - if (value == AUDIO_MAX_GAIN) - return AUDIO_MAX_GAIN; + if (value == AUDIO_MAX_GAIN) return AUDIO_MAX_GAIN; - return ((CS4231_MAX_DEV_ATEN - a) * (AUDIO_MAX_GAIN + 1) / - (CS4231_MAX_DEV_ATEN + 1)); + return ((CS4231_MAX_DEV_ATEN - a) * (AUDIO_MAX_GAIN + 1) / (CS4231_MAX_DEV_ATEN + 1)); } -/* Set record gain */ -static unsigned int cs4231_record_gain(unsigned int value, unsigned char balance) +/* Set chip record gain */ +static unsigned int cs4231_record_gain(struct sparcaudio_driver *drv, unsigned int value, unsigned char balance) { + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; unsigned int tmp = 0, r, l, ra, la; unsigned char old_gain; - r = l = value; if (balance < AUDIO_MID_BALANCE) { - r = MAX(0, (int)(value - - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT))); + r = MAX(0, (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT))); } else if (balance > AUDIO_MID_BALANCE) { - l = MAX(0, (int)(value - - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT))); + l = MAX(0, (int)(value - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT))); } la = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1); ra = r * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1); - cs4231_chip->pioregs.iar = 0x0; - old_gain = cs4231_chip->pioregs.idr; - cs4231_chip->pioregs.idr = RECGAIN_SET(old_gain, la); - cs4231_chip->pioregs.iar = 0x1; - old_gain = cs4231_chip->pioregs.idr; - cs4231_chip->pioregs.idr = RECGAIN_SET(old_gain, ra); + cs4231_chip->pioregs->iar = 0x0; + old_gain = cs4231_chip->pioregs->idr; + cs4231_chip->pioregs->idr = RECGAIN_SET(old_gain, la); + cs4231_chip->pioregs->iar = 0x1; + old_gain = cs4231_chip->pioregs->idr; + cs4231_chip->pioregs->idr = RECGAIN_SET(old_gain, ra); if (l == value) { (l == 0) ? (tmp = 0) : (tmp = ((la + 1) * AUDIO_MAX_GAIN) / (CS4231_MAX_GAIN + 1)); @@ -254,194 +252,374 @@ return (tmp); } -/* Set play gain */ -static unsigned int cs4231_play_gain(unsigned int value, unsigned char balance) +/* Set chip play gain */ +static unsigned int cs4231_play_gain(struct sparcaudio_driver *drv, unsigned int value, unsigned char balance) { + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; unsigned int tmp = 0, r, l, ra, la; unsigned char old_gain; r = l = value; if (balance < AUDIO_MID_BALANCE) { - r = MAX(0, (int)(value - - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT))); + r = MAX(0, (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT))); } else if (balance > AUDIO_MID_BALANCE) { - l = MAX(0, (int)(value - - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT))); + l = MAX(0, (int)(value - ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT))); } if (l == 0) { la = CS4231_MAX_DEV_ATEN; } else { - la = CS4231_MAX_ATEN - - (l * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1)); + la = CS4231_MAX_ATEN - (l * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1)); } if (r == 0) { ra = CS4231_MAX_DEV_ATEN; } else { - ra = CS4231_MAX_ATEN - - (r * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1)); + ra = CS4231_MAX_ATEN - (r * (CS4231_MAX_ATEN + 1) / (AUDIO_MAX_GAIN + 1)); } - cs4231_chip->pioregs.iar = 0x6; - old_gain = cs4231_chip->pioregs.idr; - cs4231_chip->pioregs.idr = GAIN_SET(old_gain, la); - cs4231_chip->pioregs.iar = 0x7; - old_gain = cs4231_chip->pioregs.idr; - cs4231_chip->pioregs.idr = GAIN_SET(old_gain, ra); + cs4231_chip->pioregs->iar = 0x6; + old_gain = cs4231_chip->pioregs->idr; + cs4231_chip->pioregs->idr = GAIN_SET(old_gain, la); + cs4231_chip->pioregs->iar = 0x7; + old_gain = cs4231_chip->pioregs->idr; + cs4231_chip->pioregs->idr = GAIN_SET(old_gain, ra); if ((value == 0) || (value == AUDIO_MAX_GAIN)) { tmp = value; } else { if (l == value) { - tmp = ((CS4231_MAX_ATEN - la) * - (AUDIO_MAX_GAIN + 1) / - (CS4231_MAX_ATEN + 1)); + tmp = ((CS4231_MAX_ATEN - la) * (AUDIO_MAX_GAIN + 1) / (CS4231_MAX_ATEN + 1)); } else if (r == value) { - tmp = ((CS4231_MAX_ATEN - ra) * - (AUDIO_MAX_GAIN + 1) / - (CS4231_MAX_ATEN + 1)); + tmp = ((CS4231_MAX_ATEN - ra) * (AUDIO_MAX_GAIN + 1) / (CS4231_MAX_ATEN + 1)); } } return (tmp); } /* Reset the audio chip to a sane state. */ -static void cs4231_reset(void) +static void cs4231_reset(struct sparcaudio_driver *drv) { - cs4231_chip->dmaregs.dmacsr = APC_RESET; - cs4231_chip->dmaregs.dmacsr = 0x00; - cs4231_chip->dmaregs.dmacsr |= APC_CODEC_PDN; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - udelay(20); + cs4231_chip->dmaregs.dmacsr = CS_CHIP_RESET; + cs4231_chip->dmaregs.dmacsr = 0x00; + cs4231_chip->dmaregs.dmacsr |= CS_CDC_RESET; + + udelay(100); + + cs4231_chip->dmaregs.dmacsr &= ~(CS_CDC_RESET); + cs4231_chip->pioregs->iar |= IAR_AUTOCAL_BEGIN; + + CHIP_BUG + + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x0c; + cs4231_chip->pioregs->idr = MISC_IR_MODE2; + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x08; + cs4231_chip->pioregs->idr = DEFAULT_DATA_FMAT; /* Ulaw */ + + CHIP_BUG + + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x1c; + cs4231_chip->pioregs->idr = DEFAULT_DATA_FMAT; /* Ulaw */ + + CHIP_BUG + + cs4231_chip->pioregs->iar = 0x19; + + /* see what we can turn on */ + if (cs4231_chip->pioregs->idr & CS4231A) + cs4231_chip->status |= CS_STATUS_REV_A; + else + cs4231_chip->status &= ~CS_STATUS_REV_A; + + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x10; + cs4231_chip->pioregs->idr = OLB_ENABLE; + + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x11; + if (cs4231_chip->status & CS_STATUS_REV_A) + cs4231_chip->pioregs->idr = (HPF_ON | XTALE_ON); + else + cs4231_chip->pioregs->idr = (HPF_ON); + + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x1a; + cs4231_chip->pioregs->idr = 0x00; + + /* Now set things up for defaults */ + cs4231_chip->perchip_info.play.port = cs4231_out_port(drv, AUDIO_SPEAKER); + cs4231_chip->perchip_info.record.port = cs4231_in_port(drv, AUDIO_MICROPHONE); + cs4231_chip->perchip_info.play.gain = cs4231_play_gain(drv, CS4231_DEFAULT_PLAYGAIN, AUDIO_MID_BALANCE); + cs4231_chip->perchip_info.record.gain = cs4231_record_gain(drv, CS4231_DEFAULT_RECGAIN, AUDIO_MID_BALANCE); + cs4231_chip->perchip_info.monitor_gain = cs4231_monitor_gain(drv, LOOPB_OFF); + + cs4231_chip->pioregs->iar = (u_char)IAR_AUTOCAL_END; + + cs4231_ready(drv); + + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x09; + cs4231_chip->pioregs->idr &= ACAL_DISABLE; + cs4231_chip->pioregs->iar = (u_char)IAR_AUTOCAL_END; + + cs4231_ready(drv); - cs4231_chip->dmaregs.dmacsr &= ~(APC_CODEC_PDN); - cs4231_chip->pioregs.iar |= IAR_AUTOCAL_BEGIN; + cs4231_output_muted(drv, 0); +} - CHIP_BUG +static void cs4231_mute(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x0c; - cs4231_chip->pioregs.idr = MISC_IR_MODE2; - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x08; - cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT; + if (!(cs4231_chip->status & CS_STATUS_REV_A)) { + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN; + udelay(100); + cs4231_chip->pioregs->iar = IAR_AUTOCAL_END; + CHIP_BUG + } +} - CHIP_BUG +/* Not yet useful */ +#if 0 +static int cs4231_len_to_sample(struct sparcaudio_driver *drv, int length, int direction) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int sample; - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1c; - cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT; + if (/* number of channels == 2*/0) { + sample = (length/2); + } else { + sample = length; + } + if (/*encoding == AUDIO_ENCODING_LINEAR*/0) { + sample = sample/2; + } + return (sample); +} +#endif - CHIP_BUG +static int cs4231_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - cs4231_chip->pioregs.iar = 0x19; + /* Set the default audio parameters. */ + + cs4231_chip->perchip_info.play.sample_rate = CS4231_RATE; + cs4231_chip->perchip_info.play.channels = CS4231_CHANNELS; + cs4231_chip->perchip_info.play.precision = CS4231_PRECISION; + cs4231_chip->perchip_info.play.encoding = AUDIO_ENCODING_ULAW; + + cs4231_chip->perchip_info.record.sample_rate = CS4231_RATE; + cs4231_chip->perchip_info.record.channels = CS4231_CHANNELS; + cs4231_chip->perchip_info.record.precision = CS4231_PRECISION; + cs4231_chip->perchip_info.record.encoding = AUDIO_ENCODING_ULAW; + + cs4231_ready(drv); + + cs4231_chip->status |= CS_STATUS_NEED_INIT; + + CHIP_BUG + + MOD_INC_USE_COUNT; + + return 0; +} - if (cs4231_chip->pioregs.idr & CS4231A) - cs4231_is_revision_a = 1; - else - cs4231_is_revision_a = 0; +static void cs4231_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +{ + /* zero out any info about what data we have as well */ + /* should insert init on close variable optionally calling cs4231_reset() */ + MOD_DEC_USE_COUNT; +} + +static int cs4231_playintr(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + /* Send the next byte of outgoing data. */ +#if 0 + if (cs4231_chip->output_ptr && cs4231_chip->output_count > 0) { + cs4231_chip->dmaregs.dmapnva = dma_handle; + cs4231_chip->dmaregs.dmapnc = length; + cs4231_chip->output_ptr++; + cs4231_chip->output_count--; + + /* Done with the buffer? Notify the midlevel driver. */ + if (cs4231_chip->output_count == 0) { + cs4231_chip->output_ptr = NULL; + cs4231_chip->output_count = 0; + sparcaudio_output_done(drv); + } + } +#endif +} - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x10; - cs4231_chip->pioregs.idr = (u_char)OLB_ENABLE; +static void cs4231_recmute(int fmt) +{ + switch (fmt) { + case AUDIO_ENCODING_LINEAR: + /* Insert 0x00 from "here" to end of data stream */ + break; + case AUDIO_ENCODING_ALAW: + /* Insert 0xd5 from "here" to end of data stream */ + break; + case AUDIO_ENCODING_ULAW: + /* Insert 0xff from "here" to end of data stream */ + break; + } +} - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x11; - if (cs4231_is_revision_a) - cs4231_chip->pioregs.idr = (HPF_ON | XTALE_ON); - else - cs4231_chip->pioregs.idr = (HPF_ON); +static int cs4231_recintr(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + cs4231_recmute(cs4231_chip->perchip_info.record.encoding); + + if (cs4231_chip->perchip_info.record.active == 0) { + cs4231_pollinput(drv); + cs4231_chip->pioregs->iar = 0x9; + cs4231_chip->pioregs->idr &= CEN_DISABLE; + } + /* Read the next byte of incoming data. */ +#if 0 + if (cs4231_chip->input_ptr && cs4231_chip->input_count > 0) { + cs4231_chip->dmaregs.dmacnva = dma_handle; + cs4231_chip->dmaregs.dmacnc = length; + cs4231_chip->input_ptr++; + cs4231_chip->input_count--; + + /* Done with the buffer? Notify the midlevel driver. */ + if (cs4231_chip->input_count == 0) { + cs4231_chip->input_ptr = NULL; + cs4231_chip->input_count = 0; + sparcaudio_input_done(drv); + } + } +#endif +} - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1a; - cs4231_chip->pioregs.idr = 0x00; +static void cs4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer, unsigned long count) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - cs4231_output.gain = cs4231_play_gain(CS4231_DEFAULT_PLAYGAIN, - AUDIO_MID_BALANCE); - cs4231_input.gain = cs4231_record_gain(CS4231_DEFAULT_RECGAIN, - AUDIO_MID_BALANCE); + if (cs4231_chip->perchip_info.play.active || (cs4231_chip->perchip_info.play.pause)) + return; - cs4231_output.port = cs4231_out_port(AUDIO_SPEAKER); - cs4231_input.port = cs4231_in_port(AUDIO_MICROPHONE); + cs4231_ready(drv); - cs4231_monitor_gain_value = cs4231_monitor_gain(LOOPB_OFF); + if (cs4231_chip->status & CS_STATUS_NEED_INIT) + { + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x08; + cs4231_chip->pioregs->idr = DEFAULT_DATA_FMAT; + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x1c; + cs4231_chip->pioregs->idr = DEFAULT_DATA_FMAT; - cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END; + CHIP_BUG - cs4231_ready(); + cs4231_chip->status &= ~CS_STATUS_NEED_INIT; + } - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x09; - cs4231_chip->pioregs.idr &= ACAL_DISABLE; - cs4231_chip->pioregs.iar = (u_char)IAR_AUTOCAL_END; + if (!cs4231_chip->perchip_info.play.pause) + { + /* init dma foo here */ + cs4231_chip->dmaregs.dmacsr &= ~CS_XINT_PLAY; + cs4231_chip->dmaregs.dmacsr &= ~CS_PPAUSE; + if (cs4231_playintr(drv)) { + cs4231_chip->dmaregs.dmacsr |= CS_PLAY_SETUP; + cs4231_chip->pioregs->iar = 0x9; + cs4231_chip->pioregs->idr |= PEN_ENABLE; + } + } + cs4231_chip->perchip_info.play.active = 1; +} - cs4231_ready(); +static void cs4231_stop_output(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - cs4231_output_muted_value = cs4231_output_muted(0x0); + cs4231_chip->perchip_info.play.active = 0; + cs4231_chip->dmaregs.dmacsr |= (CS_PPAUSE); } -static int cs4231_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) +static void cs4231_pollinput(struct sparcaudio_driver *drv) { - int level; + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + int x = 0; - /* Set the default audio parameters. */ + while (!(cs4231_chip->dmaregs.dmacsr & CS_XINT_COVF) && x <= CS_TIMEOUT) { + x++; + } + cs4231_chip->dmaregs.dmacsr |= CS_XINT_CEMP; +} - cs4231_output.sample_rate = CS4231_RATE; - cs4231_output.channels = CS4231_CHANNELS; - cs4231_output.precision = CS4231_PRECISION; - cs4231_output.encoding = AUDIO_ENCODING_ULAW; - - cs4231_input.sample_rate = CS4231_RATE; - cs4231_input.channels = CS4231_CHANNELS; - cs4231_input.precision = CS4231_PRECISION; - cs4231_input.encoding = AUDIO_ENCODING_ULAW; - - cs4231_ready(); - - cs4231_need_init = 1; -#if 1 - /* Arguably this should only happen once. I need to play around - * on a Solaris box and see what happens - */ - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x08; - cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT; - cs4231_chip->pioregs.iar = IAR_AUTOCAL_BEGIN | 0x1c; - cs4231_chip->pioregs.idr = DEFAULT_DATA_FMAT; +static void cs4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer, unsigned long count) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; -#endif + if (cs4231_chip->perchip_info.record.active || (cs4231_chip->perchip_info.record.pause)) + return; - CHIP_BUG + cs4231_ready(drv); - MOD_INC_USE_COUNT; + if (cs4231_chip->status & CS_STATUS_NEED_INIT) + { + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x08; + cs4231_chip->pioregs->idr = DEFAULT_DATA_FMAT; + cs4231_chip->pioregs->iar = IAR_AUTOCAL_BEGIN | 0x1c; + cs4231_chip->pioregs->idr = DEFAULT_DATA_FMAT; - return 0; -} + CHIP_BUG -static void cs4231_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) -{ - cs4231_disable_ints(); - MOD_DEC_USE_COUNT; + cs4231_chip->status &= ~CS_STATUS_NEED_INIT; + } + + if (!cs4231_chip->perchip_info.record.pause) + { + /* init dma foo here */ + cs4231_chip->dmaregs.dmacsr &= ~CS_XINT_CAPT; + cs4231_chip->dmaregs.dmacsr &= ~CS_CPAUSE; + cs4231_recintr(drv); + cs4231_chip->dmaregs.dmacsr |= CS_CAPT_SETUP; + cs4231_chip->pioregs->iar = 0x9; + cs4231_chip->pioregs->idr |= CEN_ENABLE; + } + cs4231_chip->perchip_info.record.active = 1; } -static void cs4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer, size_t the_count) +static void cs4231_stop_input(struct sparcaudio_driver *drv) { - count = the_count; - ptr = buffer; - cs4231_enable_ints(); + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + + cs4231_chip->perchip_info.record.active = 0; + cs4231_chip->dmaregs.dmacsr |= (CS_CPAUSE); + + cs4231_pollinput(drv); + + /* need adjust the end pointer, process the input, and clean up the dma */ + + cs4231_chip->pioregs->iar = 0x09; + cs4231_chip->pioregs->idr &= CEN_DISABLE; } -static void cs4231_stop_output(struct sparcaudio_driver *drv) +static void cs4231_audio_getdev(struct sparcaudio_driver *drv, + audio_device_t * audinfo) { - cs4231_disable_ints(); - ptr = NULL; - count = 0; + strncpy(audinfo->name, "cs4231", sizeof(audinfo->name) - 1); + strncpy(audinfo->version, "x", sizeof(audinfo->version) - 1); + strncpy(audinfo->config, "audio", sizeof(audinfo->config) - 1); } +/* The ioctl handler should be expected to identify itself and handle loopback + mode */ +/* There will also be a handler for getinfo and setinfo */ + static struct sparcaudio_operations cs4231_ops = { cs4231_open, cs4231_release, NULL, /* cs4231_ioctl */ cs4231_start_output, cs4231_stop_output, -}; - -static struct sparcaudio_driver cs4231_drv = { - "cs4231", - &cs4231_ops, + cs4231_start_input, + cs4231_stop_input, + cs4231_audio_getdev, }; /* Probe for the cs4231 chip and then attach the driver. */ @@ -451,68 +629,127 @@ __initfunc(int cs4231_init(void)) #endif { - struct linux_prom_registers regs[1]; - struct linux_prom_irqs irq; - int err; + struct linux_sbus *bus; + struct linux_sbus_device *sdev; + int cs4231_node; + + /* Find the PROM CS4231 node. */ + /* There's an easier way, and I should FIXME */ + cs4231_node = prom_getchild(prom_root_node); + cs4231_node = prom_searchsiblings(cs4231_node,"iommu"); + cs4231_node = prom_getchild(cs4231_node); + cs4231_node = prom_searchsiblings(cs4231_node,"sbus"); + cs4231_node = prom_getchild(cs4231_node); + cs4231_node = prom_searchsiblings(cs4231_node,"SUNW,CS4231"); + + if (cs4231_node && cs4231_attach(&drivers[0], cs4231_node, NULL) == 0) + num_drivers = 1; + else + num_drivers = 0; + + /* Probe each SBUS for cs4231 chips. */ + for_all_sbusdev(sdev,bus) { + if (!strcmp(sdev->prom_name, "SUNW,CS4231")) { + /* Don't go over the max number of drivers. */ + if (num_drivers >= MAX_DRIVERS) + continue; + + if (cs4231_attach(&drivers[num_drivers], + sdev->prom_node, sdev->my_bus) == 0) + num_drivers++; + } + } + + /* Only return success if we found some cs4231 chips. */ + return (num_drivers > 0) ? 0 : -EIO; +} -#ifdef MODULE - register_symtab(0); +/* Attach to an cs4231 chip given its PROM node. */ +static int cs4231_attach(struct sparcaudio_driver *drv, int node, + struct linux_sbus *sbus) +{ + struct linux_prom_registers regs; + struct linux_prom_irqs irq; + struct cs4231_chip *cs4231_chip; + int err; + + /* Allocate our private information structure. */ + drv->private = kmalloc(sizeof(struct cs4231_chip), GFP_KERNEL); + if (!drv->private) + return -ENOMEM; + + /* Point at the information structure and initialize it. */ + drv->ops = &cs4231_ops; + cs4231_chip = (struct cs4231_chip *)drv->private; +#if 0 + cs4231_chip->input_ptr = NULL; + cs4231_chip->input_count = 0; + cs4231_chip->output_ptr = NULL; + cs4231_chip->output_count = 0; #endif - /* Find the PROM CS4231 node. */ - cs4231_node = prom_getchild(prom_root_node); - cs4231_node = prom_searchsiblings(cs4231_node,"iommu"); - cs4231_node = prom_getchild(cs4231_node); - cs4231_node = prom_searchsiblings(cs4231_node,"sbus"); - cs4231_node = prom_getchild(cs4231_node); - cs4231_node = prom_searchsiblings(cs4231_node,"SUNW,CS4231"); - - if (!cs4231_node) - return -EIO; - - /* XXX Add for_each_sbus() search as well for LX and friends. */ - /* XXX Copy out for prom_apply_sbus_ranges. */ - - /* Map the registers into memory. */ - prom_getproperty(cs4231_node, "reg", (char *)regs, sizeof(regs)); - cs4231_regs_size = regs[0].reg_size; - cs4231_regs = sparc_alloc_io(regs[0].phys_addr, 0, regs[0].reg_size, - "cs4231", regs[0].which_io, 0); - if (!cs4231_regs) { - printk(KERN_ERR "cs4231: could not allocate registers\n"); - return -EIO; - } - - /* Disable cs4231 interrupt generation. */ - cs4231_disable_ints(); - - /* Reset the audio chip. */ - cs4231_reset(); - - /* Attach the interrupt handler to the audio interrupt. */ - prom_getproperty(cs4231_node, "intr", (char *)&irq, sizeof(irq)); - cs4231_irq = irq.pri; - request_irq(cs4231_irq, cs4231_interrupt, SA_INTERRUPT, "cs4231", NULL); - enable_irq(cs4231_irq); - - /* Register ourselves with the midlevel audio driver. */ - err = register_sparcaudio_driver(&cs4231_drv); - if (err < 0) { - /* XXX We should do something. Complain for now. */ - printk(KERN_ERR "cs4231: really screwed now\n"); - return -EIO; - } - - return 0; + /* Map the registers into memory. */ + prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); + if (sbus) + prom_apply_sbus_ranges(sbus, ®s, 1); + cs4231_chip->regs_size = regs.reg_size; + cs4231_chip->pioregs = sparc_alloc_io(regs.phys_addr, 0, regs.reg_size, + "cs4231", regs.which_io, 0); + if (!cs4231_chip->pioregs) { + printk(KERN_ERR "cs4231: could not allocate registers\n"); + kfree(drv->private); + return -EIO; + } + + /* Reset the audio chip. */ + cs4231_reset(drv); + + /* Attach the interrupt handler to the audio interrupt. */ + prom_getproperty(node, "intr", (char *)&irq, sizeof(irq)); + cs4231_chip->irq = irq.pri; + request_irq(cs4231_chip->irq, cs4231_interrupt, SA_INTERRUPT, "cs4231", NULL); + enable_irq(cs4231_chip->irq); + + /* Register ourselves with the midlevel audio driver. */ + err = register_sparcaudio_driver(drv); + if (err < 0) { + printk(KERN_ERR "cs4231: unable to register\n"); + disable_irq(cs4231_chip->irq); + free_irq(cs4231_chip->irq, drv); + sparc_free_io(cs4231_chip->pioregs, cs4231_chip->regs_size); + kfree(drv->private); + return -EIO; + } + + /* Announce the hardware to the user. */ + printk(KERN_INFO "cs4231 at 0x%lx irq %d\n", + (unsigned long)cs4231_chip->pioregs, cs4231_chip->irq); + + /* Success! */ + return 0; } #ifdef MODULE +/* Detach from an cs4231 chip given the device structure. */ +static void cs4231_detach(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *info = (struct cs4231_chip *)drv->private; + + unregister_sparcaudio_driver(drv); + disable_irq(info->irq); + free_irq(info->irq, drv); + sparc_free_io(info->pioregs, info->regs_size); + kfree(drv->private); +} + void cleanup_module(void) { - unregister_sparcaudio_driver(&cs4231_drv); - cs4231_disable_ints(); - disable_irq(cs4231_irq); - free_irq(cs4231_irq, NULL); - sparc_free_io(cs4231_regs, cs4231_regs_size); + register int i; + + for (i = 0; i < num_drivers; i++) { + cs4231_detach(&drivers[i]); + num_drivers--; + } } #endif + diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/audio/cs4231.h linux/drivers/sbus/audio/cs4231.h --- v2.1.28/linux/drivers/sbus/audio/cs4231.h Sun Jan 26 02:07:18 1997 +++ linux/drivers/sbus/audio/cs4231.h Wed Mar 5 17:04:32 1997 @@ -26,113 +26,205 @@ u_long dmapad[3]; u_long dmacva; /* Capture Virtual Address */ u_long dmacc; /* Capture Count */ - u_long dmacnva; /* Capture Next VAddress */ + u_long dmacnva; /* Capture Next Virtual Address */ u_long dmacnc; /* Capture Next Count */ u_long dmapva; /* Playback Virtual Address */ u_long dmapc; /* Playback Count */ - u_long dmapnva; /* Playback Next VAddress */ + u_long dmapnva; /* Playback Next Virtual Address */ u_long dmapnc; /* Playback Next Count */ }; struct cs4231_chip { - struct cs4231_regs pioregs; + struct cs4231_regs *pioregs; struct cs4231_dma dmaregs; -}; + struct audio_info perchip_info; + int irq; + unsigned long regs_size; + + /* Keep track of various info */ + volatile unsigned int status; -struct cs4231_stream_info { - unsigned int sample_rate; /* samples per second */ - unsigned int channels; /* number of interleaved channels */ - unsigned int precision; /* bit-width of each sample */ - unsigned int encoding; /* data encoding method */ - unsigned int gain; /* gain level: 0 - 255 */ - unsigned int port; + int dma; + int dma2; }; +/* Status bits */ +#define CS_STATUS_NEED_INIT 0x01 +#define CS_STATUS_INIT_ON_CLOSE 0x02 +#define CS_STATUS_REV_A 0x04 + #define CS_TIMEOUT 9000000 #define GAIN_SET(var, gain) ((var & ~(0x3f)) | gain) #define RECGAIN_SET(var, gain) ((var & ~(0x1f)) | gain) -#define IAR_AUTOCAL_BEGIN 0x40 -#define IAR_AUTOCAL_END ~(0x40) +#define IAR_AUTOCAL_BEGIN 0x40 /* IAR_MCE */ +#define IAR_AUTOCAL_END ~(0x40) /* IAR_MCD */ #define IAR_NOT_READY 0x80 /* 80h not ready CODEC state */ +/* Each register assumed mode 1 and 2 unless noted */ + +/* 0 - Left Input Control */ +/* 1 - Right Input Control */ #define MIC_ENABLE(var) ((var & 0x2f) | 0x80) #define LINE_ENABLE(var) (var & 0x2f) #define CDROM_ENABLE(var) ((var & 0x2f) | 0x40) +#define INPUTCR_AUX1 0x40 + +/* 2 - Left Aux 1 Input Control */ +/* 3 - Right Aux 1 Input Control */ +/* 4 - Left Aux 2 Input Control */ +/* 5 - Right Aux 2 Input Control */ +/* 6 - Left Output Control */ +/* 7 - Right Output Control */ #define OUTCR_MUTE 0x80 #define OUTCR_UNMUTE ~0x80 -/* 8 */ -#define DEFAULT_DATA_FMAT 0x20 - -/* 10 */ +/* 8 - Playback Data Format (Mode 2) */ +#define CHANGE_DFR(var, val) ((var & ~(0xF)) | val) +#define CHANGE_ENCODING(var, val) ((var & ~(0xe0)) | val) +#define DEFAULT_DATA_FMAT CS4231_DFR_ULAW +#define CS4231_DFR_8000 0x00 +#define CS4231_DFR_9600 0x0e +#define CS4231_DFR_11025 0x03 +#define CS4231_DFR_16000 0x02 +#define CS4231_DFR_18900 0x05 +#define CS4231_DFR_22050 0x07 +#define CS4231_DFR_32000 0x06 +#define CS4231_DFR_37800 0x09 +#define CS4231_DFR_44100 0x0b +#define CS4231_DFR_48000 0x0c +#define CS4231_DFR_LINEAR8 0x00 +#define CS4231_DFR_ULAW 0x20 +#define CS4231_DFR_ALAW 0x60 +#define CS4231_DFR_ADPCM 0xa0 +#define CS4231_DFR_LINEARBE 0xc0 +#define CS4231_STEREO_ON(val) (val | 0x10) +#define CS4231_MONO_ON(val) (val & ~0x10) + +/* 9 - Interface Config. Register */ +#define CHIP_INACTIVE 0x08 +#define PEN_ENABLE (0x01) +#define PEN_DISABLE (~0x01) +#define CEN_ENABLE (0x02) +#define CEN_DISABLE (~0x02) +#define ACAL_DISABLE (~0x08) +#define ICR_AUTOCAL_INIT 0x01 + +/* 10 - Pin Control Register */ +#define INTR_ON 0x82 +#define INTR_OFF 0x80 #define PINCR_LINE_MUTE 0x40 #define PINCR_HDPH_MUTE 0x80 -/* 11 */ +/* 11 - Test/Initialization */ +#define DRQ_STAT 0x10 #define AUTOCAL_IN_PROGRESS 0x20 -/* 12 */ +/* 12 - Misc Information */ #define MISC_IR_MODE2 0x40 -/* 13 */ +/* 13 - Loopback Control */ #define LOOPB_ON 0x01 #define LOOPB_OFF 0x00 -/* 16 */ +/* 14 - Unused (mode 1) */ +/* 15 - Unused (mode 1) */ + +/* 14 - Playback Upper (mode 2) */ +/* 15 - Playback Lower (mode 2) */ + +/* The rest are mode 2 only */ + +/* 16 - Alternate Feature 1 Enable */ #define OLB_ENABLE 0x80 -/* 17 */ +/* 17 - Alternate Feature 2 Enable */ #define HPF_ON 0x01 #define XTALE_ON 0x20 -#define MONO_IOCR_MUTE 0x40; +/* 18 - Left Line Input Gain */ +/* 19 - Right Line Input Gain */ + +/* 20 - Timer High */ +/* 21 - Timer Low */ + +/* 22 - unused */ +/* 23 - unused */ -/* 30 */ +/* 24 - Alternate Feature Status */ +#define CS_PU 0x01 /* Underrun */ +#define CS_PO 0x20 /* Overrun */ + +/* 25 - Version */ #define CS4231A 0x20 +#define CS4231CDE 0x80 +/* 26 - Mono I/O Control */ +#define CHANGE_MONO_GAIN(val) ((val & ~(0xFF)) | val) +#define MONO_IOCR_MUTE 0x40 + +/* 27 - Unused */ + +/* 28 - Capture Data Format */ +/* see register 8 */ + +/* 29 - Unused */ + +/* 30 - Capture Upper */ +/* 31 - Capture Lower */ + +/* Following are CSR register definitions for the Sparc */ +/* Also list "Solaris" equivs for now, not really useful tho */ +#define CS_INT_PENDING 0x800000 /* APC_IP */ /* Interrupt Pending */ +#define CS_PLAY_INT 0x400000 /* APC_PI */ /* Playback interrupt */ +#define CS_CAPT_INT 0x200000 /* APC_CI */ /* Capture interrupt */ +#define CS_GENL_INT 0x100000 /* APC_EI */ /* General interrupt */ +#define CS_XINT_ENA 0x80000 /* APC_IE */ /* General ext int. enable */ +#define CS_XINT_PLAY 0x40000 /* APC_PIE */ /* Playback ext intr */ +#define CS_XINT_CAPT 0x20000 /* APC_CIE */ /* Capture ext intr */ +#define CS_XINT_GENL 0x10000 /* APC_EIE */ /* Error ext intr */ +#define CS_XINT_EMPT 0x8000 /* APC_PMI */ /* Pipe empty interrupt */ +#define CS_XINT_PEMP 0x4000 /* APC_PM */ /* Play pipe empty */ +#define CS_XINT_PNVA 0x2000 /* APC_PD */ /* Playback NVA dirty */ +#define CS_XINT_PENA 0x1000 /* APC_PMIE */ /* play pipe empty Int enable */ +#define CS_XINT_COVF 0x800 /* APC_CM */ /* Cap data dropped on floor */ +#define CS_XINT_CNVA 0x400 /* APC_CD */ /* Capture NVA dirty */ +#define CS_XINT_CEMP 0x200 /* APC_CMI */ /* Capture pipe empty interrupt */ +#define CS_XINT_CENA 0x100 /* APC_CMIE */ /* Cap. pipe empty int enable */ +#define CS_PPAUSE 0x80 /* APC_PPAUSE */ /* Pause the play DMA */ +#define CS_CPAUSE 0x40 /* APC_CPAUSE */ /* Pause the capture DMA */ +#define CS_CDC_RESET 0x20 /* APC_CODEC_PDN */ /* CODEC RESET */ +#define PDMA_READY 0x08 /* PDMA_GO */ +#define CDMA_READY 0x04 /* CDMA_GO */ +#define CS_CHIP_RESET 0x01 /* APC_RESET */ /* Reset the chip */ -#define APC_CODEC_PDN 0x20 -#define APC_RESET 0x01 +#define CS_INIT_SETUP (CDMA_READY | PDMA_READY | CS_XINT_ENA | CS_XINT_PLAY | CS_XINT_GENL | CS_INT_PENDING | CS_PLAY_INT | CS_CAPT_INT | CS_GENL_INT) -#define CS4231_DEFAULT_PLAYGAIN (132) -#define CS4231_DEFAULT_RECGAIN (126) +#define CS_PLAY_SETUP (CS_GENL_INT | CS_PLAY_INT | CS_XINT_ENA | CS_XINT_PLAY | CS_XINT_EMPT | CS_XINT_GENL | CS_XINT_PENA | PDMA_READY) + +#define CS_CAPT_SETUP (CS_GENL_INT | CS_CAPT_INT | CS_XINT_ENA | CS_XINT_CAPT | CS_XINT_CEMP | CS_XINT_GENL | CDMA_READY) #define CS4231_MIN_ATEN (0) #define CS4231_MAX_ATEN (31) #define CS4231_MAX_DEV_ATEN (63) -#define CS4231_MIN_GAIN (0) -#define CS4231_MAX_GAIN (15) + #define CS4231_MON_MIN_ATEN (0) #define CS4231_MON_MAX_ATEN (63) -#define CS4231_PRECISION (8) /* Bits per sample unit */ -#define CS4231_CHANNELS (1) /* Channels per sample frame */ +#define CS4231_DEFAULT_PLAYGAIN (132) +#define CS4231_DEFAULT_RECGAIN (126) -#define CS4231_RATE (8000) +#define CS4231_MIN_GAIN (0) +#define CS4231_MAX_GAIN (15) -#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */ -#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */ -#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */ -#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */ -#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */ -#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */ - -#define AUDIO_LEFT_BALANCE (0) -#define AUDIO_MID_BALANCE (32) -#define AUDIO_RIGHT_BALANCE (64) -#define AUDIO_BALANCE_SHIFT (3) - -#define AUDIO_SPEAKER 0x01 -#define AUDIO_HEADPHONE 0x02 -#define AUDIO_LINE_OUT 0x04 - -#define AUDIO_MICROPHONE 0x01 -#define AUDIO_LINE_IN 0x02 -#define AUDIO_INTERNAL_CD_IN 0x04 +#define CS4231_PRECISION (8) /* # of bits/sample */ +#define CS4231_CHANNELS (1) /* channels/sample */ -#define AUDIO_MAX_GAIN (255) +#define CS4231_RATE (8000) /* default sample rate */ +/* Other rates supported are: + * 9600, 11025, 16000, 18900, 22050, 32000, 37800, 44100, 48000 + */ #endif diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in --- v2.1.28/linux/drivers/sbus/char/Config.in Fri Dec 13 01:37:32 1996 +++ linux/drivers/sbus/char/Config.in Wed Mar 5 17:04:32 1997 @@ -10,11 +10,7 @@ bool 'bwtwo support' SUN_FB_BWTWO bool 'leo/zx support' SUN_FB_LEO bool 'weitek P9X00 support' TADPOLE_FB_WEITEK - bool 'Fast 8 bit 1152x900 mode' SUN_FB_FAST_ONE - bool 'Fast mono 1152x900 mode' SUN_FB_FAST_TWO - bool 'Fast 8 bit 1280x1024 mode' SUN_FB_FAST_MONO if [ "$TADPOLE_FB_WEITEK" = "n" ]; then - bool 'Generic AutoResolution mode' SUN_FB_GENERIC fbs=$SUN_FB_CGSIX fbs=$fbs$SUN_FB_TCX fbs=$fbs$SUN_FB_CGTHREE @@ -22,7 +18,6 @@ fbs=$fbs$SUN_FB_CGFOURTEEN fbs=$fbs$SUN_FB_LEO fbs=$fbs$TADPOLE_FB_WEITEK - fbs=$fbs$SUN_FB_GENERIC if [ "$fbs" = "nnnnnnnn" ]; then echo "Warning: You have excluded ALL FB Support" echo "Notice: Enabling Generic AutoResolution" @@ -39,12 +34,9 @@ define_bool SUN_FB_BWTWO y define_bool SUN_FB_LEO y define_bool TADPOLE_FB_WEITEK y - define_bool SUN_FB_FAST_ONE y - define_bool SUN_FB_FAST_TWO y - define_bool SUN_FB_FAST_MONO y - define_bool SUN_FB_GENERIC y fi comment 'Misc Linux/SPARC drivers' tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC +tristate 'Bidirectional parallel port support' CONFIG_SUN_BPP diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile --- v2.1.28/linux/drivers/sbus/char/Makefile Fri Dec 13 01:37:32 1996 +++ linux/drivers/sbus/char/Makefile Wed Mar 5 17:04:32 1997 @@ -65,5 +65,13 @@ endif endif +ifeq ($(CONFIG_SUN_BPP),y) +O_OBJS += bpp.o +else + ifeq ($(CONFIG_SUN_BPP),m) + M_OBJS += bpp.o + endif +endif + include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c --- v2.1.28/linux/drivers/sbus/char/bpp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/bpp.c Wed Mar 5 17:04:32 1997 @@ -0,0 +1,1093 @@ +/* + * drivers/sbus/char/bpp.c + * + * Copyright (c) 1995 Picture Elements + * Stephen Williams (steve@icarus.com) + * Gus Baldauf (gbaldauf@ix.netcom.com) + * + * Linux/SPARC port by Peter Zaitcev. + * Integration into SPARC tree by Tom Dyas. + */ + + +# include +# include +# include +# include +# include +# include +# include +# include + +# include + +# if defined(__i386__) +# include +# include +# include +# endif + +# if defined(__sparc__) +# include /* udelay() */ + +# include /* OpenProm Library */ +# include /* struct linux_sbus *SBus_chain */ +# include /* sparc_alloc_io() */ +# endif + +# include + +#define BPP_PROBE_CODE 0x55 +#define BPP_DELAY 100 + +static const unsigned BPP_MAJOR = 32; +static const char* dev_name = "bpp"; + +/* When switching from compatability to a mode where I can read, try + the following mode first. */ + +/* const unsigned char DEFAULT_ECP = 0x10; */ +static const unsigned char DEFAULT_ECP = 0x30; +static const unsigned char DEFAULT_NIBBLE = 0x00; + +/* + * These are 1284 time constraints, in units of jiffies. + */ + +static const unsigned long TIME_PSetup = 1; +static const unsigned long TIME_PResponse = 6; +static const unsigned long TIME_IDLE_LIMIT = 2000; + +/* + * One instance per supported subdevice... + */ +# define BPP_NO 3 + +enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP }; + +struct inst { + unsigned present : 1; /* True if the hardware exists */ + unsigned enhanced : 1; /* True if the hardware in "enhanced" */ + unsigned opened : 1; /* True if the device is opened already */ + unsigned run_flag : 1; /* True if waiting for a repeate byte */ + + unsigned char direction; /* 0 --> out, 0x20 --> IN */ + unsigned char pp_state; /* State of host controlled pins. */ + enum IEEE_Mode mode; + + unsigned char run_length; + unsigned char repeat_byte; + + /* These members manage timeouts for programmed delays */ + struct wait_queue *wait_queue; + struct timer_list timer_list; +}; + +static struct inst instances[BPP_NO]; + +#if defined(__i386__) + +const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc }; + +/* + * These are for data access. + * Control lines accesses are hidden in set_bits() and get_bits(). + * The exeption is the probe procedure, which is system-dependent. + */ +#define bpp_outb_p(data, base) outb_p((data), (base)) +#define bpp_inb(base) inb(base) +#define bpp_inb_p(base) inb_p(base) + +/* + * This method takes the pin values mask and sets the hardware pins to + * the requested value: 1 == high voltage, 0 == low voltage. This + * burries the annoying PC bit inversion and preserves the direction + * flag. + */ +static void set_pins(unsigned short pins, unsigned minor) +{ + unsigned char bits = instances[minor].direction; /* == 0x20 */ + + if (! (pins & BPP_PP_nStrobe)) bits |= 1; + if (! (pins & BPP_PP_nAutoFd)) bits |= 2; + if ( pins & BPP_PP_nInit) bits |= 4; + if (! (pins & BPP_PP_nSelectIn)) bits |= 8; + + instances[minor].pp_state = bits; + + outb_p(bits, base_addrs[minor]+2); +} + +static unsigned short get_pins(unsigned minor) +{ + unsigned short bits = 0; + + unsigned value = instances[minor].pp_state; + if (! (value & 0x01)) bits |= BPP_PP_nStrobe; + if (! (value & 0x02)) bits |= BPP_PP_nAutoFd; + if (value & 0x04) bits |= BPP_PP_nInit; + if (! (value & 0x08)) bits |= BPP_PP_nSelectIn; + + value = inb_p(base_addrs[minor]+1); + if (value & 0x08) bits |= BPP_GP_nFault; + if (value & 0x10) bits |= BPP_GP_Select; + if (value & 0x20) bits |= BPP_GP_PError; + if (value & 0x40) bits |= BPP_GP_nAck; + if (! (value & 0x80)) bits |= BPP_GP_Busy; + + return bits; +} + +#endif /* __i386__ */ + +#if defined(__sparc__) + +/* + * Register block + */ +struct bpp_regs { + /* DMA registers */ + __u32 p_csr; /* DMA Control/Status Register */ + __u32 p_addr; /* Address Register */ + __u32 p_bcnt; /* Byte Count Register */ + __u32 p_tst_csr; /* Test Control/Status (DMA2 only) */ + /* Parallel Port registers */ + __u16 p_hcr; /* Hardware Configuration Register */ + __u16 p_ocr; /* Operation Configuration Register */ + __u8 p_dr; /* Parallel Data Register */ + __u8 p_tcr; /* Transfer Control Register */ + __u8 p_or; /* Output Register */ + __u8 p_ir; /* Input Register */ + __u16 p_icr; /* Interrupt Control Register */ +}; + +/* P_CSR. Bits of type RW1 are cleared with writting '1'. */ +#define P_DEV_ID_MASK 0xf0000000 /* R */ +#define P_DEV_ID_ZEBRA 0x40000000 +#define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */ +#define P_NA_LOADED 0x08000000 /* R NA wirtten but was not used */ +#define P_A_LOADED 0x04000000 /* R */ +#define P_DMA_ON 0x02000000 /* R DMA is not disabled */ +#define P_EN_NEXT 0x01000000 /* RW */ +#define P_TCI_DIS 0x00800000 /* RW TCI forbidden from interrupts */ +#define P_DIAG 0x00100000 /* RW Disables draining and resetting + of P-FIFO on loading of P_ADDR*/ +#define P_BURST_SIZE 0x000c0000 /* RW SBus burst size */ +#define P_BURST_8 0x00000000 +#define P_BURST_4 0x00040000 +#define P_BURST_1 0x00080000 /* "No burst" write */ +#define P_TC 0x00004000 /* RW1 Term Count, can be cleared when + P_EN_NEXT=1 */ +#define P_EN_CNT 0x00002000 /* RW */ +#define P_EN_DMA 0x00000200 /* RW */ +#define P_WRITE 0x00000100 /* R DMA dir, 1=to ram, 0=to port */ +#define P_RESET 0x00000080 /* RW */ +#define P_SLAVE_ERR 0x00000040 /* RW1 Access size error */ +#define P_INVALIDATE 0x00000020 /* W Drop P-FIFO */ +#define P_INT_EN 0x00000010 /* RW OK to P_INT_PEND||P_ERR_PEND */ +#define P_DRAINING 0x0000000c /* R P-FIFO is draining to memory */ +#define P_ERR_PEND 0x00000002 /* R */ +#define P_INT_PEND 0x00000001 /* R */ + +/* P_HCR. Time is in increments of SBus clock. */ +#define P_HCR_TEST 0x8000 /* Allows buried counters to be read */ +#define P_HCR_DSW 0x7f00 /* Data strobe width (in ticks) */ +#define P_HCR_DDS 0x007f /* Data setup before strobe (in ticks) */ + +/* P_OCR. */ +#define P_OCR_MEM_CLR 0x8000 +#define P_OCR_DATA_SRC 0x4000 /* ) */ +#define P_OCR_DS_DSEL 0x2000 /* ) Bidirectional */ +#define P_OCR_BUSY_DSEL 0x1000 /* ) selects */ +#define P_OCR_ACK_DSEL 0x0800 /* ) */ +#define P_OCR_EN_DIAG 0x0400 +#define P_OCR_BUSY_OP 0x0200 /* Busy operation */ +#define P_OCR_ACK_OP 0x0100 /* Ack operation */ +#define P_OCR_SRST 0x0080 /* Reset state machines. Not selfcleaning. */ +#define P_OCR_IDLE 0x0008 /* PP data transfer state machine is idle */ +#define P_OCR_V_ILCK 0x0002 /* Versatec faded. Zebra only. */ +#define P_OCR_EN_VER 0x0001 /* Enable Versatec (0 - enable). Zebra only. */ + +/* P_TCR */ +#define P_TCR_DIR 0x08 +#define P_TCR_BUSY 0x04 +#define P_TCR_ACK 0x02 +#define P_TCR_DS 0x01 /* Strobe */ + +/* P_OR */ +#define P_OR_V3 0x20 /* ) */ +#define P_OR_V2 0x10 /* ) on Zebra only */ +#define P_OR_V1 0x08 /* ) */ +#define P_OR_INIT 0x04 +#define P_OR_AFXN 0x02 /* Auto Feed */ +#define P_OR_SLCT_IN 0x01 + +/* P_IR */ +#define P_IR_PE 0x04 +#define P_IR_SLCT 0x02 +#define P_IR_ERR 0x01 + +/* P_ICR */ +#define P_DS_IRQ 0x8000 /* RW1 */ +#define P_ACK_IRQ 0x4000 /* RW1 */ +#define P_BUSY_IRQ 0x2000 /* RW1 */ +#define P_PE_IRQ 0x1000 /* RW1 */ +#define P_SLCT_IRQ 0x0800 /* RW1 */ +#define P_ERR_IRQ 0x0400 /* RW1 */ +#define P_DS_IRQ_EN 0x0200 /* RW Always on rising edge */ +#define P_ACK_IRQ_EN 0x0100 /* RW Always on rising edge */ +#define P_BUSY_IRP 0x0080 /* RW 1= rising edge */ +#define P_BUSY_IRQ_EN 0x0040 /* RW */ +#define P_PE_IRP 0x0020 /* RW 1= rising edge */ +#define P_PE_IRQ_EN 0x0010 /* RW */ +#define P_SLCT_IRP 0x0008 /* RW 1= rising edge */ +#define P_SLCT_IRQ_EN 0x0004 /* RW */ +#define P_ERR_IRP 0x0002 /* RW1 1= rising edge */ +#define P_ERR_IRQ_EN 0x0001 /* RW */ + +volatile struct bpp_regs *base_addrs[BPP_NO]; + +static inline void bpp_outb_p(__u8 data, volatile struct bpp_regs *base){ + base->p_dr = data; +} + +#define bpp_inb_p(base) bpp_inb(base) + +static inline __u8 bpp_inb(volatile struct bpp_regs *base){ + return base->p_dr; +} + + +static void set_pins(unsigned short pins, unsigned minor) +{ + volatile struct bpp_regs *base = base_addrs[minor]; + unsigned char bits_tcr = 0, bits_or = 0; + + if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR; + if ( pins & BPP_PP_nStrobe) bits_tcr |= P_TCR_DS; + + if ( pins & BPP_PP_nAutoFd) bits_or |= P_OR_AFXN; + if (! (pins & BPP_PP_nInit)) bits_or |= P_OR_INIT; + if (! (pins & BPP_PP_nSelectIn)) bits_or |= P_OR_SLCT_IN; + + base->p_or = bits_or; + base->p_tcr = bits_tcr; +} + +/* + * i386 people read output pins from a software image. + * We may get them back from hardware. + * Again, inversion of pins must he buried here. + */ +static unsigned short get_pins(unsigned minor) +{ + volatile struct bpp_regs *base = base_addrs[minor]; + unsigned short bits = 0; + unsigned value_tcr = base->p_tcr; + unsigned value_ir = base->p_ir; + unsigned value_or = base->p_or; + + if (value_tcr & P_TCR_DS) bits |= BPP_PP_nStrobe; + if (value_or & P_OR_AFXN) bits |= BPP_PP_nAutoFd; + if (! (value_or & P_OR_INIT)) bits |= BPP_PP_nInit; + if (! (value_or & P_OR_SLCT_IN)) bits |= BPP_PP_nSelectIn; + + if (value_ir & P_IR_ERR) bits |= BPP_GP_nFault; + if (! (value_ir & P_IR_SLCT)) bits |= BPP_GP_Select; + if (! (value_ir & P_IR_PE)) bits |= BPP_GP_PError; + if (! (value_tcr & P_TCR_ACK)) bits |= BPP_GP_nAck; + if (value_tcr & P_TCR_BUSY) bits |= BPP_GP_Busy; + + return bits; +} + +#if 0 +/* P3 */ +static inline void bpp_snap(const char *msg, unsigned minor) +{ + volatile struct bpp_regs *r = base_addrs[minor]; + printk("bpp.%s: c=%02x o=%02x i=%02x\n", msg, r->p_tcr, r->p_or, r->p_ir); +} +#endif + +#endif /* __sparc__ */ + +/* + * This is TRUE if the module_init successfully loaded the module. + */ +#if 0 +static int loaded_flag = 0; +#endif + +static void bpp_wake_up(unsigned long val) +{ wake_up(&instances[val].wait_queue); } + +static void snooze(unsigned long snooze_time, unsigned minor) +{ + instances[minor].timer_list.expires = snooze_time+1; + instances[minor].timer_list.data = minor; + add_timer(&instances[minor].timer_list); + sleep_on (&instances[minor].wait_queue); +} + +static int wait_for(unsigned short set, unsigned short clr, + unsigned long delay, unsigned minor) +{ + unsigned short pins = get_pins(minor); + + unsigned long extime = 0; + + /* + * Try a real fast scan for the first jiffy, in case the device + * responds real good. The first while loop guesses an expire + * time accounting for possible wraparound of jiffies. + */ + while (extime <= jiffies) extime = jiffies + 1; + while ( (jiffies < extime) + && (((pins & set) != set) || ((pins & clr) != 0)) ) { + pins = get_pins(minor); + } + + delay -= 1; + + /* + * If my delay expired or the pins are still not where I want + * them, then resort to using the timer and greatly reduce my + * sample rate. If the peripheral is going to be slow, this will + * give the CPU up to some more worthy process. + */ + while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) { + + snooze(1, minor); + pins = get_pins(minor); + delay -= 1; + } + + if (delay == 0) return -1; + else return pins; +} + +/* + * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An + * errno means something broke, and I do not yet know how to fix it. + */ +static int negotiate(unsigned char mode, unsigned minor) +{ + int rc; + unsigned short pins = get_pins(minor); + if (pins & BPP_PP_nSelectIn) return -EIO; + + + /* Event 0: Write the mode to the data lines */ + bpp_outb_p(mode, base_addrs[minor]); + + snooze(TIME_PSetup, minor); + + /* Event 1: Strobe the mode code into the peripheral */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor); + + /* Wait for Event 2: Peripheral responds as a 1284 device. */ + rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault, + BPP_GP_nAck, + TIME_PResponse, + minor); + + if (rc == -1) return -ETIMEDOUT; + + /* Event 3: latch extensibility request */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor); + + /* ... quick nap while peripheral ponders the byte i'm sending...*/ + snooze(1, minor); + + /* Event 4: restore strobe, to ACK peripheral's response. */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); + + /* Wait for Event 6: Peripheral latches response bits */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor); + if (rc == -1) return -EIO; + + /* A 1284 device cannot refuse nibble mode */ + if (mode == DEFAULT_NIBBLE) return 0; + + if (pins & BPP_GP_Select) return 0; + + return -EPROTONOSUPPORT; +} + +static int terminate(unsigned minor) +{ + int rc; + + /* Event 22: Request termination of 1284 mode */ + set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); + + /* Wait for Events 23 and 24: ACK termination request. */ + rc = wait_for(BPP_GP_Busy|BPP_GP_nFault, + BPP_GP_nAck, + TIME_PSetup+TIME_PResponse, + minor); + + instances[minor].direction = 0; + instances[minor].mode = COMPATIBILITY; + + if (rc == -1) { + return -EIO; + } + + /* Event 25: Handshake by lowering nAutoFd */ + set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor); + + /* Event 26: Peripheral wiggles lines... */ + + /* Event 27: Peripheral sets nAck HIGH to ack handshake */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); + if (rc == -1) { + set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); + return -EIO; + } + + /* Event 28: Finish phase by raising nAutoFd */ + set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); + + return 0; +} + + +/* + * Allow only one process to open the device at a time. + */ +static int open(struct inode *inode, struct file *f) +{ + unsigned minor = MINOR(inode->i_rdev); + if (minor >= BPP_NO) return -ENODEV; + if (! instances[minor].present) return -ENODEV; + if (instances[minor].opened) return -EBUSY; + + instances[minor].opened = 1; + + return 0; +} + +/* + * When the process closes the device, this method is called to clean + * up and reset the hardware. Always leave the device in compatibility + * mode as this is a reasonable place to clean up from messes made by + * ioctls, or other mayhem. + */ +static void release(struct inode *inode, struct file *f) +{ + unsigned minor = MINOR(inode->i_rdev); + instances[minor].opened = 0; + + if (instances[minor].mode != COMPATIBILITY) + terminate(minor); +} + +static long read_nibble(unsigned minor, char *c, unsigned long cnt) +{ + unsigned long remaining = cnt; + long rc; + + while (remaining > 0) { + unsigned char byte = 0; + int pins; + + /* Event 7: request nibble */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); + + /* Wait for event 9: Peripher strobes first nibble */ + pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); + if (pins == -1) return -ETIMEDOUT; + + /* Event 10: I handshake nibble */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); + if (pins & BPP_GP_nFault) byte |= 0x01; + if (pins & BPP_GP_Select) byte |= 0x02; + if (pins & BPP_GP_PError) byte |= 0x04; + if (pins & BPP_GP_Busy) byte |= 0x08; + + /* Wait for event 11: Peripheral handshakes nibble */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); + + /* Event 7: request nibble */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); + + /* Wait for event 9: Peripher strobes first nibble */ + pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + + /* Event 10: I handshake nibble */ + set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); + if (pins & BPP_GP_nFault) byte |= 0x10; + if (pins & BPP_GP_Select) byte |= 0x20; + if (pins & BPP_GP_PError) byte |= 0x40; + if (pins & BPP_GP_Busy) byte |= 0x80; + + put_user_ret(byte, c, -EFAULT); + c += 1; + remaining -= 1; + + /* Wait for event 11: Peripheral handshakes nibble */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); + if (rc == -1) return -EIO; + } + + return cnt - remaining; +} + +static long read_ecp(unsigned minor, char *c, unsigned long cnt) +{ + unsigned long remaining; + long rc; + + /* Turn ECP mode from forward to reverse if needed. */ + if (! instances[minor].direction) { + unsigned short pins = get_pins(minor); + + /* Event 38: Turn the bus around */ + instances[minor].direction = 0x20; + pins &= ~BPP_PP_nAutoFd; + set_pins(pins, minor); + + /* Event 39: Set pins for reverse mode. */ + snooze(TIME_PSetup, minor); + set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); + + /* Wait for event 40: Peripheral ready to be strobed */ + rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + } + + remaining = cnt; + + while (remaining > 0) { + + /* If there is a run length for a repeated byte, repeat */ + /* that byte a few times. */ + if (instances[minor].run_length && !instances[minor].run_flag) { + + char buffer[128]; + unsigned idx; + unsigned repeat = remaining < instances[minor].run_length + ? remaining + : instances[minor].run_length; + + for (idx = 0 ; idx < repeat ; idx += 1) + buffer[idx] = instances[minor].repeat_byte; + + copy_to_user_ret(c, buffer, repeat, -EFAULT); + remaining -= repeat; + c += repeat; + instances[minor].run_length -= repeat; + } + + if (remaining == 0) break; + + + /* Wait for Event 43: Data active on the bus. */ + rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); + if (rc == -1) break; + + if (rc & BPP_GP_Busy) { + /* OK, this is data. read it in. */ + unsigned char byte = bpp_inb(base_addrs[minor]); + put_user_ret(byte, c, -EFAULT); + c += 1; + remaining -= 1; + + if (instances[minor].run_flag) { + instances[minor].repeat_byte = byte; + instances[minor].run_flag = 0; + } + + } else { + unsigned char byte = bpp_inb(base_addrs[minor]); + if (byte & 0x80) { + printk("bpp%d: " + "Ignoring ECP channel %u from device.\n", + minor, byte & 0x7f); + } else { + instances[minor].run_length = byte; + instances[minor].run_flag = 1; + } + } + + /* Event 44: I got it. */ + set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor); + + /* Wait for event 45: peripheral handshake */ + rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + + /* Event 46: Finish handshake */ + set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); + + } + + + return cnt - remaining; +} + +static long read(struct inode *inode, struct file *f, + char *c, unsigned long cnt) +{ + long rc; + const unsigned minor = MINOR(inode->i_rdev); + if (minor >= BPP_NO) return -ENODEV; + if (!instances[minor].present) return -ENODEV; + + switch (instances[minor].mode) { + + default: + if (instances[minor].mode != COMPATIBILITY) + terminate(minor); + + if (instances[minor].enhanced) { + /* For now, do all reads with ECP-RLE mode */ + unsigned short pins; + + rc = negotiate(DEFAULT_ECP, minor); + if (rc < 0) break; + + instances[minor].mode = ECP_RLE; + + /* Event 30: set nAutoFd low to setup for ECP mode */ + pins = get_pins(minor); + pins &= ~BPP_PP_nAutoFd; + set_pins(pins, minor); + + /* Wait for Event 31: peripheral ready */ + rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + + rc = read_ecp(minor, c, cnt); + + } else { + rc = negotiate(DEFAULT_NIBBLE, minor); + if (rc < 0) break; + + instances[minor].mode = NIBBLE; + + rc = read_nibble(minor, c, cnt); + } + break; + + case NIBBLE: + rc = read_nibble(minor, c, cnt); + break; + + case ECP: + case ECP_RLE: + rc = read_ecp(minor, c, cnt); + break; + + } + + + return rc; +} + +/* + * Compatibility mode handshaking is a matter of writing data, + * strobing it, and waiting for the printer to stop being busy. + */ +static long write_compat(unsigned minor, const char *c, unsigned long cnt) +{ + long rc; + unsigned short pins = get_pins(minor); + + unsigned long remaining = cnt; + + while (remaining > 0) { + unsigned char byte; + c += 1; + get_user_ret(byte, c, -EFAULT); + + rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor); + if (rc == -1) return -ETIMEDOUT; + + bpp_outb_p(byte, base_addrs[minor]); + remaining -= 1; + /* snooze(1, minor); */ + + pins &= ~BPP_PP_nStrobe; + set_pins(pins, minor); + + rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); + + pins |= BPP_PP_nStrobe; + set_pins(pins, minor); + } + + return cnt - remaining; +} + +/* + * Write data using ECP mode. Watch out that the port may be set up + * for reading. If so, turn the port around. + */ +static long write_ecp(unsigned minor, const char *c, unsigned long cnt) +{ + unsigned short pins = get_pins(minor); + unsigned long remaining = cnt; + + if (instances[minor].direction) { + int rc; + + /* Event 47 Request bus be turned around */ + pins |= BPP_PP_nInit; + set_pins(pins, minor); + + /* Wait for Event 49: Peripheral relinquished bus */ + rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); + + pins |= BPP_PP_nAutoFd; + instances[minor].direction = 0; + set_pins(pins, minor); + } + + while (remaining > 0) { + unsigned char byte; + int rc; + + get_user_ret(byte, c, -EFAULT); + + rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor); + if (rc == -1) return -ETIMEDOUT; + + c += 1; + + bpp_outb_p(byte, base_addrs[minor]); + + pins &= ~BPP_PP_nStrobe; + set_pins(pins, minor); + + pins |= BPP_PP_nStrobe; + rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); + if (rc == -1) return -EIO; + + set_pins(pins, minor); + } + + return cnt - remaining; +} + +/* + * Write to the peripheral. Be sensitive of the current mode. If I'm + * in a mode that can be turned around (ECP) then just do + * that. Otherwise, terminate and do my writing in compat mode. This + * is the safest course as any device can handle it. + */ +static long write(struct inode *inode, struct file *f, + const char *c, unsigned long cnt) +{ + long errno = 0; + unsigned minor = MINOR(inode->i_rdev); + if (minor >= BPP_NO) return -ENODEV; + if (!instances[minor].present) return -ENODEV; + + switch (instances[minor].mode) { + + case ECP: + case ECP_RLE: + errno = write_ecp(minor, c, cnt); + break; + case COMPATIBILITY: + errno = write_compat(minor, c, cnt); + break; + default: + terminate(minor); + errno = write_compat(minor, c, cnt); + } + + return errno; +} + +static int ioctl(struct inode *inode, struct file *f, unsigned int cmd, + unsigned long arg) +{ + int errno = 0; + + unsigned minor = MINOR(inode->i_rdev); + if (minor >= BPP_NO) return -ENODEV; + if (!instances[minor].present) return -ENODEV; + + + switch (cmd) { + + case BPP_PUT_PINS: + set_pins(arg, minor); + break; + + case BPP_GET_PINS: + errno = get_pins(minor); + break; + + case BPP_PUT_DATA: + bpp_outb_p(arg, base_addrs[minor]); + break; + + case BPP_GET_DATA: + errno = bpp_inb_p(base_addrs[minor]); + break; + + case BPP_SET_INPUT: + if (arg) + if (instances[minor].enhanced) { + unsigned short bits = get_pins(minor); + instances[minor].direction = 0x20; + set_pins(bits, minor); + } else { + errno = -ENOTTY; + } + else { + unsigned short bits = get_pins(minor); + instances[minor].direction = 0x00; + set_pins(bits, minor); + } + break; + + default: + errno = -EINVAL; + } + + return errno; +} + +static struct file_operations bpp_fops = { + 0, + read, /* read */ + write, /* write */ + 0, + 0, + ioctl, + 0, /* mmap */ + open, + release, + 0, + 0, + 0, + 0 +}; + +#if defined(__i386__) + +#define collectLptPorts() {} + +static void probeLptPort(unsigned idx) +{ + unsigned int testvalue; + const unsigned short lpAddr = base_addrs[idx]; + + instances[idx].present = 0; + instances[idx].enhanced = 0; + instances[idx].direction = 0; + instances[idx].mode = COMPATIBILITY; + instances[idx].wait_queue = 0; + instances[idx].run_length = 0; + instances[idx].run_flag = 0; + init_timer(&instances[idx].timer_list); + instances[idx].timer_list.function = bpp_wake_up; + if (check_region(lpAddr,3)) return; + + /* + * First, make sure the instance exists. Do this by writing to + * the data latch and reading the value back. If the port *is* + * present, test to see if it supports extended-mode + * operation. This will be required for IEEE1284 reverse + * transfers. + */ + + outb_p(BPP_PROBE_CODE, lpAddr); + for (testvalue=0; testvaluereg_addrs[0]; + printk("bpp%d.map_bpp: 0x%x.%p[0x%x] i=%d\n", idx, + areg.which_io, areg.phys_addr, areg.reg_size, + dev->irqs[0].pri); + /* IPC Zebra 1.fa200000[1c] i=2 */ + /** prom_apply_sbus_ranges (&areg, 1); **/ + + regs = sparc_alloc_io (areg.phys_addr, 0, + sizeof(struct bpp_regs), "bpp", + areg.which_io, 0x0); + + return regs; +} + +static int collectLptPorts(void) +{ + struct linux_sbus *bus; + struct linux_sbus_device *dev; + int count; + + count = 0; + for_all_sbusdev(dev, bus) { + if (strcmp(dev->prom_name, "SUNW,bpp") == 0) { + if (count >= BPP_NO) { + printk(KERN_NOTICE + "bpp: More than %d bpp ports," + " rest is ignored\n", BPP_NO); + return count; + } + base_addrs[count] = map_bpp(dev, count); + count++; + } + } + return count; +} + +static void probeLptPort(unsigned idx) +{ + volatile struct bpp_regs *rp = base_addrs[idx]; + __u32 csr; + char *brand; + + instances[idx].present = 0; + instances[idx].enhanced = 0; + instances[idx].direction = 0; + instances[idx].mode = COMPATIBILITY; + instances[idx].wait_queue = 0; + instances[idx].run_length = 0; + instances[idx].run_flag = 0; + init_timer(&instances[idx].timer_list); + instances[idx].timer_list.function = bpp_wake_up; + + if (rp == 0) return; + + instances[idx].present = 1; + instances[idx].enhanced = 1; /* Sure */ + + if (((csr = rp->p_csr) & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { + udelay(20); + csr = rp->p_csr; + if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { + printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr); + } + } + printk("bpp%d: reset with 0x%08x ..", idx, csr); + rp->p_csr = (csr | P_RESET) & ~P_INT_EN; + udelay(500); + rp->p_csr &= ~P_RESET; + printk(" done with csr=0x%08x ocr=0x%04x\n", rp->p_csr, rp->p_ocr); + + switch (rp->p_csr & P_DEV_ID_MASK) { + case P_DEV_ID_ZEBRA: + brand = "Zebra"; + break; + case P_DEV_ID_L64854: + brand = "DMA2"; + break; + default: + brand = "Unknown"; + } + printk("bpp%d: %s at 0x%p\n", idx, brand, rp); + + /* + * Leave the port in compat idle mode. + */ + set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); + + return; +} + +static inline void freeLptPort(int idx) +{ + sparc_free_io ((void *)base_addrs[idx], sizeof(struct bpp_regs)); +} + +#endif + +#ifdef MODULE +int init_module(void) +#else +__initfunc(int bpp_init(void)) +#endif +{ + int rc; + unsigned idx; + + rc = collectLptPorts(); + if (rc == 0) + return -ENODEV; + + rc = register_chrdev(BPP_MAJOR, dev_name, &bpp_fops); + if (rc < 0) + return rc; + + for (idx = 0; idx < BPP_NO; idx += 1) { + instances[idx].opened = 0; + probeLptPort(idx); + } + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + unsigned idx; + + unregister_chrdev(BPP_MAJOR, dev_name); + + for (idx = 0 ; idx < BPP_NO ; idx += 1) { + if (instances[idx].present) + freeLptPort(idx); + } +} +#endif diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c --- v2.1.28/linux/drivers/sbus/char/cgsix.c Mon Dec 30 02:00:04 1996 +++ linux/drivers/sbus/char/cgsix.c Wed Mar 5 17:04:32 1997 @@ -1,4 +1,4 @@ -/* $Id: cgsix.c,v 1.21 1996/12/23 10:16:05 ecd Exp $ +/* $Id: cgsix.c,v 1.22 1997/02/02 02:12:41 ecd Exp $ * cgsix.c: cgsix frame buffer driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -553,7 +553,7 @@ static void cg6_blitc(unsigned short charattr, int xoff, int yoff) { - unsigned char attrib = charattr >> 8; + unsigned char attrib = CHARATTR_TO_SUNCOLOR(charattr); unsigned char *p = &vga_font[((unsigned char)charattr) << 4]; GX_BLITC_START(attrib) GX_BLITC_BODY1(xoff, yoff, gx->font=((*p++) << 24)) @@ -562,7 +562,7 @@ static void cg6_setw(int xoff, int yoff, unsigned short c, int count) { - unsigned char attrib = c >> 8; + unsigned char attrib = CHARATTR_TO_SUNCOLOR(c); unsigned char *p = &vga_font[((unsigned char)c) << 4]; register unsigned char *q; register uint l; @@ -584,7 +584,7 @@ static void cg6_cpyw(int xoff, int yoff, unsigned short *p, int count) { - unsigned char attrib = *p >> 8; + unsigned char attrib = CHARATTR_TO_SUNCOLOR(*p); unsigned char *p1, *p2, *p3, *p4; GX_BLITC_START(attrib) if (count >= 4) { diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/fb.h linux/drivers/sbus/char/fb.h --- v2.1.28/linux/drivers/sbus/char/fb.h Mon Dec 30 02:00:05 1996 +++ linux/drivers/sbus/char/fb.h Wed Mar 5 17:04:32 1997 @@ -1,4 +1,4 @@ -/* $Id: fb.h,v 1.20 1996/12/23 10:16:08 ecd Exp $ +/* $Id: fb.h,v 1.21 1997/02/02 02:12:43 ecd Exp $ * fb.h: contains the definitions of the structures that various sun * frame buffer can use to do console driver stuff. * @@ -149,6 +149,12 @@ } fbinfo_t; #define CM(i, j) [3*(i)+(j)] + +extern unsigned char reverse_color_table[]; + +#define CHARATTR_TO_SUNCOLOR(attr) \ + ((reverse_color_table[(attr) >> 12] << 4) | \ + reverse_color_table[((attr) >> 8) & 0x0f]) extern fbinfo_t *fbinfo; extern int fbinfos; diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/leo.c linux/drivers/sbus/char/leo.c --- v2.1.28/linux/drivers/sbus/char/leo.c Mon Dec 30 02:00:05 1996 +++ linux/drivers/sbus/char/leo.c Wed Mar 5 17:04:32 1997 @@ -1,4 +1,4 @@ -/* $Id: leo.c,v 1.10 1996/12/23 10:16:09 ecd Exp $ +/* $Id: leo.c,v 1.11 1997/02/02 02:12:44 ecd Exp $ * leo.c: SUNW,leo 24/8bit frame buffer driver * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -637,7 +637,7 @@ static void leo_blitc(unsigned short charattr, int xoff, int yoff) { - unsigned char attrib = charattr >> 8; + unsigned char attrib = CHARATTR_TO_SUNCOLOR(charattr); unsigned char *p = &vga_font[((unsigned char)charattr) << 4]; u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff; GX_BLITC_START(attrib, xoff, yoff, 1) @@ -648,7 +648,7 @@ static void leo_setw(int xoff, int yoff, unsigned short c, int count) { - unsigned char attrib = c >> 8; + unsigned char attrib = CHARATTR_TO_SUNCOLOR(c); unsigned char *p = &vga_font[((unsigned char)c) << 4]; register unsigned char *q; u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff; @@ -664,7 +664,7 @@ static void leo_cpyw(int xoff, int yoff, unsigned short *p, int count) { - unsigned char attrib = *p >> 8; + unsigned char attrib = CHARATTR_TO_SUNCOLOR(*p); register unsigned char *q; u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff; GX_BLITC_START(attrib, xoff, yoff, count) diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c --- v2.1.28/linux/drivers/sbus/char/openprom.c Sun Jan 26 02:07:18 1997 +++ linux/drivers/sbus/char/openprom.c Wed Mar 5 17:04:32 1997 @@ -1,6 +1,6 @@ /* * Linux/SPARC PROM Configuration Driver - * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) + * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * * This character device driver allows user programs to access the @@ -29,6 +29,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define PROMLIB_INTERNAL + #include #include #include @@ -40,8 +42,8 @@ #include #include #include +#include -#include /* Private data kept by the driver for each descriptor. */ typedef struct openprom_private_data @@ -214,9 +216,9 @@ save_and_cli(flags); if (cmd == OPROMNEXT) - node = prom_nodeops->no_nextnode(node); + node = __prom_getsibling(node); else - node = prom_nodeops->no_child(node); + node = __prom_getchild(node); restore_flags(flags); data->current_node = node; @@ -447,9 +449,9 @@ save_and_cli(flags); if (cmd == OPIOCGETNEXT) - node = prom_nodeops->no_nextnode(node); + node = __prom_getsibling(node); else - node = prom_nodeops->no_child(node); + node = __prom_getchild(node); restore_flags(flags); __copy_to_user_ret((void *)arg, &node, sizeof(int), -EFAULT); @@ -601,10 +603,8 @@ } #ifdef MODULE - void cleanup_module(void) { misc_deregister(&openprom_dev); } - #endif diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c --- v2.1.28/linux/drivers/sbus/char/suncons.c Sun Jan 26 02:07:18 1997 +++ linux/drivers/sbus/char/suncons.c Wed Mar 5 17:04:32 1997 @@ -1,4 +1,4 @@ -/* $Id: suncons.c,v 1.44 1997/01/25 02:47:10 miguel Exp $ +/* $Id: suncons.c,v 1.50 1997/02/26 08:55:22 ecd Exp $ * * suncons.c: Sun SparcStation console support. * @@ -166,39 +166,52 @@ #define COLOR_FBUF_OFFSET(cindex) (*color_fbuf_offset)(cindex) -/* These four routines are optimizations for the _generic routine for the most common cases. - I guess doing twice sll is much faster than doing .mul, sra faster than doing .div, - and the disadvantage that someone has to call it (it cannot be inline) runs away, 'cause - otherwise it would have to call .mul anyway. - The shifting + addition only routines won't eat any stack frame :)) - Names come from width, screen_num_columns */ +/* These four routines are optimizations for the _generic routine for + * the most common cases. + * I guess doing twice sll is much faster than doing .mul, sra faster + * than doing .div, and the disadvantage that someone has to call it + * (it cannot be inline) runs away, 'cause otherwise it would have to + * call .mul anyway. + * The shifting + addition only routines won't eat any stack frame :)) + * Names come from width, screen_num_columns. + */ static int -color_fbuf_offset_1152_128 (int cindex) +color_fbuf_offset_1280_144 (int cindex) { - register int i = (cindex>>7); - /* (1152 * CHAR_HEIGHT) == 10010000000.0000 */ - return skip_bytes + (i << 14) + (i << 11) + ((cindex & 127) << 3); + register int i = (cindex/144); + /* (1280 * CHAR_HEIGHT) == 101.0000.0000.0000 */ + return skip_bytes + (i << 14) + (i << 12) + ((cindex % 144) << 3); } static int -color_fbuf_offset_1280_144 (int cindex) +color_fbuf_offset_1152_128 (int cindex) { - register int i = (cindex/144); - /* (1280 * CHAR_HEIGHT) == 10100000000.0000 */ - return skip_bytes + (i << 14) + (i << 12) + ((cindex % 144) << 3); + register int i = (cindex>>7); + /* (1152 * CHAR_HEIGHT) == 100.1000.0000.0000 */ + return skip_bytes + (i << 14) + (i << 11) + ((cindex & 127) << 3); } - + static int color_fbuf_offset_1024_128 (int cindex) { register int i = (cindex>>7); + /* (1024 * CHAR_HEIGHT) == 100.0000.0000.0000 */ return skip_bytes + (i << 14) + ((cindex & 127) << 3); } - + +static int +color_fbuf_offset_800_96 (int cindex) +{ + register int i = (cindex / 96); + /* (800 * CHAR_HEIGHT) == 11.0010.0000.0000 */ + return skip_bytes + (i<<13) + (i<<12) + (i<<9) + ((cindex % 96)<<3); +} + static int color_fbuf_offset_640_80 (int cindex) { register int i = (cindex/80); + /* (640 * CHAR_HEIGHT) == 10.1000.0000.0000 */ return skip_bytes + (i << 13) + (i << 11) + ((cindex % 80) << 3); } @@ -345,10 +358,10 @@ under_cursor[1] = dst[1]; under_cursor[2] = dst[ints_per_line]; under_cursor[3] = dst[ints_per_line+1]; - dst[0] = 0x0f0f0f0f; - dst[1] = 0x0f0f0f0f; - dst[ints_per_line] = 0x0f0f0f0f; - dst[ints_per_line+1] = 0x0f0f0f0f; + dst[0] = 0x00000000; + dst[1] = 0x00000000; + dst[ints_per_line] = 0x00000000; + dst[ints_per_line+1] = 0x00000000; break; } default: @@ -399,7 +412,7 @@ rects [1] = 0; rects [2] = con_width; rects [3] = con_height; - (*fbinfo[0].fill)(0, 1, rects); + (*fbinfo[0].fill)(reverse_color_table[0], 1, rects); return; /* Dunno how to display logo on leo/zx yet */ } if (con_depth == 8 && fbinfo[0].loadcmap) { @@ -411,7 +424,7 @@ (*fbinfo [0].loadcmap)(&fbinfo [0], 0, LINUX_LOGO_COLORS + 32); for (i = 0; i < 80; i++, p += chars_per_line){ for (cpu = 0; cpu < linux_num_cpus; cpu++){ - memcpy (p + (cpu * 84), linux_logo + 80 * i, 80); + memcpy (p + (cpu * 88), linux_logo + 80 * i, 80); } } } else if (con_depth == 1) { @@ -419,7 +432,7 @@ memcpy (p, linux_logo_bw + 10 * i, 10); } putconsxy(0, q); - ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20 + 80 * (linux_num_cpus - 1); + ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20 + 11 * (linux_num_cpus - 1); for (p = "Linux/SPARC version " UTS_RELEASE; *p; p++, ush++) { *ush = (attr << 8) + *p; @@ -584,9 +597,10 @@ rects [1] = 0; rects [2] = con_width; rects [3] = con_height; - (*fbinfo[0].fill)(0, 1, rects); + (*fbinfo[0].fill)(reverse_color_table[0], 1, rects); } else if (fbinfo[0].base && fbinfo[0].base_depth) - memset (con_fb_base, (con_depth == 1) ? ~(0) : 0, + memset (con_fb_base, + (con_depth == 1) ? ~(0) : reverse_color_table[0], (con_depth * con_height * con_width) / 8); /* also clear out the "shadow" screen memory */ memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base)); @@ -608,12 +622,13 @@ rects [1] = 0; rects [2] = fbinfo[n].type.fb_width; rects [3] = fbinfo[n].type.fb_height; - (*fbinfo[n].fill)(0, 1, rects); + (*fbinfo[n].fill)(reverse_color_table[0], 1, rects); } #endif else if (fbinfo[n].base && fbinfo[n].base_depth) { memset((void *)fbinfo[n].base, - (fbinfo[n].base_depth == 1) ? ~(0) : 0, + (fbinfo[n].base_depth == 1) ? + ~(0) : reverse_color_table[0], (fbinfo[n].base_depth * fbinfo[n].type.fb_height * fbinfo[n].type.fb_width) / 8); } @@ -642,14 +657,14 @@ rects [13] = con_height - y_margin; rects [14] = con_width - x_margin; rects [15] = con_height; - (*fbinfo[0].fill)(0, 4, rects); + (*fbinfo[0].fill)(reverse_color_table[0], 4, rects); } else { memset (con_fb_base, - (con_depth == 1) ? ~(0) : 0, + (con_depth == 1) ? ~(0) : reverse_color_table[0], skip_bytes - (x_margin<<1)); memset (con_fb_base + chars_per_line * con_height - skip_bytes + (x_margin<<1), - (con_depth == 1) ? ~(0) : 0, + (con_depth == 1) ? ~(0) : reverse_color_table[0], skip_bytes - (x_margin<<1)); he = con_height - 2 * y_margin; i = 2 * x_margin; @@ -660,7 +675,7 @@ } else { for (p = con_fb_base+skip_bytes-(x_margin<<1), h = 0; h <= he; p += chars_per_line, h++) - memset (p, 0, i); + memset (p, reverse_color_table[0], i); } } if (fbinfo [0].switch_from_graph) @@ -687,6 +702,18 @@ { } +/* + * We permutate the colors, so we match the PROM's idea of + * black and white. + */ +unsigned char reverse_color_table[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 +}; + +static unsigned char sparc_color_table[] = { + 15, 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11 +}; + /* Call the frame buffer routine for setting the palette */ void set_palette (void) @@ -699,7 +726,7 @@ /* First keep color_map with the palette colors */ for (i = 0; i < 16; i++){ - j = color_table [i]; + j = sparc_color_table [i]; fbinfo[0].color_map CM(i,0) = default_red [j]; fbinfo[0].color_map CM(i,1) = default_grn [j]; fbinfo[0].color_map CM(i,2) = default_blu [j]; @@ -778,7 +805,8 @@ } static char *known_cards [] __initdata = { - "cgsix", "cgthree", "cgRDI", "cgthree+", "bwtwo", "SUNW,tcx", "cgfourteen", "SUNW,leo", 0 + "cgsix", "cgthree", "cgRDI", "cgthree+", "bwtwo", "SUNW,tcx", + "cgfourteen", "SUNW,leo", 0 }; static char *v0_known_cards [] __initdata = { "cgsix", "cgthree", "cgRDI", "cgthree+", "bwtwo", 0 @@ -799,12 +827,13 @@ int resx, resy; int x_margin, y_margin; } scr_def [] = { - { 1, 1152, 900, 8, 18 }, - { 8, 1152, 900, 64, 18 }, - { 8, 1152, 1024, 64, 80 }, { 8, 1280, 1024, 64, 80 }, + { 8, 1152, 1024, 64, 80 }, + { 8, 1152, 900, 64, 18 }, { 8, 1024, 768, 0, 0 }, + { 8, 800, 600, 16, 12 }, { 8, 640, 480, 0, 0 }, + { 1, 1152, 900, 8, 18 }, { 0 }, }; @@ -823,8 +852,10 @@ } __initfunc(static void -sparc_framebuffer_setup(int primary, int con_node, int type, struct linux_sbus_device *sbdp, - uint base, uint con_base, int prom_fb, int parent_node)) + sparc_framebuffer_setup(int primary, int con_node, + int type, struct linux_sbus_device *sbdp, + uint base, uint con_base, int prom_fb, + int parent_node)) { static int frame_buffers = 1; int n, i; @@ -835,7 +866,8 @@ if (primary) n = 0; else { - if (frame_buffers == FRAME_BUFFERS) return; /* Silently ignore */ + if (frame_buffers == FRAME_BUFFERS) + return; /* Silently ignore */ n = frame_buffers++; } @@ -934,21 +966,26 @@ 2 * x_margin / con_depth; ORIG_VIDEO_LINES = (con_height - 2 * y_margin) / 16; switch (chars_per_line) { - case 1152: - if (ORIG_VIDEO_COLS == 128) - color_fbuf_offset = - color_fbuf_offset_1152_128; - break; case 1280: if (ORIG_VIDEO_COLS == 144) color_fbuf_offset = color_fbuf_offset_1280_144; break; + case 1152: + if (ORIG_VIDEO_COLS == 128) + color_fbuf_offset = + color_fbuf_offset_1152_128; + break; case 1024: if (ORIG_VIDEO_COLS == 128) color_fbuf_offset = color_fbuf_offset_1024_128; break; + case 800: + if (ORIG_VIDEO_COLS == 96) + color_fbuf_offset = + color_fbuf_offset_800_96; + break; case 640: if (ORIG_VIDEO_COLS == 80) color_fbuf_offset = @@ -960,7 +997,8 @@ if (!scr_def [i].depth){ x_margin = y_margin = 0; - prom_printf ("console: unknown video resolution %dx%d, depth %d\n", + prom_printf ("console: unknown video resolution %dx%d," + " depth %d\n", con_width, con_height, con_depth); prom_halt (); } @@ -1082,7 +1120,8 @@ for_all_sbusdev(sbdp, sbus) { if (!known_card (sbdp->prom_name, known_cards)) continue; con_node = sbdp->prom_node; - prom_apply_sbus_ranges (sbdp->my_bus, &sbdp->reg_addrs [0], sbdp->num_registers); + prom_apply_sbus_ranges (sbdp->my_bus, &sbdp->reg_addrs [0], + sbdp->num_registers, sbdp); propl = prom_getproperty(con_node, "address", (char *) &con_base, 4); if (propl != 4) con_base = 0; @@ -1222,6 +1261,7 @@ sun_blitc(uint charattr, unsigned long addr) { unsigned int fgmask, bgmask; + unsigned char attrib; int j, idx; unsigned char *font_row; @@ -1235,6 +1275,7 @@ /* Invalidate the cursor position if necessary. */ idx = (addr - video_mem_base) >> 1; + attrib = CHARATTR_TO_SUNCOLOR(charattr); font_row = &vga_font[(j = (charattr & 0xff)) << 4]; switch (con_depth){ @@ -1281,7 +1322,7 @@ "\n\t std %0, [%1]" \ "\n\t std %0, [%1 + %2]" - x1 = (charattr >> 12) & 0x0f; + x1 = attrib >> 4; x1 |= x1 << 8; x1 |= x1 << 16; x3 = cpl << 1; @@ -1303,7 +1344,7 @@ __asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (under_cursor), "i" (8)); restore_flags (flags); #else - bgmask = (charattr >> 12) & 0x0f; + bgmask = attrib >> 4; bgmask |= bgmask << 8; bgmask |= bgmask << 16; @@ -1328,8 +1369,8 @@ restore_flags(flags); #endif } else /* non-space */ { - fgmask = (charattr >> 8) & 0x0f; - bgmask = (charattr >> 12) & 0x0f; + fgmask = attrib & 0x0f; + bgmask = attrib >> 4; fgmask |= fgmask << 8; fgmask |= fgmask << 16; bgmask |= bgmask << 8; diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.1.28/linux/drivers/sbus/char/sunmouse.c Sun Jan 26 02:07:18 1997 +++ linux/drivers/sbus/char/sunmouse.c Wed Mar 5 17:04:32 1997 @@ -134,6 +134,56 @@ wake_up_interruptible (&sunmouse.proc_list); } +/* Auto baud rate "detection". ;-) */ +static int mouse_bogon_bytes = 0; +static int mouse_baud_changing = 0; /* For reporting things to the user. */ +static int mouse_baud = 4800; /* Initial rate set by zilog driver. */ + +/* Change the baud rate after receiving too many "bogon bytes". */ +void sun_mouse_change_baud(void) +{ + extern void zs_change_mouse_baud(int newbaud); + + if(mouse_baud == 1200) + mouse_baud = 4800; + else + mouse_baud = 1200; + + zs_change_mouse_baud(mouse_baud); + mouse_baud_changing = 1; +} + +void mouse_baud_detection(unsigned char c) +{ + static int wait_for_synchron = 1; + static int ctr = 0; + + if(wait_for_synchron) { + if((c < 0x80) || (c > 0x87)) + mouse_bogon_bytes++; + else { + ctr = 0; + wait_for_synchron = 0; + } + } else { + ctr++; + if(ctr >= 4) { + ctr = 0; + wait_for_synchron = 1; + if(mouse_baud_changing == 1) { + printk("sunmouse: Successfully adjusted to %d baud.\n", + mouse_baud); + mouse_baud_changing = 0; + } + } + } + if(mouse_bogon_bytes > 12) { + sun_mouse_change_baud(); + mouse_bogon_bytes = 0; + wait_for_synchron = 1; + } +} + /* The following is called from the zs driver when bytes are received on * the Mouse zs8530 channel. */ @@ -148,6 +198,8 @@ if(!sunmouse.active) return; + mouse_baud_detection(byte); + if (!gen_events){ push_char (byte); return; @@ -419,6 +471,7 @@ sunmouse.delta_x = sunmouse.delta_y = 0; sunmouse.button_state = 0x80; sunmouse.proc_list = NULL; + sunmouse.byte = 69; return 0; } diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.1.28/linux/drivers/sbus/char/sunserial.c Wed Jan 1 06:24:40 1997 +++ linux/drivers/sbus/char/sunserial.c Wed Mar 5 17:04:32 1997 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.25 1996/12/30 07:50:26 davem Exp $ +/* $Id: sunserial.c,v 1.27 1997/03/04 19:33:55 davem Exp $ * serial.c: Serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1736,7 +1736,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.25 $"; + char *revision = "$Revision: 1.27 $"; char *version, *p; version = strchr(revision, ' '); @@ -2091,6 +2091,19 @@ extern void keyboard_zsinit(void); extern void sun_mouse_zsinit(void); +/* This is for the auto baud rate detection in the mouse driver. */ +void zs_change_mouse_baud(int newbaud) +{ + int channel = MOUSE_LINE; + int brg; + + zs_soft[channel].zs_baud = newbaud; + brg = BPS_TO_BRG(zs_soft[channel].zs_baud, + (ZS_CLOCK / zs_soft[channel].clk_divisor)); + write_zsreg(zs_soft[channel].zs_channel, R12, (brg & 0xff)); + write_zsreg(zs_soft[channel].zs_channel, R13, ((brg >> 8) & 0xff)); +} + __initfunc(unsigned long sun_serial_setup (unsigned long memory_start)) { char *p; @@ -2152,6 +2165,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "serial"; serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; @@ -2183,6 +2197,10 @@ serial_driver.start = rs_start; serial_driver.hangup = rs_hangup; + /* I'm too lazy, someone write versions of this for us. -DaveM */ + serial_driver.read_proc = 0; + serial_driver.proc_entry = 0; + init_zscons_termios(&serial_driver.init_termios); /* @@ -2308,7 +2326,7 @@ write_zsreg(zs_soft[channel].zs_channel, R11, (TCBR | RCBR)); - zs_soft[channel].zs_baud = 1200; + zs_soft[channel].zs_baud = 4800; brg = BPS_TO_BRG(zs_soft[channel].zs_baud, ZS_CLOCK/zs_soft[channel].clk_divisor); write_zsreg(zs_soft[channel].zs_channel, R12, diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/dvma.c linux/drivers/sbus/dvma.c --- v2.1.28/linux/drivers/sbus/dvma.c Fri Dec 13 01:37:37 1996 +++ linux/drivers/sbus/dvma.c Wed Mar 5 17:04:32 1997 @@ -76,9 +76,11 @@ * routine only alloc 1 page, that was what the original code did */ if(hme) /* On HME cards, dvma lives with esp, 2 reg sets. */ - prom_apply_sbus_ranges(sbus, dma->SBus_dev->reg_addrs, 0x2); + prom_apply_sbus_ranges(sbus, dma->SBus_dev->reg_addrs, + 0x2, dma->SBus_dev); else /* All others have only 1 reg set. */ - prom_apply_sbus_ranges(sbus, dma->SBus_dev->reg_addrs, 0x1); + prom_apply_sbus_ranges(sbus, dma->SBus_dev->reg_addrs, + 0x1, dma->SBus_dev); dma->regs = (struct sparc_dma_registers *) sparc_alloc_io (dma->SBus_dev->reg_addrs[0].phys_addr, 0, PAGE_SIZE, "dma", diff -u --recursive --new-file v2.1.28/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c --- v2.1.28/linux/drivers/sbus/sbus.c Fri Dec 13 01:37:37 1996 +++ linux/drivers/sbus/sbus.c Wed Mar 5 17:04:32 1997 @@ -12,6 +12,7 @@ #include #include #include +#include /* This file has been written to be more dynamic and a bit cleaner, * but it still needs some spring cleaning. @@ -59,6 +60,7 @@ panic("fill_sbus_device"); } sbus_dev->num_registers = (len/sizeof(struct linux_prom_registers)); + sbus_dev->ranges_applied = 0; base = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; if(base>=SUN_SBUS_BVADDR || sparc_cpu_model == sun4m) { @@ -147,6 +149,9 @@ #ifdef CONFIG_SUN_MOSTEK_RTC extern int rtc_init(void); #endif +#ifdef CONFIG_SPARCAUDIO +extern int sparcaudio_init(void); +#endif __initfunc(static unsigned long sbus_do_child_siblings(unsigned long memory_start, int start_node, @@ -157,6 +162,7 @@ int this_node = start_node; /* Child already filled in, just need to traverse siblings. */ + child->child = 0; while((this_node = prom_getsibling(this_node)) != 0) { this_dev->next = (struct linux_sbus_device *) memory_start; memory_start += sizeof(struct linux_sbus_device); @@ -332,6 +338,12 @@ #endif #ifdef CONFIG_SUN_MOSTEK_RTC rtc_init(); +#endif +#ifdef CONFIG_SPARCAUDIO + sparcaudio_init(); +#endif +#ifdef CONFIG_SUN_BPP + bpp_init(); #endif return memory_start; } diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.1.28/linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Jan 13 22:21:41 1997 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Tue Mar 4 13:22:49 1997 @@ -1,3 +1,58 @@ +Thu Feb 27 23:00 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c ncr53c8xx.h revision 1.18b + - 'On paper' support of the NCR53C895 Ultra-2 chip. + (Clock quadrupler + 7 clock divisors) + - Load the main part of the script into the on-board RAM. + - 810A rev. 0x11 PCI problem fixed. + This chip is now supported with all PCI features enabled and + 16 dwords burst transfers. + - Align on 32 boundary some internal structures. + That fixes the 810A problem and allows cache line bursting when + moving the global header (64 bytes) from/to CCBs to/from NCB. + - Synchronous parameters calculation rewritten. The driver + now uses all available clock divisors and will be able to support + clock frequencies that are not multiple of 40 Mhz if necessary. + +Sat Feb 8 22:00 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - revision 1.17a + - IRQ mode set up from boot setup command. + irqm:0 open drain (default) + irqm:1 preserve initial setting (assumed from BIOS) + irqm:2 totem pole + - DIFF mode set up from boot setup command. + Suggested by Richard Waltham. + diff:0 never set up diff mode (default) + diff:1 set up diff mode according to initial setting (BIOS?) + diff:2 always set up diff mode + diff:3 set up diff mode if GPIO3 is zero (SYMBIOS boards) + - Change CONFIG option for LED support. + CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT allows LED support and + DIFF support for SYMBIOS boards and compatibles (clones?). + - Set 16 DWORD bursts for 810A rev. >= 0x12 since my SC200 with + such a chip have no problem with it (MB with Triton 2 HX). + 810A rev. 0x11 are set to 8 DWORD bursts since they may give + problems with PCI read multiple and Triton 2 HX. + Thanks to Stefan for this information. + +Sat Jan 25 22:00 1997 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c - revision 1.17 + - Controller LED support. + Only works with LED pin wired to GPIO_FETCHN, so probably with + all boards using SMDS BIOS. + This option can be enabled only if CONFIG_EXPERIMENTAL is set. + - Assume clock doubler for 875 chip when clock frequency measurement + result is 40 MHz. May help when some old stuff as SDMS BIOS 3.0 + or some old driver has broken the normal BIOS settings. + - Add wide negotiation control from boot setup command. + May be usefull with systems using a 875 based board connected to + a wide device through a 50 pins to 68 pins converter. + - Add a "boot fail safe option" to the boot setup command line. + - Rewrite the "reset_command" routine. + Low-level driver are responsible to keep the involved command + alive. The new code seems to behave correctly. + - Change some variables used by the script from u_long to u_int32. + - Remove some useless code. + Sun Jan 12 12:00 1997 Gerard Roudier (groudier@club-internet.fr) * ncr53c8xx.c - revision 1.16e - Add support of PCI burst length control from boot setup command. diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.28/linux/drivers/scsi/Config.in Tue Mar 4 10:25:24 1997 +++ linux/drivers/scsi/Config.in Tue Mar 4 13:22:49 1997 @@ -65,6 +65,9 @@ if [ "$CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE" != "y" ]; then bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' assume boards are SYMBIOS compatible' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + fi fi fi if [ "$CONFIG_MCA" = "y" ]; then diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.1.28/linux/drivers/scsi/Makefile Tue Mar 4 10:25:24 1997 +++ linux/drivers/scsi/Makefile Thu Mar 6 10:23:04 1997 @@ -266,10 +266,8 @@ ifeq ($(CONFIG_SCSI_GENERIC_NCR5380),y) L_OBJS += g_NCR5380.o -EXTRA_CFLAGS = -DGENERIC_NCR5380_OVERRIDE="{{(NCR5380_map_type)0x350,5,0, BOARD_NCR53C400}};" else ifeq ($(CONFIG_SCSI_GENERIC_NCR5380),m) - EXTRA_CFLAGS = -DGENERIC_NCR5380_OVERRIDE="{{(NCR5380_map_type)0x350,5,0, BOARD_NCR53C400}};" M_OBJS += g_NCR5380.o endif endif diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.1.28/linux/drivers/scsi/README.ncr53c8xx Mon Jan 13 22:21:41 1997 +++ linux/drivers/scsi/README.ncr53c8xx Tue Mar 4 13:22:49 1997 @@ -4,7 +4,7 @@ 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -12 January 1997 +27 February 1997 =============================================================================== 1. Introduction @@ -91,12 +91,11 @@ 815 Y N N Y Y 825 Y Y N Y Y 825A Y Y N Y Y -860 N N Y(1) Y Y -875 Y Y Y(1) Y Y +860 N N Y Y Y +875 Y Y Y Y Y +895 Y Y Y(1) Y not yet -(1) Ultra (fast20 / fast40) SCSI data transfers are "in theory" supported - by the driver, but not fully tested, since the maintainer does not have - for the moment Ultra SCSI hard disks. +(1) The 895 chip is supported 'on paper'. 3. Summary of other supported features. @@ -212,6 +211,7 @@ 860 0x6 825A 0x3 >= 0x10 875 0xf +895 0xc The profiling information is updated upon completion of SCSI commands. A data structure is allocated and zeroed when the host adapter is @@ -287,16 +287,21 @@ Available commands: -8.1 Set minimum synchronous period +8.1 Set minimum synchronous period factor - setsync + setsync target: target number - period: minimum synchronous period in nano-seconds. - Maximum speed = 1000/(4*period) MB/second + period: minimum synchronous period. + Maximum speed = 1000/(4*period factor) except for special + cases below. Specify a period of 255, to force asynchronous transfer mode. + 10 means 25 nano-seconds synchronous period + 11 means 30 nano-seconds synchronous period + 12 means 50 nano-seconds synchronous period + 8.2 Set wide size setwide @@ -403,6 +408,18 @@ you can answer "y". Then, all SCSI devices will never disconnect the bus even while performing long SCSI operations. +CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + Genuine SYMBIOS boards use GPIO0 in output for controller LED and GPIO3 + bit as a flag indicating singled-ended/differential interface. + If all the boards of your system are genuine SYMBIOS boards or use + BIOS and drivers from SYMBIOS, you would want to enable this option. + This option must NOT be enabled if your system has at least one 53C8XX + based scsi board with a vendor-specific BIOS. + For example, Tekram DC-390/U, DC-390/W and DC-390/F scsi controllers + use a vendor-specific BIOS and are known to not use SYMBIOS compatible + GPIO wiring. So, this option must not be enabled if your system has + such a board installed. + 10. Boot setup commands @@ -459,11 +476,14 @@ If the driver is configured with a maximum of 4 queued commands, tags:4 is the right argument to specify. -Default synchronous negotiation frequency - sync:0 disabled (asynchronous transfer mode) - sync:#MHz enabled up to #MHz. - #MHz > 10 Ultra SCSI - #MHz > 5 Fast SCSI +Default synchronous period factor + sync:255 disabled (asynchronous transfer mode) + sync:#factor + #factor = 10 Ultra-2 SCSI 40 Mega-transfers / second + #factor = 11 Ultra-2 SCSI 33 Mega-transfers / second + #factor < 25 Ultra SCSI 20 Mega-transfers / second + #factor < 50 Fast SCSI-2 + In all cases, the driver will use the minimum transfer period supported by controllers according to NCR53C8XX chip type. @@ -478,7 +498,7 @@ verb:2 too much Debug mode - debug:0 clear debug flags + debug:0 clear debug flags debug:#x set debug flags #x is an integer value combining the following power-of-2 values: DEBUG_ALLOC 0x1 @@ -509,18 +529,71 @@ and revision ids. By default the driver uses the maximum value supported by the chip. +LED support + led:1 enable LED support + led:0 disable LED support + Donnot enable LED support if your scsi board does not use SDMS BIOS. + (See 'Configuration parameters') + +Max wide + wide:1 wide scsi enabled + wide:0 wide scsi disabled + Some scsi boards use a 875 (ultra wide) and only supply narrow connectors. + If you have connected a wide device with a 50 pins to 68 pins cable + converter, any accepted wide negotiation will break further data transfers. + In such a case, using "wide:0" in the bootup command will be helpfull. + +Differential mode + diff:0 never set up diff mode + diff:1 set up diff mode if BIOS set it + diff:2 always set up diff mode + diff:3 set diff mode if GPIO3 is not set + +IRQ mode + irqm:0 always open drain + irqm:1 same as initial settings (assumed BIOS settings) + irqm:2 always totem pole + +Boot fail safe + safe:y load the following assumed fail safe initial setup + + master parity disabled mpar:n + scsi parity enabled spar:y + disconnections not allowed disc:n + special features disabled specf:n + ultra scsi disabled ultra:n + force sync negotiation disabled fsn:n + verbosity level 2 verb:2 + tagged command queuing disabled tags:0 + synchronous negotiation disabled sync:255 + debug flags none debug:0 + burst length from BIOS settings burst:255 + LED support disabled led:0 + wide support disabled wide:0 + settle time 10 seconds settle:10 + differential support from BIOS settings diff:1 + irq mode from BIOS settings irqm:1 10.3 Advised boot setup commands If the driver has been configured with default options, the equivalent boot setup is: - ncr53c8xx=mpar:y,spar:y,disc:y,fsn:n,specf:y,ultra:y,sync:5,tags:0,verb:1 -For an installation diskette or a safe but not fast system, boot setup is: - ncr53c8xx=mpar:y,spar:y,disc:n,fsn:n,specf:n,ultra:n,sync:0,tags:0 + ncr53c8xx=mpar:y,spar:y,disc:y,specf:y,fsn:n,ultra:y,fsn:n,verb:2,tags:0\ + sync:50,debug:0,burst:7,led:0,wide:1,settle:2,diff:0,irqm:0 + +For an installation diskette or a safe but not fast system, +boot setup can be: -My personnal system works flawlessly with the following setup: - ncr53c8xx=mpar:y,spar:y,disc:y,fsn:n,specf:y,ultra:y,sync:20,tags:8 + ncr53c8xx=safe:y,mpar:y,disc:y + ncr53c8xx=safe:y,disc:y + ncr53c8xx=safe:y,mpar:y + ncr53c8xx=safe:y + +My personnal system works flawlessly with the following equivalent setup: + + ncr53c8xx=mpar:y,spar:y,disc:y,specf:y,fsn:n,ultra:y,fsn:n,verb:1,tags:8\ + sync:12,debug:0,burst:7,led:1,wide:1,settle:2,diff:0,irqm:0 The driver prints its actual setup when verbosity level is 2. You can try "ncr53c8xx=verb:2" to get the "static" setup of the driver, or add "verb:2" @@ -560,10 +633,10 @@ Maximum number of simultaneous tagged commands to a device. Can be changed by "settags " -SCSI_NCR_SETUP_DEFAULT_SYNC (default: 5) - Frequency in KHz the driver will use at boot time for synchronous +SCSI_NCR_SETUP_DEFAULT_SYNC (default: 50) + Transfer period factor the driver will use at boot time for synchronous negotiation. 0 means asynchronous. - Can be changed by "setsync " + Can be changed by "setsync " SCSI_NCR_SETUP_DEFAULT_TAGS (default: 4) Default number of simultaneous tagged commands to a device. @@ -635,18 +708,18 @@ Install.ncr53c8xx : installation script Patch-1.2.13.ncr53c8xx : patch for linux-1.2.13 - Patch-2.0.27.ncr53c8xx : patch for linux-2.0.27 + Patch-2.0.29.ncr53c8xx : patch for linux-2.0.29 + +You must untar the distribution with the following command: -Prior to installing the driver, you must untar the distribution, as follow: + tar zxvf ncrBsd2Linux-1.18b-src.tar.gz - mkdir ncrB2L - cd ncrB2L - tar zxvf ncrBsd2Linux-1.16b-src.tar.gz +The sub-directory ncr53c8xx-1.18b will be created. Change to this directory. 12.2 Installation procedure -This install script has been tested with linux-1.2.13 and 2.0.27. +This install script has been tested with linux-1.2.13 and 2.0.29. This procedure copies the new driver files to the kernel tree and applies a patch to some files of the kernel tree. diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/dtc.c linux/drivers/scsi/dtc.c --- v2.1.28/linux/drivers/scsi/dtc.c Wed Nov 6 02:21:09 1996 +++ linux/drivers/scsi/dtc.c Thu Mar 6 10:23:04 1997 @@ -87,6 +87,53 @@ #include #include + +#define DTC_PUBLIC_RELEASE 2 + +/*#define DTCDEBUG 0x1*/ +#define DTCDEBUG_INIT 0x1 +#define DTCDEBUG_TRANSFER 0x2 + +/* + * The DTC3180 & 3280 boards are memory mapped. + * + */ + +/* + */ +/* Offset from DTC_5380_OFFSET */ +#define DTC_CONTROL_REG 0x100 /* rw */ +#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ +#define CSR_DIR_READ 0x40 /* rw direction, 1 = read 0 = write */ + +#define CSR_RESET 0x80 /* wo Resets 53c400 */ +#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ +#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ +#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ +#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ +#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ +#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ +#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ +#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ +#define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR) + + +#define DTC_BLK_CNT 0x101 /* rw + * # of 128-byte blocks to transfer */ + + +#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ + +#define DTC_SWITCH_REG 0x3982 /* ro - DIP switches */ +#define DTC_RESUME_XFER 0x3982 /* wo - resume data xfer + * after disconnect/reconnect*/ + +#define DTC_5380_OFFSET 0x3880 /* 8 registers here, see NCR5380.h */ + +/*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */ +#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ + + struct proc_dir_entry proc_scsi_dtc = { PROC_SCSI_T128, 7, "dtc3x80", S_IFDIR | S_IRUGO | S_IXUGO, 2 @@ -178,7 +225,7 @@ else for (; !base && (current_base < NO_BASES); ++current_base) { #if (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi : probing address %08x\n", bases[current_base].address); + printk("scsi-dtc : probing address %08x\n", bases[current_base].address); #endif for (sig = 0; sig < NO_SIGNATURES; ++sig) if (!bases[current_base].noauto && diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/dtc.h linux/drivers/scsi/dtc.h --- v2.1.28/linux/drivers/scsi/dtc.h Wed Nov 6 02:21:09 1996 +++ linux/drivers/scsi/dtc.h Thu Mar 6 10:23:04 1997 @@ -28,52 +28,6 @@ #ifndef DTC3280_H #define DTC3280_H -#define DTC_PUBLIC_RELEASE 2 - -/*#define DTCDEBUG 0x1*/ -#define DTCDEBUG_INIT 0x1 -#define DTCDEBUG_TRANSFER 0x2 - -/* - * The DTC3180 & 3280 boards are memory mapped. - * - */ - -/* - */ -/* Offset from DTC_5380_OFFSET */ -#define DTC_CONTROL_REG 0x100 /* rw */ -#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ -#define CSR_DIR_READ 0x40 /* rw direction, 1 = read 0 = write */ - -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ -#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ -#define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR) - - -#define DTC_BLK_CNT 0x101 /* rw - * # of 128-byte blocks to transfer */ - - -#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ - -#define DTC_SWITCH_REG 0x3982 /* ro - DIP switches */ -#define DTC_RESUME_XFER 0x3982 /* wo - resume data xfer - * after disconnect/reconnect*/ - -#define DTC_5380_OFFSET 0x3880 /* 8 registers here, see NCR5380.h */ - -/*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */ -#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ - - #ifndef ASM int dtc_abort(Scsi_Cmnd *); int dtc_biosparam(Disk *, kdev_t, int*); diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v2.1.28/linux/drivers/scsi/esp.c Fri Dec 13 01:37:37 1996 +++ linux/drivers/scsi/esp.c Wed Mar 5 17:04:33 1997 @@ -750,7 +750,8 @@ /* Map in the ESP registers from I/O space */ if(!hme) { prom_apply_sbus_ranges(esp->edev->my_bus, - esp->edev->reg_addrs, 1); + esp->edev->reg_addrs, + 1, esp->edev); esp->eregs = eregs = (struct Sparc_ESP_regs *) sparc_alloc_io(esp->edev->reg_addrs[0].phys_addr, 0, diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.1.28/linux/drivers/scsi/ncr53c8xx.c Mon Jan 13 22:21:41 1997 +++ linux/drivers/scsi/ncr53c8xx.c Tue Mar 4 13:22:49 1997 @@ -40,7 +40,7 @@ */ /* -** 12 January 1997, version 1.16e +** 27 February 1997, version 1.18b ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -57,6 +57,7 @@ ** 53C825 (Wide, ~53C820 with on board rom BIOS) ** 53C860 (Narrow fast 20, BIOS required) ** 53C875 (Wide fast 40 with on board rom BIOS) +** 53C895 (Ultra2 80 MB/s with on board rom BIOS) ** ** Other features: ** Memory mapped IO (linux-1.3.X and above only) @@ -151,24 +152,6 @@ #endif /* -** The maximal synchronous frequency in kHz. -** (0=asynchronous) -*/ - -#ifndef SCSI_NCR_MAX_SYNC -#define SCSI_NCR_MAX_SYNC (10000) -#endif - -/* -** The maximal bus with (in log2 byte) -** (0=8 bit, 1=16 bit) -*/ - -#ifndef SCSI_NCR_MAX_WIDE -#define SCSI_NCR_MAX_WIDE (1) -#endif - -/* ** The maximum number of tags per logic unit. ** Used only for disk devices that support tags. */ @@ -352,18 +335,66 @@ ** I notice that kmalloc() returns NULL during host attach under ** Linux 1.2.13. But this ncr driver is reliable enough to ** accomodate with this joke. -**/ +** +** kmalloc() only ensure 8 bytes boundary alignment. +** The NCR need better alignment for cache line bursting. +** The global header is moved betewen the NCB and CCBs and need +** origin and destination addresses to have same lower four bits. +** +** We use 32 boundary alignment for NCB and CCBs and offset multiple +** of 32 for global header fields. That's too much but at least enough. +*/ + +#define ALIGN_SIZE(shift) (1UL << shift) +#define ALIGN_MASK(shift) (~(ALIGN_SIZE(shift)-1)) + +#define NCB_ALIGN_SHIFT 5 +#define CCB_ALIGN_SHIFT 5 +#define LCB_ALIGN_SHIFT 5 +#define SCR_ALIGN_SHIFT 5 + +#define NCB_ALIGN_SIZE ALIGN_SIZE(NCB_ALIGN_SHIFT) +#define NCB_ALIGN_MASK ALIGN_MASK(NCB_ALIGN_SHIFT) +#define CCB_ALIGN_SIZE ALIGN_SIZE(CCB_ALIGN_SHIFT) +#define CCB_ALIGN_MASK ALIGN_MASK(CCB_ALIGN_SHIFT) +#define SCR_ALIGN_SIZE ALIGN_SIZE(SCR_ALIGN_SHIFT) +#define SCR_ALIGN_MASK ALIGN_MASK(SCR_ALIGN_SHIFT) + +static void *m_alloc(int size, int a_shift) +{ + u_long addr; + void *ptr; + u_long a_size, a_mask; + + if (a_shift < 3) + a_shift = 3; + + a_size = ALIGN_SIZE(a_shift); + a_mask = ALIGN_MASK(a_shift); + + ptr = (void *) kmalloc(size + a_size, GFP_ATOMIC); + if (ptr) { + addr = (((u_long) ptr) + a_size) & a_mask; + *((void **) (addr - sizeof(void *))) = ptr; + ptr = (void *) addr; + } -static void *m_alloc(int size) -{ - void *ptr = (void *) kmalloc(size, GFP_ATOMIC); - if (((unsigned long) ptr) & 3) - panic("ncr53c8xx: kmalloc returns misaligned address %lx\n", (unsigned long) ptr); return ptr; } -static inline void m_free(void *ptr, int size) - { kfree(ptr); } +#ifdef MODULE +static void m_free(void *ptr, int size) +{ + u_long addr; + + if (ptr) { + addr = (u_long) ptr; + ptr = *((void **) (addr - sizeof(void *))); + + kfree(ptr); + } +} +#endif /* ** Transfer direction @@ -431,19 +462,27 @@ ** This structure is initialized from linux config options. ** It can be overridden at boot-up by the boot command line. */ -static struct { +struct ncr_driver_setup { unsigned master_parity : 1; unsigned scsi_parity : 1; unsigned disconnection : 1; unsigned special_features : 1; - unsigned ultra_scsi : 1; + unsigned ultra_scsi : 2; unsigned force_sync_nego: 1; - unsigned verbose : 8; - unsigned default_tags; - unsigned default_sync; - unsigned debug; - unsigned burst_max; -} driver_setup = SCSI_NCR_DRIVER_SETUP; + u_char verbose; + u_char default_tags; + u_short default_sync; + u_short debug; + u_char burst_max; + u_char led_pin; + u_char max_wide; + u_char settle_time; + u_char diff_support; + u_char irqm; +}; + +static struct ncr_driver_setup driver_setup = SCSI_NCR_DRIVER_SETUP; +static struct ncr_driver_setup driver_safe_setup= SCSI_NCR_DRIVER_SAFE_SETUP; /* ** Other Linux definitions @@ -719,7 +758,6 @@ */ #define CCB_MAGIC (0xf2691ad2) -#define MAX_TAGS (16) /* hard limit */ /*========================================================== ** @@ -1019,9 +1057,9 @@ ** the last transfer command. */ - u_long savep; - u_long lastp; - u_long goalp; + u_int32 savep; + u_int32 lastp; + u_int32 goalp; /* ** The virtual address of the ccb @@ -1152,6 +1190,14 @@ struct ccb { /* + ** This field forces 32 bytes alignement for phys.header, + ** in order to use cache line bursting when copying it + ** to the ncb. + */ + + struct link filler[2]; + + /* ** during reselection the ncr jumps to this point. ** If a "SIMPLE_TAG" message was received, ** then SFBR is set to the tag. @@ -1278,6 +1324,16 @@ */ struct ncb { + /* + ** The global header. + ** Accessible to both the host and the + ** script-processor. + ** Is 32 bytes aligned since ncb is, in order to + ** allow cache line bursting when copying it from or + ** to ccbs. + */ + struct head header; + /*----------------------------------------------- ** Specific Linux fields **----------------------------------------------- @@ -1289,6 +1345,7 @@ Scsi_Cmnd *waiting_list; /* Waiting list header for commands */ /* that we can't put into the squeue */ u_char release_stage; /* Synchronisation stage on release */ + u_char resetting; /* Reset in progess */ /*----------------------------------------------- ** Added field to support differences @@ -1310,13 +1367,16 @@ u_char sv_ctest3; u_char sv_ctest4; u_char sv_ctest5; + u_char sv_gpcntl; + u_char sv_stest2; u_char rv_dmode; u_char rv_dcntl; u_char rv_ctest3; u_char rv_ctest4; u_char rv_ctest5; - u_char uf_doubler; + u_char rv_stest2; + u_char multiplier; /*----------------------------------------------- ** Scripts .. @@ -1342,6 +1402,9 @@ vm_offset_t vaddr; vm_offset_t paddr; + vm_offset_t vaddr2; + vm_offset_t paddr2; + /* ** pointer to the chip's registers. */ @@ -1349,14 +1412,22 @@ struct ncr_reg* reg; /* - ** A copy of the script, relocated for this ncb. + ** A copy of the scripts, relocated for this ncb. + */ + struct script *script0; + struct scripth *scripth0; + + /* + ** Scripts instance virtual address. */ struct script *script; + struct scripth *scripth; /* - ** Physical address of this instance of ncb->script + ** Scripts instance physical address. */ u_long p_script; + u_long p_scripth; /* ** The SCSI address of the host adapter. @@ -1374,6 +1445,12 @@ */ u_char maxoffs; + /* + ** controller scsi clock frequency and available divisors + */ + u_long clock_khz; + int clock_divn; + /*----------------------------------------------- ** Link to the generic SCSI driver **----------------------------------------------- @@ -1398,7 +1475,7 @@ /* ** Start queue. */ - u_long squeue [MAX_START]; + u_int32 squeue [MAX_START]; u_short squeueput; u_short actccbs; @@ -1427,19 +1504,12 @@ u_long disc_ref; /* - ** The global header. - ** Accessible to both the host and the - ** script-processor. - */ - struct head header; - - /* ** The global control block. ** It's used only during the configuration phase. ** A target control block will be created ** after the first successful transfer. */ - struct ccb ccb; + struct ccb *ccb; /* ** message buffers. @@ -1449,7 +1519,7 @@ */ u_char msgout[8]; u_char msgin [8]; - u_long lastmsg; + u_int32 lastmsg; /* ** Buffer for STATUS_IN phase. @@ -1477,7 +1547,8 @@ u_short irq; }; -#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) +#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) +#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth, lbl)) /*========================================================== ** @@ -1500,12 +1571,15 @@ **---------------------------------------------------------- */ +/* +** Script fragments which are loaded into the on-board RAM +** of 825A, 875 and 895 chips. +*/ struct script { ncrcmd start [ 7]; ncrcmd start0 [ 2]; ncrcmd start1 [ 3]; ncrcmd startpos [ 1]; - ncrcmd tryloop [MAX_START*5+2]; ncrcmd trysel [ 8]; ncrcmd skip [ 8]; ncrcmd skip2 [ 3]; @@ -1523,14 +1597,6 @@ ncrcmd status [ 27]; ncrcmd msg_in [ 26]; ncrcmd msg_bad [ 6]; - ncrcmd msg_parity [ 6]; - ncrcmd msg_reject [ 8]; - ncrcmd msg_ign_residue [ 32]; - ncrcmd msg_extended [ 18]; - ncrcmd msg_ext_2 [ 18]; - ncrcmd msg_wdtr [ 27]; - ncrcmd msg_ext_3 [ 18]; - ncrcmd msg_sdtr [ 27]; ncrcmd complete [ 13]; ncrcmd cleanup [ 12]; ncrcmd cleanup0 [ 11]; @@ -1542,6 +1608,30 @@ ncrcmd disconnect1 [ 23]; ncrcmd msg_out [ 9]; ncrcmd msg_out_done [ 7]; + ncrcmd badgetcc [ 6]; + ncrcmd reselect [ 8]; + ncrcmd reselect1 [ 8]; + ncrcmd reselect2 [ 8]; + ncrcmd resel_tmp [ 5]; + ncrcmd resel_lun [ 18]; + ncrcmd resel_tag [ 24]; + ncrcmd data_io [ 2]; /* MUST be just before data_in */ + ncrcmd data_in [MAX_SCATTER * 4 + 7]; +}; + +/* +** Script fragments which stay in main memory for all chips. +*/ +struct scripth { + ncrcmd tryloop [MAX_START*5+2]; + ncrcmd msg_parity [ 6]; + ncrcmd msg_reject [ 8]; + ncrcmd msg_ign_residue [ 32]; + ncrcmd msg_extended [ 18]; + ncrcmd msg_ext_2 [ 18]; + ncrcmd msg_wdtr [ 27]; + ncrcmd msg_ext_3 [ 18]; + ncrcmd msg_sdtr [ 27]; ncrcmd msg_out_abort [ 10]; ncrcmd getcc [ 4]; ncrcmd getcc1 [ 5]; @@ -1551,14 +1641,6 @@ ncrcmd getcc2 [ 14]; #endif ncrcmd getcc3 [ 10]; - ncrcmd badgetcc [ 6]; - ncrcmd reselect [ 12]; - ncrcmd reselect2 [ 6]; - ncrcmd resel_tmp [ 5]; - ncrcmd resel_lun [ 18]; - ncrcmd resel_tag [ 24]; - ncrcmd data_io [ 2]; /* MUST be just before data_in */ - ncrcmd data_in [MAX_SCATTER * 4 + 7]; ncrcmd data_out [MAX_SCATTER * 4 + 7]; ncrcmd aborttag [ 4]; ncrcmd abort [ 22]; @@ -1579,7 +1661,8 @@ static void ncr_complete (ncb_p np, ccb_p cp); static void ncr_exception (ncb_p np); static void ncr_free_ccb (ncb_p np, ccb_p cp, u_long t, u_long l); -static void ncr_getclock (ncb_p np); +static void ncr_getclock (ncb_p np, int mult); +static void ncr_selectclock (ncb_p np, u_char scntl3); static void ncr_save_bios_setting (ncb_p np); static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l); static void ncr_init (ncb_p np, char * msg, u_long code); @@ -1596,10 +1679,11 @@ #endif static void ncr_script_copy_and_bind - (struct script * script, ncb_p np); -static void ncr_script_fill (struct script * scr); + (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); +static void ncr_script_fill (struct script * scr, struct scripth * scripth); static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd); static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long usrtags); +static int ncr_getsync (ncb_p np, u_char fac, u_char *fakp, u_char *scntl3p); static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer); static void ncr_settags (tcb_p tp, lcb_p lp); static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide); @@ -1617,11 +1701,12 @@ int irq, int bus, u_char device_fn); static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd); -static Scsi_Cmnd *remove_from_waiting_list(ncb_p np, Scsi_Cmnd *cmd); +static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd); static void process_waiting_list(ncb_p np, int sts); +#define remove_from_waiting_list(np, cmd) \ + retrieve_from_waiting_list(1, (np), (cmd)) #define requeue_waiting_list(np) process_waiting_list((np), DID_OK) -#define abort_waiting_list(np) process_waiting_list((np), DID_ABORT) #define reset_waiting_list(np) process_waiting_list((np), DID_RESET) /*========================================================== @@ -1687,10 +1772,12 @@ #define RELOC_LABEL 0x50000000 #define RELOC_REGISTER 0x60000000 #define RELOC_KVAR 0x70000000 +#define RELOC_LABELH 0x80000000 #define RELOC_MASK 0xf0000000 #define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label)) #define PADDR(label) (RELOC_LABEL | offsetof(struct script, label)) +#define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label)) #define RADDR(label) (RELOC_REGISTER | REG(label)) #define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs))) #define KVAR(which) (RELOC_KVAR | (which)) @@ -1747,33 +1834,7 @@ */ SCR_JUMP, }/*-------------------------< STARTPOS >--------------------*/,{ - PADDR(tryloop), -}/*-------------------------< TRYLOOP >---------------------*/,{ -/* -** Load an entry of the start queue into dsa -** and try to start it by jumping to TRYSEL. -** -** Because the size depends on the -** #define MAX_START parameter, it is filled -** in at runtime. -** -**----------------------------------------------------------- -** -** ##===========< I=0; i=========== -** || SCR_COPY (4), -** || NADDR (squeue[i]), -** || RADDR (dsa), -** || SCR_CALL, -** || PADDR (trysel), -** ##========================================== -** -** SCR_JUMP, -** PADDR(tryloop), -** -**----------------------------------------------------------- -*/ -0 - + PADDRH(tryloop), }/*-------------------------< TRYSEL >----------------------*/,{ /* ** Now: @@ -2011,7 +2072,7 @@ SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), PADDR (msg_in), SCR_JUMP ^ IFTRUE (DATA (M_REJECT)), - PADDR (msg_reject), + PADDRH (msg_reject), /* ** normal processing */ @@ -2228,7 +2289,7 @@ SCR_FROM_REG (socl), 0, SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDR (msg_parity), + PADDRH (msg_parity), SCR_FROM_REG (scratcha), 0, /* @@ -2243,13 +2304,13 @@ SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), PADDR (disconnect), SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), - PADDR (msg_extended), + PADDRH (msg_extended), SCR_JUMP ^ IFTRUE (DATA (M_NOOP)), PADDR (clrack), SCR_JUMP ^ IFTRUE (DATA (M_REJECT)), - PADDR (msg_reject), + PADDRH (msg_reject), SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)), - PADDR (msg_ign_residue), + PADDRH (msg_ign_residue), /* ** Rest of the messages left as ** an exercise ... @@ -2268,196 +2329,624 @@ SCR_JUMP, PADDR (setmsg), -}/*-------------------------< MSG_PARITY >---------------*/,{ +}/*-------------------------< COMPLETE >-----------------*/,{ /* - ** count it + ** Complete message. + ** + ** If it's not the get condition code, + ** copy TEMP register to LASTP in header. */ - SCR_REG_REG (PS_REG, SCR_ADD, 0x01), + SCR_FROM_REG (SS_REG), 0, - /* - ** send a "message parity error" message. +/*<<<*/ SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)), + 12, + SCR_COPY (4), + RADDR (temp), + NADDR (header.lastp), +/*>>>*/ /* + ** When we terminate the cycle by clearing ACK, + ** the target may disconnect immediately. + ** + ** We don't want to be told of an + ** "unexpected disconnect", + ** so we disable this feature. */ - SCR_LOAD_REG (scratcha, M_PARITY), + SCR_REG_REG (scntl2, SCR_AND, 0x7f), 0, - SCR_JUMP, - PADDR (setmsg), -}/*-------------------------< MSG_REJECT >---------------*/,{ /* - ** If a negotiation was in progress, - ** negotiation failed. + ** Terminate cycle ... */ - SCR_FROM_REG (HS_REG), + SCR_CLR (SCR_ACK|SCR_ATN), 0, - SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), - SIR_NEGO_FAILED, /* - ** else make host log this message + ** ... and wait for the disconnect. */ - SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)), - SIR_REJECT_RECEIVED, - SCR_JUMP, - PADDR (clrack), - -}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{ + SCR_WAIT_DISC, + 0, +}/*-------------------------< CLEANUP >-------------------*/,{ /* - ** Terminate cycle + ** dsa: Pointer to ccb + ** or xxxxxxFF (no ccb) + ** + ** HS_REG: Host-Status (<>0!) */ - SCR_CLR (SCR_ACK), + SCR_FROM_REG (dsa), 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR (dispatch), + SCR_JUMP ^ IFTRUE (DATA (0xff)), + PADDR (signal), /* - ** get residue size. + ** dsa is valid. + ** save the status registers */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[1]), + SCR_COPY (4), + RADDR (scr0), + NADDR (header.status), /* - ** Check for message parity error. + ** and copy back the header to the ccb. */ - SCR_TO_REG (scratcha), + SCR_COPY (4), + RADDR (dsa), + PADDR (cleanup0), + SCR_COPY (sizeof (struct head)), + NADDR (header), +}/*-------------------------< CLEANUP0 >--------------------*/,{ 0, - SCR_FROM_REG (socl), + + /* + ** If command resulted in "check condition" + ** status and is not yet completed, + ** try to get the condition code. + */ + SCR_FROM_REG (HS_REG), 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDR (msg_parity), - SCR_FROM_REG (scratcha), +/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)), + 16, + SCR_FROM_REG (SS_REG), 0, + SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)), + PADDRH(getcc2), /* - ** Size is 0 .. ignore message. + ** And make the DSA register invalid. */ - SCR_JUMP ^ IFTRUE (DATA (0)), - PADDR (clrack), +/*>>>*/ SCR_LOAD_REG (dsa, 0xff), /* invalid */ + 0, +}/*-------------------------< SIGNAL >----------------------*/,{ /* - ** Size is not 1 .. have to interrupt. + ** if status = queue full, + ** reinsert in startqueue and stall queue. */ -/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (1)), - 40, + SCR_FROM_REG (SS_REG), + 0, + SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)), + SIR_STALL_QUEUE, /* - ** Check for residue byte in swide register + ** if job completed ... */ - SCR_FROM_REG (scntl2), + SCR_FROM_REG (HS_REG), 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), - 16, /* - ** There IS data in the swide register. - ** Discard it. + ** ... signal completion to the host */ - SCR_REG_REG (scntl2, SCR_OR, WSR), + SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)), 0, + /* + ** Auf zu neuen Schandtaten! + */ + SCR_JUMP, + PADDR(start), + +}/*-------------------------< SAVE_DP >------------------*/,{ + /* + ** SAVE_DP message: + ** Copy TEMP register to SAVEP in header. + */ + SCR_COPY (4), + RADDR (temp), + NADDR (header.savep), SCR_JUMP, PADDR (clrack), +}/*-------------------------< RESTORE_DP >---------------*/,{ /* - ** Load again the size to the sfbr register. + ** RESTORE_DP message: + ** Copy SAVEP in header to TEMP register. */ -/*>>>*/ SCR_FROM_REG (scratcha), - 0, -/*>>>*/ SCR_INT, - SIR_IGN_RESIDUE, + SCR_COPY (4), + NADDR (header.savep), + RADDR (temp), SCR_JUMP, PADDR (clrack), -}/*-------------------------< MSG_EXTENDED >-------------*/,{ +}/*-------------------------< DISCONNECT >---------------*/,{ /* - ** Terminate cycle + ** If QUIRK_AUTOSAVE is set, + ** do an "save pointer" operation. */ - SCR_CLR (SCR_ACK), + SCR_FROM_REG (QU_REG), 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), +/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)), + 12, + /* + ** like SAVE_DP message: + ** Copy TEMP register to SAVEP in header. + */ + SCR_COPY (4), + RADDR (temp), + NADDR (header.savep), +/*>>>*/ /* + ** Check if temp==savep or temp==goalp: + ** if not, log a missing save pointer message. + ** In fact, it's a comparison mod 256. + ** + ** Hmmm, I hadn't thought that I would be urged to + ** write this kind of ugly self modifying code. + ** + ** It's unbelievable, but the ncr53c8xx isn't able + ** to subtract one register from another. + */ + SCR_FROM_REG (temp), + 0, + /* + ** You are not expected to understand this .. + ** + ** CAUTION: only little endian architectures supported! XXX + */ + SCR_COPY (1), + NADDR (header.savep), + PADDR (disconnect0), +}/*-------------------------< DISCONNECT0 >--------------*/,{ +/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (1)), + 20, + /* + ** neither this + */ + SCR_COPY (1), + NADDR (header.goalp), + PADDR (disconnect1), +}/*-------------------------< DISCONNECT1 >--------------*/,{ + SCR_INT ^ IFFALSE (DATA (1)), + SIR_MISSING_SAVE, +/*>>>*/ + + /* + ** DISCONNECTing ... + ** + ** disable the "unexpected disconnect" feature, + ** and remove the ACK signal. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** Wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, + /* + ** Profiling: + ** Set a time stamp, + ** and count the disconnects. + */ + SCR_COPY (sizeof (u_long)), + KVAR(SCRIPT_KVAR_JIFFIES), + NADDR (header.stamp.disconnect), + SCR_COPY (4), + NADDR (disc_phys), + RADDR (temp), + SCR_REG_REG (temp, SCR_ADD, 0x01), + 0, + SCR_COPY (4), + RADDR (temp), + NADDR (disc_phys), + /* + ** Status is: DISCONNECTED. + */ + SCR_LOAD_REG (HS_REG, HS_DISCONNECT), + 0, + SCR_JUMP, + PADDR (cleanup), + +}/*-------------------------< MSG_OUT >-------------------*/,{ + /* + ** The target requests a message. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), + /* + ** If it was no ABORT message ... + */ + SCR_JUMP ^ IFTRUE (DATA (M_ABORT)), + PADDRH (msg_out_abort), + /* + ** ... wait for the next phase + ** if it's a message out, send it again, ... + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDR (msg_out), +}/*-------------------------< MSG_OUT_DONE >--------------*/,{ + /* + ** ... else clear the message ... + */ + SCR_LOAD_REG (scratcha, M_NOOP), + 0, + SCR_COPY (4), + RADDR (scratcha), + NADDR (msgout), + /* + ** ... and process the next phase + */ + SCR_JUMP, PADDR (dispatch), +}/*------------------------< BADGETCC >---------------------*/,{ /* - ** get length. + ** If SIGP was set, clear it and try again. + */ + SCR_FROM_REG (ctest2), + 0, + SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)), + PADDRH (getcc2), + SCR_INT, + SIR_SENSE_FAILED, +}/*-------------------------< RESELECT >--------------------*/,{ + /* + ** This NOP will be patched with LED OFF + ** SCR_REG_REG (gpreg, SCR_OR, 0x01) + */ + SCR_JUMP ^ IFFALSE (0), + 0, + /* + ** make the DSA invalid. + */ + SCR_LOAD_REG (dsa, 0xff), + 0, + SCR_CLR (SCR_TRG), + 0, + /* + ** Sleep waiting for a reselection. + ** If SIGP is set, special treatment. + ** + ** Zu allem bereit .. + */ + SCR_WAIT_RESEL, + PADDR(reselect2), +}/*-------------------------< RESELECT1 >--------------------*/,{ + /* + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + */ + SCR_JUMP ^ IFFALSE (0), + 0, + /* + ** ... zu nichts zu gebrauchen ? + ** + ** load the target id into the SFBR + ** and jump to the control block. + ** + ** Look at the declarations of + ** - struct ncb + ** - struct tcb + ** - struct lcb + ** - struct ccb + ** to understand what's going on. + */ + SCR_REG_SFBR (ssid, SCR_AND, 0x8F), + 0, + SCR_TO_REG (ctest0), + 0, + SCR_JUMP, + NADDR (jump_tcb), +}/*-------------------------< RESELECT2 >-------------------*/,{ + /* + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + */ + SCR_JUMP ^ IFFALSE (0), + 0, + /* + ** If it's not connected :( + ** -> interrupted by SIGP bit. + ** Jump to start. + */ + SCR_FROM_REG (ctest2), + 0, + SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)), + PADDR (start), + SCR_JUMP, + PADDR (reselect), + +}/*-------------------------< RESEL_TMP >-------------------*/,{ + /* + ** The return address in TEMP + ** is in fact the data structure address, + ** so copy it to the DSA register. + */ + SCR_COPY (4), + RADDR (temp), + RADDR (dsa), + SCR_JUMP, + PADDR (prepare), + +}/*-------------------------< RESEL_LUN >-------------------*/,{ + /* + ** come back to this point + ** to get an IDENTIFY message + ** Wait for a msg_in phase. + */ +/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), + 48, + /* + ** message phase + ** It's not a sony, it's a trick: + ** read the data without acknowledging it. + */ + SCR_FROM_REG (sbdl), + 0, +/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)), + 32, + /* + ** It WAS an Identify message. + ** get it and ack it! */ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[1]), + NADDR (msgin), + SCR_CLR (SCR_ACK), + 0, /* - ** Check for message parity error. + ** Mask out the lun. */ - SCR_TO_REG (scratcha), + SCR_REG_REG (sfbr, SCR_AND, 0x07), 0, - SCR_FROM_REG (socl), + SCR_RETURN, 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDR (msg_parity), - SCR_FROM_REG (scratcha), + /* + ** No message phase or no IDENTIFY message: + ** return 0. + */ +/*>>>*/ SCR_LOAD_SFBR (0), 0, + SCR_RETURN, + 0, + +}/*-------------------------< RESEL_TAG >-------------------*/,{ /* + ** come back to this point + ** to get a SIMPLE_TAG message + ** Wait for a MSG_IN phase. */ - SCR_JUMP ^ IFTRUE (DATA (3)), - PADDR (msg_ext_3), - SCR_JUMP ^ IFFALSE (DATA (2)), - PADDR (msg_bad), -}/*-------------------------< MSG_EXT_2 >----------------*/,{ +/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), + 64, + /* + ** message phase + ** It's a trick - read the data + ** without acknowledging it. + */ + SCR_FROM_REG (sbdl), + 0, +/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)), + 48, + /* + ** It WAS a SIMPLE_TAG message. + ** get it and ack it! + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), SCR_CLR (SCR_ACK), 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR (dispatch), /* - ** get extended message code. + ** Wait for the second byte (the tag) + */ +/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), + 24, + /* + ** Get it and ack it! */ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[2]), + NADDR (msgin), + SCR_CLR (SCR_ACK|SCR_CARRY), + 0, + SCR_RETURN, + 0, /* - ** Check for message parity error. + ** No message phase or no SIMPLE_TAG message + ** or no second byte: return 0. */ - SCR_TO_REG (scratcha), +/*>>>*/ SCR_LOAD_SFBR (0), 0, - SCR_FROM_REG (socl), + SCR_SET (SCR_CARRY), 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDR (msg_parity), - SCR_FROM_REG (scratcha), + SCR_RETURN, 0, - SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)), - PADDR (msg_wdtr), + +}/*-------------------------< DATA_IO >--------------------*/,{ +/* +** Because Linux does not provide xfer data direction +** to low-level scsi drivers, we must trust the target +** for actual data direction when we cannot guess it. +** The programmed interrupt patches savep, lastp, goalp, +** etc.., and restarts the scsi script at data_out. +*/ + SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)), + SIR_DATA_IO_IS_OUT, + +}/*-------------------------< DATA_IN >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTER parameter, +** it is filled in at runtime. +** +** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), +** PADDR (no_data), +** SCR_COPY (sizeof (u_long)), +** KVAR(SCRIPT_KVAR_JIFFIES), +** NADDR (header.stamp.data), +** SCR_MOVE_TBL ^ SCR_DATA_IN, +** offsetof (struct dsb, data[ 0]), +** +** ##===========< i=1; i========= +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), +** || PADDR (checkatn), +** || SCR_MOVE_TBL ^ SCR_DATA_IN, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +** SCR_CALL, +** PADDR (checkatn), +** SCR_JUMP, +** PADDR (no_data), +*/ +0 +}/*--------------------------------------------------------*/ +}; + +static struct scripth scripth0 = { +/*-------------------------< TRYLOOP >---------------------*/{ +/* +** Load an entry of the start queue into dsa +** and try to start it by jumping to TRYSEL. +** +** Because the size depends on the +** #define MAX_START parameter, it is filled +** in at runtime. +** +**----------------------------------------------------------- +** +** ##===========< I=0; i=========== +** || SCR_COPY (4), +** || NADDR (squeue[i]), +** || RADDR (dsa), +** || SCR_CALL, +** || PADDR (trysel), +** ##========================================== +** +** SCR_JUMP, +** PADDRH(tryloop), +** +**----------------------------------------------------------- +*/ +0 +},/*-------------------------< MSG_PARITY >---------------*/{ /* - ** unknown extended message + ** count it */ + SCR_REG_REG (PS_REG, SCR_ADD, 0x01), + 0, + /* + ** send a "message parity error" message. + */ + SCR_LOAD_REG (scratcha, M_PARITY), + 0, SCR_JUMP, - PADDR (msg_bad) -}/*-------------------------< MSG_WDTR >-----------------*/,{ + PADDR (setmsg), +}/*-------------------------< MSG_REJECT >---------------*/,{ + /* + ** If a negotiation was in progress, + ** negotiation failed. + */ + SCR_FROM_REG (HS_REG), + 0, + SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), + SIR_NEGO_FAILED, + /* + ** else make host log this message + */ + SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)), + SIR_REJECT_RECEIVED, + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{ + /* + ** Terminate cycle + */ SCR_CLR (SCR_ACK), 0, SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), PADDR (dispatch), /* - ** get data bus width + ** get residue size. */ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[3]), + NADDR (msgin[1]), + /* + ** Check for message parity error. + */ + SCR_TO_REG (scratcha), + 0, SCR_FROM_REG (socl), 0, SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDR (msg_parity), + PADDRH (msg_parity), + SCR_FROM_REG (scratcha), + 0, /* - ** let the host do the real work. + ** Size is 0 .. ignore message. */ - SCR_INT, - SIR_NEGO_WIDE, + SCR_JUMP ^ IFTRUE (DATA (0)), + PADDR (clrack), /* - ** let the target fetch our answer. + ** Size is not 1 .. have to interrupt. */ - SCR_SET (SCR_ATN), +/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (1)), + 40, + /* + ** Check for residue byte in swide register + */ + SCR_FROM_REG (scntl2), 0, - SCR_CLR (SCR_ACK), +/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), + 16, + /* + ** There IS data in the swide register. + ** Discard it. + */ + SCR_REG_REG (scntl2, SCR_OR, WSR), 0, - - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), - SIR_NEGO_PROTO, + SCR_JUMP, + PADDR (clrack), /* - ** Send the M_X_WIDE_REQ + ** Load again the size to the sfbr register. */ - SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, - NADDR (msgout), - SCR_CLR (SCR_ATN), +/*>>>*/ SCR_FROM_REG (scratcha), 0, - SCR_COPY (1), - RADDR (sfbr), - NADDR (lastmsg), +/*>>>*/ SCR_INT, + SIR_IGN_RESIDUE, SCR_JUMP, - PADDR (msg_out_done), + PADDR (clrack), -}/*-------------------------< MSG_EXT_3 >----------------*/,{ +}/*-------------------------< MSG_EXTENDED >-------------*/,{ + /* + ** Terminate cycle + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get length. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + /* + ** Check for message parity error. + */ + SCR_TO_REG (scratcha), + 0, + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDRH (msg_parity), + SCR_FROM_REG (scratcha), + 0, + /* + */ + SCR_JUMP ^ IFTRUE (DATA (3)), + PADDRH (msg_ext_3), + SCR_JUMP ^ IFFALSE (DATA (2)), + PADDR (msg_bad), +}/*-------------------------< MSG_EXT_2 >----------------*/,{ SCR_CLR (SCR_ACK), 0, SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), @@ -2475,36 +2964,35 @@ SCR_FROM_REG (socl), 0, SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDR (msg_parity), + PADDRH (msg_parity), SCR_FROM_REG (scratcha), 0, - SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)), - PADDR (msg_sdtr), + SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)), + PADDRH (msg_wdtr), /* ** unknown extended message */ SCR_JUMP, PADDR (msg_bad) - -}/*-------------------------< MSG_SDTR >-----------------*/,{ +}/*-------------------------< MSG_WDTR >-----------------*/,{ SCR_CLR (SCR_ACK), 0, SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), PADDR (dispatch), /* - ** get period and offset + ** get data bus width */ - SCR_MOVE_ABS (2) ^ SCR_MSG_IN, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, NADDR (msgin[3]), SCR_FROM_REG (socl), 0, SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDR (msg_parity), + PADDRH (msg_parity), /* ** let the host do the real work. */ SCR_INT, - SIR_NEGO_SYNC, + SIR_NEGO_WIDE, /* ** let the target fetch our answer. */ @@ -2516,9 +3004,9 @@ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), SIR_NEGO_PROTO, /* - ** Send the M_X_SYNC_REQ + ** Send the M_X_WIDE_REQ */ - SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, + SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, NADDR (msgout), SCR_CLR (SCR_ATN), 0, @@ -2528,257 +3016,77 @@ SCR_JUMP, PADDR (msg_out_done), -}/*-------------------------< COMPLETE >-----------------*/,{ - /* - ** Complete message. - ** - ** If it's not the get condition code, - ** copy TEMP register to LASTP in header. - */ - SCR_FROM_REG (SS_REG), - 0, -/*<<<*/ SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)), - 12, - SCR_COPY (4), - RADDR (temp), - NADDR (header.lastp), -/*>>>*/ /* - ** When we terminate the cycle by clearing ACK, - ** the target may disconnect immediately. - ** - ** We don't want to be told of an - ** "unexpected disconnect", - ** so we disable this feature. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - /* - ** Terminate cycle ... - */ - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - /* - ** ... and wait for the disconnect. - */ - SCR_WAIT_DISC, - 0, -}/*-------------------------< CLEANUP >-------------------*/,{ - /* - ** dsa: Pointer to ccb - ** or xxxxxxFF (no ccb) - ** - ** HS_REG: Host-Status (<>0!) - */ - SCR_FROM_REG (dsa), - 0, - SCR_JUMP ^ IFTRUE (DATA (0xff)), - PADDR (signal), - /* - ** dsa is valid. - ** save the status registers - */ - SCR_COPY (4), - RADDR (scr0), - NADDR (header.status), - /* - ** and copy back the header to the ccb. - */ - SCR_COPY (4), - RADDR (dsa), - PADDR (cleanup0), - SCR_COPY (sizeof (struct head)), - NADDR (header), -}/*-------------------------< CLEANUP0 >--------------------*/,{ - 0, - - /* - ** If command resulted in "check condition" - ** status and is not yet completed, - ** try to get the condition code. - */ - SCR_FROM_REG (HS_REG), - 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)), - 16, - SCR_FROM_REG (SS_REG), +}/*-------------------------< MSG_EXT_3 >----------------*/,{ + SCR_CLR (SCR_ACK), 0, - SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)), - PADDR(getcc2), + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), /* - ** And make the DSA register invalid. + ** get extended message code. */ -/*>>>*/ SCR_LOAD_REG (dsa, 0xff), /* invalid */ - 0, -}/*-------------------------< SIGNAL >----------------------*/,{ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[2]), /* - ** if status = queue full, - ** reinsert in startqueue and stall queue. + ** Check for message parity error. */ - SCR_FROM_REG (SS_REG), + SCR_TO_REG (scratcha), 0, - SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)), - SIR_STALL_QUEUE, - /* - ** if job completed ... - */ - SCR_FROM_REG (HS_REG), + SCR_FROM_REG (socl), 0, - /* - ** ... signal completion to the host - */ - SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)), + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDRH (msg_parity), + SCR_FROM_REG (scratcha), 0, + SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)), + PADDRH (msg_sdtr), /* - ** Auf zu neuen Schandtaten! - */ - SCR_JUMP, - PADDR(start), - -}/*-------------------------< SAVE_DP >------------------*/,{ - /* - ** SAVE_DP message: - ** Copy TEMP register to SAVEP in header. - */ - SCR_COPY (4), - RADDR (temp), - NADDR (header.savep), - SCR_JUMP, - PADDR (clrack), -}/*-------------------------< RESTORE_DP >---------------*/,{ - /* - ** RESTORE_DP message: - ** Copy SAVEP in header to TEMP register. + ** unknown extended message */ - SCR_COPY (4), - NADDR (header.savep), - RADDR (temp), SCR_JUMP, - PADDR (clrack), - -}/*-------------------------< DISCONNECT >---------------*/,{ - /* - ** If QUIRK_AUTOSAVE is set, - ** do an "save pointer" operation. - */ - SCR_FROM_REG (QU_REG), - 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)), - 12, - /* - ** like SAVE_DP message: - ** Copy TEMP register to SAVEP in header. - */ - SCR_COPY (4), - RADDR (temp), - NADDR (header.savep), -/*>>>*/ /* - ** Check if temp==savep or temp==goalp: - ** if not, log a missing save pointer message. - ** In fact, it's a comparison mod 256. - ** - ** Hmmm, I hadn't thought that I would be urged to - ** write this kind of ugly self modifying code. - ** - ** It's unbelievable, but the ncr53c8xx isn't able - ** to subtract one register from another. - */ - SCR_FROM_REG (temp), - 0, - /* - ** You are not expected to understand this .. - ** - ** CAUTION: only little endian architectures supported! XXX - */ - SCR_COPY (1), - NADDR (header.savep), - PADDR (disconnect0), -}/*-------------------------< DISCONNECT0 >--------------*/,{ -/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (1)), - 20, - /* - ** neither this - */ - SCR_COPY (1), - NADDR (header.goalp), - PADDR (disconnect1), -}/*-------------------------< DISCONNECT1 >--------------*/,{ - SCR_INT ^ IFFALSE (DATA (1)), - SIR_MISSING_SAVE, -/*>>>*/ + PADDR (msg_bad) - /* - ** DISCONNECTing ... - ** - ** disable the "unexpected disconnect" feature, - ** and remove the ACK signal. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - /* - ** Wait for the disconnect. - */ - SCR_WAIT_DISC, - 0, - /* - ** Profiling: - ** Set a time stamp, - ** and count the disconnects. - */ - SCR_COPY (sizeof (u_long)), - KVAR(SCRIPT_KVAR_JIFFIES), - NADDR (header.stamp.disconnect), - SCR_COPY (4), - NADDR (disc_phys), - RADDR (temp), - SCR_REG_REG (temp, SCR_ADD, 0x01), +}/*-------------------------< MSG_SDTR >-----------------*/,{ + SCR_CLR (SCR_ACK), 0, - SCR_COPY (4), - RADDR (temp), - NADDR (disc_phys), + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), /* - ** Status is: DISCONNECTED. + ** get period and offset */ - SCR_LOAD_REG (HS_REG, HS_DISCONNECT), + SCR_MOVE_ABS (2) ^ SCR_MSG_IN, + NADDR (msgin[3]), + SCR_FROM_REG (socl), 0, - SCR_JUMP, - PADDR (cleanup), - -}/*-------------------------< MSG_OUT >-------------------*/,{ - /* - ** The target requests a message. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, - NADDR (msgout), - SCR_COPY (1), - RADDR (sfbr), - NADDR (lastmsg), - /* - ** If it was no ABORT message ... - */ - SCR_JUMP ^ IFTRUE (DATA (M_ABORT)), - PADDR (msg_out_abort), + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDRH (msg_parity), /* - ** ... wait for the next phase - ** if it's a message out, send it again, ... + ** let the host do the real work. */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), - PADDR (msg_out), -}/*-------------------------< MSG_OUT_DONE >--------------*/,{ + SCR_INT, + SIR_NEGO_SYNC, /* - ** ... else clear the message ... + ** let the target fetch our answer. */ - SCR_LOAD_REG (scratcha, M_NOOP), + SCR_SET (SCR_ATN), 0, - SCR_COPY (4), - RADDR (scratcha), - NADDR (msgout), + SCR_CLR (SCR_ACK), + 0, + + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), + SIR_NEGO_PROTO, /* - ** ... and process the next phase + ** Send the M_X_SYNC_REQ */ + SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_CLR (SCR_ATN), + 0, + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), SCR_JUMP, - PADDR (dispatch), + PADDR (msg_out_done), + }/*-------------------------< MSG_OUT_ABORT >-------------*/,{ /* ** After ABORT message, @@ -2811,7 +3119,7 @@ */ SCR_COPY (4), RADDR (dsa), - PADDR (getcc1), + PADDRH (getcc1), /* ** ... then we do the actual copy. */ @@ -2877,7 +3185,7 @@ SCR_FROM_REG (QU_REG), 0, SCR_JUMP ^ IFTRUE (MASK (QUIRK_NOMSG, QUIRK_NOMSG)), - PADDR(getcc3), + PADDRH(getcc3), /* ** Then try to connect to the target. ** If we are reselected, special treatment @@ -2941,205 +3249,6 @@ SCR_JUMP, PADDR (prepare2), -}/*------------------------< BADGETCC >---------------------*/,{ - /* - ** If SIGP was set, clear it and try again. - */ - SCR_FROM_REG (ctest2), - 0, - SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)), - PADDR (getcc2), - SCR_INT, - SIR_SENSE_FAILED, -}/*-------------------------< RESELECT >--------------------*/,{ - /* - ** make the DSA invalid. - */ - SCR_LOAD_REG (dsa, 0xff), - 0, - SCR_CLR (SCR_TRG), - 0, - /* - ** Sleep waiting for a reselection. - ** If SIGP is set, special treatment. - ** - ** Zu allem bereit .. - */ - SCR_WAIT_RESEL, - PADDR(reselect2), - /* - ** ... zu nichts zu gebrauchen ? - ** - ** load the target id into the SFBR - ** and jump to the control block. - ** - ** Look at the declarations of - ** - struct ncb - ** - struct tcb - ** - struct lcb - ** - struct ccb - ** to understand what's going on. - */ - SCR_REG_SFBR (ssid, SCR_AND, 0x8F), - 0, - SCR_TO_REG (ctest0), - 0, - SCR_JUMP, - NADDR (jump_tcb), -}/*-------------------------< RESELECT2 >-------------------*/,{ - /* - ** If it's not connected :( - ** -> interrupted by SIGP bit. - ** Jump to start. - */ - SCR_FROM_REG (ctest2), - 0, - SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)), - PADDR (start), - SCR_JUMP, - PADDR (reselect), - -}/*-------------------------< RESEL_TMP >-------------------*/,{ - /* - ** The return address in TEMP - ** is in fact the data structure address, - ** so copy it to the DSA register. - */ - SCR_COPY (4), - RADDR (temp), - RADDR (dsa), - SCR_JUMP, - PADDR (prepare), - -}/*-------------------------< RESEL_LUN >-------------------*/,{ - /* - ** come back to this point - ** to get an IDENTIFY message - ** Wait for a msg_in phase. - */ -/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), - 48, - /* - ** message phase - ** It's not a sony, it's a trick: - ** read the data without acknowledging it. - */ - SCR_FROM_REG (sbdl), - 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)), - 32, - /* - ** It WAS an Identify message. - ** get it and ack it! - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_CLR (SCR_ACK), - 0, - /* - ** Mask out the lun. - */ - SCR_REG_REG (sfbr, SCR_AND, 0x07), - 0, - SCR_RETURN, - 0, - /* - ** No message phase or no IDENTIFY message: - ** return 0. - */ -/*>>>*/ SCR_LOAD_SFBR (0), - 0, - SCR_RETURN, - 0, - -}/*-------------------------< RESEL_TAG >-------------------*/,{ - /* - ** come back to this point - ** to get a SIMPLE_TAG message - ** Wait for a MSG_IN phase. - */ -/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), - 64, - /* - ** message phase - ** It's a trick - read the data - ** without acknowledging it. - */ - SCR_FROM_REG (sbdl), - 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)), - 48, - /* - ** It WAS a SIMPLE_TAG message. - ** get it and ack it! - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_CLR (SCR_ACK), - 0, - /* - ** Wait for the second byte (the tag) - */ -/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), - 24, - /* - ** Get it and ack it! - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_CLR (SCR_ACK|SCR_CARRY), - 0, - SCR_RETURN, - 0, - /* - ** No message phase or no SIMPLE_TAG message - ** or no second byte: return 0. - */ -/*>>>*/ SCR_LOAD_SFBR (0), - 0, - SCR_SET (SCR_CARRY), - 0, - SCR_RETURN, - 0, - -}/*-------------------------< DATA_IO >--------------------*/,{ -/* -** Because Linux does not provide xfer data direction -** to low-level scsi drivers, we must trust the target -** for actual data direction when we cannot guess it. -** The programmed interrupt patches savep, lastp, goalp, -** etc.., and restarts the scsi script at data_out. -*/ - SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)), - SIR_DATA_IO_IS_OUT, - -}/*-------------------------< DATA_IN >--------------------*/,{ -/* -** Because the size depends on the -** #define MAX_SCATTER parameter, -** it is filled in at runtime. -** -** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), -** PADDR (no_data), -** SCR_COPY (sizeof (u_long)), -** KVAR(SCRIPT_KVAR_JIFFIES), -** NADDR (header.stamp.data), -** SCR_MOVE_TBL ^ SCR_DATA_IN, -** offsetof (struct dsb, data[ 0]), -** -** ##===========< i=1; i========= -** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), -** || PADDR (checkatn), -** || SCR_MOVE_TBL ^ SCR_DATA_IN, -** || offsetof (struct dsb, data[ i]), -** ##========================================== -** -** SCR_CALL, -** PADDR (checkatn), -** SCR_JUMP, -** PADDR (no_data), -*/ -0 }/*-------------------------< DATA_OUT >-------------------*/,{ /* ** Because the size depends on the @@ -3169,7 +3278,6 @@ **--------------------------------------------------------- */ 0 /* was (u_long)&ident ? */ - }/*-------------------------< ABORTTAG >-------------------*/,{ /* ** Abort a bad reselection. @@ -3243,12 +3351,12 @@ **========================================================== */ -void ncr_script_fill (struct script * scr) +void ncr_script_fill (struct script * scr, struct scripth * scrh) { int i; ncrcmd *p; - p = scr->tryloop; + p = scrh->tryloop; for (i=0; itryloop + sizeof (scr->tryloop)); + assert ((u_long)p == (u_long)&scrh->tryloop + sizeof (scrh->tryloop)); p = scr->data_in; @@ -3285,7 +3393,7 @@ assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in)); - p = scr->data_out; + p = scrh->data_out; *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)); *p++ =PADDR (no_data); @@ -3307,7 +3415,7 @@ *p++ =SCR_JUMP; *p++ =PADDR (no_data); - assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out)); + assert ((u_long)p == (u_long)&scrh->data_out + sizeof (scrh->data_out)); } /*========================================================== @@ -3319,19 +3427,14 @@ **========================================================== */ -static void ncr_script_copy_and_bind (struct script *script, ncb_p np) +static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len) { ncrcmd opcode, new, old, tmp1, tmp2; - ncrcmd *src, *dst, *start, *end; + ncrcmd *start, *end; int relocs; - np->p_script = vtophys(np->script); - - src = script->start; - dst = np->script->start; - start = src; - end = src + (sizeof (struct script) / 4); + end = src + len/4; while (src < end) { @@ -3418,6 +3521,9 @@ case RELOC_LABEL: new = (old & ~RELOC_MASK) + np->p_script; break; + case RELOC_LABELH: + new = (old & ~RELOC_MASK) + np->p_scripth; + break; case RELOC_SOFTC: new = (old & ~RELOC_MASK) + vtophys(np); break; @@ -3459,10 +3565,6 @@ **========================================================== */ -#define MIN_ASYNC_PD 40 -#define MIN_SYNC_PD 20 - - /* ** Linux host data structure ** @@ -3472,12 +3574,22 @@ */ struct host_data { - struct ncb ncb_data; + struct ncb *ncb; + + char ncb_align[NCB_ALIGN_SIZE-1]; /* Filler for alignment */ + struct ncb _ncb_data; + + char ccb_align[CCB_ALIGN_SIZE-1]; /* Filler for alignment */ + struct ccb _ccb_data; + + char scr_align[SCR_ALIGN_SIZE-1]; /* Filler for alignment */ struct script script_data; + + struct scripth scripth_data; }; /* -** Print something which allow to retreive the controler type, unit, +** Print something which allow to retrieve the controler type, unit, ** target, lun concerned by a kernel message. */ @@ -3487,7 +3599,7 @@ static inline void PRINT_ADDR(Scsi_Cmnd *cmd) { struct host_data *host_data = (struct host_data *) cmd->host->hostdata; - ncb_p np = &host_data->ncb_data; + ncb_p np = host_data->ncb; if (np) PRINT_LUN(np, cmd->target, cmd->lun); } @@ -3530,13 +3642,25 @@ instance->irq = irq; host_data = (struct host_data *) instance->hostdata; - np = &host_data->ncb_data; + /* + ** Align np and first ccb to 32 boundary for cache line + ** bursting when copying the global header. + */ + np = (ncb_p) (((u_long) &host_data->_ncb_data) & NCB_ALIGN_MASK); + host_data->ncb = np; bzero (np, sizeof (*np)); + + np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK); + bzero (np->ccb, sizeof (*np->ccb)); + np->unit = unit; np->chip = chip; np->device_id = device_id; np->revision_id = revision_id; - np->script = &host_data->script_data; + + np->script0 = + (struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK); + np->scripth0 = &host_data->scripth_data; /* ** Initialize timer structure @@ -3562,7 +3686,7 @@ #endif } else - if (bootverbose) + if (bootverbose > 1) printf("%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr); /* @@ -3595,7 +3719,10 @@ np->maxwide = 0; np->rv_scntl3 = 0x13; /* default: 40MHz clock */ np->ns_sync = 25; + np->clock_khz = 40000; + np->clock_divn = 4; np->maxoffs = 8; + np->multiplier = 1; /* ** Get the frequency of the chip's clock. @@ -3609,21 +3736,67 @@ case PCI_DEVICE_ID_NCR_53C860: if (driver_setup.ultra_scsi) { np->rv_scntl3 = 0x15; + np->clock_khz = 80000; np->ns_sync = 12; } else np->rv_scntl3 = 0x35; /* always assume 80MHz clock for 860 */ + np->clock_divn = 5; + break; + case PCI_DEVICE_ID_NCR_53C875: + np->maxwide = 1; + if (driver_setup.special_features) + np->maxoffs = 16; + np->clock_divn = 5; + ncr_getclock(np, revision_id >= 2 ? 2 : 1); + break; + case PCI_DEVICE_ID_NCR_53C895: + np->maxwide = 1; + if (driver_setup.special_features) + np->maxoffs = 31; + np->clock_divn = 7; + ncr_getclock(np, 4); break; + } + + /* + ** Get on-board RAM bus address when supported + */ + switch (device_id) { + case PCI_DEVICE_ID_NCR_53C825: + if (revision_id < 0x10) + break; case PCI_DEVICE_ID_NCR_53C875: - np->maxwide = 1; - if (driver_setup.special_features) - np->maxoffs = 16; - ncr_getclock(np); + case PCI_DEVICE_ID_NCR_53C895: + if (driver_setup.special_features) { + OUTONB(nc_ctest2, 0x8); + np->paddr2 = INL(nc_scr0); + OUTOFFB(nc_ctest2, 0x8); + } break; } + if (bootverbose && np->paddr2) + printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2); + if (bootverbose && np->ns_sync < 25) - printf ("%s: Ultra SCSI support enabled\n", ncr_name(np)); + printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np), + np->ns_sync < 12 ? "-2": ""); + +#ifndef NCR_IOMAPPED + if (np->paddr2 && sizeof(struct script) <= 4096) { + np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096); + if (!np->vaddr2) { + printf("%s: can't map memory mapped IO region\n", ncr_name(np)); +#ifdef NCR_MEMORYMAPPED + goto attach_error; +#endif + } + else + if (bootverbose > 1) + printf("%s: on-board ram mapped at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr); + } +#endif /* !defined NCR_IOMAPPED */ /* ** Fill Linux host instance structure @@ -3646,16 +3819,24 @@ /* ** Patch script to physical addresses */ - ncr_script_fill (&script0); - ncr_script_copy_and_bind (&script0, np); - np->ccb.p_ccb = vtophys (&np->ccb); + ncr_script_fill (&script0, &scripth0); + + np->scripth = np->scripth0; + np->p_scripth = vtophys(np->scripth); + + np->script = (np->vaddr2) ? (struct script *) np->vaddr2 : np->script0; + np->p_script = (np->vaddr2) ? np->paddr2 : vtophys(np->script0); + + ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script)); + ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth)); + np->ccb->p_ccb = vtophys (np->ccb); /* ** init data structure */ np->jump_tcb.l_cmd = SCR_JUMP; - np->jump_tcb.l_paddr = NCB_SCRIPT_PHYS (np, abort); + np->jump_tcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort); #if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED) retry_chip_init: @@ -3701,7 +3882,7 @@ */ #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) # ifdef SCSI_NCR_SHARE_IRQ - if (bootverbose) + if (bootverbose > 1) printf("%s: requesting shared irq %d (dev_id=0x%lx)\n", ncr_name(np), irq, (u_long) np); if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT|SA_SHIRQ, "53c8xx", np)) { @@ -3750,14 +3931,11 @@ ** The middle-level SCSI driver does not ** wait devices to settle. */ -#ifdef SCSI_NCR_SETTLE_TIME -#if SCSI_NCR_SETTLE_TIME > 2 - printf("%s: waiting for scsi devices to settle...\n", ncr_name(np)); -#endif -#if SCSI_NCR_SETTLE_TIME > 0 - DELAY(SCSI_NCR_SETTLE_TIME*1000000); -#endif -#endif + if (driver_setup.settle_time > 2) + printf("%s: waiting %d seconds for scsi devices to settle...\n", + ncr_name(np), driver_setup.settle_time); + if (driver_setup.settle_time) + DELAY(1000000UL * driver_setup.settle_time); /* ** Now let the generic SCSI driver @@ -3794,6 +3972,10 @@ printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128); } + if (np->vaddr2) { + printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096); + unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096); + } #endif if (np->port) { printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); @@ -3859,7 +4041,7 @@ struct Scsi_Host *host = cmd->host; /* Scsi_Device *device = cmd->device; */ struct host_data *host_data = (struct host_data *) host->hostdata; - ncb_p np = &host_data->ncb_data; + ncb_p np = host_data->ncb; tcb_p tp = &np->target[cmd->target]; ccb_p cp; @@ -3867,7 +4049,7 @@ int segments; u_char qidx, nego, idmsg, *msgptr; - u_long msglen, msglen2; + u_int msglen, msglen2; u_long flags; int xfer_direction; @@ -4000,7 +4182,7 @@ */ if (!nego && !tp->period) { - if (SCSI_NCR_MAX_SYNC + if ( 1 #if defined (CDROM_ASYNC) && ((tp->inqdata[0] & 0x1f) != 5) #endif @@ -4051,7 +4233,7 @@ idmsg = M_IDENTIFY | cmd->lun; - if (cp != &np->ccb && ((np->disc && !(tp->usrflag & UF_NODISC)) || cp->tag)) + if (cp != np->ccb && ((np->disc && !(tp->usrflag & UF_NODISC)) || cp->tag)) idmsg |= 0x40; msgptr = cp->scsi_smsg; @@ -4187,7 +4369,7 @@ cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16; break; case XferOut: - cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_out); + cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out); cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16; break; case XferNone: @@ -4295,7 +4477,7 @@ printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np), np->squeueput, (unsigned)(np->script->startpos[0]- - (NCB_SCRIPT_PHYS (np, tryloop)))); + (NCB_SCRIPTH_PHYS (np, tryloop)))); /* ** Script processor may be waiting for reselect. @@ -4329,18 +4511,67 @@ struct Scsi_Host *host = cmd->host; /* Scsi_Device *device = cmd->device; */ struct host_data *host_data = (struct host_data *) host->hostdata; - ncb_p np = &host_data->ncb_data; + ncb_p np = host_data->ncb; + ccb_p cp; u_long flags; + int found; save_flags(flags); cli(); - - reset_waiting_list(np); - - OUTB (nc_scntl1, CRST); +/* + * Return immediately from recursive call + */ + if (np->resetting) { + restore_flags(flags); + return SCSI_RESET_PUNT; + } + ++np->resetting; +/* + * Perform chip reset, SCSI reset, wait 2 seconds + */ + OUTB (nc_istat, SRST); DELAY (1000); + OUTB (nc_istat, 0); + OUTB (nc_scntl1, CRST); + DELAY (100); + OUTB (nc_scntl1, 0); + DELAY (2000000); +/* + * First, look in the wakeup list + */ + for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) { + /* + ** look for the ccb of this command. + */ + if (cp->host_status == HS_IDLE) continue; + if (cp->cmd == cmd) { + found = 1; + break; + } + } +/* + * Then, look in the waiting list + */ + if (!found && retrieve_from_waiting_list(0, np, cmd)) + found = 1; +/* + * Reinitialise the NCR and wake-up pending commands + */ ncr_init(np, "scsi bus reset", HS_RESET); - np->disc = 1; +/* + * Complete awaiting commands with DID_RESET + */ + reset_waiting_list(np); +/* + * If the involved command was not in a driver queue, complete it + * with DID_RESET, in order to keep it alive. + */ + if (!found && cmd && cmd->scsi_done) { + cmd->result = ScsiResult(DID_RESET, 0); + cmd->scsi_done(cmd); + } + + --np->resetting; restore_flags(flags); @@ -4361,7 +4592,7 @@ struct Scsi_Host *host = cmd->host; /* Scsi_Device *device = cmd->device; */ struct host_data *host_data = (struct host_data *) host->hostdata; - ncb_p np = &host_data->ncb_data; + ncb_p np = host_data->ncb; ccb_p cp; u_long flags; int found; @@ -4381,7 +4612,7 @@ /* * Then, look in the wakeup list */ - for (found=0, cp=&np->ccb; cp; cp=cp->link_ccb) { + for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) { /* ** look for the ccb of this command. */ @@ -4502,17 +4733,10 @@ OUTB(nc_ctest3, np->sv_ctest3); OUTB(nc_ctest4, np->sv_ctest4); OUTB(nc_ctest5, np->sv_ctest5); + OUTB(nc_gpcntl, np->sv_gpcntl); + OUTB(nc_stest2, np->sv_stest2); - if (np->uf_doubler) { - OUTB(nc_stest1, DBLEN); /* Enable clock doubler */ - DELAY(10); - OUTB(nc_stest3, 0x20); /* Halt the scsi clock */ - OUTB(nc_scntl3, np->sv_scntl3); - OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock doubler */ - OUTB(nc_stest3, 0x00); /* Restart scsi clock */ - } - else - OUTB(nc_scntl3, np->sv_scntl3); + ncr_selectclock(np, np->sv_scntl3); /* ** Release Memory mapped IO region and IO mapped region @@ -4520,9 +4744,13 @@ #ifndef NCR_IOMAPPED #ifdef DEBUG - printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->reg, 128); + printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); #endif unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128); +#ifdef DEBUG + printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096); +#endif + unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096); #endif #ifdef DEBUG @@ -4534,8 +4762,8 @@ ** Free allocated ccb(s) */ - while ((cp=np->ccb.link_ccb) != NULL) { - np->ccb.link_ccb = cp->link_ccb; + while ((cp=np->ccb->link_ccb) != NULL) { + np->ccb->link_ccb = cp->link_ccb; if (cp->host_status) { printf("%s: shall free an active ccb (host_status=%d)\n", ncr_name(np), cp->host_status); @@ -4889,7 +5117,7 @@ ** complete all jobs that are not IDLE. */ - ccb_p cp = &np->ccb; + ccb_p cp = np->ccb; while (cp) { switch (cp->host_status) { @@ -4918,7 +5146,7 @@ /*=============================================================== ** ** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 -** transfers. 32,64,128 are only supported by 875 chips. +** transfers. 32,64,128 are only supported by 875 and 895 chips. ** We use log base 2 (burst length) as internal code, with ** value 0 meaning "burst disabled". ** @@ -4995,8 +5223,8 @@ */ np->squeueput = 0; - np->script->startpos[0] = NCB_SCRIPT_PHYS (np, tryloop); - np->script->start0 [0] = SCR_INT ^ IFFALSE (0); + np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop); + np->script0->start0 [0] = SCR_INT ^ IFFALSE (0); /* ** Wakeup all pending jobs. @@ -5043,10 +5271,8 @@ /** NCR53C810A or NCR53C860 **/ if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) || ChipDevice == PCI_DEVICE_ID_NCR_53C860) { - if (!driver_setup.special_features) - burst_max = burst_max < 4 ? burst_max : 4; - else { - burst_max = burst_max < 4 ? burst_max : 4; + burst_max = burst_max < 4 ? burst_max : 4; + if (driver_setup.special_features) { np->rv_dmode = BOF | ERMP | ERL; /* burst op-code fetch, read multiple */ /* read line */ @@ -5056,9 +5282,10 @@ } } else -/** NCR53C825A or NCR53C875 **/ +/** NCR53C825A or NCR53C875 or NCR53C895 **/ if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) || - ChipDevice == PCI_DEVICE_ID_NCR_53C875) { + ChipDevice == PCI_DEVICE_ID_NCR_53C875 || + ChipDevice == PCI_DEVICE_ID_NCR_53C895) { if (!driver_setup.special_features) burst_max = burst_max < 4 ? burst_max : 4; else { @@ -5069,7 +5296,7 @@ np->rv_dcntl = PFEN | CLSE; /* prefetch, cache line size */ np->rv_ctest3 = WRIE; /* write and invalidate */ - np->rv_ctest5 = 0x20; /* dma fifo 536 (0x20) */ + np->rv_ctest5 = 0x20; /* large dma fifo (0x20) */ } } /** OTHERS **/ @@ -5078,26 +5305,60 @@ } #endif /* SCSI_NCR_TRUST_BIOS_SETTING */ +#if 0 + /* + * Do not enable read-multiple for 810A revision 0x11 + */ + if (np->device_id == PCI_DEVICE_ID_NCR_53C810 && np->revision_id == 0x11) + np->rv_dmode &= (~ERMP); +#endif + /* * Prepare initial io register bits for burst length */ ncr_init_burst(np, burst_max); - if (bootverbose > 1) { - printf ("%s: initial value of dmode/ctest4/ctest5 = 0x%02x/0x%02x/0x%02x\n", - ncr_name(np), np->sv_dmode, np->sv_ctest4, np->sv_ctest5); + /* + ** Set differential mode. + */ + switch(driver_setup.diff_support) { + case 3: + if (INB(nc_gpreg) & 0x08) + break; + case 2: + np->rv_stest2 |= 0x20; + break; + case 1: + np->rv_stest2 |= (np->sv_stest2 & 0x20); + break; + default: + break; } - if (bootverbose) { - printf ("%s: final value of dmode/ctest4/ctest5 = 0x%02x/0x%02x/0x%02x\n", - ncr_name(np), np->rv_dmode, np->rv_ctest4, np->rv_ctest5); + + /* + ** Set irq mode. + */ + switch(driver_setup.irqm) { + case 2: + np->rv_dcntl |= IRQM; + break; + case 1: + np->rv_stest2 |= (np->sv_dcntl & IRQM); + break; + default: + break; } -#if 0 - printf("%s: bios: dmode=0x%02x, dcntl=0x%02x, ctest3=0x%02x, ctest4=0x%02x, ctest5=0x%02x\n", - ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); - printf("%s: used: dmode=0x%02x, dcntl=0x%02x, ctest3=0x%02x, ctest4=0x%02x, ctest5=0x%02x\n", - ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); -#endif + if (bootverbose > 1) { + printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); + } + if (bootverbose > 1) { + printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); + if (np->rv_stest2 & 0x20) + printf ("%s: setting up differential mode\n", ncr_name(np)); + } OUTB (nc_istat, 0x00 ); /* Remove Reset, abort ... */ if (driver_setup.scsi_parity) @@ -5107,18 +5368,8 @@ OUTB (nc_scntl1, 0x00 ); /* odd parity, and remove CRST!! */ - if (np->uf_doubler) { - if (bootverbose >= 2) - printf ("%s: enabling clock doubler\n", ncr_name(np)); - OUTB(nc_stest1, DBLEN); /* Enable clock doubler */ - DELAY(10); - OUTB(nc_stest3, 0x20); /* Halt the scsi clock */ - OUTB(nc_scntl3, 0x05); /* Safe timing for now */ - OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock doubler */ - OUTB(nc_stest3, 0x00); /* Restart scsi clock */ - } + ncr_selectclock(np, np->rv_scntl3); - OUTB (nc_scntl3, np->rv_scntl3);/* timing prescaler */ OUTB (nc_scid , RRE|np->myaddr);/* host adapter SCSI address */ OUTW (nc_respid, 1ul<myaddr);/* id to respond to */ OUTB (nc_istat , SIGP ); /* Signal Process */ @@ -5135,7 +5386,7 @@ else OUTB (nc_ctest4, 0x00|np->rv_ctest4); /* disable master parity checking */ - OUTB (nc_stest2, EXT ); /* Extended Sreq/Sack filtering */ + OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */ OUTB (nc_stest3, TE ); /* TolerANT enable */ OUTB (nc_stime0, 0x0d ); /* HTH = disable STO = 0.4 sec. */ /* 0.25 sec recommended for scsi 1 */ @@ -5145,17 +5396,15 @@ ** Have to renegotiate synch mode. */ - usrsync = 255; - - if (driver_setup.default_sync && SCSI_NCR_MAX_SYNC) { - u_long period; - period =1000000/driver_setup.default_sync; /* ns = 10e6 / kHz */ - if (period <= 11 * 50) { - if (period < 4 * np->ns_sync) + usrsync = driver_setup.default_sync; + if (usrsync != 255) { + if (4 * usrsync <= 11 * 50) { + if (usrsync < np->ns_sync) { usrsync = np->ns_sync; - else - usrsync = period / 4; - }; + } + } + else + usrsync = 255; }; /* @@ -5163,7 +5412,7 @@ ** Have to renegotiate wide mode. */ - usrwide = (SCSI_NCR_MAX_WIDE); + usrwide = driver_setup.max_wide; if (usrwide > np->maxwide) usrwide=np->maxwide; /* @@ -5189,6 +5438,27 @@ } /* + ** Enable GPIO0 pin for writing. + ** Patch the script for LED support. + */ + + if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) { + OUTOFFB (nc_gpcntl, 0x01); + np->script0->reselect[0] = SCR_REG_REG(gpreg, SCR_OR, 0x01); + np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe); + np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe); + } + + /* + ** Upload the script into on-board RAM + */ + if (np->vaddr2) { + if (bootverbose) + printf ("%s: copying script fragments into the on-board RAM ...\n", ncr_name(np)); + bcopy(np->script0, np->script, sizeof(struct script)); + } + + /* ** enable ints */ @@ -5218,7 +5488,10 @@ u_long minsync = tp->usrsync; - if (driver_setup.ultra_scsi) { + if (driver_setup.ultra_scsi >= 2) { + if (minsync < 10) minsync=10; + } + else if (driver_setup.ultra_scsi == 1) { if (minsync < 12) minsync=12; } else { @@ -5264,6 +5537,92 @@ /*========================================================== ** +** Get clock factor and sync divisor. +** +**========================================================== +*/ + +#define SCSI_NCR_USE_ALL_DIVISORS + +/* +** NCR chip clock divisor table. +** Multiplied by 2x2000000 in order to avoid useless operations in +** the code that gets clock factor and sync divisor from sync factor. +*/ +#define _2M 2000000 +static u_long ncr_div2_2M[] = {2*_2M, 3*_2M, 4*_2M, 6*_2M, 8*_2M, 12*_2M, 16*_2M}; + +/* +** Get clock factor and sync divisor for a given sync factor period. +** Returns the clock factor, scntl3 and resulting period. +*/ +static int ncr_getsync(ncb_p np, u_char fac, u_char *fakp, u_char *scntl3p) +{ + u_long clk = np->clock_khz; /* Clock in kHz */ + int idiv = np->clock_divn; /* # divisors supported */ + u_long fak, per, per_clk; + + /* + ** Compute the synchronous period in nano-seconds + */ + if (fac <= 10) per = 25; + else if (fac == 11) per = 30; + else if (fac == 12) per = 50; + else per = 4 * fac; + + /* + ** Find the greatest divisor that allows an input speed + ** faster than the period. + */ + per_clk = per * clk; + while (--idiv >= 0) { +#ifndef SCSI_NCR_USE_ALL_DIVISORS + if (idiv & 1) continue; +#endif + if (ncr_div2_2M[idiv] <= per_clk) break; + } + if (idiv < 0) idiv = 0; /* Should never happen */ + + /* + ** Calculate the lowest clock factor that allows an output + ** speed not faster than the period. + */ + fak = (4 * per_clk - 1) / ncr_div2_2M[idiv] + 1; + per = (fak * ncr_div2_2M[idiv]) / (4 * clk); + +#ifdef SCSI_NCR_USE_ALL_DIVISORS + /* + ** Try the next divisor and choose the one that give + ** the fastest output speed. + */ + if (idiv >= 1 && fak < 8) { + u_long fak2, per2; + fak2 = (4 * per_clk - 1) / ncr_div2_2M[idiv-1] + 1; + per2 = (fak2 * ncr_div2_2M[idiv-1]) / (4 * clk); + if (per2 < per && fak2 <= 8) { + fak = fak2; + per = per2; + --idiv; + } + } +#endif + if (fak < 4) fak = 4; /* Should never happen */ + + /* + ** Compute and return sync parameters for the ncr + */ + *fakp = fak - 4; + *scntl3p = ((idiv+1) << 4) + (per < 100 ? 0x80 : 0); + +#ifdef DEBUG +printf("fac=%d idiv=%d per=%d fak=%x ", fac, idiv, per, *fakp); +#endif + + return per; +} + +/*========================================================== +** ** Switch sync mode for current job and it's target ** **========================================================== @@ -5274,7 +5633,7 @@ Scsi_Cmnd *cmd; tcb_p tp; u_char target = INB (nc_ctest0) & 0x0f; - u_char p2; + u_char idiv; assert (cp); if (!cp) return; @@ -5292,18 +5651,16 @@ /* ** Deduce the value of controller sync period from scntl3. - ** p2 is twice this value since we do integer calculations. - * (12.5 ns would give inaccurate results) */ - p2 = (scntl3 & 0x07) == 0x05 ? 25 : 50; - switch(scntl3 & 0x70) { - case 0x50: p2 *= 4; break; - case 0x30: p2 *= 2; break; - default: break; - } - - tp->period= sxfer&0x1f ? (((sxfer>>5)+4) * p2)/2 : 0xffff; + idiv = ((scntl3 >> 4) & 0x7); + if ((sxfer & 0x1f) && idiv) + tp->period = (((sxfer>>5)+4)*ncr_div2_2M[idiv-1])/(4*np->clock_khz); + else + tp->period = 0xffff; + /* + ** Stop there if sync parameters are unchanged + */ if (tp->sval == sxfer && tp->wval == scntl3) return; tp->sval = sxfer; tp->wval = scntl3; @@ -5315,16 +5672,29 @@ if (sxfer & 0x01f) { unsigned f10 = 10000 << (tp->widedone ? tp->widedone -1 : 0); unsigned mb10 = (f10 + tp->period/2) / tp->period; + char *msg; + /* ** Disable extended Sreq/Sack filtering */ - if (tp->period <= 200) OUTB (nc_stest2, 0); - printf ("%s%d.%d MB/s (%d ns, offset %d)\n", - tp->widedone > 1 ? - (tp->period < 100 ? "ULTRA WIDE SCSI " : - (tp->period < 200 ? "FAST WIDE SCSI-2 ":"WIDE ")) : - (tp->period < 100 ? "ULTRA SCSI " : - (tp->period < 200 ? "FAST SCSI-2 ":"")), + if (tp->period <= 200) OUTOFFB (nc_stest2, EXT); + + /* + ** Bells and whistles ;-) + */ + msg = ""; + if (tp->widedone > 1) { + if (tp->period < 50) msg = "ULTRA-2 WIDE SCSI "; + else if (tp->period < 100) msg = "ULTRA WIDE SCSI "; + else if (tp->period < 200) msg = "FAST WIDE SCSI-2 "; + } + else { + if (tp->period < 50) msg = "ULTRA-2 SCSI "; + else if (tp->period < 100) msg = "ULTRA SCSI "; + else if (tp->period < 200) msg = "FAST SCSI-2 "; + } + + printf ("%s%d.%d MB/s (%d ns, offset %d)\n", msg, mb10 / 10, mb10 % 10, tp->period, sxfer & 0x1f); } else printf ("asynchronous.\n"); @@ -5339,7 +5709,7 @@ /* ** patch ALL ccbs of this target. */ - for (cp = &np->ccb; cp; cp = cp->link_ccb) { + for (cp = np->ccb; cp; cp = cp->link_ccb) { if (!cp->cmd) continue; if (cp->cmd->target != target) continue; cp->sync_status = sxfer; @@ -5395,7 +5765,7 @@ /* ** patch ALL ccbs of this target. */ - for (cp = &np->ccb; cp; cp = cp->link_ccb) { + for (cp = np->ccb; cp; cp = cp->link_ccb) { if (!cp->cmd) continue; if (cp->cmd->target != target) continue; cp->wide_status = scntl3; @@ -5627,6 +5997,7 @@ t = (thistime - np->heartbeat) / HZ; if (t<2) np->latetime=0; else np->latetime++; +#if 0 if (np->latetime>5) { /* ** If there are no requests, the script @@ -5637,6 +6008,7 @@ OUTB (nc_istat, SIGP); } +#endif /*---------------------------------------------------- ** @@ -5645,7 +6017,7 @@ **---------------------------------------------------- */ - for (cp=&np->ccb; cp; cp=cp->link_ccb) { + for (cp=np->ccb; cp; cp=cp->link_ccb) { /* ** look for timed out ccbs. */ @@ -6077,7 +6449,7 @@ */ dsa = INL (nc_dsa); - cp = &np->ccb; + cp = np->ccb; while (cp && (CCB_PHYS (cp, phys) != dsa)) cp = cp->link_ccb; @@ -6091,7 +6463,7 @@ */ scratcha = INL (nc_scratcha); - diff = scratcha - NCB_SCRIPT_PHYS (np, tryloop); + diff = scratcha - NCB_SCRIPTH_PHYS (np, tryloop); /* assert ((diff <= MAX_START * 20) && !(diff % 20));*/ @@ -6122,59 +6494,79 @@ { u_int32 dbc; u_int32 rest; - u_int32 dsa; u_int32 dsp; + u_int32 dsa; u_int32 nxtdsp; u_int32 *vdsp; u_int32 oadr, olen; u_int32 *tblp; ncrcmd *newcmd; - u_char cmd, sbcl, ss0, ss2, ctest5; - u_short delta; + u_char cmd, sbcl; ccb_p cp; - dsp = INL (nc_dsp); - dsa = INL (nc_dsa); - dbc = INL (nc_dbc); - ss0 = INB (nc_sstat0); - ss2 = INB (nc_sstat2); - sbcl= INB (nc_sbcl); - - if (driver_setup.special_features) - ctest5 = INB (nc_ctest5); - else - ctest5 = 0; - - cmd = dbc >> 24; - rest= dbc & 0xffffff; + dsp = INL (nc_dsp); + dbc = INL (nc_dbc); + sbcl = INB (nc_sbcl); - if (ctest5 & 0x20) - delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff; - else - delta=(INB (nc_dfifo) - rest) & 0x7f; + cmd = dbc >> 24; + rest = dbc & 0xffffff; /* - ** The data in the dma fifo has not been transfered to - ** the target -> add the amount to the rest - ** and clear the data. - ** Check the sstat2 register in case of wide transfer. + ** Take into account dma fifo and various buffers and latches, + ** only if the interrupted phase in an OUTPUT phase. */ - if (! (INB(nc_dstat) & DFE)) rest += delta; - if (ss0 & OLF) rest++; - if (ss0 & ORF) rest++; - if (INB(nc_scntl3) & EWS) { - if (ss2 & OLF1) rest++; - if (ss2 & ORF1) rest++; - }; - OUTONB (nc_ctest3, CLF ); /* clear dma fifo */ - OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + if ((cmd & 1) == 0) { + u_char ctest5, ss0, ss2; + u_short delta; + + if (!(INB(nc_dstat) & DFE)) { + ctest5 = (np->rv_ctest5 & 0x20) ? INB (nc_ctest5) : 0; + if (ctest5 & 0x20) + delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff; + else + delta=(INB (nc_dfifo) - rest) & 0x7f; + } else { + delta = 0; + } + + /* + ** The data in the dma fifo has not been transfered to + ** the target -> add the amount to the rest + ** and clear the data. + ** Check the sstat2 register in case of wide transfer. + */ + + rest += delta; + ss0 = INB (nc_sstat0); + if (ss0 & OLF) rest++; + if (ss0 & ORF) rest++; + if (INB(nc_scntl3) & EWS) { + ss2 = INB (nc_sstat2); + if (ss2 & OLF1) rest++; + if (ss2 & ORF1) rest++; + }; + + OUTONB (nc_ctest3, CLF ); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + + if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) + printf ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7, + (unsigned) rest, (unsigned) delta, ss0); + + } else { + if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) + printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest); + if (!(INB(nc_dstat) & DFE)) + printf("INPUT phase mismatch with DMA fifo not empty, P%x%x RL=%d\n", + cmd&7, sbcl&7, rest); + } /* ** locate matching cp */ dsa = INL (nc_dsa); - cp = &np->ccb; + cp = np->ccb; while (cp && (CCB_PHYS (cp, phys) != dsa)) cp = cp->link_ccb; @@ -6200,19 +6592,18 @@ } else if (dsp == vtophys (&cp->patch[6])) { vdsp = &cp->patch[4]; nxtdsp = vdsp[3]; - } else { + } else if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) { vdsp = (u_int32 *) ((char*)np->script - np->p_script + dsp -8); nxtdsp = dsp; + } else { + vdsp = (u_int32 *) ((char*)np->scripth - np->p_scripth + dsp -8); + nxtdsp = dsp; }; /* ** log the information */ - if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) { - printf ("P%x%x ",cmd&7, sbcl&7); - printf ("RL=%d D=%d SS0=%x ", - (unsigned) rest, (unsigned) delta, ss0); - }; + if (DEBUG_FLAGS & DEBUG_PHASE) { printf ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", cp, np->header.cp, @@ -6349,7 +6740,7 @@ ** lookup the ccb */ dsa = INL (nc_dsa); - cp = &np->ccb; + cp = np->ccb; while (cp && (CCB_PHYS (cp, phys) != dsa)) cp = cp->link_ccb; @@ -6369,7 +6760,7 @@ ** We have to patch the script context with DATA OUT context and ** restart processing at data out script address. */ - cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_out); + cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out); cp->phys.header.goalp = cp->phys.header.savep +20 +cp->segments*16; cp->phys.header.lastp = cp->phys.header.savep; np->header.savep = cp->phys.header.savep; @@ -6415,7 +6806,7 @@ if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+ restart job ..\n"); OUTL (nc_dsa, CCB_PHYS (cp, phys)); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, getcc)); + OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, getcc)); return; }; @@ -6602,38 +6993,11 @@ /* ** Check against controller limits. - ** -------------------------------- - ** per < 25 fast20 - ** per < 50 fast - ** per < 100 slow - ** Use a value p2 twice the controller limit in order to - ** not do wrong integer calculation for 80 MHz clock. - ** (12.5x2 = 25ns). - ** Compute scntl3&0xf0 sync clock divisor for 50 ns period - ** from the async pre-scaler. - ** Ajust it according to actual controller sync period. - ** - 0x40 divides it by 4 -> 50/4 = 12.5ns - ** - 0x20 divides it by 2 -> 50/2 = 25 ns - ** Similar stuff is used in ncr_getclock(). */ fak = 7; scntl3 = 0; if (ofs != 0) { - u_char p2; - - p2 = 100; - scntl3 = (np->rv_scntl3 & 0x07) << 4; - - if (per < 25) { - p2 = 25; - scntl3 = (scntl3 - 0x40) | 0x80; - } - else if (per < 50) { - p2 = 50; - scntl3 = scntl3 - 0x20; - } - - fak = (8 * per - 1) / p2 - 3; + (void) ncr_getsync(np, per, &fak, &scntl3); if (fak > 7) { chg = 1; ofs = 0; @@ -6942,7 +7306,7 @@ /* ** Look for a disconnected job. */ - cp = &np->ccb; + cp = np->ccb; while (cp && cp->host_status != HS_DISCONNECT) cp = cp->link_ccb; @@ -7020,7 +7384,7 @@ if ((!cp) && lp && lp->actccbs > 0) return ((ccb_p) 0); - if (!cp) cp = &np->ccb; + if (!cp) cp = np->ccb; /* ** Wait until available. @@ -7072,7 +7436,7 @@ cp -> host_status = HS_IDLE; cp -> magic = 0; #if 0 - if (cp == &np->ccb) + if (cp == np->ccb) wakeup ((caddr_t) cp); #endif } @@ -7123,7 +7487,7 @@ tp->call_lun.l_paddr = NCB_SCRIPT_PHYS (np, resel_lun); tp->jump_lcb.l_cmd = (SCR_JUMP); - tp->jump_lcb.l_paddr = NCB_SCRIPT_PHYS (np, abort); + tp->jump_lcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort); np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb); } @@ -7135,7 +7499,7 @@ /* ** Allocate a lcb */ - lp = (lcb_p) m_alloc (sizeof (struct lcb)); + lp = (lcb_p) m_alloc (sizeof (struct lcb), LCB_ALIGN_SHIFT); if (!lp) return; if (DEBUG_FLAGS & DEBUG_ALLOC) { @@ -7154,7 +7518,7 @@ lp->call_tag.l_paddr = NCB_SCRIPT_PHYS (np, resel_tag); lp->jump_ccb.l_cmd = (SCR_JUMP); - lp->jump_ccb.l_paddr = NCB_SCRIPT_PHYS (np, aborttag); + lp->jump_ccb.l_paddr = NCB_SCRIPTH_PHYS (np, aborttag); lp->actlink = 1; @@ -7186,7 +7550,7 @@ /* ** Allocate a ccb */ - cp = (ccb_p) m_alloc (sizeof (struct ccb)); + cp = (ccb_p) m_alloc (sizeof (struct ccb), CCB_ALIGN_SHIFT); if (!cp) return; @@ -7224,8 +7588,8 @@ /* ** Chain into wakeup list */ - cp->link_ccb = np->ccb.link_ccb; - np->ccb.link_ccb = cp; + cp->link_ccb = np->ccb->link_ccb; + np->ccb->link_ccb = cp; /* ** Chain into CCB list @@ -7401,7 +7765,7 @@ /* ** init */ - pc = NCB_SCRIPT_PHYS (np, snooptest); + pc = NCB_SCRIPTH_PHYS (np, snooptest); host_wr = 1; ncr_wr = 2; /* @@ -7445,11 +7809,11 @@ /* ** Check termination position. */ - if (pc != NCB_SCRIPT_PHYS (np, snoopend)+8) { + if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) { printf ("CACHE TEST FAILED: script execution failed.\n"); printf ("start=%08lx, pc=%08lx, end=%08lx\n", - (u_long) NCB_SCRIPT_PHYS (np, snooptest), pc, - (u_long) NCB_SCRIPT_PHYS (np, snoopend) +8); + (u_long) NCB_SCRIPTH_PHYS (np, snooptest), pc, + (u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8); return (0x40); }; /* @@ -7482,29 +7846,14 @@ **========================================================== */ - #ifdef SCSI_NCR_PROFILE -#if 0 -/* -** Compute the difference in milliseconds. -*/ - -static int ncr_delta (u_long from, u_long to) -{ - if (!from) return (-1); - if (!to) return (-2); - return ((to - from) * 1000 / HZ ); -} -#else - /* ** Compute the difference in jiffies ticks. */ #define ncr_delta(from, to) \ ( ((to) && (from))? (to) - (from) : -1 ) -#endif #define PROFILE cp->phys.header.stamp static void ncb_profile (ncb_p np, ccb_p cp) @@ -7634,10 +7983,6 @@ **---------------------------------------------------------- */ -#ifndef NCR_CLOCK -# define NCR_CLOCK 40 -#endif /* NCR_CLOCK */ - /* * calculate NCR SCSI clock frequency (in KHz) */ @@ -7687,67 +8032,114 @@ return ms ? ((1 << gen) * 4340) / ms : 0; } -static void ncr_getclock (ncb_p np) +/* + * Select NCR SCSI clock frequency + */ +static void ncr_selectclock(ncb_p np, u_char scntl3) +{ + if (np->multiplier < 2) { + OUTB(nc_scntl3, scntl3); + return; + } + + if (bootverbose >= 2) + printf ("%s: enabling clock multiplier\n", ncr_name(np)); + + OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ + if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */ + int i = 20; + while (!(INB(nc_stest4) & 0x20) && --i > 0) + DELAY(20); + if (!i) + printf("%s: the chip cannot lock the frequency\n", ncr_name(np)); + } else /* Wait 20 micro-seconds for doubler */ + DELAY(20); + OUTB(nc_stest3, 0x20); /* Halt the scsi clock */ + OUTB(nc_scntl3, scntl3); + OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ + OUTB(nc_stest3, 0x00); /* Restart scsi clock */ +} + + +/* + * Get/probe NCR SCSI clock frequency + */ +static void ncr_getclock (ncb_p np, int mult) { unsigned char scntl3 = INB(nc_scntl3); unsigned char stest1 = INB(nc_stest1); + unsigned f1; + + np->multiplier = 1; + f1 = 40000; /* - ** Always false, except for 875 with clock doubler selected - ** If true, disable clock doubler and assume 40 MHz clock. + ** True with 875 or 895 with clock multiplier selected */ - if ((stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { - if (driver_setup.ultra_scsi) { - if (bootverbose >= 2) - printf ("%s: clock doubler found\n", ncr_name(np)); - np->uf_doubler = 1; - scntl3 = 5; - } - else { + if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { + if (bootverbose >= 2) + printf ("%s: clock multiplier found\n", ncr_name(np)); + np->multiplier = mult; + } + + /* + ** If multiplier not found or scntl3 not 7,5,3, + ** reset chip and get frequency from general purpose timer. + ** Otherwise trust scntl3 BIOS setting. + */ + if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { + unsigned f2; + + OUTB(nc_istat, SRST); DELAY(5); OUTB(nc_istat, 0); + + (void) ncrgetfreq (np, 11); /* throw away first result */ + f1 = ncrgetfreq (np, 11); + f2 = ncrgetfreq (np, 11); + + if (bootverbose) + printf ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2); + + if (f1 > f2) f1 = f2; /* trust lower result */ + + if (f1 < 45000) f1 = 40000; + else if (f1 < 55000) f1 = 50000; + else f1 = 80000; + + if (f1 < 80000 && mult > 1) { if (bootverbose >= 2) - printf ("%s: disabling clock doubler\n", ncr_name(np)); - OUTB(nc_stest1, 0); - np->sv_scntl3 = 3; /* Fix scntl3 for next insmod */ - scntl3 = 3; + printf ("%s: clock multiplier assumed\n", ncr_name(np)); + np->multiplier = mult; } } else { - if ((scntl3 & 7) == 0) { - unsigned f1, f2; - /* throw away first result */ - (void) ncrgetfreq (np, 11); - f1 = ncrgetfreq (np, 11); - f2 = ncrgetfreq (np, 11); - - if (bootverbose) - printf ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2); - if (f1 > f2) f1 = f2; /* trust lower result */ - if (f1 > 45000) { - scntl3 = 5; /* >45Mhz: assume 80MHz */ - } else { - scntl3 = 3; /* <45Mhz: assume 40MHz */ - } - } + if ((scntl3 & 7) == 3) f1 = 40000; + else if ((scntl3 & 7) == 5) f1 = 80000; + else f1 = 160000; + + f1 /= np->multiplier; } /* - ** Assume 40 Mhz clock if no dependable value supplied by BIOS. + ** Compute controller synchronous parameters. */ - if ((scntl3 & 7) < 3) { - scntl3 = 3; - } + f1 *= np->multiplier; + np->clock_khz = f1; + np->ns_sync = 25; - if (driver_setup.ultra_scsi && ((scntl3 & 0x7) == 0x5)) { - np->ns_sync = 12; - np->rv_scntl3 = ((scntl3 & 0x7) << 4) -0x40 + (scntl3 & 0x7); + if (f1 >= 160000) { + if (driver_setup.ultra_scsi) np->ns_sync = 10; + np->rv_scntl3 = 7; + } + else if (f1 >= 80000) { + if (driver_setup.ultra_scsi) np->ns_sync = 12; + np->rv_scntl3 = 5; } else { - np->ns_sync = 25; - np->rv_scntl3 = ((scntl3 & 0x7) << 4) -0x20 + (scntl3 & 0x7); + np->rv_scntl3 = 3; } - if (bootverbose) { + if (bootverbose > 1) { printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n", - ncr_name(np), INB(nc_scntl3), np->rv_scntl3); + ncr_name(np), scntl3, np->rv_scntl3); } } @@ -7768,8 +8160,10 @@ ** CTEST4 0x80 ** 0x80 burst disabled ** CTEST5 0x24 -** 0x20 dma fifo 536 (875 only) -** 0x04 burst len 32/64/128 (875 only) +** 0x20 large dma fifo (875 and 895 only) +** 0x04 burst len 32/64/128 (875 and 895 only) +** GPCNTL general purpose control register +** STEST2 0x20 differential mode */ static void ncr_save_bios_setting(ncb_p np) @@ -7780,6 +8174,8 @@ np->sv_ctest3 = INB(nc_ctest3) & 0x01; np->sv_ctest4 = INB(nc_ctest4) & 0x80; np->sv_ctest5 = INB(nc_ctest5) & 0x24; + np->sv_gpcntl = INB(nc_gpcntl); + np->sv_stest2 = INB(nc_stest2) & 0x20; } /*===================== LINUX ENTRY POINTS SECTION ==========================*/ @@ -7855,13 +8251,26 @@ driver_setup.default_tags = val; } else if (!strncmp(cur, "sync:", 5)) - driver_setup.default_sync = val * 1000; + driver_setup.default_sync = val; else if (!strncmp(cur, "verb:", 5)) driver_setup.verbose = val; else if (!strncmp(cur, "debug:", 6)) driver_setup.debug = val; else if (!strncmp(cur, "burst:", 6)) driver_setup.burst_max = val; + else if (!strncmp(cur, "led:", 4)) + driver_setup.led_pin = val; + else if (!strncmp(cur, "wide:", 5)) + driver_setup.max_wide = val? 1:0; + else if (!strncmp(cur, "settle:", 7)) + driver_setup.settle_time= val; + else if (!strncmp(cur, "diff:", 5)) + driver_setup.diff_support= val; + else if (!strncmp(cur, "irqm:", 5)) + driver_setup.irqm = val; + + else if (!strncmp(cur, "safe:", 5) && val) + memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup)); if ((cur = strchr(cur, ',')) != NULL) ++cur; @@ -7916,19 +8325,24 @@ #define YesNo(y) y ? 'y' : 'n' if (bootverbose >= 2) { - printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d\n", - YesNo(driver_setup.disconnection), - YesNo(driver_setup.special_features), - YesNo(driver_setup.ultra_scsi), - driver_setup.default_tags, - driver_setup.default_sync/1000, - driver_setup.burst_max); - printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x\n", - YesNo(driver_setup.master_parity), - YesNo(driver_setup.scsi_parity), - YesNo(driver_setup.force_sync_nego), - driver_setup.verbose, - driver_setup.debug); + printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n", + YesNo(driver_setup.disconnection), + YesNo(driver_setup.special_features), + YesNo(driver_setup.ultra_scsi), + driver_setup.default_tags, + driver_setup.default_sync, + driver_setup.burst_max, + YesNo(driver_setup.max_wide), + driver_setup.diff_support); + printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n", + YesNo(driver_setup.master_parity), + YesNo(driver_setup.scsi_parity), + YesNo(driver_setup.force_sync_nego), + driver_setup.verbose, + driver_setup.debug, + YesNo(driver_setup.led_pin), + driver_setup.settle_time, + driver_setup.irqm); } #undef YesNo @@ -8053,13 +8467,6 @@ " match expected 0x%04x\n", (unsigned int) device_id, (unsigned int) expected_id ); - if (max_revision != -1 && revision > max_revision) - printk("ncr53c8xx: warning : revision %d is greater than expected.\n", - (int) revision); - else if (min_revision != -1 && revision < min_revision) - printk("ncr53c8xx: warning : revision %d is lower than expected.\n", - (int) revision); - if (io_port && check_region (io_port, 128)) { printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n", (int) io_port, (int) (io_port + 127)); @@ -8142,10 +8549,10 @@ host_data = (struct host_data *) host->hostdata; #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) # ifdef SCSI_NCR_SHARE_IRQ - if (dev_id == &host_data->ncb_data) + if (dev_id == host_data->ncb) # endif #endif - ncr_intr(&host_data->ncb_data); + ncr_intr(host_data->ncb); } } } @@ -8169,9 +8576,7 @@ int ncr53c8xx_reset(Scsi_Cmnd *cmd) #endif { -#ifdef DEBUG -printk("ncr53c8xx_reset : reset call\n"); -#endif + printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid); return ncr_reset_bus(cmd); } @@ -8181,7 +8586,7 @@ int ncr53c8xx_abort(Scsi_Cmnd *cmd) { -printk("ncr53c8xx_abort : abort call\n"); + printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid); return ncr_abort_command(cmd); } @@ -8196,7 +8601,7 @@ for (host = first_host; host; host = host->next) { if (host->hostt == the_template) { host_data = (struct host_data *) host->hostdata; - ncr_detach(&host_data->ncb_data, host->irq); + ncr_detach(host_data->ncb, host->irq); } } @@ -8236,17 +8641,19 @@ } } -static Scsi_Cmnd *remove_from_waiting_list(ncb_p np, Scsi_Cmnd *cmd) +static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd) { Scsi_Cmnd *wcmd; if (!(wcmd = np->waiting_list)) return 0; while (wcmd->next_wcmd) { if (cmd == (Scsi_Cmnd *) wcmd->next_wcmd) { - wcmd->next_wcmd = cmd->next_wcmd; - cmd->next_wcmd = 0; + if (to_remove) { + wcmd->next_wcmd = cmd->next_wcmd; + cmd->next_wcmd = 0; + } #ifdef DEBUG_WAITING_LIST - printf("%s: cmd %lx removed from waiting list\n", ncr_name(np), (u_long) cmd); + printf("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd); #endif return cmd; } @@ -8583,11 +8990,7 @@ ** Copy formatted profile information into the input buffer. */ -#if 0 -#define to_ms(t) (t) -#else #define to_ms(t) ((t) * 1000 / HZ) -#endif static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) { @@ -8650,7 +9053,7 @@ for (host = first_host; host; host = host->next) { if (host->hostt == the_template && host->host_no == hostno) { host_data = (struct host_data *) host->hostdata; - ncb = &host_data->ncb_data; + ncb = host_data->ncb; break; } } diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h --- v2.1.28/linux/drivers/scsi/ncr53c8xx.h Mon Jan 13 22:21:41 1997 +++ linux/drivers/scsi/ncr53c8xx.h Wed Mar 5 10:42:49 1997 @@ -45,7 +45,7 @@ /* ** Name and revision of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 1.16e" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 1.18b" /* ** If SCSI_NCR_SETUP_SPECIAL_FEATURES is defined, @@ -65,7 +65,7 @@ ** 0x80 burst disabled ** CTEST5 0x24 (825a and 875 only) ** 0x04 burst 128 -** 0x80 dma fifo 536 +** 0x80 large dma fifo ** ** If SCSI_NCR_TRUST_BIOS_SETTING is defined, the driver will use the ** initial value of corresponding bit fields, assuming they have been @@ -146,18 +146,12 @@ */ /* - * For Ultra SCSI support option, use special features and allow 20Mhz + * For Ultra2 SCSI support option, use special features and allow 40Mhz * synchronous data transfers. */ -#if 1 /* CONFIG_SCSI_NCR53C8XX_ULTRA_SUPPORT */ #define SCSI_NCR_SETUP_SPECIAL_FEATURES (1) -#define SCSI_NCR_SETUP_ULTRA_SCSI (1) -#define SCSI_NCR_MAX_SYNC (20000) -#else -#define SCSI_NCR_SETUP_SPECIAL_FEATURES (0) -#define SCSI_NCR_SETUP_ULTRA_SCSI (0) -#define SCSI_NCR_MAX_SYNC (10000) -#endif +#define SCSI_NCR_SETUP_ULTRA_SCSI (2) +#define SCSI_NCR_MAX_SYNC (40) /* * Allow tags from 2 to 12, default 4 @@ -193,20 +187,24 @@ /* * Sync transfer frequency at startup. - * Allow from 5Mhz to 20Mhz default 10 Mhz. + * Allow from 5Mhz to 40Mhz default 10 Mhz. */ -#ifdef CONFIG_SCSI_NCR53C8XX_SYNC -#if CONFIG_SCSI_NCR53C8XX_SYNC == 0 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (0) -#elif CONFIG_SCSI_NCR53C8XX_SYNC*1000 < 5000 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (5000) -#elif CONFIG_SCSI_NCR53C8XX_SYNC*1000 > SCSI_NCR_MAX_SYNC +#ifndef CONFIG_SCSI_NCR53C8XX_SYNC +#define CONFIG_SCSI_NCR53C8XX_SYNC (5) +#elif CONFIG_SCSI_NCR53C8XX_SYNC > SCSI_NCR_MAX_SYNC #define SCSI_NCR_SETUP_DEFAULT_SYNC SCSI_NCR_MAX_SYNC -#else -#define SCSI_NCR_SETUP_DEFAULT_SYNC (CONFIG_SCSI_NCR53C8XX_SYNC * 1000) #endif + +#if CONFIG_SCSI_NCR53C8XX_SYNC == 0 +#define SCSI_NCR_SETUP_DEFAULT_SYNC (255) +#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 5 +#define SCSI_NCR_SETUP_DEFAULT_SYNC (50) +#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 20 +#define SCSI_NCR_SETUP_DEFAULT_SYNC (250/(CONFIG_SCSI_NCR53C8XX_SYNC)) +#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 33 +#define SCSI_NCR_SETUP_DEFAULT_SYNC (11) #else -#define SCSI_NCR_SETUP_DEFAULT_SYNC (10000) +#define SCSI_NCR_SETUP_DEFAULT_SYNC (10) #endif /* @@ -214,7 +212,7 @@ */ #ifdef CONFIG_SCSI_FORCE_ASYNCHRONOUS #undef SCSI_NCR_SETUP_DEFAULT_SYNC -#define SCSI_NCR_SETUP_DEFAULT_SYNC (0) +#define SCSI_NCR_SETUP_DEFAULT_SYNC (255) #endif /* @@ -254,6 +252,22 @@ #endif /* + * Vendor specific stuff + */ +#ifdef CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT +#define SCSI_NCR_SETUP_LED_PIN (1) +#define SCSI_NCR_SETUP_DIFF_SUPPORT (3) +#else +#define SCSI_NCR_SETUP_LED_PIN (0) +#define SCSI_NCR_SETUP_DIFF_SUPPORT (0) +#endif + +/* + * Settle time after reset at boot-up + */ +#define SCSI_NCR_SETUP_SETTLE_TIME (2) + +/* ** Other parameters not configurable with "make config" ** Avoid to change these constants, unless you know what you are doing. */ @@ -262,7 +276,6 @@ #define SCSI_NCR_MAX_SCATTER (128) #define SCSI_NCR_MAX_TARGET (16) #define SCSI_NCR_MAX_HOST (2) -#define SCSI_NCR_SETTLE_TIME (2) #define SCSI_NCR_TIMEOUT_ALERT (3*HZ) #define SCSI_NCR_CAN_QUEUE (7*SCSI_NCR_MAX_TAGS) @@ -293,9 +306,38 @@ SCSI_NCR_SETUP_DEFAULT_TAGS, \ SCSI_NCR_SETUP_DEFAULT_SYNC, \ 0x00, \ - 7 \ + 7, \ + SCSI_NCR_SETUP_LED_PIN, \ + 1, \ + SCSI_NCR_SETUP_SETTLE_TIME, \ + SCSI_NCR_SETUP_DIFF_SUPPORT, \ + 0 \ } +/* +** Boot fail safe setup. +** Override initial setup from boot command line: +** ncr53c8xx=safe:y +*/ +#define SCSI_NCR_DRIVER_SAFE_SETUP \ +{ \ + 0, \ + 1, \ + 0, \ + 0, \ + 0, \ + 0, \ + 2, \ + 0, \ + 255, \ + 0x00, \ + 255, \ + 0, \ + 0, \ + 10, \ + 1, \ + 1 \ +} /* ** Define Scsi_Host_Template parameters @@ -670,7 +712,8 @@ #define CSF 0x02 /* c: clear scsi fifo */ /*50*/ u_short nc_sidl; /* Lowlevel: latched from scsi data */ -/*52*/ u_short nc_52_; +/*52*/ u_char nc_stest4; +/*53*/ u_char nc_53_; /*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */ /*56*/ u_short nc_56_; /*58*/ u_short nc_sbdl; /* Lowlevel: data from scsi data */ diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.1.28/linux/drivers/scsi/qlogicpti.c Fri Dec 13 01:37:37 1996 +++ linux/drivers/scsi/qlogicpti.c Wed Mar 5 17:04:33 1997 @@ -618,7 +618,8 @@ /* Setup the reg property for this device. */ prom_apply_sbus_ranges(qpti->qdev->my_bus, - qpti->qdev->reg_addrs, 1); + qpti->qdev->reg_addrs, + 1, qpti->qdev); /* Map in Qlogic,ISP regs and the PTI status reg. */ qpti->qregs = qregs = (struct qlogicpti_regs *) diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.28/linux/drivers/scsi/scsi.c Fri Feb 7 04:02:08 1997 +++ linux/drivers/scsi/scsi.c Mon Mar 10 12:35:39 1997 @@ -282,6 +282,7 @@ {"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN}, {"CANON","IPUBJD","*", BLIST_SPARSELUN}, {"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN}, +{"YAMAHA","CDR102","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ /* * Must be at end of list... */ diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c --- v2.1.28/linux/drivers/scsi/t128.c Tue Apr 9 04:25:38 1996 +++ linux/drivers/scsi/t128.c Thu Mar 6 10:23:04 1997 @@ -214,13 +214,15 @@ else for (; !base && (current_base < NO_BASES); ++current_base) { #if (TDEBUG & TDEBUG_INIT) - printk("scsi : probing address %08x\n", (unsigned int) bases[current_base].address); + printk("scsi-t128 : probing address %08x\n", (unsigned int) bases[current_base].address); #endif for (sig = 0; sig < NO_SIGNATURES; ++sig) - if (!bases[current_base].noauto && !memcmp - (bases[current_base].address + signatures[sig].offset, - signatures[sig].string, strlen(signatures[sig].string))) { - base = bases[current_base].address; + if (!bases[current_base].noauto && + check_signature(bases[current_base].address + + signatures[sig].offset, + signatures[sig].string, + strlen(signatures[sig].string))) { + base = bases[current_base].address; #if (TDEBUG & TDEBUG_INIT) printk("scsi-t128 : detected board.\n"); #endif diff -u --recursive --new-file v2.1.28/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.1.28/linux/drivers/scsi/wd7000.c Sun Feb 2 05:34:32 1997 +++ linux/drivers/scsi/wd7000.c Thu Mar 6 10:23:04 1997 @@ -1300,8 +1300,9 @@ break; if ((i == pass) && - !memcmp ((void *) (wd7000_biosaddr[biosaddr_ptr] + - signatures[sig_ptr].ofs), signatures[sig_ptr].sig, + check_signature(wd7000_biosaddr[biosaddr_ptr] + + signatures[sig_ptr].ofs, + signatures[sig_ptr].sig, signatures[sig_ptr].len)) goto bios_matched; } diff -u --recursive --new-file v2.1.28/linux/fs/proc/Makefile linux/fs/proc/Makefile --- v2.1.28/linux/fs/proc/Makefile Tue Mar 4 10:25:26 1997 +++ linux/fs/proc/Makefile Fri Mar 7 12:51:44 1997 @@ -9,7 +9,7 @@ O_TARGET := proc.o O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \ - kmsg.o net.o scsi.o proc_tty.o + kmsg.o scsi.o proc_tty.o OX_OBJS := procfs_syms.o M_OBJS := diff -u --recursive --new-file v2.1.28/linux/fs/proc/generic.c linux/fs/proc/generic.c --- v2.1.28/linux/fs/proc/generic.c Tue Mar 4 10:25:26 1997 +++ linux/fs/proc/generic.c Fri Mar 7 12:51:44 1997 @@ -41,7 +41,7 @@ * proc files can do almost nothing.. */ struct inode_operations proc_file_inode_operations = { - &proc_file_operations, /* default scsi directory file-ops */ + &proc_file_operations, /* default proc file-ops */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ @@ -60,6 +60,30 @@ NULL /* permission */ }; +/* + * compatibility to replace fs/proc/net.c + */ +struct inode_operations proc_net_inode_operations = { + &proc_file_operations, /* default net file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + + #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif @@ -72,7 +96,8 @@ { char *page; int retval=0; - int n; + int eof=0; + int n, count; char *start; struct proc_dir_entry * dp; @@ -82,10 +107,11 @@ if (!(page = (char*) __get_free_page(GFP_KERNEL))) return -ENOMEM; - while (nbytes > 0) + while ((nbytes > 0) && !eof) { - n = MIN(PROC_BLOCK_SIZE, nbytes); + count = MIN(PROC_BLOCK_SIZE, nbytes); + start = NULL; if (dp->get_info) { /* * Handle backwards compatibility with the old net @@ -94,14 +120,27 @@ * XXX What gives with the file->f_flags & O_ACCMODE * test? Seems stupid to me.... */ - n = dp->get_info(page, &start, file->f_pos, n, + n = dp->get_info(page, &start, file->f_pos, count, (file->f_flags & O_ACCMODE) == O_RDWR); + if (n < count) + eof = 1; } else if (dp->read_proc) { n = dp->read_proc(page, &start, file->f_pos, - n, dp->data); + count, &eof, dp->data); } else break; + if (!start) { + /* + * For proc files that are less than 4k + */ + start = page + file->f_pos; + n -= file->f_pos; + if (n <= 0) + break; + if (n > count) + n = count; + } if (n == 0) break; /* End of file */ if (n < 0) { @@ -131,13 +170,10 @@ const char * buffer, unsigned long count) { struct proc_dir_entry * dp; - char *page; if (count < 0) return -EINVAL; dp = (struct proc_dir_entry *) inode->u.generic_ip; - if (!(page = (char*) __get_free_page(GFP_KERNEL))) - return -ENOMEM; if (!dp->write_proc) return -EIO; @@ -146,7 +182,6 @@ } - static long long proc_file_lseek(struct inode * inode, struct file * file, long long offset, int orig) { @@ -164,10 +199,50 @@ } } +/* + * This function parses a name such as "tty/driver/serial", and + * returns the struct proc_dir_entry for "/proc/tty/driver", and + * returns "serial" in residual. + */ +static int xlate_proc_name(const char *name, + struct proc_dir_entry **ret, const char **residual) +{ + const char *cp = name, *next; + struct proc_dir_entry *de; + int len; + + de = &proc_root; + while (1) { + next = strchr(cp, '/'); + if (!next) + break; + + len = next - cp; + for (de = de->subdir; de ; de = de->next) { + if (proc_match(len, cp, de)) + break; + } + if (!de) + return -ENOENT; + cp += len + 1; + } + *residual = cp; + *ret = de; + return 0; +} + struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) { struct proc_dir_entry *ent; + const char *fn; + + if (parent) + fn = name; + else { + if (xlate_proc_name(name, &parent, &fn)) + return NULL; + } ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); if (!ent) @@ -179,17 +254,37 @@ else if (mode == 0) mode = S_IFREG | S_IRUGO; - ent->name = name; - ent->namelen = strlen(ent->name); + ent->name = fn; + ent->namelen = strlen(fn); ent->mode = mode; if (S_ISDIR(mode)) ent->nlink = 2; else ent->nlink = 1; - if (parent) - proc_register(parent, ent); + proc_register(parent, ent); return ent; } +void remove_proc_entry(const char *name, struct proc_dir_entry *parent) +{ + struct proc_dir_entry *de; + const char *fn; + int len; + + if (parent) + fn = name; + else + if (xlate_proc_name(name, &parent, &fn)) + return; + len = strlen(fn); + + for (de = parent->subdir; de ; de = de->next) { + if (proc_match(len, fn, de)) + break; + } + if (de) + proc_unregister(parent, de->low_ino); + kfree(de); +} diff -u --recursive --new-file v2.1.28/linux/fs/proc/inode.c linux/fs/proc/inode.c --- v2.1.28/linux/fs/proc/inode.c Tue Mar 4 10:25:26 1997 +++ linux/fs/proc/inode.c Fri Mar 7 12:51:44 1997 @@ -121,7 +121,6 @@ struct super_block *proc_read_super(struct super_block *s,void *data, int silent) { - proc_root_init(); lock_super(s); s->s_blocksize = 1024; s->s_blocksize_bits = 10; diff -u --recursive --new-file v2.1.28/linux/fs/proc/proc_tty.c linux/fs/proc/proc_tty.c --- v2.1.28/linux/fs/proc/proc_tty.c Tue Mar 4 10:25:26 1997 +++ linux/fs/proc/proc_tty.c Fri Mar 7 12:51:44 1997 @@ -19,20 +19,20 @@ static int tty_drivers_read_proc(char *page, char **start, off_t off, - int count, void *data); + int count, int *eof, void *data); static int tty_ldiscs_read_proc(char *page, char **start, off_t off, - int count, void *data); + int count, int *eof, void *data); /* * The /proc/tty directory inodes... */ -static struct proc_dir_entry *proc_tty, *proc_tty_ldisc, *proc_tty_driver; +static struct proc_dir_entry *proc_tty_ldisc, *proc_tty_driver; /* * This is the handler for /proc/tty/drivers */ static int tty_drivers_read_proc(char *page, char **start, off_t off, - int count, void *data) + int count, int *eof, void *data) { int len = 0; off_t begin = 0; @@ -87,6 +87,8 @@ len = 0; } } + if (!p) + *eof = 1; if (off >= len+begin) return 0; *start = page + (begin-off); @@ -97,7 +99,7 @@ * This is the handler for /proc/tty/ldiscs */ static int tty_ldiscs_read_proc(char *page, char **start, off_t off, - int count, void *data) + int count, int *eof, void *data) { int i; int len = 0; @@ -115,6 +117,8 @@ len = 0; } } + if (i >= NR_LDISCS) + *eof = 1; if (off >= len+begin) return 0; *start = page + (begin-off); @@ -168,16 +172,16 @@ { struct proc_dir_entry *ent; - proc_tty = create_proc_entry("tty", S_IFDIR, &proc_root); - if (!proc_tty) + ent = create_proc_entry("tty", S_IFDIR, 0); + if (!ent) return; - proc_tty_ldisc = create_proc_entry("ldisc", S_IFDIR, proc_tty); - proc_tty_driver = create_proc_entry("driver", S_IFDIR, proc_tty); + proc_tty_ldisc = create_proc_entry("tty/ldisc", S_IFDIR, 0); + proc_tty_driver = create_proc_entry("tty/driver", S_IFDIR, 0); - ent = create_proc_entry("ldiscs", 0, proc_tty); + ent = create_proc_entry("tty/ldiscs", 0, 0); ent->read_proc = tty_ldiscs_read_proc; - ent = create_proc_entry("drivers", 0, proc_tty); + ent = create_proc_entry("tty/drivers", 0, 0); ent->read_proc = tty_drivers_read_proc; } diff -u --recursive --new-file v2.1.28/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c --- v2.1.28/linux/fs/proc/procfs_syms.c Sun Feb 2 05:18:43 1997 +++ linux/fs/proc/procfs_syms.c Fri Mar 7 12:51:44 1997 @@ -13,7 +13,6 @@ extern struct inode_operations proc_scsi_inode_operations; EXPORT_SYMBOL(proc_register); -EXPORT_SYMBOL(proc_register_dynamic); EXPORT_SYMBOL(proc_unregister); EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_get_inode); diff -u --recursive --new-file v2.1.28/linux/fs/proc/root.c linux/fs/proc/root.c --- v2.1.28/linux/fs/proc/root.c Tue Mar 4 10:25:26 1997 +++ linux/fs/proc/root.c Fri Mar 7 12:51:44 1997 @@ -125,22 +125,7 @@ &proc_root, NULL }; -struct proc_dir_entry proc_net = { - PROC_NET, 3, "net", - S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, - 0, &proc_dir_inode_operations, - NULL, NULL, - NULL, - NULL, NULL -}; - -struct proc_dir_entry proc_scsi = { - PROC_SCSI, 4, "scsi", - S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, - 0, &proc_dir_inode_operations, - NULL, NULL, - NULL, &proc_root, NULL -}; +struct proc_dir_entry *proc_net, *proc_scsi; #ifdef CONFIG_MCA struct proc_dir_entry proc_mca = { @@ -358,18 +343,6 @@ return -EINVAL; } -int proc_register_dynamic(struct proc_dir_entry * dir, - struct proc_dir_entry * dp) -{ - /* - * Make sure we use a dynamically allocated inode. - * In the future, all procedures should just call - * proc_register.... - */ - dp->low_ino = 0; - return proc_register(dir, dp); -} - /* * /proc/self: */ @@ -567,11 +540,6 @@ void proc_root_init(void) { - static int done = 0; - - if (done) - return; - done = 1; proc_base_init(); proc_register(&proc_root, &proc_root_loadavg); proc_register(&proc_root, &proc_root_uptime); @@ -586,8 +554,8 @@ #endif proc_register(&proc_root, &proc_root_cpuinfo); proc_register(&proc_root, &proc_root_self); - proc_register(&proc_root, &proc_net); - proc_register(&proc_root, &proc_scsi); + proc_net = create_proc_entry("net", S_IFDIR, 0); + proc_scsi = create_proc_entry("scsi", S_IFDIR, 0); proc_register(&proc_root, &proc_sys_root); #ifdef CONFIG_MCA proc_register(&proc_root, &proc_mca); diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h --- v2.1.28/linux/include/asm-sparc/asm_offsets.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc/asm_offsets.h Wed Mar 5 17:04:33 1997 @@ -0,0 +1,258 @@ +/* Automatically generated. Do not edit. */ +#ifndef __ASM_OFFSETS_H__ +#define __ASM_OFFSETS_H__ + +#define AOFF_task_state 0x00000000 +#define ASIZ_task_state 0x00000004 +#define AOFF_task_counter 0x00000004 +#define ASIZ_task_counter 0x00000004 +#define AOFF_task_priority 0x00000008 +#define ASIZ_task_priority 0x00000004 +#define AOFF_task_signal 0x0000000c +#define ASIZ_task_signal 0x00000004 +#define AOFF_task_blocked 0x00000010 +#define ASIZ_task_blocked 0x00000004 +#define AOFF_task_flags 0x00000014 +#define ASIZ_task_flags 0x00000004 +#define AOFF_task_errno 0x00000018 +#define ASIZ_task_errno 0x00000004 +#define AOFF_task_debugreg 0x0000001c +#define ASIZ_task_debugreg 0x00000020 +#define AOFF_task_exec_domain 0x0000003c +#define ASIZ_task_exec_domain 0x00000004 +#define AOFF_task_binfmt 0x00000040 +#define ASIZ_task_binfmt 0x00000004 +#define AOFF_task_next_task 0x00000044 +#define ASIZ_task_next_task 0x00000004 +#define AOFF_task_prev_task 0x00000048 +#define ASIZ_task_prev_task 0x00000004 +#define AOFF_task_next_run 0x0000004c +#define ASIZ_task_next_run 0x00000004 +#define AOFF_task_prev_run 0x00000050 +#define ASIZ_task_prev_run 0x00000004 +#define AOFF_task_saved_kernel_stack 0x00000054 +#define ASIZ_task_saved_kernel_stack 0x00000004 +#define AOFF_task_kernel_stack_page 0x00000058 +#define ASIZ_task_kernel_stack_page 0x00000004 +#define AOFF_task_exit_code 0x0000005c +#define ASIZ_task_exit_code 0x00000004 +#define AOFF_task_exit_signal 0x00000060 +#define ASIZ_task_exit_signal 0x00000004 +#define AOFF_task_personality 0x00000064 +#define ASIZ_task_personality 0x00000004 +#define AOFF_task_pid 0x0000006c +#define ASIZ_task_pid 0x00000004 +#define AOFF_task_pgrp 0x00000070 +#define ASIZ_task_pgrp 0x00000004 +#define AOFF_task_tty_old_pgrp 0x00000074 +#define ASIZ_task_tty_old_pgrp 0x00000004 +#define AOFF_task_session 0x00000078 +#define ASIZ_task_session 0x00000004 +#define AOFF_task_leader 0x0000007c +#define ASIZ_task_leader 0x00000004 +#define AOFF_task_ngroups 0x00000080 +#define ASIZ_task_ngroups 0x00000004 +#define AOFF_task_groups 0x00000084 +#define ASIZ_task_groups 0x00000040 +#define AOFF_task_p_opptr 0x000000c4 +#define ASIZ_task_p_opptr 0x00000004 +#define AOFF_task_p_pptr 0x000000c8 +#define ASIZ_task_p_pptr 0x00000004 +#define AOFF_task_p_cptr 0x000000cc +#define ASIZ_task_p_cptr 0x00000004 +#define AOFF_task_p_ysptr 0x000000d0 +#define ASIZ_task_p_ysptr 0x00000004 +#define AOFF_task_p_osptr 0x000000d4 +#define ASIZ_task_p_osptr 0x00000004 +#define AOFF_task_wait_chldexit 0x000000d8 +#define ASIZ_task_wait_chldexit 0x00000004 +#define AOFF_task_uid 0x000000dc +#define ASIZ_task_uid 0x00000002 +#define AOFF_task_euid 0x000000de +#define ASIZ_task_euid 0x00000002 +#define AOFF_task_suid 0x000000e0 +#define ASIZ_task_suid 0x00000002 +#define AOFF_task_fsuid 0x000000e2 +#define ASIZ_task_fsuid 0x00000002 +#define AOFF_task_gid 0x000000e4 +#define ASIZ_task_gid 0x00000002 +#define AOFF_task_egid 0x000000e6 +#define ASIZ_task_egid 0x00000002 +#define AOFF_task_sgid 0x000000e8 +#define ASIZ_task_sgid 0x00000002 +#define AOFF_task_fsgid 0x000000ea +#define ASIZ_task_fsgid 0x00000002 +#define AOFF_task_timeout 0x000000ec +#define ASIZ_task_timeout 0x00000004 +#define AOFF_task_policy 0x000000f0 +#define ASIZ_task_policy 0x00000004 +#define AOFF_task_rt_priority 0x000000f4 +#define ASIZ_task_rt_priority 0x00000004 +#define AOFF_task_it_real_value 0x000000f8 +#define ASIZ_task_it_real_value 0x00000004 +#define AOFF_task_it_prof_value 0x000000fc +#define ASIZ_task_it_prof_value 0x00000004 +#define AOFF_task_it_virt_value 0x00000100 +#define ASIZ_task_it_virt_value 0x00000004 +#define AOFF_task_it_real_incr 0x00000104 +#define ASIZ_task_it_real_incr 0x00000004 +#define AOFF_task_it_prof_incr 0x00000108 +#define ASIZ_task_it_prof_incr 0x00000004 +#define AOFF_task_it_virt_incr 0x0000010c +#define ASIZ_task_it_virt_incr 0x00000004 +#define AOFF_task_real_timer 0x00000110 +#define ASIZ_task_real_timer 0x00000014 +#define AOFF_task_utime 0x00000124 +#define ASIZ_task_utime 0x00000004 +#define AOFF_task_stime 0x00000128 +#define ASIZ_task_stime 0x00000004 +#define AOFF_task_cutime 0x0000012c +#define ASIZ_task_cutime 0x00000004 +#define AOFF_task_cstime 0x00000130 +#define ASIZ_task_cstime 0x00000004 +#define AOFF_task_start_time 0x00000134 +#define ASIZ_task_start_time 0x00000004 +#define AOFF_task_min_flt 0x00000138 +#define ASIZ_task_min_flt 0x00000004 +#define AOFF_task_maj_flt 0x0000013c +#define ASIZ_task_maj_flt 0x00000004 +#define AOFF_task_nswap 0x00000140 +#define ASIZ_task_nswap 0x00000004 +#define AOFF_task_cmin_flt 0x00000144 +#define ASIZ_task_cmin_flt 0x00000004 +#define AOFF_task_cmaj_flt 0x00000148 +#define ASIZ_task_cmaj_flt 0x00000004 +#define AOFF_task_cnswap 0x0000014c +#define ASIZ_task_cnswap 0x00000004 +#define AOFF_task_swap_address 0x00000154 +#define ASIZ_task_swap_address 0x00000004 +#define AOFF_task_old_maj_flt 0x00000158 +#define ASIZ_task_old_maj_flt 0x00000004 +#define AOFF_task_dec_flt 0x0000015c +#define ASIZ_task_dec_flt 0x00000004 +#define AOFF_task_swap_cnt 0x00000160 +#define ASIZ_task_swap_cnt 0x00000004 +#define AOFF_task_rlim 0x00000164 +#define ASIZ_task_rlim 0x00000050 +#define AOFF_task_used_math 0x000001b4 +#define ASIZ_task_used_math 0x00000002 +#define AOFF_task_comm 0x000001b6 +#define ASIZ_task_comm 0x00000010 +#define AOFF_task_link_count 0x000001c8 +#define ASIZ_task_link_count 0x00000004 +#define AOFF_task_tty 0x000001cc +#define ASIZ_task_tty 0x00000004 +#define AOFF_task_semundo 0x000001d0 +#define ASIZ_task_semundo 0x00000004 +#define AOFF_task_semsleeping 0x000001d4 +#define ASIZ_task_semsleeping 0x00000004 +#define AOFF_task_ldt 0x000001d8 +#define ASIZ_task_ldt 0x00000004 +#define AOFF_task_tss 0x000001e0 +#define ASIZ_task_tss 0x000003a0 +#define AOFF_task_fs 0x00000580 +#define ASIZ_task_fs 0x00000004 +#define AOFF_task_files 0x00000584 +#define ASIZ_task_files 0x00000004 +#define AOFF_task_mm 0x00000588 +#define ASIZ_task_mm 0x00000004 +#define AOFF_task_sig 0x0000058c +#define ASIZ_task_sig 0x00000004 +#define AOFF_task_processor 0x00000590 +#define ASIZ_task_processor 0x00000004 +#define AOFF_task_last_processor 0x00000594 +#define ASIZ_task_last_processor 0x00000004 +#define AOFF_task_lock_depth 0x00000598 +#define ASIZ_task_lock_depth 0x00000004 +#define AOFF_mm_count 0x00000000 +#define ASIZ_mm_count 0x00000004 +#define AOFF_mm_pgd 0x00000004 +#define ASIZ_mm_pgd 0x00000004 +#define AOFF_mm_context 0x00000008 +#define ASIZ_mm_context 0x00000004 +#define AOFF_mm_start_code 0x0000000c +#define ASIZ_mm_start_code 0x00000004 +#define AOFF_mm_end_code 0x00000010 +#define ASIZ_mm_end_code 0x00000004 +#define AOFF_mm_start_data 0x00000014 +#define ASIZ_mm_start_data 0x00000004 +#define AOFF_mm_end_data 0x00000018 +#define ASIZ_mm_end_data 0x00000004 +#define AOFF_mm_start_brk 0x0000001c +#define ASIZ_mm_start_brk 0x00000004 +#define AOFF_mm_brk 0x00000020 +#define ASIZ_mm_brk 0x00000004 +#define AOFF_mm_start_stack 0x00000024 +#define ASIZ_mm_start_stack 0x00000004 +#define AOFF_mm_start_mmap 0x00000028 +#define ASIZ_mm_start_mmap 0x00000004 +#define AOFF_mm_arg_start 0x0000002c +#define ASIZ_mm_arg_start 0x00000004 +#define AOFF_mm_arg_end 0x00000030 +#define ASIZ_mm_arg_end 0x00000004 +#define AOFF_mm_env_start 0x00000034 +#define ASIZ_mm_env_start 0x00000004 +#define AOFF_mm_env_end 0x00000038 +#define ASIZ_mm_env_end 0x00000004 +#define AOFF_mm_rss 0x0000003c +#define ASIZ_mm_rss 0x00000004 +#define AOFF_mm_total_vm 0x00000040 +#define ASIZ_mm_total_vm 0x00000004 +#define AOFF_mm_locked_vm 0x00000044 +#define ASIZ_mm_locked_vm 0x00000004 +#define AOFF_mm_def_flags 0x00000048 +#define ASIZ_mm_def_flags 0x00000004 +#define AOFF_mm_mmap 0x0000004c +#define ASIZ_mm_mmap 0x00000004 +#define AOFF_mm_mmap_avl 0x00000050 +#define ASIZ_mm_mmap_avl 0x00000004 +#define AOFF_mm_mmap_sem 0x00000054 +#define ASIZ_mm_mmap_sem 0x0000000c +#define AOFF_thread_uwinmask 0x00000000 +#define ASIZ_thread_uwinmask 0x00000004 +#define AOFF_thread_kregs 0x00000004 +#define ASIZ_thread_kregs 0x00000004 +#define AOFF_thread_sig_address 0x00000008 +#define ASIZ_thread_sig_address 0x00000004 +#define AOFF_thread_sig_desc 0x0000000c +#define ASIZ_thread_sig_desc 0x00000004 +#define AOFF_thread_ksp 0x00000010 +#define ASIZ_thread_ksp 0x00000004 +#define AOFF_thread_kpc 0x00000014 +#define ASIZ_thread_kpc 0x00000004 +#define AOFF_thread_kpsr 0x00000018 +#define ASIZ_thread_kpsr 0x00000004 +#define AOFF_thread_kwim 0x0000001c +#define ASIZ_thread_kwim 0x00000004 +#define AOFF_thread_fork_kpsr 0x00000020 +#define ASIZ_thread_fork_kpsr 0x00000004 +#define AOFF_thread_fork_kwim 0x00000024 +#define ASIZ_thread_fork_kwim 0x00000004 +#define AOFF_thread_reg_window 0x00000028 +#define ASIZ_thread_reg_window 0x00000200 +#define AOFF_thread_rwbuf_stkptrs 0x00000228 +#define ASIZ_thread_rwbuf_stkptrs 0x00000020 +#define AOFF_thread_w_saved 0x00000248 +#define ASIZ_thread_w_saved 0x00000004 +#define AOFF_thread_float_regs 0x00000250 +#define ASIZ_thread_float_regs 0x00000080 +#define AOFF_thread_fsr 0x000002d0 +#define ASIZ_thread_fsr 0x00000004 +#define AOFF_thread_fpqdepth 0x000002d4 +#define ASIZ_thread_fpqdepth 0x00000004 +#define AOFF_thread_fpqueue 0x000002d8 +#define ASIZ_thread_fpqueue 0x00000080 +#define AOFF_thread_sstk_info 0x00000358 +#define ASIZ_thread_sstk_info 0x00000008 +#define AOFF_thread_flags 0x00000360 +#define ASIZ_thread_flags 0x00000004 +#define AOFF_thread_ex 0x00000368 +#define ASIZ_thread_ex 0x00000010 +#define AOFF_thread_current_ds 0x00000378 +#define ASIZ_thread_current_ds 0x00000004 +#define AOFF_thread_core_exec 0x0000037c +#define ASIZ_thread_core_exec 0x00000020 +#define AOFF_thread_new_signal 0x0000039c +#define ASIZ_thread_new_signal 0x00000004 + +#endif /* __ASM_OFFSETS_H__ */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/auxio.h linux/include/asm-sparc/auxio.h --- v2.1.28/linux/include/asm-sparc/auxio.h Fri Dec 13 01:37:39 1996 +++ linux/include/asm-sparc/auxio.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: auxio.h,v 1.15 1996/12/06 00:37:11 davem Exp $ +/* $Id: auxio.h,v 1.16 1997/01/31 23:26:05 tdyas Exp $ * auxio.h: Definitions and code for the Auxiliary I/O register. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -68,5 +68,14 @@ restore_flags(flags); } #endif /* !(__ASSEMBLY__) */ + + +/* AUXIO2 (Power Off Control) */ +extern __volatile__ unsigned char * auxio_power_register; + +#define AUXIO_POWER_DETECT_FAILURE 32 +#define AUXIO_POWER_CLEAR_FAILURE 2 +#define AUXIO_POWER_OFF 1 + #endif /* !(_SPARC_AUXIO_H) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/bpp.h linux/include/asm-sparc/bpp.h --- v2.1.28/linux/include/asm-sparc/bpp.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc/bpp.h Wed Mar 5 17:04:33 1997 @@ -0,0 +1,82 @@ +#ifndef _SPARC_BPP_H +#define _SPARC_BPP_H + +/* + * Copyright (c) 1995 Picture Elements + * Stephen Williams + * Gus Baldauf + * + * Linux/SPARC port by Peter Zaitcev. + * Integration into SPARC tree by Tom Dyas. + */ + +#include + +/* + * This is a driver that supports IEEE Std 1284-1994 communications + * with compliant or compatible devices. It will use whatever features + * the device supports, prefering those that are typically faster. + * + * When the device is opened, it is left in COMPATABILITY mode, and + * writes work like any printer device. The driver only attempt to + * negotiate 1284 modes when needed so that plugs can be pulled, + * switch boxes switched, etc., without disrupting things. It will + * also leave the device in compatibility mode when closed. + */ + + + +/* + * This driver also supplies ioctls to manually manipulate the + * pins. This is great for testing devices, or writing code to deal + * with bizzarro-mode of the ACME Special TurboThingy Plus. + * + * NOTE: These ioctl currently do not interact well with + * read/write. Caveat emptor. + * + * PUT_PINS allows us to assign the sense of all the pins, including + * the data pins if being driven by the host. The GET_PINS returns the + * pins that the peripheral drives, including data if appropriate. + */ + +# define BPP_PUT_PINS _IOW('B', 1, int) +# define BPP_GET_PINS _IOR('B', 2, void) +# define BPP_PUT_DATA _IOW('B', 3, int) +# define BPP_GET_DATA _IOR('B', 4, void) + +/* + * Set the data bus to input mode. Disengage the data bin driver and + * be prepared to read values from the peripheral. If the arg is 0, + * then revert the bus to output mode. + */ +# define BPP_SET_INPUT _IOW('B', 5, int) + +/* + * These bits apply to the PUT operation... + */ +# define BPP_PP_nStrobe 0x0001 +# define BPP_PP_nAutoFd 0x0002 +# define BPP_PP_nInit 0x0004 +# define BPP_PP_nSelectIn 0x0008 + +/* + * These apply to the GET operation, which also reads the current value + * of the previously put values. A bit mask of these will be returned + * as a bit mask in the return code of the ioctl(). + */ +# define BPP_GP_nAck 0x0100 +# define BPP_GP_Busy 0x0200 +# define BPP_GP_PError 0x0400 +# define BPP_GP_Select 0x0800 +# define BPP_GP_nFault 0x1000 + + +/* + * Prototype for the initialization routine. + */ + +#ifdef __KERNEL__ +extern int bpp_init(void); +#endif + +#endif diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/checksum.h linux/include/asm-sparc/checksum.h --- v2.1.28/linux/include/asm-sparc/checksum.h Sun Nov 10 13:28:33 1996 +++ linux/include/asm-sparc/checksum.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: checksum.h,v 1.22 1996/11/10 21:28:25 davem Exp $ */ +/* $Id: checksum.h,v 1.25 1997/02/19 15:51:19 jj Exp $ */ #ifndef __SPARC_CHECKSUM_H #define __SPARC_CHECKSUM_H @@ -8,12 +8,16 @@ * Copyright(C) 1995 Miguel de Icaza * Copyright(C) 1996 David S. Miller * Copyright(C) 1996 Eddie C. Dost + * Copyright(C) 1997 Jakub Jelinek * * derived from: * Alpha checksum c-code * ix86 inline assembly * RFC1071 Computing the Internet Checksum */ + +#include +#include /* computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) @@ -34,11 +38,84 @@ * here even more important to align src and dst on a 32-bit (or even * better 64-bit) boundary */ -extern unsigned int csum_partial_copy(char *src, char *dst, int len, int sum); +/* FIXME: Remove these two macros ASAP */ +#define csum_partial_copy(src, dst, len, sum) \ + csum_partial_copy_nocheck(src,dst,len,sum) #define csum_partial_copy_fromuser(s, d, l, w) \ - csum_partial_copy((char *) (s), (d), (l), (w)) + csum_partial_copy((char *) (s), (d), (l), (w)) + +extern __inline__ unsigned int +csum_partial_copy_nocheck (const char *src, char *dst, int len, + unsigned int sum) +{ + register unsigned int ret asm("o0") = (unsigned int)src; + register char *d asm("o1") = dst; + register int l asm("g1") = len; + + __asm__ __volatile__ (" + call " C_LABEL_STR(__csum_partial_copy_sparc_generic) " + mov %4, %%g7 + " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) : + "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + return ret; +} +extern __inline__ unsigned int +csum_partial_copy_from_user(const char *src, char *dst, int len, + unsigned int sum, int *err) + { + if (!access_ok (VERIFY_READ, src, len)) { + *err = -EFAULT; + memset (dst, 0, len); + return sum; + } else { + register unsigned int ret asm("o0") = (unsigned int)src; + register char *d asm("o1") = dst; + register int l asm("g1") = len; + register unsigned int s asm("g7") = sum; + + __asm__ __volatile__ (" + .section __ex_table,#alloc + .align 4 + .word 1f,2 + .previous +1: + call " C_LABEL_STR(__csum_partial_copy_sparc_generic) " + st %5, [%%sp + 64] + " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) : + "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + return ret; + } + } + +extern __inline__ unsigned int +csum_partial_copy_to_user(const char *src, char *dst, int len, + unsigned int sum, int *err) +{ + if (!access_ok (VERIFY_WRITE, dst, len)) { + *err = -EFAULT; + return sum; + } else { + register unsigned int ret asm("o0") = (unsigned int)src; + register char *d asm("o1") = dst; + register int l asm("g1") = len; + register unsigned int s asm("g7") = sum; + + __asm__ __volatile__ (" + .section __ex_table,#alloc + .align 4 + .word 1f,1 + .previous +1: + call " C_LABEL_STR(__csum_partial_copy_sparc_generic) " + st %5, [%%sp + 64] + " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) : + "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + return ret; + } +} + /* ihl is always 5 or greater, almost always is 5, and iph is word aligned * the majority of the time. */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/cprefix.h linux/include/asm-sparc/cprefix.h --- v2.1.28/linux/include/asm-sparc/cprefix.h Sat Nov 9 00:29:15 1996 +++ linux/include/asm-sparc/cprefix.h Wed Mar 5 17:04:33 1997 @@ -11,8 +11,10 @@ #if defined(__svr4__) || defined(__ELF__) #define C_LABEL_PREFIX +#define C_LABEL_STR(name) #name #else #define C_LABEL_PREFIX _ +#define C_LABEL_STR(name) "_" #name #endif #define CONCAT(a, b) CONCAT2(a, b) diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h --- v2.1.28/linux/include/asm-sparc/fcntl.h Sat Nov 9 00:29:24 1996 +++ linux/include/asm-sparc/fcntl.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: fcntl.h,v 1.8 1996/10/27 08:55:26 davem Exp $ */ +/* $Id: fcntl.h,v 1.9 1997/02/04 07:29:20 davem Exp $ */ #ifndef _SPARC_FCNTL_H #define _SPARC_FCNTL_H @@ -8,7 +8,6 @@ #define O_WRONLY 0x0001 #define O_RDWR 0x0002 #define O_ACCMODE 0x0003 -#define O_NDELAY 0x0004 #define O_APPEND 0x0008 #define FASYNC 0x0040 /* fcntl, for BSD compatibility */ #define O_CREAT 0x0200 /* not fcntl */ @@ -16,6 +15,7 @@ #define O_EXCL 0x0800 /* not fcntl */ #define O_SYNC 0x2000 #define O_NONBLOCK 0x4000 +#define O_NDELAY (0x0004 | O_NONBLOCK) #define O_NOCTTY 0x8000 /* not fcntl */ #define F_DUPFD 0 /* dup */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/oplib.h linux/include/asm-sparc/oplib.h --- v2.1.28/linux/include/asm-sparc/oplib.h Sat Nov 9 00:29:49 1996 +++ linux/include/asm-sparc/oplib.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.12 1996/10/31 06:29:13 davem Exp $ +/* $Id: oplib.h,v 1.13 1997/01/31 00:16:52 tdyas Exp $ * oplib.h: Describes the interface and available routines in the * Linux Prom library. * @@ -208,7 +208,19 @@ extern void prom_putsegment(int context, unsigned long virt_addr, int physical_segment); + /* PROM device tree traversal functions... */ + +#ifdef PROMLIB_INTERNAL + +/* Internal version of prom_getchild. */ +extern int __prom_getchild(int parent_node); + +/* Internal version of prom_getsibling. */ +extern int __prom_getsibling(int node); + +#endif + /* Get the child node of the given node, or zero if no child exists. */ extern int prom_getchild(int parent_node); diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h --- v2.1.28/linux/include/asm-sparc/processor.h Mon Dec 30 01:59:59 1996 +++ linux/include/asm-sparc/processor.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.54 1996/12/24 09:19:49 davem Exp $ +/* $Id: processor.h,v 1.57 1997/03/04 16:27:22 jj Exp $ * include/asm-sparc/processor.h * * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) @@ -35,12 +35,9 @@ */ #define TASK_SIZE (page_offset) -/* Ok this is hot. Sparc exception save area. */ -struct exception_struct { - unsigned long count; /* Exception count */ - unsigned long pc; /* Callers PC for copy/clear user */ - unsigned long expc; /* Where to jump when exception signaled */ - unsigned long address; /* Saved user base address for transfer */ +struct fpq { + unsigned long *insn_addr; + unsigned long insn; }; /* The Sparc processor specific thread struct. */ @@ -71,16 +68,12 @@ unsigned long w_saved; /* Floating point regs */ - unsigned long float_regs[64] __attribute__ ((aligned (8))); + unsigned long float_regs[32] __attribute__ ((aligned (8))); unsigned long fsr; unsigned long fpqdepth; - struct fpq { - unsigned long *insn_addr; - unsigned long insn; - } fpqueue[16]; + struct fpq fpqueue[16]; struct sigstack sstk_info; unsigned long flags; - struct exception_struct ex __attribute__ ((aligned (8))); int current_ds; struct exec core_exec; /* just what it says. */ int new_signal; @@ -104,15 +97,13 @@ /* w_saved */ \ 0, \ /* FPU regs */ { 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, }, \ /* FPU status, FPU qdepth, FPU queue */ \ 0, 0, { { 0, 0, }, }, \ /* sstk_info */ \ { 0, 0, }, \ -/* flags, ex, current_ds, */ \ - SPARC_FLAG_KTHREAD, { 0, }, USER_DS, \ +/* flags, current_ds, */ \ + SPARC_FLAG_KTHREAD, USER_DS, \ /* core_exec */ \ { 0, }, \ /* new_signal */ \ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/ptrace.h linux/include/asm-sparc/ptrace.h --- v2.1.28/linux/include/asm-sparc/ptrace.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/ptrace.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: ptrace.h,v 1.24 1997/01/06 06:53:23 davem Exp $ */ +/* $Id: ptrace.h,v 1.25 1997/03/04 16:27:25 jj Exp $ */ #ifndef _SPARC_PTRACE_H #define _SPARC_PTRACE_H @@ -73,36 +73,7 @@ #define REGWIN_SZ 0x40 #endif -/* First generic task_struct offsets. sizeof(task_struct)=1568 */ -#define TASK_STATE 0x000 -#define TASK_PRIORITY 0x008 -#define TASK_SIGNAL 0x00c -#define TASK_BLOCKED 0x010 -#define TASK_FLAGS 0x014 -#define TASK_SAVED_KSTACK 0x054 -#define TASK_KSTACK_PG 0x058 -#define TASK_LOCK_DEPTH 0x618 - -/* Thread stuff. */ -#define THREAD_UMASK 0x1e0 -#define THREAD_SADDR 0x1e8 -#define THREAD_SDESC 0x1ec -#define THREAD_KSP 0x1f0 -#define THREAD_KPC 0x1f4 -#define THREAD_KPSR 0x1f8 -#define THREAD_KWIM 0x1fc -#define THREAD_FORK_KPSR 0x200 -#define THREAD_FORK_KWIM 0x204 -#define THREAD_REG_WINDOW 0x208 -#define THREAD_STACK_PTRS 0x408 -#define THREAD_W_SAVED 0x428 -#define THREAD_FLOAT_REGS 0x430 -#define THREAD_FSR 0x530 -#define THREAD_SIGSTK 0x5b8 -#define THREAD_FLAGS 0x5c0 -#define THREAD_DS 0x5d8 -#define THREAD_MM 0x608 -#define THREAD_MM_CTX 0x008 +#include /* These are for pt_regs. */ #define PT_PSR 0x0 diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/sbus.h linux/include/asm-sparc/sbus.h --- v2.1.28/linux/include/asm-sparc/sbus.h Sat Nov 9 11:40:09 1996 +++ linux/include/asm-sparc/sbus.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: sbus.h,v 1.11 1996/10/31 06:29:12 davem Exp $ +/* $Id: sbus.h,v 1.12 1997/02/04 07:29:21 davem Exp $ * sbus.h: Defines for the Sun SBus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -51,7 +51,7 @@ char linux_name[64]; /* Name used internally by Linux */ struct linux_prom_registers reg_addrs[PROMREG_MAX]; - int num_registers; + int num_registers, ranges_applied; struct linux_prom_irqs irqs[PROMINTR_MAX]; int num_irqs; @@ -96,6 +96,7 @@ /* Apply promlib probed SBUS ranges to registers. */ extern void prom_apply_sbus_ranges(struct linux_sbus *sbus, - struct linux_prom_registers *sbusregs, int nregs); + struct linux_prom_registers *sbusregs, + int nregs, struct linux_sbus_device *sdev); #endif /* !(_SPARC_SBUS_H) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/sigcontext.h linux/include/asm-sparc/sigcontext.h --- v2.1.28/linux/include/asm-sparc/sigcontext.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/sigcontext.h Wed Mar 5 17:04:33 1997 @@ -1,6 +1,6 @@ -/* $Id: sigcontext.h,v 1.11 1997/01/19 22:32:07 ecd Exp $ */ -#ifndef _ASMsparc_SIGCONTEXT_H -#define _ASMsparc_SIGCONTEXT_H +/* $Id: sigcontext.h,v 1.12 1997/03/03 16:51:52 jj Exp $ */ +#ifndef __SPARC_SIGCONTEXT_H +#define __SPARC_SIGCONTEXT_H #include @@ -43,7 +43,7 @@ } __siginfo_t; typedef struct { - unsigned long si_float_regs [64]; + unsigned long si_float_regs [32]; unsigned long si_fsr; unsigned long si_fpqdepth; struct { @@ -54,4 +54,4 @@ #endif /* !(__ASSEMBLY__) */ -#endif /* !(_ASMsparc_SIGCONTEXT_H) */ +#endif /* !(__SPARC_SIGCONTEXT_H) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/smp_lock.h linux/include/asm-sparc/smp_lock.h --- v2.1.28/linux/include/asm-sparc/smp_lock.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/smp_lock.h Wed Mar 5 17:04:33 1997 @@ -46,7 +46,7 @@ mov %%o7, %%g4 call ___lock_kernel ld [%%g6 + %0], %%g2 -" : : "i" (TASK_LOCK_DEPTH), "r" (klip), "r" (proc) +" : : "i" (AOFF_task_lock_depth), "r" (klip), "r" (proc) : "g2", "g3", "g4", "g7", "memory"); } @@ -59,7 +59,7 @@ mov %%o7, %%g4 call ___unlock_kernel ld [%%g6 + %0], %%g2 -" : : "i" (TASK_LOCK_DEPTH), "r" (klip) +" : : "i" (AOFF_task_lock_depth), "r" (klip) : "g2", "g3", "g4", "memory"); } diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h --- v2.1.28/linux/include/asm-sparc/string.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/string.h Wed Mar 5 17:04:33 1997 @@ -1,8 +1,9 @@ -/* $Id: string.h,v 1.28 1997/01/15 16:01:54 jj Exp $ +/* $Id: string.h,v 1.30 1997/03/03 17:11:12 jj Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #ifndef __SPARC_STRING_H__ @@ -10,22 +11,26 @@ /* Really, userland/ksyms should not see any of this stuff. */ -#if defined(__KERNEL__) && !defined(EXPORT_SYMTAB) +#ifdef __KERNEL__ + +extern void __memmove(void *,const void *,__kernel_size_t); +extern __kernel_size_t __memcpy(void *,const void *,__kernel_size_t); +extern __kernel_size_t __memset(void *,int,__kernel_size_t); + +#ifndef EXPORT_SYMTAB /* First the mem*() things. */ #define __HAVE_ARCH_BCOPY #define __HAVE_ARCH_MEMMOVE -extern void __memmove(void *,const void *,__kernel_size_t); - #undef memmove #define memmove(_to, _from, _n) \ ({ \ - __memmove(_to, _from, _n); \ - _to; \ + void *_t = (_to); \ + __memmove(_t, (_from), (_n)); \ + _t; \ }) #define __HAVE_ARCH_MEMCPY -extern void __memcpy(void *,const void *,__kernel_size_t); extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n) { @@ -59,12 +64,11 @@ __nonconstant_memcpy((t),(f),(n))) #define __HAVE_ARCH_MEMSET -extern void *__memset(void *,int,__kernel_size_t); -extern inline void *__constant_c_and_count_memset(void *s, char c, size_t count) +extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count) { extern void *bzero_1page(void *); - extern void *__bzero(void *, size_t); + extern __kernel_size_t __bzero(void *, __kernel_size_t); if(!c) { if(count == 4096) @@ -77,9 +81,9 @@ return s; } -extern inline void *__constant_c_memset(void *s, char c, size_t count) +extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count) { - extern void *__bzero(void *, size_t); + extern __kernel_size_t __bzero(void *, __kernel_size_t); if(!c) __bzero(s, count); @@ -88,12 +92,18 @@ return s; } +extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count) +{ + __memset(s, c, count); + return s; +} + #undef memset #define memset(s, c, count) \ (__builtin_constant_p(c) ? (__builtin_constant_p(count) ? \ __constant_c_and_count_memset((s), (c), (count)) : \ __constant_c_memset((s), (c), (count))) \ - : __memset((s), (c), (count))) + : __nonconstant_memset((s), (c), (count))) #define __HAVE_ARCH_MEMSCAN @@ -181,7 +191,9 @@ (__builtin_constant_p(__arg2) ? \ __constant_strncmp(__arg0, __arg1, __arg2) : \ __strncmp(__arg0, __arg1, __arg2)) + +#endif /* EXPORT_SYMTAB */ -#endif /* (__KERNEL__) && !(_KSYMS_INTERNEL) */ +#endif /* __KERNEL__ */ #endif /* !(__SPARC_STRING_H__) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/termbits.h linux/include/asm-sparc/termbits.h --- v2.1.28/linux/include/asm-sparc/termbits.h Sat Nov 9 11:39:37 1996 +++ linux/include/asm-sparc/termbits.h Wed Mar 5 17:04:33 1997 @@ -152,6 +152,7 @@ #define B230400 0x00010003 #define B460800 0x00010004 #define CIBAUD 0x000f0000 /* input baud rate (not used) */ +#define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 0x80000000 /* flow control */ /* c_lflag bits */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h --- v2.1.28/linux/include/asm-sparc/termios.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/termios.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: termios.h,v 1.24 1996/12/31 22:35:45 davem Exp $ */ +/* $Id: termios.h,v 1.25 1997/03/04 19:36:18 davem Exp $ */ #ifndef _SPARC_TERMIOS_H #define _SPARC_TERMIOS_H @@ -88,7 +88,7 @@ * Translate a "termio" structure into a "termios". Ugh. */ #define user_termio_to_kernel_termios(termios, termio) \ -do { \ +({ \ unsigned short tmp; \ get_user(tmp, &(termio)->c_iflag); \ (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ @@ -99,7 +99,8 @@ get_user(tmp, &(termio)->c_lflag); \ (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ -} while(0) + 0; \ +}) /* * Translate a "termios" structure into a "termio". Ugh. @@ -107,7 +108,7 @@ * Note the "fun" _VMIN overloading. */ #define kernel_termios_to_user_termio(termio, termios) \ -do { \ +({ \ put_user((termios)->c_iflag, &(termio)->c_iflag); \ put_user((termios)->c_oflag, &(termio)->c_oflag); \ put_user((termios)->c_cflag, &(termio)->c_cflag); \ @@ -118,10 +119,11 @@ put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \ put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \ } \ -} while(0) + 0; \ +}) #define user_termios_to_kernel_termios(k, u) \ -do { \ +({ \ get_user((k)->c_iflag, &(u)->c_iflag); \ get_user((k)->c_oflag, &(u)->c_oflag); \ get_user((k)->c_cflag, &(u)->c_cflag); \ @@ -135,10 +137,11 @@ get_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ } \ -} while(0) + 0; \ +}) #define kernel_termios_to_user_termios(u, k) \ -do { \ +({ \ put_user((k)->c_iflag, &(u)->c_iflag); \ put_user((k)->c_oflag, &(u)->c_oflag); \ put_user((k)->c_cflag, &(u)->c_cflag); \ @@ -152,7 +155,8 @@ put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ } \ -} while(0) + 0; \ +}) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/uaccess.h linux/include/asm-sparc/uaccess.h --- v2.1.28/linux/include/asm-sparc/uaccess.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/uaccess.h Wed Mar 5 17:04:33 1997 @@ -1,11 +1,12 @@ -/* $Id: uaccess.h,v 1.10 1997/01/16 14:19:03 davem Exp $ */ +/* $Id: uaccess.h,v 1.11 1997/02/06 18:57:10 jj Exp $ + * uaccess.h: User space memore access functions. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ #ifndef _ASM_UACCESS_H #define _ASM_UACCESS_H -/* - * User space memory access functions - */ - #ifdef __KERNEL__ #include #include @@ -288,14 +289,14 @@ extern int __get_user_bad(void); -extern int __copy_user(unsigned long to, unsigned long from, int size); +extern __kernel_size_t __copy_user(void *to, void *from, __kernel_size_t size); #define copy_to_user(to,from,n) ({ \ -unsigned long __copy_to = (unsigned long) (to); \ -unsigned long __copy_size = (unsigned long) (n); \ -unsigned long __copy_res; \ -if(__copy_size && __access_ok(__copy_to, __copy_size)) { \ -__copy_res = __copy_user(__copy_to, (unsigned long) (from), __copy_size); \ +void *__copy_to = (void *) (to); \ +__kernel_size_t __copy_size = (__kernel_size_t) (n); \ +__kernel_size_t __copy_res; \ +if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \ +__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \ } else __copy_res = __copy_size; \ __copy_res; }) @@ -305,8 +306,8 @@ }) #define __copy_to_user(to,from,n) \ - __copy_user((unsigned long)(to), \ - (unsigned long)(from), n) + __copy_user((void *)(to), \ + (void *)(from), n) #define __copy_to_user_ret(to,from,n,retval) ({ \ if (__copy_to_user(to,from,n)) \ @@ -314,11 +315,11 @@ }) #define copy_from_user(to,from,n) ({ \ -unsigned long __copy_from = (unsigned long) (from); \ -unsigned long __copy_size = (unsigned long) (n); \ -unsigned long __copy_res; \ -if(__copy_size && __access_ok(__copy_from, __copy_size)) { \ -__copy_res = __copy_user((unsigned long) (to), __copy_from, __copy_size); \ +void *__copy_from = (void *) (from); \ +__kernel_size_t __copy_size = (__kernel_size_t) (n); \ +__kernel_size_t __copy_res; \ +if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \ +__copy_res = __copy_user((void *) (to), __copy_from, __copy_size); \ } else __copy_res = __copy_size; \ __copy_res; }) @@ -328,21 +329,37 @@ }) #define __copy_from_user(to,from,n) \ - __copy_user((unsigned long)(to), \ - (unsigned long)(from), n) + __copy_user((void *)(to), \ + (void *)(from), n) #define __copy_from_user_ret(to,from,n,retval) ({ \ if (__copy_from_user(to,from,n)) \ return retval; \ }) -extern int __clear_user(unsigned long addr, int size); +extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t size) +{ + __kernel_size_t ret; + __asm__ __volatile__ (" + .section __ex_table,#alloc + .align 4 + .word 1f,3 + .previous +1: + mov %2, %%o1 + call __bzero + mov %1, %%o0 + mov %%o0, %0 + " : "=r" (ret) : "r" (addr), "r" (size) : + "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7"); + return ret; +} #define clear_user(addr,n) ({ \ -unsigned long __clear_addr = (unsigned long) (addr); \ -int __clear_size = (int) (n); \ -int __clear_res; \ -if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \ +void *__clear_addr = (void *) (addr); \ +__kernel_size_t __clear_size = (__kernel_size_t) (n); \ +__kernel_size_t __clear_res; \ +if(__clear_size && __access_ok((unsigned long)__clear_addr, __clear_size)) { \ __clear_res = __clear_user(__clear_addr, __clear_size); \ } else __clear_res = __clear_size; \ __clear_res; }) diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v2.1.28/linux/include/asm-sparc/unistd.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc/unistd.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.28 1997/01/26 07:12:06 davem Exp $ */ +/* $Id: unistd.h,v 1.29 1997/02/04 07:14:17 miguel Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -479,15 +479,5 @@ } #endif /* __KERNEL_SYSCALLS__ */ - -/* sysconf options, for SunOS compatibility */ -#define _SC_ARG_MAX 1 -#define _SC_CHILD_MAX 2 -#define _SC_CLK_TCK 3 -#define _SC_NGROUPS_MAX 4 -#define _SC_OPEN_MAX 5 -#define _SC_JOB_CONTROL 6 -#define _SC_SAVED_IDS 7 -#define _SC_VERSION 8 #endif /* _SPARC_UNISTD_H */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc/winmacro.h linux/include/asm-sparc/winmacro.h --- v2.1.28/linux/include/asm-sparc/winmacro.h Sat Nov 9 00:30:28 1996 +++ linux/include/asm-sparc/winmacro.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: winmacro.h,v 1.17 1996/09/19 20:27:44 davem Exp $ +/* $Id: winmacro.h,v 1.18 1997/03/04 16:27:27 jj Exp $ * winmacro.h: Window loading-unloading macros. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -98,18 +98,18 @@ STORE_PT_INS(base_reg) #define SAVE_BOLIXED_USER_STACK(cur_reg, scratch) \ - ld [%cur_reg + THREAD_W_SAVED], %scratch; \ + ld [%cur_reg + AOFF_task_tss + AOFF_thread_w_saved], %scratch; \ sll %scratch, 2, %scratch; \ add %scratch, %cur_reg, %scratch; \ - st %sp, [%scratch + THREAD_STACK_PTRS]; \ + st %sp, [%scratch + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]; \ sub %scratch, %cur_reg, %scratch; \ sll %scratch, 4, %scratch; \ add %scratch, %cur_reg, %scratch; \ - STORE_WINDOW(scratch + THREAD_REG_WINDOW); \ + STORE_WINDOW(scratch + AOFF_task_tss + AOFF_thread_reg_window); \ sub %scratch, %cur_reg, %scratch; \ srl %scratch, 6, %scratch; \ add %scratch, 1, %scratch; \ - st %scratch, [%cur_reg + THREAD_W_SAVED]; + st %scratch, [%cur_reg + AOFF_task_tss + AOFF_thread_w_saved]; #ifdef __SMP__ #define LOAD_CURRENT(dest_reg, idreg) \ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h --- v2.1.28/linux/include/asm-sparc64/asm_offsets.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/asm_offsets.h Wed Mar 5 17:04:33 1997 @@ -0,0 +1,246 @@ +/* Automatically generated. Do not edit. */ +#ifndef __ASM_OFFSETS_H__ +#define __ASM_OFFSETS_H__ + +#define AOFF_task_state 0x00000000 +#define ASIZ_task_state 0x00000008 +#define AOFF_task_counter 0x00000008 +#define ASIZ_task_counter 0x00000008 +#define AOFF_task_priority 0x00000010 +#define ASIZ_task_priority 0x00000008 +#define AOFF_task_signal 0x00000018 +#define ASIZ_task_signal 0x00000008 +#define AOFF_task_blocked 0x00000020 +#define ASIZ_task_blocked 0x00000008 +#define AOFF_task_flags 0x00000028 +#define ASIZ_task_flags 0x00000008 +#define AOFF_task_errno 0x00000030 +#define ASIZ_task_errno 0x00000004 +#define AOFF_task_debugreg 0x00000038 +#define ASIZ_task_debugreg 0x00000040 +#define AOFF_task_exec_domain 0x00000078 +#define ASIZ_task_exec_domain 0x00000008 +#define AOFF_task_binfmt 0x00000080 +#define ASIZ_task_binfmt 0x00000008 +#define AOFF_task_next_task 0x00000088 +#define ASIZ_task_next_task 0x00000008 +#define AOFF_task_prev_task 0x00000090 +#define ASIZ_task_prev_task 0x00000008 +#define AOFF_task_next_run 0x00000098 +#define ASIZ_task_next_run 0x00000008 +#define AOFF_task_prev_run 0x000000a0 +#define ASIZ_task_prev_run 0x00000008 +#define AOFF_task_saved_kernel_stack 0x000000a8 +#define ASIZ_task_saved_kernel_stack 0x00000008 +#define AOFF_task_kernel_stack_page 0x000000b0 +#define ASIZ_task_kernel_stack_page 0x00000008 +#define AOFF_task_exit_code 0x000000b8 +#define ASIZ_task_exit_code 0x00000004 +#define AOFF_task_exit_signal 0x000000bc +#define ASIZ_task_exit_signal 0x00000004 +#define AOFF_task_personality 0x000000c0 +#define ASIZ_task_personality 0x00000008 +#define AOFF_task_pid 0x000000cc +#define ASIZ_task_pid 0x00000004 +#define AOFF_task_pgrp 0x000000d0 +#define ASIZ_task_pgrp 0x00000004 +#define AOFF_task_tty_old_pgrp 0x000000d4 +#define ASIZ_task_tty_old_pgrp 0x00000004 +#define AOFF_task_session 0x000000d8 +#define ASIZ_task_session 0x00000004 +#define AOFF_task_leader 0x000000dc +#define ASIZ_task_leader 0x00000004 +#define AOFF_task_ngroups 0x000000e0 +#define ASIZ_task_ngroups 0x00000004 +#define AOFF_task_groups 0x000000e4 +#define ASIZ_task_groups 0x00000040 +#define AOFF_task_p_opptr 0x00000128 +#define ASIZ_task_p_opptr 0x00000008 +#define AOFF_task_p_pptr 0x00000130 +#define ASIZ_task_p_pptr 0x00000008 +#define AOFF_task_p_cptr 0x00000138 +#define ASIZ_task_p_cptr 0x00000008 +#define AOFF_task_p_ysptr 0x00000140 +#define ASIZ_task_p_ysptr 0x00000008 +#define AOFF_task_p_osptr 0x00000148 +#define ASIZ_task_p_osptr 0x00000008 +#define AOFF_task_wait_chldexit 0x00000150 +#define ASIZ_task_wait_chldexit 0x00000008 +#define AOFF_task_uid 0x00000158 +#define ASIZ_task_uid 0x00000002 +#define AOFF_task_euid 0x0000015a +#define ASIZ_task_euid 0x00000002 +#define AOFF_task_suid 0x0000015c +#define ASIZ_task_suid 0x00000002 +#define AOFF_task_fsuid 0x0000015e +#define ASIZ_task_fsuid 0x00000002 +#define AOFF_task_gid 0x00000160 +#define ASIZ_task_gid 0x00000002 +#define AOFF_task_egid 0x00000162 +#define ASIZ_task_egid 0x00000002 +#define AOFF_task_sgid 0x00000164 +#define ASIZ_task_sgid 0x00000002 +#define AOFF_task_fsgid 0x00000166 +#define ASIZ_task_fsgid 0x00000002 +#define AOFF_task_timeout 0x00000168 +#define ASIZ_task_timeout 0x00000008 +#define AOFF_task_policy 0x00000170 +#define ASIZ_task_policy 0x00000008 +#define AOFF_task_rt_priority 0x00000178 +#define ASIZ_task_rt_priority 0x00000008 +#define AOFF_task_it_real_value 0x00000180 +#define ASIZ_task_it_real_value 0x00000008 +#define AOFF_task_it_prof_value 0x00000188 +#define ASIZ_task_it_prof_value 0x00000008 +#define AOFF_task_it_virt_value 0x00000190 +#define ASIZ_task_it_virt_value 0x00000008 +#define AOFF_task_it_real_incr 0x00000198 +#define ASIZ_task_it_real_incr 0x00000008 +#define AOFF_task_it_prof_incr 0x000001a0 +#define ASIZ_task_it_prof_incr 0x00000008 +#define AOFF_task_it_virt_incr 0x000001a8 +#define ASIZ_task_it_virt_incr 0x00000008 +#define AOFF_task_real_timer 0x000001b0 +#define ASIZ_task_real_timer 0x00000028 +#define AOFF_task_utime 0x000001d8 +#define ASIZ_task_utime 0x00000008 +#define AOFF_task_stime 0x000001e0 +#define ASIZ_task_stime 0x00000008 +#define AOFF_task_cutime 0x000001e8 +#define ASIZ_task_cutime 0x00000008 +#define AOFF_task_cstime 0x000001f0 +#define ASIZ_task_cstime 0x00000008 +#define AOFF_task_start_time 0x000001f8 +#define ASIZ_task_start_time 0x00000008 +#define AOFF_task_min_flt 0x00000200 +#define ASIZ_task_min_flt 0x00000008 +#define AOFF_task_maj_flt 0x00000208 +#define ASIZ_task_maj_flt 0x00000008 +#define AOFF_task_nswap 0x00000210 +#define ASIZ_task_nswap 0x00000008 +#define AOFF_task_cmin_flt 0x00000218 +#define ASIZ_task_cmin_flt 0x00000008 +#define AOFF_task_cmaj_flt 0x00000220 +#define ASIZ_task_cmaj_flt 0x00000008 +#define AOFF_task_cnswap 0x00000228 +#define ASIZ_task_cnswap 0x00000008 +#define AOFF_task_swap_address 0x00000238 +#define ASIZ_task_swap_address 0x00000008 +#define AOFF_task_old_maj_flt 0x00000240 +#define ASIZ_task_old_maj_flt 0x00000008 +#define AOFF_task_dec_flt 0x00000248 +#define ASIZ_task_dec_flt 0x00000008 +#define AOFF_task_swap_cnt 0x00000250 +#define ASIZ_task_swap_cnt 0x00000008 +#define AOFF_task_rlim 0x00000258 +#define ASIZ_task_rlim 0x000000a0 +#define AOFF_task_used_math 0x000002f8 +#define ASIZ_task_used_math 0x00000002 +#define AOFF_task_comm 0x000002fa +#define ASIZ_task_comm 0x00000010 +#define AOFF_task_link_count 0x0000030c +#define ASIZ_task_link_count 0x00000004 +#define AOFF_task_tty 0x00000310 +#define ASIZ_task_tty 0x00000008 +#define AOFF_task_semundo 0x00000318 +#define ASIZ_task_semundo 0x00000008 +#define AOFF_task_semsleeping 0x00000320 +#define ASIZ_task_semsleeping 0x00000008 +#define AOFF_task_ldt 0x00000328 +#define ASIZ_task_ldt 0x00000008 +#define AOFF_task_tss 0x00000340 +#define ASIZ_task_tss 0x00000700 +#define AOFF_task_fs 0x00000a40 +#define ASIZ_task_fs 0x00000008 +#define AOFF_task_files 0x00000a48 +#define ASIZ_task_files 0x00000008 +#define AOFF_task_mm 0x00000a50 +#define ASIZ_task_mm 0x00000008 +#define AOFF_task_sig 0x00000a58 +#define ASIZ_task_sig 0x00000008 +#define AOFF_task_processor 0x00000a60 +#define ASIZ_task_processor 0x00000004 +#define AOFF_task_last_processor 0x00000a64 +#define ASIZ_task_last_processor 0x00000004 +#define AOFF_task_lock_depth 0x00000a68 +#define ASIZ_task_lock_depth 0x00000004 +#define AOFF_mm_count 0x00000000 +#define ASIZ_mm_count 0x00000004 +#define AOFF_mm_pgd 0x00000008 +#define ASIZ_mm_pgd 0x00000008 +#define AOFF_mm_context 0x00000010 +#define ASIZ_mm_context 0x00000008 +#define AOFF_mm_start_code 0x00000018 +#define ASIZ_mm_start_code 0x00000008 +#define AOFF_mm_end_code 0x00000020 +#define ASIZ_mm_end_code 0x00000008 +#define AOFF_mm_start_data 0x00000028 +#define ASIZ_mm_start_data 0x00000008 +#define AOFF_mm_end_data 0x00000030 +#define ASIZ_mm_end_data 0x00000008 +#define AOFF_mm_start_brk 0x00000038 +#define ASIZ_mm_start_brk 0x00000008 +#define AOFF_mm_brk 0x00000040 +#define ASIZ_mm_brk 0x00000008 +#define AOFF_mm_start_stack 0x00000048 +#define ASIZ_mm_start_stack 0x00000008 +#define AOFF_mm_start_mmap 0x00000050 +#define ASIZ_mm_start_mmap 0x00000008 +#define AOFF_mm_arg_start 0x00000058 +#define ASIZ_mm_arg_start 0x00000008 +#define AOFF_mm_arg_end 0x00000060 +#define ASIZ_mm_arg_end 0x00000008 +#define AOFF_mm_env_start 0x00000068 +#define ASIZ_mm_env_start 0x00000008 +#define AOFF_mm_env_end 0x00000070 +#define ASIZ_mm_env_end 0x00000008 +#define AOFF_mm_rss 0x00000078 +#define ASIZ_mm_rss 0x00000008 +#define AOFF_mm_total_vm 0x00000080 +#define ASIZ_mm_total_vm 0x00000008 +#define AOFF_mm_locked_vm 0x00000088 +#define ASIZ_mm_locked_vm 0x00000008 +#define AOFF_mm_def_flags 0x00000090 +#define ASIZ_mm_def_flags 0x00000008 +#define AOFF_mm_mmap 0x00000098 +#define ASIZ_mm_mmap 0x00000008 +#define AOFF_mm_mmap_avl 0x000000a0 +#define ASIZ_mm_mmap_avl 0x00000008 +#define AOFF_mm_mmap_sem 0x000000a8 +#define ASIZ_mm_mmap_sem 0x00000010 +#define AOFF_thread_float_regs 0x00000000 +#define ASIZ_thread_float_regs 0x00000100 +#define AOFF_thread_fsr 0x00000100 +#define ASIZ_thread_fsr 0x00000008 +#define AOFF_thread_fpqdepth 0x00000108 +#define ASIZ_thread_fpqdepth 0x00000008 +#define AOFF_thread_fpqueue 0x00000110 +#define ASIZ_thread_fpqueue 0x00000100 +#define AOFF_thread_user_globals 0x00000210 +#define ASIZ_thread_user_globals 0x00000040 +#define AOFF_thread_ksp 0x00000250 +#define ASIZ_thread_ksp 0x00000008 +#define AOFF_thread_kpc 0x00000258 +#define ASIZ_thread_kpc 0x00000008 +#define AOFF_thread_reg_window 0x00000260 +#define ASIZ_thread_reg_window 0x00000400 +#define AOFF_thread_rwbuf_stkptrs 0x00000660 +#define ASIZ_thread_rwbuf_stkptrs 0x00000040 +#define AOFF_thread_w_saved 0x000006a0 +#define ASIZ_thread_w_saved 0x00000008 +#define AOFF_thread_flags 0x000006a8 +#define ASIZ_thread_flags 0x00000008 +#define AOFF_thread_sig_address 0x000006b0 +#define ASIZ_thread_sig_address 0x00000008 +#define AOFF_thread_sig_desc 0x000006b8 +#define ASIZ_thread_sig_desc 0x00000008 +#define AOFF_thread_sstk_info 0x000006c0 +#define ASIZ_thread_sstk_info 0x00000010 +#define AOFF_thread_current_ds 0x000006d0 +#define ASIZ_thread_current_ds 0x00000004 +#define AOFF_thread_new_signal 0x000006d4 +#define ASIZ_thread_new_signal 0x00000004 +#define AOFF_thread_core_exec 0x000006d8 +#define ASIZ_thread_core_exec 0x00000020 + +#endif /* __ASM_OFFSETS_H__ */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h --- v2.1.28/linux/include/asm-sparc64/head.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/head.h Wed Mar 5 17:04:33 1997 @@ -1,13 +1,9 @@ -/* $Id: head.h,v 1.2 1996/12/28 18:39:49 davem Exp $ */ +/* $Id: head.h,v 1.4 1997/02/25 20:00:32 jj Exp $ */ #ifndef _SPARC64_HEAD_H #define _SPARC64_HEAD_H #define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop; -#define BTRAP(lvl) - -#define BTRAPTL1(lvl) - #define CLEAN_WINDOW \ clr %o0; clr %o1; clr %o2; clr %o3; \ clr %o4; clr %o5; clr %o6; clr %o7; \ @@ -17,24 +13,194 @@ wrpr %g1, 0x0, %cleanwin; retry; \ nop; nop; nop; nop; -#define TRAP(routine) \ - b etrap; \ - rd %pc, %g7; \ - call routine; \ - add %sp, REGWIN_SZ, %o0; \ - b rtrap; \ - subcc %g0, %o0, %g0; \ - nop; \ +#define TRAP(routine) \ + b etrap; \ + rd %pc, %g7; \ + call routine; \ + add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ + b rtrap; \ + subcc %g0, %o0, %g0; \ + nop; \ nop; -#define TRAP_IRQ(routine, level) \ - b etrap; \ - rd %pc, %g7; \ - add %sp, REGWIN_SZ, %o0; \ - call routine; \ - mov level, %o1; \ - b rtrap; \ - subcc %g0, %o0, %g0; \ +#define TRAP_ARG(routine, arg) \ + b etrap; \ + rd %pc, %g7; \ + add %sp, STACK_BIAS + REGWIN_SZ, %o0; \ + call routine; \ + mov arg, %o1; \ + b rtrap; \ + subcc %g0, %o0, %g0; \ nop; + +/* FIXME: Write these actually */ +#define SUNOS_SYSCALL_TRAP TRAP(sunos_syscall) +#define LINUX_32BIT_SYSCALL_TRAP TRAP(linux32_syscall) +#define LINUX_64BIT_SYSCALL_TRAP TRAP(linux64_syscall) +#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall) +#define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall) +#define BREAKPOINT_TRAP TRAP(breakpoint_trap) +#define GETCC_TRAP TRAP(getcc) +#define SETCC_TRAP TRAP(setcc) +#define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl) + +#define TRAP_IRQ(routine, level) TRAP_ARG(routine, level) + +#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl) + +#define BTRAPTL1(lvl) TRAP_ARG(bad_trap_tl1, lvl) + +#define FLUSH_WINDOW_TRAP \ + flushw; \ + done; nop; nop; nop; nop; nop; nop; + + +/* Normal kernel spill */ +#define SPILL_0_NORMAL \ + stx %l0, [%sp + STACK_BIAS + 0x00]; \ + stx %l1, [%sp + STACK_BIAS + 0x08]; \ + stx %l2, [%sp + STACK_BIAS + 0x10]; \ + stx %l3, [%sp + STACK_BIAS + 0x18]; \ + stx %l4, [%sp + STACK_BIAS + 0x20]; \ + stx %l5, [%sp + STACK_BIAS + 0x28]; \ + stx %l6, [%sp + STACK_BIAS + 0x30]; \ + stx %l7, [%sp + STACK_BIAS + 0x38]; \ + stx %i0, [%sp + STACK_BIAS + 0x40]; \ + stx %i1, [%sp + STACK_BIAS + 0x48]; \ + stx %i2, [%sp + STACK_BIAS + 0x50]; \ + stx %i3, [%sp + STACK_BIAS + 0x58]; \ + stx %i4, [%sp + STACK_BIAS + 0x60]; \ + stx %i5, [%sp + STACK_BIAS + 0x68]; \ + stx %i6, [%sp + STACK_BIAS + 0x70]; \ + stx %i7, [%sp + STACK_BIAS + 0x78]; \ + saved; retry; nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; nop; nop; + +/* Normal 64bit spill */ +#define SPILL_1_NORMAL \ + wr %g0, ASI_AIUP, %asi; \ + stxa %l0, [%sp + STACK_BIAS + 0x00] %asi; \ + stxa %l1, [%sp + STACK_BIAS + 0x08] %asi; \ + stxa %l2, [%sp + STACK_BIAS + 0x10] %asi; \ + stxa %l3, [%sp + STACK_BIAS + 0x18] %asi; \ + stxa %l4, [%sp + STACK_BIAS + 0x20] %asi; \ + stxa %l5, [%sp + STACK_BIAS + 0x28] %asi; \ + stxa %l6, [%sp + STACK_BIAS + 0x30] %asi; \ + stxa %l7, [%sp + STACK_BIAS + 0x38] %asi; \ + stxa %i0, [%sp + STACK_BIAS + 0x40] %asi; \ + stxa %i1, [%sp + STACK_BIAS + 0x48] %asi; \ + stxa %i2, [%sp + STACK_BIAS + 0x50] %asi; \ + stxa %i3, [%sp + STACK_BIAS + 0x58] %asi; \ + stxa %i4, [%sp + STACK_BIAS + 0x60] %asi; \ + stxa %i5, [%sp + STACK_BIAS + 0x68] %asi; \ + stxa %i6, [%sp + STACK_BIAS + 0x70] %asi; \ + stxa %i7, [%sp + STACK_BIAS + 0x78] %asi; \ + saved; retry; nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; nop; + +/* Normal 32bit spill */ +#define SPILL_2_NORMAL \ + wr %g0, ASI_AIUP, %asi; \ + srl %sp, 0, %sp; \ + stda %l0, [%sp + 0x00] %asi; \ + stda %l2, [%sp + 0x10] %asi; \ + stda %l4, [%sp + 0x20] %asi; \ + stda %l6, [%sp + 0x30] %asi; \ + stda %i0, [%sp + 0x40] %asi; \ + stda %i2, [%sp + 0x50] %asi; \ + stda %i4, [%sp + 0x60] %asi; \ + stda %i6, [%sp + 0x70] %asi; \ + saved; retry; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; nop; nop; + +#define SPILL_3_NORMAL SPILL_0_NORMAL +#define SPILL_4_NORMAL SPILL_0_NORMAL +#define SPILL_5_NORMAL SPILL_0_NORMAL +#define SPILL_6_NORMAL SPILL_0_NORMAL +#define SPILL_7_NORMAL SPILL_0_NORMAL + +#define SPILL_0_OTHER SPILL_0_NORMAL +#define SPILL_1_OTHER SPILL_1_NORMAL +#define SPILL_2_OTHER SPILL_2_NORMAL +#define SPILL_3_OTHER SPILL_3_NORMAL +#define SPILL_4_OTHER SPILL_4_NORMAL +#define SPILL_5_OTHER SPILL_5_NORMAL +#define SPILL_6_OTHER SPILL_6_NORMAL +#define SPILL_7_OTHER SPILL_7_NORMAL + +/* Normal kernel fill */ +#define FILL_0_NORMAL \ + ldx [%sp + STACK_BIAS + 0x00], %l0; \ + ldx [%sp + STACK_BIAS + 0x08], %l1; \ + ldx [%sp + STACK_BIAS + 0x10], %l2; \ + ldx [%sp + STACK_BIAS + 0x18], %l3; \ + ldx [%sp + STACK_BIAS + 0x20], %l4; \ + ldx [%sp + STACK_BIAS + 0x28], %l5; \ + ldx [%sp + STACK_BIAS + 0x30], %l6; \ + ldx [%sp + STACK_BIAS + 0x38], %l7; \ + ldx [%sp + STACK_BIAS + 0x40], %i0; \ + ldx [%sp + STACK_BIAS + 0x48], %i1; \ + ldx [%sp + STACK_BIAS + 0x50], %i2; \ + ldx [%sp + STACK_BIAS + 0x58], %i3; \ + ldx [%sp + STACK_BIAS + 0x60], %i4; \ + ldx [%sp + STACK_BIAS + 0x68], %i5; \ + ldx [%sp + STACK_BIAS + 0x70], %i6; \ + ldx [%sp + STACK_BIAS + 0x78], %i7; \ + saved; retry; nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; nop; nop; + +/* Normal 64bit fill */ +#define FILL_1_NORMAL \ + wr %g0, ASI_AIUP, %asi; \ + ldxa [%sp + STACK_BIAS + 0x00] %asi, %l0; \ + ldxa [%sp + STACK_BIAS + 0x08] %asi, %l1; \ + ldxa [%sp + STACK_BIAS + 0x10] %asi, %l2; \ + ldxa [%sp + STACK_BIAS + 0x18] %asi, %l3; \ + ldxa [%sp + STACK_BIAS + 0x20] %asi, %l4; \ + ldxa [%sp + STACK_BIAS + 0x28] %asi, %l5; \ + ldxa [%sp + STACK_BIAS + 0x30] %asi, %l6; \ + ldxa [%sp + STACK_BIAS + 0x38] %asi, %l7; \ + ldxa [%sp + STACK_BIAS + 0x40] %asi, %i0; \ + ldxa [%sp + STACK_BIAS + 0x48] %asi, %i1; \ + ldxa [%sp + STACK_BIAS + 0x50] %asi, %i2; \ + ldxa [%sp + STACK_BIAS + 0x58] %asi, %i3; \ + ldxa [%sp + STACK_BIAS + 0x60] %asi, %i4; \ + ldxa [%sp + STACK_BIAS + 0x68] %asi, %i5; \ + ldxa [%sp + STACK_BIAS + 0x70] %asi, %i6; \ + ldxa [%sp + STACK_BIAS + 0x78] %asi, %i7; \ + saved; retry; nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; nop; + +/* Normal 32bit fill */ +#define FILL_2_NORMAL \ + wr %g0, ASI_AIUP, %asi; \ + srl %sp, 0, %sp; \ + ldda [%sp + 0x00] %asi, %l0; \ + ldda [%sp + 0x10] %asi, %l2; \ + ldda [%sp + 0x20] %asi, %l4; \ + ldda [%sp + 0x30] %asi, %l6; \ + ldda [%sp + 0x40] %asi, %i0; \ + ldda [%sp + 0x50] %asi, %i2; \ + ldda [%sp + 0x60] %asi, %i4; \ + ldda [%sp + 0x70] %asi, %i6; \ + saved; retry; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; nop; nop; \ + nop; nop; nop; nop; nop; nop; nop; nop; + +#define FILL_3_NORMAL FILL_0_NORMAL +#define FILL_4_NORMAL FILL_0_NORMAL +#define FILL_5_NORMAL FILL_0_NORMAL +#define FILL_6_NORMAL FILL_0_NORMAL +#define FILL_7_NORMAL FILL_0_NORMAL + +#define FILL_0_OTHER FILL_0_NORMAL +#define FILL_1_OTHER FILL_1_NORMAL +#define FILL_2_OTHER FILL_2_NORMAL +#define FILL_3_OTHER FILL_3_NORMAL +#define FILL_4_OTHER FILL_4_NORMAL +#define FILL_5_OTHER FILL_5_NORMAL +#define FILL_6_OTHER FILL_6_NORMAL +#define FILL_7_OTHER FILL_7_NORMAL #endif /* !(_SPARC64_HEAD_H) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h --- v2.1.28/linux/include/asm-sparc64/io.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/io.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: io.h,v 1.1 1996/12/26 13:25:21 davem Exp $ */ +/* $Id: io.h,v 1.3 1997/03/03 16:51:53 jj Exp $ */ #ifndef __SPARC64_IO_H #define __SPARC64_IO_H @@ -7,48 +7,18 @@ #include /* IO address mapping routines need this */ #include -extern void sun4c_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly); -extern void srmmu_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly); +extern void sparc_ultra_mapioaddr (unsigned long physaddr, unsigned long virt_addr, int bus, int rdonly); +extern void sparc_ultra_unmapioaddr (unsigned long virt_addr); -extern __inline__ void mapioaddr(unsigned long physaddr, unsigned long virt_addr, - int bus, int rdonly) +extern __inline__ void mapioaddr (unsigned long physaddr, unsigned long virt_addr, int bus, int rdonly) { - switch(sparc_cpu_model) { - case sun4c: - sun4c_mapioaddr(physaddr, virt_addr, bus, rdonly); - break; - case sun4m: - case sun4d: - case sun4e: - srmmu_mapioaddr(physaddr, virt_addr, bus, rdonly); - break; - default: - printk("mapioaddr: Trying to map IO space for unsupported machine.\n"); - printk("mapioaddr: sparc_cpu_model = %d\n", sparc_cpu_model); - printk("mapioaddr: Halting...\n"); - halt(); - }; + sparc_ultra_mapioaddr (physaddr, virt_addr, bus, rdonly); return; } -extern void srmmu_unmapioaddr(unsigned long virt); -extern void sun4c_unmapioaddr(unsigned long virt); - extern __inline__ void unmapioaddr(unsigned long virt_addr) { - switch(sparc_cpu_model) { - case sun4c: - sun4c_unmapioaddr(virt_addr); - break; - case sun4m: - case sun4d: - case sun4e: - srmmu_unmapioaddr(virt_addr); - break; - default: - printk("unmapioaddr: sparc_cpu_model = %d, halt...\n", sparc_cpu_model); - halt(); - }; + sparc_ultra_unmapioaddr (virt_addr); return; } diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/openprom.h linux/include/asm-sparc64/openprom.h --- v2.1.28/linux/include/asm-sparc64/openprom.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/openprom.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: openprom.h,v 1.1 1996/12/26 14:22:32 davem Exp $ */ +/* $Id: openprom.h,v 1.2 1997/02/25 12:40:41 jj Exp $ */ #ifndef __SPARC64_OPENPROM_H #define __SPARC64_OPENPROM_H @@ -51,7 +51,7 @@ struct linux_mlist_v0 { struct linux_mlist_v0 *theres_more; - char *start_adr; + unsigned start_adr; unsigned num_bytes; }; @@ -187,8 +187,13 @@ struct linux_prom_registers { int which_io; /* is this in OBIO space? */ - char *phys_addr; /* The physical address of this register */ + unsigned phys_addr; /* The physical address of this register */ int reg_size; /* How many bytes does this register take up? */ +}; + +struct linux_prom64_registers { + long phys_addr; + long reg_size; }; struct linux_prom_irqs { diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h --- v2.1.28/linux/include/asm-sparc64/oplib.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/oplib.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.2 1996/12/27 08:49:07 jj Exp $ +/* $Id: oplib.h,v 1.4 1997/02/25 20:00:34 jj Exp $ * oplib.h: Describes the interface and available routines in the * Linux Prom library. * @@ -29,6 +29,23 @@ */ extern int prom_root_node; +/* /chosen node of the prom device tree, this stays constant after + * initialization is complete. + */ +extern int prom_chosen_node; + +struct linux_mlist_p1275 { + struct linux_mlist_p1275 *theres_more; + unsigned long start_adr; + unsigned long num_bytes; +}; + +struct linux_mem_p1275 { + struct linux_mlist_p1275 **p1275_totphys; + struct linux_mlist_p1275 **p1275_prommap; + struct linux_mlist_p1275 **p1275_available; /* What we can use */ +}; + /* The functions... */ /* You must call prom_init() before using any of the library services, @@ -72,7 +89,7 @@ * These lists are returned pre-sorted, this should make your life easier * since the prom itself is way too lazy to do such nice things. */ -extern struct linux_mem_v0 *prom_meminfo(void); +extern struct linux_mem_p1275 *prom_meminfo(void); /* Miscellaneous routines, don't really fit in any category per se. */ @@ -252,17 +269,18 @@ extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges, struct linux_prom_ranges *pranges, int npranges); -/* Apply promlib probed OBIO ranges to registers. */ -extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs); - /* Apply ranges of any prom node (and optionally parent node as well) to registers. */ extern void prom_apply_generic_ranges(int node, int parent, struct linux_prom_registers *sbusregs, int nregs); -extern long (*prom_command)(char *, long, ...); +extern long p1275_cmd (char *, long, ...); +#if 0 #define P1275_SIZE(x) ((((long)((x) / 32)) << 32) | (x)) +#else +#define P1275_SIZE(x) x +#endif /* We support at most 16 input and 1 output argument */ #define P1275_ARG_NUMBER 0 @@ -270,10 +288,11 @@ #define P1275_ARG_OUT_BUF 2 #define P1275_ARG_OUT_32B 3 #define P1275_ARG_IN_FUNCTION 4 +#define P1275_ARG_IN_BUF 5 #define P1275_IN(x) ((x) & 0xf) #define P1275_OUT(x) (((x) << 4) & 0xf0) #define P1275_INOUT(i,o) (P1275_IN(i)|P1275_OUT(o)) -#define P1275_ARG(n,x) ((x) << ((n)*3 + 8) +#define P1275_ARG(n,x) ((x) << ((n)*3 + 8)) #endif /* !(__SPARC64_OPLIB_H) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h --- v2.1.28/linux/include/asm-sparc64/page.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/page.h Wed Mar 5 17:04:33 1997 @@ -1,16 +1,16 @@ -/* $Id: page.h,v 1.4 1996/12/28 18:39:51 davem Exp $ */ +/* $Id: page.h,v 1.5 1997/02/25 20:00:36 jj Exp $ */ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H #define PAGE_SHIFT 13 -#ifndef __ASSEMBLY__ +#ifdef __KERNEL__ -#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) -#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) @@ -73,12 +73,12 @@ #endif /* !(__ASSEMBLY__) */ -#define TASK_UNMAPPED_BASE 0x0000000070000000UL +#define TASK_UNMAPPED_BASE 0x0000000070000000 /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) -#define PAGE_OFFSET 0xFFFFF80000000000UL +#define PAGE_OFFSET 0xFFFFF80000000000 #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.1.28/linux/include/asm-sparc64/pgtable.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/pgtable.h Wed Mar 5 17:04:33 1997 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.8 1996/12/28 18:39:52 davem Exp $ +/* $Id: pgtable.h,v 1.10 1997/03/03 16:51:54 jj Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996 David S. Miller (davem@caip.rutgers.edu) @@ -11,6 +11,9 @@ * the SpitFire page tables. */ +#ifndef __ASSEMBLY__ +#include +#endif #include #include #include @@ -48,32 +51,32 @@ #endif /* !(__ASSEMBLY__) */ /* SpitFire TTE bits. */ -#define _PAGE_VALID 0x8000000000000000UL /* Valid TTE */ -#define _PAGE_R 0x8000000000000000UL /* Used to keep ref bit up to date */ -#define _PAGE_SZ4MB 0x6000000000000000UL /* 4MB Page */ -#define _PAGE_SZ512K 0x4000000000000000UL /* 512K Page */ -#define _PAGE_SZ64K 0x2000000000000000UL /* 64K Page */ -#define _PAGE_SZ8K 0x0000000000000000UL /* 8K Page */ -#define _PAGE_NFO 0x1000000000000000UL /* No Fault Only */ -#define _PAGE_IE 0x0800000000000000UL /* Invert Endianness */ -#define _PAGE_SOFT2 0x07FC000000000000UL /* Second set of software bits */ -#define _PAGE_DIAG 0x0003FE0000000000UL /* Diagnostic TTE bits */ -#define _PAGE_PADDR 0x000001FFFFFFE000UL /* Physical Address bits [40:13] */ -#define _PAGE_SOFT 0x0000000000001F80UL /* First set of software bits */ -#define _PAGE_L 0x0000000000000040UL /* Locked TTE */ -#define _PAGE_CP 0x0000000000000020UL /* Cacheable in Physical Cache */ -#define _PAGE_CV 0x0000000000000010UL /* Cacheable in Virtual Cache */ -#define _PAGE_E 0x0000000000000008UL /* side-Effect */ -#define _PAGE_P 0x0000000000000004UL /* Privileged Page */ -#define _PAGE_W 0x0000000000000002UL /* Writable */ -#define _PAGE_G 0x0000000000000001UL /* Global */ +#define _PAGE_VALID 0x8000000000000000 /* Valid TTE */ +#define _PAGE_R 0x8000000000000000 /* Used to keep ref bit up to date */ +#define _PAGE_SZ4MB 0x6000000000000000 /* 4MB Page */ +#define _PAGE_SZ512K 0x4000000000000000 /* 512K Page */ +#define _PAGE_SZ64K 0x2000000000000000 /* 64K Page */ +#define _PAGE_SZ8K 0x0000000000000000 /* 8K Page */ +#define _PAGE_NFO 0x1000000000000000 /* No Fault Only */ +#define _PAGE_IE 0x0800000000000000 /* Invert Endianness */ +#define _PAGE_SOFT2 0x07FC000000000000 /* Second set of software bits */ +#define _PAGE_DIAG 0x0003FE0000000000 /* Diagnostic TTE bits */ +#define _PAGE_PADDR 0x000001FFFFFFE000 /* Physical Address bits [40:13] */ +#define _PAGE_SOFT 0x0000000000001F80 /* First set of software bits */ +#define _PAGE_L 0x0000000000000040 /* Locked TTE */ +#define _PAGE_CP 0x0000000000000020 /* Cacheable in Physical Cache */ +#define _PAGE_CV 0x0000000000000010 /* Cacheable in Virtual Cache */ +#define _PAGE_E 0x0000000000000008 /* side-Effect */ +#define _PAGE_P 0x0000000000000004 /* Privileged Page */ +#define _PAGE_W 0x0000000000000002 /* Writable */ +#define _PAGE_G 0x0000000000000001 /* Global */ /* Here are the SpitFire software bits we use in the TTE's. */ -#define _PAGE_PRESENT 0x0000000000001000UL /* Present Page (ie. not swapped out) */ -#define _PAGE_MODIFIED 0x0000000000000800UL /* Modified Page (ie. dirty) */ -#define _PAGE_ACCESSED 0x0000000000000400UL /* Accessed Page (ie. referenced) */ -#define _PAGE_READ 0x0000000000000200UL /* Readable SW Bit */ -#define _PAGE_WRITE 0x0000000000000100UL /* Writable SW Bit */ +#define _PAGE_PRESENT 0x0000000000001000 /* Present Page (ie. not swapped out) */ +#define _PAGE_MODIFIED 0x0000000000000800 /* Modified Page (ie. dirty) */ +#define _PAGE_ACCESSED 0x0000000000000400 /* Accessed Page (ie. referenced) */ +#define _PAGE_READ 0x0000000000000200 /* Readable SW Bit */ +#define _PAGE_WRITE 0x0000000000000100 /* Writable SW Bit */ #define _PAGE_CACHE (_PAGE_CP | _PAGE_CV) @@ -365,18 +368,17 @@ extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir) { - register unsigned long paddr asm("%o5"); + register unsigned long paddr asm("o5"); paddr = ((unsigned long) pgdir) - PAGE_OFFSET; if(tsk->mm == current->mm) { __asm__ __volatile__(" rdpr %%pstate, %%g1 - or %%g1, %1, %%g2 - wrpr %%g2, %2, %%pstate + wrpr %%g1, %2, %%pstate mov %0, %%g7 wrpr %%g1, 0x0, %%pstate - " : : "r" (paddr), "i" (PSTATE_MG), "i" (PSTATE_IE) + " : : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE) : "g1", "g2"); } } diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/poll.h linux/include/asm-sparc64/poll.h --- v2.1.28/linux/include/asm-sparc64/poll.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/poll.h Wed Mar 5 17:04:33 1997 @@ -0,0 +1,21 @@ +#ifndef __SPARC64_POLL_H +#define __SPARC64_POLL_H + +#define POLLIN 1 +#define POLLPRI 2 +#define POLLOUT 4 +#define POLLERR 8 +#define POLLHUP 16 +#define POLLNVAL 32 +#define POLLRDNORM 64 +#define POLLWRNORM POLLOUT +#define POLLRDBAND 128 +#define POLLWRBAND 256 + +struct pollfd { + int fd; + short events; + short revents; +}; + +#endif diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h --- v2.1.28/linux/include/asm-sparc64/processor.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/processor.h Wed Mar 5 17:04:34 1997 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.6 1996/12/28 20:05:14 davem Exp $ +/* $Id: processor.h,v 1.8 1997/03/04 16:27:33 jj Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -32,30 +32,28 @@ #ifndef __ASSEMBLY__ -/* Ok this is hot. Sparc exception save area. */ -struct exception_struct { - unsigned long count; /* Exception count */ - unsigned long pc; /* Callers PC for copy/clear user */ - unsigned long expc; /* Where to jump when exception signaled */ - unsigned long address; /* Saved user base address for transfer */ +struct fpq { + unsigned long *insn_addr; + unsigned long insn; }; #define NSWINS 8 /* The Sparc processor specific thread struct. */ struct thread_struct { - /* Context switch saved kernel state. */ - unsigned long user_globals[8]; /* performance hack */ - unsigned long ksp, kpc; - /* Floating point regs */ - unsigned long float_regs[64] __attribute__ ((aligned (64))); + /* Please check asm_offsets, so that not to much precious space + is wasted by this alignment and move the float_regs wherever + is better in this structure. Remember every byte of alignment + is multiplied by 512 to get the amount of wasted kernel memory. */ + unsigned int float_regs[64] __attribute__ ((aligned (64))); unsigned long fsr; unsigned long fpqdepth; - struct fpq { - unsigned long *insn_addr; - unsigned long insn; - } fpqueue[16]; + struct fpq fpqueue[16]; + + /* Context switch saved kernel state. */ + unsigned long user_globals[8]; /* performance hack */ + unsigned long ksp, kpc; /* Storage for windows when user stack is bogus. */ struct reg_window reg_window[NSWINS] __attribute__ ((aligned (16))); @@ -69,7 +67,6 @@ unsigned long sig_address __attribute__ ((aligned (8))); unsigned long sig_desc; - struct exception_struct; struct sigstack sstk_info; int current_ds, new_signal; struct exec core_exec; /* just what it says. */ @@ -86,16 +83,16 @@ PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC } #define INIT_TSS { \ -/* user_globals */ \ - { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ -/* ksp, kpc */ \ - 0, 0, \ /* FPU regs */ { 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, }, \ /* FPU status, FPU qdepth, FPU queue */ \ 0, 0, { { 0, 0, }, }, \ +/* user_globals */ \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ +/* ksp, kpc */ \ + 0, 0, \ /* reg_window */ \ { { { 0, }, { 0, } }, }, \ /* rwbuf_stkptrs */ \ @@ -107,7 +104,7 @@ /* sig_address, sig_desc */ \ 0, 0, \ /* ex, sstk_info, current_ds, */ \ - { 0, }, { 0, 0, }, USER_DS, \ + { 0, 0, }, USER_DS, \ /* new_signal */ \ 0, \ /* core_exec */ \ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/ptrace.h linux/include/asm-sparc64/ptrace.h --- v2.1.28/linux/include/asm-sparc64/ptrace.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/ptrace.h Wed Mar 5 17:04:34 1997 @@ -1,4 +1,4 @@ -/* $Id: ptrace.h,v 1.4 1996/12/28 18:39:54 davem Exp $ */ +/* $Id: ptrace.h,v 1.7 1997/03/04 16:27:32 jj Exp $ */ #ifndef _SPARC64_PTRACE_H #define _SPARC64_PTRACE_H @@ -102,13 +102,153 @@ #else /* __ASSEMBLY__ */ /* For assembly code. */ -#define TRACEREG_SZ XXX -#define STACKFRAME_SZ YYY -#define REGWIN_SZ ZZZ +#define TRACEREG_SZ 0xa0 +#define STACKFRAME_SZ 0xc0 +#define REGWIN_SZ 0x80 #define TRACEREG32_SZ 0x50 #define STACKFRAME32_SZ 0x60 #define REGWIN32_SZ 0x40 + +#include #endif + +#define STACK_BIAS 2047 + +/* These are for pt_regs. */ +#define PT_V9_G0 0x00 +#define PT_V9_G1 0x08 +#define PT_V9_G2 0x10 +#define PT_V9_G3 0x18 +#define PT_V9_G4 0x20 +#define PT_V9_G5 0x28 +#define PT_V9_G6 0x30 +#define PT_V9_G7 0x38 +#define PT_V9_I0 0x40 +#define PT_V9_I1 0x48 +#define PT_V9_I2 0x50 +#define PT_V9_I3 0x58 +#define PT_V9_I4 0x60 +#define PT_V9_I5 0x68 +#define PT_V9_I6 0x70 +#define PT_V9_FP PT_V9_I6 +#define PT_V9_I7 0x78 +#define PT_V9_TSTATE 0x80 +#define PT_V9_TPC 0x88 +#define PT_V9_TNPC 0x90 +#define PT_V9_Y 0x98 +#define PT_TSTATE PT_V9_TSTATE +#define PT_TPC PT_V9_TPC +#define PT_TNPC PT_V9_TNPC + +/* These for pt_regs32. */ +#define PT_PSR 0x0 +#define PT_PC 0x4 +#define PT_NPC 0x8 +#define PT_Y 0xc +#define PT_G0 0x10 +#define PT_WIM PT_G0 +#define PT_G1 0x14 +#define PT_G2 0x18 +#define PT_G3 0x1c +#define PT_G4 0x20 +#define PT_G5 0x24 +#define PT_G6 0x28 +#define PT_G7 0x2c +#define PT_I0 0x30 +#define PT_I1 0x34 +#define PT_I2 0x38 +#define PT_I3 0x3c +#define PT_I4 0x40 +#define PT_I5 0x44 +#define PT_I6 0x48 +#define PT_FP PT_I6 +#define PT_I7 0x4c + +/* Reg_window offsets */ +#define RW_V9_L0 0x00 +#define RW_V9_L1 0x08 +#define RW_V9_L2 0x10 +#define RW_V9_L3 0x18 +#define RW_V9_L4 0x20 +#define RW_V9_L5 0x28 +#define RW_V9_L6 0x30 +#define RW_V9_L7 0x38 +#define RW_V9_I0 0x40 +#define RW_V9_I1 0x48 +#define RW_V9_I2 0x50 +#define RW_V9_I3 0x58 +#define RW_V9_I4 0x60 +#define RW_V9_I5 0x68 +#define RW_V9_I6 0x70 +#define RW_V9_I7 0x78 + +#define RW_L0 0x00 +#define RW_L1 0x04 +#define RW_L2 0x08 +#define RW_L3 0x0c +#define RW_L4 0x10 +#define RW_L5 0x14 +#define RW_L6 0x18 +#define RW_L7 0x1c +#define RW_I0 0x20 +#define RW_I1 0x24 +#define RW_I2 0x28 +#define RW_I3 0x2c +#define RW_I4 0x30 +#define RW_I5 0x34 +#define RW_I6 0x38 +#define RW_I7 0x3c + +/* Stack_frame offsets */ +#define SF_V9_L0 0x00 +#define SF_V9_L1 0x08 +#define SF_V9_L2 0x10 +#define SF_V9_L3 0x18 +#define SF_V9_L4 0x20 +#define SF_V9_L5 0x28 +#define SF_V9_L6 0x30 +#define SF_V9_L7 0x38 +#define SF_V9_I0 0x40 +#define SF_V9_I1 0x48 +#define SF_V9_I2 0x50 +#define SF_V9_I3 0x58 +#define SF_V9_I4 0x60 +#define SF_V9_I5 0x68 +#define SF_V9_FP 0x70 +#define SF_V9_PC 0x78 +#define SF_V9_RETP 0x80 +#define SF_V9_XARG0 0x88 +#define SF_V9_XARG1 0x90 +#define SF_V9_XARG2 0x98 +#define SF_V9_XARG3 0xa0 +#define SF_V9_XARG4 0xa8 +#define SF_V9_XARG5 0xb0 +#define SF_V9_XXARG 0xb8 + +#define SF_L0 0x00 +#define SF_L1 0x04 +#define SF_L2 0x08 +#define SF_L3 0x0c +#define SF_L4 0x10 +#define SF_L5 0x14 +#define SF_L6 0x18 +#define SF_L7 0x1c +#define SF_I0 0x20 +#define SF_I1 0x24 +#define SF_I2 0x28 +#define SF_I3 0x2c +#define SF_I4 0x30 +#define SF_I5 0x34 +#define SF_FP 0x38 +#define SF_PC 0x3c +#define SF_RETP 0x40 +#define SF_XARG0 0x44 +#define SF_XARG1 0x48 +#define SF_XARG2 0x4c +#define SF_XARG3 0x50 +#define SF_XARG4 0x54 +#define SF_XARG5 0x58 +#define SF_XXARG 0x5c #endif /* !(_SPARC64_PTRACE_H) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/sbus.h linux/include/asm-sparc64/sbus.h --- v2.1.28/linux/include/asm-sparc64/sbus.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/sbus.h Wed Mar 5 17:04:34 1997 @@ -1,4 +1,4 @@ -/* $Id: sbus.h,v 1.1 1996/12/26 14:22:36 davem Exp $ +/* $Id: sbus.h,v 1.2 1997/02/25 20:00:35 jj Exp $ * sbus.h: Defines for the Sun SBus. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -53,7 +53,7 @@ char linux_name[64]; /* Name used internally by Linux */ struct linux_prom_registers reg_addrs[PROMREG_MAX]; - int num_registers; + int num_registers, ranges_applied; struct linux_prom_irqs irqs[PROMINTR_MAX]; int num_irqs; @@ -93,6 +93,7 @@ /* Apply promlib probed SBUS ranges to registers. */ extern void prom_apply_sbus_ranges(struct linux_sbus *sbus, - struct linux_prom_registers *sbusregs, int nregs); + struct linux_prom_registers *sbusregs, int nregs, + struct linux_sbus_device *sdev); #endif /* !(_SPARC64_SBUS_H) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h --- v2.1.28/linux/include/asm-sparc64/semaphore.h Fri Dec 13 01:37:47 1996 +++ linux/include/asm-sparc64/semaphore.h Wed Mar 5 17:04:34 1997 @@ -7,7 +7,7 @@ struct semaphore { atomic_t count; - atomic_t waiting; + atomic_t waking; struct wait_queue * wait; }; diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/sigcontext.h linux/include/asm-sparc64/sigcontext.h --- v2.1.28/linux/include/asm-sparc64/sigcontext.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc64/sigcontext.h Wed Mar 5 17:04:34 1997 @@ -1,6 +1,6 @@ -/* $Id: sigcontext.h,v 1.2 1997/01/19 22:32:15 ecd Exp $ */ -#ifndef _ASMsparc64_SIGCONTEXT_H -#define _ASMsparc64_SIGCONTEXT_H +/* $Id: sigcontext.h,v 1.3 1997/03/03 16:51:55 jj Exp $ */ +#ifndef __SPARC64_SIGCONTEXT_H +#define __SPARC64_SIGCONTEXT_H #include @@ -15,7 +15,7 @@ }; /* This is what SunOS does, so shall I. */ -struct sigcontext { +struct sigcontext32 { int sigc_onstack; /* state to restore */ int sigc_mask; /* sigmask to restore */ int sigc_sp; /* stack pointer */ @@ -32,19 +32,42 @@ /* stack ptrs for each regwin buf */ /* XXX 32-bit ptrs pinhead... */ - char *sigc_spbuf[SUNOS_MAXWIN]; + unsigned sigc_spbuf[SUNOS_MAXWIN]; /* Windows to restore after signal */ struct reg_window32 sigc_wbuf[SUNOS_MAXWIN]; }; +/* This is what SunOS doesn't, so we have to write this alone. */ +struct sigcontext { + int sigc_onstack; /* state to restore */ + int sigc_mask; /* sigmask to restore */ + int sigc_sp; /* stack pointer */ + int sigc_pc; /* program counter */ + int sigc_npc; /* next program counter */ + int sigc_psr; /* for condition codes etc */ + int sigc_g1; /* User uses these two registers */ + int sigc_o0; /* within the trampoline code. */ + + /* Now comes information regarding the users window set + * at the time of the signal. + */ + int sigc_oswins; /* outstanding windows */ + + /* stack ptrs for each regwin buf */ + char *sigc_spbuf[SUNOS_MAXWIN]; + + /* Windows to restore after signal */ + struct reg_window sigc_wbuf[SUNOS_MAXWIN]; +}; + typedef struct { struct pt_regs32 si_regs; int si_mask; } __siginfo32_t; typedef struct { - unsigned int si_float_regs [64]; + unsigned int si_float_regs [32]; unsigned int si_fsr; unsigned int si_fpqdepth; struct { @@ -60,7 +83,7 @@ } __siginfo_t; typedef struct { - unsigned long si_float_regs [64]; + unsigned int si_float_regs [64]; unsigned long si_fsr; unsigned int si_fpqdepth; struct { @@ -71,4 +94,4 @@ #endif /* !(__ASSEMBLY__) */ -#endif /* !(_ASMsparc64_SIGCONTEXT_H) */ +#endif /* !(__SPARC64_SIGCONTEXT_H) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/signal.h linux/include/asm-sparc64/signal.h --- v2.1.28/linux/include/asm-sparc64/signal.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/signal.h Wed Mar 5 17:04:34 1997 @@ -1,4 +1,4 @@ -/* $Id: signal.h,v 1.1 1996/12/26 14:22:37 davem Exp $ */ +/* $Id: signal.h,v 1.2 1997/03/03 16:51:57 jj Exp $ */ #ifndef _ASMSPARC64_SIGNAL_H #define _ASMSPARC64_SIGNAL_H @@ -164,13 +164,12 @@ }; struct sigaction32 { - /* XXX 32-bit func ptr... */ - __sighandler_t sa_handler; + unsigned sa_handler; sigset32_t sa_mask; unsigned int sa_flags; /* XXX 32-bit func ptr... */ - void (*sa_restorer) (void); /* not used by Linux/SPARC yet */ + unsigned sa_restorer; /* not used by Linux/SPARC yet */ }; #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h --- v2.1.28/linux/include/asm-sparc64/smp.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/smp.h Wed Mar 5 17:04:34 1997 @@ -17,6 +17,9 @@ int prom_node; int mid; }; + +extern int linux_num_cpus; /* number of CPUs probed */ + #endif /* !(__ASSEMBLY__) */ #ifdef __SMP__ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h --- v2.1.28/linux/include/asm-sparc64/string.h Mon Dec 30 02:00:03 1996 +++ linux/include/asm-sparc64/string.h Wed Mar 5 17:04:34 1997 @@ -1,8 +1,9 @@ -/* $Id: string.h,v 1.1 1996/12/26 14:22:40 davem Exp $ +/* $Id: string.h,v 1.3 1997/03/03 17:11:15 jj Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #ifndef __SPARC64_STRING_H__ @@ -10,13 +11,27 @@ /* Really, userland/ksyms should not see any of this stuff. */ -#if defined(__KERNEL__) && !defined(EXPORT_SYMTAB) +#ifdef __KERNEL__ + +extern void __memmove(void *,const void *,__kernel_size_t); +extern __kernel_size_t __memcpy(void *,const void *,__kernel_size_t); +extern __kernel_size_t __memset(void *,int,__kernel_size_t); + +#ifndef EXPORT_SYMTAB /* First the mem*() things. */ #define __HAVE_ARCH_BCOPY #define __HAVE_ARCH_MEMMOVE + +#undef memmove +#define memmove(_to, _from, _n) \ +({ \ + void *_t = (_to); \ + __memmove(_t, (_from), (_n)); \ + _t; \ +}) + #define __HAVE_ARCH_MEMCPY -extern void *__memcpy(void *,const void *,__kernel_size_t); extern inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n) { @@ -50,12 +65,11 @@ __nonconstant_memcpy((t),(f),(n))) #define __HAVE_ARCH_MEMSET -extern void *__memset(void *,int,__kernel_size_t); -extern inline void *__constant_c_and_count_memset(void *s, char c, size_t count) +extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count) { extern void *bzero_1page(void *); - extern void *__bzero(void *, size_t); + extern __kernel_size_t __bzero(void *, __kernel_size_t); if(!c) { if(count == 8192) @@ -68,9 +82,9 @@ return s; } -extern inline void *__constant_c_memset(void *s, char c, size_t count) +extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count) { - extern void *__bzero(void *, size_t); + extern __kernel_size_t __bzero(void *, __kernel_size_t); if(!c) __bzero(s, count); @@ -79,12 +93,18 @@ return s; } +extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count) +{ + __memset(s, c, count); + return s; +} + #undef memset #define memset(s, c, count) \ (__builtin_constant_p(c) ? (__builtin_constant_p(count) ? \ __constant_c_and_count_memset((s), (c), (count)) : \ __constant_c_memset((s), (c), (count))) \ - : __memset((s), (c), (count))) + : __nonconstant_memset((s), (c), (count))) #define __HAVE_ARCH_MEMSCAN @@ -173,6 +193,8 @@ __constant_strncmp(__arg0, __arg1, __arg2) : \ __strncmp(__arg0, __arg1, __arg2)) -#endif /* (__KERNEL__) && !(EXPORT_SYMTAB) */ +#endif /* !EXPORT_SYMTAB */ + +#endif /* __KERNEL__ */ #endif /* !(__SPARC64_STRING_H__) */ diff -u --recursive --new-file v2.1.28/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h --- v2.1.28/linux/include/asm-sparc64/uaccess.h Sun Jan 26 02:07:47 1997 +++ linux/include/asm-sparc64/uaccess.h Wed Mar 5 17:04:34 1997 @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.3 1997/01/16 14:19:08 davem Exp $ */ +/* $Id: uaccess.h,v 1.6 1997/03/03 16:51:54 jj Exp $ */ #ifndef _ASM_UACCESS_H #define _ASM_UACCESS_H @@ -114,45 +114,45 @@ struct __large_struct { unsigned long buf[100]; }; #define __m(x) ((struct __large_struct *)(x)) -#define __put_user_check(x,addr,size) ({ \ +#define __put_user_check(data,addr,size) ({ \ register int __pu_ret; \ if (__access_ok(addr,size)) { \ switch (size) { \ -case 1: __put_user_asm(x,b,addr,__pu_ret); break; \ -case 2: __put_user_asm(x,h,addr,__pu_ret); break; \ -case 4: __put_user_asm(x,w,addr,__pu_ret); break; \ -case 8: __put_user_asm(x,x,addr,__pu_ret); break; \ +case 1: __put_user_asm(data,b,addr,__pu_ret); break; \ +case 2: __put_user_asm(data,h,addr,__pu_ret); break; \ +case 4: __put_user_asm(data,w,addr,__pu_ret); break; \ +case 8: __put_user_asm(data,x,addr,__pu_ret); break; \ default: __pu_ret = __put_user_bad(); break; \ } } else { __pu_ret = -EFAULT; } __pu_ret; }) -#define __put_user_check_ret(x,addr,size,retval) ({ \ +#define __put_user_check_ret(data,addr,size,retval) ({ \ register int __foo __asm__ ("l1"); \ if (__access_ok(addr,size)) { \ switch (size) { \ -case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \ -case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \ -case 4: __put_user_asm_ret(x,w,addr,retval,__foo); break; \ -case 8: __put_user_asm_ret(x,x,addr,retval,__foo); break; \ +case 1: __put_user_asm_ret(data,b,addr,retval,__foo); break; \ +case 2: __put_user_asm_ret(data,h,addr,retval,__foo); break; \ +case 4: __put_user_asm_ret(data,w,addr,retval,__foo); break; \ +case 8: __put_user_asm_ret(data,x,addr,retval,__foo); break; \ default: if (__put_user_bad()) return retval; break; \ } } else return retval; }) -#define __put_user_nocheck(x,addr,size) ({ \ +#define __put_user_nocheck(data,addr,size) ({ \ register int __pu_ret; \ switch (size) { \ -case 1: __put_user_asm(x,b,addr,__pu_ret); break; \ -case 2: __put_user_asm(x,h,addr,__pu_ret); break; \ -case 4: __put_user_asm(x,w,addr,__pu_ret); break; \ -case 8: __put_user_asm(x,x,addr,__pu_ret); break; \ +case 1: __put_user_asm(data,b,addr,__pu_ret); break; \ +case 2: __put_user_asm(data,h,addr,__pu_ret); break; \ +case 4: __put_user_asm(data,w,addr,__pu_ret); break; \ +case 8: __put_user_asm(data,x,addr,__pu_ret); break; \ default: __pu_ret = __put_user_bad(); break; \ } __pu_ret; }) -#define __put_user_nocheck_ret(x,addr,size,retval) ({ \ +#define __put_user_nocheck_ret(data,addr,size,retval) ({ \ register int __foo __asm__ ("l1"); \ switch (size) { \ -case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \ -case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \ -case 4: __put_user_asm_ret(x,w,addr,retval,__foo); break; \ -case 8: __put_user_asm_ret(x,x,addr,retval,__foo); break; \ +case 1: __put_user_asm_ret(data,b,addr,retval,__foo); break; \ +case 2: __put_user_asm_ret(data,h,addr,retval,__foo); break; \ +case 4: __put_user_asm_ret(data,w,addr,retval,__foo); break; \ +case 8: __put_user_asm_ret(data,x,addr,retval,__foo); break; \ default: if (__put_user_bad()) return retval; break; \ } }) @@ -203,7 +203,7 @@ extern int __put_user_bad(void); -#define __get_user_check(x,addr,size,type) ({ \ +#define __get_user_check(data,addr,size,type) ({ \ register int __gu_ret; \ register unsigned long __gu_val; \ if (__access_ok(addr,size)) { \ @@ -213,9 +213,9 @@ case 4: __get_user_asm(__gu_val,uw,addr,__gu_ret); break; \ case 8: __get_user_asm(__gu_val,x,addr,__gu_ret); break; \ default: __gu_val = 0; __gu_ret = __get_user_bad(); break; \ -} } else { __gu_val = 0; __gu_ret = -EFAULT; } x = (type) __gu_val; __gu_ret; }) +} } else { __gu_val = 0; __gu_ret = -EFAULT; } data = (type) __gu_val; __gu_ret; }) -#define __get_user_check_ret(x,addr,size,type,retval) ({ \ +#define __get_user_check_ret(data,addr,size,type,retval) ({ \ register unsigned long __gu_val __asm__ ("l1"); \ if (__access_ok(addr,size)) { \ switch (size) { \ @@ -224,9 +224,9 @@ case 4: __get_user_asm_ret(__gu_val,uw,addr,retval); break; \ case 8: __get_user_asm_ret(__gu_val,x,addr,retval); break; \ default: if (__get_user_bad()) return retval; \ -} x = (type) __gu_val; } else return retval; }) +} data = (type) __gu_val; } else return retval; }) -#define __get_user_nocheck(x,addr,size,type) ({ \ +#define __get_user_nocheck(data,addr,size,type) ({ \ register int __gu_ret; \ register unsigned long __gu_val; \ switch (size) { \ @@ -235,9 +235,9 @@ case 4: __get_user_asm(__gu_val,uw,addr,__gu_ret); break; \ case 8: __get_user_asm(__gu_val,x,addr,__gu_ret); break; \ default: __gu_val = 0; __gu_ret = __get_user_bad(); break; \ -} x = (type) __gu_val; __gu_ret; }) +} data = (type) __gu_val; __gu_ret; }) -#define __get_user_nocheck_ret(x,addr,size,type,retval) ({ \ +#define __get_user_nocheck_ret(data,addr,size,type,retval) ({ \ register unsigned long __gu_val __asm__ ("l1"); \ switch (size) { \ case 1: __get_user_asm_ret(__gu_val,ub,addr,retval); break; \ @@ -245,7 +245,7 @@ case 4: __get_user_asm_ret(__gu_val,uw,addr,retval); break; \ case 8: __get_user_asm_ret(__gu_val,x,addr,retval); break; \ default: if (__get_user_bad()) return retval; \ -} x = (type) __gu_val; }) +} data = (type) __gu_val; }) #define __get_user_asm(x,size,addr,ret) \ __asm__ __volatile__( \ @@ -295,14 +295,14 @@ extern int __get_user_bad(void); -extern int __copy_user(unsigned long to, unsigned long from, int size); +extern __kernel_size_t __copy_user(void *to, void *from, __kernel_size_t size); #define copy_to_user(to,from,n) ({ \ -unsigned long __copy_to = (unsigned long) (to); \ -unsigned long __copy_size = (unsigned long) (n); \ -unsigned long __copy_res; \ +void *__copy_to = (void *) (to); \ +__kernel_size_t __copy_size = (__kernel_size_t) (n); \ +__kernel_size_t __copy_res; \ if(__copy_size && __access_ok(__copy_to, __copy_size)) { \ -__copy_res = __copy_user(__copy_to, (unsigned long) (from), __copy_size); \ +__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \ } else __copy_res = __copy_size; \ __copy_res; }) @@ -321,11 +321,11 @@ }) #define copy_from_user(to,from,n) ({ \ -unsigned long __copy_from = (unsigned long) (from); \ -unsigned long __copy_size = (unsigned long) (n); \ -unsigned long __copy_res; \ +void *__copy_from = (void *) (from); \ +__kernel_size_t __copy_size = (__kernel_size_t) (n); \ +__kernel_size_t __copy_res; \ if(__copy_size && __access_ok(__copy_from, __copy_size)) { \ -__copy_res = __copy_user((unsigned long) (to), __copy_from, __copy_size); \ +__copy_res = __copy_user((void *) (to), __copy_from, __copy_size); \ } else __copy_res = __copy_size; \ __copy_res; }) diff -u --recursive --new-file v2.1.28/linux/include/linux/cd1400.h linux/include/linux/cd1400.h --- v2.1.28/linux/include/linux/cd1400.h Mon Mar 11 01:20:33 1996 +++ linux/include/linux/cd1400.h Tue Mar 4 13:33:21 1997 @@ -3,6 +3,7 @@ /* * cd1400.h -- cd1400 UART hardware info. * + * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.1.28/linux/include/linux/cdk.h linux/include/linux/cdk.h --- v2.1.28/linux/include/linux/cdk.h Thu Apr 11 23:49:46 1996 +++ linux/include/linux/cdk.h Tue Mar 4 13:33:21 1997 @@ -3,6 +3,7 @@ /* * cdk.h -- CDK interface definitions. * + * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.1.28/linux/include/linux/comstats.h linux/include/linux/comstats.h --- v2.1.28/linux/include/linux/comstats.h Sat Apr 20 01:25:31 1996 +++ linux/include/linux/comstats.h Tue Mar 4 13:33:21 1997 @@ -3,6 +3,7 @@ /* * comstats.h -- Serial Port Stats. * + * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.1.28/linux/include/linux/istallion.h linux/include/linux/istallion.h --- v2.1.28/linux/include/linux/istallion.h Wed Apr 24 02:48:04 1996 +++ linux/include/linux/istallion.h Tue Mar 4 13:33:21 1997 @@ -3,6 +3,7 @@ /* * istallion.h -- stallion intelligent multiport serial driver. * + * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.1.28/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.1.28/linux/include/linux/netdevice.h Fri Feb 7 05:54:55 1997 +++ linux/include/linux/netdevice.h Wed Mar 5 17:04:34 1997 @@ -69,10 +69,6 @@ #define IFF_IP_MASK_OK 2 #define IFF_IP_BRD_OK 4 -#ifdef __KERNEL__ - -#include - /* * We tag multicasts with these structures. */ @@ -130,6 +126,9 @@ }; +#ifdef __KERNEL__ + +#include /* * The DEVICE structure. diff -u --recursive --new-file v2.1.28/linux/include/linux/openpromio.h linux/include/linux/openpromio.h --- v2.1.28/linux/include/linux/openpromio.h Fri Dec 13 01:37:47 1996 +++ linux/include/linux/openpromio.h Wed Mar 5 17:04:34 1997 @@ -1,6 +0,0 @@ -#ifndef _LINUX_OPENPROMIO_H -#define _LINUX_OPENPROMIO_H 1 - -#include - -#endif diff -u --recursive --new-file v2.1.28/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.28/linux/include/linux/pci.h Thu Feb 27 10:57:31 1997 +++ linux/include/linux/pci.h Tue Mar 4 13:24:05 1997 @@ -228,6 +228,11 @@ #define PCI_DEVICE_ID_NCR_53C820 0x0002 #define PCI_DEVICE_ID_NCR_53C825 0x0003 #define PCI_DEVICE_ID_NCR_53C815 0x0004 +#define PCI_DEVICE_ID_NCR_53C860 0x0006 +#define PCI_DEVICE_ID_NCR_53C896 0x000b +#define PCI_DEVICE_ID_NCR_53C895 0x000c +#define PCI_DEVICE_ID_NCR_53C885 0x000d +#define PCI_DEVICE_ID_NCR_53C875 0x000f #define PCI_VENDOR_ID_ATI 0x1002 #define PCI_DEVICE_ID_ATI_68800 0x4158 diff -u --recursive --new-file v2.1.28/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.1.28/linux/include/linux/proc_fs.h Tue Mar 4 10:25:26 1997 +++ linux/include/linux/proc_fs.h Fri Mar 7 12:51:45 1997 @@ -224,7 +224,7 @@ struct proc_dir_entry *next, *parent, *subdir; void *data; int (*read_proc)(char *page, char **start, off_t off, - int count, void *data); + int count, int *eof, void *data); int (*write_proc)(struct file *file, const char *buffer, unsigned long count, void *data); }; @@ -233,8 +233,8 @@ off_t offset, int length, int inout); extern struct proc_dir_entry proc_root; -extern struct proc_dir_entry proc_net; -extern struct proc_dir_entry proc_scsi; +extern struct proc_dir_entry *proc_net; +extern struct proc_dir_entry *proc_scsi; extern struct proc_dir_entry proc_sys; extern struct proc_dir_entry proc_openprom; extern struct proc_dir_entry proc_pid; @@ -248,18 +248,16 @@ extern void proc_net_init(void); extern int proc_register(struct proc_dir_entry *, struct proc_dir_entry *); -extern int proc_register_dynamic(struct proc_dir_entry *, - struct proc_dir_entry *); extern int proc_unregister(struct proc_dir_entry *, int); static inline int proc_net_register(struct proc_dir_entry * x) { - return proc_register(&proc_net, x); + return proc_register(proc_net, x); } static inline int proc_net_unregister(int x) { - return proc_unregister(&proc_net, x); + return proc_unregister(proc_net, x); } static inline int proc_scsi_register(struct proc_dir_entry *driver, @@ -267,7 +265,7 @@ { x->ops = &proc_scsi_inode_operations; if(x->low_ino < PROC_SCSI_FILE){ - return(proc_register(&proc_scsi, x)); + return(proc_register(proc_scsi, x)); }else{ return(proc_register(driver, x)); } @@ -278,7 +276,7 @@ extern void scsi_init_free(char *ptr, unsigned int size); if(x <= PROC_SCSI_FILE) - return(proc_unregister(&proc_scsi, x)); + return(proc_unregister(proc_scsi, x)); else { struct proc_dir_entry **p = &driver->subdir, *dp; int ret; @@ -355,6 +353,7 @@ */ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent); +void remove_proc_entry(const char *name, struct proc_dir_entry *parent); /* * proc_tty.c diff -u --recursive --new-file v2.1.28/linux/include/linux/sc26198.h linux/include/linux/sc26198.h --- v2.1.28/linux/include/linux/sc26198.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/sc26198.h Tue Mar 4 13:33:21 1997 @@ -0,0 +1,533 @@ +/*****************************************************************************/ + +/* + * sc26198.h -- SC26198 UART hardware info. + * + * Copyright (C) 1995-1997 Stallion Technologies (support@stallion.oz.au). + * + * 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. + */ + +/*****************************************************************************/ +#ifndef _SC26198_H +#define _SC26198_H +/*****************************************************************************/ + +/* + * Define the number of async ports per sc26198 uart device. + */ +#define SC26198_PORTS 8 + +/* + * Baud rate timing clocks. All derived from a master 14.7456 MHz clock. + */ +#define SC26198_MASTERCLOCK 14745600L +#define SC26198_DCLK (SC26198_MASTERCLOCK) +#define SC26198_CCLK (SC26198_MASTERCLOCK / 2) +#define SC26198_BCLK (SC26198_MASTERCLOCK / 4) + +/* + * Define internal FIFO sizes for the 26198 ports. + */ +#define SC26198_TXFIFOSIZE 16 +#define SC26198_RXFIFOSIZE 16 + +/*****************************************************************************/ + +/* + * Global register definitions. These registers are global to each 26198 + * device, not specific ports on it. + */ +#define TSTR 0x0d +#define GCCR 0x0f +#define ICR 0x1b +#define WDTRCR 0x1d +#define IVR 0x1f +#define BRGTRUA 0x84 +#define GPOSR 0x87 +#define GPOC 0x8b +#define UCIR 0x8c +#define CIR 0x8c +#define BRGTRUB 0x8d +#define GRXFIFO 0x8e +#define GTXFIFO 0x8e +#define GCCR2 0x8f +#define BRGTRLA 0x94 +#define GPOR 0x97 +#define GPOD 0x9b +#define BRGTCR 0x9c +#define GICR 0x9c +#define BRGTRLB 0x9d +#define GIBCR 0x9d +#define GITR 0x9f + +/* + * Per port channel registers. These are the register offsets within + * the port address space, so need to have the port address (0 to 7) + * inserted in bit positions 4:6. + */ +#define MR0 0x00 +#define MR1 0x01 +#define IOPCR 0x02 +#define BCRBRK 0x03 +#define BCRCOS 0x04 +#define BCRX 0x06 +#define BCRA 0x07 +#define XONCR 0x08 +#define XOFFCR 0x09 +#define ARCR 0x0a +#define RXCSR 0x0c +#define TXCSR 0x0e +#define MR2 0x80 +#define SR 0x81 +#define SCCR 0x81 +#define ISR 0x82 +#define IMR 0x82 +#define TXFIFO 0x83 +#define RXFIFO 0x83 +#define IPR 0x84 +#define IOPIOR 0x85 +#define XISR 0x86 + +/* + * For any given port calculate the address to use to access a specified + * register. This is only used for unusual access, mostly this is done + * through the assembler access routines. + */ +#define SC26198_PORTREG(port,reg) ((((port) & 0x07) << 4) | (reg)) + +/*****************************************************************************/ + +/* + * Global configuration control register bit definitions. + */ +#define GCCR_NOACK 0x00 +#define GCCR_IVRACK 0x02 +#define GCCR_IVRCHANACK 0x04 +#define GCCR_IVRTYPCHANACK 0x06 +#define GCCR_ASYNCCYCLE 0x00 +#define GCCR_SYNCCYCLE 0x40 + +/*****************************************************************************/ + +/* + * Mode register 0 bit definitions. + */ +#define MR0_ADDRNONE 0x00 +#define MR0_AUTOWAKE 0x01 +#define MR0_AUTODOZE 0x02 +#define MR0_AUTOWAKEDOZE 0x03 +#define MR0_SWFNONE 0x00 +#define MR0_SWFTX 0x04 +#define MR0_SWFRX 0x08 +#define MR0_SWFRXTX 0x0c +#define MR0_TXMASK 0x30 +#define MR0_TXEMPTY 0x00 +#define MR0_TXHIGH 0x10 +#define MR0_TXHALF 0x20 +#define MR0_TXRDY 0x00 +#define MR0_ADDRNT 0x00 +#define MR0_ADDRT 0x40 +#define MR0_SWFNT 0x00 +#define MR0_SWFT 0x80 + +/* + * Mode register 1 bit definitions. + */ +#define MR1_CS5 0x00 +#define MR1_CS6 0x01 +#define MR1_CS7 0x02 +#define MR1_CS8 0x03 +#define MR1_PAREVEN 0x00 +#define MR1_PARODD 0x04 +#define MR1_PARENB 0x00 +#define MR1_PARFORCE 0x08 +#define MR1_PARNONE 0x10 +#define MR1_PARSPECIAL 0x18 +#define MR1_ERRCHAR 0x00 +#define MR1_ERRBLOCK 0x20 +#define MR1_ISRUNMASKED 0x00 +#define MR1_ISRMASKED 0x40 +#define MR1_AUTORTS 0x80 + +/* + * Mode register 2 bit definitions. + */ +#define MR2_STOP1 0x00 +#define MR2_STOP15 0x01 +#define MR2_STOP2 0x02 +#define MR2_STOP916 0x03 +#define MR2_RXFIFORDY 0x00 +#define MR2_RXFIFOHALF 0x04 +#define MR2_RXFIFOHIGH 0x08 +#define MR2_RXFIFOFULL 0x0c +#define MR2_AUTOCTS 0x10 +#define MR2_TXRTS 0x20 +#define MR2_MODENORM 0x00 +#define MR2_MODEAUTOECHO 0x40 +#define MR2_MODELOOP 0x80 +#define MR2_MODEREMECHO 0xc0 + +/*****************************************************************************/ + +/* + * Baud Rate Generator (BRG) selector values. + */ +#define BRG_50 0x00 +#define BRG_75 0x01 +#define BRG_150 0x02 +#define BRG_200 0x03 +#define BRG_300 0x04 +#define BRG_450 0x05 +#define BRG_600 0x06 +#define BRG_900 0x07 +#define BRG_1200 0x08 +#define BRG_1800 0x09 +#define BRG_2400 0x0a +#define BRG_3600 0x0b +#define BRG_4800 0x0c +#define BRG_7200 0x0d +#define BRG_9600 0x0e +#define BRG_14400 0x0f +#define BRG_19200 0x10 +#define BRG_28200 0x11 +#define BRG_38400 0x12 +#define BRG_57600 0x13 +#define BRG_115200 0x14 +#define BRG_230400 0x15 +#define BRG_GIN0 0x16 +#define BRG_GIN1 0x17 +#define BRG_CT0 0x18 +#define BRG_CT1 0x19 +#define BRG_RX2TX316 0x1b +#define BRG_RX2TX31 0x1c + +#define SC26198_MAXBAUD 921600 + +/*****************************************************************************/ + +/* + * Command register command definitions. + */ +#define CR_NULL 0x04 +#define CR_ADDRNORMAL 0x0c +#define CR_RXRESET 0x14 +#define CR_TXRESET 0x1c +#define CR_CLEARRXERR 0x24 +#define CR_BREAKRESET 0x2c +#define CR_TXSTARTBREAK 0x34 +#define CR_TXSTOPBREAK 0x3c +#define CR_RTSON 0x44 +#define CR_RTSOFF 0x4c +#define CR_ADDRINIT 0x5c +#define CR_RXERRBLOCK 0x6c +#define CR_TXSENDXON 0x84 +#define CR_TXSENDXOFF 0x8c +#define CR_GANGXONSET 0x94 +#define CR_GANGXOFFSET 0x9c +#define CR_GANGXONINIT 0xa4 +#define CR_GANGXOFFINIT 0xac +#define CR_HOSTXON 0xb4 +#define CR_HOSTXOFF 0xbc +#define CR_CANCELXOFF 0xc4 +#define CR_ADDRRESET 0xdc +#define CR_RESETALLPORTS 0xf4 +#define CR_RESETALL 0xfc + +#define CR_RXENABLE 0x01 +#define CR_TXENABLE 0x02 + +/*****************************************************************************/ + +/* + * Channel status register. + */ +#define SR_RXRDY 0x01 +#define SR_RXFULL 0x02 +#define SR_TXRDY 0x04 +#define SR_TXEMPTY 0x08 +#define SR_RXOVERRUN 0x10 +#define SR_RXPARITY 0x20 +#define SR_RXFRAMING 0x40 +#define SR_RXBREAK 0x80 + +#define SR_RXERRS (SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN) + +/*****************************************************************************/ + +/* + * Interrupt status register and interrupt mask register bit definitions. + */ +#define IR_TXRDY 0x01 +#define IR_RXRDY 0x02 +#define IR_RXBREAK 0x04 +#define IR_XONXOFF 0x10 +#define IR_ADDRRECOG 0x20 +#define IR_RXWATCHDOG 0x40 +#define IR_IOPORT 0x80 + +/*****************************************************************************/ + +/* + * Interrupt vector register field definitions. + */ +#define IVR_CHANMASK 0x07 +#define IVR_TYPEMASK 0x18 +#define IVR_CONSTMASK 0xc0 + +#define IVR_RXDATA 0x10 +#define IVR_RXBADDATA 0x18 +#define IVR_TXDATA 0x08 +#define IVR_OTHER 0x00 + +/*****************************************************************************/ + +/* + * BRG timer control register bit definitions. + */ +#define BRGCTCR_DISABCLK0 0x00 +#define BRGCTCR_ENABCLK0 0x08 +#define BRGCTCR_DISABCLK1 0x00 +#define BRGCTCR_ENABCLK1 0x80 + +#define BRGCTCR_0SCLK16 0x00 +#define BRGCTCR_0SCLK32 0x01 +#define BRGCTCR_0SCLK64 0x02 +#define BRGCTCR_0SCLK128 0x03 +#define BRGCTCR_0X1 0x04 +#define BRGCTCR_0X12 0x05 +#define BRGCTCR_0IO1A 0x06 +#define BRGCTCR_0GIN0 0x07 + +#define BRGCTCR_1SCLK16 0x00 +#define BRGCTCR_1SCLK32 0x10 +#define BRGCTCR_1SCLK64 0x20 +#define BRGCTCR_1SCLK128 0x30 +#define BRGCTCR_1X1 0x40 +#define BRGCTCR_1X12 0x50 +#define BRGCTCR_1IO1B 0x60 +#define BRGCTCR_1GIN1 0x70 + +/*****************************************************************************/ + +/* + * Watch dog timer enable register. + */ +#define WDTRCR_ENABALL 0xff + +/*****************************************************************************/ + +/* + * XON/XOFF interrupt status register. + */ +#define XISR_TXCHARMASK 0x03 +#define XISR_TXCHARNORMAL 0x00 +#define XISR_TXWAIT 0x01 +#define XISR_TXXOFFPEND 0x02 +#define XISR_TXXONPEND 0x03 + +#define XISR_TXFLOWMASK 0x0c +#define XISR_TXNORMAL 0x00 +#define XISR_TXSTOPPEND 0x04 +#define XISR_TXSTARTED 0x08 +#define XISR_TXSTOPPED 0x0c + +#define XISR_RXFLOWMASK 0x30 +#define XISR_RXFLOWNONE 0x00 +#define XISR_RXXONSENT 0x10 +#define XISR_RXXOFFSENT 0x20 + +#define XISR_RXXONGOT 0x40 +#define XISR_RXXOFFGOT 0x80 + +/*****************************************************************************/ + +/* + * Current interrupt register. + */ +#define CIR_TYPEMASK 0xc0 +#define CIR_TYPEOTHER 0x00 +#define CIR_TYPETX 0x40 +#define CIR_TYPERXGOOD 0x80 +#define CIR_TYPERXBAD 0xc0 + +#define CIR_RXDATA 0x80 +#define CIR_RXBADDATA 0x40 +#define CIR_TXDATA 0x40 + +#define CIR_CHANMASK 0x07 +#define CIR_CNTMASK 0x38 + +#define CIR_SUBTYPEMASK 0x38 +#define CIR_SUBNONE 0x00 +#define CIR_SUBCOS 0x08 +#define CIR_SUBADDR 0x10 +#define CIR_SUBXONXOFF 0x18 +#define CIR_SUBBREAK 0x28 + +/*****************************************************************************/ + +/* + * Global interrupting channel register. + */ +#define GICR_CHANMASK 0x07 + +/*****************************************************************************/ + +/* + * Global interrupting byte count register. + */ +#define GICR_COUNTMASK 0x0f + +/*****************************************************************************/ + +/* + * Global interrupting type register. + */ +#define GITR_RXMASK 0xc0 +#define GITR_RXNONE 0x00 +#define GITR_RXBADDATA 0x80 +#define GITR_RXGOODDATA 0xc0 +#define GITR_TXDATA 0x20 + +#define GITR_SUBTYPEMASK 0x07 +#define GITR_SUBNONE 0x00 +#define GITR_SUBCOS 0x01 +#define GITR_SUBADDR 0x02 +#define GITR_SUBXONXOFF 0x03 +#define GITR_SUBBREAK 0x05 + +/*****************************************************************************/ + +/* + * Input port change register. + */ +#define IPR_CTS 0x01 +#define IPR_DTR 0x02 +#define IPR_RTS 0x04 +#define IPR_DCD 0x08 +#define IPR_CTSCHANGE 0x10 +#define IPR_DTRCHANGE 0x20 +#define IPR_RTSCHANGE 0x40 +#define IPR_DCDCHANGE 0x80 + +#define IPR_CHANGEMASK 0xf0 + +/*****************************************************************************/ + +/* + * IO port interrupt and output register. + */ +#define IOPR_CTS 0x01 +#define IOPR_DTR 0x02 +#define IOPR_RTS 0x04 +#define IOPR_DCD 0x08 +#define IOPR_CTSCOS 0x10 +#define IOPR_DTRCOS 0x20 +#define IOPR_RTSCOS 0x40 +#define IOPR_DCDCOS 0x80 + +/*****************************************************************************/ + +/* + * IO port configuration register. + */ +#define IOPCR_SETCTS 0x00 +#define IOPCR_SETDTR 0x04 +#define IOPCR_SETRTS 0x10 +#define IOPCR_SETDCD 0x00 + +#define IOPCR_SETSIGS (IOPCR_SETRTS | IOPCR_SETRTS | IOPCR_SETDTR | IOPCR_SETDCD) + +/*****************************************************************************/ + +/* + * General purpose output select register. + */ +#define GPORS_TXC1XA 0x08 +#define GPORS_TXC16XA 0x09 +#define GPORS_RXC16XA 0x0a +#define GPORS_TXC16XB 0x0b +#define GPORS_GPOR3 0x0c +#define GPORS_GPOR2 0x0d +#define GPORS_GPOR1 0x0e +#define GPORS_GPOR0 0x0f + +/*****************************************************************************/ + +/* + * General purpose output register. + */ +#define GPOR_0 0x01 +#define GPOR_1 0x02 +#define GPOR_2 0x04 +#define GPOR_3 0x08 + +/*****************************************************************************/ + +/* + * General purpose output clock register. + */ +#define GPORC_0NONE 0x00 +#define GPORC_0GIN0 0x01 +#define GPORC_0GIN1 0x02 +#define GPORC_0IO3A 0x02 + +#define GPORC_1NONE 0x00 +#define GPORC_1GIN0 0x04 +#define GPORC_1GIN1 0x08 +#define GPORC_1IO3C 0x0c + +#define GPORC_2NONE 0x00 +#define GPORC_2GIN0 0x10 +#define GPORC_2GIN1 0x20 +#define GPORC_2IO3E 0x20 + +#define GPORC_3NONE 0x00 +#define GPORC_3GIN0 0x40 +#define GPORC_3GIN1 0x80 +#define GPORC_3IO3G 0xc0 + +/*****************************************************************************/ + +/* + * General purpose output data register. + */ +#define GPOD_0MASK 0x03 +#define GPOD_0SET1 0x00 +#define GPOD_0SET0 0x01 +#define GPOD_0SETR0 0x02 +#define GPOD_0SETIO3B 0x03 + +#define GPOD_1MASK 0x0c +#define GPOD_1SET1 0x00 +#define GPOD_1SET0 0x04 +#define GPOD_1SETR0 0x08 +#define GPOD_1SETIO3D 0x0c + +#define GPOD_2MASK 0x30 +#define GPOD_2SET1 0x00 +#define GPOD_2SET0 0x10 +#define GPOD_2SETR0 0x20 +#define GPOD_2SETIO3F 0x30 + +#define GPOD_3MASK 0xc0 +#define GPOD_3SET1 0x00 +#define GPOD_3SET0 0x40 +#define GPOD_3SETR0 0x80 +#define GPOD_3SETIO3H 0xc0 + +/*****************************************************************************/ +#endif diff -u --recursive --new-file v2.1.28/linux/include/linux/stallion.h linux/include/linux/stallion.h --- v2.1.28/linux/include/linux/stallion.h Sat Apr 20 01:25:31 1996 +++ linux/include/linux/stallion.h Tue Mar 4 13:33:21 1997 @@ -3,6 +3,7 @@ /* * stallion.h -- stallion multiport serial driver. * + * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). * * This program is free software; you can redistribute it and/or modify @@ -30,6 +31,7 @@ */ #define STL_MAXBRDS 4 #define STL_MAXPANELS 4 +#define STL_MAXBANKS 8 #define STL_PORTSPERPANEL 16 #define STL_MAXPORTS 64 #define STL_MAXDEVS (STL_MAXBRDS * STL_MAXPORTS) @@ -65,7 +67,7 @@ * is associated with, this makes it (fairly) easy to get back to the * board/panel info for a port. */ -typedef struct { +typedef struct stlport { unsigned long magic; int portnr; int panelnr; @@ -87,8 +89,11 @@ unsigned int sigs; unsigned int rxignoremsk; unsigned int rxmarkmsk; + unsigned int imr; + unsigned int crenable; unsigned long clk; unsigned long hwid; + void *uartp; struct tty_struct *tty; struct wait_queue *open_wait; struct wait_queue *close_wait; @@ -99,27 +104,31 @@ stlrq_t tx; } stlport_t; -typedef struct { +typedef struct stlpanel { unsigned long magic; int panelnr; int brdnr; int pagenr; int nrports; int iobase; + void *uartp; + void (*isr)(struct stlpanel *panelp, unsigned int iobase); unsigned int hwid; unsigned int ackmask; stlport_t *ports[STL_PORTSPERPANEL]; } stlpanel_t; -typedef struct { +typedef struct stlbrd { unsigned long magic; int brdnr; int brdtype; int state; int nrpanels; int nrports; + int nrbnks; int irq; int irqtype; + void (*isr)(struct stlbrd *brdp); unsigned int ioaddr1; unsigned int ioaddr2; unsigned int iostatus; @@ -127,6 +136,9 @@ unsigned int ioctrlval; unsigned int hwid; unsigned long clk; + unsigned int bnkpageaddr[STL_MAXBANKS]; + unsigned int bnkstataddr[STL_MAXBANKS]; + stlpanel_t *bnk2panel[STL_MAXBANKS]; stlpanel_t *panels[STL_MAXPANELS]; } stlbrd_t; diff -u --recursive --new-file v2.1.28/linux/include/linux/tty_driver.h linux/include/linux/tty_driver.h --- v2.1.28/linux/include/linux/tty_driver.h Tue Mar 4 10:25:26 1997 +++ linux/include/linux/tty_driver.h Fri Mar 7 12:51:45 1997 @@ -153,7 +153,7 @@ void (*wait_until_sent)(struct tty_struct *tty, int timeout); void (*send_xchar)(struct tty_struct *tty, char ch); int (*read_proc)(char *page, char **start, off_t off, - int count, void *data); + int count, int *eof, void *data); int (*write_proc)(struct file *file, const char *buffer, unsigned long count, void *data); diff -u --recursive --new-file v2.1.28/linux/include/linux/wireless.h linux/include/linux/wireless.h --- v2.1.28/linux/include/linux/wireless.h Thu Feb 6 02:59:18 1997 +++ linux/include/linux/wireless.h Tue Mar 4 13:19:06 1997 @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 3 18.12.96 + * Version : 4 12.2.97 * * Authors : Jean Tourrilhes - HPLB - */ @@ -63,7 +63,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 3 +#define WIRELESS_EXT 4 /* * Changes : @@ -73,6 +73,10 @@ * Alan Cox start some imcompatibles changes. I've integrated a bit more. * - Encryption renamed to Encode to avoid US regulation problems * - Frequency changed from float to struct to avoid problems on old 386 + * + * V3 to V4 + * -------- + * - Add sensitivity */ /* -------------------------- IOCTL LIST -------------------------- */ @@ -86,6 +90,8 @@ #define SIOCGIWFREQ 0x8B05 /* get channel/frequency */ #define SIOCSIWENCODE 0x8B06 /* set encoding info */ #define SIOCGIWENCODE 0x8B07 /* get encoding info */ +#define SIOCSIWSENS 0x8B08 /* set sensitivity */ +#define SIOCGIWSENS 0x8B09 /* get sensitivity */ /* Informative stuff */ #define SIOCSIWRANGE 0x8B0A /* Unused ??? */ @@ -234,6 +240,8 @@ __u64 code; /* Data used for algorithm */ } encoding; + __u32 sensitivity; /* signal level threshold */ + struct /* For all data bigger than 16 octets */ { caddr_t pointer; /* Pointer to the data @@ -271,6 +279,9 @@ /* Note : this frequency list doesn't need to fit channel numbers */ /* Encoder stuff */ + + /* signal level threshold range */ + __u32 sensitivity; /* Quality of link & SNR stuff */ struct iw_quality max_qual; /* Quality of the link */ diff -u --recursive --new-file v2.1.28/linux/init/main.c linux/init/main.c --- v2.1.28/linux/init/main.c Thu Feb 27 10:57:31 1997 +++ linux/init/main.c Fri Mar 7 12:51:45 1997 @@ -887,6 +887,7 @@ } #endif mem_init(memory_start,memory_end); + proc_root_init(); kmem_cache_sizes_init(); vma_init(); buffer_init(); diff -u --recursive --new-file v2.1.28/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.1.28/linux/kernel/sysctl.c Thu Feb 27 10:57:31 1997 +++ linux/kernel/sysctl.c Fri Mar 7 12:51:45 1997 @@ -424,11 +424,12 @@ /* Scan the sysctl entries in table and add them all into /proc */ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root) { - struct proc_dir_entry *de, *tmp; - int exists; + struct proc_dir_entry *de; + int len; + mode_t mode; for (; table->ctl_name; table++) { - exists = 0; + de = 0; /* Can't do anything without a proc name. */ if (!table->procname) continue; @@ -436,46 +437,32 @@ if (!table->proc_handler && !table->child) continue; - - de = kmalloc(sizeof(*de), GFP_KERNEL); - if (!de) continue; - de->namelen = strlen(table->procname); - de->name = table->procname; - de->mode = table->mode; - de->nlink = 1; - de->uid = 0; - de->gid = 0; - de->size = 0; - de->get_info = 0; /* For internal use if we want it */ - de->fill_inode = 0; /* To override struct inode fields */ - de->next = de->subdir = 0; - de->data = (void *) table; - /* Is it a file? */ - if (table->proc_handler) { - de->ops = &proc_sys_inode_operations; - de->mode |= S_IFREG; - } - /* Otherwise it's a subdir */ - else { - /* First check to see if it already exists */ - for (tmp = root->subdir; tmp; tmp = tmp->next) { - if (tmp->namelen == de->namelen && - !memcmp(tmp->name,de->name,de->namelen)) { - exists = 1; - kfree (de); - de = tmp; - } - } - if (!exists) { - de->ops = &proc_dir_inode_operations; - de->nlink++; - de->mode |= S_IFDIR; + + len = strlen(table->procname); + mode = table->mode; + + if (table->proc_handler) + mode |= S_IFREG; + else { + mode |= S_IFDIR; + for (de = root->subdir; de; de = de->next) { + if (proc_match(len, table->procname, de)) + break; } + /* If the subdir exists already, de is non-NULL */ + } + + if (!de) { + de = create_proc_entry(table->procname, mode, root); + if (!de) + continue; + de->data = (void *) table; + if (table->proc_handler) + de->ops = &proc_sys_inode_operations; + } table->de = de; - if (!exists) - proc_register_dynamic(root, de); - if (de->mode & S_IFDIR ) + if (de->mode & S_IFDIR) register_proc_table(table->child, de); } } diff -u --recursive --new-file v2.1.28/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.28/linux/net/ipv4/tcp_ipv4.c Tue Mar 4 10:25:27 1997 +++ linux/net/ipv4/tcp_ipv4.c Wed Mar 5 17:04:34 1997 @@ -230,8 +230,7 @@ } sk->hashtable = NULL; } - if(sk->state == TCP_CLOSE && sk->dead) - tcp_sk_unbindify(sk); + tcp_sk_unbindify(sk); SOCKHASH_UNLOCK(); } @@ -251,8 +250,8 @@ } htable = &((*htable)->next); } + tcp_sk_unbindify(sk); } - tcp_sk_unbindify(sk); htable = NULL; if(state != TCP_CLOSE || !sk->dead) { if(state == TCP_LISTEN) { diff -u --recursive --new-file v2.1.28/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.28/linux/net/ipv6/addrconf.c Thu Feb 27 10:57:32 1997 +++ linux/net/ipv6/addrconf.c Fri Mar 7 12:51:45 1997 @@ -1350,7 +1350,7 @@ if (dev && (dev->flags & IFF_UP)) addrconf_eth_config(dev); - proc_register_dynamic(&proc_net, &iface_proc_entry); + proc_register(&proc_net, &iface_proc_entry); addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY; add_timer(&addr_chk_timer); diff -u --recursive --new-file v2.1.28/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c --- v2.1.28/linux/net/ipv6/ndisc.c Thu Feb 27 10:57:32 1997 +++ linux/net/ipv6/ndisc.c Fri Mar 7 12:51:45 1997 @@ -1843,11 +1843,7 @@ add_timer(&ndisc_gc_timer); #ifdef CONFIG_PROC_FS -#ifdef CONFIG_IPV6_MODULE - proc_register_dynamic(&proc_net, &ndisc_proc_entry); -#else proc_net_register(&ndisc_proc_entry); -#endif #endif #ifdef CONFIG_IPV6_MODULE ndisc_eth_hook = ndisc_eth_resolv; diff -u --recursive --new-file v2.1.28/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.1.28/linux/net/ipv6/udp.c Tue Mar 4 10:25:27 1997 +++ linux/net/ipv6/udp.c Wed Mar 5 17:04:34 1997 @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.8 1997/02/28 09:56:35 davem Exp $ + * $Id: udp.c,v 1.9 1997/03/04 10:41:59 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -324,9 +324,10 @@ if(skb==NULL) return err; - truesize = skb->tail - skb->h.raw - sizeof(struct udphdr); + truesize=ntohs(((struct udphdr *)skb->h.raw)->len) - sizeof(struct udphdr); copied=truesize; + if(copied>len) { copied=len; @@ -357,7 +358,7 @@ if (skb->protocol == __constant_htons(ETH_P_IP)) { ipv6_addr_set(&sin6->sin6_addr, 0, 0, - __constant_htonl(0xffff), skb->nh.iph->daddr); + __constant_htonl(0xffff), skb->nh.iph->saddr); } else { diff -u --recursive --new-file v2.1.28/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.1.28/linux/net/unix/af_unix.c Thu Feb 27 10:57:32 1997 +++ linux/net/unix/af_unix.c Fri Mar 7 12:51:44 1997 @@ -1366,7 +1366,8 @@ } #ifdef CONFIG_PROC_FS -static int unix_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +static int unix_read_proc(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) { off_t pos=0; off_t begin=0; @@ -1410,6 +1411,7 @@ if(pos>offset+length) goto done; } + *eof = 1; done: *start=buffer+(offset-begin); len-=(offset-begin); @@ -1466,19 +1468,11 @@ unix_create }; -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_net_unix = { - PROC_NET_UNIX, 4, "unix", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - unix_get_info -}; -#endif - - void unix_proto_init(struct net_proto *pro) { struct sk_buff *dummy_skb; + struct proc_dir_entry *ent; + printk(KERN_INFO "NET3: Unix domain sockets 0.15 for Linux NET3.038.\n"); if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb)) { @@ -1487,7 +1481,8 @@ } sock_register(&unix_family_ops); #ifdef CONFIG_PROC_FS - proc_net_register(&proc_net_unix); + ent = create_proc_entry("net/unix", 0, 0); + ent->read_proc = unix_read_proc; #endif } /* diff -u --recursive --new-file v2.1.28/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c --- v2.1.28/linux/net/wanrouter/wanproc.c Sun Feb 2 06:44:21 1997 +++ linux/net/wanrouter/wanproc.c Fri Mar 7 12:51:45 1997 @@ -273,13 +273,13 @@ int wanrouter_proc_init (void) { - int err = proc_register_dynamic(&proc_net, &proc_router); + int err = proc_register(&proc_net, &proc_router); if (!err) { - proc_register_dynamic(&proc_router, &proc_router_info); - proc_register_dynamic(&proc_router, &proc_router_conf); - proc_register_dynamic(&proc_router, &proc_router_stat); + proc_register(&proc_router, &proc_router_info); + proc_register(&proc_router, &proc_router_conf); + proc_register(&proc_router, &proc_router_stat); } return err; } @@ -313,7 +313,7 @@ wandev->dent.ops = &wandev_inode; wandev->dent.get_info = &wandev_get_info; wandev->dent.data = wandev; - return proc_register_dynamic(&proc_router, &wandev->dent); + return proc_register(&proc_router, &wandev->dent); } /* diff -u --recursive --new-file v2.1.28/linux/scripts/Configure linux/scripts/Configure --- v2.1.28/linux/scripts/Configure Thu Feb 27 10:57:32 1997 +++ linux/scripts/Configure Mon Mar 10 12:38:56 1997 @@ -43,6 +43,9 @@ # # 200396 Tom Dyas (tdyas@eden.rutgers.edu) - when the module option is # chosen for an item, define the macro _MODULE +# +# 090397 Axel Boldt (boldt@math.ucsb.edu) - avoid ? and + in regular +# expressions for GNU expr since version 1.15 and up use \? and \+. # # Make sure we're really running bash. @@ -57,16 +60,6 @@ # Enable function cacheing. set -f -h -# Newer shellutils have a more POSIX compliant behavior which is -# sadly not backward compatible. -if expr "$(expr --version)" : '.*1\.1[56]' > /dev/null; then - INT_FILTER='0$\|-\?[1-9][0-9]*$' - HEX_FILTER='[0-9a-fA-F]\+$' -else - INT_FILTER='0$\|-?[1-9][0-9]*$' - HEX_FILTER='[0-9a-fA-F]+$' -fi - # # Dummy functions for use with a config.in modified for menuconf # @@ -299,7 +292,7 @@ def=${old:-$3} while :; do readln "$1 ($2) [$def] " "$def" "$old" - if expr "$ans" : $INT_FILTER > /dev/null; then + if expr "$ans" : '0$\|\(-[1-9]\|[1-9]\)[0-9]*$' > /dev/null; then define_int "$2" "$ans" break else @@ -330,12 +323,12 @@ while :; do readln "$1 ($2) [$def] " "$def" "$old" ans=${ans#*[x,X]} - if expr "$ans" : $HEX_FILTER > /dev/null; then - define_hex "$2" "$ans" - break - else + if expr "$ans" : '[0-9a-fA-F][0-9a-fA-F]*$' > /dev/null; then + define_hex "$2" "$ans" + break + else help "$2" - fi + fi done } diff -u --recursive --new-file v2.1.28/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v2.1.28/linux/scripts/Menuconfig Fri Feb 7 05:54:55 1997 +++ linux/scripts/Menuconfig Mon Mar 10 12:38:56 1997 @@ -400,7 +400,9 @@ answer="`cat MCdialog.out`" answer="${answer:-$3}" - if expr $answer : '0$\|-\?[1-9][0-9]*$' >/dev/null + # Semantics of + and ? in GNU expr changed, so + # we avoid them: + if expr "$answer" : '0$\|\(-[1-9]\|[1-9]\)[0-9]*$' >/dev/null then eval $2="$answer" else @@ -433,7 +435,7 @@ answer="${answer:-$3}" answer="${answer##*[x,X]}" - if expr $answer : '[0-9a-fA-F]\+$' >/dev/null + if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]*$' >/dev/null then eval $2="$answer" else @@ -452,7 +454,7 @@ } # -# Handle a on-of-many choice list. +# Handle a one-of-many choice list. # function l_choice () { # @@ -493,7 +495,7 @@ done # - # Now set the boolean value of each option base on + # Now set the boolean value of each option based on # the selection made from the radiolist. # set -- $choices