diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/CREDITS linux.pre11.6/CREDITS --- linux.pre11.5/CREDITS Fri Aug 6 18:50:20 1999 +++ linux.pre11.6/CREDITS Sat Aug 7 21:24:07 1999 @@ -2211,6 +2211,7 @@ E: R.E.Wolff@BitWizard.nl D: Written kmalloc/kfree D: Written Specialix IO8+ driver +D: Written Specialix SX driver S: van Bronckhorststraat 12 S: 2612 XV Delft S: The Netherlands diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/Documentation/Changes linux.pre11.6/Documentation/Changes --- linux.pre11.5/Documentation/Changes Fri Aug 6 18:50:20 1999 +++ linux.pre11.6/Documentation/Changes Sat Aug 7 02:57:05 1999 @@ -701,8 +701,8 @@ SMBfs ===== -The 2.0.4b release of Samba: -ftp://ftp.samba.org/pub/samba/samba-2.0.4b.tar.gz +The 2.0.5a release of Samba: +ftp://ftp.samba.org/pub/samba/samba-2.0.5a.tar.gz Pcmcia-cs ========= diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/Documentation/networking/README.sb1000 linux.pre11.6/Documentation/networking/README.sb1000 --- linux.pre11.5/Documentation/networking/README.sb1000 Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/Documentation/networking/README.sb1000 Fri Dec 11 02:16:44 1998 @@ -0,0 +1,133 @@ +This is the new release of a module network device driver for General +Instruments (also known as NextLevel) SB1000 cable modem board (also +called internal SURFboard). +I have tested and I am running this module on kernel 2.0.33. +Steven N. Hirsch gave me a diff patch +(sb1000-1.1.2_127.patch to be applied with 'patch -p') that allows +you to compile and run the driver with kernel versions 2.1.x. +Thanks very much Steve! + +Here you'll the following files: + +- README +- Makefile +- sb1000.c the actual device driver +- cmconfig.c an ifconfig-like program to correctly set the SB1000 +- cmping.c a ping-like program to test your connection +- ftptest.c a small program to test your connection speed with FTP + (requires ftplib version >= 3.0) + +The directory ppp/ contains the files I am using to connect to MediaOne +here in Jacksonville, to show how you can use the driver and the cmconfig +program. + +Clemmitt Sigler wrote a very good and useful web page and installation +script (for Adelphia PowerLink users but easy to port to other ISPs) +about this SB1000 driver for Linux. +You can find it here: + http://home.adelphia.net/~siglercm/sb1000.html +Thanks very much Clemmitt! + +To install and run it: +- cd sb1000-1.1.2 +- make +- make install +- configure the SB1000 card using the isapnp tools setting the correct + I/O's and IRQ. You can find more info about the isapnp tools at: + http://www.roestock.demon.co.uk/isapnptools/ + (once you're happy with it, you may want to set the configuration + at boot time in one of the /etc/init.d/ scripts) + IMPORTANT NOTICE: after configuring isapnp, please look in the file + /etc/isapnp.conf for the line beginning with: + (READPORT + if it says: '(READPORT 0x0203)' (which should be the default), then + go to the next step. If instead it says something like: + '(READPORT 0x020b)' or '(READPORT 0x)', then please + follow the instructions at the end of this README file before going + to the next step. +- install the PPP configuration files in the /etc/ppp directory; you + definitely have to change the file ppp@gi-on (the start up file), + setting the correct login name, the phone number for the PPP connection + and the frequency (k stands for kHz, M for MHz) for the cablemodem. + You'll also have to change the last line in the pap-secrets file + writing your login and password there (read the whole file for more + site specific configurations). + You may have to change the firewall file to suit your needs (IPs and + ports allowed to connect). +- start the PPP connection with ppp@gi-on and see what happens; you may + want to set 'pppd' (the last command in the ppp@gi-on file) to debug + mode adding 'debug' at the end of the command ('pppd' prints its info in + the file /var/log/messages and/or /var/log/ppp.log). To make sure 'chat' + s not having problems you may want to add a '-v' (verbose) after the 'chat' + command in 'ppp-on-dialer' and check the results in /var/log/messages) +- if everything is working fine you should see after a few seconds a message + likes this: + cm0: sb1000 at (0x120,0x310), csn 1, S/N 0x2a0d16d8, IRQ 9. + sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net) + and ifconfig -a should show you two new interfaces: ppp0 and cm0. + Typing 'cmconfig cm0' will show you more info about the cablemodem interface. +- please let me know if you see any other message coming from 'cm0' in + your '/var/log/messages' or '/var/log/debug' file, to help me debug the + code +- also let me know if you have any problem; if everything works (hopefully), + let me know which speed you can reach downloading the 5Mb test file using + this driver. +- if everything seems to work fine but your computer locks up after a while + (and typically during a lengthy download through the cablemodem), you may + need to add a short delay in the driver to 'slow down' the SURFboard + because your PC might not be able to keep up with the transfer rate of + the SB1000. To do this, edit the 'Makefile' and look for the 'SB1000_DELAY' + define: uncomment those 'CFLAGS' lines (and comment the default ones) + and try setting the delay to something like 60 microseconds with: + '-DSB1000_DELAY=60'; if it still doesn't work or you like playing with + the driver, you may try other numbers: remember though that the higher + the delay, the slower the driver (which slows down the rest of the PC + too when it is actively used). Thanks to Ed Daiga for this tip! + +This release has a few things fixed and a better handling of the frame errors. + +I also have slightly modified the 'cablemodem' script in the 'ppp' so +you may interested in having a look at it: I basically have added filtering +out broadcast messages (you shouldn't get them with a point-to-point +interface and so far the ones I have received were from hosts trying to +attack my system) and lower debug levels for the driver to avoid seeing +the 'frame error' messages (so far noone has noticed any problem with the +driver even with those messages). + +For questions, infos, etc, feel free to email me at: + fventuri@mediaone.net + +Good luck, +Franco Venturi + +Thanks to Edge for his useful comments and to Steven N. Hirsch +for his patch to run the driver with 2.1.x kernels. +Thanks also to Ed Daiga for his help in finding that adding a delay +in the driver fixes some lock up problems with some slow PCs. +Many thanks to Clemmitt Sigler for his (much needed) web page about the +SB1000 driver for Linux. +An interesting URL for Linux + MediaOne (although with an external modem) +is: http://rlz.ne.mediaone.net/linux/home.shtml +Today, Sep 22 1998, I finished writing a short utility (ftptest.c) to +'measure' your cablemodem speed connection in Linux, downloading to +memory the same file several times. To compile it you need ftplib, version +3 or above. To run it, type: + ftptest URL n +where URL is in the form: ftp://ftp.site.local.isp/pub/testfile +and n is the number of simultaneous FTP connections that you want to run + +--------------------------------------------------------------------------- +IMPORTANT NOTICE: if in your file /etc/isapnp.conf, you found something +like '(READPORT 0x020b)' or '(READPORT 0x)', (anything +different from the default 0x0203), you have to change the READ_DATA_PORT +parameter in the sb1000.c file as follows. + - edit the sb1000.c file, look for: + READ_DATA_PORT + (it should be around line 127 in version 1.1.2) + - change the value of READ_DATA_PORT to the same value found in + /etc/isapnp.conf; for instance, if you found a: '(READPORT 0x020b)', + then in sb1000.c you should have: + static const int READ_DATA_PORT = 0x20b; + - save sb1000.c + - compile and install again the driver + (i.e. do a 'make' and a 'make install'). diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/Documentation/sx.txt linux.pre11.6/Documentation/sx.txt --- linux.pre11.5/Documentation/sx.txt Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/Documentation/sx.txt Sat Aug 7 21:24:07 1999 @@ -0,0 +1,289 @@ + + sx.txt -- specialix SX/SI multiport serial driver readme. + + + + Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl) + + Specialix pays for the development and support of this driver. + Please DO contact support@specialix.co.uk if you require + support. + + This driver was developed in the BitWizard linux device + driver service. If you require a linux device driver for your + product, please contact devices@BitWizard.nl for a quote. + + (History) + There used to be an SI driver by Simon Allan. This is a complete + rewrite from scratch. Just a few lines-of-code have been snatched. + + (Sources) + Specialix document number 6210028: SX Host Card and Download Code + Software Functional Specification. + + (Copying) + 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. + + (Addendum) + I'd appreciate it that if you have fixes, that you send them + to me first. + + +Introduction +============ + +This file contains some random information, that I like to have online +instead of in a manual that can get lost. Ever misplace your Linux +kernel sources? And the manual of one of the boards in your computer? + + +Theory of operation +=================== + +An important thing to know is that the driver itself doesn't have the +firmware for the card. This means that you need the separate package +"sx_firmware". For now you can get the source at + + ftp://ftp.bitwizard.nl/specialix/sx_firmware_.tgz + +The firmware load needs a "misc" device, so you'll need to enable the +"Support for user misc device modules" in your kernel configuration. +The misc device needs to be called "/dev/specialix_sxctl". It needs +misc major 10, and minor number 167 (assigned by HPA). The section +on creating device files below also creates this device. + +After loading the sx.o module into your kernel, the driver will report +the number of cards detected, but because it doesn't have any +firmware, it will not be able to determine the number of ports. Only +when you then run "sx_firmware" will the firmware be downloaded and +the rest of the driver initialized. At that time the sx_firmware +program will report the number of ports installed. + +In contrast with many other multi port serial cards, some of the data +structures are only allocated when the card knows the number of ports +that are connected. This means we won't waste memory for 120 port +descriptor structures when you only have 8 ports. If you experience +problems due to this, please report them: I haven't seen any. + + +Interrupts +========== + +A multi port serial card, would generate a horrendous amount of +interrupts if it would interrupt the CPU for every received +character. Even more than 10 years ago, the trick not to use +interrupts but to poll the serial cards was invented. + +The SX card allow us to do this two ways. First the card limits its +own interrupt rate to a rate that won't overwhelm the CPU. Secondly, +we could forget about the cards interrupt completely and use the +internal timer for this purpose. + +Polling the card can take up to a few percent of your CPU. Using the +interrupts would be better if you have most of the ports idle. Using +timer-based polling is better if your card almost always has work to +do. You save the separate interrupt in that case. + +In any case, it doesn't really matter all that much. + +The most common problem with interrupts is that for ISA cards in a PCI +system the BIOS has to be told to configure that interrupt as "legacy +ISA". Otherwise the card can pull on the interrupt line all it wants +but the CPU won't see this. + +If you can't get the interrupt to work, remember that polling mode is +more efficient (provided you actually use the card intensively). + + +Allowed Configurations +====================== + +Some configurations are disallowed. Even though at a glance they might +seem to work, they are known to lockup the bus between the host card +and the device concentrators. You should respect the drivers decision +not to support certain configurations. It's there for a reason. + +Warning: Seriously technical stuff ahead. Executive summary: Don't use +SX cards except configured at a 64k boundary. Skip the next paragraph. + +The SX cards can theoretically be placed at a 32k boundary. So for +instance you can put an SX card at 0xc8000-0xd7fff. This is not a +"recommended configuration". ISA cards have to tell the bus controller +how they like their timing. Due to timing issues they have to do this +based on which 64k window the address falls into. This means that the +32k window below and above the SX card have to use exactly the same +timing as the SX card. That reportedly works for other SX cards. But +you're still left with two useless 32k windows that should not be used +by anybody else. + + +Configuring the driver +====================== + +PCI cards are always detected. The driver auto-probes for ISA cards at +some sensible addresses. Please report if the auto-probe causes trouble +in your system, or when a card isn't detected. + +I'm afraid I haven't implemented "kernel command line parameters" yet. +This means that if the default doesn't work for you, you shouldn't use +the compiled-into-the-kernel version of the driver. Use a module +instead. If you convince me that you need this, I'll make it for +you. Deal? + +I'm afraid that the module parameters are a bit clumsy. If you have a +better idea, please tell me. + +You can specify several parameters: + + sx_poll: number of jiffies between timer-based polls. + + Set this to "0" to disable timer based polls. + Initialization of cards without a working interrupt + will fail. + + Set this to "1" if you want a polling driver. + (on Intel: 100 polls per second). If you don't use + fast baud rates, you might consider a value like "5". + (If you don't know how to do the math, use 1). + + sx_slowpoll: Number of jiffies between timer-based polls. + Set this to "100" to poll once a second. + This should get the card out of a stall if the driver + ever misses an interrupt. I've never seen this happen, + and if it does, that's a bug. Tell me. + + sx_maxints: Number of interrupts to request from the card. + The card normally limits interrupts to about 100 per + second to offload the host CPU. You can increase this + number to reduce latency on the card a little. + Note that if you give a very high number you can overload + your CPU as well as the CPU on the host card. This setting + is inaccurate and not recommended for SI cards (But it + works). + + sx_irqmask: The mask of allowable IRQs to use. I suggest you set + this to 0 (disable IRQs all together) and use polling if + the assignment of IRQs becomes problematic. + + sx_debug: You can enable different sorts of debug traces with this. + At "-1" all debugging traces are active. You'll get several + times more debugging output than you'll get characters + transmitted. + + +Baud rates +========== + +Theoretically new SXDCs should be capable of more than 460k +baud. However the line drivers usually give up before that. Also the +CPU on the card may not be able to handle 8 channels going at full +blast at that speed. Moreover, the buffers are not large enough to +allow operation with 100 interrupts per second. You'll have to realize +that the card has a 256 byte buffer, so you'll have to increase the +number of interrupts per second if you have more than 256*100 bytes +per second to transmit. If you do any performance testing in this +area, I'd be glad to hear from you... + +(Psst Linux users..... I think the Linux driver is more efficient than +the driver for other OSes. If you can and want to benchmark them +against each other, be my guest, and report your findings...... :-) + + +Ports and devices +================= + +Port 0 is the top connector on the module closest to the host +card. Oh, the ports on the SXDCs and TAs are labelled from 1 to 8 +instead of from 0 to 7, as they are numbered by linux. I'm stubborn in +this: I know for sure that I wouldn't be able to calculate which port +is which anymore if I would change that.... + + +Devices: + +You should make the device files as follows: + +#!/bin/sh +# (I recommend that you cut-and-paste this into a file and run that) +cd /dev +t=0 +mknod specialix_sxctl c 10 167 +while [ $t -lt 64 ] + do + echo -n "$t " + mknod ttyX$t c 32 $t + mknod cux$t c 33 $t + t=`expr $t + 1` +done +echo "" +rm /etc/psdevtab +ps > /dev/null + + +This creates 64 devices. If you have more, increase the constant on +the line with "while". The devices start at 0, as is customary on +Linux. Specialix seems to like starting the numbering at 1. + +If your system doesn't come with these devices pre-installed, bug your +linux-vendor about this. They should have these devices +"pre-installed" before the new millennium. The "ps" stuff at the end +is to "tell" ps that the new devices exist. + +Officially the maximum number of cards per computer is 4. This driver +however supports as many cards in one machine as you want. You'll run +out of interrupts after a few, but you can switch to polled operation +then. At about 256 ports (More than 8 cards), we run out of minor +device numbers. Sorry. I suggest you buy a second computer.... (Or +switch to RIO). + +------------------------------------------------------------------------ + + + Fixed bugs and restrictions: + - Hangup processing. + -- Done. + + - the write path in generic_serial (lockup / oops). + -- Done (Ugly: not the way I want it. Copied from serial.c). + + - write buffer isn't flushed at close. + -- Done. I still seem to loose a few chars at close. + Sorry. I think that this is a firmware issue. (-> Specialix) + + - drain hardware before changing termios + - Change debug on the fly. + - ISA free irq -1. (no firmware loaded). + - adding c8000 as a probe address. Added warning. + - Add a RAMtest for the RAM on the card.c + - Crash when opening a port "way" of the number of allowed ports. + (for example opening port 60 when there are only 24 ports attached) + - Sometimes the use-count strays a bit. After a few hours of + testing the use count is sometimes "3". If you are not like + me and can remember what you did to get it that way, I'd + appreciate an Email. Possibly fixed. Tell me if anyone still + sees this. + - TAs don't work right if you don't connect all the modem control + signals. SXDCs do. T225 firmware problem -> Specialix. + (Mostly fixed now, I think. Tell me if you encounter this!) + + Bugs & restrictions: + + - Arbitrary baud rates. Requires firmware update. (-> Specialix) + + - Low latency (mostly firmware, -> Specialix) + + + diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/defconfig linux.pre11.6/arch/sparc/defconfig --- linux.pre11.5/arch/sparc/defconfig Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/defconfig Sat Aug 7 21:25:16 1999 @@ -243,6 +243,8 @@ CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y +CONFIG_EFS_FS=m +CONFIG_SGI_PARTITION=y # # Network File Systems diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/kernel/pcic.c linux.pre11.6/arch/sparc/kernel/pcic.c --- linux.pre11.5/arch/sparc/kernel/pcic.c Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/kernel/pcic.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.5 1999/03/16 00:15:20 davem Exp $ +/* $Id: pcic.c,v 1.5.2.1 1999/08/07 10:42:43 davem Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/kernel/process.c linux.pre11.6/arch/sparc/kernel/process.c --- linux.pre11.5/arch/sparc/kernel/process.c Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/kernel/process.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $ +/* $Id: process.c,v 1.137.2.1 1999/08/07 10:42:45 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/kernel/sparc-stub.c linux.pre11.6/arch/sparc/kernel/sparc-stub.c --- linux.pre11.5/arch/sparc/kernel/sparc-stub.c Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/kernel/sparc-stub.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: sparc-stub.c,v 1.24 1998/02/08 07:58:44 ecd Exp $ +/* $Id: sparc-stub.c,v 1.24.2.1 1999/08/07 10:42:46 davem Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/kernel/sparc_ksyms.c linux.pre11.6/arch/sparc/kernel/sparc_ksyms.c --- linux.pre11.5/arch/sparc/kernel/sparc_ksyms.c Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/kernel/sparc_ksyms.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.77 1999/03/21 06:37:43 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.77.2.1 1999/08/07 10:42:47 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/kernel/sys_sunos.c linux.pre11.6/arch/sparc/kernel/sys_sunos.c --- linux.pre11.5/arch/sparc/kernel/sys_sunos.c Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/kernel/sys_sunos.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.94.2.1 1999/05/24 19:42:30 davem Exp $ +/* $Id: sys_sunos.c,v 1.94.2.2 1999/08/07 10:42:49 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/lib/debuglocks.c linux.pre11.6/arch/sparc/lib/debuglocks.c --- linux.pre11.5/arch/sparc/lib/debuglocks.c Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/lib/debuglocks.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: debuglocks.c,v 1.7 1999/04/21 02:26:58 anton Exp $ +/* $Id: debuglocks.c,v 1.7.2.1 1999/08/05 09:39:27 anton Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -53,7 +53,7 @@ lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); for(i = 0; i < NR_CPUS; i++) - printk(" reader[i]=%08lx", lock->reader_pc[i]); + printk(" reader[%d]=%08lx", i, lock->reader_pc[i]); printk("\n"); } diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/mm/fault.c linux.pre11.6/arch/sparc/mm/fault.c --- linux.pre11.5/arch/sparc/mm/fault.c Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/mm/fault.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.101 1999/01/04 06:24:52 jj Exp $ +/* $Id: fault.c,v 1.101.2.2 1999/08/07 10:42:53 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -382,12 +382,13 @@ if(expand_stack(vma, address)) goto bad_area; good_area: - if(write) + if(write) { if(!(vma->vm_flags & VM_WRITE)) goto bad_area; - else + } else { if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; + } if (!handle_mm_fault(current, vma, address, write)) goto do_sigbus; up(&mm->mmap_sem); diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/mm/init.c linux.pre11.6/arch/sparc/mm/init.c --- linux.pre11.5/arch/sparc/mm/init.c Fri Aug 6 18:50:23 1999 +++ linux.pre11.6/arch/sparc/mm/init.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.65 1999/04/09 16:28:03 davem Exp $ +/* $Id: init.c,v 1.65.2.1 1999/08/07 10:42:54 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc/mm/srmmu.c linux.pre11.6/arch/sparc/mm/srmmu.c --- linux.pre11.5/arch/sparc/mm/srmmu.c Fri Aug 6 20:39:07 1999 +++ linux.pre11.6/arch/sparc/mm/srmmu.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.187 1999/04/28 17:00:45 davem Exp $ +/* $Id: srmmu.c,v 1.187.2.1 1999/08/07 10:42:55 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc64/defconfig linux.pre11.6/arch/sparc64/defconfig --- linux.pre11.5/arch/sparc64/defconfig Fri Aug 6 18:50:32 1999 +++ linux.pre11.6/arch/sparc64/defconfig Sat Aug 7 21:25:16 1999 @@ -287,6 +287,8 @@ CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y +CONFIG_EFS_FS=m +CONFIG_SGI_PARTITION=y # # Network File Systems diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc64/kernel/sys_sunos32.c linux.pre11.6/arch/sparc64/kernel/sys_sunos32.c --- linux.pre11.5/arch/sparc64/kernel/sys_sunos32.c Fri Aug 6 18:50:32 1999 +++ linux.pre11.6/arch/sparc64/kernel/sys_sunos32.c Sat Aug 7 21:25:16 1999 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.22.2.1 1999/05/24 19:42:36 davem Exp $ +/* $Id: sys_sunos32.c,v 1.22.2.2 1999/08/07 10:43:02 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc64/math-emu/op-common.h linux.pre11.6/arch/sparc64/math-emu/op-common.h --- linux.pre11.5/arch/sparc64/math-emu/op-common.h Fri Aug 6 18:50:33 1999 +++ linux.pre11.6/arch/sparc64/math-emu/op-common.h Sat Aug 7 21:25:17 1999 @@ -248,7 +248,7 @@ _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ R##_s = X##_s ^ Y##_s; \ R##_c = FP_CLS_NAN; \ - R##_r |= EFLAG_INVALID; + R##_r |= EFLAG_INVALID; \ break; \ } \ /* FALLTHRU */ \ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc64/mm/generic.c linux.pre11.6/arch/sparc64/mm/generic.c --- linux.pre11.5/arch/sparc64/mm/generic.c Fri Aug 6 18:50:32 1999 +++ linux.pre11.6/arch/sparc64/mm/generic.c Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.8 1999/03/12 06:51:50 davem Exp $ +/* $Id: generic.c,v 1.8.2.1 1999/07/23 22:31:03 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -95,7 +95,8 @@ space); curend = address + 0x10000; offset += 0x10000; - } + } else + offset += PAGE_SIZE; } else offset += PAGE_SIZE; diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/arch/sparc64/solaris/socksys.c linux.pre11.6/arch/sparc64/solaris/socksys.c --- linux.pre11.5/arch/sparc64/solaris/socksys.c Fri Aug 6 18:50:33 1999 +++ linux.pre11.6/arch/sparc64/solaris/socksys.c Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.8 1998/08/26 10:28:28 davem Exp $ +/* $Id: socksys.c,v 1.8.2.1 1999/08/07 10:43:11 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/Config.in linux.pre11.6/drivers/char/Config.in --- linux.pre11.5/drivers/char/Config.in Fri Aug 6 18:50:46 1999 +++ linux.pre11.6/drivers/char/Config.in Sat Aug 7 21:24:07 1999 @@ -41,6 +41,7 @@ if [ "$CONFIG_SPECIALIX" != "n" ]; then bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS fi + tristate 'Specialix SX (and SI) card support' CONFIG_SX tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/Makefile linux.pre11.6/drivers/char/Makefile --- linux.pre11.5/drivers/char/Makefile Fri Aug 6 18:50:45 1999 +++ linux.pre11.6/drivers/char/Makefile Sat Aug 7 21:24:07 1999 @@ -172,6 +172,14 @@ endif endif +ifeq ($(CONFIG_SX),y) +L_OBJS += sx.o generic_serial.o +else + ifeq ($(CONFIG_SX),m) + M_OBJS += sx.o + endif +endif + ifeq ($(CONFIG_ATIXL_BUSMOUSE),y) L_OBJS += atixlmouse.o else diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/generic_serial.c linux.pre11.6/drivers/char/generic_serial.c --- linux.pre11.5/drivers/char/generic_serial.c Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/drivers/char/generic_serial.c Sat Aug 7 21:24:07 1999 @@ -0,0 +1,1074 @@ +/* + * generic_serial.c + * + * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl + * + * written for the SX serial driver. + * Contains the code that should be shared over all the serial drivers. + * + * Credit for the idea to do it this way might go to Alan Cox. + * + * + * Version 0.1 -- December, 1998. Initial version. + * Version 0.2 -- March, 1999. Some more routines. Bugfixes. Etc. + * Version 0.5 -- August, 1999. Some more fixes. Reformat for Linus. + */ + +#include +#include +#include +#include +#include + + +#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */ +#define TWO_ZERO +#else +#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */ +#warning "Please use a 2.2.x kernel. " +#else +#if LINUX_VERSION_CODE < 0x020300 /* less than 2.2.x */ +#define TWO_TWO +#else +#define TWO_THREE +#endif +#endif +#endif + +#ifdef TWO_ZERO + +/* Here is the section that makes the 2.2 compatible driver source + work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, + and provide for compatibility stuff here if possible. */ + +/* Some 200 days (on intel) */ +#define MAX_SCHEDULE_TIMEOUT ((long)(~0UL>>1)) + + +#ifndef MODULE + +#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) + +static inline int copy_from_user(void *to,const void *from, int c) +{ + memcpy_fromfs(to, from, c); + return 0; +} + + +#define capable(x) suser() + +#define queue_task queue_task_irq_off +#define tty_flip_buffer_push(tty) queue_task(&tty->flip.tqueue, &tq_timer) +#define signal_pending(current) (current->signal & ~current->blocked) +#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) +#define time_after(t1,t2) (((long)t1-t2) > 0) + +#define test_and_set_bit(nr, addr) set_bit(nr, addr) +#define test_and_clear_bit(nr, addr) clear_bit(nr, addr) + +/* Not yet implemented on 2.0 */ +#define ASYNC_SPD_SHI -1 +#define ASYNC_SPD_WARP -1 + + + +/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it + to the "name" field that does exist. As long as the assignments are + done in the right order, there is nothing to worry about. */ +#define driver_name name + + +/* Should be in a header somewhere. */ +#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */ +#define TTY_HW_COOK_IN 15 /* in hardware - output and input */ +#endif + +#endif + +#ifndef TWO_ZERO +/* This include is new with 2.2 (and required!) */ +#include +#endif + +#ifndef TWO_THREE +/* These are new in 2.3. The source now uses 2.3 syntax, and here is + the compatibility define... */ +#define waitq_head_t struct wait_queue * +#define DECLARE_MUTEX(name) struct semaphore name = MUTEX +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } + +#endif + +#include "generic_serial.h" + + +#ifndef MODULE +extern void my_hd (unsigned char *ptr, int n); +#endif + +static char * tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); + +int gs_debug = 0; + + +#ifdef DEBUG +#define gs_dprintk(f, str...) if (gs_debug & f) printk (str) +#else +#define gs_dprintk(f, str...) /* nothing */ +#endif + +#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n") +#define func_exit() gs_dprintk (SX_DEBUG_FLOW, "gs: exit " __FUNCTION__ "\n") + + + +#if NEW_WRITE_LOCKING +#define DECL /* Nothing */ +#define LOCKIT down (& port->port_write_sem); +#define RELEASEIT up (&port->port_write_sem); +#else +#define DECL unsigned long flags; +#define LOCKIT save_flags (flags);cli () +#define RELEASEIT restore_flags (flags) +#endif + + + +void gs_put_char(struct tty_struct * tty, unsigned char ch) +{ + struct gs_port *port = tty->driver_data; + DECL + + /* func_enter (); */ + + /* Take a lock on the serial tranmit buffer! */ + LOCKIT; + + if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + /* Sorry, buffer is full, drop character. Update statistics???? -- REW */ + RELEASEIT; + return; + } + + port->xmit_buf[port->xmit_head++] = ch; + port->xmit_head &= SERIAL_XMIT_SIZE - 1; + port->xmit_cnt++; /* Characters in buffer */ + + RELEASEIT; + /* func_exit ();*/ +} + + +#ifdef NEW_WRITE_LOCKING + +/* +> Problems to take into account are: +> -1- Interrupts that empty part of the buffer. +> -2- page faults on the access to userspace. +> -3- Other processes that are also trying to do a "write". +*/ + +int gs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct gs_port *port = tty->driver_data; + int c, total = 0; + int t; + + /* func_enter (); */ + + if (! (port->flags & ASYNC_INITIALIZED)) + return 0; + + /* get exclusive "write" access to this port (problem 3) */ + /* This is not a spinlock because we can have a disk access (page + fault) in copy_from_user */ + down (& port->port_write_sem); + + while (1) { + + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) break; + if (from_user) + copy_from_user (port->xmit_buf + port->xmit_head, buf, c); + else + memcpy (port->xmit_buf + port->xmit_head, buf, c); + + port -> xmit_cnt += c; + port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1); + buf += c; + count -= c; + total += c; + } + up (& port->port_write_sem); + + gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", + (port->flags & GS_TX_INTEN)?"enabled": "disabled"); + + if (port->xmit_cnt && + !tty->stopped && + !tty->hw_stopped && + !(port->flags & GS_TX_INTEN)) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + /* func_exit (); */ + return total; +} +#else +/* +> Problems to take into account are: +> -1- Interrupts that empty part of the buffer. +> -2- page faults on the access to userspace. +> -3- Other processes that are also trying to do a "write". +*/ + +int gs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct gs_port *port; + int c, total = 0; + int t; + unsigned long flags; + + func_enter (); + + /* The standard serial driver returns 0 in this case. + That sounds to me as "No error, I just didn't get to writing any + bytes. Feel free to try again." + The "official" way to write n bytes from buf is: + + for (nwritten = 0;nwritten < n;nwritten += rv) { + rv = write (fd, buf+nwritten, n-nwritten); + if (rv < 0) break; // Error: bail out. // + } + + which will loop endlessly in this case. The manual page for write + agrees with me. In practise almost everybody writes + "write (fd, buf,n);" but some people might have had to deal with + incomplete writes in the past and correctly implemented it by now... + */ + + if (!tty) return -EIO; + + port = tty->driver_data; + if (!port || !port->xmit_buf || !tmp_buf) + return -EIO; + + /* printk ("from_user = %d.\n", from_user); */ + save_flags(flags); + if (from_user) { + /* printk ("Going into the semaphore\n"); */ + down(&tmp_buf_sem); + /* printk ("got out of the semaphore\n"); */ + while (1) { + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } + cli(); + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); + port->xmit_head = ((port->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + port->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = count; + + /* This is safe because we "OWN" the "head". Noone else can + change the "head": we own the port_write_sem. */ + /* Don't overrun the end of the buffer */ + t = SERIAL_XMIT_SIZE - port->xmit_head; + if (t < c) c = t; + + /* This is safe because the xmit_cnt can only decrease. This + would increase "t", so we might copy too little chars. */ + /* Don't copy past the "head" of the buffer */ + t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; + if (t < c) c = t; + + /* Can't copy more? break out! */ + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(port->xmit_buf + port->xmit_head, buf, c); + port->xmit_head = ((port->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + port->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + } + + if (port->xmit_cnt && + !tty->stopped && + !tty->hw_stopped && + !(port->flags & GS_TX_INTEN)) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + func_exit (); + return total; +} + +#endif + + + +int gs_write_room(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + int ret; + + /* func_enter (); */ + ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; + if (ret < 0) + ret = 0; + /* func_exit (); */ + return ret; +} + + +int gs_chars_in_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + func_enter (); + + func_exit (); + return port->xmit_cnt; +} + + +int gs_real_chars_in_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + func_enter (); + + if (!tty) return 0; + port = tty->driver_data; + + func_exit (); + return port->xmit_cnt + port->rd->chars_in_buffer (port); +} + + +static void gs_wait_tx_flushed (void * ptr, int timeout) +{ + struct gs_port *port = ptr; + long end_jiffies; + int jiffies_to_transmit, charsleft; + int to, rcib; + + func_enter(); + + gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port); + if (port) { + gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n", + port->xmit_cnt, port->xmit_buf, port->tty); + } + + if (!port || port->xmit_cnt < 0 || !port->xmit_buf) { + gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n"); + func_exit(); + return; /* This is an error which we don't know how to handle. */ + } + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 1\n"); + + rcib = gs_real_chars_in_buffer(port->tty); + + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 2\n"); + + if(rcib <= 0) { + gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n"); + func_exit(); + return; + } + gs_dprintk (GS_DEBUG_FLUSH, "checkpoint 3\n"); + + /* stop trying: now + twice the time it would normally take + seconds */ + end_jiffies = jiffies; + if (timeout != MAX_SCHEDULE_TIMEOUT) + end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0; + end_jiffies += timeout; + + gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n", + jiffies, end_jiffies, end_jiffies-jiffies); + + to = 100; + /* the expression is actually jiffies < end_jiffies, but that won't + work around the wraparound. Tricky eh? */ + while (to-- && + (charsleft = gs_real_chars_in_buffer (port->tty)) && + time_after (end_jiffies, jiffies)) { + /* Units check: + chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies! + check! */ + + charsleft += 16; /* Allow 16 chars more to be transmitted ... */ + jiffies_to_transmit = port->baud?(1 + charsleft * 10 * HZ / port->baud):0; + /* ^^^ Round up.... */ + if (jiffies_to_transmit <= 0) jiffies_to_transmit = 1; + + gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies " + "(%d chars).\n", jiffies_to_transmit, charsleft); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(jiffies_to_transmit); + if (signal_pending (current)) + break; + } + + gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft); + current->state = TASK_RUNNING; + + func_exit(); +} + + + +void gs_flush_buffer(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + unsigned long flags; + + func_enter (); + /* XXX Would the write semaphore do? */ + save_flags(flags); cli(); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + func_exit (); +} + + +void gs_flush_chars(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !port->xmit_buf) { + func_exit (); + return; + } + + /* Beats me -- REW */ + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + func_exit (); +} + + +void gs_stop(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + if (port->xmit_cnt && + port->xmit_buf && + (port->flags & GS_TX_INTEN) ) { + port->flags &= ~GS_TX_INTEN; + port->rd->disable_tx_interrupts (port); + } + func_exit (); +} + + +void gs_start(struct tty_struct * tty) +{ + struct gs_port *port = tty->driver_data; + + if (port->xmit_cnt && + port->xmit_buf && + !(port->flags & GS_TX_INTEN) ) { + port->flags |= GS_TX_INTEN; + port->rd->enable_tx_interrupts (port); + } + func_exit (); +} + + +void gs_shutdown_port (struct gs_port *port) +{ + long flags; + + if (!(port->flags & ASYNC_INITIALIZED)) + return; + + save_flags (flags); + cli (); + + if (port->xmit_buf) { + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = 0; + } + + if (port->tty) + set_bit(TTY_IO_ERROR, &port->tty->flags); + + port->rd->shutdown_port (port); + + port->flags &= ~ASYNC_INITIALIZED; + restore_flags (flags); +} + + +void gs_hangup(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + + func_enter (); + + tty = port->tty; + if (!tty) return; + + gs_shutdown_port (port); + + /* gs_flush_buffer (tty); */ + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE); + port->tty = NULL; + port->count = 0; + + wake_up_interruptible(&port->open_wait); + func_exit (); +} + + +void gs_do_softint(void *private_) +{ + struct gs_port *port = private_; + struct tty_struct *tty; + + tty = port->tty; + if(!tty) return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } + func_exit (); +} + + +int block_til_ready(void *port_, struct file * filp) +{ + struct gs_port *port = port_; + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + int CD; + struct tty_struct *tty; + + func_enter (); + tty = port->tty; + + gs_dprintk (GS_DEBUG_BTR, "Entering block_till_ready.\n"); + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&port->close_wait); + if (port->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == GS_TYPE_CALLOUT) { + if (port->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_SESSION_LOCKOUT) && + (port->session != current->session)) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_PGRP_LOCKOUT) && + (port->pgrp != current->pgrp)) + return -EBUSY; + port->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + gs_dprintk (GS_DEBUG_BTR, "after subtype\n"); + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (port->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); + + if (port->flags & ASYNC_CALLOUT_ACTIVE) { + if (port->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (C_CLOCAL(tty)) + do_clocal = 1; + } + + gs_dprintk (GS_DEBUG_BTR, "after clocal check.\n"); + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, port->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&port->open_wait, &wait); + + gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); + + cli(); + if (!tty_hung_up_p(filp)) + port->count--; + sti(); + port->blocked_open++; + while (1) { + CD = port->rd->get_CD (port); + gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(port->flags & ASYNC_INITIALIZED)) { + if (port->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && + !(port->flags & ASYNC_CLOSING) && + (do_clocal || CD)) + break; + gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", + (int)signal_pending (current), *(long*)(¤t->blocked)); + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n", + port->blocked_open); + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + if (!tty_hung_up_p(filp)) + port->count++; + port->blocked_open--; + if (retval) + return retval; + + port->flags |= ASYNC_NORMAL_ACTIVE; + func_exit (); + return 0; +} + + +void gs_close(struct tty_struct * tty, struct file * filp) +{ + unsigned long flags; + struct gs_port *port; + + func_enter (); + port = (struct gs_port *) tty->driver_data; + + gs_dprintk (GS_DEBUG_CLOSE, "tty=%p, port=%p port->tty=%p\n", + tty, port, port->tty); + + if(! port) { + func_exit(); + return; + } + if (!port->tty) { + printk (KERN_WARNING "gs: Odd: port->tty is NULL\n"); + port->tty = tty; + } + + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + port->rd->hungup (port); + func_exit (); + return; + } + + if ((tty->count == 1) && (port->count != 1)) { + printk(KERN_ERR "gs: gs_close: bad port count;" + " tty->count is 1, port count is %d\n", port->count); + port->count = 1; + } + if (--port->count < 0) { + printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count); + port->count = 0; + } + if (port->count) { + restore_flags(flags); + func_exit (); + return; + } + port->flags |= ASYNC_CLOSING; + + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (port->flags & ASYNC_NORMAL_ACTIVE) + port->normal_termios = *tty->termios; + if (port->flags & ASYNC_CALLOUT_ACTIVE) + port->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + /* if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); */ + + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + + port->rd->disable_rx_interrupts (port); + + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + gs_wait_tx_flushed (port, port->closing_wait); + + port->flags &= ~GS_ACTIVE; + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + port->event = 0; + port->tty = 0; + if (port->blocked_open) { + if (port->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(port->close_delay); + } + wake_up_interruptible(&port->open_wait); + } + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING | ASYNC_INITIALIZED); + wake_up_interruptible(&port->close_wait); + + port->rd->close (port); + port->rd->shutdown_port (port); + restore_flags(flags); + func_exit (); +} + + +static unsigned int gs_baudrates[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 +}; + + +void gs_set_termios (struct tty_struct * tty, + struct termios * old_termios) +{ + struct gs_port *port = tty->driver_data; + int baudrate, tmp; + struct termios *tiosp; + + func_enter(); + + tiosp = tty->termios; + + + if (gs_debug & GS_DEBUG_TERMIOS) { + gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); + my_hd ((unsigned char *)tiosp, sizeof (struct termios)); + } + +#if 0 + /* This is an optimization that is only allowed for dumb cards */ + /* Smart cards require knowledge of iflags and oflags too: that + might change hardware cooking mode.... */ +#endif + if (old_termios) { + if( (tiosp->c_iflag == old_termios->c_iflag) + && (tiosp->c_oflag == old_termios->c_oflag) + && (tiosp->c_cflag == old_termios->c_cflag) + && (tiosp->c_lflag == old_termios->c_lflag) + && (tiosp->c_line == old_termios->c_line) + && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) { + gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n"); + return; + } + } else + gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: " + "no optimization\n"); + + if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) { + if(tiosp->c_iflag != old_termios->c_iflag) printk("c_iflag changed\n"); + if(tiosp->c_oflag != old_termios->c_oflag) printk("c_oflag changed\n"); + if(tiosp->c_cflag != old_termios->c_cflag) printk("c_cflag changed\n"); + if(tiosp->c_lflag != old_termios->c_lflag) printk("c_lflag changed\n"); + if(tiosp->c_line != old_termios->c_line) printk("c_line changed\n"); + if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n"); + } + + baudrate = tiosp->c_cflag & CBAUD; + if (baudrate & CBAUDEX) { + baudrate &= ~CBAUDEX; + if ((baudrate < 1) || (baudrate > 4)) + tiosp->c_cflag &= ~CBAUDEX; + else + baudrate += 15; + } + + baudrate = gs_baudrates[baudrate]; + if ((tiosp->c_cflag & CBAUD) == B38400) { + if ( (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baudrate = 57600; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baudrate = 115200; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + baudrate = 230400; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + baudrate = 460800; + else if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + baudrate = (port->baud_base / port->custom_divisor); + } + + /* I recommend using THIS instead of the mess in termios (and + duplicating the above code). Next we should create a clean + interface towards this variable. If your card supports arbitrary + baud rates, (e.g. CD1400 or 16550 based cards) then everything + will be very easy..... */ + port->baud = baudrate; + + /* Two timer ticks seems enough to wakeup something like SLIP driver */ + /* Baudrate/10 is cps. Divide by HZ to get chars per tick. */ + tmp = (baudrate / 10 / HZ) * 2; + + if (tmp < 0) tmp = 0; + if (tmp >= SERIAL_XMIT_SIZE) tmp = SERIAL_XMIT_SIZE-1; + + port->wakeup_chars = tmp; + + /* We should really wait for the characters to be all sent before + changing the settings. -- CAL */ + gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT); + + port->rd->set_real_termios(port); + + if ((!old_termios || + (old_termios->c_cflag & CRTSCTS)) && + !( tiosp->c_cflag & CRTSCTS)) { + tty->stopped = 0; + gs_start(tty); + } + +#ifdef tytso_patch_94Nov25_1726 + /* This "makes sense", Why is it commented out? */ + + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif + + func_exit(); + return; +} + + + +/* Must be called with interrupts enabled */ +int gs_init_port(struct gs_port *port) +{ + unsigned long flags; + unsigned long page; + + save_flags (flags); + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + + cli (); /* Don't expect this to make a difference. */ + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + restore_flags (flags); + + if (!tmp_buf) { + return -ENOMEM; + } + } + + if (port->flags & ASYNC_INITIALIZED) + return 0; + + if (!port->xmit_buf) { + /* We may sleep in get_free_page() */ + unsigned long tmp; + + tmp = get_free_page(GFP_KERNEL); + + /* Spinlock? */ + cli (); + if (port->xmit_buf) + free_page (tmp); + else + port->xmit_buf = (unsigned char *) tmp; + restore_flags (flags); + + if (!port->xmit_buf) + return -ENOMEM; + } + + cli(); + + if (port->tty) + clear_bit(TTY_IO_ERROR, &port->tty->flags); + + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + + gs_set_termios(port->tty, NULL); + + port->flags |= ASYNC_INITIALIZED; + port->flags &= ~GS_TX_INTEN; + + restore_flags(flags); + return 0; +} + + +int gs_setserial(struct gs_port *port, struct serial_struct *sp) +{ + struct serial_struct sio; + + copy_from_user(&sio, sp, sizeof(struct serial_struct)); + + if (!capable(CAP_SYS_ADMIN)) { + if ((sio.baud_base != port->baud_base) || + (sio.close_delay != port->close_delay) || + ((sio.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) + return(-EPERM); + } + + port->flags = (port->flags & ~ASYNC_USR_MASK) | + (sio.flags & ASYNC_USR_MASK); + + port->baud_base = sio.baud_base; + port->close_delay = sio.close_delay; + port->closing_wait = sio.closing_wait; + port->custom_divisor = sio.custom_divisor; + + gs_set_termios (port->tty, NULL); + + return 0; +} + + +/*****************************************************************************/ + +/* + * Generate the serial struct info. + */ + +void gs_getserial(struct gs_port *port, struct serial_struct *sp) +{ + struct serial_struct sio; + + memset(&sio, 0, sizeof(struct serial_struct)); + sio.flags = port->flags; + sio.baud_base = port->baud_base; + sio.close_delay = port->close_delay; + sio.closing_wait = port->closing_wait; + sio.custom_divisor = port->custom_divisor; + sio.hub6 = 0; + + /* If you want you can override these. */ + sio.type = PORT_UNKNOWN; + sio.xmit_fifo_size = -1; + sio.line = -1; + sio.port = -1; + sio.irq = -1; + + if (port->rd->getserial) + port->rd->getserial (port, &sio); + + copy_to_user(sp, &sio, sizeof(struct serial_struct)); +} + diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/generic_serial.h linux.pre11.6/drivers/char/generic_serial.h --- linux.pre11.5/drivers/char/generic_serial.h Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/drivers/char/generic_serial.h Sat Aug 7 21:24:07 1999 @@ -0,0 +1,101 @@ +/* + * generic_serial.h + * + * Copyright (C) 1998 R.E.Wolff@BitWizard.nl + * + * written for the SX serial driver. + * Contains the code that should be shared over all the serial drivers. + * + * Version 0.1 -- December, 1998. + */ + +#ifndef GENERIC_SERIAL_H +#define GENERIC_SERIAL_H + +struct real_driver { + void (*disable_tx_interrupts) (void *); + void (*enable_tx_interrupts) (void *); + void (*disable_rx_interrupts) (void *); + void (*enable_rx_interrupts) (void *); + int (*get_CD) (void *); + void (*shutdown_port) (void*); + void (*set_real_termios) (void*); + int (*chars_in_buffer) (void*); + void (*close) (void*); + void (*hungup) (void*); + void (*getserial) (void*, struct serial_struct *sp); +}; + + + +struct gs_port { + int magic; + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + /* struct semaphore port_write_sem; */ + int flags; + struct termios normal_termios; + struct termios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + long session; + long pgrp; + int count; + int blocked_open; + struct tty_struct *tty; + int event; + unsigned short closing_wait; + int close_delay; + struct real_driver *rd; + int wakeup_chars; + int baud_base; + int baud; + int custom_divisor; +}; + + +/* Flags */ +/* Warning: serial.h defines some ASYNC_ flags, they say they are "only" + used in serial.c, but they are also used in all other serial drivers. + Make sure they don't clash with these here... */ +#define GS_TX_INTEN 0x00800000 +#define GS_RX_INTEN 0x00400000 +#define GS_ACTIVE 0x00200000 + + + +#define GS_TYPE_NORMAL 1 +#define GS_TYPE_CALLOUT 2 + + +#define GS_DEBUG_FLUSH 0x00000001 +#define GS_DEBUG_BTR 0x00000002 +#define GS_DEBUG_TERMIOS 0x00000004 +#define GS_DEBUG_STUFF 0x00000008 +#define GS_DEBUG_CLOSE 0x00000010 + + +void gs_put_char(struct tty_struct *tty, unsigned char ch); +int gs_write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count); +int gs_write_room(struct tty_struct *tty); +int gs_chars_in_buffer(struct tty_struct *tty); +void gs_flush_buffer(struct tty_struct *tty); +void gs_flush_chars(struct tty_struct *tty); +void gs_stop(struct tty_struct *tty); +void gs_start(struct tty_struct *tty); +void gs_hangup(struct tty_struct *tty); +void gs_do_softint(void *private_); +int block_til_ready(void *port, struct file *filp); +void gs_close(struct tty_struct *tty, struct file *filp); +void gs_set_termios (struct tty_struct * tty, + struct termios * old_termios); +int gs_init_port(struct gs_port *port); +int gs_setserial(struct gs_port *port, struct serial_struct *sp); +void gs_getserial(struct gs_port *port, struct serial_struct *sp); + +extern int gs_debug; + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/sx.c linux.pre11.6/drivers/char/sx.c --- linux.pre11.5/drivers/char/sx.c Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/drivers/char/sx.c Sat Aug 7 21:24:07 1999 @@ -0,0 +1,2684 @@ + +/* sx.c -- driver for the Specialix SX series cards. + * + * This driver will also support the older SI, and XIO cards. + * + * + * (C) 1998 R.E.Wolff@BitWizard.nl + * + * Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous + * version of this driver. Some fragments may have been copied. (none + * yet :-) + * + * Specialix pays for the development and support of this driver. + * Please DO contact support@specialix.co.uk if you require + * support. But please read the documentation (sx.txt) first. + * + * + * + * 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. + * + * Revision history: + * $Log: sx.c,v $ + * Revision 1.26 1999/08/05 15:22:14 wolff + * - Port to 2.3.x + * - Reformatted to Linus' liking. + * + * Revision 1.25 1999/07/30 14:24:08 wolff + * Had accidentally left "gs_debug" set to "-1" instead of "off" (=0). + * + * Revision 1.24 1999/07/28 09:41:52 wolff + * - I noticed the remark about use-count straying in sx.txt. I checked + * sx_open, and found a few places where that could happen. I hope it's + * fixed now. + * + * Revision 1.23 1999/07/28 08:56:06 wolff + * - Fixed crash when sx_firmware run twice. + * - Added sx_slowpoll as a module parameter (I guess nobody really wanted + * to change it from the default... ) + * - Fixed a stupid editing problem I introduced in 1.22. + * - Fixed dropping characters on a termios change. + * + * Revision 1.22 1999/07/26 21:01:43 wolff + * Russell Brown noticed that I had overlooked 4 out of six modem control + * signals in sx_getsignals. Ooops. + * + * Revision 1.21 1999/07/23 09:11:33 wolff + * I forgot to free dynamically allocated memory when the driver is unloaded. + * + * Revision 1.20 1999/07/20 06:25:26 wolff + * The "closing wait" wasn't honoured. Thanks to James Griffiths for + * reporting this. + * + * Revision 1.19 1999/07/11 08:59:59 wolff + * Fixed an oops in close, when an open was pending. Changed the memtest + * a bit. Should also test the board in word-mode, however my card fails the + * memtest then. I still have to figure out what is wrong... + * + * Revision 1.18 1999/06/10 09:38:42 wolff + * Changed the format of the firmware revision from %04x to %x.%02x . + * + * Revision 1.17 1999/06/04 09:44:35 wolff + * fixed problem: reference to pci stuff when config_pci was off... + * Thanks to Jorge Novo for noticing this. + * + * Revision 1.16 1999/06/02 08:30:15 wolff + * added/removed the workaround for the DCD bug in the Firmware. + * A bit more debugging code to locate that... + * + * Revision 1.15 1999/06/01 11:35:30 wolff + * when DCD is left low (floating?), on TA's the firmware first tells us + * that DCD is high, but after a short while suddenly comes to the + * conclusion that it is low. All this would be fine, if it weren't that + * Unix requires us to send a "hangup" signal in that case. This usually + * all happens BEFORE the program has had a chance to ioctl the device + * into clocal mode.. + * + * Revision 1.14 1999/05/25 11:18:59 wolff + * Added PCI-fix. + * Added checks for return code of sx_sendcommand. + * Don't issue "reconfig" if port isn't open yet. (bit us on TA modules...) + * + * Revision 1.13 1999/04/29 15:18:01 wolff + * Fixed an "oops" that showed on SuSE 6.0 systems. + * Activate DTR again after stty 0. + * + * Revision 1.12 1999/04/29 07:49:52 wolff + * Improved "stty 0" handling a bit. (used to change baud to 9600 assuming + * the connection would be dropped anyway. That is not always the case, + * and confuses people). + * Told the card to always monitor the modem signals. + * Added support for dynamic gs_debug adjustments. + * Now tells the rest of the system the number of ports. + * + * Revision 1.11 1999/04/24 11:11:30 wolff + * Fixed two stupid typos in the memory test. + * + * Revision 1.10 1999/04/24 10:53:39 wolff + * Added some of Christian's suggestions. + * Fixed an HW_COOK_IN bug (ISIG was not in I_OTHER. We used to trust the + * card to send the signal to the process.....) + * + * Revision 1.9 1999/04/23 07:26:38 wolff + * Included Christian Lademann's 2.0 compile-warning fixes and interrupt + * assignment redesign. + * Cleanup of some other stuff. + * + * Revision 1.8 1999/04/16 13:05:30 wolff + * fixed a DCD change unnoticed bug. + * + * Revision 1.7 1999/04/14 22:19:51 wolff + * Fixed typo that showed up in 2.0.x builds (get_user instead of Get_user!) + * + * Revision 1.6 1999/04/13 18:40:20 wolff + * changed misc-minor to 161, as assigned by HPA. + * + * Revision 1.5 1999/04/13 15:12:25 wolff + * Fixed use-count leak when "hangup" occurred. + * Added workaround for a stupid-PCIBIOS bug. + * + * + * Revision 1.4 1999/04/01 22:47:40 wolff + * Fixed < 1M linux-2.0 problem. + * (vremap isn't compatible with ioremap in that case) + * + * Revision 1.3 1999/03/31 13:45:45 wolff + * Firmware loading is now done through a separate IOCTL. + * + * Revision 1.2 1999/03/28 12:22:29 wolff + * rcs cleanup + * + * Revision 1.1 1999/03/28 12:10:34 wolff + * Readying for release on 2.0.x (sorry David, 1.01 becomes 1.1 for RCS). + * + * Revision 0.12 1999/03/28 09:20:10 wolff + * Fixed problem in 0.11, continueing cleanup. + * + * Revision 0.11 1999/03/28 08:46:44 wolff + * cleanup. Not good. + * + * Revision 0.10 1999/03/28 08:09:43 wolff + * Fixed loosing characters on close. + * + * Revision 0.9 1999/03/21 22:52:01 wolff + * Ported back to 2.2.... (minor things) + * + * Revision 0.8 1999/03/21 22:40:33 wolff + * Port to 2.0 + * + * Revision 0.7 1999/03/21 19:06:34 wolff + * Fixed hangup processing. + * + * Revision 0.6 1999/02/05 08:45:14 wolff + * fixed real_raw problems. Inclusion into kernel imminent. + * + * Revision 0.5 1998/12/21 23:51:06 wolff + * Snatched a nasty bug: sx_transmit_chars was getting re-entered, and it + * shouldn't have. THATs why I want to have transmit interrupts even when + * the buffer is empty. + * + * Revision 0.4 1998/12/17 09:34:46 wolff + * PPP works. ioctl works. Basically works! + * + * Revision 0.3 1998/12/15 13:05:18 wolff + * It works! Wow! Gotta start implementing IOCTL and stuff.... + * + * Revision 0.2 1998/12/01 08:33:53 wolff + * moved over to 2.1.130 + * + * Revision 0.1 1998/11/03 21:23:51 wolff + * Initial revision. Detects SX card. + * + * */ + + +#define RCS_ID "$Id: sx.c,v 1.26 1999/08/05 15:22:14 wolff Exp $" +#define RCS_REV "$Revision: 1.26 $" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The 3.0.0 version of sxboards/sxwindow.h uses BYTE and WORD.... */ +#define BYTE u8 +#define WORD u16 + +/* .... but the 3.0.4 version uses _u8 and _u16. */ +#define _u8 u8 +#define _u16 u16 + +#include "sxboards.h" +#include "sxwindow.h" + + +/* I don't think that this driver can handle more than 256 ports on + one machine. You'll have to increase the number of boards in sx.h + if you want more than 4 boards. */ + + +/* ************************************************************** */ +/* * This section can be removed when 2.0 becomes outdated.... * */ +/* ************************************************************** */ + + +#if LINUX_VERSION_CODE < 0x020100 /* Less than 2.1.0 */ +#define TWO_ZERO +#else +#if LINUX_VERSION_CODE < 0x020200 /* less than 2.2.x */ +#warning "Please use a 2.2.x kernel. " +#else +#if LINUX_VERSION_CODE < 0x020300 /* less than 2.3.x */ +#define TWO_TWO +#else +#define TWO_THREE +#endif +#endif +#endif + +#ifdef TWO_ZERO + +/* Here is the section that makes the 2.2 compatible driver source + work for 2.0 too! We mostly try to adopt the "new thingies" from 2.2, + and provide for compatibility stuff here if possible. */ + +#include + +#define Get_user(a,b) a = get_user(b) +#define Put_user(a,b) 0,put_user(a,b) +#define copy_to_user(a,b,c) memcpy_tofs(a,b,c) + +static inline int copy_from_user(void *to,const void *from, int c) +{ + memcpy_fromfs(to, from, c); + return 0; +} + +#define pci_present pcibios_present +#define pci_read_config_word pcibios_read_config_word +#define pci_read_config_dword pcibios_read_config_dword + +static inline unsigned char get_irq (unsigned char bus, unsigned char fn) +{ + unsigned char t; + pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &t); + return t; +} + +static inline void *ioremap(unsigned long base, long length) +{ + if (base < 0x100000) return (void *)base; + return vremap (base, length); +} + +#define my_iounmap(x, b) (((long)x<0x100000)?0:vfree ((void*)x)) + +#define capable(x) suser() + +#define queue_task queue_task_irq_off +#define tty_flip_buffer_push(tty) queue_task(&tty->flip.tqueue, &tq_timer) +#define signal_pending(current) (current->signal & ~current->blocked) +#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) +#define time_after(t1,t2) (((long)t1-t2) > 0) + + +#define test_and_set_bit(nr, addr) set_bit(nr, addr) +#define test_and_clear_bit(nr, addr) clear_bit(nr, addr) + +/* Not yet implemented on 2.0 */ +#define ASYNC_SPD_SHI -1 +#define ASYNC_SPD_WARP -1 + + +/* Ugly hack: the driver_name doesn't exist in 2.0.x . So we define it + to the "name" field that does exist. As long as the assignments are + done in the right order, there is nothing to worry about. */ +#define driver_name name + +/* Should be in a header somewhere. They are in tty.h on 2.2 */ +#define TTY_HW_COOK_OUT 14 /* Flag to tell ntty what we can handle */ +#define TTY_HW_COOK_IN 15 /* in hardware - output and input */ + +/* The return type of a "close" routine. */ +#define INT void +#define NO_ERROR /* Nothing */ + +#else + +/* The 2.2.x compatibility section. */ +#include + + +#define Get_user(a,b) get_user(a,b) +#define Put_user(a,b) put_user(a,b) +#define get_irq(pdev) pdev->irq + +#define INT int +#define NO_ERROR 0 + +#define my_iounmap(x,b) (iounmap((char *)(b))) + +#endif + +#ifndef TWO_THREE +/* These are new in 2.3. The source now uses 2.3 syntax, and here is + the compatibility define... */ +#define wait_queue_head_t struct wait_queue * +#define DECLARE_MUTEX(name) struct semaphore name = MUTEX +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } + +#endif + + + +#include "generic_serial.h" +#include "sx.h" + + +/* ************************************************************** */ +/* * End of compatibility section.. * */ +/* ************************************************************** */ + + + +/* Why the hell am I defining these here? */ +#define SX_TYPE_NORMAL 1 +#define SX_TYPE_CALLOUT 2 + +#ifndef SX_NORMAL_MAJOR +/* This allows overriding on the compiler commandline, or in a "major.h" + include or something like that */ +#define SX_NORMAL_MAJOR 32 +#define SX_CALLOUT_MAJOR 33 +#endif + +#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 +#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000 +#endif + + + +/* Configurable options: + (Don't be too sure that it'll work if you toggle them) */ + +/* Am I paranoid or not ? ;-) */ +#undef SX_PARANOIA_CHECK + + +/* 20 -> 2000 per second. The card should rate-limit interrupts at 100 + Hz, but it is user configurable. I don't recommend going above 1000 + Hz. The interrupt ratelimit might trigger if the interrupt is + shared with a very active other device. */ +#define IRQ_RATE_LIMIT 20 + +/* Sharing interrupts is possible now. If the other device wants more + than 2000 interrupts per second, we'd gracefully decline further + interrupts. That's not what we want. On the other hand, if the + other device interrupts 2000 times a second, don't use the SX + interrupt. Use polling. */ +#undef IRQ_RATE_LIMIT + + +#if 0 +/* Not implemented */ +/* + * The following defines are mostly for testing purposes. But if you need + * some nice reporting in your syslog, you can define them also. + */ +#define SX_REPORT_FIFO +#define SX_REPORT_OVERRUN +#endif + + +/* Function prototypes */ +static void sx_disable_tx_interrupts (void * ptr); +static void sx_enable_tx_interrupts (void * ptr); +static void sx_disable_rx_interrupts (void * ptr); +static void sx_enable_rx_interrupts (void * ptr); +static int sx_get_CD (void * ptr); +static void sx_shutdown_port (void * ptr); +static void sx_set_real_termios (void *ptr); +static void sx_hungup (void *ptr); +static void sx_close (void *ptr); +static int sx_chars_in_buffer (void * ptr); +static int sx_init_board (struct sx_board *board); +static int sx_init_portstructs (int nboards, int nports); +static int sx_fw_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int sx_fw_open(struct inode *inode, struct file *filp); +static INT sx_fw_release(struct inode *inode, struct file *filp); +static int sx_init_drivers(void); +void my_hd (unsigned char *addr, int len); + + + +static struct tty_driver sx_driver, sx_callout_driver; + +static struct tty_struct * sx_table[SX_NPORTS] = { NULL, }; +static struct termios ** sx_termios; +static struct termios ** sx_termios_locked; + +struct sx_board boards[SX_NBOARDS]; +struct sx_port *sx_ports; +int sx_refcount; +int sx_initialized = 0; +int sx_nports = 0; +int sx_debug = 0; + + +/* You can have the driver poll your card. + - Set sx_poll to 1 to poll every timer tick (10ms on Intel). + This is used when the card cannot use an interrupt for some reason. + + - set sx_slowpoll to 100 to do an extra poll once a second (on Intel). If + the driver misses an interrupt (report this if it DOES happen to you!) + everything will continue to work.... + */ +int sx_poll = 1; +int sx_slowpoll = 0; + +/* The card limits the number of interrupts per second. + At 115k2 "100" should be sufficient. + If you're using higher baudrates, you can increase this... + */ + +int sx_maxints = 100; + +/* These are the only open spaces in my computer. Yours may have more + or less.... */ +int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, + 0xc8000, 0xd8000, 0xe8000}; +int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000, + 0xc8000, 0xd8000, 0xe8000}; + +#define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int)) +#define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int)) + + +/* Set the mask to all-ones. This alas, only supports 32 interrupts. + Some architectures may need more. */ +int sx_irqmask = -1; + +#ifndef TWO_ZERO +#ifdef MODULE +MODULE_PARM(sx_poll, "i"); +MODULE_PARM(sx_slowpoll, "i"); +MODULE_PARM(sx_maxints, "i"); +MODULE_PARM(sx_debug, "i"); +MODULE_PARM(sx_irqmask, "i"); +#endif +#endif + +static struct real_driver sx_real_driver = { + sx_disable_tx_interrupts, + sx_enable_tx_interrupts, + sx_disable_rx_interrupts, + sx_enable_rx_interrupts, + sx_get_CD, + sx_shutdown_port, + sx_set_real_termios, + sx_chars_in_buffer, + sx_close, + sx_hungup, + NULL +}; + + +/* + This driver can spew a whole lot of debugging output at you. If you + need maximum performance, you should disable the DEBUG define. To + aid in debugging in the field, I'm leaving the compile-time debug + features enabled, and disable them "runtime". That allows me to + instruct people with problems to enable debugging without requiring + them to recompile... +*/ +#define DEBUG + + +#ifdef DEBUG +#define sx_dprintk(f, str...) if (sx_debug & f) printk (str) +#else +#define sx_dprintk(f, str...) /* nothing */ +#endif + + + +#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ "\n") +#define func_exit() sx_dprintk (SX_DEBUG_FLOW, "sx: exit " __FUNCTION__ "\n") + +#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ \ + "(port %d)\n", port->line) + + + + +/* + * Firmware loader driver specific routines + * + */ + +static struct file_operations sx_fw_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + sx_fw_ioctl, + NULL, /* mmap */ + sx_fw_open, +#ifndef TWO_ZERO + NULL, /* flush */ +#endif + sx_fw_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct miscdevice sx_fw_device = { + SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops +}; + + + + + +#ifdef SX_PARANOIA_CHECK + +/* This doesn't work. Who's paranoid around here? Not me! */ + +static inline int sx_paranoia_check(struct sx_port const * port, + kdev_t device, const char *routine) +{ + + static const char *badmagic = + KERN_ERR "sx: Warning: bad sx port magic number for device %s in %s\n"; + static const char *badinfo = + KERN_ERR "sx: Warning: null sx port for device %s in %s\n"; + + if (!port) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (port->magic != SX_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } + + return 0; +} +#else +#define sx_paranoia_check(a,b,c) 0 +#endif + +/* The timeouts. First try 30 times as fast as possible. Then give + the card some time to breathe between accesses. (Otherwise the + processor on the card might not be able to access its OWN bus... */ + +#define TIMEOUT_1 30 +#define TIMEOUT_2 1000000 + + +/* This needs redoing for Alpha -- REW -- Done. */ + +inline void write_sx_byte (struct sx_board *board, int offset, u8 byte) +{ + writeb (byte, board->base+offset); +} + +inline u8 read_sx_byte (struct sx_board *board, int offset) +{ + return readb (board->base+offset); +} + + +inline void write_sx_word (struct sx_board *board, int offset, u16 word) +{ + writew (word, board->base+offset); +} + +inline u16 read_sx_word (struct sx_board *board, int offset) +{ + return readw (board->base + offset); +} + + +int sx_busy_wait_eq (struct sx_board *board, + int offset, + int mask, + int correctval) +{ + int i; + + func_enter (); + + for (i=0; i < TIMEOUT_1 > 0;i++) + if ((read_sx_byte (board, offset) & mask) == correctval) { + func_exit (); + return 1; + } + + for (i=0; i < TIMEOUT_2 > 0;i++) { + if ((read_sx_byte (board, offset) & mask) == correctval) { + func_exit (); + return 1; + } + udelay (1); + } + + func_exit (); + return 0; +} + + +int sx_busy_wait_neq (struct sx_board *board, + int offset, + int mask, + int badval) +{ + int i; + + func_enter (); + + for (i=0; i < TIMEOUT_1 > 0;i++) + if ((read_sx_byte (board, offset) & mask) != badval) { + func_exit (); + return 1; + } + + for (i=0; i < TIMEOUT_2 > 0;i++) { + if ((read_sx_byte (board, offset) & mask) != badval) { + func_exit (); + return 1; + } + udelay (1); + } + + func_exit (); + return 0; +} + + + +/* 5.6.4 of 6210028 r2.3 */ +int sx_reset (struct sx_board *board) +{ + func_enter (); + + if (IS_SX_BOARD (board)) { + + write_sx_byte (board, SX_CONFIG, 0); + write_sx_byte (board, SX_RESET, 1); /* Value doesn't matter */ + + if (!sx_busy_wait_eq (board, SX_RESET_STATUS, 1, 0)) { + printk (KERN_INFO "sx: Card doesn't respond to reset....\n"); + return 0; + } + } else { + /* Gory details of the SI/ISA board */ + write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_SET); + write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR); + write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR); + write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR); + write_sx_byte (board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR); + } + + func_exit (); + return 1; +} + + +/* This doesn't work on machines where "NULL" isn't 0 */ +/* If you have one of those, someone will need to write + the equivalent of this, which will amount to about 3 lines. I don't + want to complicate this right now. -- REW + (See, I do write comments every now and then :-) */ +#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem)) + + +#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem)) +#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem)) +#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem)) + + +#define sx_write_channel_byte(port, elem, val) \ + write_sx_byte (port->board, CHAN_OFFSET (port, elem), val) + +#define sx_read_channel_byte(port, elem) \ + read_sx_byte (port->board, CHAN_OFFSET (port, elem)) + +#define sx_write_channel_word(port, elem, val) \ + write_sx_word (port->board, CHAN_OFFSET (port, elem), val) + +#define sx_read_channel_word(port, elem) \ + read_sx_word (port->board, CHAN_OFFSET (port, elem)) + + +#define sx_write_module_byte(board, addr, elem, val) \ + write_sx_byte (board, MODU_OFFSET (board, addr, elem), val) + +#define sx_read_module_byte(board, addr, elem) \ + read_sx_byte (board, MODU_OFFSET (board, addr, elem)) + +#define sx_write_module_word(board, addr, elem, val) \ + write_sx_word (board, MODU_OFFSET (board, addr, elem), val) + +#define sx_read_module_word(board, addr, elem) \ + read_sx_word (board, MODU_OFFSET (board, addr, elem)) + + +#define sx_write_board_byte(board, elem, val) \ + write_sx_byte (board, BRD_OFFSET (board, elem), val) + +#define sx_read_board_byte(board, elem) \ + read_sx_byte (board, BRD_OFFSET (board, elem)) + +#define sx_write_board_word(board, elem, val) \ + write_sx_word (board, BRD_OFFSET (board, elem), val) + +#define sx_read_board_word(board, elem) \ + read_sx_word (board, BRD_OFFSET (board, elem)) + + +int sx_start_board (struct sx_board *board) +{ + if (IS_SX_BOARD (board)) { + write_sx_byte (board, SX_CONFIG, SX_CONF_BUSEN); + } else { + /* Don't bug me about the clear_set. + I haven't the foggiest idea what it's about -- REW*/ + write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + return 1; +} + +#define SX_IRQ_REG_VAL(board) \ + ((board->flags & SX_ISA_BOARD)?(board->irq << 4):0) + +/* Note. The SX register is write-only. Therefore, we have to enable the + bus too. This is a no-op, if you don't mess with this driver... */ +int sx_start_interrupts (struct sx_board *board) +{ + + /* Don't call this with board->irq == 0 */ + + if (IS_SX_BOARD(board)) { + write_sx_byte (board, SX_CONFIG, SX_IRQ_REG_VAL (board) | + SX_CONF_BUSEN | + SX_CONF_HOSTIRQ); + } else { + switch (board->irq) { + case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break; + case 12:write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);break; + case 15:write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);break; + default:printk (KERN_INFO "sx: SI/XIO card doesn't support interrupt %d.\n", + board->irq); + return 0; + } + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + + return 1; +} + + +int sx_send_command (struct sx_port *port, + int command, + int mask, + int newstat) +{ + func_enter2 (); + write_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat), command); + func_exit (); + return sx_busy_wait_eq (port->board, CHAN_OFFSET (port, hi_hstat), mask, newstat); +} + + +char *mod_type_s (int module_type) +{ + switch (module_type) { + case TA4: return "TA4"; + case TA8: return "TA8"; + case TA4_ASIC: return "TA4_ASIC"; + case TA8_ASIC: return "TA8_ASIC"; + case MTA_CD1400:return "MTA_CD1400"; + case SXDC: return "SXDC"; + default:return "Unknown/invalid"; + } +} + + +char *pan_type_s (int pan_type) +{ + switch (pan_type) { + case MOD_RS232DB25: return "MOD_RS232DB25"; + case MOD_RS232RJ45: return "MOD_RS232RJ45"; + case MOD_RS422DB25: return "MOD_RS422DB25"; + case MOD_PARALLEL: return "MOD_PARALLEL"; + case MOD_2_RS232DB25: return "MOD_2_RS232DB25"; + case MOD_2_RS232RJ45: return "MOD_2_RS232RJ45"; + case MOD_2_RS422DB25: return "MOD_2_RS422DB25"; + case MOD_RS232DB25MALE: return "MOD_RS232DB25MALE"; + case MOD_2_PARALLEL: return "MOD_2_PARALLEL"; + case MOD_BLANK: return "empty"; + default:return "invalid"; + } +} + + +int mod_compat_type (int module_type) +{ + return module_type >> 4; +} + + +static void sx_setsignals (struct sx_port *port, int dtr, int rts) +{ + int t; + func_enter2 (); + + t = sx_read_channel_byte (port, hi_op); + if (dtr >= 0) t = dtr? (t | OP_DTR): (t & ~OP_DTR); + if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS); + sx_write_channel_byte (port, hi_op, t); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts); + func_exit (); +} + + + +static int sx_getsignals (struct sx_port *port) +{ + int i_stat,o_stat; + + o_stat = sx_read_channel_byte (port, hi_op); + i_stat = sx_read_channel_byte (port, hi_ip); + + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) %02x/%02x\n", + (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0, + port->c_dcd, sx_get_CD (port), + sx_read_channel_byte (port, hi_ip), + sx_read_channel_byte (port, hi_state)); + + return (((o_stat & OP_DTR)?TIOCM_DTR:0) | + ((o_stat & OP_RTS)?TIOCM_RTS:0) | + ((i_stat & IP_CTS)?TIOCM_CTS:0) | + ((i_stat & IP_DCD)?TIOCM_CAR:0) | + ((i_stat & IP_DSR)?TIOCM_DSR:0) | + ((i_stat & IP_RI)?TIOCM_RNG:0) + ); +} + + +static void sx_set_baud (struct sx_port *port) +{ + int t; + + if (port->board->ta_type == MOD_SXDC) { + switch (port->gs.baud) { + /* Save some typing work... */ +#define e(x) case x:t= BAUD_ ## x ; break + e(50);e(75);e(110);e(150);e(200);e(300);e(600); + e(1200);e(1800);e(2000);e(2400);e(4800);e(7200); + e(9600);e(14400);e(19200);e(28800);e(38400); + e(56000);e(57600);e(64000);e(76800);e(115200); + e(128000);e(150000);e(230400);e(256000);e(460800); + e(921600); + case 134 :t = BAUD_134_5; break; + case 0 :t = -1; + break; + default: + /* Can I return "invalid"? */ + t = BAUD_9600; + printk (KERN_INFO "sx: unsupported baud rate: %d.\n", port->gs.baud); + break; + } +#undef e + if (t > 0) { + /* The baud rate is not set to 0, so we're enabeling DTR... -- REW */ + sx_setsignals (port, 1, -1); + /* XXX This is not TA & MTA compatible */ + sx_write_channel_byte (port, hi_csr, 0xff); + + sx_write_channel_byte (port, hi_txbaud, t); + sx_write_channel_byte (port, hi_rxbaud, t); + } else { + sx_setsignals (port, 0, -1); + } + } else { + switch (port->gs.baud) { +#define e(x) case x:t= CSR_ ## x ; break + e(75);e(150);e(300);e(600);e(1200);e(2400);e(4800); + e(1800);e(9600); + e(19200);e(57600);e(38400); + /* TA supports 110, but not 115200, MTA supports 115200, but not 110 */ + case 110: + if (port->board->ta_type == MOD_TA) { + t = CSR_110; + break; + } else { + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } + case 115200: + if (port->board->ta_type == MOD_TA) { + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } else { + t = CSR_110; + break; + } + case 0 :t = -1; + break; + default: + t = CSR_9600; + printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud); + break; + } +#undef e + if (t >= 0) { + sx_setsignals (port, 1, -1); + sx_write_channel_byte (port, hi_csr, t * 0x11); + } else { + sx_setsignals (port, 0, -1); + } + } +} + + +/* Simon Allen's version of this routine was 225 lines long. 85 is a lot + better. -- REW */ + +static void sx_set_real_termios (void *ptr) +{ + struct sx_port *port = ptr; + + func_enter2(); + + /* What is this doing here? -- REW + Ha! figured it out. It is to allow you to get DTR active again + if you've dropped it with stty 0. Moved to set_baud, where it + belongs (next to the drop dtr if baud == 0) -- REW */ + /* sx_setsignals (port, 1, -1); */ + + sx_set_baud (port); + +#define CFLAG port->gs.tty->termios->c_cflag + sx_write_channel_byte (port, hi_mr1, + (C_PARENB (port->gs.tty)? MR1_WITH:MR1_NONE) | + (C_PARODD (port->gs.tty)? MR1_ODD:MR1_EVEN) | + (C_CRTSCTS(port->gs.tty)? MR1_RTS_RXFLOW:0) | + (((CFLAG & CSIZE)==CS8) ? MR1_8_BITS:0) | + (((CFLAG & CSIZE)==CS7) ? MR1_7_BITS:0) | + (((CFLAG & CSIZE)==CS6) ? MR1_6_BITS:0) | + (((CFLAG & CSIZE)==CS5) ? MR1_5_BITS:0) ); + + sx_write_channel_byte (port, hi_mr2, + (C_CRTSCTS(port->gs.tty)?MR2_CTS_TXFLOW:0) | + (C_CSTOPB (port->gs.tty)?MR2_2_STOP:MR2_1_STOP)); + + switch (CFLAG & CSIZE) { + case CS8:sx_write_channel_byte (port, hi_mask, 0xff);break; + case CS7:sx_write_channel_byte (port, hi_mask, 0x7f);break; + case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break; + case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break; + default: + printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE); + break; + } + + sx_write_channel_byte (port, hi_prtcl, + (I_IXON (port->gs.tty)?SP_TXEN:0) | + (I_IXOFF (port->gs.tty)?SP_RXEN:0) | + (I_IXANY (port->gs.tty)?SP_TANY:0) | + SP_DCEN); + + sx_write_channel_byte (port, hi_break, + I_OTHER(port->gs.tty) ? 0: + (I_IGNBRK(port->gs.tty)?BR_IGN:0 | + I_BRKINT(port->gs.tty)?BR_INT:0)); + + sx_write_channel_byte (port, hi_txon, START_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_rxon, START_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_txoff, STOP_CHAR (port->gs.tty)); + sx_write_channel_byte (port, hi_rxoff, STOP_CHAR (port->gs.tty)); + + if (sx_read_channel_byte (port, hi_hstat) == HS_IDLE_OPEN) { + if (sx_send_command (port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) { + printk (KERN_WARNING "sx: Sent reconfigure command, but card didn't react.\n"); + } + } else { + sx_dprintk (SX_DEBUG_TERMIOS, + "sx: Not sending reconfigure: port isn't open (%02x).\n", + sx_read_channel_byte (port, hi_hstat)); + } + + + /* Tell line discipline whether we will do input cooking */ + if(I_OTHER(port->gs.tty)) { + clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + } else { + set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + } + sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ", + port->gs.tty->termios->c_iflag, + I_OTHER(port->gs.tty)); + + +/* Tell line discipline whether we will do output cooking. + * If OPOST is set and no other output flags are set then we can do output + * processing. Even if only *one* other flag in the O_OTHER group is set + * we do cooking in software. + */ + if(O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) { + set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + } else { + clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + } + sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n", + port->gs.tty->termios->c_oflag, + O_OTHER(port->gs.tty)); + /* port->c_dcd = sx_get_CD (port); */ + func_exit (); +} + + + +/* ********************************************************************** * + * the interrupt related routines * + * ********************************************************************** */ + +/* Note: + Other drivers use the macro "MIN" to calculate how much to copy. + This has the disadvantage that it will evaluate parts twice. That's + expensive when it's IO (and the compiler cannot optimize those away!). + Moreover, I'm not sure that you're race-free. + + I assign a value, and then only allow the value to decrease. This + is always safe. This makes the code a few lines longer, and you + know I'm dead against that, but I think it is required in this + case. */ + + +void sx_transmit_chars (struct sx_port *port) +{ + int c; + int tx_ip; + int txroom; + + func_enter2 (); + sx_dprintk (SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n", + port, port->gs.xmit_cnt); + + if (test_and_set_bit (SX_PORT_TRANSMIT_LOCK, &port->locks)) { + return; + } + + while (1) { + c = port->gs.xmit_cnt; + + sx_dprintk (SX_DEBUG_TRANSMIT, "Copying %d ", c); + tx_ip = sx_read_channel_byte (port, hi_txipos); + + /* Took me 5 minutes to deduce this formula. + Luckily it is literally in the manual in section 6.5.4.3.5 */ + txroom = (sx_read_channel_byte (port, hi_txopos) - tx_ip - 1) & 0xff; + + /* Don't copy more bytes than there is room for in the buffer */ + if (c > txroom) + c = txroom; + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom ); + + /* Don't copy past the end of the hardware transmit buffer */ + if (c > 0x100 - tx_ip) + c = 0x100 - tx_ip; + + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100-tx_ip ); + + /* Don't copy pas the end of the source buffer */ + if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail) + c = SERIAL_XMIT_SIZE - port->gs.xmit_tail; + + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) \n", + c, SERIAL_XMIT_SIZE- port->gs.xmit_tail); + + /* If for one reason or another, we can't copy more data, we're done! */ + if (c == 0) break; + + + memcpy_toio (port->board->base + CHAN_OFFSET(port,hi_txbuf) + tx_ip, + port->gs.xmit_buf + port->gs.xmit_tail, c); + + /* Update the pointer in the card */ + sx_write_channel_byte (port, hi_txipos, (tx_ip+c) & 0xff); + + /* Update the kernel buffer end */ + port->gs.xmit_tail = (port->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1); + + /* This one last. (this is essential) + It would allow others to start putting more data into the buffer! */ + port->gs.xmit_cnt -= c; + } + + if (port->gs.xmit_cnt == 0) { + sx_disable_tx_interrupts (port); + } + + if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { + if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + port->gs.tty->ldisc.write_wakeup) + (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", + port->gs.wakeup_chars); + wake_up_interruptible(&port->gs.tty->write_wait); + } + + clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks); + func_exit (); +} + + +/* Note the symmetry between receiving chars and transmitting them! + Note: The kernel should have implemented both a receive buffer and + a transmit buffer. */ + +/* Inlined: Called only once. Remove the inline when you add another call */ +inline void sx_receive_chars (struct sx_port *port) +{ + int c; + int rx_op; + struct tty_struct *tty; + int copied=0; + + /* func_enter2 (); */ + tty = port->gs.tty; + while (1) { + rx_op = sx_read_channel_byte (port, hi_rxopos); + c = (sx_read_channel_byte (port, hi_rxipos) - rx_op) & 0xff; + + sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c); + + /* Don't copy more bytes than there is room for in the buffer */ + if (tty->flip.count + c > TTY_FLIPBUF_SIZE) + c = TTY_FLIPBUF_SIZE - tty->flip.count; + + sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); + + /* Don't copy past the end of the hardware receive buffer */ + if (rx_op + c > 0x100) c = 0x100 - rx_op; + + sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c); + + /* If for one reason or another, we can't copy more data, we're done! */ + if (c == 0) break; + + sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c, + read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op), + CHAN_OFFSET(port, hi_rxbuf)); + memcpy_fromio (tty->flip.char_buf_ptr, + port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c); + memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c); + + /* Update the kernel buffer end */ + tty->flip.count += c; + tty->flip.char_buf_ptr += c; + tty->flip.flag_buf_ptr += c; + + /* This one last. ( Not essential.) + It allows the card to start putting more data into the buffer! + Update the pointer in the card */ + sx_write_channel_byte (port, hi_rxopos, (rx_op + c) & 0xff); + + copied += c; + } + if (copied) { + struct timeval tv; + + do_gettimeofday (&tv); + sx_dprintk (SX_DEBUG_RECEIVE, + "pushing flipq port %d (%3d chars): %d.%06d (%d/%d)\n", + port->line, copied, + (int) (tv.tv_sec % 60), (int)tv.tv_usec, tty->raw, tty->real_raw); + + /* Tell the rest of the system the news. Great news. New characters! */ + tty_flip_buffer_push (tty); + /* tty_schedule_flip (tty); */ + } + + /* func_exit (); */ +} + +/* Inlined: it is called only once. Remove the inline if you add another + call */ +inline void sx_check_modem_signals (struct sx_port *port) +{ + int hi_state; + int c_dcd; + + hi_state = sx_read_channel_byte (port, hi_state); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n", + port->c_dcd, sx_get_CD (port)); + + if (hi_state & ST_BREAK) { + hi_state &= ~ST_BREAK; + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n"); + + sx_write_channel_byte (port, hi_state, hi_state); + if (port->gs.flags & ASYNC_SAK) { + do_SAK (port->gs.tty); + } + } + if (hi_state & ST_DCD) { + hi_state &= ~ST_DCD; + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n"); + sx_write_channel_byte (port, hi_state, hi_state); + c_dcd = sx_get_CD (port); + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd); + if (c_dcd != port->c_dcd) { + port->c_dcd = c_dcd; + if (sx_get_CD (port)) { + /* DCD went UP */ + if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || + ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) && + (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED)) { + /* Are we blocking in open?*/ + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n"); + wake_up_interruptible(&port->gs.open_wait); + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD raised. Ignoring.\n"); + } + } else { + /* DCD went down! */ + if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && + (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n"); + tty_hangup (port->gs.tty); + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. ignoring.\n"); + } + } + } else { + sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us DCD changed, but it didn't.\n"); + } + } +} + + +/* This is what an interrupt routine should look like. + * Small, elegant, clear. + */ + +static void sx_interrupt (int irq, void *ptr, struct pt_regs *regs) +{ + struct sx_board *board = ptr; + struct sx_port *port; + int i; + + /* func_enter (); */ + sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq); + + /* AAargh! The order in which to do these things is essential and + not trivial. + + - Rate limit goes before "recursive". Otherwise a series of + recursive calls will hang the machine in the interrupt routine. + + - hardware twiddling goes before "recursive". Otherwise when we + poll the card, and a recursive interrupt happens, we wont + ack the card, so it might keep on interrupting us. (especially + level sensitive interrupt systems like PCI). + + - Rate limit goes before hardware twiddling. Otherwise we won't + catch a card that has gone bonkers. + + - The "initialized" test goes after the hardware twiddling. Otherwise + the card will stick us in the interrupt routine again. + + - The initialized test goes before recursive. + */ + + + +#ifdef IRQ_RATE_LIMIT + /* Aaargh! I'm ashamed. This costs more lines-of-code than the + actual interrupt routine!. (Well, used to when I wrote that comment) */ + { + static int lastjif; + static int nintr=0; + + if (lastjif == jiffies) { + if (++nintr > IRQ_RATE_LIMIT) { + free_irq (board->irq, board); + printk (KERN_ERR "sx: Too many interrupts. Turning off interrupt %d.\n", + board->irq); + } + } else { + lastjif = jiffies; + nintr = 0; + } + } +#endif + + + if (board->irq == irq) { + /* Tell the card we've noticed the interrupt. */ + + sx_write_board_word (board, cc_int_pending, 0); + if (IS_SX_BOARD (board)) { + write_sx_byte (board, SX_RESET_IRQ, 1); + } else { + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR); + write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET); + } + } + + if (!sx_initialized) return; + if (!(board->flags & SX_BOARD_INITIALIZED)) return; + + if (test_and_set_bit (SX_BOARD_INTR_LOCK, &board->locks)) { + printk (KERN_ERR "Recursive interrupt! (%d)\n", board->irq); + return; + } + + for (i=0;inports;i++) { + port = &board->ports[i]; + if (port->gs.flags & GS_ACTIVE) { + if (sx_read_channel_byte (port, hi_state)) { + sx_dprintk (SX_DEBUG_INTERRUPTS, + "Port %d: modem signal change?... \n", i); + sx_check_modem_signals (port); + } + if (port->gs.xmit_cnt) { + sx_transmit_chars (port); + } + if (!(port->gs.flags & SX_RX_THROTTLE)) { + sx_receive_chars (port); + } + } + } + + clear_bit (SX_BOARD_INTR_LOCK, &board->locks); + + sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq); + /* func_exit (); */ +} + + +static void sx_pollfunc (unsigned long data) +{ + struct sx_board *board = (struct sx_board *) data; + + func_enter (); + + sx_interrupt (0, board, NULL); + + board->timer.expires = jiffies + sx_poll; + add_timer (&board->timer); + func_exit (); +} + + + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the generic_serial driver * + * ********************************************************************** */ + +/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */ +/* Hmm. Ok I figured it out. You don't. */ + +static void sx_disable_tx_interrupts (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + port->gs.flags &= ~GS_TX_INTEN; + + func_exit(); +} + + +static void sx_enable_tx_interrupts (void * ptr) +{ + struct sx_port *port = ptr; + int data_in_buffer; + func_enter2(); + + /* First transmit the characters that we're supposed to */ + sx_transmit_chars (port); + + /* The sx card will never interrupt us if we don't fill the buffer + past 25%. So we keep considering interrupts off if that's the case. */ + data_in_buffer = (sx_read_channel_byte (port, hi_txipos) - + sx_read_channel_byte (port, hi_txopos)) & 0xff; + + /* XXX Must be "HIGH_WATER" for SI card according to doc. */ + if (data_in_buffer < LOW_WATER) + port->gs.flags &= ~GS_TX_INTEN; + + func_exit(); +} + + +static void sx_disable_rx_interrupts (void * ptr) +{ + /* struct sx_port *port = ptr; */ + func_enter(); + + func_exit(); +} + +static void sx_enable_rx_interrupts (void * ptr) +{ + /* struct sx_port *port = ptr; */ + func_enter(); + + func_exit(); +} + + +/* Jeez. Isn't this simple? */ +static int sx_get_CD (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + func_exit(); + return ((sx_read_channel_byte (port, hi_ip) & IP_DCD) != 0); +} + + +/* Jeez. Isn't this simple? */ +static int sx_chars_in_buffer (void * ptr) +{ + struct sx_port *port = ptr; + func_enter2(); + + func_exit(); + return ((sx_read_channel_byte (port, hi_txipos) - + sx_read_channel_byte (port, hi_txopos)) & 0xff); +} + + +static void sx_shutdown_port (void * ptr) +{ + struct sx_port *port = ptr; + + func_enter(); + + port->gs.flags &= ~ GS_ACTIVE; + if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { + sx_setsignals (port, 0, 0); + } + + func_exit(); +} + + + + + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the rest of the system * + * ********************************************************************** */ + + +static int sx_fw_open(struct inode *inode, struct file *filp) +{ + func_enter (); + MOD_INC_USE_COUNT; + func_exit (); + return 0; +} + + +static INT sx_fw_release(struct inode *inode, struct file *filp) +{ + func_enter (); + MOD_DEC_USE_COUNT; + func_exit (); + return NO_ERROR; +} + + +static int sx_open (struct tty_struct * tty, struct file * filp) +{ + struct sx_port *port; + int retval, line; + + func_enter(); + + if (!sx_initialized) { + return -EIO; + } + + line = MINOR(tty->device); + sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n", + current->pid, line, tty, current->tty, sx_nports); + + if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports)) + return -ENODEV; + + port = & sx_ports[line]; + port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a + 1 -> 0 transition. */ + + + sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd); + + tty->driver_data = port; + port->gs.tty = tty; + port->gs.count++; + + sx_dprintk (SX_DEBUG_OPEN, "starting port\n"); + + /* + * Start up serial port + */ + retval = gs_init_port(&port->gs); + sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n"); + if (retval) { + port->gs.count--; + return retval; + } + + port->gs.flags |= GS_ACTIVE; + sx_setsignals (port, 1,1); + + sx_dprintk (SX_DEBUG_OPEN, "before inc_use_count (count=%d.\n", + port->gs.count); + if (port->gs.count == 1) { + MOD_INC_USE_COUNT; + } + sx_dprintk (SX_DEBUG_OPEN, "after inc_use_count\n"); + +#if 0 + if (sx_debug & SX_DEBUG_OPEN) + my_hd ((unsigned char *)port, sizeof (*port)); +#else + if (sx_debug & SX_DEBUG_OPEN) + my_hd ((unsigned char *)port->board->base + port->ch_base, + sizeof (*port)); +#endif + + if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) { + printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n"); + MOD_DEC_USE_COUNT; + port->gs.count--; + return -EIO; + } + + retval = block_til_ready(port, filp); + sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", + retval, port->gs.count); + + if (retval) { + MOD_DEC_USE_COUNT; + port->gs.count--; + return retval; + } + /* tty->low_latency = 1; */ + + if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = port->gs.normal_termios; + else + *tty->termios = port->gs.callout_termios; + sx_set_real_termios (port); + } + + port->gs.session = current->session; + port->gs.pgrp = current->pgrp; + port->c_dcd = sx_get_CD (port); + sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd); + func_exit(); + return 0; + +} + + +/* I haven't the foggiest why the decrement use count has to happen + here. The whole linux serial drivers stuff needs to be redesigned. + My guess is that this is a hack to minimize the impact of a bug + elsewhere. Thinking about it some more. (try it sometime) Try + running minicom on a serial port that is driven by a modularized + driver. Have the modem hangup. Then remove the driver module. Then + exit minicom. I expect an "oops". -- REW */ +static void sx_hungup (void *ptr) +{ + func_enter (); + MOD_DEC_USE_COUNT; + func_exit (); +} + + +static void sx_close (void *ptr) +{ + struct sx_port *port = ptr; + /* Give the port 5 seconds to close down. */ + int to = 5 * HZ; + + func_enter (); + sx_send_command (port, HS_CLOSE, 0, 0); + + while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout (1); + if (signal_pending (current)) + break; + } + current->state = TASK_RUNNING; + if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) { + if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) { + printk (KERN_ERR + "sx: sent the force_close command, but card didn't react\n"); + } else + sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n"); + } + + sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n", + 5 * HZ - to - 1, port->gs.count); + + MOD_DEC_USE_COUNT; + func_exit (); +} + + + +/* This is relatively thorough. But then again it is only 20 lines. */ +#define MARCHUP for (i=min;i=min;i--) +#define W0 write_sx_byte (board, i, 0x55) +#define W1 write_sx_byte (board, i, 0xaa) +#define R0 if (read_sx_byte (board, i) != 0x55) return 1 +#define R1 if (read_sx_byte (board, i) != 0xaa) return 1 + +/* This memtest takes a human-noticable time. You normally only do it + once a boot, so I guess that it is worth it. */ +int do_memtest (struct sx_board *board, int min, int max) +{ + int i; + + /* This is a marchb. Theoretically, marchb catches much more than + simpler tests. In practise, the longer test just catches more + intermittent errors. -- REW + (For the theory behind memory testing see: + Testing Semiconductor Memories by A.J. van de Goor.) */ + MARCHUP {W0;} + MARCHUP {R0;W1;R1;W0;R0;W1;} + MARCHUP {R1;W0;W1;} + MARCHDOWN {R1;W0;W1;W0;} + MARCHDOWN {R0;W1;W0;} + + return 0; +} + + +#undef MARCHUP +#undef MARCHDOWN +#undef W0 +#undef W1 +#undef R0 +#undef R1 + +#define MARCHUP for (i=min;i=min;i-=2) +#define W0 write_sx_word (board, i, 0x55aa) +#define W1 write_sx_word (board, i, 0xaa55) +#define R0 if (read_sx_word (board, i) != 0x55aa) return 1 +#define R1 if (read_sx_word (board, i) != 0xaa55) return 1 + +/* This memtest takes a human-noticable time. You normally only do it + once a boot, so I guess that it is worth it. */ +int do_memtest_w (struct sx_board *board, int min, int max) +{ + int i; + + MARCHUP {W0;} + MARCHUP {R0;W1;R1;W0;R0;W1;} + MARCHUP {R1;W0;W1;} + MARCHDOWN {R1;W0;W1;W0;} + MARCHDOWN {R0;W1;W0;} + + return 0; +} + + +static int sx_fw_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + int *descr = (int *)arg, i; + static struct sx_board *board = NULL; + int nbytes, offset, data; + char *tmp; + + func_enter(); + +#if 0 + /* Removed superuser check: Sysops can use the permissions on the device + file to restrict access. Recommendation: Root only. (root.root 600) */ + if (!suser ()) { + return -EPERM; + } +#endif + + sx_dprintk (SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg); + + if (!board) board = &boards[0]; + if (board->flags & SX_BOARD_PRESENT) { + sx_dprintk (SX_DEBUG_FIRMWARE, "Board present! (%x)\n", + board->flags); + } else { + sx_dprintk (SX_DEBUG_FIRMWARE, "Board not present! (%x) all:", + board->flags); + for (i=0;i< SX_NBOARDS;i++) + sx_dprintk (SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags); + sx_dprintk (SX_DEBUG_FIRMWARE, "\n"); + return -EIO; + } + + switch (cmd) { + case SXIO_SET_BOARD: + sx_dprintk (SX_DEBUG_FIRMWARE, "set board to %ld\n", arg); + if (arg > SX_NBOARDS) return -EIO; + sx_dprintk (SX_DEBUG_FIRMWARE, "not out of range\n"); + if (!(boards[arg].flags & SX_BOARD_PRESENT)) return -EIO; + sx_dprintk (SX_DEBUG_FIRMWARE, ".. and present!\n"); + board = &boards[arg]; + break; + case SXIO_GET_TYPE: + rc = IS_SX_BOARD (board)? SX_TYPE_SX:SX_TYPE_SI; + sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc); + break; + case SXIO_DO_RAMTEST: + if (sx_initialized) /* Already initialized: better not ramtest the board. */ + return -EPERM; + if (IS_SX_BOARD (board)) { + rc = do_memtest (board, 0, 0x7000); + if (!rc) rc = do_memtest (board, 0, 0x7000); + /*if (!rc) rc = do_memtest_w (board, 0, 0x7000);*/ + } else { + rc = do_memtest (board, 0, 0x7ff8); + /* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */ + } + sx_dprintk (SX_DEBUG_FIRMWARE, "returning memtest result= %d\n", rc); + break; + case SXIO_DOWNLOAD: + if (sx_initialized) /* Already initialized */ + return -EEXIST; + if (!sx_reset (board)) + return -EIO; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + tmp = kmalloc (SX_CHUNK_SIZE, GFP_USER); + if (!tmp) return -ENOMEM; + Get_user (nbytes, descr++); + Get_user (offset, descr++); + Get_user (data, descr++); + while (nbytes && data) { + for (i=0;inbytes)?nbytes-i:SX_CHUNK_SIZE); + memcpy_toio ((char *) (board->base + offset + i), tmp, + (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE); + } + + Get_user (nbytes, descr++); + Get_user (offset, descr++); + Get_user (data, descr++); + } + kfree (tmp); + sx_nports += sx_init_board (board); + rc = sx_nports; + break; + case SXIO_INIT: + if (sx_initialized) /* Already initialized */ + return -EEXIST; + /* This is not allowed until all boards are initialized... */ + for (i=0;i= 0) + sx_initialized++; + break; + case SXIO_SETDEBUG: + sx_debug = arg; + break; + case SXIO_GETDEBUG: + rc = sx_debug; + break; + case SXIO_SETGSDEBUG: + gs_debug = arg; + break; + case SXIO_GETGSDEBUG: + rc = gs_debug; + break; + default: + printk (KERN_WARNING "Unknown ioctl on firmware device (%x).\n", cmd); + break; + } + func_exit (); + return rc; +} + + +static int sx_ioctl (struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + int rc; + struct sx_port *port = tty->driver_data; + int ival; + + /* func_enter2(); */ + + rc = 0; + switch (cmd) { + case TIOCGSOFTCAR: + rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + (unsigned int *) arg); + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + Get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + gs_getserial(&port->gs, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_setserial(&port->gs, (struct serial_struct *) arg); + break; + case TIOCMGET: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) == 0) { + ival = sx_getsignals(port); + put_user(ival, (unsigned int *) arg); + } + break; + case TIOCMBIS: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((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) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((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) { + Get_user(ival, (unsigned int *) arg); + sx_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0), + ((ival & TIOCM_RTS) ? 1 : 0)); + } + break; + + default: + rc = -ENOIOCTLCMD; + break; + } + + /* func_exit(); */ + return rc; +} + + +/* The throttle/unthrottle scheme for the Specialix card is different + * from other drivers and deserves some explanation. + * The Specialix hardware takes care of XON/XOFF + * and CTS/RTS flow control itself. This means that all we have to + * do when signalled by the upper tty layer to throttle/unthrottle is + * to make a note of it here. When we come to read characters from the + * rx buffers on the card (sx_receive_chars()) we look to see if the + * upper layer can accept more (as noted here in sx_rx_throt[]). + * If it can't we simply don't remove chars from the cards buffer. + * When the tty layer can accept chars, we again note that here and when + * sx_receive_chars() is called it will remove them from the cards buffer. + * The card will notice that a ports buffer has drained below some low + * water mark and will unflow control the line itself, using whatever + * flow control scheme is in use for that port. -- Simon Allen + */ + +static void sx_throttle (struct tty_struct * tty) +{ + struct sx_port *port = (struct sx_port *)tty->driver_data; + + func_enter2(); + /* If the port is using any type of input flow + * control then throttle the port. + */ + if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) { + port->gs.flags |= SX_RX_THROTTLE; + } + func_exit(); +} + + +static void sx_unthrottle (struct tty_struct * tty) +{ + struct sx_port *port = (struct sx_port *)tty->driver_data; + + func_enter2(); + /* Always unthrottle even if flow control is not enabled on + * this port in case we disabled flow control while the port + * was throttled + */ + port->gs.flags &= ~SX_RX_THROTTLE; + func_exit(); + return; +} + + +/* ********************************************************************** * + * Here are the initialization routines. * + * ********************************************************************** */ + + + + +static int sx_init_board (struct sx_board *board) +{ + int addr; + int chans; + int type; + + func_enter(); + + /* This is preceded by downloading the download code. */ + + board->flags |= SX_BOARD_INITIALIZED; + + /* This resets the processor again, to make sure it didn't do any + foolish things while we were downloading the image */ + if (!sx_reset (board)) + return 0; + + sx_start_board (board); + + if (!sx_busy_wait_neq (board, 0, 0xff, 0)) { + printk (KERN_ERR "sx: Ooops. Board won't initialize.\n"); + return 0; + } + + /* Ok. So now the processor on the card is running. It gathered + some info for us... */ + sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n"); + if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base), 0x10); + sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n"); + if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base + 0x80), 0x30); + + sx_dprintk (SX_DEBUG_INIT, + "init_status: %x, %dk memory, firmware V%x.%02x,\n", + read_sx_byte (board, 0), read_sx_byte(board, 1), + read_sx_byte (board, 5), read_sx_byte(board, 4)); + + if (read_sx_byte (board, 0) == 0xff) { + printk (KERN_INFO "sx: No modules found. Sorry.\n"); + board->nports = 0; + return 0; + } + + chans = 0; + + if (IS_SX_BOARD(board)) { + sx_write_board_word (board, cc_int_count, sx_maxints); + } else { + if (sx_maxints) + sx_write_board_word (board, cc_int_count, SI_PROCESSOR_CLOCK/8/sx_maxints); + } + + /* grab the first module type... */ + /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */ + board->ta_type = mod_compat_type (sx_read_module_byte (board, 0x80, mc_chip)); + + /* XXX byteorder */ + for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) { + type = sx_read_module_byte (board, addr, mc_chip); + sx_dprintk (SX_DEBUG_INIT, "Module at %x: %d channels\n", + addr, read_sx_byte (board, addr + 2)); + + chans += sx_read_module_byte (board, addr, mc_type); + + sx_dprintk (SX_DEBUG_INIT, "module is an %s, which has %s/%s panels\n", + mod_type_s (type), + pan_type_s (sx_read_module_byte (board, addr, mc_mods) & 0xf), + pan_type_s (sx_read_module_byte (board, addr, mc_mods) >> 4)); + + sx_dprintk (SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC version: %x\n", + sx_read_module_byte (board, addr, mc_rev1), + sx_read_module_byte (board, addr, mc_rev2), + sx_read_module_byte (board, addr, mc_mtaasic_rev)); + + /* The following combinations are illegal: It should theoretically + work, but timing problems make the bus HANG. */ + + if (mod_compat_type (type) != board->ta_type) { + printk (KERN_ERR "sx: This is an invalid configuration.\n" + "Don't mix TA/MTA/SXDC on the same hostadapter.\n"); + chans=0; + break; + } + if (IS_SI_BOARD(board) && (mod_compat_type(type) == 4)) { + printk (KERN_ERR "sx: This is an invalid configuration.\n" + "Don't use SXDCs on an SI/XIO adapter.\n"); + chans=0; + break; + } +#if 0 /* Problem fixed: firmware 3.05 */ + if (IS_SX_BOARD(board) && (type == TA8)) { + /* There are some issues with the firmware and the DCD/RTS + lines. It might work if you tie them together or something. + It might also work if you get a newer sx_firmware. Therefore + this is just a warning. */ + printk (KERN_WARNING "sx: The SX host doesn't work too well " + "with the TA8 adapters.\nSpecialix is working on it.\n"); + } +#endif + } + + if (chans) { + /* board->flags |= SX_BOARD_PRESENT; */ + if(board->irq > 0) { + /* fixed irq, probably PCI */ + if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */ + if(request_irq(board->irq, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) { + printk(KERN_ERR "sx: Cannot allocate irq %d.\n", board->irq); + board->irq = 0; + } + } else + board->irq = 0; + } else if(board->irq < 0 && sx_irqmask) { + /* auto-allocate irq */ + int irqnr; + int irqmask = sx_irqmask & (IS_SX_BOARD(board) ? SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK); + for(irqnr = 15; irqnr > 0; irqnr--) + if(irqmask & (1 << irqnr)) + if(! request_irq(irqnr, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) + break; + if(! irqnr) + printk(KERN_ERR "sx: Cannot allocate IRQ.\n"); + board->irq = irqnr; + } else + board->irq = 0; + + if (board->irq) { + /* Found a valid interrupt, start up interrupts! */ + sx_dprintk (SX_DEBUG_INIT, "Using irq %d.\n", board->irq); + sx_start_interrupts (board); + board->poll = sx_slowpoll; + board->flags |= SX_IRQ_ALLOCATED; + } else { + /* no irq: setup board for polled operation */ + board->poll = sx_poll; + sx_dprintk (SX_DEBUG_INIT, "Using poll-interval %d.\n", board->poll); + } + + /* The timer should be initialized anyway: That way we can safely + del_timer it when the module is unloaded. */ + init_timer (&board->timer); + + if (board->poll) { + board->timer.data = (unsigned long) board; + board->timer.function = sx_pollfunc; + board->timer.expires = jiffies + board->poll; + add_timer (&board->timer); + } + } else { + board->irq = 0; + } + + board->nports = chans; + sx_dprintk (SX_DEBUG_INIT, "returning %d ports.", board->nports); + + func_exit(); + return chans; +} + + +void printheader(void) +{ + static int header_printed = 0; + + if (!header_printed) { + printk (KERN_INFO "Specialix SX driver " + "(C) 1998/1999 R.E.Wolff@BitWizard.nl \n"); + printk (KERN_INFO "sx: version %s\n", RCS_ID); + header_printed = 1; + } +} + + +int probe_sx (struct sx_board *board) +{ + struct vpd_prom vpdp; + char *p; + int i; + + func_enter(); + sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %x.\n", + board->base + SX_VPD_ROM); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)(board->base + SX_VPD_ROM), 0x40); + + p = (char *) &vpdp; + for (i=0;i< sizeof (struct vpd_prom);i++) + *p++ = read_sx_byte (board, SX_VPD_ROM + i*2); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)&vpdp, 0x20); + + sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n"); + + if (strncmp (vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) { + sx_dprintk (SX_DEBUG_PROBE, "Got non-SX identifier: '%s'\n", + vpdp.identifier); + return 0; + } + + printheader (); + + printk (KERN_DEBUG "sx: Found an SX board at %x\n", board->hw_base); + printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ", + vpdp.hwrev, vpdp.hwass, vpdp.uniqid); + printk ( "Manufactured: %d/%d\n", + 1970 + vpdp.myear, vpdp.mweek); + + + if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_PCI_UNIQUEID1) && + (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) { + /* This might be a bit harsh. This was the primary reason the + SX/ISA card didn't work at first... */ + printk (KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA card. Sorry: giving up.\n"); + return (0); + } + + if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) { + if (board->base & 0x8000) { + printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %x.\n", board->base); + printk (KERN_WARNING "sx: Read sx.txt for more info.\n"); + } + } + + + board->nports = -1; + + /* This resets the processor, and keeps it off the bus. */ + if (!sx_reset (board)) + return 0; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + board->flags |= SX_BOARD_PRESENT; + + func_exit(); + return 1; +} + + + +/* Specialix probes for this card at 32k increments from 640k to 16M. + I consider machines with less than 16M unlikely nowadays, so I'm + not probing above 1Mb. Also, 0xa0000, 0xb0000, are taken by the VGA + card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves + 0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */ + +int probe_si (struct sx_board *board) +{ + int i; + + func_enter(); + sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %x.\n", + board->base + SI2_ISA_ID_BASE); + + if (sx_debug & SX_DEBUG_PROBE) + my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8); + + for (i=0;i<8;i++) { + if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) { + return 0; + } + } + + printheader (); + + printk (KERN_DEBUG "sx: Found an SI board at %x\n", board->hw_base); + /* Compared to the SX boards, it is a complete guess as to what + this card is up to... */ + + board->nports = -1; + + /* This resets the processor, and keeps it off the bus. */ + if (!sx_reset (board)) + return 0; + sx_dprintk (SX_DEBUG_INIT, "reset the board...\n"); + + board->flags |= SX_BOARD_PRESENT; + + func_exit(); + return 1; +} + + +static int sx_init_drivers(void) +{ + int error; + + func_enter(); + + memset(&sx_driver, 0, sizeof(sx_driver)); + sx_driver.magic = TTY_DRIVER_MAGIC; + sx_driver.driver_name = "specialix_sx"; + sx_driver.name = "ttyX"; + sx_driver.major = SX_NORMAL_MAJOR; + sx_driver.num = sx_nports; + sx_driver.type = TTY_DRIVER_TYPE_SERIAL; + sx_driver.subtype = SX_TYPE_NORMAL; + sx_driver.init_termios = tty_std_termios; + sx_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + sx_driver.flags = TTY_DRIVER_REAL_RAW; + sx_driver.refcount = &sx_refcount; + sx_driver.table = sx_table; + sx_driver.termios = sx_termios; + sx_driver.termios_locked = sx_termios_locked; + + sx_driver.open = sx_open; + sx_driver.close = gs_close; + sx_driver.write = gs_write; + sx_driver.put_char = gs_put_char; + sx_driver.flush_chars = gs_flush_chars; + sx_driver.write_room = gs_write_room; + sx_driver.chars_in_buffer = gs_chars_in_buffer; + sx_driver.flush_buffer = gs_flush_buffer; + sx_driver.ioctl = sx_ioctl; + sx_driver.throttle = sx_throttle; + sx_driver.unthrottle = sx_unthrottle; + sx_driver.set_termios = gs_set_termios; + sx_driver.stop = gs_stop; + sx_driver.start = gs_start; + sx_driver.hangup = gs_hangup; + + sx_callout_driver = sx_driver; + sx_callout_driver.name = "cux"; + sx_callout_driver.major = SX_CALLOUT_MAJOR; + sx_callout_driver.subtype = SX_TYPE_CALLOUT; + + if ((error = tty_register_driver(&sx_driver))) { + printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&sx_callout_driver))) { + tty_unregister_driver(&sx_driver); + printk(KERN_ERR "sx: Couldn't register sx callout driver, error = %d\n", + error); + return 1; + } + + func_exit(); + return 0; +} + + +void * ckmalloc (int size) +{ + void *p; + + p = kmalloc(size, GFP_KERNEL); + if (p) + memset(p, 0, size); + return p; +} + + +static int sx_init_portstructs (int nboards, int nports) +{ + struct sx_board *board; + struct sx_port *port; + int i, j; + int addr, chans; + int portno; + + func_enter(); + + /* Many drivers statically allocate the maximum number of ports + There is no reason not to allocate them dynamically. Is there? -- REW */ + sx_ports = ckmalloc(nports * sizeof (struct sx_port)); + if (!sx_ports) + return -ENOMEM; + + sx_termios = ckmalloc(nports * sizeof (struct termios *)); + if (!sx_termios) { + kfree (sx_ports); + return -ENOMEM; + } + + sx_termios_locked = ckmalloc(nports * sizeof (struct termios *)); + if (!sx_termios_locked) { + kfree (sx_ports); + kfree (sx_termios); + return -ENOMEM; + } + + /* Adjust the values in the "driver" */ + sx_driver.termios = sx_termios; + sx_driver.termios_locked = sx_termios_locked; + + port = sx_ports; + for (i = 0; i < nboards; i++) { + board = &boards[i]; + board->ports = port; + for (j=0; j < boards[i].nports;j++) { + sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j); + port->gs.callout_termios = tty_std_termios; + port->gs.normal_termios = tty_std_termios; + port->gs.magic = SX_MAGIC; + port->gs.close_delay = HZ/2; + port->gs.closing_wait = 30 * HZ; + port->board = board; + port->gs.rd = &sx_real_driver; +#ifdef NEW_WRITE_LOCKING + port->gs.port_write_sem = MUTEX; +#endif + port++; + } + } + + port = sx_ports; + portno = 0; + for (i = 0; i < nboards; i++) { + board = &boards[i]; + board->port_base = portno; + /* Possibly the configuration was rejected. */ + sx_dprintk (SX_DEBUG_PROBE, "Board has %d channels\n", board->nports); + if (board->nports <= 0) continue; + /* XXX byteorder ?? */ + for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) { + chans = sx_read_module_byte (board, addr, mc_type); + sx_dprintk (SX_DEBUG_PROBE, "Module at %x: %d channels\n", addr, chans); + sx_dprintk (SX_DEBUG_PROBE, "Port at"); + for (j=0;jch_base = sx_read_module_word (board, addr+j*2, mc_chan_pointer); + else + port->ch_base = addr + 0x100 + 0x300*j; + + sx_dprintk (SX_DEBUG_PROBE, " %x", port->ch_base); + port->line = portno++; + port++; + } + sx_dprintk (SX_DEBUG_PROBE, "\n"); + } + /* This has to be done earlier. */ + /* board->flags |= SX_BOARD_INITIALIZED; */ + } + + func_exit(); + return 0; +} + + +static void sx_release_drivers(void) +{ + func_enter(); + tty_unregister_driver(&sx_driver); + tty_unregister_driver(&sx_callout_driver); + func_exit(); +} + +#ifdef TWO_ZERO +#define PDEV unsigned char pci_bus, unsigned pci_fun +#define pdev pci_bus, pci_fun +#else +#define PDEV struct pci_dev *pdev +#endif + + +#ifdef CONFIG_PCI + /******************************************************** + * Setting bit 17 in the CNTRL register of the PLX 9050 * + * chip forces a retry on writes while a read is pending.* + * This is to prevent the card locking up on Intel Xeon * + * multiprocessor systems with the NX chipset. -- NV * + ********************************************************/ + +/* Newer cards are produced with this bit set from the configuration + EEprom. As the bit is read/write for the CPU, we can fix it here, + if we detect that it isn't set correctly. -- REW */ + +void fix_sx_pci (PDEV, struct sx_board *board) +{ + unsigned int hwbase; + unsigned long rebase; + int t; + +#define CNTRL_REG_OFFSET 0x14 + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase); + hwbase &= PCI_BASE_ADDRESS_MEM_MASK; + rebase = (ulong) ioremap(hwbase, 0x80); + t = readb (rebase + CNTRL_REG_OFFSET*4 + 2); + if (t != 0x06) { + printk (KERN_DEBUG "sx: performing cntrl reg fix: %02x -> 06\n", t); + writeb (0x06, rebase + CNTRL_REG_OFFSET*4+2); + } + my_iounmap (hwbase, rebase); + +} +#endif + + +#ifdef MODULE +#define sx_init init_module +#endif + +int sx_init(void) +{ + int i; + int found = 0; + struct sx_board *board; + +#ifdef CONFIG_PCI +#ifndef TWO_ZERO + struct pci_dev *pdev = NULL; +#else + unsigned char pci_bus, pci_fun; + /* in 2.2.x pdev is a pointer defining a PCI device. In 2.0 its the bus/fn */ +#endif + unsigned int tint; + unsigned short tshort; +#endif + + func_enter(); + sx_dprintk (SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n", sx_debug); + if (abs ((long) (&sx_debug) - sx_debug) < 0x10000) { + printk (KERN_WARNING "sx: sx_debug is an address, instead of a value. " + "Assuming -1.\n"); + printk ("(%p)\n", &sx_debug); + sx_debug=-1; + } + +#ifdef CONFIG_PCI + if (pci_present ()) { +#ifndef TWO_ZERO + while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, + pdev))) { +#else + for (i=0;i< SX_NBOARDS;i++) { + if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, i, + &pci_bus, &pci_fun)) break; +#endif + /* Specialix has a whole bunch of cards with + 0x2000 as the device ID. They say its because + the standard requires it. Stupid standard. */ + /* It seems that reading a word doesn't work reliably on 2.0. + Also, reading a non-aligned dword doesn't work. So we read the + whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID) + ourselves */ + /* I don't know why the define doesn't work, constant 0x2c does --REW */ + pci_read_config_dword (pdev, 0x2c, &tint); + tshort = (tint >> 16) & 0xffff; + sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x.\n", tint); + /* sx_dprintk (SX_DEBUG_PROBE, "pdev = %d/%d (%x)\n", pdev, tint); */ + if (tshort != 0x0200) { + sx_dprintk (SX_DEBUG_PROBE, "But it's not an SX card (%d)...\n", + tshort); + continue; + } + board = &boards[found]; + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint); + board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK; + board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN); + board->irq = get_irq (pdev); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SX_PCI_BOARD; + + sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%x(%d).\n", + tint, boards[found].base, board->irq); + + if (probe_sx (board)) { + found++; + fix_sx_pci (pdev, board); + } else + my_iounmap (board->hw_base, board->base); + } + } +#endif + + for (i=0;ihw_base = sx_probe_addrs[i]; + board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SX_ISA_BOARD; + board->irq = sx_irqmask?-1:0; + + if (probe_sx (board)) { + found++; + } else { + my_iounmap (board->hw_base, board->base); + } + } + + for (i=0;ihw_base = si_probe_addrs[i]; + board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN); + board->flags &= ~SX_BOARD_TYPE; + board->flags |= SI_ISA_BOARD; + board->irq = sx_irqmask ?-1:0; + + if (probe_si (board)) { + found++; + } else { + my_iounmap (board->hw_base, board->base); + } + } + + if (found) { + printk (KERN_INFO "sx: total of %d boards detected.\n", found); + + if (misc_register(&sx_fw_device) < 0) { + printk(KERN_ERR "SX: Unable to register firmware loader driver.\n"); + return -EIO; + } + } + + func_exit(); + return found?0:-EIO; +} + + + +void cleanup_module(void) +{ + int i; + struct sx_board *board; + + func_enter(); + for (i = 0; i < SX_NBOARDS; i++) { + board = &boards[i]; + if (board->flags & SX_BOARD_INITIALIZED) { + sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %x\n", board->base); + /* The board should stop messing with us. + (actually I mean the interrupt) */ + sx_reset (board); + if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED)) + free_irq (board->irq, board); + + /* It is safe/allowed to del_timer a non-active timer */ + del_timer (& board->timer); + my_iounmap (board->hw_base, board->base); + } + } + if (misc_deregister(&sx_fw_device) < 0) { + printk (KERN_INFO "sx: couldn't deregister firmware loader device\n"); + } + sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized); + if (sx_initialized) + sx_release_drivers (); + + kfree (sx_ports); + kfree (sx_termios); + kfree (sx_termios_locked); + func_exit(); +} + + +#ifdef DEBUG +void my_hd (unsigned char *addr, int len) +{ + int i, j, ch; + + for (i=0;i 0x7f)?'.':ch)); + } + printk ("\n"); + } +} +#endif + +#ifdef MODULE +#undef func_enter +#undef func_exit + +#include "generic_serial.c" +#endif + + +/* + * Anybody who knows why this doesn't work for me, please tell me -- REW. + * Snatched from scsi.c (fixed one spelling error): + * Overrides for Emacs so that we follow Linus' tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/sx.h linux.pre11.6/drivers/char/sx.h --- linux.pre11.5/drivers/char/sx.h Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/drivers/char/sx.h Sat Aug 7 21:24:07 1999 @@ -0,0 +1,180 @@ + +/* + * sx.h + * + * Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl + * + * SX serial driver. + * -- Supports SI, XIO and SX host cards. + * -- Supports TAs, MTAs and SXDCs. + * + * Version 1.3 -- March, 1999. + * + */ + +#define SX_NBOARDS 4 +#define SX_PORTSPERBOARD 32 +#define SX_NPORTS (SX_NBOARDS * SX_PORTSPERBOARD) + +#ifdef __KERNEL__ + +#define SX_MAGIC 0x12345678 + +struct sx_port { + struct gs_port gs; + /* + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + */ + struct wait_queue *shutdown_wait; + int ch_base; + int c_dcd; + struct sx_board *board; + int line; + int locks; +}; + +struct sx_board { + int magic; + unsigned int base; + unsigned int hw_base; + int port_base; /* Number of the first port */ + struct sx_port *ports; + int nports; + int flags; + int irq; + int poll; + int ta_type; + struct timer_list timer; + int locks; +}; + +struct vpd_prom { + unsigned short id; + char hwrev; + char hwass; + int uniqid; + char myear; + char mweek; + char hw_feature[5]; + char oem_id; + char identifier[16]; +}; + +#ifndef MOD_RS232DB25MALE +#define MOD_RS232DB25MALE 0x0a +#endif + + +#define SX_BOARD_PRESENT 0x00000001 +#define SX_ISA_BOARD 0x00000002 +#define SX_PCI_BOARD 0x00000004 +#define SI_ISA_BOARD 0x00000008 +#define SX_BOARD_INITIALIZED 0x00000010 +#define SX_IRQ_ALLOCATED 0x00000020 + +#define SX_BOARD_TYPE (SX_ISA_BOARD|SX_PCI_BOARD|SI_ISA_BOARD) + +#define IS_SX_BOARD(board) (board->flags & (SX_PCI_BOARD | SX_ISA_BOARD)) +#define IS_SI_BOARD(board) (board->flags & SI_ISA_BOARD) + + +#define SERIAL_TYPE_NORMAL 1 + +/* The SI processor clock is required to calculate the cc_int_count register + value for the SI cards. */ +#define SI_PROCESSOR_CLOCK 25000000 + + +/* port flags */ +/* Make sure these don't clash with gs flags or async flags */ +#define SX_RX_THROTTLE 0x0000001 + + + +#define SX_PORT_TRANSMIT_LOCK 0 +#define SX_BOARD_INTR_LOCK 0 + + + +/* Debug flags. Add these together to get more debug info. */ + +#define SX_DEBUG_OPEN 0x00000001 +#define SX_DEBUG_SETTING 0x00000002 +#define SX_DEBUG_FLOW 0x00000004 +#define SX_DEBUG_MODEMSIGNALS 0x00000008 +#define SX_DEBUG_TERMIOS 0x00000010 +#define SX_DEBUG_TRANSMIT 0x00000020 +#define SX_DEBUG_RECEIVE 0x00000040 +#define SX_DEBUG_INTERRUPTS 0x00000080 +#define SX_DEBUG_PROBE 0x00000100 +#define SX_DEBUG_INIT 0x00000200 +#define SX_DEBUG_CLEANUP 0x00000400 +#define SX_DEBUG_CLOSE 0x00000800 +#define SX_DEBUG_FIRMWARE 0x00001000 +#define SX_DEBUG_MEMTEST 0x00002000 + +#define SX_DEBUG_ALL 0xffffffff + + +#define O_OTHER(tty) \ + ((O_OLCUC(tty)) ||\ + (O_ONLCR(tty)) ||\ + (O_OCRNL(tty)) ||\ + (O_ONOCR(tty)) ||\ + (O_ONLRET(tty)) ||\ + (O_OFILL(tty)) ||\ + (O_OFDEL(tty)) ||\ + (O_NLDLY(tty)) ||\ + (O_CRDLY(tty)) ||\ + (O_TABDLY(tty)) ||\ + (O_BSDLY(tty)) ||\ + (O_VTDLY(tty)) ||\ + (O_FFDLY(tty))) + +/* Same for input. */ +#define I_OTHER(tty) \ + ((I_INLCR(tty)) ||\ + (I_IGNCR(tty)) ||\ + (I_ICRNL(tty)) ||\ + (I_IUCLC(tty)) ||\ + (L_ISIG(tty))) + +#define MOD_TA ( TA>>4) +#define MOD_MTA (MTA_CD1400>>4) +#define MOD_SXDC ( SXDC>>4) + + +/* We copy the download code over to the card in chunks of ... bytes */ +#define SX_CHUNK_SIZE 128 + +#endif /* __KERNEL__ */ + + + +/* Specialix document 6210046-11 page 3 */ +#define SPX(X) (('S'<<24) | ('P' << 16) | (X)) + +/* Specialix-Linux specific IOCTLS. */ +#define SPXL(X) (SPX(('L' << 8) | (X))) + + +#define SXIO_SET_BOARD SPXL(0x01) +#define SXIO_GET_TYPE SPXL(0x02) +#define SXIO_DOWNLOAD SPXL(0x03) +#define SXIO_INIT SPXL(0x04) +#define SXIO_SETDEBUG SPXL(0x05) +#define SXIO_GETDEBUG SPXL(0x06) +#define SXIO_DO_RAMTEST SPXL(0x07) +#define SXIO_SETGSDEBUG SPXL(0x08) +#define SXIO_GETGSDEBUG SPXL(0x09) + + +#ifndef SXCTL_MISC_MINOR +/* Allow others to gather this into "major.h" or something like that */ +#define SXCTL_MISC_MINOR 167 +#endif + +#define SX_TYPE_SX 0x01 +#define SX_TYPE_SI 0x02 + diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/sxboards.h linux.pre11.6/drivers/char/sxboards.h --- linux.pre11.5/drivers/char/sxboards.h Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/drivers/char/sxboards.h Sat Aug 7 21:24:07 1999 @@ -0,0 +1,181 @@ +/************************************************************************/ +/* */ +/* Title : SX/SI/XIO Board Hardware Definitions */ +/* */ +/* Author : N.P.Vassallo */ +/* */ +/* Creation : 16th March 1998 */ +/* */ +/* Version : 3.0.0 */ +/* */ +/* Copyright : (c) Specialix International Ltd. 1998 */ +/* */ +/* Description : Prototypes, structures and definitions */ +/* describing the SX/SI/XIO board hardware */ +/* */ +/************************************************************************/ + +/* History... + +3.0.0 16/03/98 NPV Creation. + +*/ + +#ifndef _sxboards_h /* If SXBOARDS.H not already defined */ +#define _sxboards_h 1 + +/***************************************************************************** +******************************* ****************************** +******************************* Board Types ****************************** +******************************* ****************************** +*****************************************************************************/ + +/* BUS types... */ +#define BUS_ISA 0 +#define BUS_MCA 1 +#define BUS_EISA 2 +#define BUS_PCI 3 + +/* Board phases... */ +#define SI1_Z280 1 +#define SI2_Z280 2 +#define SI3_T225 3 + +/* Board types... */ +#define CARD_TYPE(bus,phase) (bus<<4|phase) +#define CARD_BUS(type) ((type>>4)&0xF) +#define CARD_PHASE(type) (type&0xF) + +#define TYPE_SI2_ISA CARD_TYPE(BUS_ISA,SI2_Z280) +#define TYPE_SI2_EISA CARD_TYPE(BUS_EISA,SI2_Z280) +#define TYPE_SI2_PCI CARD_TYPE(BUS_PCI,SI2_Z280) + +#define TYPE_SX_ISA CARD_TYPE(BUS_ISA,SI3_T225) +#define TYPE_SX_PCI CARD_TYPE(BUS_PCI,SI3_T225) + +/***************************************************************************** +****************************** ****************************** +****************************** Phase 2 Z280 ****************************** +****************************** ****************************** +*****************************************************************************/ + +/* ISA board details... */ +#define SI2_ISA_WINDOW_LEN 0x8000 /* 32 Kbyte shared memory window */ +#define SI2_ISA_MEMORY_LEN 0x7FF8 /* Usable memory */ +#define SI2_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */ +#define SI2_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */ +#define SI2_ISA_ADDR_STEP SI2_ISA_WINDOW_LEN/* ISA board address step */ +#define SI2_ISA_IRQ_MASK 0x9800 /* IRQs 15,12,11 */ + +/* ISA board, register definitions... */ +#define SI2_ISA_ID_BASE 0x7FF8 /* READ: Board ID string */ +#define SI2_ISA_RESET SI2_ISA_ID_BASE /* WRITE: Host Reset */ +#define SI2_ISA_IRQ11 (SI2_ISA_ID_BASE+1) /* WRITE: Set IRQ11 */ +#define SI2_ISA_IRQ12 (SI2_ISA_ID_BASE+2) /* WRITE: Set IRQ12 */ +#define SI2_ISA_IRQ15 (SI2_ISA_ID_BASE+3) /* WRITE: Set IRQ15 */ +#define SI2_ISA_IRQSET (SI2_ISA_ID_BASE+4) /* WRITE: Set Host Interrupt */ +#define SI2_ISA_INTCLEAR (SI2_ISA_ID_BASE+5) /* WRITE: Enable Host Interrupt */ + +#define SI2_ISA_IRQ11_SET 0x10 +#define SI2_ISA_IRQ11_CLEAR 0x00 +#define SI2_ISA_IRQ12_SET 0x10 +#define SI2_ISA_IRQ12_CLEAR 0x00 +#define SI2_ISA_IRQ15_SET 0x10 +#define SI2_ISA_IRQ15_CLEAR 0x00 +#define SI2_ISA_INTCLEAR_SET 0x10 +#define SI2_ISA_INTCLEAR_CLEAR 0x00 +#define SI2_ISA_IRQSET_CLEAR 0x10 +#define SI2_ISA_IRQSET_SET 0x00 +#define SI2_ISA_RESET_SET 0x00 +#define SI2_ISA_RESET_CLEAR 0x10 + +/* PCI board details... */ +#define SI2_PCI_WINDOW_LEN 0x100000 /* 1 Mbyte memory window */ + +/* PCI board register definitions... */ +#define SI2_PCI_SET_IRQ 0x40001 /* Set Host Interrupt */ +#define SI2_PCI_RESET 0xC0001 /* Host Reset */ + +/***************************************************************************** +****************************** ****************************** +****************************** Phase 3 T225 ****************************** +****************************** ****************************** +*****************************************************************************/ + +/* General board details... */ +#define SX_WINDOW_LEN 64*1024 /* 64 Kbyte memory window */ + +/* ISA board details... */ +#define SX_ISA_ADDR_LOW 0x0A0000 /* Lowest address = 640 Kbyte */ +#define SX_ISA_ADDR_HIGH 0xFF8000 /* Highest address = 16Mbyte - 32Kbyte */ +#define SX_ISA_ADDR_STEP SX_WINDOW_LEN /* ISA board address step */ +#define SX_ISA_IRQ_MASK 0x9E00 /* IRQs 15,12,11,10,9 */ + +/* Hardware register definitions... */ +#define SX_EVENT_STATUS 0x7800 /* READ: T225 Event Status */ +#define SX_EVENT_STROBE 0x7800 /* WRITE: T225 Event Strobe */ +#define SX_EVENT_ENABLE 0x7880 /* WRITE: T225 Event Enable */ +#define SX_VPD_ROM 0x7C00 /* READ: Vital Product Data ROM */ +#define SX_CONFIG 0x7C00 /* WRITE: Host Configuration Register */ +#define SX_IRQ_STATUS 0x7C80 /* READ: Host Interrupt Status */ +#define SX_SET_IRQ 0x7C80 /* WRITE: Set Host Interrupt */ +#define SX_RESET_STATUS 0x7D00 /* READ: Host Reset Status */ +#define SX_RESET 0x7D00 /* WRITE: Host Reset */ +#define SX_RESET_IRQ 0x7D80 /* WRITE: Reset Host Interrupt */ + +/* SX_VPD_ROM definitions... */ +#define SX_VPD_SLX_ID1 0x00 +#define SX_VPD_SLX_ID2 0x01 +#define SX_VPD_HW_REV 0x02 +#define SX_VPD_HW_ASSEM 0x03 +#define SX_VPD_UNIQUEID4 0x04 +#define SX_VPD_UNIQUEID3 0x05 +#define SX_VPD_UNIQUEID2 0x06 +#define SX_VPD_UNIQUEID1 0x07 +#define SX_VPD_MANU_YEAR 0x08 +#define SX_VPD_MANU_WEEK 0x09 +#define SX_VPD_IDENT 0x10 +#define SX_VPD_IDENT_STRING "JET HOST BY KEV#" + +/* SX unique identifiers... */ +#define SX_UNIQUEID_MASK 0xF0 +#define SX_ISA_UNIQUEID1 0x20 +#define SX_PCI_UNIQUEID1 0x50 + +/* SX_CONFIG definitions... */ +#define SX_CONF_BUSEN 0x02 /* Enable T225 memory and I/O */ +#define SX_CONF_HOSTIRQ 0x04 /* Enable board to host interrupt */ + +/* SX bootstrap... */ +#define SX_BOOTSTRAP "\x28\x20\x21\x02\x60\x0a" +#define SX_BOOTSTRAP_SIZE 6 +#define SX_BOOTSTRAP_ADDR (0x8000-SX_BOOTSTRAP_SIZE) + +/***************************************************************************** +********************************** ********************************** +********************************** EISA ********************************** +********************************** ********************************** +*****************************************************************************/ + +#define SI2_EISA_OFF 0x42 +#define SI2_EISA_VAL 0x01 + +/***************************************************************************** +*********************************** ********************************** +*********************************** PCI ********************************** +*********************************** ********************************** +*****************************************************************************/ + +/* General definitions... */ + +#define SPX_VENDOR_ID 0x11CB /* Assigned by the PCI SIG */ +#define SPX_DEVICE_ID 0x4000 /* SI/XIO boards */ +#define SPX_PLXDEVICE_ID 0x2000 /* SX boards */ + +#define SPX_SUB_VENDOR_ID SPX_VENDOR_ID /* Same as vendor id */ +#define SI2_SUB_SYS_ID 0x400 /* Phase 2 (Z280) board */ +#define SX_SUB_SYS_ID 0x200 /* Phase 3 (t225) board */ + +#endif /*_sxboards_h */ + +/* End of SXBOARDS.H */ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/sxwindow.h linux.pre11.6/drivers/char/sxwindow.h --- linux.pre11.5/drivers/char/sxwindow.h Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/drivers/char/sxwindow.h Sat Aug 7 21:24:07 1999 @@ -0,0 +1,393 @@ +/************************************************************************/ +/* */ +/* Title : SX Shared Memory Window Structure */ +/* */ +/* Author : N.P.Vassallo */ +/* */ +/* Creation : 16th March 1998 */ +/* */ +/* Version : 3.0.0 */ +/* */ +/* Copyright : (c) Specialix International Ltd. 1998 */ +/* */ +/* Description : Prototypes, structures and definitions */ +/* describing the SX/SI/XIO cards shared */ +/* memory window structure: */ +/* SXCARD */ +/* SXMODULE */ +/* SXCHANNEL */ +/* */ +/************************************************************************/ + +/* History... + +3.0.0 16/03/98 NPV Creation. (based on STRUCT.H) + +*/ + +#ifndef _sxwindow_h /* If SXWINDOW.H not already defined */ +#define _sxwindow_h 1 + +/***************************************************************************** +*************************** *************************** +*************************** Common Definitions *************************** +*************************** *************************** +*****************************************************************************/ + +typedef struct _SXCARD *PSXCARD; /* SXCARD structure pointer */ +typedef struct _SXMODULE *PMOD; /* SXMODULE structure pointer */ +typedef struct _SXCHANNEL *PCHAN; /* SXCHANNEL structure pointer */ + +/***************************************************************************** +********************************* ********************************* +********************************* SXCARD ********************************* +********************************* ********************************* +*****************************************************************************/ + +typedef struct _SXCARD +{ + BYTE cc_init_status; /* 0x00 Initialisation status */ + BYTE cc_mem_size; /* 0x01 Size of memory on card */ + WORD cc_int_count; /* 0x02 Interrupt count */ + WORD cc_revision; /* 0x04 Download code revision */ + BYTE cc_isr_count; /* 0x06 Count when ISR is run */ + BYTE cc_main_count; /* 0x07 Count when main loop is run */ + WORD cc_int_pending; /* 0x08 Interrupt pending */ + WORD cc_poll_count; /* 0x0A Count when poll is run */ + BYTE cc_int_set_count; /* 0x0C Count when host interrupt is set */ + BYTE cc_rfu[0x80 - 0x0D]; /* 0x0D Pad structure to 128 bytes (0x80) */ + +} SXCARD; + +/* SXCARD.cc_init_status definitions... */ +#define ADAPTERS_FOUND (BYTE)0x01 +#define NO_ADAPTERS_FOUND (BYTE)0xFF + +/* SXCARD.cc_mem_size definitions... */ +#define SX_MEMORY_SIZE (BYTE)0x40 + +/* SXCARD.cc_int_count definitions... */ +#define INT_COUNT_DEFAULT 100 /* Hz */ + +/***************************************************************************** +******************************** ******************************** +******************************** SXMODULE ******************************** +******************************** ******************************** +*****************************************************************************/ + +#define TOP_POINTER(a) ((a)|0x8000) /* Sets top bit of word */ +#define UNTOP_POINTER(a) ((a)&~0x8000) /* Clears top bit of word */ + +typedef struct _SXMODULE +{ + WORD mc_next; /* 0x00 Next module "pointer" (ORed with 0x8000) */ + BYTE mc_type; /* 0x02 Type of TA in terms of number of channels */ + BYTE mc_mod_no; /* 0x03 Module number on SI bus cable (0 closest to card) */ + BYTE mc_dtr; /* 0x04 Private DTR copy (TA only) */ + BYTE mc_rfu1; /* 0x05 Reserved */ + WORD mc_uart; /* 0x06 UART base address for this module */ + BYTE mc_chip; /* 0x08 Chip type / number of ports */ + BYTE mc_current_uart; /* 0x09 Current uart selected for this module */ +#ifdef DOWNLOAD + PCHAN mc_chan_pointer[8]; /* 0x0A Pointer to each channel structure */ +#else + WORD mc_chan_pointer[8]; /* 0x0A Define as WORD if not compiling into download */ +#endif + WORD mc_rfu2; /* 0x1A Reserved */ + BYTE mc_opens1; /* 0x1C Number of open ports on first four ports on MTA/SXDC */ + BYTE mc_opens2; /* 0x1D Number of open ports on second four ports on MTA/SXDC */ + BYTE mc_mods; /* 0x1E Types of connector module attached to MTA/SXDC */ + BYTE mc_rev1; /* 0x1F Revision of first CD1400 on MTA/SXDC */ + BYTE mc_rev2; /* 0x20 Revision of second CD1400 on MTA/SXDC */ + BYTE mc_mtaasic_rev; /* 0x21 Revision of MTA ASIC 1..4 -> A, B, C, D */ + BYTE mc_rfu3[0x100 - 0x22]; /* 0x22 Pad structure to 256 bytes (0x100) */ + +} SXMODULE; + +/* SXMODULE.mc_type definitions... */ +#define FOUR_PORTS (BYTE)4 +#define EIGHT_PORTS (BYTE)8 + +/* SXMODULE.mc_chip definitions... */ +#define CHIP_MASK 0xF0 +#define TA (BYTE)0 +#define TA4 (TA | FOUR_PORTS) +#define TA8 (TA | EIGHT_PORTS) +#define TA4_ASIC (BYTE)0x0A +#define TA8_ASIC (BYTE)0x0B +#define MTA_CD1400 (BYTE)0x28 +#define SXDC (BYTE)0x48 + +/* SXMODULE.mc_mods definitions... */ +#define MOD_RS232DB25 0x00 /* RS232 DB25 (socket/plug) */ +#define MOD_RS232RJ45 0x01 /* RS232 RJ45 (shielded/opto-isolated) */ +#define MOD_RESERVED_2 0x02 /* Reserved (RS485) */ +#define MOD_RS422DB25 0x03 /* RS422 DB25 Socket */ +#define MOD_RESERVED_4 0x04 /* Reserved */ +#define MOD_PARALLEL 0x05 /* Parallel */ +#define MOD_RESERVED_6 0x06 /* Reserved (RS423) */ +#define MOD_RESERVED_7 0x07 /* Reserved */ +#define MOD_2_RS232DB25 0x08 /* Rev 2.0 RS232 DB25 (socket/plug) */ +#define MOD_2_RS232RJ45 0x09 /* Rev 2.0 RS232 RJ45 */ +#define MOD_RESERVED_A 0x0A /* Rev 2.0 Reserved */ +#define MOD_2_RS422DB25 0x0B /* Rev 2.0 RS422 DB25 */ +#define MOD_RESERVED_C 0x0C /* Rev 2.0 Reserved */ +#define MOD_2_PARALLEL 0x0D /* Rev 2.0 Parallel */ +#define MOD_RESERVED_E 0x0E /* Rev 2.0 Reserved */ +#define MOD_BLANK 0x0F /* Blank Panel */ + +/***************************************************************************** +******************************** ******************************* +******************************** SXCHANNEL ******************************* +******************************** ******************************* +*****************************************************************************/ + +#define TX_BUFF_OFFSET 0x60 /* Transmit buffer offset in channel structure */ +#define BUFF_POINTER(a) (((a)+TX_BUFF_OFFSET)|0x8000) +#define UNBUFF_POINTER(a) (jet_channel*)(((a)&~0x8000)-TX_BUFF_OFFSET) +#define BUFFER_SIZE 256 +#define HIGH_WATER ((BUFFER_SIZE / 4) * 3) +#define LOW_WATER (BUFFER_SIZE / 4) + +typedef struct _SXCHANNEL +{ + WORD next_item; /* 0x00 Offset from window base of next channels hi_txbuf (ORred with 0x8000) */ + WORD addr_uart; /* 0x02 INTERNAL pointer to uart address. Includes FASTPATH bit */ + WORD module; /* 0x04 Offset from window base of parent SXMODULE structure */ + BYTE type; /* 0x06 Chip type / number of ports (copy of mc_chip) */ + BYTE chan_number; /* 0x07 Channel number on the TA/MTA/SXDC */ + WORD xc_status; /* 0x08 Flow control and I/O status */ + BYTE hi_rxipos; /* 0x0A Receive buffer input index */ + BYTE hi_rxopos; /* 0x0B Receive buffer output index */ + BYTE hi_txopos; /* 0x0C Transmit buffer output index */ + BYTE hi_txipos; /* 0x0D Transmit buffer input index */ + BYTE hi_hstat; /* 0x0E Command register */ + BYTE dtr_bit; /* 0x0F INTERNAL DTR control byte (TA only) */ + BYTE txon; /* 0x10 INTERNAL copy of hi_txon */ + BYTE txoff; /* 0x11 INTERNAL copy of hi_txoff */ + BYTE rxon; /* 0x12 INTERNAL copy of hi_rxon */ + BYTE rxoff; /* 0x13 INTERNAL copy of hi_rxoff */ + BYTE hi_mr1; /* 0x14 Mode Register 1 (databits,parity,RTS rx flow)*/ + BYTE hi_mr2; /* 0x15 Mode Register 2 (stopbits,local,CTS tx flow)*/ + BYTE hi_csr; /* 0x16 Clock Select Register (baud rate) */ + BYTE hi_op; /* 0x17 Modem Output Signal */ + BYTE hi_ip; /* 0x18 Modem Input Signal */ + BYTE hi_state; /* 0x19 Channel status */ + BYTE hi_prtcl; /* 0x1A Channel protocol (flow control) */ + BYTE hi_txon; /* 0x1B Transmit XON character */ + BYTE hi_txoff; /* 0x1C Transmit XOFF character */ + BYTE hi_rxon; /* 0x1D Receive XON character */ + BYTE hi_rxoff; /* 0x1E Receive XOFF character */ + BYTE close_prev; /* 0x1F INTERNAL channel previously closed flag */ + BYTE hi_break; /* 0x20 Break and error control */ + BYTE break_state; /* 0x21 INTERNAL copy of hi_break */ + BYTE hi_mask; /* 0x22 Mask for received data */ + BYTE mask; /* 0x23 INTERNAL copy of hi_mask */ + BYTE mod_type; /* 0x24 MTA/SXDC hardware module type */ + BYTE ccr_state; /* 0x25 INTERNAL MTA/SXDC state of CCR register */ + BYTE ip_mask; /* 0x26 Input handshake mask */ + BYTE hi_parallel; /* 0x27 Parallel port flag */ + BYTE par_error; /* 0x28 Error code for parallel loopback test */ + BYTE any_sent; /* 0x29 INTERNAL data sent flag */ + BYTE asic_txfifo_size; /* 0x2A INTERNAL SXDC transmit FIFO size */ + BYTE rfu1[2]; /* 0x2B Reserved */ + BYTE csr; /* 0x2D INTERNAL copy of hi_csr */ +#ifdef DOWNLOAD + PCHAN nextp; /* 0x2E Offset from window base of next channel structure */ +#else + WORD nextp; /* 0x2E Define as WORD if not compiling into download */ +#endif + BYTE prtcl; /* 0x30 INTERNAL copy of hi_prtcl */ + BYTE mr1; /* 0x31 INTERNAL copy of hi_mr1 */ + BYTE mr2; /* 0x32 INTERNAL copy of hi_mr2 */ + BYTE hi_txbaud; /* 0x33 Extended transmit baud rate (SXDC only if((hi_csr&0x0F)==0x0F) */ + BYTE hi_rxbaud; /* 0x34 Extended receive baud rate (SXDC only if((hi_csr&0xF0)==0xF0) */ + BYTE txbreak_state; /* 0x35 INTERNAL MTA/SXDC transmit break state */ + BYTE txbaud; /* 0x36 INTERNAL copy of hi_txbaud */ + BYTE rxbaud; /* 0x37 INTERNAL copy of hi_rxbaud */ + WORD err_framing; /* 0x38 Count of receive framing errors */ + WORD err_parity; /* 0x3A Count of receive parity errors */ + WORD err_overrun; /* 0x3C Count of receive overrun errors */ + WORD err_overflow; /* 0x3E Count of receive buffer overflow errors */ + BYTE rfu2[TX_BUFF_OFFSET - 0x40]; /* 0x40 Reserved until hi_txbuf */ + BYTE hi_txbuf[BUFFER_SIZE]; /* 0x060 Transmit buffer */ + BYTE hi_rxbuf[BUFFER_SIZE]; /* 0x160 Receive buffer */ + BYTE rfu3[0x300 - 0x260]; /* 0x260 Reserved until 768 bytes (0x300) */ + +} SXCHANNEL; + +/* SXCHANNEL.addr_uart definitions... */ +#define FASTPATH 0x1000 /* Set to indicate fast rx/tx processing (TA only) */ + +/* SXCHANNEL.xc_status definitions... */ +#define X_TANY 0x0001 /* XON is any character (TA only) */ +#define X_TION 0x0001 /* Tx interrupts on (MTA only) */ +#define X_TXEN 0x0002 /* Tx XON/XOFF enabled (TA only) */ +#define X_RTSEN 0x0002 /* RTS FLOW enabled (MTA only) */ +#define X_TXRC 0x0004 /* XOFF received (TA only) */ +#define X_RTSLOW 0x0004 /* RTS dropped (MTA only) */ +#define X_RXEN 0x0008 /* Rx XON/XOFF enabled */ +#define X_ANYXO 0x0010 /* XOFF pending/sent or RTS dropped */ +#define X_RXSE 0x0020 /* Rx XOFF sent */ +#define X_NPEND 0x0040 /* Rx XON pending or XOFF pending */ +#define X_FPEND 0x0080 /* Rx XOFF pending */ +#define C_CRSE 0x0100 /* Carriage return sent (TA only) */ +#define C_TEMR 0x0100 /* Tx empty requested (MTA only) */ +#define C_TEMA 0x0200 /* Tx empty acked (MTA only) */ +#define C_ANYP 0x0200 /* Any protocol bar tx XON/XOFF (TA only) */ +#define C_EN 0x0400 /* Cooking enabled (on MTA means port is also || */ +#define C_HIGH 0x0800 /* Buffer previously hit high water */ +#define C_CTSEN 0x1000 /* CTS automatic flow-control enabled */ +#define C_DCDEN 0x2000 /* DCD/DTR checking enabled */ +#define C_BREAK 0x4000 /* Break detected */ +#define C_RTSEN 0x8000 /* RTS automatic flow control enabled (MTA only) */ +#define C_PARITY 0x8000 /* Parity checking enabled (TA only) */ + +/* SXCHANNEL.hi_hstat definitions... */ +#define HS_IDLE_OPEN 0x00 /* Channel open state */ +#define HS_LOPEN 0x02 /* Local open command (no modem monitoring) */ +#define HS_MOPEN 0x04 /* Modem open command (wait for DCD signal) */ +#define HS_IDLE_MPEND 0x06 /* Waiting for DCD signal state */ +#define HS_CONFIG 0x08 /* Configuration command */ +#define HS_CLOSE 0x0A /* Close command */ +#define HS_START 0x0C /* Start transmit break command */ +#define HS_STOP 0x0E /* Stop transmit break command */ +#define HS_IDLE_CLOSED 0x10 /* Closed channel state */ +#define HS_IDLE_BREAK 0x12 /* Transmit break state */ +#define HS_FORCE_CLOSED 0x14 /* Force close command */ +#define HS_RESUME 0x16 /* Clear pending XOFF command */ +#define HS_WFLUSH 0x18 /* Flush transmit buffer command */ +#define HS_RFLUSH 0x1A /* Flush receive buffer command */ +#define HS_SUSPEND 0x1C /* Suspend output command (like XOFF received) */ +#define PARALLEL 0x1E /* Parallel port loopback test command (Diagnostics Only) */ +#define ENABLE_RX_INTS 0x20 /* Enable receive interrupts command (Diagnostics Only) */ +#define ENABLE_TX_INTS 0x22 /* Enable transmit interrupts command (Diagnostics Only) */ +#define ENABLE_MDM_INTS 0x24 /* Enable modem interrupts command (Diagnostics Only) */ +#define DISABLE_INTS 0x26 /* Disable interrupts command (Diagnostics Only) */ + +/* SXCHANNEL.hi_mr1 definitions... */ +#define MR1_BITS 0x03 /* Data bits mask */ +#define MR1_5_BITS 0x00 /* 5 data bits */ +#define MR1_6_BITS 0x01 /* 6 data bits */ +#define MR1_7_BITS 0x02 /* 7 data bits */ +#define MR1_8_BITS 0x03 /* 8 data bits */ +#define MR1_PARITY 0x1C /* Parity mask */ +#define MR1_ODD 0x04 /* Odd parity */ +#define MR1_EVEN 0x00 /* Even parity */ +#define MR1_WITH 0x00 /* Parity enabled */ +#define MR1_FORCE 0x08 /* Force parity */ +#define MR1_NONE 0x10 /* No parity */ +#define MR1_NOPARITY MR1_NONE /* No parity */ +#define MR1_ODDPARITY (MR1_WITH|MR1_ODD) /* Odd parity */ +#define MR1_EVENPARITY (MR1_WITH|MR1_EVEN) /* Even parity */ +#define MR1_MARKPARITY (MR1_FORCE|MR1_ODD) /* Mark parity */ +#define MR1_SPACEPARITY (MR1_FORCE|MR1_EVEN) /* Space parity */ +#define MR1_RTS_RXFLOW 0x80 /* RTS receive flow control */ + +/* SXCHANNEL.hi_mr2 definitions... */ +#define MR2_STOP 0x0F /* Stop bits mask */ +#define MR2_1_STOP 0x07 /* 1 stop bit */ +#define MR2_2_STOP 0x0F /* 2 stop bits */ +#define MR2_CTS_TXFLOW 0x10 /* CTS transmit flow control */ +#define MR2_RTS_TOGGLE 0x20 /* RTS toggle on transmit */ +#define MR2_NORMAL 0x00 /* Normal mode */ +#define MR2_AUTO 0x40 /* Auto-echo mode (TA only) */ +#define MR2_LOCAL 0x80 /* Local echo mode */ +#define MR2_REMOTE 0xC0 /* Remote echo mode (TA only) */ + +/* SXCHANNEL.hi_csr definitions... */ +#define CSR_75 0x0 /* 75 baud */ +#define CSR_110 0x1 /* 110 baud (TA), 115200 (MTA/SXDC) */ +#define CSR_38400 0x2 /* 38400 baud */ +#define CSR_150 0x3 /* 150 baud */ +#define CSR_300 0x4 /* 300 baud */ +#define CSR_600 0x5 /* 600 baud */ +#define CSR_1200 0x6 /* 1200 baud */ +#define CSR_2000 0x7 /* 2000 baud */ +#define CSR_2400 0x8 /* 2400 baud */ +#define CSR_4800 0x9 /* 4800 baud */ +#define CSR_1800 0xA /* 1800 baud */ +#define CSR_9600 0xB /* 9600 baud */ +#define CSR_19200 0xC /* 19200 baud */ +#define CSR_57600 0xD /* 57600 baud */ +#define CSR_EXTBAUD 0xF /* Extended baud rate (hi_txbaud/hi_rxbaud) */ + +/* SXCHANNEL.hi_op definitions... */ +#define OP_RTS 0x01 /* RTS modem output signal */ +#define OP_DTR 0x02 /* DTR modem output signal */ + +/* SXCHANNEL.hi_ip definitions... */ +#define IP_CTS 0x02 /* CTS modem input signal */ +#define IP_DCD 0x04 /* DCD modem input signal */ +#define IP_DSR 0x20 /* DTR modem input signal */ +#define IP_RI 0x40 /* RI modem input signal */ + +/* SXCHANNEL.hi_state definitions... */ +#define ST_BREAK 0x01 /* Break received (clear with config) */ +#define ST_DCD 0x02 /* DCD signal changed state */ + +/* SXCHANNEL.hi_prtcl definitions... */ +#define SP_TANY 0x01 /* Transmit XON/XANY (if SP_TXEN enabled) */ +#define SP_TXEN 0x02 /* Transmit XON/XOFF flow control */ +#define SP_CEN 0x04 /* Cooking enabled */ +#define SP_RXEN 0x08 /* Rx XON/XOFF enabled */ +#define SP_DCEN 0x20 /* DCD / DTR check */ +#define SP_DTR_RXFLOW 0x40 /* DTR receive flow control */ +#define SP_PAEN 0x80 /* Parity checking enabled */ + +/* SXCHANNEL.hi_break definitions... */ +#define BR_IGN 0x01 /* Ignore any received breaks */ +#define BR_INT 0x02 /* Interrupt on received break */ +#define BR_PARMRK 0x04 /* Enable parmrk parity error processing */ +#define BR_PARIGN 0x08 /* Ignore chars with parity errors */ +#define BR_ERRINT 0x80 /* Treat parity/framing/overrun errors as exceptions */ + +/* SXCHANNEL.par_error definitions.. */ +#define DIAG_IRQ_RX 0x01 /* Indicate serial receive interrupt (diags only) */ +#define DIAG_IRQ_TX 0x02 /* Indicate serial transmit interrupt (diags only) */ +#define DIAG_IRQ_MD 0x04 /* Indicate serial modem interrupt (diags only) */ + +/* SXCHANNEL.hi_txbaud/hi_rxbaud definitions... (SXDC only) */ +#define BAUD_75 0x00 /* 75 baud */ +#define BAUD_115200 0x01 /* 115200 baud */ +#define BAUD_38400 0x02 /* 38400 baud */ +#define BAUD_150 0x03 /* 150 baud */ +#define BAUD_300 0x04 /* 300 baud */ +#define BAUD_600 0x05 /* 600 baud */ +#define BAUD_1200 0x06 /* 1200 baud */ +#define BAUD_2000 0x07 /* 2000 baud */ +#define BAUD_2400 0x08 /* 2400 baud */ +#define BAUD_4800 0x09 /* 4800 baud */ +#define BAUD_1800 0x0A /* 1800 baud */ +#define BAUD_9600 0x0B /* 9600 baud */ +#define BAUD_19200 0x0C /* 19200 baud */ +#define BAUD_57600 0x0D /* 57600 baud */ +#define BAUD_230400 0x0E /* 230400 baud */ +#define BAUD_460800 0x0F /* 460800 baud */ +#define BAUD_921600 0x10 /* 921600 baud */ +#define BAUD_50 0x11 /* 50 baud */ +#define BAUD_110 0x12 /* 110 baud */ +#define BAUD_134_5 0x13 /* 134.5 baud */ +#define BAUD_200 0x14 /* 200 baud */ +#define BAUD_7200 0x15 /* 7200 baud */ +#define BAUD_56000 0x16 /* 56000 baud */ +#define BAUD_64000 0x17 /* 64000 baud */ +#define BAUD_76800 0x18 /* 76800 baud */ +#define BAUD_128000 0x19 /* 128000 baud */ +#define BAUD_150000 0x1A /* 150000 baud */ +#define BAUD_14400 0x1B /* 14400 baud */ +#define BAUD_256000 0x1C /* 256000 baud */ +#define BAUD_28800 0x1D /* 28800 baud */ + +/* SXCHANNEL.txbreak_state definiions... */ +#define TXBREAK_OFF 0 /* Not sending break */ +#define TXBREAK_START 1 /* Begin sending break */ +#define TXBREAK_START1 2 /* Begin sending break, part 1 */ +#define TXBREAK_ON 3 /* Sending break */ +#define TXBREAK_STOP 4 /* Stop sending break */ +#define TXBREAK_STOP1 5 /* Stop sending break, part 1 */ + +#endif /* _sxwindow_h */ + +/* End of SXWINDOW.H */ + diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/char/tty_io.c linux.pre11.6/drivers/char/tty_io.c --- linux.pre11.5/drivers/char/tty_io.c Fri Aug 6 18:50:45 1999 +++ linux.pre11.6/drivers/char/tty_io.c Sat Aug 7 21:24:07 1999 @@ -2166,6 +2166,9 @@ #ifdef CONFIG_SPECIALIX specialix_init(); #endif +#ifdef CONFIG_SX + sx_init(); +#endif #ifdef CONFIG_8xx rs_8xx_init(); #endif /* CONFIG_8xx */ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/net/Config.in linux.pre11.6/drivers/net/Config.in --- linux.pre11.5/drivers/net/Config.in Fri Aug 6 18:50:33 1999 +++ linux.pre11.6/drivers/net/Config.in Sun Aug 8 02:00:31 1999 @@ -24,6 +24,9 @@ tristate 'Ethertap network tap' CONFIG_ETHERTAP fi fi + +tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000 + # # Ethernet # @@ -278,6 +281,7 @@ fi endmenu + # # X.25 network drivers diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/net/Makefile linux.pre11.6/drivers/net/Makefile --- linux.pre11.5/drivers/net/Makefile Fri Aug 6 18:50:33 1999 +++ linux.pre11.6/drivers/net/Makefile Sun Aug 8 02:01:01 1999 @@ -91,6 +91,14 @@ endif endif +ifeq ($(CONFIG_NET_SB1000),y) +L_OBJS += sb1000.o +else + ifeq ($(CONFIG_NET_SB1000),m) + M_OBJS += sb1000.o + endif +endif + ifeq ($(CONFIG_DAYNAPORT), y) L_OBJS += daynaport.o CONFIG_8390_BUILTIN = y diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/net/Space.c linux.pre11.6/drivers/net/Space.c --- linux.pre11.5/drivers/net/Space.c Fri Aug 6 18:50:33 1999 +++ linux.pre11.6/drivers/net/Space.c Sun Aug 8 01:59:34 1999 @@ -818,6 +818,14 @@ # define NEXT_DEV (&bif_dev) #endif +#ifdef CONFIG_NET_SB1000 + extern int sb1000_init(struct device *dev); + static struct device sb1000_dev = { + "cm0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, sb1000_probe }; +# undef NEXT_DEV +# define NEXT_DEV (&sb1000_dev) +#endif + extern int loopback_init(struct device *dev); struct device loopback_dev = { "lo", /* Software Loopback interface */ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/net/sb1000.c linux.pre11.6/drivers/net/sb1000.c --- linux.pre11.5/drivers/net/sb1000.c Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/drivers/net/sb1000.c Sun Aug 8 01:57:25 1999 @@ -0,0 +1,1294 @@ +/* sb1000.c: A General Instruments SB1000 driver for linux. */ +/* + Written 1998 by Franco Venturi. + + Copyright 1998 by Franco Venturi. + Copyright 1994,1995 by Donald Becker. + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + + This driver is for the General Instruments SB1000 (internal SURFboard) + + The author may be reached as fventuri@mediaone.net + + 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. + + Changes: + + 981115 Steven Hirsch + + Linus changed the timer interface. Should work on all recent + development kernels. + + 980608 Steven Hirsch + + Small changes to make it work with 2.1.x kernels. Hopefully, + nothing major will change before official release of Linux 2.2. + + Merged with 2.2 - Alan Cox +*/ + +static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n"; + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for udelay() */ +#include + +#include +#include +#include +#include + +/* for SIOGCM/SIOSCM stuff */ +#include + +#ifdef SB1000_DEBUG +int sb1000_debug = SB1000_DEBUG; +#else +int sb1000_debug = 1; +#endif + +static const int SB1000_IO_EXTENT = 8; +/* SB1000 Maximum Receive Unit */ +static const int SB1000_MRU = 1500; /* octects */ + +#define NPIDS 4 +struct sb1000_private { + struct sk_buff *rx_skb[NPIDS]; + short rx_dlen[NPIDS]; + unsigned int rx_bytes; + unsigned int rx_frames; + short rx_error_count; + short rx_error_dpc_count; + unsigned char rx_session_id[NPIDS]; + unsigned char rx_frame_id[NPIDS]; + unsigned char rx_pkt_type[NPIDS]; + struct net_device_stats stats; +}; + +/* prototypes for Linux interface */ +extern int sb1000_probe(struct device *dev); +static int sb1000_open(struct device *dev); +static int sb1000_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd); +static int sb1000_start_xmit(struct sk_buff *skb, struct device *dev); +static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct enet_statistics *sb1000_stats(struct device *dev); +static int sb1000_close(struct device *dev); + +/* Plug-n-Play routine */ +static inline unsigned char read_resource_data(void); + +/* SB1000 hardware routines to be used during open/configuration phases */ +static inline void nicedelay(unsigned long usecs); +static inline int card_wait_for_busy_clear(const int ioaddr[], + const char* name); +static inline int card_wait_for_ready(const int ioaddr[], const char* name, + unsigned char in[]); +static inline int card_send_command(const int ioaddr[], const char* name, + const unsigned char out[], unsigned char in[]); + +/* SB1000 hardware routines to be used during frame rx interrupt */ +static inline int sb1000_wait_for_ready(const int ioaddr[], const char* name); +static inline int sb1000_wait_for_ready_clear(const int ioaddr[], + const char* name); +static inline void sb1000_send_command(const int ioaddr[], const char* name, + const unsigned char out[]); +static inline void sb1000_read_status(const int ioaddr[], unsigned char in[]); +static inline void sb1000_issue_read_command(const int ioaddr[], + const char* name); + +/* SB1000 commands for open/configuration */ +static inline int sb1000_reset(const int ioaddr[], const char* name); +static inline int sb1000_check_CRC(const int ioaddr[], const char* name); +static inline int sb1000_start_get_set_command(const int ioaddr[], + const char* name); +static inline int sb1000_end_get_set_command(const int ioaddr[], + const char* name); +static inline int sb1000_activate(const int ioaddr[], const char* name); +static inline int sb1000_get_firmware_version(const int ioaddr[], + const char* name, unsigned char version[], int do_end); +static inline int sb1000_get_frequency(const int ioaddr[], const char* name, + int* frequency); +static inline int sb1000_set_frequency(const int ioaddr[], const char* name, + int frequency); +static inline int sb1000_get_PIDs(const int ioaddr[], const char* name, + short PID[]); +static inline int sb1000_set_PIDs(const int ioaddr[], const char* name, + const short PID[]); + +/* SB1000 commands for frame rx interrupt */ +static inline int sb1000_rx(struct device *dev); +static inline void sb1000_error_dpc(struct device *dev); + + +/* Plug-n-Play constants */ +static const int READ_DATA_PORT = 0x203; /* This port number may change!!! */ +static const int ADDRESS_PORT = 0x279; +static const int WRITE_DATA_PORT = 0xa79; + +/* Plug-n-Play read resource mechanism */ +static inline unsigned char +read_resource_data(void) { + /* poll */ + outb(0x05, ADDRESS_PORT); /* Select PnP status register. */ + while (!(inb(READ_DATA_PORT) & 0x1)) ; + /* read resource data */ + outb(0x04, ADDRESS_PORT); /* Select PnP resource data register. */ + return inb(READ_DATA_PORT); +} + +/* probe for SB1000 using Plug-n-Play mechanism */ +int +sb1000_probe(struct device *dev) +{ + + unsigned short ioaddr[2], irq; + short i, csn; + unsigned int serial_number; + + const unsigned char initiation_key[] = { 0x00, 0x00, 0x6a, 0xb5, 0xda, + 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 0x0d, + 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, + 0xd1, 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; + const unsigned char sb1000_vendor_ID[] = { + 0x1d, 0x23, 0x10, 0x00 }; /* "GIC1000" */ + + /* Reset the ISA PnP mechanism */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ + + /* send initiation key */ + for (i = 0; i < sizeof(initiation_key) / sizeof(initiation_key[0]); i++) { + outb(initiation_key[i], ADDRESS_PORT); + } + + /* set card CSN into configuration mode */ + for (csn = 1; csn <= 255; csn++) { + outb(0x03, ADDRESS_PORT); /* Select PnP wake[CSN] register. */ + outb(csn, WRITE_DATA_PORT); /* Wake[CSN] */ + /* check card ID */ + for (i = 0; i < 4; i++) { + if (read_resource_data() != sb1000_vendor_ID[i]) break; + } + if (i == 4) break; + } + + /* SB1000 not found */ + if (csn > 255) { + /* return to WaitForKey state */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT);/* Return to WaitForKey state. */ + return -ENODEV; + } + + /* found: get serial number and skip checksum */ + serial_number = 0; + for (i = 0; i < 4; i++) { + serial_number |= read_resource_data() << (8 * i); + } + read_resource_data(); + + /* get I/O port base address */ + outb(0x60, ADDRESS_PORT); /* Select PnP I/O port base address 0. */ + ioaddr[0] = inb(READ_DATA_PORT) << 8; + outb(0x61, ADDRESS_PORT); + ioaddr[0] |= inb(READ_DATA_PORT); + outb(0x62, ADDRESS_PORT); /* Select PnP I/O port base address 1. */ + ioaddr[1] = inb(READ_DATA_PORT) << 8; + outb(0x63, ADDRESS_PORT); + ioaddr[1] |= inb(READ_DATA_PORT); + + /* get IRQ */ + outb(0x70, ADDRESS_PORT); /* Select PnP IRQ level select 0. */ + irq = inb(READ_DATA_PORT); + + /* return to WaitForKey state */ + outb(0x02, ADDRESS_PORT); /* Select PnP config control register. */ + outb(0x02, WRITE_DATA_PORT); /* Return to WaitForKey state. */ + + /* check I/O base and IRQ */ + if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) { + return -ENODEV; + } + if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1]) { + return -ENODEV; + } + if (dev->irq != 0 && dev->irq != irq) { + return -ENODEV; + } + + dev->base_addr = ioaddr[0]; + /* rmem_end holds the second I/O address - fv */ + dev->rmem_end = ioaddr[1]; + dev->irq = irq; + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), csn %d, " + "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, + dev->rmem_end, csn, serial_number, dev->irq); + + dev = init_etherdev(dev, 0); + + /* Make up a SB1000-specific-data structure. */ + dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct sb1000_private)); + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s", version); + + /* The SB1000-specific entries in the device structure. */ + dev->open = sb1000_open; + dev->do_ioctl = sb1000_dev_ioctl; + dev->hard_start_xmit = sb1000_start_xmit; + dev->stop = sb1000_close; + dev->get_stats = sb1000_stats; + + /* Fill in the generic fields of the device structure. */ + dev->change_mtu = NULL; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->set_mac_address = NULL; + dev->header_cache_update= NULL; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = 0; + dev->mtu = 0; + dev->addr_len = ETH_ALEN; + /* hardware address is 0:0:serial_number */ + dev->dev_addr[0] = 0; + dev->dev_addr[1] = 0; + dev->dev_addr[2] = serial_number >> 24 & 0xff; + dev->dev_addr[3] = serial_number >> 16 & 0xff; + dev->dev_addr[4] = serial_number >> 8 & 0xff; + dev->dev_addr[5] = serial_number >> 0 & 0xff; + dev->tx_queue_len = 0; + + /* New-style flags. */ + dev->flags = IFF_POINTOPOINT|IFF_NOARP; + return 0; +} + + +/* + * SB1000 hardware routines to be used during open/configuration phases + */ +const int TimeOutJiffies = (int)(8.75 * HZ); + +static inline void nicedelay(unsigned long usecs) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + return; +} + +/* Card Wait For Busy Clear (cannot be used during an interrupt) */ +static inline int +card_wait_for_busy_clear(const int ioaddr[], const char* name) +{ + unsigned char a; + unsigned long timeout; + + a = inb(ioaddr[0] + 7); + timeout = jiffies + TimeOutJiffies; + while (a & 0x80 || a & 0x40) { + /* a little sleep */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(0); + a = inb(ioaddr[0] + 7); + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: card_wait_for_busy_clear timeout\n", + name); + return -ETIME; + } + } + + return 0; +} + +/* Card Wait For Ready (cannot be used during an interrupt) */ +static inline int +card_wait_for_ready(const int ioaddr[], const char* name, unsigned char in[]) +{ + unsigned char a; + unsigned long timeout; + + a = inb(ioaddr[1] + 6); + timeout = jiffies + TimeOutJiffies; + while (a & 0x80 || !(a & 0x40)) { + /* a little sleep */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(0); + a = inb(ioaddr[1] + 6); + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: card_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + + in[1] = inb(ioaddr[0] + 1); + in[2] = inb(ioaddr[0] + 2); + in[3] = inb(ioaddr[0] + 3); + in[4] = inb(ioaddr[0] + 4); + in[0] = inb(ioaddr[0] + 5); + in[6] = inb(ioaddr[0] + 6); + in[5] = inb(ioaddr[1] + 6); + return 0; +} + +/* Card Send Command (cannot be used during an interrupt) */ +static inline int +card_send_command(const int ioaddr[], const char* name, + const unsigned char out[], unsigned char in[]) +{ + int status, x; + + if ((status = card_wait_for_busy_clear(ioaddr, name))) + return status; + outb(0xa0, ioaddr[0] + 6); + outb(out[2], ioaddr[0] + 1); + outb(out[3], ioaddr[0] + 2); + outb(out[4], ioaddr[0] + 3); + outb(out[5], ioaddr[0] + 4); + outb(out[1], ioaddr[0] + 5); + outb(0xa0, ioaddr[0] + 6); + outb(out[0], ioaddr[0] + 7); + if (out[0] != 0x20 && out[0] != 0x30) { + if ((status = card_wait_for_ready(ioaddr, name, in))) + return status; + inb(ioaddr[0] + 7); + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: card_send_command " + "out: %02x%02x%02x%02x%02x%02x " + "in: %02x%02x%02x%02x%02x%02x%02x\n", name, + out[0], out[1], out[2], out[3], out[4], out[5], + in[0], in[1], in[2], in[3], in[4], in[5], in[6]); + } else { + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: card_send_command " + "out: %02x%02x%02x%02x%02x%02x\n", name, + out[0], out[1], out[2], out[3], out[4], out[5]); + } + + if (out[1] == 0x1b) { + x = (out[2] == 0x02); + } else { + if (out[0] >= 0x80 && in[0] != (out[1] | 0x80)) + return -EIO; + } + return 0; +} + + +/* + * SB1000 hardware routines to be used during frame rx interrupt + */ +const int Sb1000TimeOutJiffies = 7 * HZ; + +/* Card Wait For Ready (to be used during frame rx) */ +static inline int +sb1000_wait_for_ready(const int ioaddr[], const char* name) +{ + unsigned long timeout; + + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x80) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + timeout = jiffies + Sb1000TimeOutJiffies; + while (!(inb(ioaddr[1] + 6) & 0x40)) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n", + name); + return -ETIME; + } + } + inb(ioaddr[0] + 7); + return 0; +} + +/* Card Wait For Ready Clear (to be used during frame rx) */ +static inline int +sb1000_wait_for_ready_clear(const int ioaddr[], const char* name) +{ + unsigned long timeout; + + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x80) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", + name); + return -ETIME; + } + } + timeout = jiffies + Sb1000TimeOutJiffies; + while (inb(ioaddr[1] + 6) & 0x40) { + if (jiffies >= timeout) { + printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n", + name); + return -ETIME; + } + } + return 0; +} + +/* Card Send Command (to be used during frame rx) */ +static inline void +sb1000_send_command(const int ioaddr[], const char* name, + const unsigned char out[]) +{ + outb(out[2], ioaddr[0] + 1); + outb(out[3], ioaddr[0] + 2); + outb(out[4], ioaddr[0] + 3); + outb(out[5], ioaddr[0] + 4); + outb(out[1], ioaddr[0] + 5); + outb(out[0], ioaddr[0] + 7); + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: sb1000_send_command out: %02x%02x%02x%02x" + "%02x%02x\n", name, out[0], out[1], out[2], out[3], out[4], out[5]); + return; +} + +/* Card Read Status (to be used during frame rx) */ +static inline void +sb1000_read_status(const int ioaddr[], unsigned char in[]) +{ + in[1] = inb(ioaddr[0] + 1); + in[2] = inb(ioaddr[0] + 2); + in[3] = inb(ioaddr[0] + 3); + in[4] = inb(ioaddr[0] + 4); + in[0] = inb(ioaddr[0] + 5); + return; +} + +/* Issue Read Command (to be used during frame rx) */ +static inline void +sb1000_issue_read_command(const int ioaddr[], const char* name) +{ + const unsigned char Command0[6] = {0x20, 0x00, 0x00, 0x01, 0x00, 0x00}; + + sb1000_wait_for_ready_clear(ioaddr, name); + outb(0xa0, ioaddr[0] + 6); + sb1000_send_command(ioaddr, name, Command0); + return; +} + + +/* + * SB1000 commands for open/configuration + */ +/* reset SB1000 card */ +static inline int +sb1000_reset(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int port, status; + const unsigned char Command0[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00}; + + port = ioaddr[1] + 6; + outb(0x4, port); + inb(port); + udelay(1000); + outb(0x0, port); + inb(port); + nicedelay(60000); + outb(0x4, port); + inb(port); + udelay(1000); + outb(0x0, port); + inb(port); + udelay(0); + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[3] != 0xf0) + return -EIO; + return 0; +} + +/* check SB1000 firmware CRC */ +static inline int +sb1000_check_CRC(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int crc, status; + const unsigned char Command0[6] = {0x80, 0x1f, 0x00, 0x00, 0x00, 0x00}; + + /* check CRC */ + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[1] != st[3] || st[2] != st[4]) + return -EIO; + crc = st[1] << 8 | st[2]; + return 0; +} + +static inline int +sb1000_start_get_set_command(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + const unsigned char Command0[6] = {0x80, 0x1b, 0x00, 0x00, 0x00, 0x00}; + + return card_send_command(ioaddr, name, Command0, st); +} + +static inline int +sb1000_end_get_set_command(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x1b, 0x02, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x20, 0x00, 0x00, 0x00, 0x00, 0x00}; + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + return card_send_command(ioaddr, name, Command1, st); +} + +static inline int +sb1000_activate(const int ioaddr[], const char* name) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00}; + + nicedelay(50000); + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + if (st[3] != 0xf1) { + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + return -EIO; + } + udelay(1000); + return sb1000_start_get_set_command(ioaddr, name); +} + +/* get SB1000 firmware version */ +static inline int +sb1000_get_firmware_version(const int ioaddr[], const char* name, + unsigned char version[], int do_end) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x23, 0x00, 0x00, 0x00, 0x00}; + + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + if (st[0] != 0xa3) + return -EIO; + version[0] = st[1]; + version[1] = st[2]; + if (do_end) + return sb1000_end_get_set_command(ioaddr, name); + else + return 0; +} + +/* get SB1000 frequency */ +static inline int +sb1000_get_frequency(const int ioaddr[], const char* name, int* frequency) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x44, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + *frequency = ((st[1] << 8 | st[2]) << 8 | st[3]) << 8 | st[4]; + return sb1000_end_get_set_command(ioaddr, name); +} + +/* set SB1000 frequency */ +static inline int +sb1000_set_frequency(const int ioaddr[], const char* name, int frequency) +{ + unsigned char st[7]; + int status; + unsigned char Command0[6] = {0x80, 0x29, 0x00, 0x00, 0x00, 0x00}; + + const int FrequencyLowerLimit = 57000; + const int FrequencyUpperLimit = 804000; + + if (frequency < FrequencyLowerLimit || frequency > FrequencyUpperLimit) { + printk(KERN_ERR "%s: frequency chosen (%d kHz) is not in the range " + "[%d,%d] kHz\n", name, frequency, FrequencyLowerLimit, + FrequencyUpperLimit); + return -EINVAL; + } + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + Command0[5] = frequency & 0xff; + frequency >>= 8; + Command0[4] = frequency & 0xff; + frequency >>= 8; + Command0[3] = frequency & 0xff; + frequency >>= 8; + Command0[2] = frequency & 0xff; + return card_send_command(ioaddr, name, Command0, st); +} + +/* get SB1000 PIDs */ +static inline int +sb1000_get_PIDs(const int ioaddr[], const char* name, short PID[]) +{ + unsigned char st[7]; + int status; + const unsigned char Command0[6] = {0x80, 0x40, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x41, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command2[6] = {0x80, 0x42, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command3[6] = {0x80, 0x43, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + PID[0] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + PID[1] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command2, st))) + return status; + PID[2] = st[1] << 8 | st[2]; + + if ((status = card_send_command(ioaddr, name, Command3, st))) + return status; + PID[3] = st[1] << 8 | st[2]; + + return sb1000_end_get_set_command(ioaddr, name); +} + +/* set SB1000 PIDs */ +static inline int +sb1000_set_PIDs(const int ioaddr[], const char* name, const short PID[]) +{ + unsigned char st[7]; + short p; + int status; + unsigned char Command0[6] = {0x80, 0x31, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command1[6] = {0x80, 0x32, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command2[6] = {0x80, 0x33, 0x00, 0x00, 0x00, 0x00}; + unsigned char Command3[6] = {0x80, 0x34, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command4[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; + + udelay(1000); + if ((status = sb1000_start_get_set_command(ioaddr, name))) + return status; + + p = PID[0]; + Command0[3] = p & 0xff; + p >>= 8; + Command0[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command0, st))) + return status; + + p = PID[1]; + Command1[3] = p & 0xff; + p >>= 8; + Command1[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command1, st))) + return status; + + p = PID[2]; + Command2[3] = p & 0xff; + p >>= 8; + Command2[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command2, st))) + return status; + + p = PID[3]; + Command3[3] = p & 0xff; + p >>= 8; + Command3[2] = p & 0xff; + if ((status = card_send_command(ioaddr, name, Command3, st))) + return status; + + if ((status = card_send_command(ioaddr, name, Command4, st))) + return status; + return sb1000_end_get_set_command(ioaddr, name); +} + + +static inline void +sb1000_print_status_buffer(const char* name, unsigned char st[], + unsigned char buffer[], int size) +{ + int i, j, k; + + printk(KERN_DEBUG "%s: status: %02x %02x\n", name, st[0], st[1]); + if (buffer[24] == 0x08 && buffer[25] == 0x00 && buffer[26] == 0x45) { + printk(KERN_DEBUG "%s: length: %d protocol: %d from: %d.%d.%d.%d:%d " + "to %d.%d.%d.%d:%d\n", name, buffer[28] << 8 | buffer[29], + buffer[35], buffer[38], buffer[39], buffer[40], buffer[41], + buffer[46] << 8 | buffer[47], + buffer[42], buffer[43], buffer[44], buffer[45], + buffer[48] << 8 | buffer[49]); + } else { + for (i = 0, k = 0; i < (size + 7) / 8; i++) { + printk(KERN_DEBUG "%s: %s", name, i ? " " : "buffer:"); + for (j = 0; j < 8 && k < size; j++, k++) + printk(" %02x", buffer[k]); + printk("\n"); + } + } + return; +} + +/* + * SB1000 commands for frame rx interrupt + */ +/* receive a single frame and assemble datagram + * (this is the heart of the interrupt routine) + */ +static inline int +sb1000_rx(struct device *dev) +{ + +#define FRAMESIZE 184 + unsigned char st[2], buffer[FRAMESIZE], session_id, frame_id; + short dlen; + int ioaddr, ns; + unsigned int skbsize; + struct sk_buff *skb; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct enet_statistics *stats = &lp->stats; + + /* SB1000 frame constants */ + const int FrameSize = FRAMESIZE; + const int NewDatagramHeaderSkip = 8; + const int NewDatagramHeaderSize = NewDatagramHeaderSkip + 18; + const int NewDatagramDataSize = FrameSize - NewDatagramHeaderSize; + const int ContDatagramHeaderSkip = 7; + const int ContDatagramHeaderSize = ContDatagramHeaderSkip + 1; + const int ContDatagramDataSize = FrameSize - ContDatagramHeaderSize; + const int TrailerSize = 4; + + ioaddr = dev->base_addr; + + insw(ioaddr, (unsigned short*) st, 1); +#ifdef XXXDEBUG +printk("cm0: received: %02x %02x\n", st[0], st[1]); +#endif /* XXXDEBUG */ + lp->rx_frames++; + + /* decide if it is a good or bad frame */ + for (ns = 0; ns < NPIDS; ns++) { + session_id = lp->rx_session_id[ns]; + frame_id = lp->rx_frame_id[ns]; + if (st[0] == session_id) { + if (st[1] == frame_id || (!frame_id && (st[1] & 0xf0) == 0x30)) { + goto good_frame; + } else if ((st[1] & 0xf0) == 0x30 && (st[0] & 0x40)) { + goto skipped_frame; + } else { + goto bad_frame; + } + } else if (st[0] == (session_id | 0x40)) { + if ((st[1] & 0xf0) == 0x30) { + goto skipped_frame; + } else { + goto bad_frame; + } + } + } + goto bad_frame; + +skipped_frame: + stats->rx_frame_errors++; + skb = lp->rx_skb[ns]; + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: missing frame(s): got %02x %02x " + "expecting %02x %02x\n", dev->name, st[0], st[1], + skb ? session_id : session_id | 0x40, frame_id); + if (skb) { + dev_kfree_skb(skb); + skb = 0; + } + +good_frame: + lp->rx_frame_id[ns] = 0x30 | ((st[1] + 1) & 0x0f); + /* new datagram */ + if (st[0] & 0x40) { + /* get data length */ + insw(ioaddr, buffer, NewDatagramHeaderSize / 2); +#ifdef XXXDEBUG +printk("cm0: IP identification: %02x%02x fragment offset: %02x%02x\n", buffer[30], buffer[31], buffer[32], buffer[33]); +#endif /* XXXDEBUG */ + if (buffer[0] != NewDatagramHeaderSkip) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: new datagram header skip error: " + "got %02x expecting %02x\n", dev->name, buffer[0], + NewDatagramHeaderSkip); + stats->rx_length_errors++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto bad_frame_next; + } + dlen = ((buffer[NewDatagramHeaderSkip + 3] & 0x0f) << 8 | + buffer[NewDatagramHeaderSkip + 4]) - 17; + if (dlen > SB1000_MRU) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: datagram length (%d) greater " + "than MRU (%d)\n", dev->name, dlen, SB1000_MRU); + stats->rx_length_errors++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto bad_frame_next; + } + lp->rx_dlen[ns] = dlen; + /* compute size to allocate for datagram */ + skbsize = dlen + FrameSize; + if ((skb = alloc_skb(skbsize, GFP_ATOMIC)) == NULL) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: can't allocate %d bytes long " + "skbuff\n", dev->name, skbsize); + stats->rx_dropped++; + insw(ioaddr, buffer, NewDatagramDataSize / 2); + goto dropped_frame; + } + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = (unsigned short) buffer[NewDatagramHeaderSkip + 16]; + insw(ioaddr, skb_put(skb, NewDatagramDataSize), + NewDatagramDataSize / 2); + lp->rx_skb[ns] = skb; + } else { + /* continuation of previous datagram */ + insw(ioaddr, buffer, ContDatagramHeaderSize / 2); + if (buffer[0] != ContDatagramHeaderSkip) { + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: cont datagram header skip error: " + "got %02x expecting %02x\n", dev->name, buffer[0], + ContDatagramHeaderSkip); + stats->rx_length_errors++; + insw(ioaddr, buffer, ContDatagramDataSize / 2); + goto bad_frame_next; + } + skb = lp->rx_skb[ns]; + insw(ioaddr, skb_put(skb, ContDatagramDataSize), + ContDatagramDataSize / 2); + dlen = lp->rx_dlen[ns]; + } + if (skb->len < dlen + TrailerSize) { + lp->rx_session_id[ns] &= ~0x40; + return 0; + } + + /* datagram completed: send to upper level */ + skb_trim(skb, dlen); + netif_rx(skb); + stats->rx_packets++; + lp->rx_bytes += dlen; + lp->rx_skb[ns] = 0; + lp->rx_session_id[ns] |= 0x40; + return 0; + +bad_frame: + insw(ioaddr, buffer, FrameSize / 2); + if (sb1000_debug > 1) + printk(KERN_WARNING "%s: frame error: got %02x %02x\n", + dev->name, st[0], st[1]); + stats->rx_frame_errors++; +bad_frame_next: + if (sb1000_debug > 2) + sb1000_print_status_buffer(dev->name, st, buffer, FrameSize); +dropped_frame: + stats->rx_errors++; + if (ns < NPIDS) { + if ((skb = lp->rx_skb[ns])) { + dev_kfree_skb(skb); + lp->rx_skb[ns] = 0; + } + lp->rx_session_id[ns] |= 0x40; + } + return -1; +} + +static inline void +sb1000_error_dpc(struct device *dev) +{ + char *name; + unsigned char st[5]; + int ioaddr[2]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + const unsigned char Command0[6] = {0x80, 0x26, 0x00, 0x00, 0x00, 0x00}; + const int ErrorDpcCounterInitialize = 200; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command0); + sb1000_wait_for_ready(ioaddr, name); + sb1000_read_status(ioaddr, st); + if (st[1] & 0x10) + lp->rx_error_dpc_count = ErrorDpcCounterInitialize; + return; +} + + +/* + * Linux interface functions + */ +static int +sb1000_open(struct device *dev) +{ + char *name; + int ioaddr[2], status; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + const unsigned short FirmwareVersion[] = {0x01, 0x01}; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + request_region(ioaddr[0], SB1000_IO_EXTENT, "sb1000"); + request_region(ioaddr[1], SB1000_IO_EXTENT, "sb1000"); + + /* initialize sb1000 */ + if ((status = sb1000_reset(ioaddr, name))) + return status; + nicedelay(200000); + if ((status = sb1000_check_CRC(ioaddr, name))) + return status; + + /* initialize private data before board can catch interrupts */ + lp->rx_skb[0] = NULL; + lp->rx_skb[1] = NULL; + lp->rx_skb[2] = NULL; + lp->rx_skb[3] = NULL; + lp->rx_dlen[0] = 0; + lp->rx_dlen[1] = 0; + lp->rx_dlen[2] = 0; + lp->rx_dlen[3] = 0; + lp->rx_bytes = 0; + lp->rx_frames = 0; + lp->rx_error_count = 0; + lp->rx_error_dpc_count = 0; + lp->rx_session_id[0] = 0x50; + lp->rx_session_id[0] = 0x48; + lp->rx_session_id[0] = 0x44; + lp->rx_session_id[0] = 0x42; + lp->rx_frame_id[0] = 0; + lp->rx_frame_id[1] = 0; + lp->rx_frame_id[2] = 0; + lp->rx_frame_id[3] = 0; + if (request_irq(dev->irq, &sb1000_interrupt, 0, "sb1000", dev)) { + return -EAGAIN; + } + + if (sb1000_debug > 2) + printk(KERN_DEBUG "%s: Opening, IRQ %d\n", name, dev->irq); + + /* Activate board and check firmware version */ + udelay(1000); + if ((status = sb1000_activate(ioaddr, name))) + return status; + udelay(0); + if ((status = sb1000_get_firmware_version(ioaddr, name, version, 0))) + return status; + if (version[0] != FirmwareVersion[0] || version[1] != FirmwareVersion[1]) + printk(KERN_WARNING "%s: found firmware version %x.%02x " + "(should be %x.%02x)\n", name, version[0], version[1], + FirmwareVersion[0], FirmwareVersion[1]); + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + + MOD_INC_USE_COUNT; + return 0; /* Always succeed */ +} + +static int sb1000_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) +{ + char* name; + unsigned char version[2]; + short PID[4]; + int ioaddr[2], status, frequency; + unsigned int stats[5]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + if (!(dev && dev->flags & IFF_UP)) + return -ENODEV; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + switch (cmd) { + case SIOCGCMSTATS: /* get statistics */ + stats[0] = lp->rx_bytes; + stats[1] = lp->rx_frames; + stats[2] = lp->stats.rx_packets; + stats[3] = lp->stats.rx_errors; + stats[4] = lp->stats.rx_dropped; + if(copy_to_user(ifr->ifr_data, stats, sizeof(stats))) + return -EFAULT; + status = 0; + break; + + case SIOCGCMFIRMWARE: /* get firmware version */ + if ((status = sb1000_get_firmware_version(ioaddr, name, version, 1))) + return status; + if(copy_to_user(ifr->ifr_data, version, sizeof(version))) + return -EFAULT; + break; + + case SIOCGCMFREQUENCY: /* get frequency */ + if ((status = sb1000_get_frequency(ioaddr, name, &frequency))) + return status; + if(put_user(frequency, (int*) ifr->ifr_data)) + return -EFAULT; + break; + + case SIOCSCMFREQUENCY: /* set frequency */ + if (!suser()) + return -EPERM; + if(get_user(frequency, (int*) ifr->ifr_data)) + return -EFAULT; + if ((status = sb1000_set_frequency(ioaddr, name, frequency))) + return status; + break; + + case SIOCGCMPIDS: /* get PIDs */ + if ((status = sb1000_get_PIDs(ioaddr, name, PID))) + return status; + if(copy_to_user(ifr->ifr_data, PID, sizeof(PID))) + return -EFAULT; + break; + + case SIOCSCMPIDS: /* set PIDs */ + if (!suser()) + return -EPERM; + if(copy_from_user(PID, ifr->ifr_data, sizeof(PID))) + return -EFAULT; + if ((status = sb1000_set_PIDs(ioaddr, name, PID))) + return status; + /* set session_id, frame_id and pkt_type too */ + lp->rx_session_id[0] = 0x50 | (PID[0] & 0x0f); + lp->rx_session_id[1] = 0x48; + lp->rx_session_id[2] = 0x44; + lp->rx_session_id[3] = 0x42; + lp->rx_frame_id[0] = 0; + lp->rx_frame_id[1] = 0; + lp->rx_frame_id[2] = 0; + lp->rx_frame_id[3] = 0; + break; + + default: + status = -EINVAL; + break; + } + return status; +} + +/* transmit function: do nothing since SB1000 can't send anything out */ +static int +sb1000_start_xmit(struct sk_buff *skb, struct device *dev) +{ + printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name); + /* sb1000 can't xmit datagrams */ + dev_kfree_skb(skb); + return 0; +} + +/* SB1000 interrupt handler. */ +static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char *name; + unsigned char st; + int ioaddr[2]; + struct device *dev = (struct device *) dev_id; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00}; + const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; + const int MaxRxErrorCount = 6; + + if (dev == NULL) { + printk(KERN_ERR "sb1000_interrupt(): irq %d for unknown device.\n", + irq); + return; + } + if (dev->interrupt) + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", + dev->name); + dev->interrupt = 1; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + name = dev->name; + + /* is it a good interrupt? */ + st = inb(ioaddr[1] + 6); + if (!(st & 0x08 && st & 0x20)) { + dev->interrupt = 0; + return; + } + + if (sb1000_debug > 3) + printk(KERN_DEBUG "%s: entering interrupt\n", dev->name); + + st = inb(ioaddr[0] + 7); + if (sb1000_rx(dev)) + lp->rx_error_count++; +#ifdef SB1000_DELAY + udelay(SB1000_DELAY); +#endif /* SB1000_DELAY */ + sb1000_issue_read_command(ioaddr, name); + if (st & 0x01) { + sb1000_error_dpc(dev); + sb1000_issue_read_command(ioaddr, name); + } + if (lp->rx_error_dpc_count && !(--lp->rx_error_dpc_count)) { + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command0); + sb1000_wait_for_ready(ioaddr, name); + sb1000_issue_read_command(ioaddr, name); + } + if (lp->rx_error_count >= MaxRxErrorCount) { + sb1000_wait_for_ready_clear(ioaddr, name); + sb1000_send_command(ioaddr, name, Command1); + sb1000_wait_for_ready(ioaddr, name); + sb1000_issue_read_command(ioaddr, name); + lp->rx_error_count = 0; + } + + dev->interrupt = 0; + return; +} + +static struct net_device_stats *sb1000_stats(struct device *dev) +{ + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + return &lp->stats; +} + +static int sb1000_close(struct device *dev) +{ + int i; + int ioaddr[2]; + struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + + if (sb1000_debug > 2) + printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name); + + dev->tbusy = 1; + dev->start = 0; + + ioaddr[0] = dev->base_addr; + /* rmem_end holds the second I/O address - fv */ + ioaddr[1] = dev->rmem_end; + + free_irq(dev->irq, dev); + /* If we don't do this, we can't re-insmod it later. */ + release_region(ioaddr[1], SB1000_IO_EXTENT); + release_region(ioaddr[0], SB1000_IO_EXTENT); + + /* free rx_skb's if needed */ + for (i=0; i<4; i++) { + if (lp->rx_skb[i]) { + dev_kfree_skb(lp->rx_skb[i]); + } + } + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE +MODULE_AUTHOR("Franco Venturi "); +MODULE_DESCRIPTION("General Instruments SB1000 driver"); +MODULE_PARM(io, "1-2i"); +MODULE_PARM(irq, "i"); + +static char devname[8] = {0, }; +static struct device dev_sb1000 = { + devname, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, sb1000_probe }; + +static int io[2] = {0, 0}; +static int irq = 0; + +int +init_module(void) +{ + int i; + for (i = 0; i < 100; i++) { + sprintf(devname, "cm%d", i); + if (dev_get(devname) == NULL) break; + } + if (i == 100) { + printk(KERN_ERR "sb1000: can't register any device cm\n"); + return -ENFILE; + } + dev_sb1000.base_addr = io[0]; + /* rmem_end holds the second I/O address - fv */ + dev_sb1000.rmem_end = io[1]; + dev_sb1000.irq = irq; + if (register_netdev(&dev_sb1000) != 0) { + printk(KERN_ERR "sb1000: failed to register device (io: %03x,%03x " + "irq: %d)\n", io[0], io[1], irq); + return -EIO; + } + return 0; +} + +void cleanup_module(void) +{ + unregister_netdev(&dev_sb1000); + kfree_s(dev_sb1000.priv, sizeof(struct sb1000_private)); + dev_sb1000.priv = NULL; +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -DMODULE -Wall -Wstrict-prototypes -O -m486 -c sb1000.c" + * version-control: t + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/sbus/audio/cs4231.c linux.pre11.6/drivers/sbus/audio/cs4231.c --- linux.pre11.5/drivers/sbus/audio/cs4231.c Fri Aug 6 18:51:11 1999 +++ linux.pre11.6/drivers/sbus/audio/cs4231.c Sat Aug 7 21:25:17 1999 @@ -1421,7 +1421,7 @@ status += 2; } - sparcaudio_input_done(drv, 1); + sparcaudio_input_done(drv, status); return 1; } @@ -1484,26 +1484,23 @@ cs4231_chip->perchip_info.play.active = 1; cs4231_chip->playing_count = 0; + cs4231_playintr(drv); if ((cs4231_chip->regs->dmacsr & APC_PPAUSE) || !(cs4231_chip->regs->dmacsr & APC_PDMA_READY)) { - cs4231_chip->regs->dmacsr &= ~APC_XINT_PLAY; - cs4231_chip->regs->dmacsr &= ~APC_PPAUSE; - - cs4231_playintr(drv); - - cs4231_chip->regs->dmacsr |= APC_PLAY_SETUP; + cs4231_chip->regs->dmacsr &= ~(APC_XINT_PLAY | APC_PPAUSE); + cs4231_chip->regs->dmacsr |= APC_GENL_INT | APC_XINT_ENA | APC_XINT_PLAY + | APC_XINT_GENL | APC_XINT_PENA | APC_PDMA_READY; cs4231_enable_play(drv); - + cs4231_ready(drv); - } else - cs4231_playintr(drv); + } } #ifdef EB4231_SUPPORT static void eb4231_stop_output(struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - int dcsr; + unsigned int dcsr; dprintk(("eb4231_stop_output: dcsr 0x%x dacr 0x%x dbcr %d\n", readl(&cs4231_chip->eb2p->dcsr), @@ -1547,8 +1544,11 @@ cs4231_chip->output_next_dma_handle = 0; cs4231_chip->output_next_dma_size = 0; } -#if 0 /* Not safe without shutting off the DMA controller as well. -DaveM */ +#if 1 /* Not safe without shutting off the DMA controller as well. -DaveM */ /* Else subsequent speed setting changes are ignored by the chip. */ + cs4231_chip->regs->dmacsr &= ~(APC_GENL_INT | APC_XINT_ENA | APC_XINT_PLAY + | APC_XINT_GENL | APC_PDMA_READY + | APC_XINT_PENA ); cs4231_disable_play(drv); #endif } @@ -1635,6 +1635,68 @@ cs4231_pollinput(drv); } +#ifdef EB4231_SUPPORT +static void eb4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer, + unsigned long count) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + unsigned int dcsr; + + cs4231_chip->input_ptr = buffer; + cs4231_chip->input_size = count; + + if (cs4231_chip->perchip_info.record.active || + (cs4231_chip->perchip_info.record.pause)) + return; + + cs4231_ready(drv); + + cs4231_chip->perchip_info.record.active = 1; + cs4231_chip->recording_count = 0; + + dcsr = readl(&cs4231_chip->eb2c->dcsr); + if (!(dcsr & EBUS_DCSR_EN_DMA)) { + writel(EBUS_DCSR_RESET, &(cs4231_chip->eb2c->dcsr)); + writel(EBUS_DCSR_BURST_SZ_16, &(cs4231_chip->eb2c->dcsr)); + + eb4231_recintr(drv); + + writel(EBUS_DCSR_BURST_SZ_16 | + (EBUS_DCSR_EN_DMA | EBUS_DCSR_INT_EN | EBUS_DCSR_EN_CNT | EBUS_DCSR_EN_NEXT), + &(cs4231_chip->eb2c->dcsr)); + + cs4231_enable_rec(drv); + cs4231_ready(drv); + } else + eb4231_recintr(drv); +} + +static void eb4231_stop_input(struct sparcaudio_driver *drv) +{ + struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; + unsigned int dcsr; + + cs4231_chip->perchip_info.record.active = 0; + + cs4231_chip->input_ptr = NULL; + cs4231_chip->input_size = 0; + if (cs4231_chip->input_dma_handle) { + cs4231_chip->input_dma_handle = 0; + cs4231_chip->input_dma_size = 0; + } + if (cs4231_chip->input_next_dma_handle) { + cs4231_chip->input_next_dma_handle = 0; + cs4231_chip->input_next_dma_size = 0; + } + + dcsr = readl(&(cs4231_chip->eb2c->dcsr)); + if (dcsr & EBUS_DCSR_EN_DMA) + writel(dcsr & ~EBUS_DCSR_EN_DMA, &(cs4231_chip->eb2c->dcsr)); + + cs4231_disable_rec(drv); +} +#endif + static int cs4231_set_output_pause(struct sparcaudio_driver *drv, int value) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; @@ -1763,13 +1825,25 @@ struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; int dummy; - /* Read status. */ - dummy = readl(&cs4231_chip->eb2c->dcsr); + /* Clear the interrupt. */ + dummy = readl(&(cs4231_chip->eb2c->dcsr)); + writel(dummy, &(cs4231_chip->eb2c->dcsr)); - cs4231_chip->perchip_info.record.samples += - cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), - cs4231_chip->reclen); - eb4231_recintr(drv); + if ((dummy & EBUS_DCSR_TC) != 0 + /*&& (dummy & EBUS_DCSR_A_LOADED) != 0*/) { + cs4231_chip->perchip_info.record.samples += + cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), + cs4231_chip->reclen); + eb4231_recintr(drv); + } + + if ((dummy & EBUS_DCSR_A_LOADED) == 0) { + cs4231_chip->perchip_info.record.active = 0; + eb4231_recintr(drv); +#if 1 + eb4231_getsamplecount(drv, cs4231_chip->reclen, 1); +#endif + } } /* ebus audio play interrupt handler. */ @@ -1823,7 +1897,7 @@ */ if (dummy & APC_PLAY_INT) { - if (dummy & APC_XINT_PNVA) { + if (dummy & APC_XINT_PEMP) { cs4231_chip->perchip_info.play.samples += cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), cs4231_chip->playlen); @@ -1937,8 +2011,8 @@ cs4231_ioctl, eb4231_start_output, eb4231_stop_output, - cs4231_start_input, - cs4231_stop_input, + eb4231_start_input, + eb4231_stop_input, cs4231_audio_getdev, cs4231_set_output_volume, cs4231_get_output_volume, diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/sbus/char/bpp.c linux.pre11.6/drivers/sbus/char/bpp.c --- linux.pre11.5/drivers/sbus/char/bpp.c Fri Aug 6 18:51:10 1999 +++ linux.pre11.6/drivers/sbus/char/bpp.c Sat Aug 7 21:25:17 1999 @@ -149,18 +149,18 @@ */ 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) */ + __volatile__ __u32 p_csr; /* DMA Control/Status Register */ + __volatile__ __u32 p_addr; /* Address Register */ + __volatile__ __u32 p_bcnt; /* Byte Count Register */ + __volatile__ __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 */ + __volatile__ __u16 p_hcr; /* Hardware Configuration Register */ + __volatile__ __u16 p_ocr; /* Operation Configuration Register */ + __volatile__ __u8 p_dr; /* Parallel Data Register */ + __volatile__ __u8 p_tcr; /* Transfer Control Register */ + __volatile__ __u8 p_or; /* Output Register */ + __volatile__ __u8 p_ir; /* Input Register */ + __volatile__ __u16 p_icr; /* Interrupt Control Register */ }; /* P_CSR. Bits of type RW1 are cleared with writting '1'. */ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/drivers/video/atyfb.c linux.pre11.6/drivers/video/atyfb.c --- linux.pre11.5/drivers/video/atyfb.c Fri Aug 6 18:51:14 1999 +++ linux.pre11.6/drivers/video/atyfb.c Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.106.2.1 1999/06/22 06:28:23 paulus Exp $ +/* $Id: atyfb.c,v 1.106.2.2 1999/08/07 10:49:25 davem Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/fs/coda/cache.c linux.pre11.6/fs/coda/cache.c --- linux.pre11.5/fs/coda/cache.c Fri Aug 6 18:51:23 1999 +++ linux.pre11.6/fs/coda/cache.c Sat Aug 7 21:24:33 1999 @@ -65,7 +65,7 @@ if ( ! list_empty(&el->cc_cclist) ) list_del(&el->cc_cclist); else - printk("coda_cnremove: loose cc entry!"); + printk("coda_ccremove: loose cc entry!"); } /* remove a cache entry from the inode's list */ @@ -139,7 +139,7 @@ /* remove all cached acl matches from an inode */ void coda_cache_clear_inode(struct inode *inode) { - struct list_head *lh, *le; + struct list_head *le; struct coda_inode_info *cii; struct coda_cache *cc; ENTRY; @@ -150,9 +150,10 @@ } cii = ITOC(inode); - lh = le = &cii->c_cnhead; - while ( (le = le->next ) != lh ) { + le = cii->c_cnhead.next; + while ( le != &cii->c_cnhead ) { cc = list_entry(le, struct coda_cache, cc_cnlist); + le = le->next; coda_cnremove(cc); coda_ccremove(cc); CODA_FREE(cc, sizeof(*cc)); @@ -162,7 +163,7 @@ /* remove all acl caches */ void coda_cache_clear_all(struct super_block *sb) { - struct list_head *lh, *le; + struct list_head *le; struct coda_cache *cc; struct coda_sb_info *sbi = coda_sbp(sb); @@ -174,9 +175,10 @@ if ( list_empty(&sbi->sbi_cchead) ) return; - lh = le = &sbi->sbi_cchead; - while ( (le = le->next ) != lh ) { + le = sbi->sbi_cchead.next; + while ( le != &sbi->sbi_cchead ) { cc = list_entry(le, struct coda_cache, cc_cclist); + le = le->next; coda_cnremove(cc); coda_ccremove(cc); CODA_FREE(cc, sizeof(*cc)); @@ -186,7 +188,7 @@ /* remove all acl caches for a principal */ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) { - struct list_head *lh, *le; + struct list_head *le; struct coda_cache *cc; struct coda_sb_info *sbi = coda_sbp(sb); @@ -198,9 +200,10 @@ if (list_empty(&sbi->sbi_cchead)) return; - lh = le = &sbi->sbi_cchead; - while ( (le = le->next ) != lh ) { + le = sbi->sbi_cchead.next; + while ( le != &sbi->sbi_cchead ) { cc = list_entry(le, struct coda_cache, cc_cclist); + le = le->next; if ( coda_cred_eq(&cc->cc_cred, cred)) { coda_cnremove(cc); coda_ccremove(cc); diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/fs/coda/cnode.c linux.pre11.6/fs/coda/cnode.c --- linux.pre11.5/fs/coda/cnode.c Fri Aug 6 18:51:23 1999 +++ linux.pre11.6/fs/coda/cnode.c Sat Aug 7 21:24:33 1999 @@ -120,10 +120,10 @@ if ( coda_f2i(fid) != ino ) { if ( !coda_fid_is_weird(fid) ) printk("Coda: unknown weird fid: ino %ld, fid %s." - "Tell Peter.\n", ino, coda_f2s(&cnp->c_fid)); + "Tell Peter.\n", (long)ino, coda_f2s(&cnp->c_fid)); list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead); CDEBUG(D_UPCALL, "Added %ld ,%s to volroothead\n", - ino, coda_f2s(&cnp->c_fid)); + (long)ino, coda_f2s(&cnp->c_fid)); } coda_fill_inode(*inode, &attr); @@ -211,7 +211,7 @@ inode = iget(sb, nr); if ( !inode ) { printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n", - sb, nr); + sb, (long)nr); return NULL; } diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/fs/coda/dir.c linux.pre11.6/fs/coda/dir.c --- linux.pre11.5/fs/coda/dir.c Fri Aug 6 18:51:23 1999 +++ linux.pre11.6/fs/coda/dir.c Sat Aug 7 21:24:33 1999 @@ -124,12 +124,12 @@ if ( length > CODA_MAXNAMLEN ) { printk("name too long: lookup, %s (%*s)\n", - coda_f2s(&dircnp->c_fid), length, name); + coda_f2s(&dircnp->c_fid), (int)length, name); return ERR_PTR(-ENAMETOOLONG); } - CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n", - name, length, dir->i_ino, coda_f2s(&dircnp->c_fid)); + CDEBUG(D_INODE, "name %s, len %ld in ino %ld, fid %s\n", + name, (long)length, dir->i_ino, coda_f2s(&dircnp->c_fid)); /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { @@ -156,7 +156,7 @@ return ERR_PTR(error); } else if (error != -ENOENT) { CDEBUG(D_INODE, "error for %s(%*s)%d\n", - coda_f2s(&dircnp->c_fid), length, name, error); + coda_f2s(&dircnp->c_fid), (int)length, name, error); return ERR_PTR(error); } CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n", @@ -503,10 +503,10 @@ old_cnp = ITOC(old_dir); new_cnp = ITOC(new_dir); - CDEBUG(D_INODE, "old: %s, (%d length, %d strlen), new: %s" - "(%d length, %d strlen).old:d_count: %d, new:d_count: %d\n", - old_name, old_length, strlen(old_name), new_name, new_length, - strlen(new_name),old_dentry->d_count, new_dentry->d_count); + CDEBUG(D_INODE, "old: %s, (%d length, %ld strlen), new: %s" + "(%d length, %ld strlen).old:d_count: %d, new:d_count: %d\n", + old_name, old_length, (long)strlen(old_name), new_name, new_length, + (long)strlen(new_name),old_dentry->d_count, new_dentry->d_count); /* the C library will do unlink/create etc */ if ( coda_crossvol_rename == 0 && @@ -593,12 +593,12 @@ error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev); if (error) { CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n", - dev, ino, error); + dev, (long)ino, error); return error; } /* coda_upcall returns ino number of cached object, get inode */ - CDEBUG(D_FILE, "cache file dev %d, ino %ld\n", dev, ino); + CDEBUG(D_FILE, "cache file dev %d, ino %ld\n", dev, (long)ino); error = coda_inode_grab(dev, ino, &cont_inode); if ( error || !cont_inode ){ @@ -621,9 +621,9 @@ CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n", error, i->i_count, i->i_ino); - CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %x\n", + CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", cnp->c_ovp->i_ino, cnp->c_ovp->i_count, - (int)(cnp->c_ovp->i_op)); + (cnp->c_ovp->i_op)); EXIT; return 0; } diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/fs/coda/file.c linux.pre11.6/fs/coda/file.c --- linux.pre11.5/fs/coda/file.c Fri Aug 6 18:51:23 1999 +++ linux.pre11.6/fs/coda/file.c Sat Aug 7 21:24:33 1999 @@ -155,8 +155,8 @@ result = cont_file.f_op->read(&cont_file , buff, count, &(cont_file.f_pos)); - CDEBUG(D_FILE, "ops at %x result %d, count %d, position: %d\n", - (int)cont_file.f_op, result, count, (int)cont_file.f_pos); + CDEBUG(D_FILE, "ops at %p result %d, count %ld, position: %d\n", + cont_file.f_op, result, (long)count, (int)cont_file.f_pos); coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file); return result; @@ -292,10 +292,10 @@ if ( *ind == NULL ) { printk("coda_inode_grab: iget(dev: %d, ino: %ld) - returns NULL.\n", dev, ino); + returns NULL.\n", dev, (long)ino); return -ENOENT; } - CDEBUG(D_FILE, "ino: %ld, ops at %x\n", ino, (int)(*ind)->i_op); + CDEBUG(D_FILE, "ino: %ld, ops at %p\n", (long)ino, (*ind)->i_op); return 0; } diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/fs/coda/inode.c linux.pre11.6/fs/coda/inode.c --- linux.pre11.5/fs/coda/inode.c Fri Aug 6 18:51:23 1999 +++ linux.pre11.6/fs/coda/inode.c Sat Aug 7 21:24:33 1999 @@ -205,7 +205,7 @@ coda_cache_clear_inode(inode); CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags); - inode->u.generic_ip = NULL; + inode->u.coda_i.c_magic = 0; clear_inode(inode); EXIT; } diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/fs/coda/psdev.c linux.pre11.6/fs/coda/psdev.c --- linux.pre11.5/fs/coda/psdev.c Fri Aug 6 18:51:23 1999 +++ linux.pre11.6/fs/coda/psdev.c Sat Aug 7 21:24:33 1999 @@ -98,8 +98,8 @@ if (copy_from_user(&hdr, buf, 2 * sizeof(u_long))) return -EFAULT; - CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %d\n", - current->pid, hdr.opcode, hdr.unique, count); + CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %ld\n", + current->pid, hdr.opcode, hdr.unique, (long)count); if (DOWNCALL(hdr.opcode)) { struct super_block *sb = NULL; @@ -160,8 +160,8 @@ /* move data into response buffer. */ if (req->uc_outSize < count) { - printk("psdev_write: too much cnt: %d, cnt: %d, opc: %ld, uniq: %ld.\n", - req->uc_outSize, count, hdr.opcode, hdr.unique); + printk("psdev_write: too much cnt: %d, cnt: %ld, opc: %ld, uniq: %ld.\n", + req->uc_outSize, (long)count, hdr.opcode, hdr.unique); count = req->uc_outSize; /* don't have more space! */ } if (copy_from_user(req->uc_data, buf, count)) @@ -172,8 +172,8 @@ req->uc_flags |= REQ_WRITE; CDEBUG(D_PSDEV, - "Found! Count %d for (opc,uniq)=(%ld,%ld), upc_req at %x\n", - count, hdr.opcode, hdr.unique, (int)&req); + "Found! Count %ld for (opc,uniq)=(%ld,%ld), upc_req at %p\n", + (long)count, hdr.opcode, hdr.unique, &req); wake_up(&req->uc_sleep); return(count); @@ -190,7 +190,7 @@ struct upc_req *req; int result = count ; - CDEBUG(D_PSDEV, "count %d\n", count); + CDEBUG(D_PSDEV, "count %ld\n", (long)count); if (list_empty(&(vcp->vc_pending))) { return -1; } @@ -203,8 +203,8 @@ result = req->uc_inSize; if (count < req->uc_inSize) { - printk ("psdev_read: Venus read %d bytes of %d in message\n", - count, req->uc_inSize); + printk ("psdev_read: Venus read %ld bytes of %d in message\n", + (long)count, req->uc_inSize); } if ( copy_to_user(buf, req->uc_data, result)) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/fs/coda/upcall.c linux.pre11.6/fs/coda/upcall.c --- linux.pre11.5/fs/coda/upcall.c Fri Aug 6 18:51:23 1999 +++ linux.pre11.6/fs/coda/upcall.c Sat Aug 7 21:24:33 1999 @@ -710,8 +710,8 @@ /* Append msg to pending queue and poke Venus. */ list_add(&(req->uc_chain), vcommp->vc_pending.prev); CDEBUG(D_UPCALL, - "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %x.zzz.\n", - current->pid, req->uc_opcode, req->uc_unique, (int)req); + "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n", + current->pid, req->uc_opcode, req->uc_unique, req); wake_up_interruptible(&vcommp->vc_waitq); /* We can be interrupted while we wait for Venus to process @@ -731,8 +731,8 @@ req->uc_opcode, jiffies - req->uc_posttime, req->uc_unique, req->uc_outSize); CDEBUG(D_UPCALL, - "..process %d woken up by Venus for req at 0x%x, data at %x\n", - current->pid, (int)req, (int)req->uc_data); + "..process %d woken up by Venus for req at %p, data at %p\n", + current->pid, req, req->uc_data); if (vcommp->vc_pid) { /* i.e. Venus is still alive */ /* Op went through, interrupt or not... */ if (req->uc_flags & REQ_WRITE) { diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/asm-sparc/keyboard.h linux.pre11.6/include/asm-sparc/keyboard.h --- linux.pre11.5/include/asm-sparc/keyboard.h Fri Aug 6 18:51:40 1999 +++ linux.pre11.6/include/asm-sparc/keyboard.h Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: keyboard.h,v 1.2 1999/04/28 11:59:07 davem Exp $ +/* $Id: keyboard.h,v 1.2.2.1 1999/08/07 10:52:45 davem Exp $ * linux/include/asm-sparc/keyboard.h * * sparc64 Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/asm-sparc/pgtable.h linux.pre11.6/include/asm-sparc/pgtable.h --- linux.pre11.5/include/asm-sparc/pgtable.h Fri Aug 6 18:51:39 1999 +++ linux.pre11.6/include/asm-sparc/pgtable.h Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.78 1999/01/07 14:14:05 jj Exp $ */ +/* $Id: pgtable.h,v 1.78.2.1 1999/08/07 10:52:48 davem Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/asm-sparc/socket.h linux.pre11.6/include/asm-sparc/socket.h --- linux.pre11.5/include/asm-sparc/socket.h Fri Aug 6 18:51:39 1999 +++ linux.pre11.6/include/asm-sparc/socket.h Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: socket.h,v 1.12 1998/07/22 22:06:48 davem Exp $ */ +/* $Id: socket.h,v 1.12.2.1 1999/08/07 10:52:51 davem Exp $ */ #ifndef _ASM_SOCKET_H #define _ASM_SOCKET_H diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/asm-sparc64/floppy.h linux.pre11.6/include/asm-sparc64/floppy.h --- linux.pre11.5/include/asm-sparc64/floppy.h Fri Aug 6 18:51:43 1999 +++ linux.pre11.6/include/asm-sparc64/floppy.h Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: floppy.h,v 1.18 1999/03/21 10:51:38 davem Exp $ +/* $Id: floppy.h,v 1.18.2.1 1999/08/03 08:00:20 davem Exp $ * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -548,6 +548,7 @@ #ifdef CONFIG_PCI struct linux_ebus *ebus; struct linux_ebus_device *edev = 0; + unsigned long auxio_reg; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { @@ -575,6 +576,12 @@ sun_fdc = (struct sun_flpy_controller *)edev->base_address[0]; FLOPPY_IRQ = edev->irqs[0]; + + /* Make sure the high density bit is set, some systems + * (most notably Ultra5/Ultra10) come up with it clear. + */ + auxio_reg = edev->base_address[2]; + writel(readl(auxio_reg)|0x2, auxio_reg); sun_pci_fd_ebus_dma = (struct linux_ebus_dma *) edev->base_address[1]; diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/asm-sparc64/pgtable.h linux.pre11.6/include/asm-sparc64/pgtable.h --- linux.pre11.5/include/asm-sparc64/pgtable.h Fri Aug 6 18:51:43 1999 +++ linux.pre11.6/include/asm-sparc64/pgtable.h Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.103 1999/03/28 08:40:04 davem Exp $ +/* $Id: pgtable.h,v 1.103.2.1 1999/08/07 10:52:55 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/asm-sparc64/socket.h linux.pre11.6/include/asm-sparc64/socket.h --- linux.pre11.5/include/asm-sparc64/socket.h Fri Aug 6 18:51:43 1999 +++ linux.pre11.6/include/asm-sparc64/socket.h Sat Aug 7 21:25:17 1999 @@ -1,4 +1,4 @@ -/* $Id: socket.h,v 1.5 1998/07/22 22:06:49 davem Exp $ */ +/* $Id: socket.h,v 1.5.2.1 1999/08/07 10:52:59 davem Exp $ */ #ifndef _ASM_SOCKET_H #define _ASM_SOCKET_H diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/linux/coda_fs_i.h linux.pre11.6/include/linux/coda_fs_i.h --- linux.pre11.5/include/linux/coda_fs_i.h Fri Aug 6 21:01:41 1999 +++ linux.pre11.6/include/linux/coda_fs_i.h Sat Aug 7 21:37:44 1999 @@ -20,6 +20,13 @@ * coda fs inode data */ struct coda_inode_info { + /* + * This is a place holder so named pipes work (more or less + * correctly). This must be first in the struct because the + * data is really accessed via inode->u.pipe_i. + */ + struct pipe_inode_info pipeinfo; + struct ViceFid c_fid; /* Coda identifier */ u_short c_flags; /* flags (see below) */ u_short c_ocount; /* count of openers */ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/linux/coda_linux.h linux.pre11.6/include/linux/coda_linux.h --- linux.pre11.5/include/linux/coda_linux.h Fri Aug 6 21:24:24 1999 +++ linux.pre11.6/include/linux/coda_linux.h Sat Aug 7 22:04:36 1999 @@ -113,10 +113,10 @@ do { \ if (size < 3000) { \ ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL); \ - CDEBUG(D_MALLOC, "kmalloced: %x at %x.\n", (int) size, (int) ptr);\ + CDEBUG(D_MALLOC, "kmalloced: %lx at %p.\n", (long)size, ptr);\ } else { \ ptr = (cast)vmalloc((unsigned long) size); \ - CDEBUG(D_MALLOC, "vmalloced: %x at %x.\n", (int) size, (int) ptr);}\ + CDEBUG(D_MALLOC, "vmalloced: %lx at %p .\n", (long)size, ptr);}\ if (ptr == 0) { \ printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \ } \ @@ -124,7 +124,7 @@ } while (0) -#define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %x at %x.\n", (int) size, (int) ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %x at %x.\n", (int) size, (int) ptr);} } while (0) +#define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %lx at %p.\n", (long) size, ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %lx at %p.\n", (long) size, ptr);} } while (0) /* inode to cnode */ diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/linux/if_cablemodem.h linux.pre11.6/include/linux/if_cablemodem.h --- linux.pre11.5/include/linux/if_cablemodem.h Thu Jan 1 01:00:00 1970 +++ linux.pre11.6/include/linux/if_cablemodem.h Fri Dec 11 02:16:43 1998 @@ -0,0 +1,22 @@ +#ifndef _LINUX_CABLEMODEM_H_ +#define _LINUX_CABLEMODEM_H_ +/* + * Author: Franco Venturi + * Copyright 1998 Franco Venturi + * + * 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. + */ + +/* some useful defines for sb1000.c e cmconfig.c - fv */ +#define SIOCGCMSTATS SIOCDEVPRIVATE+0 /* get cable modem stats */ +#define SIOCGCMFIRMWARE SIOCDEVPRIVATE+1 /* get cm firmware version */ +#define SIOCGCMFREQUENCY SIOCDEVPRIVATE+2 /* get cable modem frequency */ +#define SIOCSCMFREQUENCY SIOCDEVPRIVATE+3 /* set cable modem frequency */ +#define SIOCGCMPIDS SIOCDEVPRIVATE+4 /* get cable modem PIDs */ +#define SIOCSCMPIDS SIOCDEVPRIVATE+5 /* set cable modem PIDs */ + +#endif diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/include/net/pkt_cls.h linux.pre11.6/include/net/pkt_cls.h --- linux.pre11.5/include/net/pkt_cls.h Fri Aug 6 18:51:40 1999 +++ linux.pre11.6/include/net/pkt_cls.h Sat Aug 7 21:25:17 1999 @@ -79,9 +79,12 @@ extern __inline__ unsigned long cls_set_class(unsigned long *clp, unsigned long cl) { - cl = xchg(clp, cl); + unsigned long old_cl; + + old_cl = *clp; + *clp = cl; synchronize_bh(); - return cl; + return old_cl; } extern int register_tcf_proto_ops(struct tcf_proto_ops *ops); diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/kernel/fork.c linux.pre11.6/kernel/fork.c --- linux.pre11.5/kernel/fork.c Fri Aug 6 18:51:46 1999 +++ linux.pre11.6/kernel/fork.c Sat Aug 7 21:25:18 1999 @@ -610,7 +610,7 @@ { int i; p->has_cpu = 0; - p->processor = NO_PROC_ID; + p->processor = current->processor; /* ?? should we just memset this ?? */ for(i = 0; i < smp_num_cpus; i++) p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/af_inet.c linux.pre11.6/net/ipv4/af_inet.c --- linux.pre11.5/net/ipv4/af_inet.c Fri Aug 6 18:51:49 1999 +++ linux.pre11.6/net/ipv4/af_inet.c Sat Aug 7 21:25:18 1999 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.87.2.3 1999/07/01 10:43:51 davem Exp $ + * Version: $Id: af_inet.c,v 1.87.2.4 1999/07/23 15:29:19 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/devinet.c linux.pre11.6/net/ipv4/devinet.c --- linux.pre11.5/net/ipv4/devinet.c Fri Aug 6 20:41:53 1999 +++ linux.pre11.6/net/ipv4/devinet.c Sat Aug 7 21:25:18 1999 @@ -1,7 +1,7 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.28.2.1 1999/06/28 10:39:30 davem Exp $ + * Version: $Id: devinet.c,v 1.28.2.2 1999/08/07 10:56:18 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/igmp.c linux.pre11.6/net/ipv4/igmp.c --- linux.pre11.5/net/ipv4/igmp.c Fri Aug 6 18:51:50 1999 +++ linux.pre11.6/net/ipv4/igmp.c Sat Aug 7 21:25:18 1999 @@ -8,7 +8,7 @@ * the older version didn't come out right using gcc 2.5.8, the newer one * seems to fall out with gcc 2.6.2. * - * Version: $Id: igmp.c,v 1.30 1999/03/25 10:04:10 davem Exp $ + * Version: $Id: igmp.c,v 1.30.2.1 1999/07/23 15:29:22 davem Exp $ * * Authors: * Alan Cox @@ -242,7 +242,7 @@ /* Timers are only set for non-local groups */ - if (LOCAL_MCAST(group)) + if (group == IGMP_ALL_HOSTS) return; for (im=in_dev->mc_list; im!=NULL; im=im->next) { @@ -284,7 +284,7 @@ for (im=in_dev->mc_list; im!=NULL; im=im->next) { if (group && group != im->multiaddr) continue; - if (LOCAL_MCAST(im->multiaddr)) + if (im->multiaddr == IGMP_ALL_HOSTS) continue; im->unsolicit_count = 0; if (im->tm_running && (long)(im->timer.expires-jiffies) > max_delay) @@ -377,7 +377,7 @@ } #ifdef CONFIG_IP_MULTICAST - if (LOCAL_MCAST(im->multiaddr)) + if (im->multiaddr == IGMP_ALL_HOSTS) return; start_bh_atomic(); @@ -397,7 +397,7 @@ } #ifdef CONFIG_IP_MULTICAST - if (LOCAL_MCAST(im->multiaddr)) + if (im->multiaddr == IGMP_ALL_HOSTS) return; start_bh_atomic(); diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/ip_masq.c linux.pre11.6/net/ipv4/ip_masq.c --- linux.pre11.5/net/ipv4/ip_masq.c Fri Aug 6 18:51:51 1999 +++ linux.pre11.6/net/ipv4/ip_masq.c Sat Aug 7 21:25:18 1999 @@ -4,7 +4,7 @@ * * Copyright (c) 1994 Pauline Middelink * - * $Id: ip_masq.c,v 1.34.2.1 1999/07/02 10:10:00 davem Exp $ + * $Id: ip_masq.c,v 1.34.2.2 1999/08/07 10:56:28 davem Exp $ * * * See ip_fw.c for original log diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/ip_masq_user.c linux.pre11.6/net/ipv4/ip_masq_user.c --- linux.pre11.5/net/ipv4/ip_masq_user.c Fri Aug 6 18:51:52 1999 +++ linux.pre11.6/net/ipv4/ip_masq_user.c Sat Aug 7 21:25:18 1999 @@ -2,7 +2,7 @@ * IP_MASQ_USER user space control module * * - * $Id: ip_masq_user.c,v 1.1 1998/08/29 23:51:08 davem Exp $ + * $Id: ip_masq_user.c,v 1.1.2.1 1999/08/07 10:56:33 davem Exp $ */ #include diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/route.c linux.pre11.6/net/ipv4/route.c --- linux.pre11.5/net/ipv4/route.c Fri Aug 6 18:51:49 1999 +++ linux.pre11.6/net/ipv4/route.c Sat Aug 7 21:25:18 1999 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.67.2.1 1999/06/28 10:39:11 davem Exp $ + * Version: $Id: route.c,v 1.67.2.2 1999/07/23 15:29:26 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/tcp.c linux.pre11.6/net/ipv4/tcp.c --- linux.pre11.5/net/ipv4/tcp.c Fri Aug 6 18:51:49 1999 +++ linux.pre11.6/net/ipv4/tcp.c Sat Aug 7 21:25:18 1999 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.140.2.1 1999/05/29 04:16:48 davem Exp $ + * Version: $Id: tcp.c,v 1.140.2.2 1999/08/07 10:56:35 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1335,8 +1335,8 @@ if(copied >= 0 && msg->msg_name) { tp->af_specific->addr2sockaddr(sk, (struct sockaddr *) msg->msg_name); - if(addr_len) - *addr_len = tp->af_specific->sockaddr_len; + if(addr_len) + *addr_len = tp->af_specific->sockaddr_len; } remove_wait_queue(sk->sleep, &wait); diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/tcp_ipv4.c linux.pre11.6/net/ipv4/tcp_ipv4.c --- linux.pre11.5/net/ipv4/tcp_ipv4.c Fri Aug 6 18:51:51 1999 +++ linux.pre11.6/net/ipv4/tcp_ipv4.c Sat Aug 7 21:25:18 1999 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.175.2.6 1999/07/02 10:09:59 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.175.2.7 1999/07/23 15:38:46 davem Exp $ * * IPv4 specific functions * @@ -542,7 +542,8 @@ * so it actually scales. */ sk = __tcp_v4_lookup(NULL, sk->daddr, sk->dport, - sk->rcv_saddr, snum, sk->bound_dev_if); + sk->rcv_saddr, htons(snum), + sk->bound_dev_if); if((sk != NULL) && (sk->state != TCP_LISTEN)) retval = 0; break; diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv4/udp.c linux.pre11.6/net/ipv4/udp.c --- linux.pre11.5/net/ipv4/udp.c Fri Aug 6 18:51:51 1999 +++ linux.pre11.6/net/ipv4/udp.c Sat Aug 7 21:25:18 1999 @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.66.2.1 1999/06/20 20:14:48 davem Exp $ + * Version: $Id: udp.c,v 1.66.2.3 1999/08/07 10:56:36 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -687,8 +687,15 @@ connected = 0; } - if (connected) - rt = (struct rtable*)dst_clone(sk->dst_cache); + if (connected && sk->dst_cache) { + rt = (struct rtable*)sk->dst_cache; + if (rt->u.dst.obsolete) { + sk->dst_cache = NULL; + dst_release(&rt->u.dst); + rt = NULL; + } else + dst_clone(&rt->u.dst); + } if (rt == NULL) { err = ip_route_output(&rt, daddr, ufh.saddr, @@ -702,6 +709,8 @@ err = -EACCES; if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) goto out; + if (connected && sk->dst_cache == NULL) + sk->dst_cache = dst_clone(&rt->u.dst); } ufh.saddr = rt->rt_src; diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv6/ip6_fw.c linux.pre11.6/net/ipv6/ip6_fw.c --- linux.pre11.5/net/ipv6/ip6_fw.c Fri Aug 6 18:51:53 1999 +++ linux.pre11.6/net/ipv6/ip6_fw.c Sat Aug 7 21:25:18 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_fw.c,v 1.10 1998/08/26 12:04:57 davem Exp $ + * $Id: ip6_fw.c,v 1.10.2.1 1999/08/07 10:56:39 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/ipv6/tcp_ipv6.c linux.pre11.6/net/ipv6/tcp_ipv6.c --- linux.pre11.5/net/ipv6/tcp_ipv6.c Fri Aug 6 18:51:53 1999 +++ linux.pre11.6/net/ipv6/tcp_ipv6.c Sat Aug 7 21:25:18 1999 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.104.2.4 1999/06/30 09:27:12 davem Exp $ + * $Id: tcp_ipv6.c,v 1.104.2.5 1999/07/23 15:38:49 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -342,7 +342,8 @@ */ sk = __tcp_v6_lookup(NULL, &sk->net_pinfo.af_inet6.daddr, sk->dport, - &sk->net_pinfo.af_inet6.rcv_saddr, snum, + &sk->net_pinfo.af_inet6.rcv_saddr, + htons(snum), sk->bound_dev_if); if((sk != NULL) && (sk->state != TCP_LISTEN)) retval = 0; diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/sched/sch_cbq.c linux.pre11.6/net/sched/sch_cbq.c --- linux.pre11.5/net/sched/sch_cbq.c Fri Aug 6 18:51:54 1999 +++ linux.pre11.6/net/sched/sch_cbq.c Sat Aug 7 21:25:18 1999 @@ -176,6 +176,7 @@ struct cbq_class *tx_borrowed; int tx_len; psched_time_t now; /* Cached timestamp */ + psched_time_t now_rt; /* Cached real time */ unsigned pmask; struct timer_list delay_timer; @@ -375,9 +376,11 @@ if (toplevel > cl->level && !(cl->q->flags&TCQ_F_THROTTLED)) { psched_time_t now; + psched_tdiff_t incr; + PSCHED_GET_TIME(now); - if (PSCHED_TLESS(now, q->now)) - now = q->now; + incr = PSCHED_TDIFF(now, q->now_rt); + PSCHED_TADD2(q->now, incr, now); do { if (PSCHED_TLESS(cl->undertime, now)) { @@ -503,7 +506,7 @@ } } - q->wd_expires = delay; + q->wd_expires = base_delay; } } @@ -756,14 +759,19 @@ idle = (now - last) - last_pktlen/rate */ - idle = PSCHED_TDIFF(q->now, cl->last) - L2T(cl, len); + idle = PSCHED_TDIFF(q->now, cl->last); + if ((unsigned long)idle > 128*1024*1024) { + avgidle = cl->maxidle; + } else { + idle -= L2T(cl, len); /* true_avgidle := (1-W)*true_avgidle + W*idle, where W=2^{-ewma_log}. But cl->avgidle is scaled: cl->avgidle == true_avgidle/W, hence: */ - avgidle += idle - (avgidle>>cl->ewma_log); + avgidle += idle - (avgidle>>cl->ewma_log); + } if (avgidle <= 0) { /* Overlimit or at-limit */ @@ -980,10 +988,13 @@ struct sk_buff *skb; struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; psched_time_t now; + psched_tdiff_t incr; PSCHED_GET_TIME(now); + incr = PSCHED_TDIFF(now, q->now_rt); if (q->tx_class) { + psched_tdiff_t incr2; /* Time integrator. We calculate EOS time by adding expected packet transmittion time. If real time is greater, we warp artificial clock, @@ -991,12 +1002,14 @@ cbq_time = max(real_time, work); */ - PSCHED_TADD(q->now, L2T(&q->link, q->tx_len)); - if (PSCHED_TLESS(q->now, now)) - q->now = now; + incr2 = L2T(&q->link, q->tx_len); + PSCHED_TADD(q->now, incr2); cbq_update(q); - } else if (PSCHED_TLESS(q->now, now)) - q->now = now; + if ((incr -= incr2) < 0) + incr = 0; + } + PSCHED_TADD(q->now, incr); + q->now_rt = now; for (;;) { q->wd_expires = 0; @@ -1044,6 +1057,11 @@ del_timer(&q->wd_timer); if (delay <= 0) delay = 1; + if (delay > 10*HZ) { + if (net_ratelimit()) + printk(KERN_DEBUG "CBQ delay %ld > 10sec\n", delay); + delay = 10*HZ; + } q->wd_timer.expires = jiffies + delay; add_timer(&q->wd_timer); sch->flags |= TCQ_F_THROTTLED; @@ -1224,7 +1242,7 @@ struct cbq_class *cl, *cl_head; int prio; - for (prio = TC_CBQ_MAXPRIO; prio >= 0; prio++) { + for (prio = TC_CBQ_MAXPRIO; prio >= 0; prio--) { if ((cl_head = q->active[prio]) == NULL) continue; @@ -1252,6 +1270,8 @@ del_timer(&q->wd_timer); del_timer(&q->delay_timer); q->toplevel = TC_CBQ_MAXLEVEL; + PSCHED_GET_TIME(q->now); + q->now_rt = q->now; for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++) q->active[prio] = NULL; @@ -1425,6 +1445,8 @@ q->delay_timer.data = (unsigned long)sch; q->delay_timer.function = cbq_undelay; q->toplevel = TC_CBQ_MAXLEVEL; + PSCHED_GET_TIME(q->now); + q->now_rt = q->now; cbq_link_class(&q->link); diff -u --new-file --recursive --exclude-from ../exclude linux.pre11.5/net/unix/af_unix.c linux.pre11.6/net/unix/af_unix.c --- linux.pre11.5/net/unix/af_unix.c Fri Aug 6 18:51:47 1999 +++ linux.pre11.6/net/unix/af_unix.c Sat Aug 7 21:25:18 1999 @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.76.2.1 1999/06/28 10:40:07 davem Exp $ + * Version: $Id: af_unix.c,v 1.76.2.2 1999/08/07 10:56:48 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures.