]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.14pre6 2.2.14pre6
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:20:15 +0000 (15:20 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:20:15 +0000 (15:20 -0500)
o Fix missing auth check in shaper (Alan Cox)
o ISDN update (Karsten Keil)
o Sparc update (Dave Miller)
o NFS/TCP races fixes (Dave Miller)
o Remove unused nfs show_dentry routine (Dave Miller)
o Networking updates (Dave Miller)
o Fix to oom changes in ptrace for kills (Dave Miller)
o Delay on keyboard polls to fix some DECompaq kit(Phillip Ezolt)
o Documentation for the SiS900 card. Move to non (Ollie Lho)
experimental
o SMBfs improvements on directory scan (Andrew Tridgell)
o Documentation additions for oops-tracing (Keith Owens)
o Add HITACHI GF-1050 to the DVD RAM list (Rogier Wolff)
o Longer timeouts in ide-scsi for CD-RW (Mark Lord)
o Fix IDE/PCI compile
o Export inode_generation_count
o Maestro driver update (Fufu Brown)

176 files changed:
Documentation/Changes
Documentation/Configure.help
Documentation/isdn/00-INDEX
Documentation/isdn/README
Documentation/isdn/README.FAQ [new file with mode: 0644]
Documentation/isdn/README.avmb1
Documentation/isdn/README.eicon
Documentation/isdn/README.fax
Documentation/isdn/README.pcbit
Documentation/networking/sis900.txt [new file with mode: 0644]
Documentation/oops-tracing.txt
Makefile
arch/alpha/kernel/ptrace.c
arch/i386/kernel/ptrace.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/head.S
arch/sparc/kernel/process.c
arch/sparc/kernel/ptrace.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/lib/Makefile
arch/sparc/lib/ashldi3.S [new file with mode: 0644]
arch/sparc/lib/ashrdi3.S
arch/sparc/mm/Makefile
arch/sparc/mm/asyncd.c
arch/sparc/mm/fault.c
arch/sparc/mm/iommu.c
arch/sparc/mm/nosrmmu.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/mm/swift.S [new file with mode: 0644]
arch/sparc/mm/tsunami.S
arch/sparc64/config.in
arch/sparc64/defconfig
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/head.S
arch/sparc64/kernel/ioctl32.c
arch/sparc64/kernel/psycho.c
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/time.c
arch/sparc64/kernel/trampoline.S
arch/sparc64/lib/blockops.S
arch/sparc64/mm/asyncd.c
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
arch/sparc64/prom/Makefile
arch/sparc64/prom/map.S [new file with mode: 0644]
arch/sparc64/prom/misc.c
arch/sparc64/prom/p1275.c
drivers/block/ide.c
drivers/block/ns87415.c
drivers/char/pc_keyb.c
drivers/isdn/Config.in
drivers/isdn/act2000/act2000_isa.c
drivers/isdn/act2000/act2000_isa.h
drivers/isdn/act2000/module.c
drivers/isdn/avmb1/avmcard.h
drivers/isdn/avmb1/b1.c
drivers/isdn/avmb1/b1isa.c
drivers/isdn/avmb1/b1pci.c
drivers/isdn/avmb1/b1pcmcia.c
drivers/isdn/avmb1/capi.c
drivers/isdn/avmb1/capidrv.c
drivers/isdn/avmb1/kcapi.c
drivers/isdn/avmb1/t1isa.c
drivers/isdn/avmb1/t1pci.c [new file with mode: 0644]
drivers/isdn/eicon/eicon.h
drivers/isdn/eicon/eicon_idi.c
drivers/isdn/eicon/eicon_io.c
drivers/isdn/eicon/eicon_isa.h
drivers/isdn/eicon/eicon_mod.c
drivers/isdn/hisax/callc.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/hfc_2bds0.c
drivers/isdn/hisax/hfc_2bs0.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/hfc_pci.h
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hscx_irq.c
drivers/isdn/hisax/isac.c
drivers/isdn/hisax/isar.c
drivers/isdn/hisax/isar.h
drivers/isdn/hisax/isurf.c
drivers/isdn/hisax/l3dss1.c
drivers/isdn/hisax/md5sums.asc
drivers/isdn/hisax/netjet.c
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/telespci.c
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_net.c
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_tty.c
drivers/isdn/isdn_v110.c
drivers/isdn/isdn_v110.h
drivers/isdn/pcbit/drv.c
drivers/isdn/pcbit/pcbit.h
drivers/net/Config.in
drivers/net/myri_sbus.c
drivers/net/shaper.c
drivers/net/sunbmac.c
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/sbus/audio/amd7930.c
drivers/sbus/audio/cs4215.h
drivers/sbus/audio/cs4231.c
drivers/sbus/audio/dbri.c
drivers/sbus/char/openprom.c
drivers/sbus/char/pcikbd.c
drivers/sbus/char/sab82532.c
drivers/sbus/char/su.c
drivers/sbus/char/sunkeymap.c
drivers/sbus/char/sunkeymap.map
drivers/sbus/char/sunmouse.c
drivers/sbus/char/sunmouse.h
drivers/sbus/char/sunserial.c
drivers/sbus/char/sunserial.h
drivers/sbus/char/zs.c
drivers/scsi/esp.c
drivers/scsi/ide-scsi.c
drivers/scsi/qlogicpti.c
drivers/scsi/qlogicpti.h
drivers/scsi/scsi.c
drivers/sound/maestro.c
drivers/video/atyfb.c
drivers/video/bwtwofb.c
drivers/video/cgfourteenfb.c
drivers/video/cgsixfb.c
drivers/video/cgthreefb.c
drivers/video/creatorfb.c
drivers/video/fbmem.c
drivers/video/leofb.c
drivers/video/pm2fb.c
drivers/video/pm2fb.h
drivers/video/tcxfb.c
fs/nfs/dir.c
fs/proc/mem.c
fs/smbfs/proc.c
include/asm-sparc/asm_offsets.h
include/asm-sparc/shmparam.h
include/asm-sparc64/asm_offsets.h
include/asm-sparc64/mmu_context.h
include/asm-sparc64/oplib.h
include/asm-sparc64/ttable.h
include/linux/fb.h
include/linux/isdn.h
include/linux/isdnif.h
include/linux/pci.h
include/linux/sunrpc/xprt.h
include/linux/sysctl.h
kernel/ksyms.c
kernel/panic.c
kernel/sysctl.c
net/ethernet/eth.c
net/ipv4/arp.c
net/ipv4/icmp.c
net/ipv4/ip_forward.c
net/ipv4/ip_masq_user.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_timer.c
net/ipv6/tcp_ipv6.c
net/sunrpc/xprt.c

index 77dc7ee7e00b03674dd9b9413e8f549d98276c5a..81972c1f50dcfcf8ce4bf857888f6a79058e25ab 100644 (file)
@@ -74,6 +74,7 @@ running, the suggested command should tell you.
 - Pcmcia-cs              3.0.14                  ; cardmgr -V
 - PPP                    2.3.10                  ; pppd --version
 - Util-linux             2.9z                    ; chsh -v
+- isdn4k-utils           v3.1beta7               ; isdnctrl 2>&1|grep version
 
 Upgrade notes
 *************
@@ -272,9 +273,6 @@ available from http://juanjox.linuxhq.com/ .
    DHCP clients for 2.0 do not work with the new networking code in the
 2.2 kernel.  You will need to upgrade your dhcpcd / dhcpclient.
 
-   The ISDN code in the stock 2.2 kernel may not work for you.  If it
-doesn't, look in ftp://ftp.suse.com/pub/isdn4linux for updated versions.
-
    In 2.0.x the kernel could be configured to drop source routed IP
 packets via a compile time configuration option.  In 2.2.x, this has
 been replaced by a sysctl.  See Documentation/networking/ip-sysctl.txt
@@ -513,6 +511,11 @@ config.h file needs to
 
    so be sure to check that when you recompile.
 
+ISDN4Linux
+==========
+Older isdn4k-utils versions don't support EXTRAVERSION into kernel version
+string. A upgrade to isdn4k-utils.v3.1beta7 or later is recomented.
+
 Where to get the files
 **********************
 
@@ -790,6 +793,11 @@ Patch
 The 2.5 release:
 ftp://ftp.gnu.org/gnu/patch/patch-2.5.tar.gz
 
+ISDN4Linux
+==========
+The v3.1beta7 release:
+ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-utils.v3.1beta7.tar.gz
+
 Other Info
 ==========
 
index aca71364b07a3d120e710169cddc36050f65ad72..3212980b2e4339ad95d4638ebd4ff84588a5190b 100644 (file)
@@ -5857,6 +5857,24 @@ CONFIG_RTL8139
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called rtl8139.o.
 
+SiS 900/7016 support
+CONFIG_SIS900
+  This is a driver for the Fast Ethernet PCI network cards based on
+  the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
+  SiS 630 and SiS 540 chipsets. If you have one of those, say Y and
+  read the Ethernet-HOWTO, available via FTP (user: anonymous) in   
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read 
+  Documentation/networking/sis900.txt and comments at the beginning
+  of drivers/net/sis900.c for more information.
+
+  This driver also supports AMD 79C901 HomePNA such that you can use
+  your phone line as network cable.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want), 
+  say M here and read Documentation/modules.txt. This is recommended. 
+  The module will be called sis900.o.
+
 Packet Engines Yellowfin Gigabit-NIC support
 CONFIG_YELLOWFIN
   Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
@@ -10006,11 +10024,6 @@ CONFIG_MAGIC_SYSRQ
 
 ISDN subsystem
 CONFIG_ISDN
-  CAUTION: the ISDN driver shipped with this kernel distribution
-  is outdated and might not work without problems. An updated driver
-  is available for download. Please read http://www.isdn4linux.de
-  on the WWW for a list of servers.
-
   ISDN ("Integrated Services Digital Networks", called RNIS in France)
   is a special type of fully digital telephone service; it's mostly
   used to connect to your Internet service provider (with SLIP or
@@ -10019,9 +10032,7 @@ CONFIG_ISDN
   conversations while downloading stuff. It only works if your
   computer is equipped with an ISDN card and both you and your service
   provider purchased an ISDN line from the phone company. For details,
-  read http://alumni.caltech.edu/~dank/isdn/ on the WWW. (To browse
-  the WWW, you need to have access to a machine on the Internet that
-  has a program like lynx or netscape.)
+  read http://alumni.caltech.edu/~dank/isdn/ on the WWW.
 
   This driver allows you to use an ISDN-card for networking
   connections and as dialin/out device. The isdn-tty's have a built in
@@ -10071,25 +10082,28 @@ CONFIG_ISDN_AUDIO
   is the only voice-supporting driver. See
   Documentation/isdn/README.audio for more information.
 
-X.25 PLP on top of ISDN (EXPERIMENTAL)
+X.25 PLP on top of ISDN
 CONFIG_ISDN_X25
-  This experimental feature provides the X.25 protocol over ISDN
-  connections. See Documentation/isdn/README.x25 for more information
+  This feature provides the X.25 protocol over ISDN connections.
+  See Documentation/isdn/README.x25 for more information
   if you are thinking about using this.
 
 ISDN diversion services support
 CONFIG_ISDN_DIVERSION
   This option allows you to use some supplementary diversion
   services in conjunction with the HiSax driver on an EURO/DSS1
-  line. Supported options are CD (call deflection), CFU (Call 
-  forward unconditional), CFB (Call forward when busy) and CFNR 
-  (call forward not reachable).
-  Additionally the actual CFU, CFB and CFNR state may be 
-  interrogated. The use of CFU, CFB, CFNR and interrogation may
-  be limited to some countries. The keypad protocol is still not
-  implemented.
-  CD should work in all countries if this service has been sub-
-  scribed.
+  line. 
+
+  Supported options are CD (call deflection), CFU (Call forward
+  unconditional), CFB (Call forward when busy) and CFNR (call forward
+  not reachable). Additionally the actual CFU, CFB and CFNR state may
+  be interrogated.
+
+  The use of CFU, CFB, CFNR and interrogation may be limited to some
+  countries. The keypad protocol is still not implemented. CD should
+  work in all countries if the service has been subscribed to.
+
+  Please read the file Documentation/isdn/README.diversion.
 
 ICN 2B and 4B support
 CONFIG_ISDN_DRV_ICN
@@ -10331,7 +10345,7 @@ CONFIG_HISAX_HFC_PCI
   
   For more informations see under Documentation/isdn/README.hfc-pci.
 
-HiSax Support for Winbond W6692 based cards (EXPERIMENTAL)
+HiSax Support for Winbond W6692 based cards
 CONFIG_HISAX_W6692
   This enables HiSax support for Winbond W6692 based PCI ISDN cards.
   
@@ -10364,35 +10378,33 @@ CONFIG_ISDN_DRV_SC
   can be inserted in and removed from the running kernel whenever you
   want, details in Documentation/modules.txt); the module will be
   called sc.o. See Documentation/isdn/README.sc and
-  http://www.spellcast.com for more information (to browse the WWW,
-  you need to have access to a machine on the Internet that has a
-  program like lynx or netscape).
+  http://www.spellcast.com for more information.
 
 Eicon.Diehl active card support
 CONFIG_ISDN_DRV_EICON
   Say Y here if you have an Eicon active ISDN card. In order to use
   this card, additional firmware is necessary, which has to be loaded
-  into the card using the eiconctrl utility which is part of the latest
-  isdn4k-utils package. Please read the file
+  into the card using the eiconctrl utility which is part of the
+  latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
   
 Eicon old-type card support
 CONFIG_ISDN_DRV_EICON_ISA
-  Say Y here if you have an old-type Eicon active ISDN card. In order to
-  use this card, additional firmware is necessary, which has to be loaded
-  into the card using the eiconctrl utility which is part of the latest
-  isdn4k-utils package. Please read the file
+  Say Y here if you have an old-type Eicon active ISDN card. In order
+  to use this card, additional firmware is necessary, which has to be
+  loaded into the card using the eiconctrl utility which is part of
+  the latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
 
 Support AT-Fax Class 2 commands
 CONFIG_ISDN_TTY_FAX
   If you say Y here, the modem-emulator will support a subset of the
   Fax Class 2 commands. Using a getty with fax-support
-  (mgetty+sendfax, hylafax), you will be able to use your Linux box 
-  as an ISDN-fax-machine. This must be supported by the lowlevel driver
+  (mgetty+sendfax, hylafax), you will be able to use your Linux box as
+  an ISDN-fax-machine. This must be supported by the lowlevel driver
   also. See Documentation/isdn/README.fax for more information.
 
-AVM-B1 with CAPI2.0 support
+AVM CAPI2.0 support
 CONFIG_ISDN_DRV_AVMB1
   This enables support for the AVM B1/T1 ISDN networking cards.In
   addition, a CAPI (Common ISDN Application Programming Interface, a
@@ -10403,7 +10415,7 @@ CONFIG_ISDN_DRV_AVMB1
   additional firmware is necessary, which has to be downloaded into
   the card using a utility which is distributed separately. Please
   read the file Documentation/isdn/README.avmb1. 
-
+  
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called avmb1.o. If you want to compile it as a
@@ -10417,7 +10429,7 @@ AVM B1 PCI support
 CONFIG_ISDN_DRV_AVMB1_B1PCI
   Enable support for the PCI version of the AVM B1 card.
 
-AVM T1/T1B ISA support
+AVM T1/T1-B ISA support
 CONFIG_ISDN_DRV_AVMB1_T1ISA
   Enable support for the AVM T1 T1B card.
   Note: This is a PRI card and handle 30 B-channels.
@@ -10426,12 +10438,18 @@ AVM B1/M1/M2 PCMCIA support
 CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
   Enable support for the PCMCIA version of the AVM B1 card.
 
+AVM T1/T1-B PCI support
+CONFIG_ISDN_DRV_AVMB1_T1PCI
+  Enable support for the AVM T1 T1B card.
+  Note: This is a PRI card and handle 30 B-channels.
+
 Verbose reason code reporting (kernel size +=7K)
 CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
   If you say Y here, the AVM B1 driver will give verbose reasons for
   disconnecting. This will increase the size of the kernel by 7 KB. If
   unsure, say Y.
 
+
 IBM Active 2000 support (EXPERIMENTAL)
 CONFIG_ISDN_DRV_ACT2000
   Say Y here if you have an IBM Active 2000 ISDN card. In order to use
index 919af90576546aa79caea0142a13258f0a369d3f..b7161af1a78f298cf4a01acc890438718ecb198e 100644 (file)
@@ -6,12 +6,18 @@ INTERFACE
        - description of Linklevel and Hardwarelevel ISDN interface.
 README
        - general info on what you need and what to do for Linux ISDN.
+README.FAQ
+       - general info for FAQ.
 README.audio
        - info for running audio over ISDN.
+README.fax
+       - info for using Fax over ISDN.
 README.icn
        - info on the ICN-ISDN-card and its driver.
 README.HiSax
        - info on the HiSax driver which replaces the old teles.
+README.hfc-pci
+       - info on hfc-pci based cards.
 README.pcbit
        - info on the PCBIT-D ISDN adapter and driver.
 README.syncppp
@@ -22,8 +28,12 @@ README.avmb1
        - info on driver for AVM-B1 ISDN card.
 README.act2000
        - info on driver for IBM ACT-2000 card.
+README.eicon
+       - info on driver for Eicon active cards.
 README.concap
        - info on "CONCAP" ecapsulation protocol interface used for X.25.
+README.diversion
+       - info on module for isdn diversion services.
 README.sc
        - info on driver for Spellcaster cards.
 README.x25
index 1c91909d84aacef4253becc8968922ed2b15d796..3cf623d48eec5dfb0e69f372e34996ccb6b5a92e 100644 (file)
@@ -11,7 +11,7 @@ README for the ISDN-subsystem
   necessary. Those programs and some contributed utilities are available
   at
 
-   ftp.franken.de
+   ftp.isdn4linux.de
 
    /pub/isdn4linux/isdn4k-utils-<VersionNumber>.tar.gz
 
@@ -22,11 +22,11 @@ README for the ISDN-subsystem
    reasons, the mailing-list's primary language is german. However mails
    written in english have been welcome all the time.
 
-   to subscribe: write a email to majordomo@hub-wue.franken.de,
+   to subscribe: write a email to majordomo@listserv.isdn4linux.de,
    Subject irrelevant, in the message body:
    subscribe isdn4linux <your_email_address>
 
-   To write to the mailing-list, write to isdn4linux@hub-wue.franken.de
+   To write to the mailing-list, write to isdn4linux@listserv.isdn4linux.de
 
    This mailinglist is bidirectionally gated to the newsgroup
 
diff --git a/Documentation/isdn/README.FAQ b/Documentation/isdn/README.FAQ
new file mode 100644 (file)
index 0000000..356f794
--- /dev/null
@@ -0,0 +1,26 @@
+
+The FAQ for isdn4linux
+======================
+
+Please note that there is a big FAQ available in the isdn4k-utils.
+You find it in:
+ isdn4k-utils/FAQ/i4lfaq.sgml
+
+In case you just want to see the FAQ online, or download the newest version,
+you can have a look at my website:
+http://www.mhessler.de/i4lfaq/ (view + download)
+or:
+http://www.isdn4linux.de/faq/ (view)
+
+As the extension tells, the FAQ is in SGML format, and you can convert it
+into text/html/... format by using the sgml2txt/sgml2html/... tools.
+Alternatively, you can also do a 'configure; make all' in the FAQ directory.
+
+
+Please have a look at the FAQ before posting anything in the Mailinglist,
+or the newsgroup!
+
+
+Matthias Hessler
+hessler@isdn4linux.de
+
index 34eee2125b2f47d62b8ac6dcc6669e1c587ebba7..6fa9406dfece99ef3bf1b79809e94932797ae524 100644 (file)
@@ -169,7 +169,7 @@ capi20
 
 Questions
 ---------
-Check out the FAQ (ftp.franken.de) or subscribe to the
+Check out the FAQ (ftp.isdn4linux.de) or subscribe to the
 linux-avmb1@calle.in-berlin.de mailing list by sending
 a mail to majordomo@calle.in-berlin.de with
 subscribe linux-avmb1
index d55cc14ad0052be07415daab1ef612ebb6dca3cb..b40e1ecd23c529a7d0072d47008fe982bb708740 100644 (file)
@@ -1,6 +1,6 @@
-$Id: README.eicon,v 1.4 1999/07/11 17:17:30 armin Exp $
+$Id: README.eicon,v 1.5 1999/10/11 18:13:25 armin Exp $
 
-(c) 1999 Cytronics & Melware
+(c) 1999 Cytronics & Melware (info@melware.de)
 
 This document describes the eicon driver for the
 Eicon.Diehl active ISDN cards.
@@ -24,17 +24,26 @@ It is meant to be used with isdn4linux, an ISDN link-level module for Linux.
 
 
 Supported Cards
----------------
+===============
 
+Old ISA type
+------------
 - S-Card ISA
 - SX-Card ISA
 - SXn-Card ISA
 - SCOM-Card ISA
 - Quadro-Card ISA
 - S2M-Card ISA
+
+DIVA Server family
+------------------
 - DIVA Server BRI/PCI 2M
 - DIVA Server PRI/PCI 2M (9M 23M 30M)
-  (Only analog modem functions of the DSPs are currently implemented)
+       supported functions of onboard DSPs:
+       - analog modem
+       - fax group 2/3 (Fax Class 2 commands)
+       - DTMF detection
+
 
 ISDN D-Channel Protocols
 ------------------------
@@ -76,6 +85,10 @@ Example for loading and starting a PRI card with E-DSS1 Protocol.
 Details about using the eiconctrl utility are in 'man eiconctrl'
 or will be printed by starting eiconctrl without any parameters.
 
+Thanks to 
+       Deutsche Mailbox Saar-Lor-Lux GmbH
+       for sponsoring and testing fax
+       capabilities with Diva Server cards.
 
 
 Any reports about bugs, errors and even wishes are welcome.
index 897abd0ef53843521988a6cc92ef7bfc159d33df..eeff9ce9f2c0d983a6a91a94900480760867aaee 100644 (file)
@@ -9,7 +9,7 @@ This only makes sense under the following conditions :
 
 - You need the commands as dummy, because you are using
   hylafax (with patch) for AVM capi.
-- You want to use the fax capabillities of your isdn-card.
+- You want to use the fax capabilities of your isdn-card.
   (supported cards are listed below)
 
 
@@ -21,8 +21,12 @@ NOTE: This implementation does *not* support fax with passive
 Supported ISDN-Cards
 --------------------
 
-Eicon DIVA Server BRI/PCI (will be ready soon)
-Eicon DIVA Server PRI/PCI (will be ready soon)
+Eicon DIVA Server BRI/PCI
+       - full support with both B-channels.
+
+Eicon DIVA Server PRI/PCI
+       - full support on amount of B-channels
+               depending on DSPs on board.
 
 
 
index fb696422f911193583ae945a39c2334373f165d7..5125002282e5e4129da192477f692c19a6b09b12 100644 (file)
@@ -32,7 +32,7 @@ allow normal operation. Plans for the future include cooperation with
 the manufacturer in order to solve this problem.
 
 Information/hints/help can be obtained in the linux isdn
-mailing list (isdn4linux@hub-wue.franken.de) or directly from me.
+mailing list (isdn4linux@listserv.isdn4linux.de) or directly from me.
 
 regards,
   Pedro.
diff --git a/Documentation/networking/sis900.txt b/Documentation/networking/sis900.txt
new file mode 100644 (file)
index 0000000..474d3c0
--- /dev/null
@@ -0,0 +1,460 @@
+  SiS 900/7016 Fast Ethernet Device Driver
+  by Ollie Lho (ollie@sis.com.tw)
+  November 4, 1999. Document Revision: 0.1
+
+  This document gives some information on installation and usage of SiS
+  900/7016 device driver under Linux.
+  ______________________________________________________________________
+
+  Table of Contents
+
+
+  1. Introduction
+
+  2. License
+
+  3. Changes
+
+  4. Tested Environment
+
+  5. Files in This Rackage
+
+  6. Installation
+
+     6.1 Kernel version later than 2.2.11 and 2.3.15
+        6.1.1 Building the driver as loadable module
+        6.1.2 Building the driver into kernel
+     6.2 Earlier Kernel Version in 2.2.x and 2.3.x Series
+
+  7. Known Problems and Bugs
+
+  8. Revision History
+
+  9. Acknowledgements
+
+
+
+  ______________________________________________________________________
+
+  1.  Introduction
+
+  This document describes the revision 1.06 of SiS 900/7016 Fast
+  Ethernet device driver under Linux. The driver is developed by Silicon
+  Integrated System Corp. and distributed freely under the GNU General
+  Public License (GPL). The driver can be compiled as a loadable module
+  and used under Linux kernel version 2.2.x. With minimal changes, the
+  driver can also be used under 2.3.x kernel, please see section
+  ``Installation''. If you are intended to use the driver for earlier
+  kernels, you are on your own.
+
+  The driver is tested with usual TCP/IP applications including FTP,
+  Telnet, Netscape etc. and is used constantly by the developers.
+
+  Please send all comments/fixes/questions to Ollie Lho.
+
+
+  2.  License
+
+
+
+
+
+
+
+
+
+
+          Copyright (C) 1999 Silicon Integrated System Corp.
+
+          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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+
+
+
+  3.  Changes
+
+  Changes made in Revision 1.06
+
+  1. Separation of sis900.c and sis900.h in order to move most constant
+     definition to sis900.h (many of those constants were corrected)
+
+  2. Clean up PCI detection, the pci-scan from Donald Becker were not
+     used, just simple pci_find_*.
+
+  3. MII detection is modified to support multiple mii transceiver.
+
+  4. Bugs in read_eeprom, mdio_* were removed.
+
+  5. Lot of sis900 irrelevant comments were removed/changed and more
+     comments were added to reflect the real situation.
+
+  6. Clean up of physical/virtual address space mess in buffer
+     descriptors.
+
+  7. Better transmit/receive error handling.
+
+  8. The driver now uses zero-copy single buffer management scheme to
+     improve performance.
+
+  9. Names of variables were changed to be more consistent.
+
+ 10. Clean up of auo-negotiation and timer code.
+
+ 11. Automatic detection and change of PHY on the fly.
+
+
+  4.  Tested Environment
+
+  This driver is developed on the following hardware
+
+  o  Intel Celeron 336 with SiS 620 (rev 02) chipset
+
+  o  SiS 900 (rev 01) and SiS 7016/7014 Fast Ethernet Card
+
+     and tested with these software environments
+
+  o  Red Hat Linux version 6.0
+
+  o  Linux kernel version 2.2.13
+
+  o  Netscape version 4.6
+
+  o  NcFTP 3.0.0 beta 18
+
+  o  Samba version 2.0.3
+
+
+  5.  Files in This Rackage
+
+  In the package you can find these files:
+
+
+     sis900-2.2.x.c
+        Driver source for kernel 2.2.x
+
+     sis900-2.3.x.c
+        Driver source for kernel 2.3.x
+
+     sis900.h
+        Header file for both 2.2.x and 2.3.x kernel
+
+     sis900.sgml
+        Linux-Doc SGML source of the document
+
+
+  6.  Installation
+
+  Before trying to install the driver, be sure to get the latest
+  revision from SiS' Home Page.  If you have no prior experience in
+  networking under Linux, please read Ethernet HOWTO and Networking
+  HOWTO available from Linux Documentation Project (LDP).
+
+  The installation procedure are different according to your kernel
+  versions.
+
+
+  6.1.  Kernel version later than 2.2.11 and 2.3.15
+
+  The driver is bundled in release later than 2.2.11 and 2.3.15 so this
+  is the most easy case.  Be sure you have the appropriate packages for
+  compiling kernel source.  Those packages are listed in
+  Document/Changes in kernel source distribution. There are two
+  alternative ways to install the driver
+
+
+  6.1.1.  Building the driver as loadable module
+
+  To build the driver as a loadable kernel module you have to
+  reconfigure the kernel to activate network support by
+
+
+
+       make config
+
+
+
+
+  Choose "Network Device Support" to "Y" and "Ethernet Support" to "Y".
+  Then you have to choose "SiS 900 Fast Ethernet Adapter Support" to
+  "M".
+
+  After reconfiguring the kernel, you can make the driver module by
+
+
+       make modules
+
+
+
+
+  The driver should be compiled with no errors. After compiling the
+  driver, the driver can be installed to proper place by
+
+
+
+       make modules_install
+
+
+
+
+  Load the driver into kernel by
+
+
+
+       insmod sis900
+
+
+
+
+  When loading the driver into memory, some information message can be
+  view by
+
+
+
+       dmesg
+
+
+
+
+  or
+
+
+       cat /var/log/message
+
+
+
+
+  If the driver is loaded properly you will have messages similar to
+  this:
+
+
+
+       sis900.c: v1.06  11/04/99
+       eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4.
+       eth0: SiS 900 Internal MII PHY transceiver found at address 1.
+
+
+
+
+  showing the version of the driver and the results of probing routine.
+
+  Once the driver is loaded, network can be brought up by
+
+
+
+       /sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK
+
+
+
+
+
+  where IPADDR, BROADCAST, NETMASK are your IP address, broadcast
+  address and netmask respectively. For more information on how to
+  configure network interface, please refer to Networking HOWTO.
+
+  The link status is also shown by kernel messages. For example, after
+  the network interface is activated, you may have the message:
+
+
+
+       eth0: Using SiS 900 Internal MII PHY as default
+       eth0: Media Link On 100mbps full-duplex
+
+
+
+
+  If you try to unplug the twist pair (TP) cable you will get
+
+
+
+       eth0: Media Link Off
+
+
+
+
+  indicating that the link is failed.
+
+
+  6.1.2.  Building the driver into kernel
+
+  If you want to make the driver into kernel, choose "Y" rather than "M"
+  on "SiS 900 Fast Ethernet Adapter Support" when configuring the
+  kernel.  Build the kernel image in the usual way
+
+
+
+       make dep
+
+       make clean
+
+       make bzlilo
+
+
+
+
+  Next time the system reboot, you have the driver in memory.
+
+
+  6.2.  Earlier Kernel Version in 2.2.x and 2.3.x Series
+
+  Installing the driver for earlier kernels in 2.2.x and 2.3.x series
+  requires a little bit more work. First you have to copy sis900-2.x.x.c
+  to /usr/src/linux/drivers/net/ and you have to modify some files
+  manually (sorry !! no patch available !!)
+
+  in Space.c, add
+
+
+       extern int sis900_probe(struct device *dev);
+
+       ...
+
+       #ifdef CONFIG_SIS900
+               {sis900_probe,0},
+       #endif
+
+
+  in Config.in add
+
+
+       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+               ... //other adapter drivers
+               tristate 'SiS 900 PCI Fast Ethernet Adapter Support' CONFIG_SIS900
+               ... //other adapter drivers
+       fi
+
+
+
+
+  in Makefile add
+
+
+       ifeq ($(CONFIG_SIS900),y)
+               L_OBJS += sis900.o
+       else
+               ifeq ($(CONFIG_SIS900),m)
+                       M_OBJS += sis900.o
+               endif
+       endif
+
+
+
+
+  After modifying these files, the driver can be build as described in
+  the previous section.
+
+
+  7.  Known Problems and Bugs
+
+  There are some known problems and bugs. If you find any other bugs
+  please mail to ollie@sis.com.tw
+
+  1. AM79C901 HomePNA PHY is not thoroughly tested, there may be some
+     bugs in the "on the fly" change of transceiver.
+
+  2. A bug is hidden somewhere in the receive buffer management code,
+     the bug causes NULL pointer reference in the kernel. This fault is
+     caught before bad things happen and reported with the message:
+
+
+       eth0: NULL pointer encountered in Rx ring, skipping
+
+
+
+
+  which can be viewed with dmesg or cat /var/log/message.
+
+
+  8.  Revision History
+
+
+  o  November 4, 1999, Revision 1.06, Second release, lots of clean up
+     and optimization.
+
+  o  August 8, 1999, Revision 1.05, Initial Public Release
+
+
+  9.  Acknowledgements
+
+  This driver was originally derived form Donald Becker's pci-skeleton
+  and rtl8139 drivers. Donald also provided various suggestion regarded
+  with improvements made in revision 1.06.
+
+  The 1.05 revision was created by Jim Huang, AMD 79c901 support was
+  added by Chin-Shan Li.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
index 108c3b645b626ee708ffa911071efd6855c3c44f..3d241095aa8c01a731ec99f41219bd5a437efafc 100644 (file)
@@ -15,6 +15,37 @@ If you are totally stumped as to whom to send the report, send it to
 linux-kernel@vger.rutgers.edu. Thanks for your help in making Linux as
 stable as humanly possible.
 
+Where is the_oops.txt?
+----------------------
+
+Normally the Oops text is read from the kernel buffers by klogd and
+handed to syslogd which writes it to a syslog file, typically
+/var/log/messages (depends on /etc/syslog.conf).  Sometimes klogd dies,
+in which case you can run dmesg > file to read the data from the kernel
+buffers and save it.  Or you can cat /proc/kmsg > file, however you
+have to break in to stop the transfer, kmsg is a "never ending file".
+If the machine has crashed so badly that you cannot enter commands or
+the disk is not available then you have three options :-
+
+(1) Hand copy the text from the screen and type it in after the machine
+    has restarted.  Messy but it is the only option if you have not
+    planned for a crash.
+
+(2) Boot with a serial console (see Documentation/serial-console.txt),
+    run a null modem to a second machine and capture the output there
+    using your favourite communication program.  Minicom works well.
+
+(3) Patch the kernel with one of the crash dump patches.  These save
+    data to a floppy disk or video rom or a swap partition.  None of
+    these are standard kernel patches so you have to find and apply
+    them yourself.  Search kernel archives for kmsgdump, lkcd and
+    oops+smram.
+
+No matter how you capture the log output, feed the resulting file to
+ksymoops along with /proc/ksyms and /proc/modules that applied at the
+time of the crash.  /var/log/ksymoops can be useful to capture the
+latter, man ksymoops for details.
+
 
 Full Information
 ----------------
index bb3a1f244e868e1176311a486d81bf8a0f6a96ad..3d0903396c708f4293c56b0a3d225946da4504c2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 14
-EXTRAVERSION = pre4
+EXTRAVERSION = pre6
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 4e2f7359b286c0adb79f62ea7ad9db4d390ffd70..899ad3923b1be2f212458ed1349c9e110d564eef 100644 (file)
@@ -159,7 +159,7 @@ get_long(struct task_struct * tsk, struct vm_area_struct * vma,
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return 0;
        }
        if (pgd_bad(*pgdir)) {
@@ -173,7 +173,7 @@ get_long(struct task_struct * tsk, struct vm_area_struct * vma,
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return 0;
        }
        if (pmd_bad(*pgmiddle)) {
@@ -187,7 +187,7 @@ get_long(struct task_struct * tsk, struct vm_area_struct * vma,
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return 0;
        }
        page = pte_page(*pgtable);
@@ -224,7 +224,7 @@ put_long(struct task_struct * tsk, struct vm_area_struct * vma,
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return;
        }
        if (pgd_bad(*pgdir)) {
@@ -238,7 +238,7 @@ put_long(struct task_struct * tsk, struct vm_area_struct * vma,
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return;
        }
        if (pmd_bad(*pgmiddle)) {
@@ -252,7 +252,7 @@ put_long(struct task_struct * tsk, struct vm_area_struct * vma,
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return;
        }
        page = pte_page(*pgtable);
@@ -261,7 +261,7 @@ put_long(struct task_struct * tsk, struct vm_area_struct * vma,
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return;
        }
 
index 1eb33a82d992409b075aee842b8ce71d8b083c1e..c252b2c549d2061df1b8b74891e5361ccff0cb9e 100644 (file)
@@ -89,7 +89,7 @@ repeat:
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return 0;
        }
        if (pgd_bad(*pgdir)) {
@@ -103,7 +103,7 @@ repeat:
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return 0;
        }
        if (pmd_bad(*pgmiddle)) {
@@ -117,7 +117,7 @@ repeat:
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return 0;
        }
        page = pte_page(*pgtable);
@@ -153,7 +153,7 @@ repeat:
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return;
        }
        if (pgd_bad(*pgdir)) {
@@ -167,7 +167,7 @@ repeat:
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return;
        }
        if (pmd_bad(*pgmiddle)) {
@@ -181,7 +181,7 @@ repeat:
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return;
        }
        page = pte_page(*pgtable);
@@ -190,7 +190,7 @@ repeat:
                if (fault > 0)
                        goto repeat;
                if (fault < 0)
-                       force_sig(SIGKILL, current);
+                       force_sig(SIGKILL, tsk);
                return;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
index 9ceaf859172c1b93cd68b46c514fa7bbb273f409..1bfd7ee868c809f9fbcced69c5552ebd10aeec36 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.159.2.2 1999/09/22 11:37:29 jj Exp $
+/* $Id: entry.S,v 1.159.2.6 1999/10/11 08:24:35 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -829,13 +829,13 @@ linux_trap_nmi_sun4c:
        .globl  C_LABEL(invalid_segment_patch1_ff)
        .globl  C_LABEL(invalid_segment_patch2_ff)
 C_LABEL(invalid_segment_patch1_ff):    cmp     %l4, 0xff
-C_LABEL(invalid_segment_patch2_ff):    mov     0xff, %l4
+C_LABEL(invalid_segment_patch2_ff):    mov     0xff, %l3
 
        .align  4
        .globl  C_LABEL(invalid_segment_patch1_1ff)
        .globl  C_LABEL(invalid_segment_patch2_1ff)
 C_LABEL(invalid_segment_patch1_1ff):   cmp     %l4, 0x1ff
-C_LABEL(invalid_segment_patch2_1ff):   mov     0x1ff, %l4
+C_LABEL(invalid_segment_patch2_1ff):   mov     0x1ff, %l3
 
        .align  4
        .globl  C_LABEL(num_context_patch1_16), C_LABEL(num_context_patch2_16)
@@ -856,7 +856,7 @@ C_LABEL(vac_linesize_patch_32):             subcc   %l7, 32, %l7
 #ifdef CONFIG_SUN4
 C_LABEL(vac_hwflush_patch1_on):                nop
 #else
-C_LABEL(vac_hwflush_patch1_on):                subcc   %l7, (PAGE_SIZE - 4), %l7
+C_LABEL(vac_hwflush_patch1_on):                addcc   %l7, -PAGE_SIZE, %l7
 #endif
 
 C_LABEL(vac_hwflush_patch2_on):                sta     %g0, [%l3 + %l7] ASI_HWFLUSHSEG
@@ -972,12 +972,12 @@ C_LABEL(invalid_segment_patch1):
        bne     1f
         sethi  %hi(C_LABEL(sun4c_kfree_ring)), %l4
        or      %l4, %lo(C_LABEL(sun4c_kfree_ring)), %l4
-       ld      [%l4 + 0x10], %l3
+       ld      [%l4 + 0x18], %l3
        deccc   %l3                     ! do we have a free entry?
        bcs,a   2f                      ! no, unmap one.
         sethi  %hi(C_LABEL(sun4c_kernel_ring)), %l4
 
-       st      %l3, [%l4 + 0x10]       ! sun4c_kfree_ring.num_entries--
+       st      %l3, [%l4 + 0x18]       ! sun4c_kfree_ring.num_entries--
 
        ld      [%l4 + 0x00], %l6       ! entry = sun4c_kfree_ring.ringhd.next
        st      %l5, [%l6 + 0x08]       ! entry->vaddr = address
@@ -1000,10 +1000,11 @@ C_LABEL(invalid_segment_patch1):
 
        st      %l6, [%l4 + 0x00]       ! head->next = entry
 
-       ld      [%l4 + 0x10], %l3
+       ld      [%l4 + 0x18], %l3
        inc     %l3                     ! sun4c_kernel_ring.num_entries++
+       st      %l3, [%l4 + 0x18]
        b       4f
-        st     %l3, [%l4 + 0x10]
+        ld     [%l6 + 0x08], %l5
 
 2:
        or      %l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4
@@ -1023,7 +1024,7 @@ C_LABEL(invalid_segment_patch1):
 C_LABEL(vac_hwflush_patch1):
 C_LABEL(vac_linesize_patch):
        subcc   %l7, 16, %l7
-       b     9b
+       bne     9b
 C_LABEL(vac_hwflush_patch2):
         sta    %g0, [%l3 + %l7] ASI_FLUSHSEG
 
@@ -1044,47 +1045,36 @@ C_LABEL(vac_hwflush_patch2):
 
        mov     %l3, %l5                ! address = tmp
 
+4:
 C_LABEL(num_context_patch1):
        mov     0x08, %l7
 
-C_LABEL(invalid_segment_patch2):
-       mov     0x7f, %l4
+       ld      [%l6 + 0x08], %l4
+       ldub    [%l6 + 0x0c], %l3
+       or      %l4, %l3, %l4           ! encode new vaddr/pseg into l4
 
        sethi   %hi(AC_CONTEXT), %l3
        lduba   [%l3] ASI_CONTROL, %l6
 
-3:
-       deccc   %l7
-       stba    %l7, [%l3] ASI_CONTROL
-       bne     3b
-        stXa   %l4, [%l5] ASI_SEGMAP
-
-       stba    %l6, [%l3] ASI_CONTROL
-
-       ! reload the entry
-
-       sethi   %hi(C_LABEL(sun4c_kernel_ring)), %l4
-       ld      [%l4 + %lo(C_LABEL(sun4c_kernel_ring))], %l6
-
-       ld      [%l6 + 0x08], %l5       ! restore address from entry->vaddr
-
-4:
-C_LABEL(num_context_patch2):
-       mov     0x08, %l7
-
-       ldub    [%l6 + 0x0c], %l4       ! entry->pseg
-
+       /* Invalidate old mapping, instantiate new mapping,
+        * for each context.  Registers l6/l7 are live across
+        * this loop.
+        */
+3:     deccc   %l7
        sethi   %hi(AC_CONTEXT), %l3
-       lduba   [%l3] ASI_CONTROL, %l6
-
-3:
-       deccc   %l7
        stba    %l7, [%l3] ASI_CONTROL
+C_LABEL(invalid_segment_patch2):
+       mov     0x7f, %l3
+       stXa    %l3, [%l5] ASI_SEGMAP
+       andn    %l4, 0x1ff, %l3
        bne     3b
-        stXa   %l4, [%l5] ASI_SEGMAP
+        stXa   %l4, [%l3] ASI_SEGMAP
 
+       sethi   %hi(AC_CONTEXT), %l3
        stba    %l6, [%l3] ASI_CONTROL
 
+       andn    %l4, 0x1ff, %l5
+
 1:
        sethi   %hi(SUN4C_VMALLOC_START), %l4
        cmp     %l5, %l4
@@ -1152,6 +1142,7 @@ C_LABEL(num_context_patch2):
 
 sun4c_fault_fromuser:
        SAVE_ALL
+        nop
        
        mov     %l7, %o1                ! Decode the info from %l7
        mov     %l7, %o2
index aa0816a6810a9aecd89a8eb84a2ed96da89e0513..783feb814c7b214454eb3a2c3ae3531f593bbb78 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.95.2.2 1999/09/23 09:53:18 anton Exp $
+/* $Id: head.S,v 1.95.2.3 1999/11/12 15:45:45 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -450,7 +450,7 @@ C_LABEL(empty_zero_page):           .skip PAGE_SIZE
  */
        .ascii  "HdrS"
        .word   LINUX_VERSION_CODE
-       .half   0x0201          /* HdrS version */
+       .half   0x0203          /* HdrS version */
 C_LABEL(root_flags):
        .half   1
 C_LABEL(root_dev):
@@ -462,6 +462,8 @@ C_LABEL(sparc_ramdisk_image):
 C_LABEL(sparc_ramdisk_size):
        .word   0
        .word   C_LABEL(reboot_command)
+       .word   0, 0, 0
+       .word   _end
 
 /* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
  * %g7 and at prom_vector_p. And also quickly check whether we are on
index 01cb1baa099fa0bae253974388164919a3cdb6f3..8b7b632c1033dc062d194cfd86982153a1e8bb71 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.137.2.1 1999/08/07 10:42:45 davem Exp $
+/*  $Id: process.c,v 1.137.2.2 1999/10/01 01:32:53 anton Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -55,7 +55,6 @@ asmlinkage int sys_idle(void)
 {
        int ret = -EPERM;
 
-       lock_kernel();
        if (current->pid != 0)
                goto out;
 
@@ -100,7 +99,6 @@ asmlinkage int sys_idle(void)
        }
        ret = 0;
 out:
-       unlock_kernel();
        return ret;
 }
 
index 7f6ec54f980a0dfec33d46adbac3b3c5931298df..a4a296cf3f426ec2fdf939c2798f8d0ff6ba18ec 100644 (file)
@@ -37,12 +37,17 @@ static unsigned long get_long(struct task_struct * tsk,
        pmd_t * pgmiddle;
        pte_t * pgtable;
        unsigned long page, retval;
+       int fault;
 
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
        if (pgd_none(*pgdir)) {
-               handle_mm_fault(tsk, vma, addr, 0);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, 0);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return 0;
        }
        if (pgd_bad(*pgdir)) {
                printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
@@ -51,8 +56,12 @@ repeat:
        }
        pgmiddle = pmd_offset(pgdir, addr);
        if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk, vma, addr, 0);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, 0);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return 0;
        }
        if (pmd_bad(*pgmiddle)) {
                printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
@@ -61,8 +70,12 @@ repeat:
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 0);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, 0);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return 0;
        }
        page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -90,12 +103,17 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
        pmd_t *pgmiddle;
        pte_t *pgtable;
        unsigned long page;
+       int fault;
 
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
        if (!pgd_present(*pgdir)) {
-               handle_mm_fault(tsk, vma, addr, 1);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, 1);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return;
        }
        if (pgd_bad(*pgdir)) {
                printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
@@ -104,8 +122,12 @@ repeat:
        }
        pgmiddle = pmd_offset(pgdir, addr);
        if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk, vma, addr, 1);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, 1);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return;
        }
        if (pmd_bad(*pgmiddle)) {
                printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
@@ -114,13 +136,21 @@ repeat:
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 1);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, 1);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return;
        }
        page = pte_page(*pgtable);
        if (!pte_write(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 1);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, 1);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
        flush_cache_page(vma, addr);
index d29c1cb661388b393ec7269903f64f84a3f30a64..823100e7c5d3f25c8e546f76ddb8a4078155afa0 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.105 1999/04/13 14:17:08 jj Exp $
+/*  $Id: setup.c,v 1.105.2.1 1999/11/16 06:29:31 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -424,7 +424,9 @@ __initfunc(void setup_arch(char **cmdline_p,
                                initrd_start -= KERNBASE;
                                initrd_end -= KERNBASE;
                                break;
-                       }
+                       default:
+                               break;
+                       };
                }
        }
 #endif 
index 46b57cbb61938a870cde838408062b22f8ae26af..e52c91ba234b195e2571c6d9289efab956bdc45a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.77.2.3 1999/09/22 17:06:50 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.77.2.4 1999/09/28 16:47:30 davem Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -63,6 +63,7 @@ extern char saved_command_line[];
 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
+extern int __ashldi3(int, int);
 extern int __lshrdi3(int, int);
 
 extern void dump_thread(struct pt_regs *, struct user *);
@@ -269,6 +270,7 @@ EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memmove);
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
 EXPORT_SYMBOL_NOVERS(__lshrdi3);
 
 EXPORT_SYMBOL_DOT(rem);
index edd736b41bd844e4d88d6380b0c2115d84ca0345..1cff15a09544795a4899a397b63d1fac09c3922d 100644 (file)
@@ -99,6 +99,14 @@ __initfunc(void smp4d_callin(void))
        local_flush_cache_all();
        local_flush_tlb_all();
 
+       /*
+        * Unblock the master CPU _only_ when the scheduler state
+        * of all secondary CPUs will be up-to-date, so after
+        * the SMP initialization the master will be just allowed
+        * to call the scheduler code.
+        */
+       init_idle();
+
        /* Get our local ticker going. */
        smp_setup_percpu_timer();
 
index c9acf609c47e98157031305c055b0cd3c1d68046..09dd2d0bf6e72706594808d7b6d64b70dee68e9a 100644 (file)
@@ -93,6 +93,14 @@ __initfunc(void smp4m_callin(void))
        local_flush_cache_all();
        local_flush_tlb_all();
 
+       /*
+        * Unblock the master CPU _only_ when the scheduler state
+        * of all secondary CPUs will be up-to-date, so after
+        * the SMP initialization the master will be just allowed
+        * to call the scheduler code.
+        */
+       init_idle();
+
        /* Allow master to continue. */
        swap((unsigned long *)&cpu_callin_map[cpuid], 1);
        local_flush_cache_all();
index ed3918c10544d4aa57f5dfeb6cf01e5767322db2..92c565ab50b34aeefca2149bd6789f032852f9d2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $
+/* $Id: sys_sparc.c,v 1.52.2.1 1999/10/04 10:36:15 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -192,10 +192,17 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
        }
        retval = -ENOMEM;
        len = PAGE_ALIGN(len);
-       if(!(flags & MAP_FIXED) && !addr) {
-               addr = get_unmapped_area(addr, len);
+       if(!(flags & MAP_FIXED) &&
+          (!addr || (ARCH_SUN4C_SUN4 &&
+                     (addr >= 0x20000000 && addr < 0xe0000000)))) {
+               addr = get_unmapped_area(0, len);
                if(!addr)
                        goto out_putf;
+               if (ARCH_SUN4C_SUN4 &&
+                   (addr >= 0x20000000 && addr < 0xe0000000)) {
+                       retval = -EINVAL;
+                       goto out_putf;
+               }
        }
 
        /* See asm-sparc/uaccess.h */
@@ -203,14 +210,6 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
        if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
                goto out_putf;
 
-       if(ARCH_SUN4C_SUN4) {
-               if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
-                       /* VM hole */
-                       retval = current->mm->brk;
-                       goto out_putf;
-               }
-       }
-
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        retval = do_mmap(file, addr, len, prot, flags, off);
 
index 00d9624ad54476607263ead2af32af7a2e82987c..4357d4dcb9256032b95d8ac810f724cd4afb05c5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.94.2.2 1999/08/07 10:42:49 davem Exp $
+/* $Id: sys_sunos.c,v 1.94.2.3 1999/10/04 10:36:20 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -85,10 +85,17 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
        }
 
        retval = -ENOMEM;
-       if(!(flags & MAP_FIXED) && !addr) {
-               addr = get_unmapped_area(addr, len);
+       if(!(flags & MAP_FIXED) &&
+          (!addr || (ARCH_SUN4C_SUN4 &&
+                     (addr >= 0x20000000 && addr < 0xe0000000)))) {
+               addr = get_unmapped_area(0, len);
                if(!addr)
                        goto out_putf;
+               if (ARCH_SUN4C_SUN4 &&
+                   (addr >= 0x20000000 && addr < 0xe0000000)) {
+                       retval = -EINVAL;
+                       goto out_putf;
+               }
        }
        /* If this is ld.so or a shared library doing an mmap
         * of /dev/zero, transform it into an anonymous mapping.
@@ -111,13 +118,6 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
        if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
                goto out_putf;
 
-       if(ARCH_SUN4C_SUN4) {
-               if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
-                       retval = current->mm->brk;
-                       goto out_putf;
-               }
-       }
-
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        retval = do_mmap(file, addr, len, prot, flags, off);
        if(!ret_type)
index d5b4754802d6afee11dd53f1f4bd62aaf35bdd8d..5c37301930bb39caf263c57929d2ca6a37bccc92 100644 (file)
@@ -1,11 +1,12 @@
-# $Id: Makefile,v 1.28 1999/03/21 06:37:44 davem Exp $
+# $Id: Makefile,v 1.28.2.1 1999/09/28 16:47:36 davem Exp $
 # Makefile for Sparc library files..
 #
 
 OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
         strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
        strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
-       copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o
+       copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \
+       ashldi3.o
 
 ifdef CONFIG_SMP
 OBJS += irqlock.o
@@ -89,6 +90,9 @@ urem.o: urem.S
 ashrdi3.o: ashrdi3.S
        $(CC) -D__ASSEMBLY__ -c -o ashrdi3.o ashrdi3.S
 
+ashldi3.o: ashldi3.S
+       $(CC) -D__ASSEMBLY__ -c -o ashldi3.o ashldi3.S
+
 lshrdi3.o: lshrdi3.S
        $(CC) -D__ASSEMBLY__ -c -o lshrdi3.o lshrdi3.S
 
diff --git a/arch/sparc/lib/ashldi3.S b/arch/sparc/lib/ashldi3.S
new file mode 100644 (file)
index 0000000..81dcd17
--- /dev/null
@@ -0,0 +1,36 @@
+/* $Id: ashldi3.S,v 1.1.2.1 1999/09/28 16:47:39 davem Exp $
+ * ashldi3.S:  GCC emits these for certain drivers playing
+ *             with long longs.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/cprefix.h>
+
+       .text
+       .align  4
+       .globl  C_LABEL(__ashldi3)
+C_LABEL(__ashldi3):
+       cmp     %o2, 0
+       be      9f
+        mov    0x20, %g2
+
+       sub     %g2, %o2, %g2
+       cmp     %g2, 0
+       bg      7f
+        sll    %o0, %o2, %g3
+
+       neg     %g2
+       clr     %o5
+       b       8f
+        sll    %o1, %g2, %o4
+7:
+       srl     %o1, %g2, %g2
+       sll     %o1, %o2, %o5
+       or      %g3, %g2, %o4
+8:
+       mov     %o4, %o0
+       mov     %o5, %o1
+9:
+       retl
+        nop
index bf589c2833130e35592c055cfae89333adb614bd..ad0050675a84294d593abc44ec6d5b84e45786f0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ashrdi3.S,v 1.3 1996/09/07 23:18:10 davem Exp $
+/* $Id: ashrdi3.S,v 1.3.12.1 1999/09/28 16:47:42 davem Exp $
  * ashrdi3.S:  The filesystem code creates all kinds of references to
  *              this little routine on the sparc with gcc.
  *
@@ -7,7 +7,9 @@
 
 #include <asm/cprefix.h>
 
-               .globl C_LABEL(__ashrdi3)
+       .text
+       .align  4
+       .globl C_LABEL(__ashrdi3)
 C_LABEL(__ashrdi3):
        tst     %o2
        be      3f
index 76dbf643a0e0361de36dfda830faba16db60af05..fcabe58db5af26e2f7edba0891102ef11ec6251c 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.33 1999/01/02 16:45:47 davem Exp $
+# $Id: Makefile,v 1.33.2.1 1999/10/06 15:36:20 davem Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -12,7 +12,7 @@ O_OBJS   := fault.o init.o loadmmu.o generic.o asyncd.o extable.o btfixup.o
 ifeq ($(CONFIG_SUN4),y)
 O_OBJS  += nosrmmu.o
 else
-O_OBJS  += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o
+O_OBJS  += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
 endif
 ifdef CONFIG_SMP
 O_OBJS   += nosun4c.o
@@ -30,3 +30,6 @@ viking.o: viking.S
 
 tsunami.o: tsunami.S
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o tsunami.o tsunami.S
+
+swift.o: swift.S
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o swift.o swift.S
index 666bf8429f7f3be1a2bbfaafc08a738fb7a81ad8..72ede8b32ef5d44ce04275001c54f52b791a169a 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.12 1998/09/13 04:30:30 davem Exp $
+/*  $Id: asyncd.c,v 1.12.2.1 1999/11/16 06:29:36 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
@@ -152,7 +152,9 @@ static int fault_in_page(int taskid,
        if(!pte)
                goto no_memory;
        if(!pte_present(*pte)) {
-               handle_mm_fault(tsk, vma, address, write);
+               int fault = handle_mm_fault(tsk, vma, address, write);
+               if (fault < 0)
+                       goto no_memory;
                goto finish_up;
        }
        set_pte(pte, pte_mkyoung(*pte));
@@ -164,7 +166,11 @@ static int fault_in_page(int taskid,
                flush_tlb_page(vma, address);
                goto finish_up;
        }
-       handle_mm_fault(tsk, vma, address, write);
+       {
+               int fault = handle_mm_fault(tsk, vma, address, write);
+               if (fault < 0)
+                       goto no_memory;
+       }
 
        /* Fall through for do_wp_page */
 finish_up:
@@ -173,7 +179,7 @@ finish_up:
 
 no_memory:
        stats.failure++;
-       oom(tsk);
+       force_sig(SIGKILL, tsk);
        return 1;
        
 bad_area:        
index 274d53dab5fc5b42d2177a4807f3bfdd6772b651..b2f09a00762feb697367362b66feb1a90df1a1ae 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.101.2.2 1999/08/07 10:42:53 davem Exp $
+/* $Id: fault.c,v 1.101.2.5 1999/11/16 06:29:39 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -237,8 +237,14 @@ good_area:
                if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
-       if (!handle_mm_fault(current, vma, address, write))
-               goto do_sigbus;
+survive:
+       {
+               int fault = handle_mm_fault(current, vma, address, write);
+               if (!fault)
+                       goto do_sigbus;
+               if (fault < 0)
+                       goto out_of_memory;
+       }
        up(&mm->mmap_sem);
        return;
        /*
@@ -288,6 +294,17 @@ do_kernel_fault:
        unhandled_fault (address, tsk, regs);
        return;
 
+out_of_memory:
+       if (tsk->pid == 1) {
+               tsk->policy |= SCHED_YIELD;
+               schedule();
+               goto survive;
+       }
+       up(&mm->mmap_sem);
+       printk("VM: killing process %s\n", tsk->comm);
+       do_exit(SIGKILL);
+       return;
+
 do_sigbus:
        up(&mm->mmap_sem);
        tsk->tss.sig_address = address;
@@ -309,8 +326,18 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
        pgd_t *pgdp;
        pte_t *ptep;
 
-       if (text_fault)
+       if (text_fault) {
                address = regs->pc;
+       } else if (!write &&
+                  !(regs->psr & PSR_PS)) {
+               unsigned int insn, *ip;
+
+               ip = (unsigned int *)regs->pc;
+               if (! get_user(insn, ip)) {
+                       if ((insn & 0xc1680000) == 0xc0680000)
+                               write = 1;
+               }
+       }
 
        pgdp = sun4c_pgd_offset(mm, address);
        ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
@@ -319,28 +346,36 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
            if (write) {
                if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
                                   == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
+                       unsigned long flags;
 
                        *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
                                      _SUN4C_PAGE_MODIFIED |
                                      _SUN4C_PAGE_VALID |
                                      _SUN4C_PAGE_DIRTY);
 
+                       save_and_cli(flags);
                        if (sun4c_get_segmap(address) != invalid_segment) {
                                sun4c_put_pte(address, pte_val(*ptep));
+                               restore_flags(flags);
                                return;
                        }
+                       restore_flags(flags);
                }
            } else {
                if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
                                   == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
+                       unsigned long flags;
 
                        *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
                                      _SUN4C_PAGE_VALID);
 
+                       save_and_cli(flags);
                        if (sun4c_get_segmap(address) != invalid_segment) {
                                sun4c_put_pte(address, pte_val(*ptep));
+                               restore_flags(flags);
                                return;
                        }
+                       restore_flags(flags);
                }
            }
        }
@@ -389,8 +424,14 @@ good_area:
                if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
-       if (!handle_mm_fault(current, vma, address, write))
-               goto do_sigbus;
+survive:
+       {
+               int fault = handle_mm_fault(current, vma, address, write);
+               if (!fault)
+                       goto do_sigbus;
+               if (fault < 0)
+                       goto out_of_memory;
+       }
        up(&mm->mmap_sem);
        return;
 bad_area:
@@ -404,6 +445,17 @@ bad_area:
        send_sig(SIGSEGV, tsk, 1);
        return;
 
+out_of_memory:
+       if (tsk->pid == 1) {
+               tsk->policy |= SCHED_YIELD;
+               schedule();
+               goto survive;
+       }
+       up(&mm->mmap_sem);
+       printk("VM: killing process %s\n", tsk->comm);
+       do_exit(SIGKILL);
+       return;
+
 do_sigbus:
        up(&mm->mmap_sem);
        tsk->tss.sig_address = address;
@@ -415,31 +467,25 @@ void window_overflow_fault(void)
 {
        unsigned long sp;
 
-       lock_kernel();
        sp = current->tss.rwbuf_stkptrs[0];
        if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
                force_user_fault(sp + 0x38, 1);
        force_user_fault(sp, 1);
-       unlock_kernel();
 }
 
 void window_underflow_fault(unsigned long sp)
 {
-       lock_kernel();
        if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
                force_user_fault(sp + 0x38, 0);
        force_user_fault(sp, 0);
-       unlock_kernel();
 }
 
 void window_ret_fault(struct pt_regs *regs)
 {
        unsigned long sp;
 
-       lock_kernel();
        sp = regs->u_regs[UREG_FP];
        if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
                force_user_fault(sp + 0x38, 0);
        force_user_fault(sp, 0);
-       unlock_kernel();
 }
index 2f233e1b3b87449d44587e34eaf427e2fb6b3cc4..fc5c328de0c3c763dafdda532dbdb17e72d0a03e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.10.2.1 1999/08/13 12:35:35 davem Exp $
+/* $Id: iommu.c,v 1.10.2.2 1999/11/03 03:05:55 davem Exp $
  * iommu.c:  IOMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -16,6 +16,7 @@
 #include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/mxcc.h>
+#include <asm/mbus.h>
 
 /* srmmu.c */
 extern int viking_mxcc_present;
@@ -201,16 +202,19 @@ static void iommu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_s
 #ifdef CONFIG_SBUS
 static void iommu_map_dma_area(unsigned long addr, int len)
 {
-       unsigned long page, end;
+       unsigned long page, end, ipte_cache;
        pgprot_t dvma_prot;
        struct iommu_struct *iommu = SBus_chain->iommu;
        iopte_t *iopte = iommu->page_table;
        iopte_t *first;
 
-       if(viking_mxcc_present)
+       if(viking_mxcc_present || srmmu_modtype == HyperSparc) {
                dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
-       else
+               ipte_cache = 1;
+       } else {
                dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV);
+               ipte_cache = 0;
+       }
 
        iopte += ((addr - iommu->start) >> PAGE_SHIFT);
        first = iopte;
@@ -229,13 +233,20 @@ static void iommu_map_dma_area(unsigned long addr, int len)
                                viking_mxcc_flush_page(page);
                        else if (viking_flush)
                                viking_flush_page(page);
+                       else
+                               flush_page_to_ram(page);
 
                        pgdp = pgd_offset(init_task.mm, addr);
                        pmdp = pmd_offset(pgdp, addr);
                        ptep = pte_offset(pmdp, addr);
 
                        set_pte(ptep, pte_val(mk_pte(page, dvma_prot)));
-                       iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
+                       if (ipte_cache != 0) {
+                               iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
+                       } else {
+                               iopte_val(*iopte++) =
+                                       MKIOPTE(mmu_v2p(page)) & ~IOPTE_CACHE;
+                       }
                }
                addr += PAGE_SIZE;
        }
index b87b2bdeb07f3e5b242169e3894d4261ab4890de..830ab7c0894ea50864cb988f7aaae806a912b3e3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: nosrmmu.c,v 1.2 1999/03/30 10:17:39 jj Exp $
+/* $Id: nosrmmu.c,v 1.2.2.1 1999/10/06 10:52:37 anton Exp $
  * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, 
  *         so that it does not need srmmu and avoid ifdefs.
  *
@@ -14,6 +14,8 @@ static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
 
 enum mbus_module srmmu_modtype;
 
+int vac_cache_size = 0;
+
 __initfunc(static void should_not_happen(void))
 {
        prom_printf(shouldnothappen);
index 68a2dae914fb1ba26e5281f357751dda2cc00df5..4d103826ef1fc74e3948ddf7ad2e2c18e18459ac 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.187.2.2 1999/09/21 11:24:15 anton Exp $
+/* $Id: srmmu.c,v 1.187.2.7 1999/11/16 06:29:44 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -114,7 +114,9 @@ static unsigned long srmmu_p2v_hash[SRMMU_HASHSZ];
 #define srmmu_ahashfn(addr)    ((addr) >> 24)
 
 int viking_mxcc_present = 0;
+#ifdef __SMP__
 static spinlock_t srmmu_context_spinlock = SPIN_LOCK_UNLOCKED;
+#endif
 
 /* Physical memory can be _very_ non-contiguous on the sun4m, especially
  * the SS10/20 class machines and with the latest openprom revisions.
@@ -725,6 +727,17 @@ static void srmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval)
        srmmu_set_entry(ptep, pte_val(pteval));
 }
 
+extern void swift_flush_chunk(unsigned long chunk);
+
+static void srmmu_set_pte_nocache_swift(pte_t *ptep, pte_t pteval)
+{
+       unsigned long page;
+
+       srmmu_set_entry(ptep, pte_val(pteval));
+       page = ((unsigned long)ptep) & PAGE_MASK;
+       swift_flush_chunk(page);
+}
+
 static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval)
 {
        register unsigned long a, b, c, d, e, f, g;
@@ -909,7 +922,8 @@ static void srmmu_free_task_struct(struct task_struct *tsk)
 /* tsunami.S */
 extern void tsunami_flush_cache_all(void);
 extern void tsunami_flush_cache_mm(struct mm_struct *mm);
-extern void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_cache_range(struct mm_struct *mm,
+                                     unsigned long start, unsigned long end);
 extern void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void tsunami_flush_page_to_ram(unsigned long page);
 extern void tsunami_flush_page_for_dma(unsigned long page);
@@ -917,111 +931,54 @@ extern void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_add
 extern void tsunami_flush_chunk(unsigned long chunk);
 extern void tsunami_flush_tlb_all(void);
 extern void tsunami_flush_tlb_mm(struct mm_struct *mm);
-extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_tlb_range(struct mm_struct *mm,
+                                   unsigned long start, unsigned long end);
 extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
-
-/* Workaround, until we find what's going on with Swift. When low on memory, it sometimes
- * loops in fault/handle_mm_fault incl. flush_tlb_page to find out it is already in page tables/
- * fault again on the same instruction. I really don't understand it, have checked it and contexts
- * are right, flush_tlb_all is done as well, and it faults again... Strange. -jj
- */
-static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
-{
-       static unsigned long last;
-
-       if (last == address) viking_hwprobe(address);
-       last = address;
-}
-
-/* Swift flushes.  It has the recommended SRMMU specification flushing
- * facilities, so we can do things in a more fine grained fashion than we
- * could on the tsunami.  Let's watch out for HARDWARE BUGS...
- */
-
-static void swift_flush_cache_all(void)
-{
-       flush_user_windows();
-       swift_idflash_clear();
-}
-
-static void swift_flush_cache_mm(struct mm_struct *mm)
-{
-       FLUSH_BEGIN(mm)
-       flush_user_windows();
-       swift_idflash_clear();
-       FLUSH_END
-}
-
-static void swift_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-       FLUSH_BEGIN(mm)
-       flush_user_windows();
-       swift_idflash_clear();
-       FLUSH_END
-}
-
-static void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
-       FLUSH_BEGIN(vma->vm_mm)
-       flush_user_windows();
-       if(vma->vm_flags & VM_EXEC)
-               swift_flush_icache();
-       swift_flush_dcache();
-       FLUSH_END
-}
-
-/* Not copy-back on swift. */
-static void swift_flush_page_to_ram(unsigned long page)
-{
-}
-
-/* But not IO coherent either. */
-static void swift_flush_page_for_dma(unsigned long page)
-{
-       swift_flush_dcache();
-}
-
-/* Again, Swift is non-snooping split I/D cache'd just like tsunami,
- * so have to punt the icache for on-stack signal insns.  Only the
- * icache need be flushed since the dcache is write-through.
- */
-static void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
-       swift_flush_icache();
-}
-
-static void swift_flush_chunk(unsigned long chunk)
+extern void tsunami_setup_blockops(void);
+
+/* swift.S */
+extern void swift_flush_cache_all(void);
+extern void swift_flush_cache_mm(struct mm_struct *mm);
+extern void swift_flush_cache_range(struct mm_struct *mm,
+                                   unsigned long start, unsigned long end);
+extern void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
+extern void swift_flush_page_to_ram(unsigned long page);
+extern void swift_flush_page_for_dma(unsigned long page);
+extern void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
+extern void swift_flush_tlb_all(void);
+extern void swift_flush_tlb_mm(struct mm_struct *mm);
+extern void swift_flush_tlb_range(struct mm_struct *mm,
+                                 unsigned long start, unsigned long end);
+extern void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+
+static void swift_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
 {
+       if(pgdp != swapper_pg_dir)
+               swift_flush_chunk((unsigned long)pgdp);
+       if(tsk->mm->context != NO_CONTEXT &&
+          tsk->mm->pgd != pgdp) {
+               swift_flush_cache_mm(tsk->mm);
+               ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
+               swift_flush_tlb_mm(tsk->mm);
+       }
 }
 
-static void swift_flush_tlb_all(void)
+static void swift_init_new_context(struct mm_struct *mm)
 {
-       srmmu_flush_whole_tlb();
-       module_stats.invall++;
-}
+       ctxd_t *ctxp;
 
-static void swift_flush_tlb_mm(struct mm_struct *mm)
-{
-       FLUSH_BEGIN(mm)
-       srmmu_flush_whole_tlb();
-       module_stats.invmm++;
-       FLUSH_END
-}
+       spin_lock(&srmmu_context_spinlock);
+       alloc_context(mm);
+       spin_unlock(&srmmu_context_spinlock);
 
-static void swift_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-       FLUSH_BEGIN(mm)
-       srmmu_flush_whole_tlb();
-       module_stats.invrnge++;
-       FLUSH_END
-}
+       ctxp = &srmmu_context_table[mm->context];
+       srmmu_set_entry((pte_t *)ctxp,
+                       __pte((SRMMU_ET_PTD |
+                              (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
+       swift_flush_chunk(((unsigned long)ctxp) & PAGE_MASK);
 
-static void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-       FLUSH_BEGIN(vma->vm_mm)
-       srmmu_flush_whole_tlb();
-       module_stats.invpg++;
-       FLUSH_END
+       if(mm == current->mm)
+               srmmu_set_context(mm->context);
 }
 
 /* The following are all MBUS based SRMMU modules, and therefore could
@@ -1306,7 +1263,8 @@ extern void sun4dsmp_flush_tlb_page(struct vm_area_struct *vma,
 /* hypersparc.S */
 extern void hypersparc_flush_cache_all(void);
 extern void hypersparc_flush_cache_mm(struct mm_struct *mm);
-extern void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_cache_range(struct mm_struct *mm,
+                                        unsigned long start, unsigned long end);
 extern void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void hypersparc_flush_page_to_ram(unsigned long page);
 extern void hypersparc_flush_chunk(unsigned long chunk);
@@ -1314,7 +1272,8 @@ extern void hypersparc_flush_page_for_dma(unsigned long page);
 extern void hypersparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 extern void hypersparc_flush_tlb_all(void);
 extern void hypersparc_flush_tlb_mm(struct mm_struct *mm);
-extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_tlb_range(struct mm_struct *mm,
+                                      unsigned long start, unsigned long end);
 extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 extern void hypersparc_setup_blockops(void);
 
@@ -1328,7 +1287,8 @@ static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval)
 
 static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
 {
-       srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))));
+       srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD |
+                                             (srmmu_v2p((unsigned long) pgdp) >> 4))));
        hypersparc_flush_page_to_ram((unsigned long)ctxp);
        hyper_flush_whole_icache();
 }
@@ -1407,7 +1367,9 @@ static void hypersparc_switch_to_context(struct task_struct *tsk)
                alloc_context(tsk->mm);
                spin_unlock(&srmmu_context_spinlock);
                ctxp = &srmmu_context_table[tsk->mm->context];
-               srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
+               srmmu_set_entry((pte_t *)ctxp,
+                               __pte((SRMMU_ET_PTD |
+                                      (srmmu_v2p((unsigned long) tsk->mm->pgd) >> 4))));
                hypersparc_flush_page_to_ram((unsigned long)ctxp);
        }
        hyper_flush_whole_icache();
@@ -1423,7 +1385,9 @@ static void hypersparc_init_new_context(struct mm_struct *mm)
        spin_unlock(&srmmu_context_spinlock);
 
        ctxp = &srmmu_context_table[mm->context];
-       srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
+       srmmu_set_entry((pte_t *)ctxp,
+                       __pte((SRMMU_ET_PTD |
+                              (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
        hypersparc_flush_page_to_ram((unsigned long)ctxp);
 
        if(mm == current->mm) {
@@ -1450,12 +1414,14 @@ static inline unsigned long srmmu_early_paddr(unsigned long vaddr)
 
 static inline void srmmu_early_pgd_set(pgd_t *pgdp, pmd_t *pmdp)
 {
-       set_pte((pte_t *)pgdp, __pte((SRMMU_ET_PTD | (srmmu_early_paddr((unsigned long) pmdp) >> 4))));
+       set_pte((pte_t *)pgdp, __pte((SRMMU_ET_PTD |
+                                     (srmmu_early_paddr((unsigned long) pmdp) >> 4))));
 }
 
 static inline void srmmu_early_pmd_set(pmd_t *pmdp, pte_t *ptep)
 {
-       set_pte((pte_t *)pmdp, __pte((SRMMU_ET_PTD | (srmmu_early_paddr((unsigned long) ptep) >> 4))));
+       set_pte((pte_t *)pmdp, __pte((SRMMU_ET_PTD |
+                                     (srmmu_early_paddr((unsigned long) ptep) >> 4))));
 }
 
 static inline unsigned long srmmu_early_pgd_page(pgd_t pgd)
@@ -1470,12 +1436,14 @@ static inline unsigned long srmmu_early_pmd_page(pmd_t pmd)
 
 static inline pmd_t *srmmu_early_pmd_offset(pgd_t *dir, unsigned long address)
 {
-       return (pmd_t *) srmmu_early_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
+       return (pmd_t *) srmmu_early_pgd_page(*dir) +
+               ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
 }
 
 static inline pte_t *srmmu_early_pte_offset(pmd_t *dir, unsigned long address)
 {
-       return (pte_t *) srmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+       return (pte_t *) srmmu_early_pmd_page(*dir) +
+               ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
 }
 
 static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end)
@@ -2245,6 +2213,7 @@ __initfunc(static void poke_hypersparc(void))
 __initfunc(static void init_hypersparc(void))
 {
        srmmu_name = "ROSS HyperSparc";
+       srmmu_modtype = HyperSparc;
 
        init_vac_layout();
 
@@ -2373,21 +2342,14 @@ __initfunc(static void init_cypress_605(unsigned long mrev))
 
 __initfunc(static void poke_swift(void))
 {
-       unsigned long mreg = srmmu_get_mmureg();
+       unsigned long mreg;
 
        /* Clear any crap from the cache or else... */
-       swift_idflash_clear();
-       mreg |= (SWIFT_IE | SWIFT_DE); /* I & D caches on */
-
-       /* The Swift branch folding logic is completely broken.  At
-        * trap time, if things are just right, if can mistakenly
-        * think that a trap is coming from kernel mode when in fact
-        * it is coming from user mode (it mis-executes the branch in
-        * the trap code).  So you see things like crashme completely
-        * hosing your machine which is completely unacceptable.  Turn
-        * this shit off... nice job Fujitsu.
-        */
-       mreg &= ~(SWIFT_BF);
+       swift_flush_cache_all();
+
+       /* Enable I & D caches */
+       mreg = srmmu_get_mmureg();
+       mreg |= (SWIFT_IE | SWIFT_DE);
        srmmu_set_mmureg(mreg);
 }
 
@@ -2444,18 +2406,24 @@ __initfunc(static void init_swift(void))
        BTFIXUPSET_CALL(flush_cache_page, swift_flush_cache_page, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_cache_range, swift_flush_cache_range, BTFIXUPCALL_NORM);
 
-       BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
+       BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
 
        BTFIXUPSET_CALL(flush_tlb_all, swift_flush_tlb_all, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_tlb_mm, swift_flush_tlb_mm, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_tlb_page, swift_flush_tlb_page, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_tlb_range, swift_flush_tlb_range, BTFIXUPCALL_NORM);
 
-       BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_sig_insns, swift_flush_sig_insns, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_page_for_dma, swift_flush_page_for_dma, BTFIXUPCALL_NORM);
 
-       BTFIXUPSET_CALL(update_mmu_cache, swift_update_mmu_cache, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(update_mmu_cache, srmmu_update_mmu_cache, BTFIXUPCALL_NOP);
+
+       BTFIXUPSET_CALL(sparc_update_rootmmu_dir, swift_update_rootmmu_dir, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_swift, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(init_new_context, swift_init_new_context, BTFIXUPCALL_NORM);
+
+       flush_page_for_dma_global = 0;
 
        /* Are you now convinced that the Swift is one of the
         * biggest VLSI abortions of all time?  Bravo Fujitsu!
@@ -2613,7 +2581,7 @@ __initfunc(static void init_turbosparc(void))
        BTFIXUPSET_CALL(flush_chunk, turbosparc_flush_chunk, BTFIXUPCALL_NORM);
 
        BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP);
-       BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NOP);
+       BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NORM);
 
        poke_srmmu = poke_turbosparc;
 }
@@ -2644,7 +2612,7 @@ __initfunc(static void init_tsunami(void))
        BTFIXUPSET_CALL(flush_cache_page, tsunami_flush_cache_page, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_cache_range, tsunami_flush_cache_range, BTFIXUPCALL_NORM);
 
-       BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NOP); /* local flush _only_ */
+       BTFIXUPSET_CALL(flush_chunk, tsunami_flush_chunk, BTFIXUPCALL_NORM); /* local flush _only_ */
 
        BTFIXUPSET_CALL(flush_tlb_all, tsunami_flush_tlb_all, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_tlb_mm, tsunami_flush_tlb_mm, BTFIXUPCALL_NORM);
@@ -2656,6 +2624,8 @@ __initfunc(static void init_tsunami(void))
        BTFIXUPSET_CALL(flush_page_for_dma, tsunami_flush_page_for_dma, BTFIXUPCALL_NORM);
 
        poke_srmmu = poke_tsunami;
+
+       tsunami_setup_blockops();
 }
 
 __initfunc(static void poke_viking(void))
@@ -2738,8 +2708,7 @@ __initfunc(static void init_viking(void))
                 * which we use the IOMMU.
                 */
                BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page, BTFIXUPCALL_NORM);
-               /* Also, this is so far the only chip which actually uses
-                  the page argument to flush_page_for_dma */
+
                flush_page_for_dma_global = 0;
        } else {
                srmmu_name = "TI Viking/MXCC";
index d3cb2f6d772cf9753f745e05e8cacf8a7720059b..62e78c461b0e21120e6167ff4248db089fa025a4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.173.2.1 1999/09/08 00:32:02 davem Exp $
+/* $Id: sun4c.c,v 1.173.2.5 1999/10/11 08:24:44 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/mmu_context.h>
 #include <asm/sun4paddr.h>
 
-/* TODO: Make it such that interrupt handlers cannot dick with
- *       the user segment lists, most of the cli/sti pairs can
- *       disappear once that is taken care of.
- */
-
-/* XXX Ok the real performance win, I figure, will be to use a combined hashing
- * XXX and bitmap scheme to keep track of what we have mapped where.  The whole
- * XXX incentive is to make it such that the range flushes can be serviced
- * XXX always in near constant time. --DaveM
+/* Because of our dynamic kernel TLB miss strategy, and how
+ * our DVMA mapping allocation works, you _MUST_:
+ *
+ * 1) Disable interrupts _and_ not touch any dynamic kernel
+ *    memory while messing with kernel MMU state.  By
+ *    dynamic memory I mean any object which is not in
+ *    the kernel image itself or a task_struct (both of
+ *    which are locked into the MMU).
+ * 2) Disable interrupts while messing with user MMU state.
  */
 
 extern int num_segmaps, num_contexts;
 
-/* Define this to get extremely anal debugging, undefine for performance. */
-/* #define DEBUG_SUN4C_MM */
-
-#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))
-
-/* This is used in many routines below. */
-#define FUW_INLINE do {                                                        \
-       register int ctr asm("g5");                                     \
-       ctr = 0;                                                        \
-       __asm__ __volatile__("\n"                                       \
-       "1:     ld      [%%g6 + %2], %%g4       ! flush user windows\n" \
-       "       orcc    %%g0, %%g4, %%g0\n"                             \
-       "       add     %0, 1, %0\n"                                    \
-       "       bne     1b\n"                                           \
-       "        save   %%sp, -64, %%sp\n"                              \
-       "2:     subcc   %0, 1, %0\n"                                    \
-       "       bne     2b\n"                                           \
-       "        restore %%g0, %%g0, %%g0\n"                            \
-       : "=&r" (ctr)                                                   \
-       : "0" (ctr), "i" (UWINMASK_OFFSET)                              \
-       : "g4", "cc");                                                  \
-} while(0);
-
 #ifdef CONFIG_SUN4
 #define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
 #else
@@ -82,58 +59,21 @@ extern int num_segmaps, num_contexts;
 #define MIN(a,b) ((a)<(b)?(a):(b))
 #endif
 
-
-#define KGPROF_PROFILING 0
-#if KGPROF_PROFILING
-#define KGPROF_DEPTH 3 /* this needs to match the code below */
-#define KGPROF_SIZE 100
-static struct {
-       unsigned addr[KGPROF_DEPTH];
-       unsigned count;
-} kgprof_counters[KGPROF_SIZE];
-
-/* just call this function from whatever function you think needs it then
-   look at /proc/cpuinfo to see where the function is being called from
-   and how often. This gives a type of "kernel gprof" */
-#define NEXT_PROF(prev,lvl) (prev>PAGE_OFFSET?__builtin_return_address(lvl):0)
-static inline void kgprof_profile(void)
-{
-       unsigned ret[KGPROF_DEPTH];
-       int i,j;
-       /* you can't use a variable argument to __builtin_return_address() */
-       ret[0] = (unsigned)__builtin_return_address(0);
-       ret[1] = (unsigned)NEXT_PROF(ret[0],1);
-       ret[2] = (unsigned)NEXT_PROF(ret[1],2);
-
-       for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
-               for (j=0;j<KGPROF_DEPTH;j++) 
-                       if (ret[j] != kgprof_counters[i].addr[j]) break;
-               if (j==KGPROF_DEPTH) break;
-       }
-       if (i<KGPROF_SIZE) {            
-               for (j=0;j<KGPROF_DEPTH;j++)
-                       kgprof_counters[i].addr[j] = ret[j];
-               kgprof_counters[i].count++;
-       }
-}
-#endif
-
-
 /* Flushing the cache. */
 struct sun4c_vac_props sun4c_vacinfo;
-static int ctxflushes, segflushes, pageflushes;
 unsigned long sun4c_kernel_faults;
 
 /* convert a virtual address to a physical address and vice
-   versa. Easy on the 4c */
+ * versa. Easy on the 4c
+ */
 static unsigned long sun4c_v2p(unsigned long vaddr)
 {
-  return(vaddr - PAGE_OFFSET);
+       return (vaddr - PAGE_OFFSET);
 }
 
 static unsigned long sun4c_p2v(unsigned long vaddr)
 {
-  return(vaddr + PAGE_OFFSET);
+       return (vaddr + PAGE_OFFSET);
 }
 
 
@@ -142,44 +82,64 @@ void sun4c_flush_all(void)
 {
        unsigned long begin, end;
 
-       if(sun4c_vacinfo.on)
+       if (sun4c_vacinfo.on)
                panic("SUN4C: AIEEE, trying to invalidate vac while"
                       " it is on.");
 
        /* Clear 'valid' bit in all cache line tags */
        begin = AC_CACHETAGS;
        end = (AC_CACHETAGS + SUN4C_VAC_SIZE);
-       while(begin < end) {
+       while (begin < end) {
                __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
                                     "r" (begin), "i" (ASI_CONTROL));
                begin += sun4c_vacinfo.linesize;
        }
 }
 
-/* Context level flush. */
-static inline void sun4c_flush_context_hw(void)
+static __inline__ void sun4c_flush_context_hw(void)
 {
        unsigned long end = SUN4C_VAC_SIZE;
-       unsigned pgsz = PAGE_SIZE;
 
-       ctxflushes++;
-       __asm__ __volatile__("
-1:     subcc   %0, %2, %0
-       bg      1b
-        sta    %%g0, [%0] %3
-       nop; nop; nop;          ! Weitek hwbug
-"      : "=&r" (end)
-       : "0" (end), "r" (pgsz), "i" (ASI_HWFLUSHCONTEXT)
+       __asm__ __volatile__(
+               "1:     addcc   %0, -4096, %0\n\t"
+               "       bne     1b\n\t"
+               "        sta    %%g0, [%0] %2"
+       : "=&r" (end)
+       : "0" (end), "i" (ASI_HWFLUSHCONTEXT)
        : "cc");
 }
 
+/* Must be called minimally with IRQs disabled. */
+static void sun4c_flush_segment_hw(unsigned long addr)
+{
+       if (sun4c_get_segmap(addr) != invalid_segment) {
+               unsigned long vac_size = SUN4C_VAC_SIZE;
+
+               __asm__ __volatile__(
+                       "1:     addcc   %0, -4096, %0\n\t"
+                       "       bne     1b\n\t"
+                       "        sta    %%g0, [%2 + %0] %3"
+                       : "=&r" (vac_size)
+                       : "0" (vac_size), "r" (addr), "i" (ASI_HWFLUSHSEG)
+                       : "cc");
+       }
+}
+
+/* Must be called minimally with interrupts disabled. */
+static __inline__ void sun4c_flush_page_hw(unsigned long addr)
+{
+       addr &= PAGE_MASK;
+       if ((int)sun4c_get_pte(addr) < 0)
+               __asm__ __volatile__("sta %%g0, [%0] %1"
+                                    : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
+}
+
 /* Don't inline the software version as it eats too many cache lines if expanded. */
 static void sun4c_flush_context_sw(void)
 {
        unsigned long nbytes = SUN4C_VAC_SIZE;
        unsigned long lsize = sun4c_vacinfo.linesize;
 
-       ctxflushes++;
        __asm__ __volatile__("
        add     %2, %2, %%g1
        add     %2, %%g1, %%g2
@@ -203,72 +163,13 @@ static void sun4c_flush_context_sw(void)
        : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
 }
 
-/* Scrape the segment starting at ADDR from the virtual cache. */
-static inline void sun4c_flush_segment(unsigned long addr)
-{
-       if(sun4c_get_segmap(addr) == invalid_segment)
-               return;
-
-       segflushes++;
-       if(sun4c_vacinfo.do_hwflushes) {
-               unsigned long end = (addr + SUN4C_VAC_SIZE);
-
-               for( ; addr < end; addr += PAGE_SIZE)
-                       __asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
-                                            "r" (addr), "i" (ASI_HWFLUSHSEG));
-       } else {
-               unsigned long nbytes = SUN4C_VAC_SIZE;
-               unsigned long lsize = sun4c_vacinfo.linesize;
-
-               __asm__ __volatile__("add       %2, %2, %%g1\n\t"
-                                    "add       %2, %%g1, %%g2\n\t"
-                                    "add       %2, %%g2, %%g3\n\t"
-                                    "add       %2, %%g3, %%g4\n\t"
-                                    "add       %2, %%g4, %%g5\n\t"
-                                    "add       %2, %%g5, %%o4\n\t"
-                                    "add       %2, %%o4, %%o5\n"
-                                    "1:\n\t"
-                                    "subcc     %1, %%o5, %1\n\t"
-                                    "sta       %%g0, [%0] %6\n\t"
-                                    "sta       %%g0, [%0 + %2] %6\n\t"
-                                    "sta       %%g0, [%0 + %%g1] %6\n\t"
-                                    "sta       %%g0, [%0 + %%g2] %6\n\t"
-                                    "sta       %%g0, [%0 + %%g3] %6\n\t"
-                                    "sta       %%g0, [%0 + %%g4] %6\n\t"
-                                    "sta       %%g0, [%0 + %%g5] %6\n\t"
-                                    "sta       %%g0, [%0 + %%o4] %6\n\t"
-                                    "bg        1b\n\t"
-                                    " add      %0, %%o5, %0\n\t"
-                                    : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize)
-                                    : "0" (addr), "1" (nbytes), "2" (lsize),
-                                      "i" (ASI_FLUSHSEG)
-                                    : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
-       }
-}
-
-/* Call this version when you know hardware flushes are available. */
-static inline void sun4c_flush_segment_hw(unsigned long addr)
-{
-       if(sun4c_get_segmap(addr) != invalid_segment) {
-               unsigned long end;
-
-               segflushes++;
-               for(end = addr + SUN4C_VAC_SIZE; addr < end; addr += PAGE_SIZE)
-                       __asm__ __volatile__("sta %%g0, [%0] %1"
-                                            : : "r" (addr), "i" (ASI_HWFLUSHSEG));
-               /* Weitek POWER-UP hwbug workaround. */
-               __asm__ __volatile__("nop;nop;nop;      ! Weitek hwbug");
-       }
-}
-
 /* Don't inline the software version as it eats too many cache lines if expanded. */
 static void sun4c_flush_segment_sw(unsigned long addr)
 {
-       if(sun4c_get_segmap(addr) != invalid_segment) {
+       if (sun4c_get_segmap(addr) != invalid_segment) {
                unsigned long nbytes = SUN4C_VAC_SIZE;
                unsigned long lsize = sun4c_vacinfo.linesize;
 
-               segflushes++;
                __asm__ __volatile__("
                add     %2, %2, %%g1
                add     %2, %%g1, %%g2
@@ -300,12 +201,11 @@ static void sun4c_flush_page(unsigned long addr)
 {
        addr &= PAGE_MASK;
 
-       if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
-          _SUN4C_PAGE_VALID)
+       if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
+           _SUN4C_PAGE_VALID)
                return;
 
-       pageflushes++;
-       if(sun4c_vacinfo.do_hwflushes) {
+       if (sun4c_vacinfo.do_hwflushes) {
                __asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
                                     "r" (addr), "i" (ASI_HWFLUSHPAGE));
        } else {
@@ -338,30 +238,15 @@ static void sun4c_flush_page(unsigned long addr)
        }
 }
 
-/* Again, hw-only and sw-only cache page-level flush variants. */
-static inline void sun4c_flush_page_hw(unsigned long addr)
-{
-       addr &= PAGE_MASK;
-       if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
-          _SUN4C_PAGE_VALID) {
-               pageflushes++;
-               __asm__ __volatile__("sta %%g0, [%0] %1"
-                                    : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
-               /* Weitek POWER-UP hwbug workaround. */
-               __asm__ __volatile__("nop;nop;nop;      ! Weitek hwbug");
-       }
-}
-
 /* Don't inline the software version as it eats too many cache lines if expanded. */
 static void sun4c_flush_page_sw(unsigned long addr)
 {
        addr &= PAGE_MASK;
-       if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
-          _SUN4C_PAGE_VALID) {
+       if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
+           _SUN4C_PAGE_VALID) {
                unsigned long left = PAGE_SIZE;
                unsigned long lsize = sun4c_vacinfo.linesize;
 
-               pageflushes++;
                __asm__ __volatile__("
                add     %2, %2, %%g1
                add     %2, %%g1, %%g2
@@ -411,7 +296,7 @@ static inline void sun4c_init_clean_segmap(unsigned char pseg)
        unsigned long vaddr;
 
        sun4c_put_segmap(0, pseg);
-       for(vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr+=PAGE_SIZE)
+       for (vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr += PAGE_SIZE)
                sun4c_put_pte(vaddr, 0);
        sun4c_put_segmap(0, invalid_segment);
 }
@@ -423,15 +308,15 @@ static inline void sun4c_init_clean_mmu(unsigned long kernel_end)
 
        savectx = sun4c_get_context();
        kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
-       for(ctx = 0; ctx < num_contexts; ctx++) {
+       for (ctx = 0; ctx < num_contexts; ctx++) {
                sun4c_set_context(ctx);
-               for(vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
+               for (vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
                        sun4c_put_segmap(vaddr, invalid_segment);
-               for(vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
+               for (vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
                        sun4c_put_segmap(vaddr, invalid_segment);
-               for(vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
+               for (vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
                        sun4c_put_segmap(vaddr, invalid_segment);
-               for(vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
+               for (vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
                        sun4c_put_segmap(vaddr, invalid_segment);
        }
        sun4c_set_context(savectx);
@@ -442,7 +327,7 @@ __initfunc(void sun4c_probe_vac(void))
        sun4c_disable_vac();
 
        if (ARCH_SUN4) {
-               switch(idprom->id_machtype) {
+               switch (idprom->id_machtype) {
 
                case (SM_SUN4|SM_4_110):
                        sun4c_vacinfo.type = NONE;
@@ -477,12 +362,12 @@ __initfunc(void sun4c_probe_vac(void))
                default:
                        prom_printf("Cannot initialize VAC - wierd sun4 model idprom->id_machtype = %d", idprom->id_machtype);
                        prom_halt();
-               }
+               };
        } else {
                sun4c_vacinfo.type = WRITE_THROUGH;
 
-               if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-                  (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+               if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+                   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
                        /* PROM on SS1 lacks this info, to be super safe we
                         * hard code it here since this arch is cast in stone.
                         */
@@ -497,7 +382,7 @@ __initfunc(void sun4c_probe_vac(void))
                sun4c_vacinfo.do_hwflushes =
                 prom_getintdefault(prom_root_node, "vac-hwflush", 0);
 
-               if(sun4c_vacinfo.do_hwflushes == 0)
+               if (sun4c_vacinfo.do_hwflushes == 0)
                        sun4c_vacinfo.do_hwflushes =
                         prom_getintdefault(prom_root_node, "vac_hwflush", 0);
 
@@ -509,7 +394,7 @@ __initfunc(void sun4c_probe_vac(void))
 
        sun4c_vacinfo.num_lines =
                (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
-       switch(sun4c_vacinfo.linesize) {
+       switch (sun4c_vacinfo.linesize) {
        case 16:
                sun4c_vacinfo.log2lsize = 4;
                break;
@@ -566,7 +451,7 @@ static void patch_kernel_fault_handler(void)
                        prom_printf("Unhandled number of segmaps: %d\n",
                                    num_segmaps);
                        prom_halt();
-       }
+       };
        switch (num_contexts) {
                case 8:
                        /* Default, nothing to do. */
@@ -574,19 +459,22 @@ static void patch_kernel_fault_handler(void)
                case 16:
                        PATCH_INSN(num_context_patch1_16,
                                   num_context_patch1);
+#if 0
                        PATCH_INSN(num_context_patch2_16,
                                   num_context_patch2);
+#endif
                        break;
                default:
                        prom_printf("Unhandled number of contexts: %d\n",
                                    num_contexts);
                        prom_halt();
-       }
-       if(sun4c_vacinfo.do_hwflushes != 0) {
+       };
+
+       if (sun4c_vacinfo.do_hwflushes != 0) {
                PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1);
                PATCH_INSN(vac_hwflush_patch2_on, vac_hwflush_patch2);
        } else {
-               switch(sun4c_vacinfo.linesize) {
+               switch (sun4c_vacinfo.linesize) {
                case 16:
                        /* Default, nothing to do. */
                        break;
@@ -604,7 +492,7 @@ static void patch_kernel_fault_handler(void)
 __initfunc(static void sun4c_probe_mmu(void))
 {
        if (ARCH_SUN4) {
-               switch(idprom->id_machtype) {
+               switch (idprom->id_machtype) {
                case (SM_SUN4|SM_4_110):
                        prom_printf("No support for 4100 yet\n");
                        prom_halt();
@@ -631,10 +519,10 @@ __initfunc(static void sun4c_probe_mmu(void))
                default:
                        prom_printf("Invalid SUN4 model\n");
                        prom_halt();
-               }
+               };
        } else {
-               if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-               (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+               if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+                   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
                        /* Hardcode these just to be safe, PROM on SS1 does
                        * not have this info available in the root node.
                        */
@@ -679,10 +567,10 @@ static inline void sun4c_init_ss2_cache_bug(void)
 {
        extern unsigned long start;
 
-       if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
-          (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
-          (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
-          (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
+       if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
+           (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
+           (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
+           (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
                /* Whee.. */
                printk("SS2 cache bug detected, uncaching trap table page\n");
                sun4c_flush_page((unsigned int) &start);
@@ -697,9 +585,9 @@ static void sun4c_map_dma_area(unsigned long addr, int len)
        unsigned long page, end;
 
        end = PAGE_ALIGN((addr + len));
-       while(addr < end) {
+       while (addr < end) {
                page = get_free_page(GFP_KERNEL);
-               if(!page) {
+               if (!page) {
                        prom_printf("alloc_dvma: Cannot get a dvma page\n");
                        prom_halt();
                }
@@ -726,6 +614,13 @@ struct sun4c_mmu_entry {
        unsigned long vaddr;
        unsigned char pseg;
        unsigned char locked;
+
+       /* For user mappings only, and completely hidden from kernel
+        * TLB miss code.
+        */
+       unsigned char ctx;
+       struct sun4c_mmu_entry *lru_next;
+       struct sun4c_mmu_entry *lru_prev;
 };
 
 static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS];
@@ -734,12 +629,15 @@ __initfunc(static void sun4c_init_mmu_entry_pool(void))
 {
        int i;
 
-       for(i=0; i < SUN4C_MAX_SEGMAPS; i++) {
+       for (i = 0; i < SUN4C_MAX_SEGMAPS; i++) {
                mmu_entry_pool[i].pseg = i;
                mmu_entry_pool[i].next = 0;
                mmu_entry_pool[i].prev = 0;
                mmu_entry_pool[i].vaddr = 0;
                mmu_entry_pool[i].locked = 0;
+               mmu_entry_pool[i].ctx = 0;
+               mmu_entry_pool[i].lru_next = 0;
+               mmu_entry_pool[i].lru_prev = 0;
        }
        mmu_entry_pool[invalid_segment].locked = 1;
 }
@@ -750,8 +648,8 @@ static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
        unsigned long start, end;
 
        end = vaddr + SUN4C_REAL_PGDIR_SIZE;
-       for(start = vaddr; start < end; start += PAGE_SIZE)
-               if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
+       for (start = vaddr; start < end; start += PAGE_SIZE)
+               if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
                        sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
                                      ~bits_off);
 }
@@ -762,16 +660,16 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
        unsigned char pseg, ctx;
 #ifdef CONFIG_SUN4
        /* sun4/110 and 260 have no kadb. */
-       if((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
-          (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
+       if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
+           (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
 #endif
-       for(vaddr = KADB_DEBUGGER_BEGVM;
-           vaddr < LINUX_OPPROM_ENDVM;
-           vaddr += SUN4C_REAL_PGDIR_SIZE) {
+       for (vaddr = KADB_DEBUGGER_BEGVM;
+            vaddr < LINUX_OPPROM_ENDVM;
+            vaddr += SUN4C_REAL_PGDIR_SIZE) {
                pseg = sun4c_get_segmap(vaddr);
-               if(pseg != invalid_segment) {
+               if (pseg != invalid_segment) {
                        mmu_entry_pool[pseg].locked = 1;
-                       for(ctx = 0; ctx < num_contexts; ctx++)
+                       for (ctx = 0; ctx < num_contexts; ctx++)
                                prom_putsegment(ctx, vaddr, pseg);
                        fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
                }
@@ -779,10 +677,10 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
 #ifdef CONFIG_SUN4
        }
 #endif
-       for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
+       for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
                pseg = sun4c_get_segmap(vaddr);
                mmu_entry_pool[pseg].locked = 1;
-               for(ctx = 0; ctx < num_contexts; ctx++)
+               for (ctx = 0; ctx < num_contexts; ctx++)
                        prom_putsegment(ctx, vaddr, pseg);
                fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
        }
@@ -792,13 +690,13 @@ __initfunc(static void sun4c_init_lock_area(unsigned long start, unsigned long e
 {
        int i, ctx;
 
-       while(start < end) {
-               for(i=0; i < invalid_segment; i++)
-                       if(!mmu_entry_pool[i].locked)
+       while (start < end) {
+               for (i = 0; i < invalid_segment; i++)
+                       if (!mmu_entry_pool[i].locked)
                                break;
                mmu_entry_pool[i].locked = 1;
                sun4c_init_clean_segmap(i);
-               for(ctx = 0; ctx < num_contexts; ctx++)
+               for (ctx = 0; ctx < num_contexts; ctx++)
                        prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
                start += SUN4C_REAL_PGDIR_SIZE;
        }
@@ -815,13 +713,15 @@ struct sun4c_mmu_ring {
 
 static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */
 static struct sun4c_mmu_ring sun4c_ufree_ring;       /* free user entries */
+static struct sun4c_mmu_ring sun4c_ulru_ring;       /* LRU user entries */
 struct sun4c_mmu_ring sun4c_kernel_ring;      /* used kernel entries */
 struct sun4c_mmu_ring sun4c_kfree_ring;       /* free kernel entries */
 
 static inline void sun4c_init_rings(unsigned long *mempool)
 {
        int i;
-       for(i=0; i<SUN4C_MAX_CONTEXTS; i++) {
+
+       for (i = 0; i<SUN4C_MAX_CONTEXTS; i++) {
                sun4c_context_ring[i].ringhd.next =
                        sun4c_context_ring[i].ringhd.prev =
                        &sun4c_context_ring[i].ringhd;
@@ -830,6 +730,9 @@ static inline void sun4c_init_rings(unsigned long *mempool)
        sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
                &sun4c_ufree_ring.ringhd;
        sun4c_ufree_ring.num_entries = 0;
+       sun4c_ulru_ring.ringhd.lru_next = sun4c_ulru_ring.ringhd.lru_prev =
+               &sun4c_ulru_ring.ringhd;
+       sun4c_ulru_ring.num_entries = 0;
        sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
                &sun4c_kernel_ring.ringhd;
        sun4c_kernel_ring.num_entries = 0;
@@ -838,8 +741,8 @@ static inline void sun4c_init_rings(unsigned long *mempool)
        sun4c_kfree_ring.num_entries = 0;
 }
 
-static inline void add_ring(struct sun4c_mmu_ring *ring,
-                           struct sun4c_mmu_entry *entry)
+static void add_ring(struct sun4c_mmu_ring *ring,
+                    struct sun4c_mmu_entry *entry)
 {
        struct sun4c_mmu_entry *head = &ring->ringhd;
 
@@ -849,49 +752,58 @@ static inline void add_ring(struct sun4c_mmu_ring *ring,
        ring->num_entries++;
 }
 
-static inline void add_ring_ordered(struct sun4c_mmu_ring *ring,
-                                   struct sun4c_mmu_entry *entry)
+static __inline__ void add_lru(struct sun4c_mmu_entry *entry)
+{
+       struct sun4c_mmu_ring *ring = &sun4c_ulru_ring;
+       struct sun4c_mmu_entry *head = &ring->ringhd;
+
+       entry->lru_next = head;
+       (entry->lru_prev = head->lru_prev)->lru_next = entry;
+       head->lru_prev = entry;
+}
+
+static void add_ring_ordered(struct sun4c_mmu_ring *ring,
+                            struct sun4c_mmu_entry *entry)
 {
        struct sun4c_mmu_entry *head = &ring->ringhd;
        unsigned long addr = entry->vaddr;
 
-       if(head->next != &ring->ringhd) {
-               while((head->next != &ring->ringhd) && (head->next->vaddr < addr))
-                       head = head->next;
-       }
+       while ((head->next != &ring->ringhd) && (head->next->vaddr < addr))
+               head = head->next;
+
        entry->prev = head;
        (entry->next = head->next)->prev = entry;
        head->next = entry;
        ring->num_entries++;
+
+       add_lru(entry);
 }
 
-static inline void remove_ring(struct sun4c_mmu_ring *ring,
-                              struct sun4c_mmu_entry *entry)
+static __inline__ void remove_ring(struct sun4c_mmu_ring *ring,
+                                  struct sun4c_mmu_entry *entry)
 {
        struct sun4c_mmu_entry *next = entry->next;
 
        (next->prev = entry->prev)->next = next;
        ring->num_entries--;
-#ifdef DEBUG_SUN4C_MM
-       if(ring->num_entries < 0)
-               panic("sun4c: Ring num_entries < 0!");
-#endif
 }
 
-static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
+static void remove_lru(struct sun4c_mmu_entry *entry)
 {
-        remove_ring(sun4c_context_ring+ctx, entry);
-        add_ring(&sun4c_ufree_ring, entry);
+       struct sun4c_mmu_entry *next = entry->lru_next;
+
+       (next->lru_prev = entry->lru_prev)->lru_next = next;
 }
 
-static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry) 
+static void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
 {
-        remove_ring(&sun4c_ufree_ring, entry);
-        add_ring_ordered(sun4c_context_ring+ctx, entry);
+        remove_ring(sun4c_context_ring+ctx, entry);
+       remove_lru(entry);
+        add_ring(&sun4c_ufree_ring, entry);
 }
 
-static inline void free_kernel_entry(struct sun4c_mmu_entry *entry,
-                                    struct sun4c_mmu_ring *ring)
+static void free_kernel_entry(struct sun4c_mmu_entry *entry,
+                             struct sun4c_mmu_ring *ring)
 {
         remove_ring(ring, entry);
         add_ring(&sun4c_kfree_ring, entry);
@@ -901,9 +813,9 @@ __initfunc(static void sun4c_init_fill_kernel_ring(int howmany))
 {
        int i;
 
-       while(howmany) {
-               for(i=0; i < invalid_segment; i++)
-                       if(!mmu_entry_pool[i].locked)
+       while (howmany) {
+               for (i = 0; i < invalid_segment; i++)
+                       if (!mmu_entry_pool[i].locked)
                                break;
                mmu_entry_pool[i].locked = 1;
                sun4c_init_clean_segmap(i);
@@ -916,54 +828,40 @@ __initfunc(static void sun4c_init_fill_user_ring(void))
 {
        int i;
 
-       for(i=0; i < invalid_segment; i++) {
-               if(mmu_entry_pool[i].locked)
+       for (i = 0; i < invalid_segment; i++) {
+               if (mmu_entry_pool[i].locked)
                        continue;
                sun4c_init_clean_segmap(i);
                add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
        }
 }
 
-static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
+static void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
 {
        int savectx, ctx;
 
        savectx = sun4c_get_context();
-       for(ctx = 0; ctx < num_contexts; ctx++) {
+       for (ctx = 0; ctx < num_contexts; ctx++) {
                sun4c_set_context(ctx);
                sun4c_put_segmap(kentry->vaddr, invalid_segment);
        }
        sun4c_set_context(savectx);
 }
 
-static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
+static void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
 {
        int savectx, ctx;
 
        savectx = sun4c_get_context();
-       for(ctx = 0; ctx < num_contexts; ctx++) {
+       for (ctx = 0; ctx < num_contexts; ctx++) {
                sun4c_set_context(ctx);
                sun4c_put_segmap(kentry->vaddr, kentry->pseg);
        }
        sun4c_set_context(savectx);
 }
 
-static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
-{
-       sun4c_put_segmap(uentry->vaddr, invalid_segment);
-}
-
-static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry)
-{
-       unsigned long start = uentry->vaddr;
-       unsigned long end = start + SUN4C_REAL_PGDIR_SIZE;
-
-       sun4c_put_segmap(uentry->vaddr, uentry->pseg);
-       while(start < end) {
-               sun4c_put_pte(start, 0);
-               start += PAGE_SIZE;
-       }
-}
+#define sun4c_user_unmap(__entry) \
+       sun4c_put_segmap((__entry)->vaddr, invalid_segment)
 
 static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx)
 {
@@ -971,11 +869,11 @@ static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx
        unsigned long flags;
 
        save_and_cli(flags);
-       if(head->next != head) {
+       if (head->next != head) {
                struct sun4c_mmu_entry *entry = head->next;
                int savectx = sun4c_get_context();
 
-               FUW_INLINE
+               flush_user_windows();
                sun4c_set_context(ctx);
                sun4c_flush_context_hw();
                do {
@@ -985,7 +883,7 @@ static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx
                        free_user_entry(ctx, entry);
 
                        entry = next;
-               } while(entry != head);
+               } while (entry != head);
                sun4c_set_context(savectx);
        }
        restore_flags(flags);
@@ -997,11 +895,11 @@ static void sun4c_demap_context_sw(struct sun4c_mmu_ring *crp, unsigned char ctx
        unsigned long flags;
 
        save_and_cli(flags);
-       if(head->next != head) {
+       if (head->next != head) {
                struct sun4c_mmu_entry *entry = head->next;
                int savectx = sun4c_get_context();
 
-               FUW_INLINE
+               flush_user_windows();
                sun4c_set_context(ctx);
                sun4c_flush_context_sw();
                do {
@@ -1011,49 +909,31 @@ static void sun4c_demap_context_sw(struct sun4c_mmu_ring *crp, unsigned char ctx
                        free_user_entry(ctx, entry);
 
                        entry = next;
-               } while(entry != head);
+               } while (entry != head);
                sun4c_set_context(savectx);
        }
        restore_flags(flags);
 }
 
-static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx)
-{
-       /* by using .prev we get a kind of "lru" algorithm */
-       struct sun4c_mmu_entry *entry = crp->ringhd.prev;
-       unsigned long flags;
-       int savectx = sun4c_get_context();
-
-#ifdef DEBUG_SUN4C_MM
-       if(entry == &crp->ringhd)
-               panic("sun4c_demap_one: Freeing from empty ctx ring.");
-#endif
-       FUW_INLINE
-       save_and_cli(flags);
-       sun4c_set_context(ctx);
-       sun4c_flush_segment(entry->vaddr);
-       sun4c_user_unmap(entry);
-       free_user_entry(ctx, entry);
-       sun4c_set_context(savectx);
-       restore_flags(flags);
-}
-
 static int sun4c_user_taken_entries = 0;  /* This is how much we have.             */
 static int max_user_taken_entries = 0;    /* This limits us and prevents deadlock. */
 
-static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
+static struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
 {
        struct sun4c_mmu_entry *this_entry;
 
        /* If some are free, return first one. */
-       if(sun4c_kfree_ring.num_entries) {
+       if (sun4c_kfree_ring.num_entries) {
                this_entry = sun4c_kfree_ring.ringhd.next;
                return this_entry;
        }
 
        /* Else free one up. */
        this_entry = sun4c_kernel_ring.ringhd.prev;
-       sun4c_flush_segment(this_entry->vaddr);
+       if (sun4c_vacinfo.do_hwflushes)
+               sun4c_flush_segment_hw(this_entry->vaddr);
+       else
+               sun4c_flush_segment_sw(this_entry->vaddr);
        sun4c_kernel_unmap(this_entry);
        free_kernel_entry(this_entry, &sun4c_kernel_ring);
        this_entry = sun4c_kfree_ring.ringhd.next;
@@ -1061,141 +941,73 @@ static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
        return this_entry;
 }
 
-void sun4c_shrink_kernel_ring(void)
-{
-       struct sun4c_mmu_entry *entry;
-       unsigned long flags;
-
-       /* If an interrupt comes in here, we die... */
-       save_and_cli(flags);
-
-       if (sun4c_user_taken_entries) {
-               entry = sun4c_kernel_strategy();
-               remove_ring(&sun4c_kfree_ring, entry);
-               add_ring(&sun4c_ufree_ring, entry);
-               sun4c_user_taken_entries--;
-#if 0
-               printk("shrink: ufree= %d, kfree= %d, kernel= %d\n",
-                       sun4c_ufree_ring.num_entries,
-                       sun4c_kfree_ring.num_entries,
-                       sun4c_kernel_ring.num_entries);
-#endif
-#ifdef DEBUG_SUN4C_MM
-               if(sun4c_user_taken_entries < 0)
-                       panic("sun4c_shrink_kernel_ring: taken < 0.");
-#endif
-       }
-       restore_flags(flags);
-}
-
 /* Using this method to free up mmu entries eliminates a lot of
  * potential races since we have a kernel that incurs tlb
  * replacement faults.  There may be performance penalties.
+ *
+ * NOTE: Must be called with interrupts disabled.
  */
-static inline struct sun4c_mmu_entry *sun4c_user_strategy(void)
+static struct sun4c_mmu_entry *sun4c_user_strategy(void)
 {
-       struct ctx_list *next_one;
-       struct sun4c_mmu_ring *rp = 0;
+       struct sun4c_mmu_entry *entry;
        unsigned char ctx;
-#ifdef DEBUG_SUN4C_MM
-       int lim = num_contexts;
-#endif
+       int savectx;
 
        /* If some are free, return first one. */
-       if(sun4c_ufree_ring.num_entries) {
-#ifdef DEBUG_SUN4C_MM
-               if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-                       panic("sun4c_user_strategy: num_entries!=0 but ring empty.");
-#endif
-               return sun4c_ufree_ring.ringhd.next;
+       if (sun4c_ufree_ring.num_entries) {
+               entry = sun4c_ufree_ring.ringhd.next;
+               goto unlink_out;
        }
 
        if (sun4c_user_taken_entries) {
-               sun4c_shrink_kernel_ring();
-#ifdef DEBUG_SUN4C_MM
-               if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-                       panic("sun4c_user_strategy: kernel shrunk but ufree empty.");
-#endif
-               return sun4c_ufree_ring.ringhd.next;
+               entry = sun4c_kernel_strategy();
+               sun4c_user_taken_entries--;
+               goto kunlink_out;
        }
 
-       /* Grab one from the LRU context. */
-       next_one = ctx_used.next;
-       while ((sun4c_context_ring[next_one->ctx_number].num_entries == 0)
-#ifdef DEBUG_SUN4C_MM
-              && (--lim >= 0)
-#endif
-              )
-               next_one = next_one->next;
+       /* Grab from the beginning of the LRU list. */
+       entry = sun4c_ulru_ring.ringhd.lru_next;
+       ctx = entry->ctx;
 
-#ifdef DEBUG_SUN4C_MM
-       if(lim < 0)
-               panic("No user segmaps!");
-#endif
+       savectx = sun4c_get_context();
+       flush_user_windows();
+       sun4c_set_context(ctx);
+       if (sun4c_vacinfo.do_hwflushes)
+               sun4c_flush_segment_hw(entry->vaddr);
+       else
+               sun4c_flush_segment_sw(entry->vaddr);
+       sun4c_user_unmap(entry);
+       remove_ring(sun4c_context_ring + ctx, entry);
+       remove_lru(entry);
+       sun4c_set_context(savectx);
 
-       ctx = next_one->ctx_number;
-       rp = &sun4c_context_ring[ctx];
+       return entry;
 
-       sun4c_demap_one(rp, ctx);
-#ifdef DEBUG_SUN4C_MM
-       if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
-               panic("sun4c_user_strategy: demapped one but ufree empty.");
-#endif
-       return sun4c_ufree_ring.ringhd.next;
+unlink_out:
+       remove_ring(&sun4c_ufree_ring, entry);
+       return entry;
+kunlink_out:
+       remove_ring(&sun4c_kfree_ring, entry);
+       return entry;
 }
 
+/* NOTE: Must be called with interrupts disabled. */
 void sun4c_grow_kernel_ring(void)
 {
        struct sun4c_mmu_entry *entry;
 
-#if 0
-       printk("grow: ");
-#endif
-
        /* Prevent deadlock condition. */
-       if(sun4c_user_taken_entries >= max_user_taken_entries) {
-#if 0
-               printk("deadlock avoidance, taken= %d max= %d\n",
-                      sun4c_user_taken_entries, max_user_taken_entries);
-#endif
+       if (sun4c_user_taken_entries >= max_user_taken_entries)
                return;
-       }
 
        if (sun4c_ufree_ring.num_entries) {
                entry = sun4c_ufree_ring.ringhd.next;
-#ifdef DEBUG_SUN4C_MM
-               if(entry == &sun4c_ufree_ring.ringhd)
-                       panic("\nsun4c_grow_kernel_ring: num_entries!=0, ring empty.");
-#endif
                remove_ring(&sun4c_ufree_ring, entry);
                add_ring(&sun4c_kfree_ring, entry);
-#ifdef DEBUG_SUN4C_MM
-               if(sun4c_user_taken_entries < 0)
-                       panic("\nsun4c_grow_kernel_ring: taken < 0.");
-#endif
                sun4c_user_taken_entries++;
-#if 0
-               printk("ufree= %d, kfree= %d, kernel= %d\n",
-                       sun4c_ufree_ring.num_entries,
-                       sun4c_kfree_ring.num_entries,
-                       sun4c_kernel_ring.num_entries);
-#endif
        }
 }
 
-static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
-{
-       struct sun4c_mmu_entry *entry;
-       unsigned long flags;
-
-       save_and_cli(flags);
-       entry = sun4c_user_strategy();
-       entry->vaddr = (address & SUN4C_REAL_PGDIR_MASK);
-       assign_user_entry(ctx, entry);
-       sun4c_user_map(entry);
-       restore_flags(flags);
-}
-
 /* This is now a fast in-window trap handler to avoid any and all races. */
 static void sun4c_quick_kernel_fault(unsigned long address)
 {
@@ -1234,7 +1046,7 @@ static int sun4c_lowbucket_avail;
 #define BUCKET_PTE_PAGE(pte)   \
         (PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT))
 
-static inline void get_locked_segment(unsigned long addr)
+static void get_locked_segment(unsigned long addr)
 {
        struct sun4c_mmu_entry *stolen;
        unsigned long flags;
@@ -1242,19 +1054,14 @@ static inline void get_locked_segment(unsigned long addr)
        save_and_cli(flags);
        addr &= SUN4C_REAL_PGDIR_MASK;
        stolen = sun4c_user_strategy();
-       remove_ring(&sun4c_ufree_ring, stolen);
        max_user_taken_entries--;
-#ifdef DEBUG_SUN4C_MM
-       if(max_user_taken_entries < 0)
-               panic("get_locked_segment: max_user_taken < 0.");
-#endif
        stolen->vaddr = addr;
-       FUW_INLINE
+       flush_user_windows();
        sun4c_kernel_map(stolen);
        restore_flags(flags);
 }
 
-static inline void free_locked_segment(unsigned long addr)
+static void free_locked_segment(unsigned long addr)
 {
        struct sun4c_mmu_entry *entry;
        unsigned long flags;
@@ -1265,14 +1072,13 @@ static inline void free_locked_segment(unsigned long addr)
        pseg = sun4c_get_segmap(addr);
        entry = &mmu_entry_pool[pseg];
 
-       FUW_INLINE
-       sun4c_flush_segment(addr);
+       flush_user_windows();
+       if (sun4c_vacinfo.do_hwflushes)
+               sun4c_flush_segment_hw(addr);
+       else
+               sun4c_flush_segment_sw(addr);
        sun4c_kernel_unmap(entry);
        add_ring(&sun4c_ufree_ring, entry);
-#ifdef DEBUG_SUN4C_MM
-       if(max_user_taken_entries < 0)
-               panic("free_locked_segment: max_user_taken < 0.");
-#endif
        max_user_taken_entries++;
        restore_flags(flags);
 }
@@ -1284,8 +1090,8 @@ static inline void garbage_collect(int entry)
        /* 32 buckets per segment... */
        entry &= ~31;
        start = entry;
-       for(end = (start + 32); start < end; start++)
-               if(sun4c_bucket[start] != BUCKET_EMPTY)
+       for (end = (start + 32); start < end; start++)
+               if (sun4c_bucket[start] != BUCKET_EMPTY)
                        return;
 
        /* Entire segment empty, release it. */
@@ -1304,23 +1110,39 @@ static struct task_struct *sun4c_alloc_task_struct(void)
        int entry;
 
        pages = __get_free_pages(GFP_KERNEL, TASK_STRUCT_ORDER);
-       if(!pages)
+       if (!pages)
                return (struct task_struct *) 0;
 
-       for(entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++)
-               if(sun4c_bucket[entry] == BUCKET_EMPTY)
+       for (entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++)
+               if (sun4c_bucket[entry] == BUCKET_EMPTY)
                        break;
-       if(entry == NR_TASK_BUCKETS) {
+       if (entry == NR_TASK_BUCKETS) {
                free_pages(pages, TASK_STRUCT_ORDER);
                return (struct task_struct *) 0;
        }
-       if(entry >= sun4c_lowbucket_avail)
+       if (entry >= sun4c_lowbucket_avail)
                sun4c_lowbucket_avail = entry + 1;
 
        addr = BUCKET_ADDR(entry);
        sun4c_bucket[entry] = (union task_union *) addr;
-       if(sun4c_get_segmap(addr) == invalid_segment)
+       if (sun4c_get_segmap(addr) == invalid_segment)
                get_locked_segment(addr);
+
+       /* We are changing the virtual color of the page(s)
+        * so we must flush the cache to guarentee consistancy.
+        */
+       if (sun4c_vacinfo.do_hwflushes) {
+               sun4c_flush_page_hw(pages);
+#ifndef CONFIG_SUN4    
+               sun4c_flush_page_hw(pages + PAGE_SIZE);
+#endif
+       } else {
+               sun4c_flush_page_sw(pages);
+#ifndef CONFIG_SUN4    
+               sun4c_flush_page_sw(pages + PAGE_SIZE);
+#endif
+       }
+
        sun4c_put_pte(addr, BUCKET_PTE(pages));
 #ifndef CONFIG_SUN4    
        sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
@@ -1344,7 +1166,7 @@ static void sun4c_free_task_struct_hw(struct task_struct *tsk)
        sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
 #endif
        sun4c_bucket[entry] = BUCKET_EMPTY;
-       if(entry < sun4c_lowbucket_avail)
+       if (entry < sun4c_lowbucket_avail)
                sun4c_lowbucket_avail = entry;
 
        free_pages(pages, TASK_STRUCT_ORDER);
@@ -1367,7 +1189,7 @@ static void sun4c_free_task_struct_sw(struct task_struct *tsk)
        sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
 #endif
        sun4c_bucket[entry] = BUCKET_EMPTY;
-       if(entry < sun4c_lowbucket_avail)
+       if (entry < sun4c_lowbucket_avail)
                sun4c_lowbucket_avail = entry;
 
        free_pages(pages, TASK_STRUCT_ORDER);
@@ -1378,10 +1200,10 @@ __initfunc(static void sun4c_init_buckets(void))
 {
        int entry;
 
-       if(sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
+       if (sizeof(union task_union) != (PAGE_SIZE << TASK_STRUCT_ORDER)) {
                prom_printf("task union not %d page(s)!\n", 1 << TASK_STRUCT_ORDER);
        }
-       for(entry = 0; entry < NR_TASK_BUCKETS; entry++)
+       for (entry = 0; entry < NR_TASK_BUCKETS; entry++)
                sun4c_bucket[entry] = BUCKET_EMPTY;
        sun4c_lowbucket_avail = 0;
 }
@@ -1501,7 +1323,7 @@ static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sb
        unsigned long page;
 
        page = ((unsigned long)bufptr) & PAGE_MASK;
-       if(MAP_NR(page) > max_mapnr) {
+       if (MAP_NR(page) > max_mapnr) {
                sun4c_flush_page(page);
                return (__u32)bufptr; /* already locked */
        }
@@ -1510,7 +1332,7 @@ static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sb
 
 static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
-       while(sz >= 0) {
+       while (sz >= 0) {
                sg[sz].dvma_addr = (__u32)sun4c_lockarea(sg[sz].addr, sg[sz].len);
                sz--;
        }
@@ -1518,14 +1340,14 @@ static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus
 
 static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct linux_sbus *sbus)
 {
-       if(bufptr < sun4c_iobuffer_start)
+       if (bufptr < sun4c_iobuffer_start)
                return; /* On kernel stack or similar, see above */
        sun4c_unlockarea((char *)bufptr, len);
 }
 
 static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
-       while(sz >= 0) {
+       while (sz >= 0) {
                sun4c_unlockarea((char *)sg[sz].dvma_addr, sg[sz].len);
                sz--;
        }
@@ -1546,7 +1368,7 @@ __initfunc(static unsigned long sun4c_init_lock_areas(unsigned long start_mem))
        sun4c_taskstack_start = SUN4C_LOCK_VADDR;
        sun4c_taskstack_end = (sun4c_taskstack_start +
                               (TASK_ENTRY_SIZE * NR_TASK_BUCKETS));
-       if(sun4c_taskstack_end >= SUN4C_LOCK_END) {
+       if (sun4c_taskstack_end >= SUN4C_LOCK_END) {
                prom_printf("Too many tasks, decrease NR_TASK_BUCKETS please.\n");
                prom_halt();
        }
@@ -1576,12 +1398,12 @@ static void sun4c_flush_cache_all(void)
 {
        unsigned long begin, end;
 
-       FUW_INLINE
+       flush_user_windows();
        begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE);
        end = (begin + SUN4C_VAC_SIZE);
 
-       if(sun4c_vacinfo.linesize == 32) {
-               while(begin < end) {
+       if (sun4c_vacinfo.linesize == 32) {
+               while (begin < end) {
                        __asm__ __volatile__("
                        ld      [%0 + 0x00], %%g0
                        ld      [%0 + 0x20], %%g0
@@ -1603,7 +1425,7 @@ static void sun4c_flush_cache_all(void)
                        begin += 512;
                }
        } else {
-               while(begin < end) {
+               while (begin < end) {
                        __asm__ __volatile__("
                        ld      [%0 + 0x00], %%g0
                        ld      [%0 + 0x10], %%g0
@@ -1631,29 +1453,31 @@ static void sun4c_flush_cache_mm_hw(struct mm_struct *mm)
 {
        int new_ctx = mm->context;
 
-       if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
-               struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-               unsigned long flags;
+       if (new_ctx != NO_CONTEXT) {
+               flush_user_windows();
+               if (sun4c_context_ring[new_ctx].num_entries) {
+                       struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+                       unsigned long flags;
 
-               save_and_cli(flags);
-               if(head->next != head) {
-                       struct sun4c_mmu_entry *entry = head->next;
-                       int savectx = sun4c_get_context();
+                       save_and_cli(flags);
+                       if (head->next != head) {
+                               struct sun4c_mmu_entry *entry = head->next;
+                               int savectx = sun4c_get_context();
 
-                       FUW_INLINE
-                       sun4c_set_context(new_ctx);
-                       sun4c_flush_context_hw();
-                       do {
-                               struct sun4c_mmu_entry *next = entry->next;
+                               sun4c_set_context(new_ctx);
+                               sun4c_flush_context_hw();
+                               do {
+                                       struct sun4c_mmu_entry *next = entry->next;
 
-                               sun4c_user_unmap(entry);
-                               free_user_entry(new_ctx, entry);
+                                       sun4c_user_unmap(entry);
+                                       free_user_entry(new_ctx, entry);
 
-                               entry = next;
-                       } while(entry != head);
-                       sun4c_set_context(savectx);
+                                       entry = next;
+                               } while (entry != head);
+                               sun4c_set_context(savectx);
+                       }
+                       restore_flags(flags);
                }
-               restore_flags(flags);
        }
 }
 
@@ -1661,29 +1485,28 @@ static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start
 {
        int new_ctx = mm->context;
        
-#if KGPROF_PROFILING
-       kgprof_profile();
-#endif
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
                struct sun4c_mmu_entry *entry;
                unsigned long flags;
 
-               FUW_INLINE
+               flush_user_windows();
+
                save_and_cli(flags);
 
                /* All user segmap chains are ordered on entry->vaddr. */
-               for(entry = head->next;
-                   (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-                   entry = entry->next)
+               for (entry = head->next;
+                    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+                    entry = entry->next)
                        ;
 
                /* Tracing various job mixtures showed that this conditional
                 * only passes ~35% of the time for most worse case situations,
                 * therefore we avoid all of this gross overhead ~65% of the time.
                 */
-               if((entry != head) && (entry->vaddr < end)) {
+               if ((entry != head) && (entry->vaddr < end)) {
                        int octx = sun4c_get_context();
+
                        sun4c_set_context(new_ctx);
 
                        /* At this point, always, (start >= entry->vaddr) and
@@ -1698,11 +1521,11 @@ static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start
 
                                /* "realstart" is always >= entry->vaddr */
                                realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
-                               if(end < realend)
+                               if (end < realend)
                                        realend = end;
-                               if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+                               if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
                                        unsigned long page = entry->vaddr;
-                                       while(page < realend) {
+                                       while (page < realend) {
                                                sun4c_flush_page_hw(page);
                                                page += PAGE_SIZE;
                                        }
@@ -1712,14 +1535,13 @@ static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start
                                        free_user_entry(new_ctx, entry);
                                }
                                entry = next;
-                       } while((entry != head) && (entry->vaddr < end));
+                       } while ((entry != head) && (entry->vaddr < end));
                        sun4c_set_context(octx);
                }
                restore_flags(flags);
        }
 }
 
-/* XXX no save_and_cli/restore_flags needed, but put here if darkside still crashes */
 static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page)
 {
        struct mm_struct *mm = vma->vm_mm;
@@ -1728,76 +1550,84 @@ static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long
        /* Sun4c has no separate I/D caches so cannot optimize for non
         * text page flushes.
         */
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                int octx = sun4c_get_context();
+               unsigned long flags;
 
-               FUW_INLINE
+               flush_user_windows();
+               save_and_cli(flags);
                sun4c_set_context(new_ctx);
                sun4c_flush_page_hw(page);
                sun4c_set_context(octx);
+               restore_flags(flags);
        }
 }
 
 static void sun4c_flush_page_to_ram_hw(unsigned long page)
 {
+       unsigned long flags;
+
+       save_and_cli(flags);
        sun4c_flush_page_hw(page);
+       restore_flags(flags);
 }
 
 static void sun4c_flush_cache_mm_sw(struct mm_struct *mm)
 {
        int new_ctx = mm->context;
 
-       if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
-               struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-               unsigned long flags;
+       if (new_ctx != NO_CONTEXT) {
+               flush_user_windows();
 
-               save_and_cli(flags);
-               if(head->next != head) {
-                       struct sun4c_mmu_entry *entry = head->next;
-                       int savectx = sun4c_get_context();
+               if (sun4c_context_ring[new_ctx].num_entries) {
+                       struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+                       unsigned long flags;
 
-                       FUW_INLINE
-                       sun4c_set_context(new_ctx);
-                       sun4c_flush_context_sw();
-                       do {
-                               struct sun4c_mmu_entry *next = entry->next;
+                       save_and_cli(flags);
+                       if (head->next != head) {
+                               struct sun4c_mmu_entry *entry = head->next;
+                               int savectx = sun4c_get_context();
 
-                               sun4c_user_unmap(entry);
-                               free_user_entry(new_ctx, entry);
+                               sun4c_set_context(new_ctx);
+                               sun4c_flush_context_sw();
+                               do {
+                                       struct sun4c_mmu_entry *next = entry->next;
 
-                               entry = next;
-                       } while(entry != head);
-                       sun4c_set_context(savectx);
+                                       sun4c_user_unmap(entry);
+                                       free_user_entry(new_ctx, entry);
+
+                                       entry = next;
+                               } while (entry != head);
+                               sun4c_set_context(savectx);
+                       }
+                       restore_flags(flags);
                }
-               restore_flags(flags);
        }
 }
 
 static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
        int new_ctx = mm->context;
-       
-#if KGPROF_PROFILING
-       kgprof_profile();
-#endif
-       if(new_ctx != NO_CONTEXT) {
+
+       if (new_ctx != NO_CONTEXT) {
                struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
                struct sun4c_mmu_entry *entry;
                unsigned long flags;
 
-               FUW_INLINE
+               flush_user_windows();
+
                save_and_cli(flags);
                /* All user segmap chains are ordered on entry->vaddr. */
-               for(entry = head->next;
-                   (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-                   entry = entry->next)
+               for (entry = head->next;
+                    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+                    entry = entry->next)
                        ;
 
                /* Tracing various job mixtures showed that this conditional
                 * only passes ~35% of the time for most worse case situations,
                 * therefore we avoid all of this gross overhead ~65% of the time.
                 */
-               if((entry != head) && (entry->vaddr < end)) {
+               if ((entry != head) && (entry->vaddr < end)) {
                        int octx = sun4c_get_context();
                        sun4c_set_context(new_ctx);
 
@@ -1813,11 +1643,11 @@ static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start
 
                                /* "realstart" is always >= entry->vaddr */
                                realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
-                               if(end < realend)
+                               if (end < realend)
                                        realend = end;
-                               if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+                               if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
                                        unsigned long page = entry->vaddr;
-                                       while(page < realend) {
+                                       while (page < realend) {
                                                sun4c_flush_page_sw(page);
                                                page += PAGE_SIZE;
                                        }
@@ -1827,7 +1657,7 @@ static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start
                                        free_user_entry(new_ctx, entry);
                                }
                                entry = next;
-                       } while((entry != head) && (entry->vaddr < end));
+                       } while ((entry != head) && (entry->vaddr < end));
                        sun4c_set_context(octx);
                }
                restore_flags(flags);
@@ -1842,19 +1672,26 @@ static void sun4c_flush_cache_page_sw(struct vm_area_struct *vma, unsigned long
        /* Sun4c has no separate I/D caches so cannot optimize for non
         * text page flushes.
         */
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                int octx = sun4c_get_context();
+               unsigned long flags;
 
-               FUW_INLINE
+               flush_user_windows();
+               save_and_cli(flags);
                sun4c_set_context(new_ctx);
                sun4c_flush_page_sw(page);
                sun4c_set_context(octx);
+               restore_flags(flags);
        }
 }
 
 static void sun4c_flush_page_to_ram_sw(unsigned long page)
 {
+       unsigned long flags;
+
+       save_and_cli(flags);
        sun4c_flush_page_sw(page);
+       restore_flags(flags);
 }
 
 /* Sun4c cache is unified, both instructions and data live there, so
@@ -1881,8 +1718,11 @@ static void sun4c_flush_tlb_all(void)
        flush_user_windows();
        while (sun4c_kernel_ring.num_entries) {
                next_entry = this_entry->next;
-               sun4c_flush_segment(this_entry->vaddr);
-               for(ctx = 0; ctx < num_contexts; ctx++) {
+               if (sun4c_vacinfo.do_hwflushes)
+                       sun4c_flush_segment_hw(this_entry->vaddr);
+               else
+                       sun4c_flush_segment_sw(this_entry->vaddr);
+               for (ctx = 0; ctx < num_contexts; ctx++) {
                        sun4c_set_context(ctx);
                        sun4c_put_segmap(this_entry->vaddr, invalid_segment);
                }
@@ -1897,16 +1737,15 @@ static void sun4c_flush_tlb_mm_hw(struct mm_struct *mm)
 {
        int new_ctx = mm->context;
 
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
                unsigned long flags;
 
                save_and_cli(flags);
-               if(head->next != head) {
+               if (head->next != head) {
                        struct sun4c_mmu_entry *entry = head->next;
                        int savectx = sun4c_get_context();
 
-                       FUW_INLINE
                        sun4c_set_context(new_ctx);
                        sun4c_flush_context_hw();
                        do {
@@ -1916,7 +1755,7 @@ static void sun4c_flush_tlb_mm_hw(struct mm_struct *mm)
                                free_user_entry(new_ctx, entry);
 
                                entry = next;
-                       } while(entry != head);
+                       } while (entry != head);
                        sun4c_set_context(savectx);
                }
                restore_flags(flags);
@@ -1927,26 +1766,21 @@ static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start,
 {
        int new_ctx = mm->context;
 
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
                struct sun4c_mmu_entry *entry;
                unsigned long flags;
-#if KGPROF_PROFILING
-               kgprof_profile();
-#endif
 
                save_and_cli(flags);
                /* See commentary in sun4c_flush_cache_range_*(). */
-               for(entry = head->next;
-                   (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-                   entry = entry->next)
+               for (entry = head->next;
+                    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+                    entry = entry->next)
                        ;
 
-               if((entry != head) && (entry->vaddr < end)) {
+               if ((entry != head) && (entry->vaddr < end)) {
                        int octx = sun4c_get_context();
 
-                       /* This window flush is paranoid I think... -DaveM */
-                       FUW_INLINE
                        sun4c_set_context(new_ctx);
                        do {
                                struct sun4c_mmu_entry *next = entry->next;
@@ -1956,7 +1790,7 @@ static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start,
                                free_user_entry(new_ctx, entry);
 
                                entry = next;
-                       } while((entry != head) && (entry->vaddr < end));
+                       } while ((entry != head) && (entry->vaddr < end));
                        sun4c_set_context(octx);
                }
                restore_flags(flags);
@@ -1968,15 +1802,17 @@ static void sun4c_flush_tlb_page_hw(struct vm_area_struct *vma, unsigned long pa
        struct mm_struct *mm = vma->vm_mm;
        int new_ctx = mm->context;
 
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                int savectx = sun4c_get_context();
+               unsigned long flags;
 
-               FUW_INLINE
+               save_and_cli(flags);
                sun4c_set_context(new_ctx);
                page &= PAGE_MASK;
                sun4c_flush_page_hw(page);
                sun4c_put_pte(page, 0);
                sun4c_set_context(savectx);
+               restore_flags(flags);
        }
 }
 
@@ -1984,16 +1820,15 @@ static void sun4c_flush_tlb_mm_sw(struct mm_struct *mm)
 {
        int new_ctx = mm->context;
 
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
                unsigned long flags;
 
                save_and_cli(flags);
-               if(head->next != head) {
+               if (head->next != head) {
                        struct sun4c_mmu_entry *entry = head->next;
                        int savectx = sun4c_get_context();
 
-                       FUW_INLINE
                        sun4c_set_context(new_ctx);
                        sun4c_flush_context_sw();
                        do {
@@ -2003,7 +1838,7 @@ static void sun4c_flush_tlb_mm_sw(struct mm_struct *mm)
                                free_user_entry(new_ctx, entry);
 
                                entry = next;
-                       } while(entry != head);
+                       } while (entry != head);
                        sun4c_set_context(savectx);
                }
                restore_flags(flags);
@@ -2014,27 +1849,21 @@ static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start,
 {
        int new_ctx = mm->context;
 
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
                struct sun4c_mmu_entry *entry;
                unsigned long flags;
 
-#if KGPROF_PROFILING
-               kgprof_profile();
-#endif
-
                save_and_cli(flags);
                /* See commentary in sun4c_flush_cache_range_*(). */
-               for(entry = head->next;
-                   (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-                   entry = entry->next)
+               for (entry = head->next;
+                    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+                    entry = entry->next)
                        ;
 
-               if((entry != head) && (entry->vaddr < end)) {
+               if ((entry != head) && (entry->vaddr < end)) {
                        int octx = sun4c_get_context();
 
-                       /* This window flush is paranoid I think... -DaveM */
-                       FUW_INLINE
                        sun4c_set_context(new_ctx);
                        do {
                                struct sun4c_mmu_entry *next = entry->next;
@@ -2044,7 +1873,7 @@ static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start,
                                free_user_entry(new_ctx, entry);
 
                                entry = next;
-                       } while((entry != head) && (entry->vaddr < end));
+                       } while ((entry != head) && (entry->vaddr < end));
                        sun4c_set_context(octx);
                }
                restore_flags(flags);
@@ -2056,15 +1885,17 @@ static void sun4c_flush_tlb_page_sw(struct vm_area_struct *vma, unsigned long pa
        struct mm_struct *mm = vma->vm_mm;
        int new_ctx = mm->context;
 
-       if(new_ctx != NO_CONTEXT) {
+       if (new_ctx != NO_CONTEXT) {
                int savectx = sun4c_get_context();
+               unsigned long flags;
 
-               FUW_INLINE
+               save_and_cli(flags);
                sun4c_set_context(new_ctx);
                page &= PAGE_MASK;
                sun4c_flush_page_sw(page);
                sun4c_put_pte(page, 0);
                sun4c_set_context(savectx);
+               restore_flags(flags);
        }
 }
 
@@ -2077,7 +1908,6 @@ static void sun4c_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
 {
 }
 
-
 void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
                     int bus_type, int rdonly)
 {
@@ -2085,7 +1915,7 @@ void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
 
        page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK);
        page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT));
-       if(rdonly)
+       if (rdonly)
                page_entry &= ~_SUN4C_WRITEABLE;
        sun4c_put_pte(virt_addr, page_entry);
 }
@@ -2100,7 +1930,7 @@ static void sun4c_alloc_context_hw(struct mm_struct *mm)
        struct ctx_list *ctxp;
 
        ctxp = ctx_free.next;
-       if(ctxp != &ctx_free) {
+       if (ctxp != &ctx_free) {
                remove_from_ctx_list(ctxp);
                add_to_used_ctxlist(ctxp);
                mm->context = ctxp->ctx_number;
@@ -2108,26 +1938,22 @@ static void sun4c_alloc_context_hw(struct mm_struct *mm)
                return;
        }
        ctxp = ctx_used.next;
-       if(ctxp->ctx_mm == current->mm)
+       if (ctxp->ctx_mm == current->mm)
                ctxp = ctxp->next;
-#ifdef DEBUG_SUN4C_MM
-       if(ctxp == &ctx_used)
-               panic("out of mmu contexts");
-#endif
        remove_from_ctx_list(ctxp);
        add_to_used_ctxlist(ctxp);
        ctxp->ctx_mm->context = NO_CONTEXT;
        ctxp->ctx_mm = mm;
        mm->context = ctxp->ctx_number;
        sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number],
-                           ctxp->ctx_number);
+                              ctxp->ctx_number);
 }
 
 static void sun4c_switch_to_context_hw(struct task_struct *tsk)
 {
        struct ctx_list *ctx;
 
-       if(tsk->mm->context == NO_CONTEXT) {
+       if (tsk->mm->context == NO_CONTEXT) {
                sun4c_alloc_context_hw(tsk->mm);
        } else {
                /* Update the LRU ring of contexts. */
@@ -2141,7 +1967,7 @@ static void sun4c_switch_to_context_hw(struct task_struct *tsk)
 static void sun4c_init_new_context_hw(struct mm_struct *mm)
 {
        sun4c_alloc_context_hw(mm);
-       if(mm == current->mm)
+       if (mm == current->mm)
                sun4c_set_context(mm->context);
 }
 
@@ -2149,7 +1975,7 @@ static void sun4c_destroy_context_hw(struct mm_struct *mm)
 {
        struct ctx_list *ctx_old;
 
-       if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+       if (mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
                sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
                ctx_old = ctx_list_pool + mm->context;
                remove_from_ctx_list(ctx_old);
@@ -2163,7 +1989,7 @@ static void sun4c_alloc_context_sw(struct mm_struct *mm)
        struct ctx_list *ctxp;
 
        ctxp = ctx_free.next;
-       if(ctxp != &ctx_free) {
+       if (ctxp != &ctx_free) {
                remove_from_ctx_list(ctxp);
                add_to_used_ctxlist(ctxp);
                mm->context = ctxp->ctx_number;
@@ -2171,26 +1997,22 @@ static void sun4c_alloc_context_sw(struct mm_struct *mm)
                return;
        }
        ctxp = ctx_used.next;
-       if(ctxp->ctx_mm == current->mm)
+       if (ctxp->ctx_mm == current->mm)
                ctxp = ctxp->next;
-#ifdef DEBUG_SUN4C_MM
-       if(ctxp == &ctx_used)
-               panic("out of mmu contexts");
-#endif
        remove_from_ctx_list(ctxp);
        add_to_used_ctxlist(ctxp);
        ctxp->ctx_mm->context = NO_CONTEXT;
        ctxp->ctx_mm = mm;
        mm->context = ctxp->ctx_number;
        sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number],
-                           ctxp->ctx_number);
+                              ctxp->ctx_number);
 }
 
 static void sun4c_switch_to_context_sw(struct task_struct *tsk)
 {
        struct ctx_list *ctx;
 
-       if(tsk->mm->context == NO_CONTEXT) {
+       if (tsk->mm->context == NO_CONTEXT) {
                sun4c_alloc_context_sw(tsk->mm);
        } else {
                /* Update the LRU ring of contexts. */
@@ -2204,7 +2026,7 @@ static void sun4c_switch_to_context_sw(struct task_struct *tsk)
 static void sun4c_init_new_context_sw(struct mm_struct *mm)
 {
        sun4c_alloc_context_sw(mm);
-       if(mm == current->mm)
+       if (mm == current->mm)
                sun4c_set_context(mm->context);
 }
 
@@ -2212,7 +2034,7 @@ static void sun4c_destroy_context_sw(struct mm_struct *mm)
 {
        struct ctx_list *ctx_old;
 
-       if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+       if (mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
                sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
                ctx_old = ctx_list_pool + mm->context;
                remove_from_ctx_list(ctx_old);
@@ -2227,7 +2049,7 @@ static int sun4c_mmu_info(char *buf)
        int len;
 
        used_user_entries = 0;
-       for(i=0; i < num_contexts; i++)
+       for (i = 0; i < num_contexts; i++)
                used_user_entries += sun4c_context_ring[i].num_entries;
 
        len = sprintf(buf, 
@@ -2241,10 +2063,7 @@ static int sun4c_mmu_info(char *buf)
                "usedpsegs\t: %d\n"
                "ufreepsegs\t: %d\n"
                "user_taken\t: %d\n"
-               "max_taken\t: %d\n"
-               "context\t\t: %d flushes\n"
-               "segment\t\t: %d flushes\n"
-               "page\t\t: %d flushes\n",
+               "max_taken\t: %d\n",
                sun4c_vacinfo.num_bytes,
                (sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
                sun4c_vacinfo.linesize,
@@ -2255,22 +2074,7 @@ static int sun4c_mmu_info(char *buf)
                used_user_entries,
                sun4c_ufree_ring.num_entries,
                sun4c_user_taken_entries,
-               max_user_taken_entries,
-               ctxflushes, segflushes, pageflushes);
-
-#if KGPROF_PROFILING
-       {
-               int i,j;
-               len += sprintf(buf + len,"kgprof profiling:\n");
-               for (i=0;i<KGPROF_SIZE && kgprof_counters[i].addr[0];i++) {
-                       len += sprintf(buf + len,"%5d  ",kgprof_counters[i].count);
-                       for (j=0;j<KGPROF_DEPTH;j++) {
-                               len += sprintf(buf + len,"%08x ",kgprof_counters[i].addr[j]);
-                       }
-                       len += sprintf(buf + len,"\n");
-               }
-       }
-#endif
+               max_user_taken_entries);
 
        return len;
 }
@@ -2279,13 +2083,6 @@ static int sun4c_mmu_info(char *buf)
  * data structures.
  */
 
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
-#endif
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
-#endif
-
 /* First the functions which the mid-level code uses to directly
  * manipulate the software page tables.  Some defines since we are
  * emulating the i386 page directory layout.
@@ -2297,17 +2094,6 @@ static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_AL
 #define PGD_DIRTY    0x040
 #define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
 
-#if 0 /* Not used due to BTFIXUPs */
-static unsigned long sun4c_vmalloc_start(void)
-{
-       return SUN4C_VMALLOC_START;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_none(pte_t pte)           { return !pte_val(pte); }
-#endif
-
 static int sun4c_pte_present(pte_t pte)
 {
        return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);
@@ -2336,48 +2122,6 @@ static void sun4c_pgd_clear(pgd_t * pgdp)        { }
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_write(pte_t pte)
-{
-       return pte_val(pte) & _SUN4C_PAGE_WRITE;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_dirty(pte_t pte)
-{
-       return pte_val(pte) & _SUN4C_PAGE_MODIFIED;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static int sun4c_pte_young(pte_t pte)
-{
-       return pte_val(pte) & _SUN4C_PAGE_ACCESSED;
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_wrprotect(pte_t pte)
-{
-       return __pte(pte_val(pte) & ~(_SUN4C_PAGE_WRITE | _SUN4C_PAGE_SILENT_WRITE));
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_mkclean(pte_t pte)
-{
-       return __pte(pte_val(pte) & ~(_SUN4C_PAGE_MODIFIED | _SUN4C_PAGE_SILENT_WRITE));
-}
-#endif
-
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_mkold(pte_t pte)
-{
-       return __pte(pte_val(pte) & ~(_SUN4C_PAGE_ACCESSED | _SUN4C_PAGE_SILENT_READ));
-}
-#endif
-
 static pte_t sun4c_pte_mkwrite(pte_t pte)
 {
        pte = __pte(pte_val(pte) | _SUN4C_PAGE_WRITE);
@@ -2421,14 +2165,6 @@ static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
        return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
 }
 
-#if 0 /* Not used due to BTFIXUPs */
-static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
-{
-       return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) |
-                    pgprot_val(newprot));
-}
-#endif
-
 static unsigned long sun4c_pte_page(pte_t pte)
 {
        return (PAGE_OFFSET + ((pte_val(pte) & SUN4C_PFN_MASK) << (PAGE_SHIFT)));
@@ -2489,7 +2225,7 @@ static void sun4c_pte_free_kernel(pte_t *pte)
 
 static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
-       if(address >= SUN4C_LOCK_VADDR)
+       if (address >= SUN4C_LOCK_VADDR)
                return NULL;
        address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
        if (sun4c_pmd_none(*pmd))
@@ -2529,7 +2265,7 @@ extern __inline__ pgd_t *sun4c_get_pgd_fast(void)
 {
        unsigned long *ret;
 
-       if((ret = pgd_quicklist) != NULL) {
+       if ((ret = pgd_quicklist) != NULL) {
                pgd_quicklist = (unsigned long *)(*ret);
                ret[0] = ret[1];
                pgtable_cache_size--;
@@ -2548,15 +2284,15 @@ extern __inline__ pgd_t *sun4c_get_pgd_fast(void)
 static int sun4c_check_pgt_cache(int low, int high)
 {
        int freed = 0;
-       if(pgtable_cache_size > high) {
+       if (pgtable_cache_size > high) {
                do {
-                       if(pgd_quicklist)
+                       if (pgd_quicklist)
                                free_pgd_slow(get_pgd_fast()), freed++;
-                       if(pmd_quicklist)
+                       if (pmd_quicklist)
                                free_pmd_slow(get_pmd_fast()), freed++;
-                       if(pte_quicklist)
+                       if (pte_quicklist)
                                free_pte_slow(get_pte_fast()), freed++;
-               } while(pgtable_cache_size > low);
+               } while (pgtable_cache_size > low);
        }
        return freed;
 }
@@ -2577,7 +2313,7 @@ extern __inline__ pte_t *sun4c_get_pte_fast(void)
 {
        unsigned long *ret;
 
-       if((ret = (unsigned long *)pte_quicklist) != NULL) {
+       if ((ret = (unsigned long *)pte_quicklist) != NULL) {
                pte_quicklist = (unsigned long *)(*ret);
                ret[0] = ret[1];
                pgtable_cache_size--;
@@ -2680,9 +2416,9 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
 
        if (vma->vm_file)
                dentry = vma->vm_file->f_dentry;
-       if(dentry)
+       if (dentry)
                inode = dentry->d_inode;
-       if(inode) {
+       if (inode) {
                unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
                struct vm_area_struct *vmaring = inode->i_mmap; 
                int alias_found = 0;
@@ -2691,19 +2427,21 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
                        unsigned long start;
 
                        /* Do not mistake ourselves as another mapping. */
-                       if(vmaring == vma)
+                       if (vmaring == vma)
                                continue;
 
                        if (S4CVAC_BADALIAS(vaddr, address)) {
                                alias_found++;
                                start = vmaring->vm_start;
-                               while(start < vmaring->vm_end) {
+                               while (start < vmaring->vm_end) {
                                        pgdp = sun4c_pgd_offset(vmaring->vm_mm, start);
-                                       if(!pgdp) goto next;
+                                       if (!pgdp)
+                                               goto next;
                                        ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
-                                       if(!ptep) goto next;
+                                       if (!ptep)
+                                               goto next;
 
-                                       if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
+                                       if (pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
                                                flush_cache_page(vmaring, start);
                                                *ptep = __pte(pte_val(*ptep) |
                                                              _SUN4C_PAGE_NOCACHE);
@@ -2715,7 +2453,7 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
                        }
                } while ((vmaring = vmaring->vm_next_share) != NULL);
 
-               if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
+               if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
                        pgdp = sun4c_pgd_offset(vma->vm_mm, address);
                        ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
                        *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
@@ -2724,16 +2462,62 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
        }
 }
 
+/* An experiment, turn off by default for now... -DaveM */
+#define SUN4C_PRELOAD_PSEG
+
 void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
        unsigned long flags;
+       int pseg;
 
        save_and_cli(flags);
        address &= PAGE_MASK;
-       if(sun4c_get_segmap(address) == invalid_segment)
-               alloc_user_segment(address, sun4c_get_context());
+       if ((pseg = sun4c_get_segmap(address)) == invalid_segment) {
+               struct sun4c_mmu_entry *entry = sun4c_user_strategy();
+               struct mm_struct *mm = vma->vm_mm;
+               unsigned long start, end;
+
+               entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK);
+               entry->ctx = mm->context;
+               add_ring_ordered(sun4c_context_ring + mm->context, entry);
+               sun4c_put_segmap(entry->vaddr, entry->pseg);
+               end = start + SUN4C_REAL_PGDIR_SIZE;
+               while (start < end) {
+#ifdef SUN4C_PRELOAD_PSEG
+                       pgd_t *pgdp = sun4c_pgd_offset(mm, start);
+                       pte_t *ptep;
+
+                       if (!pgdp)
+                               goto no_mapping;
+                       ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
+                       if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT))
+                               goto no_mapping;
+                       sun4c_put_pte(start, pte_val(*ptep));
+                       goto next;
+
+               no_mapping:
+#endif
+                       sun4c_put_pte(start, 0);
+#ifdef SUN4C_PRELOAD_PSEG
+               next:
+#endif
+                       start += PAGE_SIZE;
+               }
+               if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+                       sun4c_vac_alias_fixup(vma, address, pte);
+#ifndef SUN4C_PRELOAD_PSEG
+               sun4c_put_pte(address, pte_val(pte));
+#endif
+               restore_flags(flags);
+               return;
+       } else {
+               struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg];
+
+               remove_lru(entry);
+               add_lru(entry);
+       }
 
-       if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+       if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
                sun4c_vac_alias_fixup(vma, address, pte);
 
        sun4c_put_pte(address, pte_val(pte));
@@ -2786,8 +2570,8 @@ __initfunc(unsigned long sun4c_paging_init(unsigned long start_mem, unsigned lon
        start_mem = sparc_context_init(start_mem, num_contexts);
        start_mem = free_area_init(start_mem, end_mem);
        cnt = 0;
-       for(i = 0; i < num_segmaps; i++)
-               if(mmu_entry_pool[i].locked)
+       for (i = 0; i < num_segmaps; i++)
+               if (mmu_entry_pool[i].locked)
                        cnt++;
 
        max_user_taken_entries = num_segmaps - cnt - 40 - 1;
@@ -2839,7 +2623,7 @@ __initfunc(void ld_mmu_sun4c(void))
 
        BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM);
 
-       if(sun4c_vacinfo.do_hwflushes) {
+       if (sun4c_vacinfo.do_hwflushes) {
                BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_hw, BTFIXUPCALL_NORM);
                BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_hw, BTFIXUPCALL_NORM);
                BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_hw, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/mm/swift.S b/arch/sparc/mm/swift.S
new file mode 100644 (file)
index 0000000..c570f55
--- /dev/null
@@ -0,0 +1,274 @@
+/* $Id: swift.S,v 1.1.2.3 1999/10/14 01:00:17 davem Exp $
+ * swift.S: MicroSparc-II mmu/cache operations.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/pgtsrmmu.h>
+#include <asm/asm_offsets.h>
+
+#define WINDOW_FLUSH(tmp1, tmp2)                                       \
+       mov     0, tmp1;                                                \
+98:    ld      [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2;     \
+       orcc    %g0, tmp2, %g0;                                         \
+       add     tmp1, 1, tmp1;                                          \
+       bne     98b;                                                    \
+        save   %sp, -64, %sp;                                          \
+99:    subcc   tmp1, 1, tmp1;                                          \
+       bne     99b;                                                    \
+        restore %g0, %g0, %g0;
+
+       .text
+       .align  4
+
+#if 1  /* XXX screw this, I can't get the VAC flushes working
+        * XXX reliably... -DaveM
+        */
+       .globl  swift_flush_cache_all, swift_flush_cache_mm
+       .globl  swift_flush_cache_range, swift_flush_cache_page
+       .globl  swift_flush_page_for_dma, swift_flush_chunk
+       .globl  swift_flush_page_to_ram
+
+swift_flush_cache_all:
+swift_flush_cache_mm:
+swift_flush_cache_range:
+swift_flush_cache_page:
+swift_flush_page_for_dma:
+swift_flush_chunk:
+swift_flush_page_to_ram:
+       sethi   %hi(0x2000), %o0
+1:     subcc   %o0, 0x10, %o0
+       sta     %g0, [%o0] ASI_M_TXTC_TAG
+       sta     %g0, [%o0] ASI_M_DATAC_TAG
+       bne     1b
+        nop
+       retl
+        nop
+#else
+
+       .globl  swift_flush_cache_all
+swift_flush_cache_all:
+       WINDOW_FLUSH(%g4, %g5)
+
+       /* Just clear out all the tags. */
+       sethi   %hi(16 * 1024), %o0
+1:     subcc   %o0, 16, %o0
+       sta     %g0, [%o0] ASI_M_TXTC_TAG
+       bne     1b
+        sta    %g0, [%o0] ASI_M_DATAC_TAG
+       retl
+        nop
+
+       .globl  swift_flush_cache_mm
+swift_flush_cache_mm:
+#ifndef __SMP__
+       ld      [%o0 + AOFF_mm_context], %g2
+       cmp     %g2, -1
+       be      swift_flush_cache_mm_out
+#endif
+       WINDOW_FLUSH(%g4, %g5)
+       rd      %psr, %g1
+       andn    %g1, PSR_ET, %g3
+       wr      %g3, 0x0, %psr
+       nop
+       nop
+       mov     SRMMU_CTX_REG, %g7
+       lda     [%g7] ASI_M_MMUREGS, %g5
+       sta     %g2, [%g7] ASI_M_MMUREGS
+
+#if 1
+       sethi   %hi(0x2000), %o0
+1:     subcc   %o0, 0x10, %o0
+       sta     %g0, [%o0] ASI_M_FLUSH_CTX
+       bne     1b
+        nop
+#else
+       clr     %o0
+       or      %g0, 2048, %g7
+       or      %g0, 2048, %o1
+       add     %o1, 2048, %o2
+       add     %o2, 2048, %o3
+       mov     16, %o4
+       add     %o4, 2048, %o5
+       add     %o5, 2048, %g2
+       add     %g2, 2048, %g3
+1:     sta     %g0, [%o0      ] ASI_M_FLUSH_CTX
+       sta     %g0, [%o0 + %o1] ASI_M_FLUSH_CTX
+       sta     %g0, [%o0 + %o2] ASI_M_FLUSH_CTX
+       sta     %g0, [%o0 + %o3] ASI_M_FLUSH_CTX
+       sta     %g0, [%o0 + %o4] ASI_M_FLUSH_CTX
+       sta     %g0, [%o0 + %o5] ASI_M_FLUSH_CTX
+       sta     %g0, [%o0 + %g2] ASI_M_FLUSH_CTX
+       sta     %g0, [%o0 + %g3] ASI_M_FLUSH_CTX
+       subcc   %g7, 32, %g7
+       bne     1b
+        add    %o0, 32, %o0
+#endif
+
+       mov     SRMMU_CTX_REG, %g7
+       sta     %g5, [%g7] ASI_M_MMUREGS
+       wr      %g1, 0x0, %psr
+       nop
+       nop
+swift_flush_cache_mm_out:
+       retl
+        nop
+
+       .globl  swift_flush_cache_range
+swift_flush_cache_range:
+       sub     %o2, %o1, %o2
+       sethi   %hi(4096), %o3
+       cmp     %o2, %o3
+       bgu     swift_flush_cache_mm
+        nop
+       b       70f
+        nop
+
+       .globl  swift_flush_cache_page
+swift_flush_cache_page:
+       ld      [%o0 + 0x0], %o0                /* XXX vma->vm_mm, GROSS XXX */
+70:
+#ifndef __SMP__
+       ld      [%o0 + AOFF_mm_context], %g2
+       cmp     %g2, -1
+       be      swift_flush_cache_page_out
+#endif
+       WINDOW_FLUSH(%g4, %g5)
+       rd      %psr, %g1
+       andn    %g1, PSR_ET, %g3
+       wr      %g3, 0x0, %psr
+       nop
+       nop
+       mov     SRMMU_CTX_REG, %g7
+       lda     [%g7] ASI_M_MMUREGS, %g5
+       sta     %g2, [%g7] ASI_M_MMUREGS
+
+       andn    %o1, (PAGE_SIZE - 1), %o1
+#if 1
+       sethi   %hi(0x1000), %o0
+1:     subcc   %o0, 0x10, %o0
+       sta     %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+       bne     1b
+        nop
+#else
+       or      %g0, 512, %g7
+       or      %g0, 512, %o0
+       add     %o0, 512, %o2
+       add     %o2, 512, %o3
+       add     %o3, 512, %o4
+       add     %o4, 512, %o5
+       add     %o5, 512, %g3
+       add     %g3, 512, %g4
+1:     sta     %g0, [%o1      ] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o2] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o3] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o4] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o5] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %g3] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %g4] ASI_M_FLUSH_PAGE
+       subcc   %g7, 16, %g7
+       bne     1b
+        add    %o1, 16, %o1
+#endif
+
+       mov     SRMMU_CTX_REG, %g7
+       sta     %g5, [%g7] ASI_M_MMUREGS
+       wr      %g1, 0x0, %psr
+       nop
+       nop
+swift_flush_cache_page_out:
+       retl
+        nop
+
+       /* Swift is write-thru, however it is not
+        * I/O nor TLB-walk coherent.  Also it has
+        * caches which are virtually indexed and tagged.
+        */
+       .globl  swift_flush_page_for_dma
+       .globl  swift_flush_chunk
+       .globl  swift_flush_page_to_ram
+swift_flush_page_for_dma:
+swift_flush_chunk:
+swift_flush_page_to_ram:
+       andn    %o0, (PAGE_SIZE - 1), %o1
+#if 1
+       sethi   %hi(0x1000), %o0
+1:     subcc   %o0, 0x10, %o0
+       sta     %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+       bne     1b
+        nop
+#else
+       or      %g0, 512, %g7
+       or      %g0, 512, %o0
+       add     %o0, 512, %o2
+       add     %o2, 512, %o3
+       add     %o3, 512, %o4
+       add     %o4, 512, %o5
+       add     %o5, 512, %g3
+       add     %g3, 512, %g4
+1:     sta     %g0, [%o1      ] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o0] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o2] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o3] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o4] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o5] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %g3] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %g4] ASI_M_FLUSH_PAGE
+       subcc   %g7, 16, %g7
+       bne     1b
+        add    %o1, 16, %o1
+#endif
+       retl
+        nop
+#endif
+
+       .globl  swift_flush_sig_insns
+swift_flush_sig_insns:
+       flush   %o1
+       retl
+        flush  %o1 + 4
+
+       .globl  swift_flush_tlb_mm
+       .globl  swift_flush_tlb_range
+       .globl  swift_flush_tlb_all
+swift_flush_tlb_mm:
+swift_flush_tlb_range:
+#ifndef __SMP__
+       ld      [%o0 + AOFF_mm_context], %g2
+       cmp     %g2, -1
+       be      swift_flush_tlb_all_out
+#endif
+swift_flush_tlb_all:
+       mov     0x400, %o1
+       sta     %g0, [%o1] ASI_M_FLUSH_PROBE
+swift_flush_tlb_all_out:
+       retl
+        nop
+
+       .globl  swift_flush_tlb_page
+swift_flush_tlb_page:
+       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       mov     SRMMU_CTX_REG, %g1
+       ld      [%o0 + AOFF_mm_context], %o3
+       andn    %o1, (PAGE_SIZE - 1), %o1
+#ifndef __SMP__
+       cmp     %o3, -1
+       be      swift_flush_tlb_page_out
+        nop
+#endif
+#if 1
+       mov     0x400, %o1
+       sta     %g0, [%o1] ASI_M_FLUSH_PROBE    
+#else
+       lda     [%g1] ASI_M_MMUREGS, %g5
+       sta     %o3, [%g1] ASI_M_MMUREGS
+       sta     %g0, [%o1] ASI_M_FLUSH_PROBE
+       sta     %g5, [%g1] ASI_M_MMUREGS
+#endif
+swift_flush_tlb_page_out:
+       retl
+        nop
index e8bcf1ee1d688254bb53051501fcf731d13904f4..5d21165ded887d897d805d9b53cd72ac5b4ef79f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tsunami.S,v 1.1.6.1 1999/08/09 13:00:16 davem Exp $
+/* $Id: tsunami.S,v 1.1.6.3 1999/10/06 15:36:38 davem Exp $
  * tsunami.S: High speed MicroSparc-I mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -44,11 +44,11 @@ tsunami_flush_cache_range:
 tsunami_flush_cache_all:
        WINDOW_FLUSH(%g4, %g5)
 tsunami_flush_page_for_dma:
-       sta     %g0, [%g0] ASI_M_DC_FLCLEAR
        sta     %g0, [%g0] ASI_M_IC_FLCLEAR
+tsunami_flush_chunk:
+       sta     %g0, [%g0] ASI_M_DC_FLCLEAR
 tsunami_flush_cache_out:
 tsunami_flush_page_to_ram:
-tsunami_flush_chunk:
        retl
         nop
 
@@ -98,3 +98,51 @@ tsunami_flush_tlb_page:
 tsunami_flush_tlb_page_out:
        retl
         sta    %g5, [%g1] ASI_M_MMUREGS
+
+#define MIRROR_BLOCK(dst, src, offset, t0, t1, t2, t3) \
+       ldd     [src + offset + 0x18], t0; \
+       std     t0, [dst + offset + 0x18]; \
+       ldd     [src + offset + 0x10], t2; \
+       std     t2, [dst + offset + 0x10]; \
+       ldd     [src + offset + 0x08], t0; \
+       std     t0, [dst + offset + 0x08]; \
+       ldd     [src + offset + 0x00], t2; \
+       std     t2, [dst + offset + 0x00];
+
+       .globl  tsunami_copy_1page
+tsunami_copy_1page:
+/* NOTE: This routine has to be shorter than 70insns --jj */
+       or      %g0, (PAGE_SIZE >> 8), %g1
+1:
+       MIRROR_BLOCK(%o0, %o1, 0x00, %o2, %o3, %o4, %o5)
+       MIRROR_BLOCK(%o0, %o1, 0x20, %o2, %o3, %o4, %o5)
+       MIRROR_BLOCK(%o0, %o1, 0x40, %o2, %o3, %o4, %o5)
+       MIRROR_BLOCK(%o0, %o1, 0x60, %o2, %o3, %o4, %o5)
+       MIRROR_BLOCK(%o0, %o1, 0x80, %o2, %o3, %o4, %o5)
+       MIRROR_BLOCK(%o0, %o1, 0xa0, %o2, %o3, %o4, %o5)
+       MIRROR_BLOCK(%o0, %o1, 0xc0, %o2, %o3, %o4, %o5)
+       MIRROR_BLOCK(%o0, %o1, 0xe0, %o2, %o3, %o4, %o5)
+       subcc   %g1, 1, %g1
+       add     %o0, 0x100, %o0
+       bne     1b
+        add    %o1, 0x100, %o1
+
+       .globl  tsunami_setup_blockops
+tsunami_setup_blockops:
+       sethi   %hi(__copy_1page), %o0
+       or      %o0, %lo(__copy_1page), %o0
+       sethi   %hi(tsunami_copy_1page), %o1
+       or      %o1, %lo(tsunami_copy_1page), %o1
+       sethi   %hi(tsunami_setup_blockops), %o2
+       or      %o2, %lo(tsunami_setup_blockops), %o2
+       ld      [%o1], %o4
+1:     add     %o1, 4, %o1
+       st      %o4, [%o0]
+       add     %o0, 4, %o0
+       cmp     %o1, %o2
+       bne     1b
+       ld      [%o1], %o4
+       sta     %g0, [%g0] ASI_M_IC_FLCLEAR
+       sta     %g0, [%g0] ASI_M_DC_FLCLEAR
+       retl
+        nop
index cbdb33bb1d2912aaa5d2ef457bf09b8f1187bfb4..d5a3e6775e88e082f715b18fdd19489a6a2bccf9 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.67.2.2 1999/09/22 11:37:42 jj Exp $
+# $Id: config.in,v 1.67.2.5 1999/10/19 16:49:37 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -169,7 +169,7 @@ if [ "$CONFIG_SCSI" != "n" ]; then
            bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
            int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
          fi
-         dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
+         dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
          if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
            int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
            int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
index 231dc11e0d942df263054ab34a8e0fdd2f9d8fd5..690653a835d20869425a9b92665745e3956ddfe8 100644 (file)
@@ -27,7 +27,9 @@ CONFIG_VT_CONSOLE=y
 CONFIG_PROM_CONSOLE=y
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_PM2 is not set
+CONFIG_FB_PM2=y
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
+CONFIG_FB_PM2_PCI=y
 # CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
 CONFIG_FB_SBUS=y
@@ -200,10 +202,10 @@ CONFIG_SCSI_SUNESP=y
 CONFIG_SCSI_QLOGICPTI=m
 CONFIG_SCSI_AIC7XXX=y
 # CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
-# CONFIG_CMDS_PER_DEVICE is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
-CONFIG_SCSI_NCR53C8XX=y
+CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=10
index 43a2843a15f102609c50eb6aed25c7a4fa9d4382..66647ce06827fb9e6b0ef43d650b463db23fb7d1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.36.2.3 1999/09/21 15:45:37 davem Exp $
+/* $Id: ebus.c,v 1.36.2.4 1999/11/08 23:25:45 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -56,15 +56,15 @@ static inline unsigned long ebus_alloc(size_t size)
        return mem;
 }
 
-__initfunc(void ebus_intmap_match(struct linux_ebus *ebus,
-                                 struct linux_prom_registers *reg,
-                                 int *interrupt))
+__initfunc(int ebus_intmap_match(struct linux_ebus *ebus,
+                                struct linux_prom_registers *reg,
+                                int *interrupt))
 {
        unsigned int hi, lo, irq;
        int i;
 
        if (!ebus->num_ebus_intmap)
-               return;
+               return 0;
 
        hi = reg->which_io & ebus->ebus_intmask.phys_hi;
        lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
@@ -74,13 +74,10 @@ __initfunc(void ebus_intmap_match(struct linux_ebus *ebus,
                    (ebus->ebus_intmap[i].phys_lo == lo) &&
                    (ebus->ebus_intmap[i].interrupt == irq)) {
                        *interrupt = ebus->ebus_intmap[i].cinterrupt;
-                       return;
+                       return 0;
                }
        }
-
-       prom_printf("ebus: IRQ [%08x.%08x.%08x] not found in interrupt-map\n",
-                   reg->which_io, reg->phys_addr, *interrupt);
-       prom_halt();
+       return -1;
 }
 
 __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
@@ -132,9 +129,16 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
        } else {
                dev->num_irqs = len / sizeof(irqs[0]);
                for (i = 0; i < dev->num_irqs; i++) {
-                       ebus_intmap_match(dev->bus, preg, &irqs[i]);
-                       dev->irqs[i] = psycho_irq_build(dev->bus->parent,
-                                                       dev->bus->self, irqs[i]);
+                       if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
+                               dev->irqs[i] = psycho_irq_build(dev->bus->parent,
+                                                               dev->bus->self,
+                                                               irqs[i]);
+                       } else {
+                               /* If we get a bogus interrupt property, just
+                                * record the raw value instead of punting.
+                                */
+                               dev->irqs[i] = irqs[i];
+                       }
                }
        }
 
@@ -186,9 +190,16 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
        } else {
                dev->num_irqs = len / sizeof(irqs[0]);
                for (i = 0; i < dev->num_irqs; i++) {
-                       ebus_intmap_match(dev->bus, &regs[0], &irqs[i]);
-                       dev->irqs[i] = psycho_irq_build(dev->bus->parent,
-                                                       dev->bus->self, irqs[i]);
+                       if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) {
+                               dev->irqs[i] = psycho_irq_build(dev->bus->parent,
+                                                               dev->bus->self,
+                                                               irqs[i]);
+                       } else {
+                               /* If we get a bogus interrupt property, just
+                                * record the raw value instead of punting.
+                                */
+                               dev->irqs[i] = irqs[i];
+                       }
                }
        }
 
index 24eb4f64fedbd8dee5f07e9af339fdec3246ae31..47cdfc9bcce247f2b2810c01e5eeb0d7050ec21f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.103.2.2 1999/09/22 11:37:37 jj Exp $
+/* $Id: entry.S,v 1.103.2.4 1999/10/24 17:29:13 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -214,8 +214,8 @@ do_fptrap:
        .align          32
        .globl          do_ivec
 do_ivec:
-       wr              %g0, ASI_UDB_INTR_R, %asi
-       ldxa            [%g0 + 0x40] %asi, %g3
+       mov             0x40, %g3
+       ldxa            [%g3 + %g0] ASI_UDB_INTR_R, %g3
        sethi           %hi(KERNBASE), %g4
        cmp             %g3, %g4
        bgeu,pn         %xcc, do_ivec_xcall
@@ -234,22 +234,25 @@ do_ivec:
 
        sllx            %g2, %g4, %g2
        sllx            %g4, 2, %g4
-       lduw            [%g1 + %g4], %g5        /* g5 = irq_work(cpu, pil) */
+       lduw            [%g6 + %g4], %g5        /* g5 = irq_work(cpu, pil) */
        stw             %g5, [%g3 + 0x00]       /* bucket->irq_chain = g5 */
-       stw             %g3, [%g1 + %g4]        /* irq_work(cpu, pil) = bucket */
+       stw             %g3, [%g6 + %g4]        /* irq_work(cpu, pil) = bucket */
        wr              %g2, 0x0, %set_softint
        retry
 do_ivec_xcall:
-       ldxa            [%g0 + 0x50] %asi, %g6
+       mov             0x50, %g1
 
+       ldxa            [%g1 + %g0] ASI_UDB_INTR_R, %g1
        srl             %g3, 0, %g3
-       ldxa            [%g0 + 0x60] %asi, %g7
+       mov             0x60, %g7
+       ldxa            [%g7 + %g0] ASI_UDB_INTR_R, %g7
        stxa            %g0, [%g0] ASI_INTR_RECEIVE
        membar          #Sync
        jmpl            %g3, %g0
         nop
+
 do_ivec_spurious:
-       stw             %g3, [%g1 + 0x00]       /* irq_work(cpu, 0) = bucket */
+       stw             %g3, [%g6 + 0x00]       /* irq_work(cpu, 0) = bucket */
        rdpr            %pstate, %g5
 
        wrpr            %g5, PSTATE_IG | PSTATE_AG, %pstate
@@ -261,6 +264,76 @@ do_ivec_spurious:
        ba,pt           %xcc, rtrap
         clr            %l6
 
+       .globl          save_alternate_globals
+save_alternate_globals: /* %o0 = save_area */
+       rdpr            %pstate, %o5
+       andn            %o5, PSTATE_IE, %o1
+       wrpr            %o1, PSTATE_AG, %pstate
+       stx             %g0, [%o0 + 0x00]
+       stx             %g1, [%o0 + 0x08]
+       stx             %g2, [%o0 + 0x10]
+       stx             %g3, [%o0 + 0x18]
+       stx             %g4, [%o0 + 0x20]
+       stx             %g5, [%o0 + 0x28]
+       stx             %g6, [%o0 + 0x30]
+       stx             %g7, [%o0 + 0x38]
+       wrpr            %o1, PSTATE_IG, %pstate
+       stx             %g0, [%o0 + 0x40]
+       stx             %g1, [%o0 + 0x48]
+       stx             %g2, [%o0 + 0x50]
+       stx             %g3, [%o0 + 0x58]
+       stx             %g4, [%o0 + 0x60]
+       stx             %g5, [%o0 + 0x68]
+       stx             %g6, [%o0 + 0x70]
+       stx             %g7, [%o0 + 0x78]
+       wrpr            %o1, PSTATE_MG, %pstate
+       stx             %g0, [%o0 + 0x80]
+       stx             %g1, [%o0 + 0x88]
+       stx             %g2, [%o0 + 0x90]
+       stx             %g3, [%o0 + 0x98]
+       stx             %g4, [%o0 + 0xa0]
+       stx             %g5, [%o0 + 0xa8]
+       stx             %g6, [%o0 + 0xb0]
+       stx             %g7, [%o0 + 0xb8]
+       wrpr            %o5, 0x0, %pstate
+       retl
+        nop
+
+       .globl          restore_alternate_globals
+restore_alternate_globals: /* %o0 = save_area */
+       rdpr            %pstate, %o5
+       andn            %o5, PSTATE_IE, %o1
+       wrpr            %o1, PSTATE_AG, %pstate
+       ldx             [%o0 + 0x00], %g0
+       ldx             [%o0 + 0x08], %g1
+       ldx             [%o0 + 0x10], %g2
+       ldx             [%o0 + 0x18], %g3
+       ldx             [%o0 + 0x20], %g4
+       ldx             [%o0 + 0x28], %g5
+       ldx             [%o0 + 0x30], %g6
+       ldx             [%o0 + 0x38], %g7
+       wrpr            %o1, PSTATE_IG, %pstate
+       ldx             [%o0 + 0x40], %g0
+       ldx             [%o0 + 0x48], %g1
+       ldx             [%o0 + 0x50], %g2
+       ldx             [%o0 + 0x58], %g3
+       ldx             [%o0 + 0x60], %g4
+       ldx             [%o0 + 0x68], %g5
+       ldx             [%o0 + 0x70], %g6
+       ldx             [%o0 + 0x78], %g7
+       wrpr            %o1, PSTATE_MG, %pstate
+       ldx             [%o0 + 0x80], %g0
+       ldx             [%o0 + 0x88], %g1
+       ldx             [%o0 + 0x90], %g2
+       ldx             [%o0 + 0x98], %g3
+       ldx             [%o0 + 0xa0], %g4
+       ldx             [%o0 + 0xa8], %g5
+       ldx             [%o0 + 0xb0], %g6
+       ldx             [%o0 + 0xb8], %g7
+       wrpr            %o5, 0x0, %pstate
+       retl
+        nop
+
        .globl          getcc, setcc
 getcc:
        ldx             [%o0 + PT_V9_TSTATE], %o1
index 5cd44e48ed032aff8aae5440be6a1e024dd43763..2bb3d81460ab132ff17124ee10567e942489e136 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.60.2.2 1999/08/19 01:11:12 davem Exp $
+/* $Id: head.S,v 1.60.2.4 1999/11/12 15:45:47 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -52,7 +52,7 @@ bootup_user_stack:
 
         .ascii  "HdrS"
         .word   LINUX_VERSION_CODE
-        .half   0x0202          /* HdrS version */
+        .half   0x0203          /* HdrS version */
 root_flags:
         .half   1
 root_dev:
@@ -65,6 +65,7 @@ sparc_ramdisk_size:
         .word   0
         .xword  reboot_command
        .xword  bootstr_len
+       .word   _end
 
        /* We must be careful, 32-bit OpenBOOT will get confused if it
         * tries to save away a register window to a 64-bit kernel
@@ -92,28 +93,6 @@ sparc64_boot:
        wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
        wr      %g0, 0, %fprs
 
-#ifdef __SMP__
-       /* Ugly but necessary... */
-       sethi   %hi(KERNBASE), %g7
-       sethi   %hi(sparc64_cpu_startup), %g5
-       or      %g5, %lo(sparc64_cpu_startup), %g5
-       sub     %g5, %g7, %g5
-       sethi   %hi(sparc64_cpu_startup_end), %g6
-       or      %g6, %lo(sparc64_cpu_startup_end), %g6
-       sub     %g6, %g7, %g6
-       sethi   %hi(smp_trampoline), %g3
-       or      %g3, %lo(smp_trampoline), %g3
-       sub     %g3, %g7, %g3
-1:     ldx     [%g5], %g1
-       stx     %g1, [%g3]
-       membar  #StoreStore
-       flush   %g3
-       add     %g5, 8, %g5
-       cmp     %g5, %g6
-       blu,pt  %xcc, 1b
-        add    %g3, 8, %g3
-#endif
-
 create_mappings:
        /* %g5 holds the tlb data */
         sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
@@ -379,7 +358,7 @@ setup_tba:  /* i0 = is_starfire */
        wrpr    %o1, (PSTATE_IG|PSTATE_IE), %pstate
 #ifndef __SMP__
        sethi   %hi(__up_workvec), %g5
-       or      %g5, %lo(__up_workvec), %g1
+       or      %g5, %lo(__up_workvec), %g6
 #else
        /* By definition of where we are, this is boot_cpu. */
        sethi   %hi(cpu_data), %g5
@@ -403,7 +382,7 @@ not_starfire:
 set_worklist:
        sllx    %g1, 7, %g1
        add     %g5, %g1, %g5
-       add     %g5, 64, %g1
+       add     %g5, 64, %g6
 #endif
 
        /* Kill PROM timer */
index b6faa61ae7a6d4fedb50e20754ac64e625ce0f81..8722b81d745bc47264a5d8954a3ba9ce917f4f5c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.62.2.4 1999/09/22 17:06:56 jj Exp $
+/* $Id: ioctl32.c,v 1.62.2.7 1999/10/09 06:03:20 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -1699,9 +1699,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        int error = -EBADF;
 
        lock_kernel();
-       filp = fcheck(fd);
+       filp = fget(fd);
        if(!filp)
-               goto out;
+               goto out2;
 
        if (!filp->f_op || !filp->f_op->ioctl) {
                error = sys_ioctl (fd, cmd, arg);
@@ -1920,6 +1920,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        case TIOCSCTTY:
        case TIOCGPTN:
        case TIOCSPTLCK:
+       case TIOCGSERIAL:
+       case TIOCSSERIAL:
+       case TIOCSERGETLSR:
        
        /* Big F */
        case FBIOGTYPE:
@@ -2219,6 +2222,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        case CDROM_DRIVE_STATUS:
        case CDROM_DISC_STATUS:
        case CDROM_CHANGER_NSLOTS:
+       case CDROM_LOCKDOOR:
+       case CDROM_DEBUG:
+       case CDROM_GET_CAPABILITY:
        
        /* Big L */
        case LOOP_SET_FD:
@@ -2385,6 +2391,10 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        case AUTOFS_IOC_PROTOVER:
        case AUTOFS_IOC_EXPIRE:
        
+       /* Raw devices */
+       case _IO(0xac, 0): /* RAW_SETBIND */
+       case _IO(0xac, 1): /* RAW_GETBIND */
+
                error = sys_ioctl (fd, cmd, arg);
                goto out;
 
@@ -2397,9 +2407,11 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
                                       (int)fd, (unsigned int)cmd, (unsigned int)arg);
                } while(0);
                error = -EINVAL;
-               break;
+               goto out;
        }
 out:
+       fput(filp);
+out2:
        unlock_kernel();
        return error;
 }
index 4b72648696cc504fa58a597126b6f0665282780a..7d261302bc9a16b538027e9ca3c51236ad42063c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.85.2.2 1999/08/09 13:00:21 davem Exp $
+/* $Id: psycho.c,v 1.85.2.5 1999/10/28 02:28:38 davem Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -221,15 +221,12 @@ out:
        control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
        switch(tsbsize) {
        case 8:
-               pci_dvma_mask = 0x1fffffffUL;
                control |= IOMMU_TSBSZ_8K;
                break;
        case 16:
-               pci_dvma_mask = 0x3fffffffUL;
                control |= IOMMU_TSBSZ_16K;
                break;
        case 32:
-               pci_dvma_mask = 0x7fffffffUL;
                control |= IOMMU_TSBSZ_32K;
                break;
        default:
@@ -461,8 +458,19 @@ void __init pcibios_init(void)
 
                err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
                if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) {
+                       /* SABRE/APB is composed of a 4GB aligned 4GB
+                        * total PCI memory space.
+                        */
+                       pci_dvma_mask = 0xffffffff;
+
                        sabre_init(node);
                        goto next_pci;
+               } else {
+                       /* PSYCHO has two independant 4GB, 2GB aligned,
+                        * memory spaces, and the lower 2GB is the region
+                        * for all PCI memory space device mappings.
+                        */
+                       pci_dvma_mask = 0x7fffffff;
                }
 
                portid = prom_getintdefault(node, "upa-portid", 0xff);
@@ -755,17 +763,18 @@ static void __init apb_init(struct linux_psycho *sabre)
 {
        struct pci_dev *pdev;
        unsigned short stmp;
-       unsigned int itmp;
-       unsigned char btmp;
+#if 0
+       unsigned char sabre_latency_timer = 32;
 
        for(pdev = pci_devices; pdev; pdev = pdev->next) {
                if(pdev->vendor == PCI_VENDOR_ID_SUN &&
                   pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
-                       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+                       pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
+                                            &sabre_latency_timer);
                        break;
                }
        }
-
+#endif
        for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
                if (pdev->vendor == PCI_VENDOR_ID_SUN &&
                    pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
@@ -778,52 +787,11 @@ static void __init apb_init(struct linux_psycho *sabre)
                        /* Status register bits are "write 1 to clear". */
                        pci_write_config_word(pdev, PCI_STATUS, 0xffff);
                        pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
-
-                       pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &stmp);
-                       stmp = PCI_BRIDGE_CTL_MASTER_ABORT |
-                              PCI_BRIDGE_CTL_SERR |
-                              PCI_BRIDGE_CTL_PARITY;
-                       pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, stmp);
-
-                       pci_read_config_dword(pdev, APB_PCI_CONTROL_HIGH, &itmp);
-                       itmp = APB_PCI_CTL_HIGH_SERR |
-                              APB_PCI_CTL_HIGH_ARBITER_EN;
-                       pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp);
-
-                       /* Systems with SIMBA are usually workstations, so
-                        * we configure to park to SIMBA not to the previous
-                        * bus owner.
-                        */
-                       pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
-                       itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
-                       pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
-
-                       /* Don't mess with the retry limit and PIO/DMA latency
-                        * timer settings.  But do set primary and secondary
-                        * latency timers.
-                        */
-                       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
-                       pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
-
-                       /* Here is an overview of the behavior of various
-                        * revisions of APB wrt. write buffer full conditions:
-                        *
-                        * Revision 1.0: pre-FCS, always stalls
-                        * Revision 1.1: pre-FCS, always disconnects
-                        * Revision 1.2: same behavior as rev 1.1
-                        * Revision 1.3: behavior is determined by bit 4 of
-                        *               secondary control register
-                        *               0: stall initially, but disconnect
-                        *                  if PCI latency timer expires
-                        *               1: always disconnect
-                        *
-                        * By setting the bit, since it is reserved in previous
-                        * revisions of APB, we get all FCS hardware to have
-                        * identical behavior when APB's write buffer fills up.
-                        */
-                       pci_read_config_byte(pdev, APB_SECONDARY_CONTROL, &btmp);
-                       btmp |= APB_SECONDARY_CTL_DISCON_FULL;
-                       pci_write_config_byte(pdev, APB_SECONDARY_CONTROL, btmp);
+#if 0
+                       /* Propagate Sabre latency timer value into APB. */
+                       pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
+                                             sabre_latency_timer);
+#endif
                }
        }
 }
@@ -1959,6 +1927,12 @@ static void __init fixup_pci_dev(struct pci_dev *pdev,
 
        node = pcp->prom_node;
 
+       /* No need to crash if the PCI device lacks PROM
+        * information.
+        */
+       if (node == -1)
+               return;
+
        err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
        if(err == 0 || err == -1) {
                prom_printf("Cannot find REG for pci_dev\n");
index 4dd9651b3e2e1f457fd39fa2eeaec42d80cdb8ed..7e453413d77394befe8f59ea814fba4748a32ce8 100644 (file)
@@ -40,6 +40,7 @@ static pte_t *get_page(struct task_struct * tsk,
        pgd_t * pgdir;
        pmd_t * pgmiddle;
        pte_t * pgtable;
+       int fault;
 
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
@@ -50,8 +51,12 @@ repeat:
        current->mm->segments = (void *) (addr & PAGE_SIZE);
 
        if (pgd_none(*pgdir)) {
-               handle_mm_fault(tsk, vma, addr, write);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, write);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return 0;
        }
        if (pgd_bad(*pgdir)) {
                printk("ptrace: bad page directory %016lx\n", pgd_val(*pgdir));
@@ -60,8 +65,12 @@ repeat:
        }
        pgmiddle = pmd_offset(pgdir, addr);
        if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk, vma, addr, write);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, write);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return 0;
        }
        if (pmd_bad(*pgmiddle)) {
                printk("ptrace: bad page middle %016lx\n", pmd_val(*pgmiddle));
@@ -70,12 +79,20 @@ repeat:
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, write);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, write);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return 0;
        }
        if (write && !pte_write(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, write);
-               goto repeat;
+               fault = handle_mm_fault(tsk, vma, addr, write);
+               if (fault > 0)
+                       goto repeat;
+               if (fault < 0)
+                       force_sig(SIGKILL, tsk);
+               return 0;
        }
        return pgtable;
 }
index b09df057641349ab6f12da1815f312b716194370..1c2e67bd05c6d142034273db70a1d54c9a20d696 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.43.2.1 1999/05/28 02:18:13 davem Exp $
+/*  $Id: setup.c,v 1.43.2.2 1999/10/24 17:29:20 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -434,6 +434,17 @@ static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
 
 extern struct consw sun_serial_con;
 
+void register_prom_callbacks(void)
+{
+       prom_setcallback(prom_callback);
+       prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
+                  "' linux-va>tte-data to va>tte-data");
+       prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
+                  "' linux-.soft1 to .soft1");
+       prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
+                  "' linux-.soft2 to .soft2");
+}
+
 __initfunc(void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
@@ -478,13 +489,6 @@ __initfunc(void setup_arch(char **cmdline_p,
                        }
                }
        }
-       prom_setcallback(prom_callback);
-       prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
-                  "' linux-va>tte-data to va>tte-data");
-       prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
-                  "' linux-.soft1 to .soft1");
-       prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
-                  "' linux-.soft2 to .soft2");
 
        /* In paging_init() we tip off this value to see if we need
         * to change init_mm.pgd to point to the real alias mapping.
index 27344f4b62e13de167d8712720cb2a28682a8efa..3d3219a02a559db5f9aac4afda308c8f4727e734 100644 (file)
@@ -180,7 +180,7 @@ void cpu_panic(void)
 
 extern struct prom_cpuinfo linux_cpus[64];
 
-extern unsigned long smp_trampoline;
+extern unsigned long sparc64_cpu_startup;
 
 /* The OBP cpu startup callback truncates the 3rd arg cookie to
  * 32-bits (I think) so to be safe we have it read the pointer
@@ -206,15 +206,13 @@ __initfunc(void smp_boot_cpus(void))
                        continue;
 
                if(cpu_present_map & (1UL << i)) {
-                       unsigned long entry = (unsigned long)(&smp_trampoline);
+                       unsigned long entry = (unsigned long)(&sparc64_cpu_startup);
                        unsigned long cookie = (unsigned long)(&cpu_new_task);
                        struct task_struct *p;
                        int timeout;
                        int no;
-                       extern unsigned long phys_base;
 
-                       entry += phys_base - KERNBASE;
-                       cookie += phys_base - KERNBASE;
+                       prom_printf("Starting CPU %d... ", i);
                        kernel_thread(start_secondary, NULL, CLONE_PID);
                        p = task[++cpucount];
                        p->processor = i;
@@ -235,9 +233,11 @@ __initfunc(void smp_boot_cpus(void))
                                cpu_number_map[i] = cpucount;
                                __cpu_logical_map[cpucount] = i;
                                prom_cpu_nodes[i] = linux_cpus[no].prom_node;
+                               prom_printf("OK\n");
                        } else {
                                cpucount--;
                                printk("Processor %d is stuck.\n", i);
+                               prom_printf("FAILED\n");
                        }
                }
                if(!callin_flag) {
@@ -536,14 +536,31 @@ void smp_release(void)
 /* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
  * can service tlb flush xcalls...
  */
+extern void prom_world(int);
+extern void save_alternate_globals(unsigned long *);
+extern void restore_alternate_globals(unsigned long *);
 void smp_penguin_jailcell(void)
 {
-       flushw_user();
+       unsigned long global_save[24];
+
+       __asm__ __volatile__("flushw");
+       save_alternate_globals(global_save);
+       prom_world(1);
        atomic_inc(&smp_capture_registry);
        membar("#StoreLoad | #StoreStore");
        while(penguins_are_doing_time)
                membar("#LoadLoad");
+       restore_alternate_globals(global_save);
        atomic_dec(&smp_capture_registry);
+       prom_world(0);
+}
+
+extern unsigned long xcall_promstop;
+
+void smp_promstop_others(void)
+{
+       if (smp_processors_ready)
+               smp_cross_call(&xcall_promstop, 0, 0, 0);
 }
 
 static inline void sparc64_do_profile(unsigned long pc)
index 4d2396829db42f804dc12b80b78a12979d92f39b..8ac88ccde83773bb88eeb48b3975f721c55de899 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.107.2.1 1999/05/16 10:48:44 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.5 1999/11/12 11:17:47 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -44,6 +44,7 @@
 #include <linux/personality.h>
 #include <linux/stat.h>
 #include <linux/timex.h>
+#include <linux/filter.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -1136,8 +1137,10 @@ asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
        }
 
        ret = -EINVAL;
-       if (n < 0 || n > KFDS_NR)
+       if (n < 0)
                goto out_nofds;
+       if (n > current->files->max_fdset)
+               n = current->files->max_fdset;
 
        /*
         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
@@ -1197,84 +1200,157 @@ out_nofds:
        return ret;
 }
 
-static inline int putstat(struct stat32 *ubuf, struct stat *kbuf)
+static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
 {
+       unsigned long ino, blksize, blocks;
+       kdev_t dev, rdev;
+       umode_t mode;
+       nlink_t nlink;
+       uid_t uid;
+       gid_t gid;
+       off_t size;
+       time_t atime, mtime, ctime;
        int err;
-       
-       err = put_user (kbuf->st_dev, &ubuf->st_dev);
-       err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
-       err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
-       err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);
-       err |= __put_user (kbuf->st_uid, &ubuf->st_uid);
-       err |= __put_user (kbuf->st_gid, &ubuf->st_gid);
-       err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);
-       err |= __put_user (kbuf->st_size, &ubuf->st_size);
-       err |= __put_user (kbuf->st_atime, &ubuf->st_atime);
-       err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);
-       err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);
-       err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);
-       err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);
+
+       /* Stream the loads of inode data into the load buffer,
+        * then we push it all into the store buffer below.  This
+        * should give optimal cache performance.
+        */
+       ino = inode->i_ino;
+       dev = inode->i_dev;
+       mode = inode->i_mode;
+       nlink = inode->i_nlink;
+       uid = inode->i_uid;
+       gid = inode->i_gid;
+       rdev = inode->i_rdev;
+       size = inode->i_size;
+       atime = inode->i_atime;
+       mtime = inode->i_mtime;
+       ctime = inode->i_ctime;
+       blksize = inode->i_blksize;
+       blocks = inode->i_blocks;
+
+       err  = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
+       err |= put_user(ino, &statbuf->st_ino);
+       err |= put_user(mode, &statbuf->st_mode);
+       err |= put_user(nlink, &statbuf->st_nlink);
+       err |= put_user(uid, &statbuf->st_uid);
+       err |= put_user(gid, &statbuf->st_gid);
+       err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
+       err |= put_user(size, &statbuf->st_size);
+       err |= put_user(atime, &statbuf->st_atime);
+       err |= put_user(0, &statbuf->__unused1);
+       err |= put_user(mtime, &statbuf->st_mtime);
+       err |= put_user(0, &statbuf->__unused2);
+       err |= put_user(ctime, &statbuf->st_ctime);
+       err |= put_user(0, &statbuf->__unused3);
+       if (blksize) {
+               err |= put_user(blksize, &statbuf->st_blksize);
+               err |= put_user(blocks, &statbuf->st_blocks);
+       } else {
+               unsigned int tmp_blocks;
+
+#define D_B   7
+#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
+               tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+               if (tmp_blocks > D_B) {
+                       unsigned int indirect;
+
+                       indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
+                       tmp_blocks += indirect;
+                       if (indirect > 1) {
+                               indirect = (indirect - 1 + I_B - 1) / I_B;
+                               tmp_blocks += indirect;
+                               if (indirect > 1)
+                                       tmp_blocks++;
+                       }
+               }
+               err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
+               err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
+#undef D_B
+#undef I_B
+       }
+       err |= put_user(0, &statbuf->__unused4[0]);
+       err |= put_user(0, &statbuf->__unused4[1]);
+
        return err;
 }
 
-extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
-
 asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
 {
-       int ret;
-       struct stat s;
-       char *filenam;
-       mm_segment_t old_fs = get_fs();
-       
-       filenam = getname32 (filename);
-       ret = PTR_ERR(filenam);
-       if (!IS_ERR(filenam)) {
-               set_fs (KERNEL_DS);
-               ret = sys_newstat(filenam, &s);
-               set_fs (old_fs);
-               putname (filenam);
-               if (putstat (statbuf, &s))
-                       return -EFAULT;
+       struct dentry *dentry;
+       int error;
+
+       lock_kernel();
+       dentry = namei(filename);
+
+       error = PTR_ERR(dentry);
+       if (!IS_ERR(dentry)) {
+               struct inode *inode = dentry->d_inode;
+
+               if (inode->i_op &&
+                   inode->i_op->revalidate)
+                       error = inode->i_op->revalidate(dentry);
+               else
+                       error = 0;
+               if (!error)
+                       error = cp_new_stat32(inode, statbuf);
+
+               dput(dentry);
        }
-       return ret;
+       unlock_kernel();
+       return error;
 }
 
-extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
-
 asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
 {
-       int ret;
-       struct stat s;
-       char *filenam;
-       mm_segment_t old_fs = get_fs();
-       
-       filenam = getname32 (filename);
-       ret = PTR_ERR(filenam);
-       if (!IS_ERR(filenam)) {
-               set_fs (KERNEL_DS);
-               ret = sys_newlstat(filenam, &s);
-               set_fs (old_fs);
-               putname (filenam);
-               if (putstat (statbuf, &s))
-                       return -EFAULT;
+       struct dentry *dentry;
+       int error;
+
+       lock_kernel();
+       dentry = lnamei(filename);
+
+       error = PTR_ERR(dentry);
+       if (!IS_ERR(dentry)) {
+               struct inode *inode = dentry->d_inode;
+
+               if (inode->i_op &&
+                   inode->i_op->revalidate)
+                       error = inode->i_op->revalidate(dentry);
+               else
+                       error = 0;
+               if (!error)
+                       error = cp_new_stat32(inode, statbuf);
+
+               dput(dentry);
        }
-       return ret;
+       unlock_kernel();
+       return error;
 }
 
-extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
-
 asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
 {
-       int ret;
-       struct stat s;
-       mm_segment_t old_fs = get_fs();
-       
-       set_fs (KERNEL_DS);
-       ret = sys_newfstat(fd, &s);
-       set_fs (old_fs);
-       if (putstat (statbuf, &s))
-               return -EFAULT;
-       return ret;
+       struct file *f;
+       int err = -EBADF;
+
+       lock_kernel();
+       f = fget(fd);
+       if (f) {
+               struct dentry *dentry = f->f_dentry;
+               struct inode *inode = dentry->d_inode;
+
+               if (inode->i_op &&
+                   inode->i_op->revalidate)
+                       err = inode->i_op->revalidate(dentry);
+               else
+                       err = 0;
+               if (!err)
+                       err = cp_new_stat32(inode, statbuf);
+
+               fput(f);
+       }
+       unlock_kernel();
+       return err;
 }
 
 extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
@@ -1677,7 +1753,7 @@ asmlinkage int sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize
 siginfo_t32 *
 siginfo64to32(siginfo_t32 *d, siginfo_t *s)
 {
-       memset (&d, 0, sizeof(siginfo_t32));
+       memset (d, 0, sizeof(siginfo_t32));
        d->si_signo = s->si_signo;
        d->si_errno = s->si_errno;
        d->si_code = s->si_code;
@@ -2581,6 +2657,48 @@ out:
        return len;
 }
 
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+                                    char *optval, int optlen);
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+                               char *optval, int optlen)
+{
+       if (optname == SO_ATTACH_FILTER) {
+               struct sock_fprog32 {
+                       __u16 len;
+                       __u32 filter;
+               } *fprog32 = (struct sock_fprog32 *)optval;
+               struct sock_fprog kfprog;
+               struct sock_filter *kfilter;
+               unsigned int fsize;
+               mm_segment_t old_fs;
+               __u32 uptr;
+               int ret;
+
+               if (get_user(kfprog.len, &fprog32->len) ||
+                   __get_user(uptr, &fprog32->filter))
+                       return -EFAULT;
+               kfprog.filter = (struct sock_filter *)A(uptr);
+               fsize = kfprog.len * sizeof(struct sock_filter);
+               kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+               if (kfilter == NULL)
+                       return -ENOMEM;
+               if (copy_from_user(kfilter, kfprog.filter, fsize)) {
+                       kfree(kfilter);
+                       return -EFAULT;
+               }
+               kfprog.filter = kfilter;
+               old_fs = get_fs();
+               set_fs(KERNEL_DS);
+               ret = sys_setsockopt(fd, level, optname,
+                                    (char *)&kfprog, sizeof(kfprog));
+               set_fs(old_fs);
+               kfree(kfilter);
+               return ret;
+       }
+       return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
 /* Argument list sizes for sys_socketcall */
 #define AL(x) ((x) * sizeof(u32))
 static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
@@ -2599,8 +2717,6 @@ extern asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
 extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
 extern asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
                                     unsigned flags, u32 addr, u32 addr_len);
-extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
-                                    char *optval, int optlen);
 extern asmlinkage int sys32_getsockopt(int fd, int level, int optname,
                                       u32 optval, u32 optlen);
 
@@ -2651,7 +2767,7 @@ asmlinkage int sys32_socketcall(int call, u32 *args)
                case SYS_SHUTDOWN:
                        return sys_shutdown(a0,a1);
                case SYS_SETSOCKOPT:
-                       return sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
+                       return sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]);
                case SYS_GETSOCKOPT:
                        return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
                case SYS_SENDMSG:
index 0b72e6e0b8fdeb0e0ddf27252dca26af11eaabd6..dcf9571d8dec18ac10d44b450565ea42b26f12d5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.20 1999/03/15 22:13:40 davem Exp $
+/* $Id: time.c,v 1.20.2.1 1999/10/09 06:03:23 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -47,7 +47,7 @@ static int set_rtc_mmss(unsigned long);
  */
 unsigned long timer_tick_offset;
 static unsigned long timer_tick_compare;
-static unsigned long timer_ticks_per_usec;
+static unsigned long timer_ticks_per_usec_quotient;
 
 static __inline__ void timer_check_rtc(void)
 {
@@ -392,7 +392,7 @@ void __init time_init(void)
 
        init_timers(timer_interrupt, &clock);
        timer_tick_offset = clock / HZ;
-       timer_ticks_per_usec = clock / 1000000;
+       timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020UL));
 }
 
 static __inline__ unsigned long do_gettimeoffset(void)
@@ -408,7 +408,7 @@ static __inline__ unsigned long do_gettimeoffset(void)
                : "r" (timer_tick_offset), "r" (timer_tick_compare)
                : "g1", "g2");
 
-       return ticks / timer_ticks_per_usec;
+       return (ticks * timer_ticks_per_usec_quotient) >> 32UL;
 }
 
 /* This need not obtain the xtime_lock as it is coded in
@@ -431,24 +431,22 @@ void do_gettimeofday(struct timeval *tv)
        or      %g2, %lo(xtime), %g2
        or      %g1, %lo(timer_tick_compare), %g1
 1:     ldda    [%g2] 0x24, %o4
-       membar  #LoadLoad | #MemIssue
        rd      %tick, %o1
        ldx     [%g1], %g7
-       membar  #LoadLoad | #MemIssue
        ldda    [%g2] 0x24, %o2
-       membar  #LoadLoad
        xor     %o4, %o2, %o2
        xor     %o5, %o3, %o3
        orcc    %o2, %o3, %g0
        bne,pn  %xcc, 1b
         sethi  %hi(lost_ticks), %o2
-       sethi   %hi(timer_ticks_per_usec), %o3
+       sethi   %hi(timer_ticks_per_usec_quotient), %o3
        ldx     [%o2 + %lo(lost_ticks)], %o2
        add     %g3, %o1, %o1
-       ldx     [%o3 + %lo(timer_ticks_per_usec)], %o3
+       ldx     [%o3 + %lo(timer_ticks_per_usec_quotient)], %o3
        sub     %o1, %g7, %o1
+       mulx    %o3, %o1, %o1
        brz,pt  %o2, 1f
-        udivx  %o1, %o3, %o1
+        srlx   %o1, 32, %o1
        sethi   %hi(10000), %g2
        or      %g2, %lo(10000), %g2
        add     %o1, %g2, %o1
index df9b1b7b99c7d1d4a09225e2ccbbaf82eedb63c6..0e017d7c9c1f05a609afd780d02e910db3471b87 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.8.2.2 1999/08/19 01:11:14 davem Exp $
+/* $Id: trampoline.S,v 1.8.2.4 1999/10/27 00:22:24 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/asm_offsets.h>
 
        .data
-       .align          8
-       .globl          smp_trampoline
-smp_trampoline:                .skip   0x300
+       .align  8
+call_method:
+       .asciz  "call-method"
+       .align  8
+itlb_load:
+       .asciz  "SUNW,itlb-load"
+       .align  8
+dtlb_load:
+       .asciz  "SUNW,dtlb-load"
 
        .text
        .align          8
        .globl          sparc64_cpu_startup, sparc64_cpu_startup_end
 sparc64_cpu_startup:
        flushw
+
        mov     (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
        stxa    %g1, [%g0] ASI_LSU_CONTROL
        membar  #Sync
-       wrpr    %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
-       wr      %g0, 0, %fprs
+
        wrpr    %g0, 15, %pil
+       wr      %g0, 0, %tick_cmpr
+
+       /* Call OBP by hand to lock KERNBASE into i/d tlbs. */
+       mov     %o0, %l0
+
+       sethi   %hi(prom_entry_lock), %g2
+1:     ldstub  [%g2 + %lo(prom_entry_lock)], %g1
+       brnz,pn %g1, 1b
+        membar #StoreLoad | #StoreStore
+
+       sethi   %hi(p1275buf), %g2
+       or      %g2, %lo(p1275buf), %g2
+       ldx     [%g2 + 0x10], %l2
+       mov     %sp, %l1
+       add     %l2, -(192 + 128), %sp
+       flushw
+
+       sethi   %hi(call_method), %g2
+       or      %g2, %lo(call_method), %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x00]
+       mov     5, %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x08]
+       mov     1, %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x10]
+       sethi   %hi(itlb_load), %g2
+       or      %g2, %lo(itlb_load), %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x18]
+       sethi   %hi(mmu_ihandle_cache), %g2
+       lduw    [%g2 + %lo(mmu_ihandle_cache)], %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x20]
+       sethi   %hi(KERNBASE), %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x28]
+       sethi   %hi(kern_locked_tte_data), %g2
+       ldx     [%g2 + %lo(kern_locked_tte_data)], %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x30]
+       mov     63, %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x38]
+       sethi   %hi(p1275buf), %g2
+       or      %g2, %lo(p1275buf), %g2
+       ldx     [%g2 + 0x08], %o1
+       call    %o1
+        add    %sp, (2047 + 128), %o0
+
+       sethi   %hi(call_method), %g2
+       or      %g2, %lo(call_method), %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x00]
+       mov     5, %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x08]
+       mov     1, %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x10]
+       sethi   %hi(dtlb_load), %g2
+       or      %g2, %lo(dtlb_load), %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x18]
+       sethi   %hi(mmu_ihandle_cache), %g2
+       lduw    [%g2 + %lo(mmu_ihandle_cache)], %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x20]
+       sethi   %hi(KERNBASE), %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x28]
+       sethi   %hi(kern_locked_tte_data), %g2
+       ldx     [%g2 + %lo(kern_locked_tte_data)], %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x30]
+       mov     63, %g2
+       stx     %g2, [%sp + 2047 + 128 + 0x38]
+       sethi   %hi(p1275buf), %g2
+       or      %g2, %lo(p1275buf), %g2
+       ldx     [%g2 + 0x08], %o1
+       call    %o1
+        add    %sp, (2047 + 128), %o0
+
+       sethi   %hi(prom_entry_lock), %g2
+       stb     %g0, [%g2 + %lo(prom_entry_lock)]
+       membar  #StoreStore | #StoreLoad
+
+       mov     %l1, %sp
+       flushw
+
+       mov     %l0, %o0
+
+       wrpr    %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
+       wr      %g0, 0, %fprs
 
        sethi   %uhi(PAGE_OFFSET), %g4
        sllx    %g4, 32, %g4
@@ -37,99 +123,6 @@ sparc64_cpu_startup:
        srl     %o0, 0, %o0
        ldx     [%o0], %g6
 
-       sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
-       sllx    %g5, 32, %g5
-       or      %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
-
-       sethi   %uhi(_PAGE_PADDR), %g3
-       or      %g3, %ulo(_PAGE_PADDR), %g3
-       sllx    %g3, 32, %g3
-       sethi   %hi(_PAGE_PADDR), %g7
-       or      %g7, %lo(_PAGE_PADDR), %g7
-       or      %g3, %g7, %g3
-
-       clr     %l0
-       set     0x1fff, %l2
-       rd      %pc, %l3
-       andn    %l3, %l2, %g2
-1:     ldxa    [%l0] ASI_ITLB_TAG_READ, %g1
-       nop
-       nop
-       nop
-       andn    %g1, %l2, %g1
-       cmp     %g1, %g2
-       be,a,pn %xcc, 2f
-        ldxa   [%l0] ASI_ITLB_DATA_ACCESS, %g1
-       cmp     %l0, (63 << 3)
-       blu,pt  %xcc, 1b
-        add    %l0, (1 << 3), %l0
-
-2:     nop
-       nop
-       nop
-       and     %g1, %g3, %g1
-       sub     %g1, %g2, %g1
-       or      %g5, %g1, %g5
-       clr     %l0
-       sethi   %hi(KERNBASE), %g3
-       sethi   %hi(KERNBASE<<1), %g7
-       mov     TLB_TAG_ACCESS, %l7
-1:     ldxa    [%l0] ASI_ITLB_TAG_READ, %g1
-       nop
-       nop
-       nop
-       andn    %g1, %l2, %g1
-       cmp     %g1, %g3
-       blu,pn  %xcc, 2f
-        cmp    %g1, %g7
-       bgeu,pn %xcc, 2f
-        nop
-       stxa    %g0, [%l7] ASI_IMMU
-       stxa    %g0, [%l0] ASI_ITLB_DATA_ACCESS
-2:     cmp     %l0, (63 << 3)
-       blu,pt  %xcc, 1b
-        add    %l0, (1 << 3), %l0
-
-       nop
-       nop
-       nop
-       clr     %l0
-1:     ldxa    [%l0] ASI_DTLB_TAG_READ, %g1
-       nop
-       nop
-       nop
-       andn    %g1, %l2, %g1
-       cmp     %g1, %g3
-       blu,pn  %xcc, 2f
-        cmp    %g1, %g7
-       bgeu,pn %xcc, 2f
-        nop
-       stxa    %g0, [%l7] ASI_DMMU
-       stxa    %g0, [%l0] ASI_DTLB_DATA_ACCESS
-2:     cmp     %l0, (63 << 3)
-       blu,pt  %xcc, 1b
-        add    %l0, (1 << 3), %l0
-
-       nop
-       nop
-       nop
-       sethi   %hi(KERNBASE), %g3
-       mov     (63 << 3), %g7
-       stxa    %g3, [%l7] ASI_DMMU
-       stxa    %g5, [%g7] ASI_DTLB_DATA_ACCESS
-       membar  #Sync
-       stxa    %g3, [%l7] ASI_IMMU
-       stxa    %g5, [%g7] ASI_ITLB_DATA_ACCESS
-       membar  #Sync
-       flush   %g3
-       membar  #Sync
-       b,pt    %xcc, 1f
-        nop
-1:     set     bounce, %g2
-       jmpl    %g2 + %g0, %g0
-        nop
-
-bounce:
        mov     PRIMARY_CONTEXT, %g7
        stxa    %g0, [%g7] ASI_DMMU
        membar  #Sync
@@ -137,24 +130,6 @@ bounce:
        stxa    %g0, [%g7] ASI_DMMU
        membar  #Sync
 
-       mov     TLB_TAG_ACCESS, %g2
-       stxa    %g3, [%g2] ASI_IMMU
-       stxa    %g3, [%g2] ASI_DMMU
-
-       mov     (63 << 3), %g7
-       ldxa    [%g7] ASI_ITLB_DATA_ACCESS, %g1
-       andn    %g1, (_PAGE_G), %g1
-       stxa    %g1, [%g7] ASI_ITLB_DATA_ACCESS
-       membar  #Sync
-
-       ldxa    [%g7] ASI_DTLB_DATA_ACCESS, %g1
-       andn    %g1, (_PAGE_G), %g1
-       stxa    %g1, [%g7] ASI_DTLB_DATA_ACCESS
-       membar  #Sync
-
-       flush   %g3
-       membar  #Sync
-
        mov     1, %g5
        sllx    %g5, (PAGE_SHIFT + 1), %g5
        sub     %g5, (REGWIN_SZ + STACK_BIAS), %g5
@@ -167,12 +142,12 @@ bounce:
        /* Setup the trap globals, then we can resurface. */
        rdpr    %pstate, %o1
        mov     %g6, %o2
-       wrpr    %o1, (PSTATE_AG | PSTATE_IE), %pstate
+       wrpr    %o1, PSTATE_AG, %pstate
        sethi   %hi(sparc64_ttable_tl0), %g5
        wrpr    %g5, %tba
        mov     %o2, %g6
 
-       wrpr    %o1, (PSTATE_MG | PSTATE_IE), %pstate
+       wrpr    %o1, PSTATE_MG, %pstate
 #define KERN_HIGHBITS          ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
 #define KERN_LOWBITS           (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
 #ifdef THIS_IS_CHEETAH
@@ -198,7 +173,7 @@ bounce:
 #undef VPTE_BASE
 
        /* Setup interrupt globals, we are always SMP. */
-       wrpr    %o1, (PSTATE_IG | PSTATE_IE), %pstate
+       wrpr    %o1, PSTATE_IG, %pstate
 
        /* Get our UPA MID. */
        lduw    [%o2 + AOFF_task_processor], %g1
@@ -208,12 +183,15 @@ bounce:
        /* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */
        sllx    %g1, 7, %g1
        add     %g5, %g1, %g1
-       add     %g1, 64, %g1
+       add     %g1, 64, %g6
 
        wrpr    %g0, 0, %wstate
        or      %o1, PSTATE_IE, %o1
        wrpr    %o1, 0, %pstate
 
+       call    prom_set_trap_table
+        sethi  %hi(sparc64_ttable_tl0), %o0
+
        call    smp_callin
         nop
        call    cpu_idle
index cc189ce2d381a2b440a61eed5f7c2873327b7c16..c850247cafcb2e227999867d3829b63fc01dce8d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.16 1998/10/20 03:09:04 jj Exp $
+/* $Id: blockops.S,v 1.16.2.1 1999/10/07 20:48:14 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
@@ -136,16 +136,18 @@ clear_page:               /* %o0=dest */
 
        faddd           %f0, %f2, %f12                  ! FPA   Group
        fmuld           %f0, %f2, %f14                  ! FPM
-       wr              %g0, ASI_BLK_P, %asi            ! LSU   Group
        membar          #StoreLoad | #StoreStore | #LoadStore   ! LSU   Group
-1:     stda            %f0, [%o0 + 0x00] %asi          ! Store Group
-       stda            %f0, [%o0 + 0x40] %asi          ! Store Group
-       stda            %f0, [%o0 + 0x80] %asi          ! Store Group
-       stda            %f0, [%o0 + 0xc0] %asi          ! Store Group
+1:     stda            %f0, [%o0 + %g0] ASI_BLK_P      ! Store Group
+       add             %o0, 0x40, %o0                  ! IEU0
+       stda            %f0, [%o0 + %g0] ASI_BLK_P      ! Store Group
+       add             %o0, 0x40, %o0                  ! IEU0
+       stda            %f0, [%o0 + %g0] ASI_BLK_P      ! Store Group
 
+       add             %o0, 0x40, %o0                  ! IEU0  Group
+       stda            %f0, [%o0 + %g0] ASI_BLK_P      ! Store Group
        subcc           %o1, 1, %o1                     ! IEU1
        bne,pt          %icc, 1b                        ! CTI
-        add            %o0, 0x100, %o0                 ! IEU0  Group
+        add            %o0, 0x40, %o0                  ! IEU0  Group
        membar          #Sync                           ! LSU   Group
        VISExitHalf
 
index a0d1c8144d67728ed54cbd615813bfa421451add..df858eb2cfe05f097fc5ecd5d667313749278b34 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.5 1998/09/13 04:30:33 davem Exp $
+/*  $Id: asyncd.c,v 1.5.2.1 1999/11/16 06:29:53 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
@@ -152,7 +152,9 @@ static int fault_in_page(int taskid,
        if(!pte)
                goto no_memory;
        if(!pte_present(*pte)) {
-               handle_mm_fault(tsk, vma, address, write);
+               int fault = handle_mm_fault(tsk, vma, address, write);
+               if (fault < 0)
+                       goto no_memory;
                goto finish_up;
        }
        set_pte(pte, pte_mkyoung(*pte));
@@ -164,7 +166,11 @@ static int fault_in_page(int taskid,
                flush_tlb_page(vma, address);
                goto finish_up;
        }
-       handle_mm_fault(tsk, vma, address, write);
+       {
+               int fault = handle_mm_fault(tsk, vma, address, write);
+               if (fault < 0)
+                       goto no_memory;
+       }
 
        /* Fall through for do_wp_page */
 finish_up:
@@ -173,7 +179,7 @@ finish_up:
 
 no_memory:
        stats.failure++;
-       oom(tsk);
+       force_sig(SIGKILL, tsk);
        return 1;
        
 bad_area:        
index 88fd55e0327af7e72c6a485794ffdf18a03d066c..869b34ccee6dce54ae1b503cbe6ee23dcda8ec70 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.34 1999/03/16 12:12:28 jj Exp $
+/* $Id: fault.c,v 1.34.2.1 1999/11/16 06:29:56 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -210,8 +210,15 @@ good_area:
                        goto bad_area;
        }
        current->mm->segments = (void *) (address & PAGE_SIZE);
-       if (!handle_mm_fault(current, vma, address, write))
-               goto do_sigbus;
+survive:
+       {
+               int fault = handle_mm_fault(current, vma, address, write);
+               if (!fault)
+                       goto do_sigbus;
+               if (fault < 0)
+                       goto out_of_memory;
+       }
+
        up(&mm->mmap_sem);
        return;
        /*
@@ -291,6 +298,17 @@ do_kernel_fault:
        }
        return;
 
+out_of_memory:
+       if (current->pid == 1) {
+               current->policy |= SCHED_YIELD;
+               schedule();
+               goto survive;
+       }
+       up(&mm->mmap_sem);
+       printk("VM: killing process %s\n", current->comm);
+       do_exit(SIGKILL);
+       return;
+
 do_sigbus:
        up(&mm->mmap_sem);
        current->tss.sig_address = address;
index 4bc3c3881b754c45af5e117ca47d72d427841276..916c46a569ccfe21dcc037c691787afd1cca5b23 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.127.2.1 1999/06/25 10:42:10 davem Exp $
+/*  $Id: init.c,v 1.127.2.4 1999/10/24 17:29:30 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -40,9 +40,6 @@ unsigned long *sparc64_valid_addr_bitmap;
 /* Ugly, but necessary... -DaveM */
 unsigned long phys_base;
 
-/* get_new_mmu_context() uses "cache + 1".  */
-unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
-
 /* References to section boundaries */
 extern char __init_begin, __init_end, etext, __bss_start;
 
@@ -646,13 +643,23 @@ struct linux_prom_translation {
        unsigned long data;
 };
 
-static inline void inherit_prom_mappings(void)
+extern unsigned long prom_boot_page;
+extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
+extern int prom_get_mmu_ihandle(void);
+extern void register_prom_callbacks(void);
+
+/* Exported for SMP bootup purposes. */
+unsigned long kern_locked_tte_data;
+
+static void inherit_prom_mappings(void)
 {
        struct linux_prom_translation *trans;
+       unsigned long phys_page, tte_vaddr, tte_data;
+       void (*remap_func)(unsigned long, unsigned long, int);
        pgd_t *pgdp;
        pmd_t *pmdp;
        pte_t *ptep;
-       int node, n, i;
+       int node, n, i, tsz;
 
        node = prom_finddevice("/virtual-memory");
        n = prom_getproplen(node, "translations");
@@ -660,11 +667,12 @@ static inline void inherit_prom_mappings(void)
                prom_printf("Couldn't get translation property\n");
                prom_halt();
        }
+       n += 5 * sizeof(struct linux_prom_translation);
+       for (tsz = 1; tsz < n; tsz <<= 1)
+               /* empty */;
+       trans = sparc_init_alloc(&mempool, tsz);
 
-       for (i = 1; i < n; i <<= 1) /* empty */;
-       trans = sparc_init_alloc(&mempool, i);
-
-       if (prom_getproperty(node, "translations", (char *)trans, i) == -1) {
+       if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
                prom_printf("Couldn't get translation property\n");
                prom_halt();
        }
@@ -696,6 +704,83 @@ static inline void inherit_prom_mappings(void)
                        }
                }
        }
+
+       /* Now fixup OBP's idea about where we really are mapped. */
+       prom_printf("Remapping the kernel... ");
+       phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR;
+       phys_page += ((unsigned long)&prom_boot_page -
+                     (unsigned long)&empty_zero_page);
+
+       /* Lock this into i/d tlb entry 59 */
+       __asm__ __volatile__(
+               "stxa   %%g0, [%2] %3\n\t"
+               "stxa   %0, [%1] %4\n\t"
+               "membar #Sync\n\t"
+               "flush  %%g6\n\t"
+               "stxa   %%g0, [%2] %5\n\t"
+               "stxa   %0, [%1] %6\n\t"
+               "membar #Sync\n\t"
+               "flush  %%g6"
+               : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP |
+                        _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W),
+                   "r" (59 << 3), "r" (TLB_TAG_ACCESS),
+                   "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
+                   "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
+               : "memory");
+
+       tte_vaddr = (unsigned long) &empty_zero_page;
+       kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63);
+
+       remap_func = (void *)  ((unsigned long) &prom_remap -
+                               (unsigned long) &prom_boot_page);
+
+       remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR,
+                  (unsigned long) &empty_zero_page,
+                  prom_get_mmu_ihandle());
+
+       /* Flush out that temporary mapping. */
+       spitfire_flush_dtlb_nucleus_page(0x0);
+       spitfire_flush_itlb_nucleus_page(0x0);
+
+       /* Now lock us back into the TLBs via OBP. */
+       prom_dtlb_load(63, tte_data, tte_vaddr);
+       prom_itlb_load(63, tte_data, tte_vaddr);
+
+       /* Re-read translations property. */
+       if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
+               prom_printf("Couldn't get translation property\n");
+               prom_halt();
+       }
+       n = n / sizeof(*trans);
+
+       for (i = 0; i < n; i++) {
+               unsigned long vaddr = trans[i].virt;
+               unsigned long size = trans[i].size;
+
+               if (vaddr < 0xf0000000UL) {
+                       unsigned long avoid_start = (unsigned long) &empty_zero_page;
+                       unsigned long avoid_end = avoid_start + (4 * 1024 * 1024);
+
+                       if (vaddr < avoid_start) {
+                               unsigned long top = vaddr + size;
+
+                               if (top > avoid_start)
+                                       top = avoid_start;
+                               prom_unmap(top - vaddr, vaddr);
+                       }
+                       if ((vaddr + size) > avoid_end) {
+                               unsigned long bottom = vaddr;
+
+                               if (bottom < avoid_end)
+                                       bottom = avoid_end;
+                               prom_unmap((vaddr + size) - bottom, bottom);
+                       }
+               }
+       }
+
+       prom_printf("done.\n");
+
+       register_prom_callbacks();
 }
 
 /* The OBP specifications for sun4u mark 0xfffffffc00000000 and
@@ -956,6 +1041,8 @@ void __flush_tlb_all(void)
 
 #define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
 unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
+spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED;
+unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
 
 /* Caller does TLB context flushing on local CPU if necessary.
  *
@@ -966,14 +1053,17 @@ unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
  */
 void get_new_mmu_context(struct mm_struct *mm)
 {
-       unsigned long ctx = (tlb_context_cache + 1) & ~(CTX_VERSION_MASK);
-       unsigned long new_ctx;
+       unsigned long ctx, new_ctx;
        
+       spin_lock(&ctx_alloc_lock);
+       ctx = (tlb_context_cache + 1) & ~(CTX_VERSION_MASK);
        if (ctx == 0)
                ctx = 1;
        if ((mm->context != NO_CONTEXT) &&
-           !((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK))
-               clear_bit(mm->context & ~(CTX_VERSION_MASK), mmu_context_bmap);
+           !((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)) {
+               unsigned long nr = mm->context & ~(CTX_VERSION_MASK);
+               mmu_context_bmap[nr >> 6] &= ~(1UL << (nr & 63));
+       }
        new_ctx = find_next_zero_bit(mmu_context_bmap, 1UL << CTX_VERSION_SHIFT, ctx);
        if (new_ctx >= (1UL << CTX_VERSION_SHIFT)) {
                new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1);
@@ -1000,10 +1090,12 @@ void get_new_mmu_context(struct mm_struct *mm)
                        goto out;
                }
        }
-       set_bit(new_ctx, mmu_context_bmap);
+       mmu_context_bmap[new_ctx >> 6] |= (1UL << (new_ctx & 63));
        new_ctx |= (tlb_context_cache & CTX_VERSION_MASK);
 out:
        tlb_context_cache = new_ctx;
+       spin_unlock(&ctx_alloc_lock);
+
        mm->context = new_ctx;
        mm->cpu_vm_mask = 0;
 }
@@ -1214,7 +1306,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        /* Allocate 64M for dynamic DVMA mapping area. */
        allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000);
        inherit_prom_mappings();
-       
+
        /* Ok, we can use our TLB miss and window trap handlers safely.
         * We need to do a quick peek here to see if we are on StarFire
         * or not, so setup_tba can setup the IRQ globals correctly (it
@@ -1230,24 +1322,12 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
                setup_tba(is_starfire);
        }
 
-       /* Really paranoid. */
-       flushi((long)&empty_zero_page);
-       membar("#Sync");
-
-       /* Cleanup the extra locked TLB entry we created since we have the
-        * nice TLB miss handlers of ours installed now.
-        */
+       inherit_locked_prom_mappings(1);
+       
        /* We only created DTLB mapping of this stuff. */
        spitfire_flush_dtlb_nucleus_page(alias_base);
        if (second_alias_page)
                spitfire_flush_dtlb_nucleus_page(second_alias_page);
-       membar("#Sync");
-
-       /* Paranoid */
-       flushi((long)&empty_zero_page);
-       membar("#Sync");
-
-       inherit_locked_prom_mappings(1);
 
        flush_tlb_all();
 
@@ -1256,11 +1336,97 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
        return device_scan (PAGE_ALIGN (start_mem));
 }
 
+/* Ok, it seems that the prom can allocate some more memory chunks
+ * as a side effect of some prom calls we perform during the
+ * boot sequence.  My most likely theory is that it is from the
+ * prom_set_traptable() call, and OBP is allocating a scratchpad
+ * for saving client program register state etc.
+ */
+__initfunc(static void sort_memlist(struct linux_mlist_p1275 *thislist))
+{
+       int swapi = 0;
+       int i, mitr;
+       unsigned long tmpaddr, tmpsize;
+       unsigned long lowest;
+
+       for(i=0; thislist[i].theres_more != 0; i++) {
+               lowest = thislist[i].start_adr;
+               for(mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++)
+                       if(thislist[mitr].start_adr < lowest) {
+                               lowest = thislist[mitr].start_adr;
+                               swapi = mitr;
+                       }
+               if(lowest == thislist[i].start_adr) continue;
+               tmpaddr = thislist[swapi].start_adr;
+               tmpsize = thislist[swapi].num_bytes;
+               for(mitr = swapi; mitr > i; mitr--) {
+                       thislist[mitr].start_adr = thislist[mitr-1].start_adr;
+                       thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
+               }
+               thislist[i].start_adr = tmpaddr;
+               thislist[i].num_bytes = tmpsize;
+       }
+}
+
+__initfunc(static void rescan_sp_banks(void))
+{
+       struct linux_prom64_registers memlist[64];
+       struct linux_mlist_p1275 avail[64], *mlist;
+       unsigned long bytes, base_paddr;
+       int num_regs, node = prom_finddevice("/memory");
+       int i;
+
+       num_regs = prom_getproperty(node, "available",
+                                   (char *) memlist, sizeof(memlist));
+       num_regs = (num_regs / sizeof(struct linux_prom64_registers));
+       for (i = 0; i < num_regs; i++) {
+               avail[i].start_adr = memlist[i].phys_addr;
+               avail[i].num_bytes = memlist[i].reg_size;
+               avail[i].theres_more = &avail[i + 1];
+       }
+       avail[i - 1].theres_more = NULL;
+       sort_memlist(avail);
+
+       mlist = &avail[0];
+       i = 0;
+       bytes = mlist->num_bytes;
+       base_paddr = mlist->start_adr;
+  
+       sp_banks[0].base_addr = base_paddr;
+       sp_banks[0].num_bytes = bytes;
+
+       while (mlist->theres_more != NULL){
+               i++;
+               mlist = mlist->theres_more;
+               bytes = mlist->num_bytes;
+               if (i >= SPARC_PHYS_BANKS-1) {
+                       printk ("The machine has more banks than "
+                               "this kernel can support\n"
+                               "Increase the SPARC_PHYS_BANKS "
+                               "setting (currently %d)\n",
+                               SPARC_PHYS_BANKS);
+                       i = SPARC_PHYS_BANKS-1;
+                       break;
+               }
+    
+               sp_banks[i].base_addr = mlist->start_adr;
+               sp_banks[i].num_bytes = mlist->num_bytes;
+       }
+
+       i++;
+       sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;
+       sp_banks[i].num_bytes = 0;
+
+       for (i = 0; sp_banks[i].num_bytes != 0; i++)
+               sp_banks[i].num_bytes &= PAGE_MASK;
+}
+
 __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
 {
        unsigned long tmp = 0, paddr, endaddr;
        unsigned long end = __pa(end_mem);
 
+       rescan_sp_banks();
        dvmaio_init();
        for (paddr = __pa(start_mem); paddr < end; ) {
                for (; sp_banks[tmp].num_bytes != 0; tmp++)
index 3d3d1a2892c00eb5574acb99b61490009a5d9b63..b2b0d4a32074e53bb8ec2971cf7850ac0010f20d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.32 1999/03/28 08:39:34 davem Exp $
+/* $Id: ultra.S,v 1.32.2.1 1999/10/24 17:29:34 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -173,10 +173,10 @@ iflush2:stxa              %g0, [%o1 + %o2] ASI_IC_TAG
         *
         * Register usage:
         *   %g5        mm->context     (all tlb flushes)
-        *   %g6        address arg 1   (tlb page and range flushes)
+        *   %g1        address arg 1   (tlb page and range flushes)
         *   %g7        address arg 2   (tlb range flush only)
         *
-        *   %g1        ivector table, don't touch
+        *   %g6        ivector table, don't touch
         *   %g2        scratch 1
         *   %g3        scratch 2
         *   %g4        scratch 3
@@ -187,7 +187,7 @@ iflush2:stxa                %g0, [%o1 + %o2] ASI_IC_TAG
        .globl          xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
 xcall_flush_tlb_page:
        mov             SECONDARY_CONTEXT, %g2
-       or              %g6, 0x10, %g4
+       or              %g1, 0x10, %g4
        ldxa            [%g2] ASI_DMMU, %g3
        stxa            %g5, [%g2] ASI_DMMU
        stxa            %g0, [%g4] ASI_DMMU_DEMAP
@@ -208,11 +208,11 @@ xcall_flush_tlb_mm:
 xcall_flush_tlb_range:
        sethi           %hi(8192 - 1), %g2
        or              %g2, %lo(8192 - 1), %g2
-       andn            %g6, %g2, %g6
+       andn            %g1, %g2, %g1
        andn            %g7, %g2, %g7
-       sub             %g7, %g6, %g3
+       sub             %g7, %g1, %g3
        add             %g2, 1, %g2
-       orcc            %g6, 0x10, %g6
+       orcc            %g1, 0x10, %g1
        srlx            %g3, 13, %g4
 
        cmp             %g4, 96
@@ -224,8 +224,8 @@ xcall_flush_tlb_range:
        nop
        nop
 
-1:     stxa            %g0, [%g6 + %g3] ASI_DMMU_DEMAP
-       stxa            %g0, [%g6 + %g3] ASI_IMMU_DEMAP
+1:     stxa            %g0, [%g1 + %g3] ASI_DMMU_DEMAP
+       stxa            %g0, [%g1 + %g3] ASI_IMMU_DEMAP
        brnz,pt         %g3, 1b
         sub            %g3, %g2, %g3
        stxa            %g7, [%g4] ASI_DMMU
@@ -261,6 +261,22 @@ xcall_capture:
        b,pt            %xcc, rtrap
         clr            %l6
 
+       .globl          xcall_promstop
+xcall_promstop:
+       rdpr            %pstate, %g2
+       wrpr            %g2, PSTATE_IG | PSTATE_AG, %pstate
+       rdpr            %pil, %g2
+       wrpr            %g0, 15, %pil
+       sethi           %hi(109f), %g7
+       b,pt            %xcc, etrap_irq
+109:    or             %g7, %lo(109b), %g7
+       flushw
+       call            prom_stopself
+        nop
+       /* We should not return, just spin if we do... */
+1:     b,a,pt          %xcc, 1b
+       nop
+
        .globl          xcall_receive_signal
 xcall_receive_signal:
        rdpr            %pstate, %g2
@@ -302,7 +318,7 @@ xcall_flush_tlb_all:
        cmp             %g2, 63
        ble,pt          %icc, 1b
         sll            %g2, 3, %g3
-       flush           %g1
+       flush           %g6
        retry
 
        .globl          xcall_flush_cache_all
@@ -315,6 +331,6 @@ xcall_flush_cache_all:
        cmp             %g3, %g2
        bleu,pt         %xcc, 1b
         nop
-       flush           %g1
+       flush           %g6
        retry
 #endif /* __SMP__ */
index 1cec2111e18df214589965550abffe9c70ab8b47..8532d64caf36d4f61b75200d61256d44669ee352 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.2 1997/02/25 12:40:25 jj Exp $
+# $Id: Makefile,v 1.2.6.1 1999/10/24 17:29:02 davem Exp $
 # Makefile for the Sun Boot PROM interface library under
 # Linux.
 #
@@ -9,7 +9,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 OBJS  = bootstr.o devops.o init.o memory.o misc.o \
-        ranges.o tree.o console.o printf.o p1275.o
+        ranges.o tree.o console.o printf.o p1275.o map.o
 
 all: promlib.a
 
@@ -17,6 +17,12 @@ promlib.a: $(OBJS)
        $(AR) rcs promlib.a $(OBJS)
        sync
 
+.S.s:
+       $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+       $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
 dep:
        $(CPP) -M *.c > .depend
 
diff --git a/arch/sparc64/prom/map.S b/arch/sparc64/prom/map.S
new file mode 100644 (file)
index 0000000..6315eeb
--- /dev/null
@@ -0,0 +1,70 @@
+/* $Id: map.S,v 1.1.2.1 1999/10/24 17:28:59 davem Exp $
+ * map.S: Tricky coding required to fixup the kernel OBP maps
+ *       properly.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+       .text
+       .align  8192
+       .globl  prom_boot_page
+prom_boot_page:
+call_method:
+       .asciz  "call-method"
+       .align  8
+map:
+       .asciz  "map"
+       .align  8
+
+       /* When we are invoked, our caller has remapped us to
+        * page zero, therefore we must use PC relative addressing
+        * for everything after we begin performing the unmap/map
+        * calls.
+        */
+       .globl  prom_remap
+prom_remap:    /* %o0 = physpage, %o1 = virtpage, %o2 = mmu_ihandle */
+       rd      %pc, %g1
+       srl     %o2, 0, %o2                     ! kill sign extension
+       sethi   %hi(p1275buf), %g2
+       or      %g2, %lo(p1275buf), %g2
+       ldx     [%g2 + 0x10], %g3               ! prom_cif_stack
+       save    %g3, -(192 + 128), %sp
+       ldx     [%g2 + 0x08], %l0               ! prom_cif_handler
+       mov     %g6, %i3
+       mov     %g4, %i4
+       flushw
+
+       sethi   %hi(prom_remap - call_method), %g7
+       or      %g7, %lo(prom_remap - call_method), %g7
+       sub     %g1, %g7, %l2                   ! call-method string
+       sethi   %hi(prom_remap - map), %g7
+       or      %g7, %lo(prom_remap - map), %g7
+       sub     %g1, %g7, %l4                   ! map string
+
+       /* OK, map the 4MB region we really live at. */
+       stx     %l2, [%sp + 2047 + 128 + 0x00]  ! call-method
+       mov     7, %l5
+       stx     %l5, [%sp + 2047 + 128 + 0x08]  ! num_args
+       mov     1, %l5
+       stx     %l5, [%sp + 2047 + 128 + 0x10]  ! num_rets
+       stx     %l4, [%sp + 2047 + 128 + 0x18]  ! map
+       stx     %i2, [%sp + 2047 + 128 + 0x20]  ! mmu_ihandle
+       mov     -1, %l5
+       stx     %l5, [%sp + 2047 + 128 + 0x28]  ! mode == default
+       sethi   %hi(4 * 1024 * 1024), %l5
+       stx     %l5, [%sp + 2047 + 128 + 0x30]  ! size
+       stx     %i1, [%sp + 2047 + 128 + 0x38]  ! vaddr
+       stx     %g0, [%sp + 2047 + 128 + 0x40]  ! filler
+       stx     %i0, [%sp + 2047 + 128 + 0x48]  ! paddr
+       call    %l0
+        add    %sp, (2047 + 128), %o0          ! argument array
+
+       /* Restore hard-coded globals. */
+       mov     %i3, %g6
+       mov     %i4, %g4
+
+       /* Wheee.... we are done. */
+       ret
+       restore
+
+       .align  8192
index 53b3b2771184a6a35ad9d98263b289ebd7765f6a..36ba6923fb871c3f3a31c95794a0381503fbe20b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.14.2.1 1999/08/19 01:11:18 davem Exp $
+/* $Id: misc.c,v 1.14.2.3 1999/10/27 00:22:26 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -10,6 +10,8 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
@@ -37,6 +39,11 @@ extern void (*prom_palette)(int);
 extern int serial_console;
 #endif
 
+#ifdef __SMP__
+extern void smp_capture(void);
+extern void smp_release(void);
+#endif
+
 /* Drop into the prom, with the chance to continue with the 'go'
  * prom command.
  */
@@ -44,26 +51,57 @@ void
 prom_cmdline(void)
 {
        unsigned long flags;
-    
+
+       __save_and_cli(flags);
+
 #ifdef CONFIG_SUN_CONSOLE
        if(!serial_console && prom_palette)
                prom_palette (1);
 #endif
-       __save_and_cli(flags);
+
+       /* We always arrive here via a serial interrupt.
+        * So in order for everything to work reliably, even
+        * on SMP, we need to drop the IRQ locks we hold.
+        */
+#ifdef __SMP__
+       hardirq_exit(smp_processor_id());
+       smp_capture();
+#else
+       local_irq_count--;
+#endif
+
        p1275_cmd ("enter", P1275_INOUT(0,0));
-       __restore_flags(flags);
+
+#ifdef __SMP__
+       smp_release();
+       hardirq_enter(smp_processor_id());
+       spin_unlock_wait(&global_irq_lock);
+#else
+       local_irq_count++;
+#endif
+
 #ifdef CONFIG_SUN_CONSOLE
        if(!serial_console && prom_palette)
                prom_palette (0);
 #endif
+
+       __restore_flags(flags);
 }
 
+#ifdef __SMP__
+extern void smp_promstop_others(void);
+#endif
+
 /* Drop into the prom, but completely terminate the program.
  * No chance of continuing.
  */
 void
 prom_halt(void)
 {
+#ifdef __SMP__
+       smp_promstop_others();
+       udelay(8000);
+#endif
 again:
        p1275_cmd ("exit", P1275_INOUT(0,0));
        goto again; /* PROM is out to get me -DaveM */
@@ -122,10 +160,10 @@ void prom_set_trap_table(unsigned long tba)
        p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
 }
 
-/* This is only used internally below. */
-static int prom_get_mmu_ihandle(void)
+int mmu_ihandle_cache = 0;
+
+int prom_get_mmu_ihandle(void)
 {
-       static int mmu_ihandle_cache = 0;
        int node, ret;
 
        if (mmu_ihandle_cache != 0)
@@ -165,7 +203,10 @@ long prom_itlb_load(unsigned long index,
                    unsigned long vaddr)
 {
        return p1275_cmd("call-method",
-                        (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)),
+                        (P1275_ARG(0, P1275_ARG_IN_STRING) |
+                         P1275_ARG(2, P1275_ARG_IN_64B) |
+                         P1275_ARG(3, P1275_ARG_IN_64B) |
+                         P1275_INOUT(5, 1)),
                         "SUNW,itlb-load",
                         prom_get_mmu_ihandle(),
                         /* And then our actual args are pushed backwards. */
@@ -179,7 +220,10 @@ long prom_dtlb_load(unsigned long index,
                    unsigned long vaddr)
 {
        return p1275_cmd("call-method",
-                        (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)),
+                        (P1275_ARG(0, P1275_ARG_IN_STRING) |
+                         P1275_ARG(2, P1275_ARG_IN_64B) |
+                         P1275_ARG(3, P1275_ARG_IN_64B) |
+                         P1275_INOUT(5, 1)),
                         "SUNW,dtlb-load",
                         prom_get_mmu_ihandle(),
                         /* And then our actual args are pushed backwards. */
@@ -188,6 +232,41 @@ long prom_dtlb_load(unsigned long index,
                         index);
 }
 
+int prom_map(int mode, unsigned long size,
+            unsigned long vaddr, unsigned long paddr)
+{
+       int ret = p1275_cmd("call-method",
+                           (P1275_ARG(0, P1275_ARG_IN_STRING) |
+                            P1275_ARG(3, P1275_ARG_IN_64B) |
+                            P1275_ARG(4, P1275_ARG_IN_64B) |
+                            P1275_ARG(6, P1275_ARG_IN_64B) |
+                            P1275_INOUT(7, 1)),
+                           "map",
+                           prom_get_mmu_ihandle(),
+                           mode,
+                           size,
+                           vaddr,
+                           0,
+                           paddr);
+
+       if (ret == 0)
+               ret = -1;
+       return ret;
+}
+
+void prom_unmap(unsigned long size, unsigned long vaddr)
+{
+       p1275_cmd("call-method",
+                 (P1275_ARG(0, P1275_ARG_IN_STRING) |
+                  P1275_ARG(2, P1275_ARG_IN_64B) |
+                  P1275_ARG(3, P1275_ARG_IN_64B) |
+                  P1275_INOUT(4, 0)),
+                 "unmap",
+                 prom_get_mmu_ihandle(),
+                 size,
+                 vaddr);
+}
+
 /* Set aside physical memory which is not touched or modified
  * across soft resets.
  */
@@ -226,7 +305,7 @@ int prom_getunumber(int syndrome_code,
        return p1275_cmd("call-method",
                         (P1275_ARG(0, P1275_ARG_IN_STRING)     |
                          P1275_ARG(3, P1275_ARG_OUT_BUF)       |
-                         P1275_ARG(5, P1275_ARG_IN_64B)        |
+                         P1275_ARG(6, P1275_ARG_IN_64B)        |
                          P1275_INOUT(8, 2)),
                         "SUNW,get-unumber", prom_get_memory_ihandle(),
                         buflen, buf, P1275_SIZE(buflen),
index d0a4baa86bee8854559cb898ff2d2d482427335a..769826c715c7645029749a18d48b0d9d31cb9a8e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.15.2.1 1999/08/19 01:11:19 davem Exp $
+/* $Id: p1275.c,v 1.15.2.3 1999/10/27 00:22:27 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -253,9 +253,7 @@ void prom_cif_callback(void)
  */
 static int prom_entry_depth = 0;
 #ifdef __SMP__
-static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
-extern void smp_capture(void);
-extern void smp_release(void);
+spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
 #endif
 
 static __inline__ unsigned long prom_get_lock(void)
@@ -269,9 +267,6 @@ static __inline__ unsigned long prom_get_lock(void)
 #if 1 /* DEBUGGING */
                if (prom_entry_depth != 0)
                        panic("prom_get_lock");
-#endif
-#ifdef __SMP__
-               smp_capture();
 #endif
        }
        prom_entry_depth++;
@@ -281,12 +276,9 @@ static __inline__ unsigned long prom_get_lock(void)
 
 static __inline__ void prom_release_lock(unsigned long flags)
 {
-       if (--prom_entry_depth == 0) {
-#ifdef __SMP__
-               smp_release();
-#endif
+       if (--prom_entry_depth == 0)
                spin_unlock(&prom_entry_lock);
-       }
+
        __restore_flags(flags);
 }
 
index 3f43fc174f28bd200dbcce171c58237b19e72198..f71335e8e49668e6cf9dc8345006edb0b6ef7bc5 100644 (file)
@@ -1175,17 +1175,14 @@ static void ide_do_request (ide_hwgroup_t *hwgroup)
                                 * This gives other hwgroups on the same a chance to
                                 * play fairly with us, just in case there are big differences
                                 * in relative throughputs.. don't want to hog the cpu too much.
-                                *
-                                * Mmmm.. note we also do hwgroup->busy=0 below, which means
-                                * we will also be woken up if somebody enqueues another
-                                * request against this hwgroup while we're snoozing.
-                                * We could "fix" that by setting hwgroup->busy=1 instead,
-                                * but that would make the error handling more complicated
-                                * in ide_timer_expiry() -- this is good enough for now.
                                 */
                                if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
                                        sleep = jiffies + WAIT_MIN_SLEEP;
                                hwgroup->sleeping = 1;  /* so that ide_timer_expiry knows what to do */
+#if 1  /* paranoia */
+                               if (hwgroup->timer.next || hwgroup->timer.prev)
+                                       printk("ide_set_handler: timer was already active\n");
+#endif
                                mod_timer(&hwgroup->timer, sleep);
                                /* we purposely leave hwgroup->busy==1 while sleeping */
                        } else {
@@ -1419,12 +1416,16 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
                         */
                        (void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);
                        unexpected_intr(irq, hwgroup);
-               } else {
+               } 
+#ifdef CONFIG_BLK_DEV_IDEPCI           
+               else 
+               {
                        /*
                         * Whack the status register, just in case we have a leftover pending IRQ.
                         */
                        (void)IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
                }
+#endif         
                spin_unlock_irqrestore(&io_request_lock, flags);
                return;
        }
index a89b0e9c5e1f08ec03ee57564dcfbeede34d26d0..cd69c86319f35e11d03d3bb0a273a55f339359cb 100644 (file)
@@ -97,6 +97,10 @@ static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
                                return 0;
                        ns87415_prepare_drive(drive, 0);        /* DMA failed: select PIO xfer */
                        return 1;
+               case ide_dma_check:
+                       if (drive->media != ide_disk)
+                               return ide_dmaproc(ide_dma_off_quietly, drive);
+                       /* Fallthrough... */
                default:
                        return ide_dmaproc(func, drive);        /* use standard DMA stuff */
        }
index a9bef35f7753322c738fc6b9bda6be39f7901461..416fc036a825f05a84796637b1ec9d351f30981f 100644 (file)
@@ -433,7 +433,7 @@ static unsigned char handle_kbd_event(void)
                                handle_scancode(scancode, !(scancode & 0x80));
                        mark_bh(KEYBOARD_BH);
                }
-
+               mdelay(1);
                status = kbd_read_status();
                
                if(!work--)
index c8d6ab020bdf3da8f62f1d4c9f9e825912afe4b0..64422d49690f42f66493c709e7f385213ed0c367 100644 (file)
@@ -2,77 +2,78 @@
 # ISDN device configuration
 #
 if [ "$CONFIG_INET" != "n" ]; then
-  bool 'Support synchronous PPP' CONFIG_ISDN_PPP
-  if [ "$CONFIG_ISDN_PPP" != "n" ]; then
-    bool 'Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
-    bool 'Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
-  fi
+   bool '  Support synchronous PPP' CONFIG_ISDN_PPP
+   if [ "$CONFIG_ISDN_PPP" != "n" ]; then
+      bool '    Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
+      bool '    Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
+   fi
 fi
-bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
+bool '  Support audio via ISDN' CONFIG_ISDN_AUDIO
 if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
-  bool 'Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
+   bool '    Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
 fi
-bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
+bool '  Support isdn diversion services' CONFIG_ISDN_DIVERSION
 if [ "$CONFIG_X25" != "n" ]; then
-  bool 'X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25
+   bool '  X.25 PLP on top of ISDN' CONFIG_ISDN_X25
 fi
-dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
-dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
-dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+dep_tristate '  ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate '  isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
+dep_tristate '  PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
+dep_tristate '  HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
-    bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
-    if [ "$CONFIG_HISAX_EURO" != "n" ]; then
-           bool 'Support for german chargeinfo' CONFIG_DE_AOC
-           bool 'Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
-           bool 'Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
-    fi
-    bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
-    bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
-    bool 'HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
-    bool 'HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI 
-    bool 'HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX 
-    bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
-    bool 'HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
-    bool 'HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
-    bool 'HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
-    bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
-    bool 'HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
-    bool 'HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
-    bool 'HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
-    bool 'HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
-    bool 'HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
-    bool 'HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
-    bool 'HiSax Support for MIC card' CONFIG_HISAX_MIC
-    bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET
-    bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
-    bool 'HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
-    bool 'HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
-    bool 'HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
-    bool 'HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
-    bool 'HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
-    bool 'HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
-    if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-        bool 'HiSax Support for Winbond W6692 based cards (EXPERIMENTAL)' CONFIG_HISAX_W6692
-#      bool 'HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
-       if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
-               bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
-       fi
-    fi
+   bool '    HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+   if [ "$CONFIG_HISAX_EURO" != "n" ]; then
+      bool '      Support for german chargeinfo' CONFIG_DE_AOC
+      bool '      Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
+      bool '      Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
+   fi
+   bool '    HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+   bool '    HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
+   bool '    HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+   bool '    HiSax Support for Teles PCI' CONFIG_HISAX_TELESPCI 
+   bool '    HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX 
+   bool '    HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+   bool '    HiSax Support for AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
+   bool '    HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
+   bool '    HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
+   bool '    HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+   bool '    HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
+   bool '    HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
+   bool '    HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
+   bool '    HiSax Support for HFC-S based cards' CONFIG_HISAX_HFCS
+   bool '    HiSax Support for Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
+   bool '    HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+   bool '    HiSax Support for MIC card' CONFIG_HISAX_MIC
+   bool '    HiSax Support for NETjet card' CONFIG_HISAX_NETJET
+   bool '    HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
+   bool '    HiSax Support for Siemens I-Surf card' CONFIG_HISAX_ISURF
+   bool '    HiSax Support for HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+   bool '    HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T
+   bool '    HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
+   bool '    HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL
+   bool '    HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
+   bool '    HiSax Support for Winbond W6692 based cards' CONFIG_HISAX_W6692
+   if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+#      bool '    HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+      if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+        bool '    HiSax Support for Am7930' CONFIG_HISAX_AMD7930
+      fi
+   fi
 fi
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-       dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
-       dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
+   dep_tristate '  Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+   dep_tristate '  IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
 fi
-dep_tristate 'Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+dep_tristate '  Eicon.Diehl active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
-    bool 'Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+   bool '    Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
 fi
-dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
+dep_tristate '  AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
-    bool 'AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
-    bool 'AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
-    bool 'AVM T1/T1B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
-    bool 'AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-    bool 'Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+   bool '    AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
+   bool '    AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
+   bool '    AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
+   bool '    AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+   bool '    AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
+   bool '    Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
 fi
index 3b256dcee698d61e726f6b91efa7d7f2cfa451c0..1be45734f8e291d526a247bd40438955afac9cdb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.c,v 1.9 1999/09/04 06:20:04 keil Exp $
+/* $Id: act2000_isa.c,v 1.10 1999/10/24 18:46:05 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: act2000_isa.c,v $
+ * Revision 1.10  1999/10/24 18:46:05  fritz
+ * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
+ * kernels.
+ *
  * Revision 1.9  1999/09/04 06:20:04  keil
  * Changes from kernel set_current_state()
  *
@@ -64,14 +68,14 @@ static act2000_card *irq2card_map[16] =
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
-static int isa_irqs[] =
+static int act2000_isa_irqs[] =
 {
         3, 5, 7, 10, 11, 12, 15
 };
-#define ISA_NRIRQS (sizeof(isa_irqs)/sizeof(int))
+#define ISA_NRIRQS (sizeof(act2000_isa_irqs)/sizeof(int))
 
 static void
-isa_delay(long t)
+act2000_isa_delay(long t)
 {
         sti();
         current->state = TASK_INTERRUPTIBLE;
@@ -86,7 +90,7 @@ isa_delay(long t)
  *   0 = Signature not found.
  */
 static int
-isa_reset(unsigned short portbase)
+act2000_isa_reset(unsigned short portbase)
 {
         unsigned char reg;
         int i;
@@ -112,7 +116,7 @@ isa_reset(unsigned short portbase)
 }
 
 int
-isa_detect(unsigned short portbase)
+act2000_isa_detect(unsigned short portbase)
 {
         int ret = 0;
         unsigned long flags;
@@ -120,13 +124,13 @@ isa_detect(unsigned short portbase)
         save_flags(flags);
         cli();
         if (!check_region(portbase, ISA_REGION))
-                ret = isa_reset(portbase);
+                ret = act2000_isa_reset(portbase);
         restore_flags(flags);
         return ret;
 }
 
 static void
-isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
         act2000_card *card = irq2card_map[irq];
         u_char istatus;
@@ -141,7 +145,7 @@ isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                 /* RX fifo has data */
                istatus &= ISA_ISR_OUT_MASK;
                outb(0, ISA_PORT_SIS);
-               isa_receive(card);
+               act2000_isa_receive(card);
                outb(ISA_SIS_INT, ISA_PORT_SIS);
         }
         if (istatus & ISA_ISR_ERR) {
@@ -154,7 +158,7 @@ isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 }
 
 static void
-isa_select_irq(act2000_card * card)
+act2000_isa_select_irq(act2000_card * card)
 {
        unsigned char reg;
 
@@ -186,9 +190,9 @@ isa_select_irq(act2000_card * card)
 }
 
 static void
-isa_enable_irq(act2000_card * card)
+act2000_isa_enable_irq(act2000_card * card)
 {
-       isa_select_irq(card);
+       act2000_isa_select_irq(card);
        /* Enable READ irq */
        outb(ISA_SIS_INT, ISA_PORT_SIS);
 }
@@ -198,7 +202,7 @@ isa_enable_irq(act2000_card * card)
  * If irq is -1, choose next free irq, else irq is given explicitely.
  */
 int
-isa_config_irq(act2000_card * card, short irq)
+act2000_isa_config_irq(act2000_card * card, short irq)
 {
         int i;
         unsigned long flags;
@@ -216,8 +220,8 @@ isa_config_irq(act2000_card * card, short irq)
         if (irq == -1) {
                 /* Auto select */
                 for (i = 0; i < ISA_NRIRQS; i++) {
-                        if (!request_irq(isa_irqs[i], &isa_interrupt, 0, card->regname, NULL)) {
-                                card->irq = isa_irqs[i];
+                        if (!request_irq(act2000_isa_irqs[i], &act2000_isa_interrupt, 0, card->regname, NULL)) {
+                                card->irq = act2000_isa_irqs[i];
                                 irq2card_map[card->irq] = card;
                                 card->flags |= ACT2000_FLAGS_IVALID;
                                 break;
@@ -225,7 +229,7 @@ isa_config_irq(act2000_card * card, short irq)
                 }
         } else {
                 /* Fixed irq */
-                if (!request_irq(irq, &isa_interrupt, 0, card->regname, NULL)) {
+                if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) {
                         card->irq = irq;
                         irq2card_map[card->irq] = card;
                        card->flags |= ACT2000_FLAGS_IVALID;
@@ -237,7 +241,7 @@ isa_config_irq(act2000_card * card, short irq)
                        "act2000: Could not request irq\n");
                 return -EBUSY;
         } else {
-               isa_select_irq(card);
+               act2000_isa_select_irq(card);
                 /* Disable READ and WRITE irq */
                 outb(0, ISA_PORT_SIS);
                 outb(0, ISA_PORT_SOS);
@@ -246,7 +250,7 @@ isa_config_irq(act2000_card * card, short irq)
 }
 
 int
-isa_config_port(act2000_card * card, unsigned short portbase)
+act2000_isa_config_port(act2000_card * card, unsigned short portbase)
 {
         if (card->flags & ACT2000_FLAGS_PVALID) {
                 release_region(card->port, ISA_REGION);
@@ -265,7 +269,7 @@ isa_config_port(act2000_card * card, unsigned short portbase)
  * Release ressources, used by an adaptor.
  */
 void
-isa_release(act2000_card * card)
+act2000_isa_release(act2000_card * card)
 {
         unsigned long flags;
 
@@ -283,7 +287,7 @@ isa_release(act2000_card * card)
 }
 
 static int
-isa_writeb(act2000_card * card, u_char data)
+act2000_isa_writeb(act2000_card * card, u_char data)
 {
         u_char timeout = 40;
 
@@ -300,7 +304,7 @@ isa_writeb(act2000_card * card, u_char data)
 }
 
 static int
-isa_readb(act2000_card * card, u_char * data)
+act2000_isa_readb(act2000_card * card, u_char * data)
 {
         u_char timeout = 40;
 
@@ -317,13 +321,13 @@ isa_readb(act2000_card * card, u_char * data)
 }
 
 void
-isa_receive(act2000_card *card)
+act2000_isa_receive(act2000_card *card)
 {
        u_char c;
 
         if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
                return;
-       while (!isa_readb(card, &c)) {
+       while (!act2000_isa_readb(card, &c)) {
                if (card->idat.isa.rcvidx < 8) {
                         card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
                        if (card->idat.isa.rcvidx == 8) {
@@ -335,7 +339,7 @@ isa_receive(act2000_card *card)
                                        if (card->idat.isa.rcvskb == NULL) {
                                                card->idat.isa.rcvignore = 1;
                                                printk(KERN_WARNING
-                                                      "isa_receive: no memory\n");
+                                                      "act2000_isa_receive: no memory\n");
                                                test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
                                                return;
                                        }
@@ -344,12 +348,12 @@ isa_receive(act2000_card *card)
                                } else {
                                        card->idat.isa.rcvidx = 0;
                                        printk(KERN_WARNING
-                                              "isa_receive: Invalid CAPI msg\n");
+                                              "act2000_isa_receive: Invalid CAPI msg\n");
                                        {
                                                int i; __u8 *p; __u8 *c; __u8 tmp[30];
                                                for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
                                                        c += sprintf(c, "%02x ", *(p++));
-                                               printk(KERN_WARNING "isa_receive: %s\n", tmp);
+                                               printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
                                        }
                                }
                        }
@@ -380,7 +384,7 @@ isa_receive(act2000_card *card)
 }
 
 void
-isa_send(act2000_card * card)
+act2000_isa_send(act2000_card * card)
 {
        unsigned long flags;
        struct sk_buff *skb;
@@ -413,7 +417,7 @@ isa_send(act2000_card * card)
                skb = card->sbuf;
                l = 0;
                while (skb->len) {
-                       if (isa_writeb(card, *(skb->data))) {
+                       if (act2000_isa_writeb(card, *(skb->data))) {
                                /* Fifo is full, but more data to send */
                                test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
                                /* Schedule myself */
@@ -444,7 +448,7 @@ isa_send(act2000_card * card)
  * Get firmware ID, check for 'ISDN' signature.
  */
 static int
-isa_getid(act2000_card * card)
+act2000_isa_getid(act2000_card * card)
 {
 
         act2000_fwid fid;
@@ -454,7 +458,7 @@ isa_getid(act2000_card * card)
         while (1) {
                 if (count > 510)
                         return -EPROTO;
-                if (isa_readb(card, p++))
+                if (act2000_isa_readb(card, p++))
                         break;
                 count++;
         }
@@ -473,7 +477,7 @@ isa_getid(act2000_card * card)
         printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
        if (card->flags & ACT2000_FLAGS_IVALID) {
                printk(KERN_DEBUG "Enabling Interrupts ...\n");
-               isa_enable_irq(card);
+               act2000_isa_enable_irq(card);
        }
         return 0;
 }
@@ -482,7 +486,7 @@ isa_getid(act2000_card * card)
  * Download microcode into card, check Firmware signature.
  */
 int
-isa_download(act2000_card * card, act2000_ddef * cb)
+act2000_isa_download(act2000_card * card, act2000_ddef * cb)
 {
         int length;
         int ret;
@@ -494,9 +498,9 @@ isa_download(act2000_card * card, act2000_ddef * cb)
         u_char *buf;
         act2000_ddef cblock;
 
-        if (!isa_reset(card->port))
+        if (!act2000_isa_reset(card->port))
                 return -ENXIO;
-        isa_delay(HZ / 2);
+        act2000_isa_delay(HZ / 2);
         if ((ret = verify_area(VERIFY_READ, (void *) cb, sizeof(cblock))))
                 return ret;
         copy_from_user(&cblock, (char *) cb, sizeof(cblock));
@@ -514,7 +518,7 @@ isa_download(act2000_card * card, act2000_ddef * cb)
                 b = buf;
                 copy_from_user(buf, p, l);
                 while (c < l) {
-                        if (isa_writeb(card, *b++)) {
+                        if (act2000_isa_writeb(card, *b++)) {
                                 printk(KERN_WARNING
                                        "act2000: loader timed out"
                                        " len=%d c=%d\n", length, c);
@@ -527,6 +531,6 @@ isa_download(act2000_card * card, act2000_ddef * cb)
                 p += l;
         }
         kfree(buf);
-        isa_delay(HZ / 2);
-        return (isa_getid(card));
+        act2000_isa_delay(HZ / 2);
+        return (act2000_isa_getid(card));
 }
index 35a68e7d2ca04092f1edb49c51c077feca9bc10d..ff3e5419aeb7f3f3fb4ac0c2c84ab8c4a4ef926d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.h,v 1.2 1998/11/05 22:12:43 fritz Exp $
+/* $Id: act2000_isa.h,v 1.3 1999/10/24 18:46:05 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: act2000_isa.h,v $
+ * Revision 1.3  1999/10/24 18:46:05  fritz
+ * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
+ * kernels.
+ *
  * Revision 1.2  1998/11/05 22:12:43  fritz
  * Changed mail-address.
  *
@@ -141,12 +145,12 @@ typedef enum {
 
 /* Prototypes */
 
-extern int isa_detect(unsigned short portbase);
-extern int isa_config_irq(act2000_card * card, short irq);
-extern int isa_config_port(act2000_card * card, unsigned short portbase);
-extern int isa_download(act2000_card * card, act2000_ddef * cb);
-extern void isa_release(act2000_card * card);
-extern void isa_receive(act2000_card *card);
-extern void isa_send(act2000_card *card);
+extern int act2000_isa_detect(unsigned short portbase);
+extern int act2000_isa_config_irq(act2000_card * card, short irq);
+extern int act2000_isa_config_port(act2000_card * card, unsigned short portbase);
+extern int act2000_isa_download(act2000_card * card, act2000_ddef * cb);
+extern void act2000_isa_release(act2000_card * card);
+extern void act2000_isa_receive(act2000_card *card);
+extern void act2000_isa_send(act2000_card *card);
 
 #endif                          /* act2000_isa_h */
index 8304e63cbc38ffd972600ca72ddc85512c7d9664..f152792532ad88a274da22bc8ca3d514dc794c64 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: module.c,v 1.9 1999/04/12 13:13:56 fritz Exp $
+/* $Id: module.c,v 1.11 1999/10/30 09:48:04 keil Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: module.c,v $
+ * Revision 1.11  1999/10/30 09:48:04  keil
+ * miss one prefix act2000
+ *
+ * Revision 1.10  1999/10/24 18:46:05  fritz
+ * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
+ * kernels.
+ *
  * Revision 1.9  1999/04/12 13:13:56  fritz
  * Made cards pointer static to avoid name-clash.
  *
 #include "act2000_isa.h"
 #include "capi.h"
 
-static unsigned short isa_ports[] =
+static unsigned short act2000_isa_ports[] =
 {
         0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
         0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
 };
-#define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short))
+#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short))
 
 static act2000_card *cards = (act2000_card *) NULL;
 
@@ -238,7 +245,7 @@ act2000_transmit(struct act2000_card *card)
 {
        switch (card->bus) {
                case ACT2000_BUS_ISA:
-                       isa_send(card);
+                       act2000_isa_send(card);
                        break;
                case ACT2000_BUS_PCMCIA:
                case ACT2000_BUS_MCA:
@@ -253,7 +260,7 @@ act2000_receive(struct act2000_card *card)
 {
        switch (card->bus) {
                case ACT2000_BUS_ISA:
-                       isa_receive(card);
+                       act2000_isa_receive(card);
                        break;
                case ACT2000_BUS_PCMCIA:
                case ACT2000_BUS_MCA:
@@ -296,7 +303,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c)
                                case ACT2000_IOCTL_LOADBOOT:
                                        switch (card->bus) {
                                                case ACT2000_BUS_ISA:
-                                                       ret = isa_download(card,
+                                                       ret = act2000_isa_download(card,
                                                                           (act2000_ddef *)a);
                                                        if (!ret) {
                                                                card->flags |= ACT2000_FLAGS_LOADED;
@@ -758,7 +765,7 @@ unregister_card(act2000_card * card)
         card->interface.statcallb(&cmd);
         switch (card->bus) {
                case ACT2000_BUS_ISA:
-                       isa_release(card);
+                       act2000_isa_release(card);
                        break;
                case ACT2000_BUS_MCA:
                case ACT2000_BUS_PCMCIA:
@@ -792,11 +799,11 @@ act2000_addcard(int bus, int port, int irq, char *id)
                switch (bus) {
                        case ACT2000_BUS_ISA:
                                for (i = 0; i < ISA_NRPORTS; i++)
-                                       if (isa_detect(isa_ports[i])) {
+                                       if (act2000_isa_detect(act2000_isa_ports[i])) {
                                                printk(KERN_INFO
                                                       "act2000: Detected ISA card at port 0x%x\n",
-                                                      isa_ports[i]);
-                                               act2000_alloccard(bus, isa_ports[i], irq, id);
+                                                      act2000_isa_ports[i]);
+                                               act2000_alloccard(bus, act2000_isa_ports[i], irq, id);
                                        }
                                break;
                        case ACT2000_BUS_MCA:
@@ -819,10 +826,10 @@ act2000_addcard(int bus, int port, int irq, char *id)
                        added++;
                        switch (p->bus) {
                                case ACT2000_BUS_ISA:
-                                       if (isa_detect(p->port)) {
+                                       if (act2000_isa_detect(p->port)) {
                                                if (act2000_registercard(p))
                                                        break;
-                                               if (isa_config_port(p, p->port)) {
+                                               if (act2000_isa_config_port(p, p->port)) {
                                                        printk(KERN_WARNING
                                                               "act2000: Could not request port 0x%04x\n",
                                                               p->port);
@@ -830,7 +837,7 @@ act2000_addcard(int bus, int port, int irq, char *id)
                                                        p->interface.statcallb = NULL;
                                                        break;
                                                }
-                                               if (isa_config_irq(p, p->irq)) {
+                                               if (act2000_isa_config_irq(p, p->irq)) {
                                                        printk(KERN_INFO
                                                               "act2000: No IRQ available, fallback to polling\n");
                                                        /* Fall back to polled operation */
index 588546a304a5edadfc6bda1a6714879de98c751d..f4b5df6891194afdf72df6402317001633862e1b 100644 (file)
@@ -1,9 +1,16 @@
 /*
- * $Id: avmcard.h,v 1.5 1999/09/07 09:02:53 calle Exp $
+ * $Id: avmcard.h,v 1.6 1999/11/05 16:38:01 calle Exp $
  *
  * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: avmcard.h,v $
+ * Revision 1.6  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
  * Revision 1.5  1999/09/07 09:02:53  calle
  * SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
  * DATA_B3_IND is always directly after the CAPI message. The "Data" member
@@ -78,6 +85,7 @@ typedef struct avmcard_dmainfo {
        __u8  sendbuf[128+2048];
 } avmcard_dmainfo;
 
+
 typedef struct avmcard {
        char name[32];
        unsigned int port;
@@ -86,13 +94,6 @@ typedef struct avmcard {
        enum avmcardtype cardtype;
        int cardnr; /* for t1isa */
 
-       int versionlen;
-       char versionbuf[1024];
-       char *version[AVM_MAXVERSION];
-
-       char cardname[32];
-
-       char infobuf[128];      /* for function procinfo */
        char msgbuf[128];       /* capimsg msg part */
        char databuf[2048];     /* capimsg data part */
 
@@ -102,9 +103,25 @@ typedef struct avmcard {
        volatile __u32 csr;
        avmcard_dmainfo *dma;
 
-       struct capi_ctr *ctrl;
+       struct avmctrl_info {
+               char cardname[32];
+
+               int versionlen;
+               char versionbuf[1024];
+               char *version[AVM_MAXVERSION];
+
+               char infobuf[128];      /* for function procinfo */
+
+               struct avmcard  *card;
+               struct capi_ctr *capi_ctrl;
+
+       } *ctrlinfo;
+
+       int nlogcontr;
 } avmcard;
 
+typedef struct avmctrl_info avmctrl_info;
+
 extern int b1_irq_table[16];
 
 /*
@@ -545,16 +562,16 @@ static inline void b1_setinterrupt(unsigned int base, unsigned irq,
 }
 
 int b1_detect(unsigned int base, enum avmcardtype cardtype);
-int b1_load_t4file(unsigned int base, capiloaddatapart * t4file);
-int b1_load_config(unsigned int base, capiloaddatapart * config);
-int b1_loaded(unsigned int base);
+int b1_load_t4file(avmcard *card, capiloaddatapart * t4file);
+int b1_load_config(avmcard *card, capiloaddatapart * config);
+int b1_loaded(avmcard *card);
 int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
 void b1_reset_ctr(struct capi_ctr *ctrl);
 void b1_register_appl(struct capi_ctr *ctrl, __u16 appl,
                                capi_register_params *rp);
 void b1_release_appl(struct capi_ctr *ctrl, __u16 appl);
 void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
-void b1_parse_version(avmcard *card);
+void b1_parse_version(avmctrl_info *card);
 void b1_handle_interrupt(avmcard * card);
 
 int b1ctl_read_proc(char *page, char **start, off_t off,
index 85206685c9be918e97fe46b55c51ae39cf79e21e..900b31c8c1632a0475ae0199482dcaab2f5b4020 100644 (file)
@@ -1,11 +1,21 @@
 /*
- * $Id: b1.c,v 1.10 1999/09/15 08:16:03 calle Exp $
+ * $Id: b1.c,v 1.12 1999/11/05 16:38:01 calle Exp $
  * 
  * Common module for AVM B1 cards.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1.c,v $
+ * Revision 1.12  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
+ * Revision 1.11  1999/10/11 22:04:12  keil
+ * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
+ *
  * Revision 1.10  1999/09/15 08:16:03  calle
  * Implementation of 64Bit extention complete.
  *
@@ -76,7 +86,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.12 $";
 
 /* ------------------------------------------------------------- */
 
@@ -148,11 +158,12 @@ int b1_detect(unsigned int base, enum avmcardtype cardtype)
        return 0;
 }
 
-int b1_load_t4file(unsigned int base, capiloaddatapart * t4file)
+int b1_load_t4file(avmcard *card, capiloaddatapart * t4file)
 {
        unsigned char buf[256];
        unsigned char *dp;
        int i, left, retval;
+       unsigned int base = card->port;
 
        dp = t4file->data;
        left = t4file->len;
@@ -166,7 +177,8 @@ int b1_load_t4file(unsigned int base, capiloaddatapart * t4file)
                }
                for (i = 0; i < sizeof(buf); i++)
                        if (b1_save_put_byte(base, buf[i]) < 0) {
-                               printk(KERN_ERR "b1_load_t4file: corrupted t4 file ?\n");
+                               printk(KERN_ERR "%s: corrupted firmware file ?\n",
+                                               card->name);
                                return -EIO;
                        }
                left -= sizeof(buf);
@@ -182,17 +194,19 @@ int b1_load_t4file(unsigned int base, capiloaddatapart * t4file)
                }
                for (i = 0; i < left; i++)
                        if (b1_save_put_byte(base, buf[i]) < 0) {
-                               printk(KERN_ERR "b1_load_t4file: corrupted t4 file ?\n");
+                               printk(KERN_ERR "%s: corrupted firmware file ?\n",
+                                               card->name);
                                return -EIO;
                        }
        }
        return 0;
 }
 
-int b1_load_config(unsigned int base, capiloaddatapart * config)
+int b1_load_config(avmcard *card, capiloaddatapart * config)
 {
        unsigned char buf[256];
        unsigned char *dp;
+       unsigned int base = card->port;
        int i, j, left, retval;
 
        dp = config->data;
@@ -241,8 +255,9 @@ int b1_load_config(unsigned int base, capiloaddatapart * config)
        return 0;
 }
 
-int b1_loaded(unsigned int base)
+int b1_loaded(avmcard *card)
 {
+       unsigned int base = card->port;
        unsigned long stop;
        unsigned char ans;
        unsigned long tout = 2;
@@ -252,7 +267,8 @@ int b1_loaded(unsigned int base)
                        break;
        }
        if (!b1_tx_empty(base)) {
-               printk(KERN_ERR "b1_loaded: tx err, corrupted t4 file ?\n");
+               printk(KERN_ERR "%s: b1_loaded: tx err, corrupted t4 file ?\n",
+                               card->name);
                return 0;
        }
        b1_put_byte(base, SEND_POLL);
@@ -261,11 +277,12 @@ int b1_loaded(unsigned int base)
                        if ((ans = b1_get_byte(base)) == RECEIVE_POLL) {
                                return 1;
                        }
-                       printk(KERN_ERR "b1_loaded: got 0x%x, firmware not running\n", ans);
+                       printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n",
+                                       card->name, ans);
                        return 0;
                }
        }
-       printk(KERN_ERR "b1_loaded: firmware not running\n");
+       printk(KERN_ERR "%s: b1_loaded: firmware not running\n", card->name);
        return 0;
 }
 
@@ -273,14 +290,15 @@ int b1_loaded(unsigned int base)
 
 int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
        unsigned long flags;
        int retval;
 
        b1_reset(port);
 
-       if ((retval = b1_load_t4file(port, &data->firmware))) {
+       if ((retval = b1_load_t4file(card, &data->firmware))) {
                b1_reset(port);
                printk(KERN_ERR "%s: failed to load t4file!!\n",
                                        card->name);
@@ -290,7 +308,7 @@ int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
        b1_disable_irq(port);
 
        if (data->configuration.len > 0 && data->configuration.data) {
-               if ((retval = b1_load_config(port, &data->configuration))) {
+               if ((retval = b1_load_config(card, &data->configuration))) {
                        b1_reset(port);
                        printk(KERN_ERR "%s: failed to load config!!\n",
                                        card->name);
@@ -298,7 +316,7 @@ int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
                }
        }
 
-       if (!b1_loaded(port)) {
+       if (!b1_loaded(card)) {
                printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
                return -EIO;
        }
@@ -317,13 +335,14 @@ int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 
 void b1_reset_ctr(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
 
        b1_reset(port);
        b1_reset(port);
 
-       memset(card->version, 0, sizeof(card->version));
+       memset(cinfo->version, 0, sizeof(cinfo->version));
        ctrl->reseted(ctrl);
 }
 
@@ -331,7 +350,8 @@ void b1_register_appl(struct capi_ctr *ctrl,
                                __u16 appl,
                                capi_register_params *rp)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
        unsigned long flags;
        int nconn, want = rp->level3cnt;
@@ -355,7 +375,8 @@ void b1_register_appl(struct capi_ctr *ctrl,
 
 void b1_release_appl(struct capi_ctr *ctrl, __u16 appl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
        unsigned long flags;
 
@@ -368,7 +389,8 @@ void b1_release_appl(struct capi_ctr *ctrl, __u16 appl)
 
 void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
        unsigned long flags;
        __u16 len = CAPIMSG_LEN(skb->data);
@@ -392,25 +414,26 @@ void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 
 /* ------------------------------------------------------------- */
 
-void b1_parse_version(avmcard *card)
+void b1_parse_version(avmctrl_info *cinfo)
 {
-       struct capi_ctr *ctrl = card->ctrl;
+       struct capi_ctr *ctrl = cinfo->capi_ctrl;
+       avmcard *card = cinfo->card;
        capi_profile *profp;
        __u8 *dversion;
        __u8 flag;
        int i, j;
 
        for (j = 0; j < AVM_MAXVERSION; j++)
-               card->version[j] = "\0\0" + 1;
+               cinfo->version[j] = "\0\0" + 1;
        for (i = 0, j = 0;
-            j < AVM_MAXVERSION && i < card->versionlen;
-            j++, i += card->versionbuf[i] + 1)
-               card->version[j] = &card->versionbuf[i + 1];
+            j < AVM_MAXVERSION && i < cinfo->versionlen;
+            j++, i += cinfo->versionbuf[i] + 1)
+               cinfo->version[j] = &cinfo->versionbuf[i + 1];
 
-       strncpy(ctrl->serial, card->version[VER_SERIAL], CAPI_SERIAL_LEN);
-       memcpy(&ctrl->profile, card->version[VER_PROFILE],sizeof(capi_profile));
+       strncpy(ctrl->serial, cinfo->version[VER_SERIAL], CAPI_SERIAL_LEN);
+       memcpy(&ctrl->profile, cinfo->version[VER_PROFILE],sizeof(capi_profile));
        strncpy(ctrl->manu, "AVM GmbH", CAPI_MANUFACTURER_LEN);
-       dversion = card->version[VER_DRIVER];
+       dversion = cinfo->version[VER_DRIVER];
        ctrl->version.majorversion = 2;
        ctrl->version.minorversion = 0;
        ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
@@ -423,23 +446,24 @@ void b1_parse_version(avmcard *card)
 
        flag = ((__u8 *)(profp->manu))[1];
        switch (flag) {
-       case 0: if (card->version[VER_CARDTYPE])
-                  strcpy(card->cardname, card->version[VER_CARDTYPE]);
-               else strcpy(card->cardname, "B1");
+       case 0: if (cinfo->version[VER_CARDTYPE])
+                  strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]);
+               else strcpy(cinfo->cardname, "B1");
                break;
-       case 3: strcpy(card->cardname,"PCMCIA B"); break;
-       case 4: strcpy(card->cardname,"PCMCIA M1"); break;
-       case 5: strcpy(card->cardname,"PCMCIA M2"); break;
-       case 6: strcpy(card->cardname,"B1 V3.0"); break;
-       case 7: strcpy(card->cardname,"B1 PCI"); break;
-       default: sprintf(card->cardname, "AVM?%u", (unsigned int)flag); break;
+       case 3: strcpy(cinfo->cardname,"PCMCIA B"); break;
+       case 4: strcpy(cinfo->cardname,"PCMCIA M1"); break;
+       case 5: strcpy(cinfo->cardname,"PCMCIA M2"); break;
+       case 6: strcpy(cinfo->cardname,"B1 V3.0"); break;
+       case 7: strcpy(cinfo->cardname,"B1 PCI"); break;
+       default: sprintf(cinfo->cardname, "AVM?%u", (unsigned int)flag); break;
         }
         printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n",
-                               card->name, ctrl->cnr, card->cardname);
+                               card->name, ctrl->cnr, cinfo->cardname);
 
         flag = ((__u8 *)(profp->manu))[3];
         if (flag)
-               printk(KERN_NOTICE "b1capi: card %d Protocol:%s%s%s%s%s%s%s\n",
+               printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n",
+                       card->name,
                        ctrl->cnr,
                        (flag & 0x01) ? " DSS1" : "",
                        (flag & 0x02) ? " CT1" : "",
@@ -466,7 +490,8 @@ void b1_parse_version(avmcard *card)
 
 void b1_handle_interrupt(avmcard * card)
 {
-       struct capi_ctr *ctrl = card->ctrl;
+       avmctrl_info *cinfo = &card->ctrlinfo[0];
+       struct capi_ctr *ctrl = cinfo->capi_ctrl;
        unsigned char b1cmd;
        struct sk_buff *skb;
 
@@ -548,12 +573,12 @@ void b1_handle_interrupt(avmcard * card)
 
        case RECEIVE_INIT:
 
-               card->versionlen = b1_get_slice(card->port, card->versionbuf);
-               b1_parse_version(card);
+               cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf);
+               b1_parse_version(cinfo);
                printk(KERN_INFO "%s: %s-card (%s) now active\n",
                       card->name,
-                      card->version[VER_CARDTYPE],
-                      card->version[VER_DRIVER]);
+                      cinfo->version[VER_CARDTYPE],
+                      cinfo->version[VER_DRIVER]);
                ctrl->ready(ctrl);
                break;
 
@@ -593,7 +618,8 @@ void b1_handle_interrupt(avmcard * card)
 int b1ctl_read_proc(char *page, char **start, off_t off,
                        int count, int *eof, struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        __u8 flag;
        int len = 0;
        char *s;
@@ -615,11 +641,11 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
        len += sprintf(page+len, "%-16s %s\n", "type", s);
        if (card->cardtype == avm_t1isa)
           len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
-       if ((s = card->version[VER_DRIVER]) != 0)
+       if ((s = cinfo->version[VER_DRIVER]) != 0)
           len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
-       if ((s = card->version[VER_CARDTYPE]) != 0)
+       if ((s = cinfo->version[VER_CARDTYPE]) != 0)
           len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
-       if ((s = card->version[VER_SERIAL]) != 0)
+       if ((s = cinfo->version[VER_SERIAL]) != 0)
           len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
 
        if (card->cardtype != avm_m1) {
@@ -647,7 +673,7 @@ int b1ctl_read_proc(char *page, char **start, off_t off,
                        (flag & 0x04) ? " leased line with D-channel" : ""
                        );
        }
-       len += sprintf(page+len, "%-16s %s\n", "cardname", card->cardname);
+       len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
 
        if (off+count >= len)
           *eof = 1;
index 030dddac44e025a40010afd66602bc5d7de90fd0..01972b2d21df5a8dbaf3541cc7bec48428463b17 100644 (file)
@@ -1,11 +1,18 @@
 /*
- * $Id: b1isa.c,v 1.4 1999/08/22 20:26:24 calle Exp $
+ * $Id: b1isa.c,v 1.5 1999/11/05 16:38:01 calle Exp $
  * 
  * Module for AVM B1 ISA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1isa.c,v $
+ * Revision 1.5  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
  * Revision 1.4  1999/08/22 20:26:24  calle
  * backported changes from kernel 2.3.14:
  * - several #include "config.h" gone, others come.
@@ -54,7 +61,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.5 $";
 
 /* ------------------------------------------------------------- */
 
@@ -91,7 +98,8 @@ static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
 
 static void b1isa_remove_ctr(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
 
        b1_reset(port);
@@ -100,6 +108,7 @@ static void b1isa_remove_ctr(struct capi_ctr *ctrl)
        di->detach_ctr(ctrl);
        free_irq(card->irq, card);
        release_region(card->port, AVMB1_PORTLEN);
+       kfree(card->ctrlinfo);
        kfree(card);
 
        MOD_DEC_USE_COUNT;
@@ -109,6 +118,7 @@ static void b1isa_remove_ctr(struct capi_ctr *ctrl)
 
 static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
+       avmctrl_info *cinfo;
        avmcard *card;
        int retval;
 
@@ -119,6 +129,15 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
                return -ENOMEM;
        }
        memset(card, 0, sizeof(avmcard));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+       if (!cinfo) {
+               printk(KERN_WARNING "b1isa: no memory.\n");
+               kfree(card);
+               return -ENOMEM;
+       }
+       memset(cinfo, 0, sizeof(avmctrl_info));
+       card->ctrlinfo = cinfo;
+       cinfo->card = card;
        sprintf(card->name, "b1isa-%x", p->port);
        card->port = p->port;
        card->irq = p->irq;
@@ -128,17 +147,20 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
                printk(KERN_WARNING
                       "b1isa: ports 0x%03x-0x%03x in use.\n",
                       card->port, card->port + AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
        if (b1_irq_table[card->irq & 0xf] == 0) {
                printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EINVAL;
        }
        if (   card->port != 0x150 && card->port != 0x250
            && card->port != 0x300 && card->port != 0x340) {
                printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EINVAL;
        }
@@ -146,6 +168,7 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
        if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
                printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n",
                                        card->port, retval);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EIO;
        }
@@ -157,15 +180,17 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
        if (retval) {
                printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
                release_region(card->port, AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
 
-       card->ctrl = di->attach_ctr(driver, card->name, card);
-       if (!card->ctrl) {
+       cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+       if (!cinfo->capi_ctrl) {
                printk(KERN_ERR "b1isa: attach controller failed.\n");
                free_irq(card->irq, card);
                release_region(card->port, AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
@@ -176,15 +201,17 @@ static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
 
 static char *b1isa_procinfo(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
-       if (!card)
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+       if (!cinfo)
                return "";
-       sprintf(card->infobuf, "%s %s 0x%x %d",
-               card->cardname[0] ? card->cardname : "-",
-               card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
-               card->port, card->irq
+       sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+               cinfo->cardname[0] ? cinfo->cardname : "-",
+               cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+               cinfo->card ? cinfo->card->port : 0x0,
+               cinfo->card ? cinfo->card->irq : 0
                );
-       return card->infobuf;
+       return cinfo->infobuf;
 }
 
 /* ------------------------------------------------------------- */
index b2d9fc4210d56bfc68136a76e69d3c41931af0d8..b494b614e322d57600d64a78b1b448200d2b1a66 100644 (file)
@@ -1,11 +1,21 @@
 /*
- * $Id: b1pci.c,v 1.16 1999/08/11 21:01:07 keil Exp $
+ * $Id: b1pci.c,v 1.18 1999/11/05 16:38:01 calle Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pci.c,v $
+ * Revision 1.18  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
+ * Revision 1.17  1999/10/05 06:50:07  calle
+ * Forgot SA_SHIRQ as argument to request_irq.
+ *
  * Revision 1.16  1999/08/11 21:01:07  keil
  * new PCI codefix
  *
@@ -56,7 +66,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.16 $";
+static char *revision = "$Revision: 1.18 $";
 
 /* ------------------------------------------------------------- */
 
@@ -85,11 +95,11 @@ static void b1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
        card = (avmcard *) devptr;
 
        if (!card) {
-               printk(KERN_WARNING "b1_interrupt: wrong device\n");
+               printk(KERN_WARNING "b1pci: interrupt: wrong device\n");
                return;
        }
        if (card->interrupt) {
-               printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
+               printk(KERN_ERR "%s: reentering interrupt hander.\n", card->name);
                return;
        }
 
@@ -103,7 +113,8 @@ static void b1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
 
 static void b1pci_remove_ctr(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
 
        b1_reset(port);
@@ -113,6 +124,7 @@ static void b1pci_remove_ctr(struct capi_ctr *ctrl)
        free_irq(card->irq, card);
        release_region(card->port, AVMB1_PORTLEN);
        ctrl->driverdata = 0;
+       kfree(card->ctrlinfo);
        kfree(card);
 
        MOD_DEC_USE_COUNT;
@@ -122,15 +134,17 @@ static void b1pci_remove_ctr(struct capi_ctr *ctrl)
 
 static char *b1pci_procinfo(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
-       if (!card)
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+       if (!cinfo)
                return "";
-       sprintf(card->infobuf, "%s %s 0x%x %d",
-               card->cardname[0] ? card->cardname : "-",
-               card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
-               card->port, card->irq
+       sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+               cinfo->cardname[0] ? cinfo->cardname : "-",
+               cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+               cinfo->card ? cinfo->card->port : 0x0,
+               cinfo->card ? cinfo->card->irq : 0
                );
-       return card->infobuf;
+       return cinfo->infobuf;
 }
 
 /* ------------------------------------------------------------- */
@@ -138,15 +152,25 @@ static char *b1pci_procinfo(struct capi_ctr *ctrl)
 static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
        avmcard *card;
+       avmctrl_info *cinfo;
        int retval;
 
        card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
 
        if (!card) {
-               printk(KERN_WARNING "b1pci: no memory.\n");
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
                return -ENOMEM;
        }
        memset(card, 0, sizeof(avmcard));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+       if (!cinfo) {
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
+               kfree(card);
+               return -ENOMEM;
+       }
+       memset(cinfo, 0, sizeof(avmctrl_info));
+       card->ctrlinfo = cinfo;
+       cinfo->card = card;
        sprintf(card->name, "b1pci-%x", p->port);
        card->port = p->port;
        card->irq = p->irq;
@@ -154,15 +178,17 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
 
        if (check_region(card->port, AVMB1_PORTLEN)) {
                printk(KERN_WARNING
-                      "b1pci: ports 0x%03x-0x%03x in use.\n",
-                      card->port, card->port + AVMB1_PORTLEN);
+                      "%s: ports 0x%03x-0x%03x in use.\n",
+                      driver->name, card->port, card->port + AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
        b1_reset(card->port);
        if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
-               printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
-                                       card->port, retval);
+               printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+                                       driver->name, card->port, retval);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EIO;
        }
@@ -170,19 +196,23 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
 
        request_region(p->port, AVMB1_PORTLEN, card->name);
 
-       retval = request_irq(card->irq, b1pci_interrupt, 0, card->name, card);
+       retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
        if (retval) {
-               printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
+               printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+                               driver->name, card->irq);
                release_region(card->port, AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
 
-       card->ctrl = di->attach_ctr(driver, card->name, card);
-       if (!card->ctrl) {
-               printk(KERN_ERR "b1pci: attach controller failed.\n");
+       cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+       if (!cinfo->capi_ctrl) {
+               printk(KERN_ERR "%s: attach controller failed.\n",
+                               driver->name);
                free_irq(card->irq, card);
                release_region(card->port, AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
@@ -276,7 +306,7 @@ int b1pci_init(void)
        printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name);
        return -ESRCH;
 #else
-       printk(KERN_ERR "b1pci: kernel not compiled with PCI.\n");
+       printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
        return -EIO;
 #endif
 }
index b7bdb54044984c5273869263bb49d2aac8817854..79e34316481adec4deb2182a0bb8fbdced68f3c3 100644 (file)
@@ -1,11 +1,18 @@
 /*
- * $Id: b1pcmcia.c,v 1.4 1999/08/22 20:26:26 calle Exp $
+ * $Id: b1pcmcia.c,v 1.5 1999/11/05 16:38:01 calle Exp $
  * 
  * Module for AVM B1/M1/M2 PCMCIA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pcmcia.c,v $
+ * Revision 1.5  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
  * Revision 1.4  1999/08/22 20:26:26  calle
  * backported changes from kernel 2.3.14:
  * - several #include "config.h" gone, others come.
@@ -55,7 +62,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.5 $";
 
 /* ------------------------------------------------------------- */
 
@@ -74,11 +81,12 @@ static void b1pcmcia_interrupt(int interrupt, void *devptr, struct pt_regs *regs
        card = (avmcard *) devptr;
 
        if (!card) {
-               printk(KERN_WARNING "b1_interrupt: wrong device\n");
+               printk(KERN_WARNING "b1pcmcia: interrupt: wrong device\n");
                return;
        }
        if (card->interrupt) {
-               printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
+               printk(KERN_ERR "%s: reentering interrupt hander.\n",
+                       card->name);
                return;
        }
 
@@ -92,7 +100,8 @@ static void b1pcmcia_interrupt(int interrupt, void *devptr, struct pt_regs *regs
 
 static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
 
        b1_reset(port);
@@ -115,16 +124,26 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
                                unsigned irq,
                                enum avmcardtype cardtype)
 {
+       avmctrl_info *cinfo;
        avmcard *card;
        int retval;
 
        card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
 
        if (!card) {
-               printk(KERN_WARNING "b1pcmcia: no memory.\n");
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
                return -ENOMEM;
        }
        memset(card, 0, sizeof(avmcard));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+       if (!cinfo) {
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
+               kfree(card);
+               return -ENOMEM;
+       }
+       memset(cinfo, 0, sizeof(avmctrl_info));
+       card->ctrlinfo = cinfo;
+       cinfo->card = card;
        switch (cardtype) {
                case avm_m1: sprintf(card->name, "m1-%x", port); break;
                case avm_m2: sprintf(card->name, "m2-%x", port); break;
@@ -136,8 +155,9 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
 
        b1_reset(card->port);
        if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
-               printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n",
-                                       card->port, retval);
+               printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+                                       driver->name, card->port, retval);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EIO;
        }
@@ -145,36 +165,42 @@ static int b1pcmcia_add_card(struct capi_driver *driver,
 
        retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
        if (retval) {
-               printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n", card->irq);
+               printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+                               driver->name, card->irq);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
 
-       card->ctrl = di->attach_ctr(driver, card->name, card);
-       if (!card->ctrl) {
-               printk(KERN_ERR "b1pcmcia: attach controller failed.\n");
+       cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+       if (!cinfo->capi_ctrl) {
+               printk(KERN_ERR "%s: attach controller failed.\n",
+                               driver->name);
                free_irq(card->irq, card);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
 
        MOD_INC_USE_COUNT;
-       return card->ctrl->cnr;
+       return cinfo->capi_ctrl->cnr;
 }
 
 /* ------------------------------------------------------------- */
 
 static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
-       if (!card)
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+       if (!cinfo)
                return "";
-       sprintf(card->infobuf, "%s %s 0x%x %d",
-               card->cardname[0] ? card->cardname : "-",
-               card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
-               card->port, card->irq
+       sprintf(cinfo->infobuf, "%s %s 0x%x %d",
+               cinfo->cardname[0] ? cinfo->cardname : "-",
+               cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+               cinfo->card ? cinfo->card->port : 0x0,
+               cinfo->card ? cinfo->card->irq : 0
                );
-       return card->infobuf;
+       return cinfo->infobuf;
 }
 
 /* ------------------------------------------------------------- */
@@ -219,7 +245,7 @@ int b1pcmcia_delcard(unsigned int port, unsigned irq)
        avmcard *card;
 
        for (ctrl = b1pcmcia_driver.controller; ctrl; ctrl = ctrl->next) {
-               card = (avmcard *)(ctrl->driverdata);
+               card = ((avmctrl_info *)(ctrl->driverdata))->card;
                if (card->port == port && card->irq == irq) {
                        b1pcmcia_remove_ctr(ctrl);
                        return 0;
index e2942e133fc24ce94f94c9d88c000e3e37a47863..af2074ae6c99ed2e2ac15e219d6971e250ca53b5 100644 (file)
@@ -1,11 +1,14 @@
 /*
- * $Id: capi.c,v 1.21 1999/09/10 17:24:18 calle Exp $
+ * $Id: capi.c,v 1.22 1999/11/13 21:27:16 keil Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capi.c,v $
+ * Revision 1.22  1999/11/13 21:27:16  keil
+ * remove KERNELVERSION
+ *
  * Revision 1.21  1999/09/10 17:24:18  calle
  * Changes for proposed standard for CAPI2.0:
  * - AK148 "Linux Exention"
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
@@ -283,20 +285,13 @@ static unsigned int
 capi_poll(struct file *file, poll_table * wait)
 {
        unsigned int mask = 0;
-#if (LINUX_VERSION_CODE >= 0x02012d)
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
-#else
-       unsigned int minor = MINOR(file->f_inode->i_rdev);
-#endif
        struct capidev *cdev;
 
        if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
                return POLLERR;
 
        cdev = &capidevs[minor];
-#if (LINUX_VERSION_CODE < 0x020159) /* 2.1.89 */
-#define poll_wait(f,wq,w) poll_wait((wq),(w))
-#endif
        poll_wait(file, &(cdev->recv_wait), wait);
        mask = POLLOUT | POLLWRNORM;
        if (!skb_queue_empty(&cdev->recv_queue))
@@ -524,9 +519,7 @@ static struct file_operations capi_fops =
        capi_ioctl,
        NULL,                   /* capi_mmap */
        capi_open,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
         NULL,                   /* capi_flush */
-#endif
        capi_release,
        NULL,                   /* capi_fsync */
        NULL,                   /* capi_fasync */
index 19c8d717da9647ee07337165533cba43723ddd1c..6db170e42486117f4814c7c4ab8015348b31c4bf 100644 (file)
@@ -1,11 +1,14 @@
 /*
- * $Id: capidrv.c,v 1.27 1999/09/16 15:13:04 calle Exp $
+ * $Id: capidrv.c,v 1.28 1999/11/05 16:22:37 calle Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.c,v $
+ * Revision 1.28  1999/11/05 16:22:37  calle
+ * Bugfix: Missing break in switch on ISDN_CMD_HANGUP.
+ *
  * Revision 1.27  1999/09/16 15:13:04  calle
  * forgot to change paramter type of contr for lower_callback ...
  *
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.27 $";
+static char *revision = "$Revision: 1.28 $";
 int debugmode = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -716,8 +719,6 @@ static struct plcistatechange plcitable[] =
   /* P-0.1 */
   {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
   {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
-  {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
-  {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
   /* P-1 */
   {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
   {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
@@ -1857,14 +1858,19 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
                        );
                        ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
                        send_message(card, &cmdcmsg);
+                       return 0;
                } else if (bchan->plcip) {
-                       bchan->disconnecting = 1;
                        if (bchan->plcip->state == ST_PLCI_INCOMING) {
-                               /* just ignore, we a called from isdn_status_callback(),
-                                * which will return 0 or 2, this is handled by the
-                                * CONNECT_IND handler
+                               /*
+                                * just ignore, we a called from
+                                * isdn_status_callback(),
+                                * which will return 0 or 2, this is handled
+                                * by the CONNECT_IND handler
                                 */
-                       } else {
+                               bchan->disconnecting = 1;
+                               return 0;
+                       } else if (bchan->plcip->plci) {
+                               bchan->disconnecting = 1;
                                capi_fill_DISCONNECT_REQ(&cmdcmsg,
                                                         global.appid,
                                                         card->msgid++,
@@ -1876,8 +1882,18 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
                                );
                                plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
                                send_message(card, &cmdcmsg);
+                               return 0;
+                       } else {
+                               printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
+                                      card->contrnr,
+                                      c->arg);
+                               return -EINVAL;
                        }
                }
+               printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
+                                      card->contrnr,
+                                      c->arg);
+               return -EINVAL;
 /* ready */
 
        case ISDN_CMD_SETL2:
index 5caa537cd4dfe532e3bd62764399f17f09b54541..8ebed33004811d75d0ab0daabeeb5f7009775bda 100644 (file)
@@ -1,11 +1,18 @@
 /*
- * $Id: kcapi.c,v 1.8 1999/09/10 17:24:18 calle Exp $
+ * $Id: kcapi.c,v 1.10 1999/10/26 15:30:32 calle Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: kcapi.c,v $
+ * Revision 1.10  1999/10/26 15:30:32  calle
+ * Generate error message if user want to add card, but driver module is
+ * not loaded.
+ *
+ * Revision 1.9  1999/10/11 22:04:12  keil
+ * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
+ *
  * Revision 1.8  1999/09/10 17:24:18  calle
  * Changes for proposed standard for CAPI2.0:
  * - AK148 "Linux Exention"
@@ -72,7 +79,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.8 $";
+static char *revision = "$Revision: 1.10 $";
 
 /* ------------------------------------------------------------- */
 
@@ -1226,7 +1233,12 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
                        case AVM_CARDTYPE_T1: driver = t1isa_driver; break;
                        default: driver = 0;
                }
-               if (!driver || !driver->add_card) {
+               if (!driver) {
+                       printk(KERN_ERR "kcapi: driver not loaded.\n");
+                       return -EIO;
+               }
+               if (!driver->add_card) {
+                       printk(KERN_ERR "kcapi: driver has no add card function.\n");
                        return -EIO;
                }
 
index e574bda17332fa6aff92543c14cd56a5bfcce406..22a07f2ade758a0eebb8e2a5cbf0cc4d7d06ce2b 100644 (file)
@@ -1,11 +1,18 @@
 /*
- * $Id: t1isa.c,v 1.7 1999/09/15 08:16:03 calle Exp $
+ * $Id: t1isa.c,v 1.8 1999/11/05 16:38:01 calle Exp $
  * 
  * Module for AVM T1 HEMA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: t1isa.c,v $
+ * Revision 1.8  1999/11/05 16:38:01  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
  * Revision 1.7  1999/09/15 08:16:03  calle
  * Implementation of 64Bit extention complete.
  *
@@ -66,7 +73,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.8 $";
 
 /* ------------------------------------------------------------- */
 
@@ -169,7 +176,8 @@ static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
 
 static void t1_handle_interrupt(avmcard * card)
 {
-       struct capi_ctr *ctrl = card->ctrl;
+       avmctrl_info *cinfo = &card->ctrlinfo[0];
+       struct capi_ctr *ctrl = cinfo->capi_ctrl;
        unsigned char b1cmd;
        struct sk_buff *skb;
 
@@ -197,7 +205,8 @@ static void t1_handle_interrupt(avmcard * card)
                                CAPIMSG_SETLEN(card->msgbuf, 30);
                        }
                        if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
-                               printk(KERN_ERR "t1isa: incoming packet dropped\n");
+                               printk(KERN_ERR "%s: incoming packet dropped\n",
+                                       card->name);
                        } else {
                                memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
                                memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
@@ -210,7 +219,8 @@ static void t1_handle_interrupt(avmcard * card)
                        ApplId = (unsigned) b1_get_word(card->port);
                        MsgLen = t1_get_slice(card->port, card->msgbuf);
                        if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
-                               printk(KERN_ERR "t1isa: incoming packet dropped\n");
+                               printk(KERN_ERR "%s: incoming packet dropped\n",
+                                               card->name);
                        } else {
                                memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
                                ctrl->handle_capimsg(ctrl, ApplId, skb);
@@ -248,12 +258,12 @@ static void t1_handle_interrupt(avmcard * card)
 
                case RECEIVE_INIT:
 
-                       card->versionlen = t1_get_slice(card->port, card->versionbuf);
-                       b1_parse_version(card);
+                       cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf);
+                       b1_parse_version(cinfo);
                        printk(KERN_INFO "%s: %s-card (%s) now active\n",
                               card->name,
-                              card->version[VER_CARDTYPE],
-                              card->version[VER_DRIVER]);
+                              cinfo->version[VER_CARDTYPE],
+                              cinfo->version[VER_DRIVER]);
                        ctrl->ready(ctrl);
                        break;
 
@@ -299,11 +309,12 @@ static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
        card = (avmcard *) devptr;
 
        if (!card) {
-               printk(KERN_WARNING "t1_interrupt: wrong device\n");
+               printk(KERN_WARNING "t1isa: interrupt: wrong device\n");
                return;
        }
        if (card->interrupt) {
-               printk(KERN_ERR "t1_interrupt: reentering interrupt hander (%s)\n", card->name);
+               printk(KERN_ERR "%s: reentering interrupt hander.\n",
+                                card->name);
                return;
        }
 
@@ -317,7 +328,8 @@ static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
 
 static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
        unsigned long flags;
        int retval;
@@ -325,7 +337,7 @@ static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
        t1_disable_irq(port);
        b1_reset(port);
 
-       if ((retval = b1_load_t4file(port, &data->firmware))) {
+       if ((retval = b1_load_t4file(card, &data->firmware))) {
                b1_reset(port);
                printk(KERN_ERR "%s: failed to load t4file!!\n",
                                        card->name);
@@ -333,7 +345,7 @@ static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
        }
 
        if (data->configuration.len > 0 && data->configuration.data) {
-               if ((retval = b1_load_config(port, &data->configuration))) {
+               if ((retval = b1_load_config(card, &data->configuration))) {
                        b1_reset(port);
                        printk(KERN_ERR "%s: failed to load config!!\n",
                                        card->name);
@@ -341,7 +353,7 @@ static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
                }
        }
 
-       if (!b1_loaded(port)) {
+       if (!b1_loaded(card)) {
                printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
                return -EIO;
        }
@@ -360,20 +372,22 @@ static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
 
 void t1isa_reset_ctr(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
 
        t1_disable_irq(port);
        b1_reset(port);
        b1_reset(port);
 
-       memset(card->version, 0, sizeof(card->version));
+       memset(cinfo->version, 0, sizeof(cinfo->version));
        ctrl->reseted(ctrl);
 }
 
 static void t1isa_remove_ctr(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
 
        t1_disable_irq(port);
@@ -384,6 +398,7 @@ static void t1isa_remove_ctr(struct capi_ctr *ctrl)
        di->detach_ctr(ctrl);
        free_irq(card->irq, card);
        release_region(card->port, AVMB1_PORTLEN);
+       kfree(card->ctrlinfo);
        kfree(card);
 
        MOD_DEC_USE_COUNT;
@@ -394,16 +409,26 @@ static void t1isa_remove_ctr(struct capi_ctr *ctrl)
 static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
 {
        struct capi_ctr *ctrl;
+       avmctrl_info *cinfo;
        avmcard *card;
        int retval;
 
        card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
 
        if (!card) {
-               printk(KERN_WARNING "t1isa: no memory.\n");
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
                return -ENOMEM;
        }
        memset(card, 0, sizeof(avmcard));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+       if (!cinfo) {
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
+               kfree(card);
+               return -ENOMEM;
+       }
+       memset(cinfo, 0, sizeof(avmctrl_info));
+       card->ctrlinfo = cinfo;
+       cinfo->card = card;
        sprintf(card->name, "t1isa-%x", p->port);
        card->port = p->port;
        card->irq = p->irq;
@@ -411,33 +436,42 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
        card->cardnr = p->cardnr;
 
        if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
-               printk(KERN_WARNING "t1isa: illegal port 0x%x.\n", card->port);
+               printk(KERN_WARNING "%s: illegal port 0x%x.\n",
+                               driver->name, card->port);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EINVAL;
         }
 
        if (check_region(card->port, AVMB1_PORTLEN)) {
                printk(KERN_WARNING
-                      "t1isa: ports 0x%03x-0x%03x in use.\n",
-                      card->port, card->port + AVMB1_PORTLEN);
+                      "%s: ports 0x%03x-0x%03x in use.\n",
+                      driver->name, card->port, card->port + AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
        if (hema_irq_table[card->irq & 0xf] == 0) {
-               printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq);
+               printk(KERN_WARNING "%s: irq %d not valid.\n",
+                               driver->name, card->irq);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EINVAL;
        }
        for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) {
-               if (((avmcard *)(ctrl->driverdata))->cardnr == card->cardnr) {
-                       printk(KERN_WARNING "t1isa: card with number %d already installed.\n", card->cardnr);
+               avmcard *cardp = ((avmctrl_info *)(ctrl->driverdata))->card;
+               if (cardp->cardnr == card->cardnr) {
+                       printk(KERN_WARNING "%s: card with number %d already installed at 0x%x.\n",
+                                       driver->name, card->cardnr, cardp->port);
+                       kfree(card->ctrlinfo);
                        kfree(card);
                        return -EBUSY;
                }
        }
         if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
-               printk(KERN_NOTICE "t1isa: NO card at 0x%x (%d)\n",
-                                       card->port, retval);
+               printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+                                       driver->name, card->port, retval);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EIO;
        }
@@ -448,17 +482,21 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
 
        retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
        if (retval) {
-               printk(KERN_ERR "t1isa: unable to get IRQ %d.\n", card->irq);
+               printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+                               driver->name, card->irq);
                release_region(card->port, AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
 
-       card->ctrl = di->attach_ctr(driver, card->name, card);
-       if (!card->ctrl) {
-               printk(KERN_ERR "t1isa: attach controller failed.\n");
+       cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+       if (!cinfo->capi_ctrl) {
+               printk(KERN_ERR "%s: attach controller failed.\n",
+                               driver->name);
                free_irq(card->irq, card);
                release_region(card->port, AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
                kfree(card);
                return -EBUSY;
        }
@@ -469,7 +507,8 @@ static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
 
 static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
        unsigned int port = card->port;
        unsigned long flags;
        __u16 len = CAPIMSG_LEN(skb->data);
@@ -494,15 +533,18 @@ static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
 
 static char *t1isa_procinfo(struct capi_ctr *ctrl)
 {
-       avmcard *card = (avmcard *)(ctrl->driverdata);
-       if (!card)
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+       if (!cinfo)
                return "";
-       sprintf(card->infobuf, "%s %s 0x%x %d %d",
-               card->cardname[0] ? card->cardname : "-",
-               card->version[VER_DRIVER] ? card->version[VER_DRIVER] : "-",
-               card->port, card->irq, card->cardnr
+       sprintf(cinfo->infobuf, "%s %s 0x%x %d %d",
+               cinfo->cardname[0] ? cinfo->cardname : "-",
+               cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+               cinfo->card ? cinfo->card->port : 0x0,
+               cinfo->card ? cinfo->card->irq : 0,
+               cinfo->card ? cinfo->card->cardnr : 0
                );
-       return card->infobuf;
+       return cinfo->infobuf;
 }
 
 
diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c
new file mode 100644 (file)
index 0000000..6fe0a87
--- /dev/null
@@ -0,0 +1,1166 @@
+/*
+ * $Id: t1pci.c,v 1.3 1999/11/13 21:27:16 keil Exp $
+ * 
+ * Module for AVM T1 PCI-card.
+ * 
+ * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ * 
+ * $Log: t1pci.c,v $
+ * Revision 1.3  1999/11/13 21:27:16  keil
+ * remove KERNELVERSION
+ *
+ * Revision 1.2  1999/11/05 16:38:02  calle
+ * Cleanups before kernel 2.4:
+ * - Changed all messages to use card->name or driver->name instead of
+ *   constant string.
+ * - Moved some data from struct avmcard into new struct avmctrl_info.
+ *   Changed all lowlevel capi driver to match the new structur.
+ *
+ * Revision 1.1  1999/10/26 15:31:42  calle
+ * Added driver for T1-PCI card.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include "capicmd.h"
+#include "capiutil.h"
+#include "capilli.h"
+#include "avmcard.h"
+
+static char *revision = "$Revision: 1.3 $";
+
+#undef CONFIG_T1PCI_DEBUG
+#undef CONFIG_T1PCI_POLLDEBUG
+
+/* ------------------------------------------------------------- */
+
+#ifndef PCI_VENDOR_ID_AVM
+#define PCI_VENDOR_ID_AVM      0x1244
+#endif
+
+#ifndef PCI_DEVICE_ID_AVM_T1
+#define PCI_DEVICE_ID_AVM_T1   0x1200
+#endif
+
+/* ------------------------------------------------------------- */
+
+int suppress_pollack = 0;
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+
+MODULE_PARM(suppress_pollack, "0-1i");
+
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver_interface *di;
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+/* S5933 */
+
+#define        AMCC_RXPTR      0x24
+#define        AMCC_RXLEN      0x28
+#define        AMCC_TXPTR      0x2c
+#define        AMCC_TXLEN      0x30
+
+#define        AMCC_INTCSR     0x38
+#      define EN_READ_TC_INT           0x00008000L
+#      define EN_WRITE_TC_INT          0x00004000L
+#      define EN_TX_TC_INT             EN_READ_TC_INT
+#      define EN_RX_TC_INT             EN_WRITE_TC_INT
+#      define AVM_FLAG                 0x30000000L
+
+#      define ANY_S5933_INT            0x00800000L
+#      define  READ_TC_INT             0x00080000L
+#      define WRITE_TC_INT             0x00040000L
+#      define  TX_TC_INT               READ_TC_INT
+#      define  RX_TC_INT               WRITE_TC_INT
+#      define MASTER_ABORT_INT         0x00100000L
+#      define TARGET_ABORT_INT         0x00200000L
+#      define BUS_MASTER_INT           0x00200000L
+#      define ALL_INT                  0x000C0000L
+
+#define        AMCC_MCSR       0x3c
+#      define A2P_HI_PRIORITY          0x00000100L
+#      define EN_A2P_TRANSFERS         0x00000400L
+#      define P2A_HI_PRIORITY          0x00001000L
+#      define EN_P2A_TRANSFERS         0x00004000L
+#      define RESET_A2P_FLAGS          0x04000000L
+#      define RESET_P2A_FLAGS          0x02000000L
+
+/* ------------------------------------------------------------- */
+
+#define t1outmeml(addr, value) writel(value, addr)
+#define t1inmeml(addr) readl(addr)
+#define t1outmemw(addr, value) writew(value, addr)
+#define t1inmemw(addr) readw(addr)
+#define t1outmemb(addr, value) writeb(value, addr)
+#define t1inmemb(addr) readb(addr)
+
+/* ------------------------------------------------------------- */
+
+static inline int t1pci_tx_empty(unsigned int port)
+{
+       return inb(port + 0x03) & 0x1;
+}
+
+static inline int t1pci_rx_full(unsigned int port)
+{
+       return inb(port + 0x02) & 0x1;
+}
+
+static int t1pci_tolink(avmcard *card, void *buf, unsigned int len)
+{
+       unsigned long stop = jiffies + 1 * HZ;  /* maximum wait time 1 sec */
+       unsigned char *s = (unsigned char *)buf;
+       while (len--) {
+               while (   !t1pci_tx_empty(card->port)
+                      && time_before(jiffies, stop));
+               if (!t1pci_tx_empty(card->port)) 
+                       return -1;
+               t1outp(card->port, 0x01, *s++);
+       }
+       return 0;
+}
+
+static int t1pci_fromlink(avmcard *card, void *buf, unsigned int len)
+{
+       unsigned long stop = jiffies + 1 * HZ;  /* maximum wait time 1 sec */
+       unsigned char *s = (unsigned char *)buf;
+       while (len--) {
+               while (   !t1pci_rx_full(card->port)
+                      && time_before(jiffies, stop));
+               if (!t1pci_rx_full(card->port)) 
+                       return -1;
+               *s++ = t1inp(card->port, 0x00);
+       }
+       return 0;
+}
+
+static int WriteReg(avmcard *card, __u32 reg, __u8 val)
+{
+       __u8 cmd = 0x00;
+       if (   t1pci_tolink(card, &cmd, 1) == 0
+           && t1pci_tolink(card, &reg, 4) == 0) {
+               __u32 tmp = val;
+               return t1pci_tolink(card, &tmp, 4);
+       }
+       return -1;
+}
+
+static __u8 ReadReg(avmcard *card, __u32 reg)
+{
+       __u8 cmd = 0x01;
+       if (   t1pci_tolink(card, &cmd, 1) == 0
+           && t1pci_tolink(card, &reg, 4) == 0) {
+               __u32 tmp;
+               if (t1pci_fromlink(card, &tmp, 4) == 0)
+                       return (__u8)tmp;
+       }
+       return 0xff;
+}
+
+/* ------------------------------------------------------------- */
+
+static inline void _put_byte(void **pp, __u8 val)
+{
+       __u8 *s = *pp;
+       *s++ = val;
+       *pp = s;
+}
+
+static inline void _put_word(void **pp, __u32 val)
+{
+       __u8 *s = *pp;
+       *s++ = val & 0xff;
+       *s++ = (val >> 8) & 0xff;
+       *s++ = (val >> 16) & 0xff;
+       *s++ = (val >> 24) & 0xff;
+       *pp = s;
+}
+
+static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
+{
+       unsigned i = len;
+       _put_word(pp, i);
+       while (i-- > 0)
+               _put_byte(pp, *dp++);
+}
+
+static inline __u8 _get_byte(void **pp)
+{
+       __u8 *s = *pp;
+       __u8 val;
+       val = *s++;
+       *pp = s;
+       return val;
+}
+
+static inline __u32 _get_word(void **pp)
+{
+       __u8 *s = *pp;
+       __u32 val;
+       val = *s++;
+       val |= (*s++ << 8);
+       val |= (*s++ << 16);
+       val |= (*s++ << 24);
+       *pp = s;
+       return val;
+}
+
+static inline __u32 _get_slice(void **pp, unsigned char *dp)
+{
+       unsigned int len, i;
+
+       len = i = _get_word(pp);
+       while (i-- > 0) *dp++ = _get_byte(pp);
+       return len;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_reset(avmcard *card)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       card->csr = 0x0;
+       t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+       t1outmeml(card->mbase+AMCC_MCSR, 0);
+       t1outmeml(card->mbase+AMCC_RXLEN, 0);
+       t1outmeml(card->mbase+AMCC_TXLEN, 0);
+
+       t1outp(card->port, T1_RESETLINK, 0x00);
+       t1outp(card->port, 0x07, 0x00);
+
+       restore_flags(flags);
+
+       t1outmeml(card->mbase+AMCC_MCSR, 0);
+       udelay(10 * 1000);
+       t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+       udelay(10 * 1000);
+       t1outmeml(card->mbase+AMCC_MCSR, 0);
+       udelay(42 * 1000);
+
+}
+
+/* ------------------------------------------------------------- */
+
+static int t1pci_detect(avmcard *card)
+{
+       t1outmeml(card->mbase+AMCC_MCSR, 0);
+       udelay(10 * 1000);
+       t1outmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
+       udelay(10 * 1000);
+       t1outmeml(card->mbase+AMCC_MCSR, 0);
+       udelay(42 * 1000);
+
+       t1outmeml(card->mbase+AMCC_RXLEN, 0);
+       t1outmeml(card->mbase+AMCC_TXLEN, 0);
+       card->csr = 0x0;
+       t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+
+       if (t1inmeml(card->mbase+AMCC_MCSR) != 0x000000E6)
+               return 1;
+
+       t1outmeml(card->mbase+AMCC_RXPTR, 0xffffffff);
+       t1outmeml(card->mbase+AMCC_TXPTR, 0xffffffff);
+       if (   t1inmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc
+           || t1inmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc)
+               return 2;
+
+       t1outmeml(card->mbase+AMCC_RXPTR, 0x0);
+       t1outmeml(card->mbase+AMCC_TXPTR, 0x0);
+       if (   t1inmeml(card->mbase+AMCC_RXPTR) != 0x0
+           || t1inmeml(card->mbase+AMCC_TXPTR) != 0x0)
+               return 3;
+
+       t1outp(card->port, T1_RESETLINK, 0x00);
+       t1outp(card->port, 0x07, 0x00);
+       
+       t1outp(card->port, 0x02, 0x02);
+       t1outp(card->port, 0x03, 0x02);
+
+       if (   (t1inp(card->port, 0x02) & 0xFE) != 0x02
+           || t1inp(card->port, 0x3) != 0x03)
+               return 4;
+
+       t1outp(card->port, 0x02, 0x00);
+       t1outp(card->port, 0x03, 0x00);
+
+       if (   (t1inp(card->port, 0x02) & 0xFE) != 0x00
+           || t1inp(card->port, 0x3) != 0x01)
+               return 5;
+
+       /* Transputer test */
+       
+       if (   WriteReg(card, 0x80001000, 0x11) != 0
+           || WriteReg(card, 0x80101000, 0x22) != 0
+           || WriteReg(card, 0x80201000, 0x33) != 0
+           || WriteReg(card, 0x80301000, 0x44) != 0)
+               return 6;
+
+       if (   ReadReg(card, 0x80001000) != 0x11
+           || ReadReg(card, 0x80101000) != 0x22
+           || ReadReg(card, 0x80201000) != 0x33
+           || ReadReg(card, 0x80301000) != 0x44)
+               return 7;
+
+       if (   WriteReg(card, 0x80001000, 0x55) != 0
+           || WriteReg(card, 0x80101000, 0x66) != 0
+           || WriteReg(card, 0x80201000, 0x77) != 0
+           || WriteReg(card, 0x80301000, 0x88) != 0)
+               return 8;
+
+       if (   ReadReg(card, 0x80001000) != 0x55
+           || ReadReg(card, 0x80101000) != 0x66
+           || ReadReg(card, 0x80201000) != 0x77
+           || ReadReg(card, 0x80301000) != 0x88)
+               return 9;
+
+       return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_dispatch_tx(avmcard *card)
+{
+       avmcard_dmainfo *dma = card->dma;
+       unsigned long flags;
+       struct sk_buff *skb;
+       __u8 cmd, subcmd;
+       __u16 len;
+       __u32 txlen;
+       int inint;
+       void *p;
+       
+       save_flags(flags);
+       cli();
+
+       inint = card->interrupt;
+
+       if (card->csr & EN_TX_TC_INT) { /* tx busy */
+               restore_flags(flags);
+               return;
+       }
+
+       skb = skb_dequeue(&dma->send_queue);
+       if (!skb) {
+#ifdef CONFIG_T1PCI_DEBUG
+               printk(KERN_DEBUG "tx(%d): underrun\n", inint);
+#endif
+               restore_flags(flags);
+               return;
+       }
+
+       len = CAPIMSG_LEN(skb->data);
+
+       if (len) {
+               cmd = CAPIMSG_COMMAND(skb->data);
+               subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+               p = dma->sendbuf;
+
+               if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+                       __u16 dlen = CAPIMSG_DATALEN(skb->data);
+                       _put_byte(&p, SEND_DATA_B3_REQ);
+                       _put_slice(&p, skb->data, len);
+                       _put_slice(&p, skb->data + len, dlen);
+               } else {
+                       _put_byte(&p, SEND_MESSAGE);
+                       _put_slice(&p, skb->data, len);
+               }
+               txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
+#ifdef CONFIG_T1PCI_DEBUG
+               printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
+                               inint, txlen);
+#endif
+       } else {
+               txlen = skb->len-2;
+#ifdef CONFIG_T1PCI_POLLDEBUG
+               if (skb->data[2] == SEND_POLLACK)
+                       printk(KERN_INFO "%s: ack to t1\n", card->name);
+#endif
+#ifdef CONFIG_T1PCI_DEBUG
+               printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
+                               inint, skb->data[2], txlen);
+#endif
+               memcpy(dma->sendbuf, skb->data+2, skb->len-2);
+       }
+       txlen = (txlen + 3) & ~3;
+
+       t1outmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
+       t1outmeml(card->mbase+AMCC_TXLEN, txlen);
+
+       card->csr |= EN_TX_TC_INT;
+
+       if (!inint)
+               t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+
+       restore_flags(flags);
+       dev_kfree_skb(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void queue_pollack(avmcard *card)
+{
+       struct sk_buff *skb;
+       void *p;
+
+       skb = alloc_skb(3, GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_CRIT "%s: no memory, lost poll ack\n",
+                                       card->name);
+               return;
+       }
+       p = skb->data;
+       _put_byte(&p, 0);
+       _put_byte(&p, 0);
+       _put_byte(&p, SEND_POLLACK);
+       skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+       skb_queue_tail(&card->dma->send_queue, skb);
+       t1pci_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_handle_rx(avmcard *card)
+{
+       avmctrl_info *cinfo = &card->ctrlinfo[0];
+       avmcard_dmainfo *dma = card->dma;
+       struct capi_ctr *ctrl = cinfo->capi_ctrl;
+       struct sk_buff *skb;
+       void *p = dma->recvbuf+4;
+       __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+       __u8 b1cmd =  _get_byte(&p);
+
+#ifdef CONFIG_T1PCI_DEBUG
+       printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
+#endif
+       
+       switch (b1cmd) {
+       case RECEIVE_DATA_B3_IND:
+
+               ApplId = (unsigned) _get_word(&p);
+               MsgLen = _get_slice(&p, card->msgbuf);
+               DataB3Len = _get_slice(&p, card->databuf);
+
+               if (MsgLen < 30) { /* not CAPI 64Bit */
+                       memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
+                       MsgLen = 30;
+                       CAPIMSG_SETLEN(card->msgbuf, 30);
+               }
+               if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
+                       printk(KERN_ERR "%s: incoming packet dropped\n",
+                                       card->name);
+               } else {
+                       memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+                       memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+                       ctrl->handle_capimsg(ctrl, ApplId, skb);
+               }
+               break;
+
+       case RECEIVE_MESSAGE:
+
+               ApplId = (unsigned) _get_word(&p);
+               MsgLen = _get_slice(&p, card->msgbuf);
+               if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+                       printk(KERN_ERR "%s: incoming packet dropped\n",
+                                       card->name);
+               } else {
+                       memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+                       ctrl->handle_capimsg(ctrl, ApplId, skb);
+               }
+               break;
+
+       case RECEIVE_NEW_NCCI:
+
+               ApplId = _get_word(&p);
+               NCCI = _get_word(&p);
+               WindowSize = _get_word(&p);
+
+               ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
+
+               break;
+
+       case RECEIVE_FREE_NCCI:
+
+               ApplId = _get_word(&p);
+               NCCI = _get_word(&p);
+
+               if (NCCI != 0xffffffff)
+                       ctrl->free_ncci(ctrl, ApplId, NCCI);
+               else ctrl->appl_released(ctrl, ApplId);
+               break;
+
+       case RECEIVE_START:
+#ifdef CONFIG_T1PCI_POLLDEBUG
+               printk(KERN_INFO "%s: poll from t1\n", card->name);
+#endif
+               if (!suppress_pollack)
+                       queue_pollack(card);
+               ctrl->resume_output(ctrl);
+               break;
+
+       case RECEIVE_STOP:
+               ctrl->suspend_output(ctrl);
+               break;
+
+       case RECEIVE_INIT:
+
+               cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
+               b1_parse_version(cinfo);
+               printk(KERN_INFO "%s: %s-card (%s) now active\n",
+                      card->name,
+                      cinfo->version[VER_CARDTYPE],
+                      cinfo->version[VER_DRIVER]);
+               ctrl->ready(ctrl);
+               break;
+
+       case RECEIVE_TASK_READY:
+               ApplId = (unsigned) _get_word(&p);
+               MsgLen = _get_slice(&p, card->msgbuf);
+               card->msgbuf[MsgLen--] = 0;
+               while (    MsgLen >= 0
+                      && (   card->msgbuf[MsgLen] == '\n'
+                          || card->msgbuf[MsgLen] == '\r'))
+                       card->msgbuf[MsgLen--] = 0;
+               printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+                               card->name, ApplId, card->msgbuf);
+               break;
+
+       case RECEIVE_DEBUGMSG:
+               MsgLen = _get_slice(&p, card->msgbuf);
+               card->msgbuf[MsgLen--] = 0;
+               while (    MsgLen >= 0
+                      && (   card->msgbuf[MsgLen] == '\n'
+                          || card->msgbuf[MsgLen] == '\r'))
+                       card->msgbuf[MsgLen--] = 0;
+               printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+               break;
+
+       default:
+               printk(KERN_ERR "%s: t1pci_interrupt: 0x%x ???\n",
+                               card->name, b1cmd);
+               return;
+       }
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_handle_interrupt(avmcard *card)
+{
+       __u32 status = t1inmeml(card->mbase+AMCC_INTCSR);
+       __u32 newcsr;
+
+       if ((status & ANY_S5933_INT) == 0) 
+               return;
+
+        newcsr = card->csr | (status & ALL_INT);
+       if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
+       if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
+       t1outmeml(card->mbase+AMCC_INTCSR, newcsr);
+
+       if ((status & RX_TC_INT) != 0) {
+               __u8 *recvbuf = card->dma->recvbuf;
+               __u32 rxlen;
+               if (card->dma->recvlen == 0) {
+                       card->dma->recvlen = *((__u32 *)recvbuf);
+                       rxlen = (card->dma->recvlen + 3) & ~3;
+                       t1outmeml(card->mbase+AMCC_RXPTR,
+                                       virt_to_phys(recvbuf+4));
+                       t1outmeml(card->mbase+AMCC_RXLEN, rxlen);
+               } else {
+                       t1pci_handle_rx(card);
+                       card->dma->recvlen = 0;
+                       t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
+                       t1outmeml(card->mbase+AMCC_RXLEN, 4);
+               }
+       }
+
+       if ((status & TX_TC_INT) != 0) {
+               card->csr &= ~EN_TX_TC_INT;
+               t1pci_dispatch_tx(card);
+       } else if (card->csr & EN_TX_TC_INT) {
+               if (t1inmeml(card->mbase+AMCC_TXLEN) == 0) {
+                       card->csr &= ~EN_TX_TC_INT;
+                       t1pci_dispatch_tx(card);
+               }
+       }
+       t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+}
+
+static void t1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+       avmcard *card;
+
+       card = (avmcard *) devptr;
+
+       if (!card) {
+               printk(KERN_WARNING "t1pci: interrupt: wrong device\n");
+               return;
+       }
+       if (card->interrupt) {
+               printk(KERN_ERR "%s: reentering interrupt hander\n", card->name);
+               return;
+       }
+
+       card->interrupt = 1;
+
+       t1pci_handle_interrupt(card);
+
+       card->interrupt = 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int t1pci_loaded(avmcard *card)
+{
+       unsigned long stop;
+       unsigned char ans;
+       unsigned long tout = 2;
+       unsigned int base = card->port;
+
+       for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+               if (b1_tx_empty(base))
+                       break;
+       }
+       if (!b1_tx_empty(base)) {
+               printk(KERN_ERR "%s: t1pci_loaded: tx err, corrupted t4 file ?\n",
+                               card->name);
+               return 0;
+       }
+       b1_put_byte(base, SEND_POLLACK);
+       for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+               if (b1_rx_full(base)) {
+                       if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
+                               return 1;
+                       }
+                       printk(KERN_ERR "%s: t1pci_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
+                       return 0;
+               }
+       }
+       printk(KERN_ERR "%s: t1pci_loaded: firmware not running\n", card->name);
+       return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_send_init(avmcard *card)
+{
+       struct sk_buff *skb;
+       void *p;
+
+       skb = alloc_skb(15, GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+                                       card->name);
+               return;
+       }
+       p = skb->data;
+       _put_byte(&p, 0);
+       _put_byte(&p, 0);
+       _put_byte(&p, SEND_INIT);
+       _put_word(&p, AVM_NAPPS);
+       _put_word(&p, AVM_NCCI_PER_CHANNEL*30);
+       _put_word(&p, card->cardnr - 1);
+       skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+       skb_queue_tail(&card->dma->send_queue, skb);
+       t1pci_dispatch_tx(card);
+}
+
+static int t1pci_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+       unsigned long flags;
+       int retval;
+
+       t1pci_reset(card);
+
+       if ((retval = b1_load_t4file(card, &data->firmware))) {
+               t1pci_reset(card);
+               printk(KERN_ERR "%s: failed to load t4file!!\n",
+                                       card->name);
+               return retval;
+       }
+
+       if (data->configuration.len > 0 && data->configuration.data) {
+               if ((retval = b1_load_config(card, &data->configuration))) {
+                       t1pci_reset(card);
+                       printk(KERN_ERR "%s: failed to load config!!\n",
+                                       card->name);
+                       return retval;
+               }
+       }
+
+       if (!t1pci_loaded(card)) {
+               t1pci_reset(card);
+               printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
+               return -EIO;
+       }
+
+       save_flags(flags);
+       cli();
+
+       card->csr = AVM_FLAG;
+       t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+       t1outmeml(card->mbase+AMCC_MCSR,
+               EN_A2P_TRANSFERS|EN_P2A_TRANSFERS
+               |A2P_HI_PRIORITY|P2A_HI_PRIORITY
+               |RESET_A2P_FLAGS|RESET_P2A_FLAGS);
+       t1outp(card->port, 0x07, 0x30);
+       t1outp(card->port, 0x10, 0xF0);
+
+       card->dma->recvlen = 0;
+       t1outmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
+       t1outmeml(card->mbase+AMCC_RXLEN, 4);
+       card->csr |= EN_RX_TC_INT;
+       t1outmeml(card->mbase+AMCC_INTCSR, card->csr);
+       restore_flags(flags);
+
+        t1pci_send_init(card);
+
+       return 0;
+}
+
+void t1pci_reset_ctr(struct capi_ctr *ctrl)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+
+       t1pci_reset(card);
+
+       memset(cinfo->version, 0, sizeof(cinfo->version));
+       ctrl->reseted(ctrl);
+}
+
+static void t1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+
+       t1pci_reset(card);
+
+       di->detach_ctr(ctrl);
+       free_irq(card->irq, card);
+       iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+       release_region(card->port, AVMB1_PORTLEN);
+       ctrl->driverdata = 0;
+       kfree(card->ctrlinfo);
+       kfree(card->dma);
+       kfree(card);
+
+       MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------- */
+
+
+void t1pci_register_appl(struct capi_ctr *ctrl,
+                               __u16 appl,
+                               capi_register_params *rp)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+       struct sk_buff *skb;
+       int want = rp->level3cnt;
+       int nconn;
+       void *p;
+
+       if (want > 0) nconn = want;
+       else nconn = ctrl->profile.nbchannel * -want;
+       if (nconn == 0) nconn = ctrl->profile.nbchannel;
+
+       skb = alloc_skb(23, GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+                                       card->name);
+               return;
+       }
+       p = skb->data;
+       _put_byte(&p, 0);
+       _put_byte(&p, 0);
+       _put_byte(&p, SEND_REGISTER);
+       _put_word(&p, appl);
+       _put_word(&p, 1024 * (nconn+1));
+       _put_word(&p, nconn);
+       _put_word(&p, rp->datablkcnt);
+       _put_word(&p, rp->datablklen);
+       skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+       skb_queue_tail(&card->dma->send_queue, skb);
+       t1pci_dispatch_tx(card);
+
+       ctrl->appl_registered(ctrl, appl);
+}
+
+/* ------------------------------------------------------------- */
+
+void t1pci_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+       struct sk_buff *skb;
+       void *p;
+
+       skb = alloc_skb(7, GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_CRIT "%s: no memory, lost release appl.\n",
+                                       card->name);
+               return;
+       }
+       p = skb->data;
+       _put_byte(&p, 0);
+       _put_byte(&p, 0);
+       _put_byte(&p, SEND_RELEASE);
+       _put_word(&p, appl);
+
+       skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+       skb_queue_tail(&card->dma->send_queue, skb);
+       t1pci_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+
+static void t1pci_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+       skb_queue_tail(&card->dma->send_queue, skb);
+       t1pci_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static char *t1pci_procinfo(struct capi_ctr *ctrl)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+       if (!cinfo)
+               return "";
+       sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
+               cinfo->cardname[0] ? cinfo->cardname : "-",
+               cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+               cinfo->card ? cinfo->card->port : 0x0,
+               cinfo->card ? cinfo->card->irq : 0,
+               cinfo->card ? cinfo->card->membase : 0
+               );
+       return cinfo->infobuf;
+}
+
+static int t1pci_read_proc(char *page, char **start, off_t off,
+                       int count, int *eof, struct capi_ctr *ctrl)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+       unsigned long flags;
+       __u8 flag;
+       int len = 0;
+       char *s;
+       __u32 txaddr, txlen, rxaddr, rxlen, csr;
+
+       len += sprintf(page+len, "%-16s %s\n", "name", card->name);
+       len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
+       len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+       len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+       switch (card->cardtype) {
+       case avm_b1isa: s = "B1 ISA"; break;
+       case avm_b1pci: s = "B1 PCI"; break;
+       case avm_b1pcmcia: s = "B1 PCMCIA"; break;
+       case avm_m1: s = "M1"; break;
+       case avm_m2: s = "M2"; break;
+       case avm_t1isa: s = "T1 ISA (HEMA)"; break;
+       case avm_t1pci: s = "T1 PCI"; break;
+       case avm_c4: s = "C4"; break;
+       default: s = "???"; break;
+       }
+       len += sprintf(page+len, "%-16s %s\n", "type", s);
+       if ((s = cinfo->version[VER_DRIVER]) != 0)
+          len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+       if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+          len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+       if ((s = cinfo->version[VER_SERIAL]) != 0)
+          len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+       if (card->cardtype != avm_m1) {
+               flag = ((__u8 *)(ctrl->profile.manu))[3];
+               if (flag)
+                       len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+                       "protocol",
+                       (flag & 0x01) ? " DSS1" : "",
+                       (flag & 0x02) ? " CT1" : "",
+                       (flag & 0x04) ? " VN3" : "",
+                       (flag & 0x08) ? " NI1" : "",
+                       (flag & 0x10) ? " AUSTEL" : "",
+                       (flag & 0x20) ? " ESS" : "",
+                       (flag & 0x40) ? " 1TR6" : ""
+                       );
+       }
+       if (card->cardtype != avm_m1) {
+               flag = ((__u8 *)(ctrl->profile.manu))[5];
+               if (flag)
+                       len += sprintf(page+len, "%-16s%s%s%s%s\n",
+                       "linetype",
+                       (flag & 0x01) ? " point to point" : "",
+                       (flag & 0x02) ? " point to multipoint" : "",
+                       (flag & 0x08) ? " leased line without D-channel" : "",
+                       (flag & 0x04) ? " leased line with D-channel" : ""
+                       );
+       }
+       len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+
+       save_flags(flags);
+       cli();
+
+       txaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x2c));
+       txaddr -= (__u32)card->dma->sendbuf;
+       txlen  = t1inmeml(card->mbase+0x30);
+
+       rxaddr = (__u32)phys_to_virt(t1inmeml(card->mbase+0x24));
+       rxaddr -= (__u32)card->dma->recvbuf;
+       rxlen  = t1inmeml(card->mbase+0x28);
+
+       csr  = t1inmeml(card->mbase+AMCC_INTCSR);
+
+       restore_flags(flags);
+
+        len += sprintf(page+len, "%-16s 0x%lx\n",
+                               "csr (cached)", (unsigned long)card->csr);
+        len += sprintf(page+len, "%-16s 0x%lx\n",
+                               "csr", (unsigned long)csr);
+        len += sprintf(page+len, "%-16s %lu\n",
+                               "txoff", (unsigned long)txaddr);
+        len += sprintf(page+len, "%-16s %lu\n",
+                               "txlen", (unsigned long)txlen);
+        len += sprintf(page+len, "%-16s %lu\n",
+                               "rxoff", (unsigned long)rxaddr);
+        len += sprintf(page+len, "%-16s %lu\n",
+                               "rxlen", (unsigned long)rxlen);
+
+       if (off+count >= len)
+          *eof = 1;
+       if (len < off)
+           return 0;
+       *start = page + off;
+       return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
+{
+       unsigned long page_offset, base;
+       avmcard *card;
+       avmctrl_info *cinfo;
+       int retval;
+
+       card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
+
+       if (!card) {
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
+               return -ENOMEM;
+       }
+       memset(card, 0, sizeof(avmcard));
+       card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
+       if (!card->dma) {
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
+               kfree(card);
+               return -ENOMEM;
+       }
+       memset(card->dma, 0, sizeof(avmcard_dmainfo));
+        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+       if (!cinfo) {
+               printk(KERN_WARNING "%s: no memory.\n", driver->name);
+               kfree(card->dma);
+               kfree(card);
+               return -ENOMEM;
+       }
+       memset(cinfo, 0, sizeof(avmctrl_info));
+       card->ctrlinfo = cinfo;
+       cinfo->card = card;
+       sprintf(card->name, "t1pci-%x", p->port);
+       card->port = p->port;
+       card->irq = p->irq;
+       card->membase = p->membase;
+       card->cardtype = avm_t1pci;
+
+       if (check_region(card->port, AVMB1_PORTLEN)) {
+               printk(KERN_WARNING
+                      "%s: ports 0x%03x-0x%03x in use.\n",
+                      driver->name, card->port, card->port + AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
+               kfree(card->dma);
+               kfree(card);
+               return -EBUSY;
+       }
+
+        base = card->membase & PAGE_MASK;
+       page_offset = card->membase - base;
+       card->mbase = ioremap_nocache(base, page_offset + 64);
+
+       t1pci_reset(card);
+
+       if ((retval = t1pci_detect(card)) != 0) {
+               printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+                                       driver->name, card->port, retval);
+                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+               kfree(card->ctrlinfo);
+               kfree(card->dma);
+               kfree(card);
+               return -EIO;
+       }
+       t1pci_reset(card);
+
+       request_region(p->port, AVMB1_PORTLEN, card->name);
+
+       retval = request_irq(card->irq, t1pci_interrupt, SA_SHIRQ, card->name, card);
+       if (retval) {
+               printk(KERN_ERR "%s: unable to get IRQ %d.\n",
+                               driver->name, card->irq);
+                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+               release_region(card->port, AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
+               kfree(card->dma);
+               kfree(card);
+               return -EBUSY;
+       }
+
+       cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
+       if (!cinfo->capi_ctrl) {
+               printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
+                iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
+               free_irq(card->irq, card);
+               release_region(card->port, AVMB1_PORTLEN);
+               kfree(card->ctrlinfo);
+               kfree(card->dma);
+               kfree(card);
+               return -EBUSY;
+       }
+       card->cardnr = cinfo->capi_ctrl->cnr;
+
+       skb_queue_head_init(&card->dma->send_queue);
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static struct capi_driver t1pci_driver = {
+    "t1pci",
+    "0.0",
+    t1pci_load_firmware,
+    t1pci_reset_ctr,
+    t1pci_remove_ctr,
+    t1pci_register_appl,
+    t1pci_release_appl,
+    t1pci_send_message,
+
+    t1pci_procinfo,
+    t1pci_read_proc,
+    0, /* use standard driver_read_proc */
+
+    0, /* no add_card function */
+};
+
+#ifdef MODULE
+#define t1pci_init init_module
+void cleanup_module(void);
+#endif
+
+static int ncards = 0;
+
+int t1pci_init(void)
+{
+       struct capi_driver *driver = &t1pci_driver;
+       struct pci_dev *dev = NULL;
+       char *p;
+       int retval;
+
+       if ((p = strchr(revision, ':'))) {
+               strncpy(driver->revision, p + 1, sizeof(driver->revision));
+               p = strchr(driver->revision, '$');
+               *p = 0;
+       }
+
+       printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
+
+        di = attach_capi_driver(driver);
+
+       if (!di) {
+               printk(KERN_ERR "%s: failed to attach capi_driver\n",
+                               driver->name);
+               return -EIO;
+       }
+
+#ifdef CONFIG_PCI
+       if (!pci_present()) {
+               printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
+               detach_capi_driver(driver);
+               return -EIO;
+       }
+
+       while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) {
+               struct capicardparams param;
+
+               param.port = dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
+               param.irq = dev->irq;
+               param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK;
+
+               printk(KERN_INFO
+                       "%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
+                       driver->name, param.port, param.irq, param.membase);
+               retval = t1pci_add_card(driver, &param);
+               if (retval != 0) {
+                       printk(KERN_ERR
+                       "%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
+                       driver->name, param.port, param.irq, param.membase);
+#ifdef MODULE
+                       cleanup_module();
+#endif
+                       return retval;
+               }
+               ncards++;
+       }
+       if (ncards) {
+               printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n",
+                               driver->name, ncards);
+               return 0;
+       }
+       printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name);
+       return -ESRCH;
+#else
+       printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+       return -EIO;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+    detach_capi_driver(&t1pci_driver);
+}
+#endif
index e898026d4455c060b2576713d86f207e09f24532..5827e7746bc4ffbcc7ec4827211d0a13212676ce 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.14 1999/09/08 20:17:31 armin Exp $
+/* $Id: eicon.h,v 1.17 1999/10/26 21:15:33 armin Exp $
  *
  * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon.h,v $
+ * Revision 1.17  1999/10/26 21:15:33  armin
+ * using define for checking phone number len to avoid buffer overflow.
+ *
+ * Revision 1.16  1999/10/08 22:09:33  armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.15  1999/09/26 14:17:53  armin
+ * Improved debug and log via readstat()
+ *
  * Revision 1.14  1999/09/08 20:17:31  armin
  * Added microchannel patch from Erik Weber.
  *
 
 #define MAX_HEADER_LEN 10
 
+#define MAX_STATUS_BUFFER      150
 
 /* Struct for adding new cards */
 typedef struct eicon_cdef {
@@ -233,6 +245,7 @@ typedef struct {
 #include <linux/delay.h>
 #include <linux/ctype.h>
 
+#include <linux/isdn.h>
 #include <linux/isdnif.h>
 
 
@@ -480,7 +493,6 @@ typedef struct {
 
 typedef struct {
        int            No;               /* Channel Number              */
-       unsigned short callref;          /* Call Reference              */
        unsigned short fsm_state;        /* Current D-Channel state     */
        unsigned short eazmask;          /* EAZ-Mask for this Channel   */
        int             queued;          /* User-Data Bytes in TX queue */
@@ -497,9 +509,13 @@ typedef struct {
        entity          e;               /* Entity                      */
        char            cpn[32];         /* remember cpn                */
        char            oad[32];         /* remember oad                */
+       char            dsa[32];         /* remember dsa                */
+       char            osa[32];         /* remember osa                */
        unsigned char   cause[2];        /* Last Cause                  */
        unsigned char   si1;
        unsigned char   si2;
+       unsigned char   plan;
+       unsigned char   screen;
 } eicon_chan;
 
 typedef struct {
@@ -535,7 +551,7 @@ typedef struct {
 #define EICON_STATE_LISTEN  15
 #define EICON_STATE_WMCONN  16
 
-#define EICON_MAX_QUEUED  8000 /* 2 * maxbuff */
+#define EICON_MAX_QUEUE  2138
 
 #define EICON_LOCK_TX 0
 #define EICON_LOCK_RX 1
@@ -589,6 +605,8 @@ typedef struct eicon_card {
        struct sk_buff_head sndq;        /* Send-Message queue               */
        struct sk_buff_head rackq;       /* Req-Ack-Message queue            */
        struct sk_buff_head sackq;       /* Data-Ack-Message queue           */
+       struct sk_buff_head statq;       /* Status-Message queue             */
+       int statq_entries;
        u_char *ack_msg;                 /* Ptr to User Data in User skb     */
        __u16 need_b3ack;                /* Flag: Need ACK for current skb   */
        struct sk_buff *sbuf;            /* skb which is currently sent      */
@@ -677,6 +695,7 @@ extern int eicon_info(char *, int , void *);
 #endif /* CONFIG_MCA */
 
 extern ulong DebugVar;
+extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
 
 #endif  /* __KERNEL__ */
 
index 50820afed0622cf60953081b34c8982c4a33cc60..d8634bdbe587649c4b01a3da7b9fa4a87b7108c4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.18 1999/09/07 12:48:05 armin Exp $
+/* $Id: eicon_idi.c,v 1.24 1999/10/26 21:15:33 armin Exp $
  *
  * ISDN lowlevel-module for Eicon.Diehl active cards.
  *        IDI interface 
@@ -6,6 +6,11 @@
  * Copyright 1998,99 by Armin Schindler (mac@melware.de)
  * Copyright 1999    Cytronics & Melware (info@melware.de)
  *
+ * Thanks to   Deutsche Mailbox Saar-Lor-Lux GmbH
+ *             for sponsoring and testing fax
+ *             capabilities with Diva Server cards.
+ *             (dor@deutschemailbox.de)
+ *
  * 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, or (at your option)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_idi.c,v $
+ * Revision 1.24  1999/10/26 21:15:33  armin
+ * using define for checking phone number len to avoid buffer overflow.
+ *
+ * Revision 1.23  1999/10/11 18:13:25  armin
+ * Added fax capabilities for Eicon Diva Server cards.
+ *
+ * Revision 1.22  1999/10/08 22:09:33  armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.21  1999/09/26 14:17:53  armin
+ * Improved debug and log via readstat()
+ *
+ * Revision 1.20  1999/09/21 20:35:43  armin
+ * added more error checking.
+ *
+ * Revision 1.19  1999/09/21 20:06:40  armin
+ * Added pointer checks.
+ *
  * Revision 1.18  1999/09/07 12:48:05  armin
  * Prepared for sub-address usage.
  *
 
 #undef EICON_FULL_SERVICE_OKTETT
 
-char *eicon_idi_revision = "$Revision: 1.18 $";
+char *eicon_idi_revision = "$Revision: 1.24 $";
 
 eicon_manifbuf *manbuf;
 
@@ -289,8 +314,7 @@ idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
        reqbuf->XBuffer.P[8] = 0;
        reqbuf->XBuffer.length = l;
        reqbuf->Reference = 0; /* Sig Entity */
-       if (DebugVar & 8)
-               printk(KERN_DEBUG"idi_req: Ch%d: Call_Res\n", chan->No);
+       eicon_log(NULL, 8, "idi_req: Ch%d: Call_Res\n", chan->No);
    return(0);
 }
 
@@ -306,8 +330,7 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
+                       eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
                if (skb) 
                        dev_kfree_skb(skb);
                if (skb2) 
@@ -319,8 +342,7 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
        chan2->ptr = chan;
 
        reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
-       if (DebugVar & 8)
-               printk(KERN_DEBUG "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
+       eicon_log(card, 8, "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
        if (layer) cmd |= 0x700;
        switch(cmd) {
                case ASSIGN:
@@ -359,8 +381,7 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
                        idi_put_req(reqbuf, IDI_N_DISC_ACK, 1);
                        break;
                default:
-                       if (DebugVar & 1)
-                               printk(KERN_ERR "idi_req: Ch%d: Unknown request\n", chan->No);
+                       eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
                        dev_kfree_skb(skb);
                        dev_kfree_skb(skb2);
                        return(-1);
@@ -375,8 +396,10 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
 int
 eicon_idi_listen_req(eicon_card *card, eicon_chan *chan)
 {
-       if (DebugVar & 16)
-               printk(KERN_DEBUG"idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
+       if ((!card) || (!chan))
+               return 1;
+
+       eicon_log(card, 16, "idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
        if (!chan->e.D3Id) {
                idi_do_req(card, chan, ASSIGN, 0); 
        }
@@ -430,15 +453,19 @@ idi_si2bc(int si1, int si2, char *bc, char *hlc)
 int
 idi_hangup(eicon_card *card, eicon_chan *chan)
 {
+       if ((!card) || (!chan))
+               return 1;
+
        if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
            (chan->fsm_state == EICON_STATE_WMCONN)) {
                if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1);
        }
        if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
-       idi_do_req(card, chan, HANGUP, 0);
-       chan->fsm_state = EICON_STATE_NULL;
-       if (DebugVar & 8)
-               printk(KERN_DEBUG"idi_req: Ch%d: Hangup\n", chan->No);
+       if (chan->fsm_state != EICON_STATE_NULL) {
+               idi_do_req(card, chan, HANGUP, 0);
+               chan->fsm_state = EICON_STATE_NULL;
+       }
+       eicon_log(card, 8, "idi_req: Ch%d: Hangup\n", chan->No);
 #ifdef CONFIG_ISDN_TTY_FAX
        chan->fax = 0;
 #endif
@@ -448,14 +475,16 @@ idi_hangup(eicon_card *card, eicon_chan *chan)
 int
 idi_connect_res(eicon_card *card, eicon_chan *chan)
 {
+       if ((!card) || (!chan))
+               return 1;
+
        chan->fsm_state = EICON_STATE_IWAIT;
        idi_do_req(card, chan, CALL_RES, 0);
        
        /* check if old NetID has been removed */
        if (chan->e.B2Id) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err: Ch%d: Old NetID %x was not removed.\n",
-                               chan->No, chan->e.B2Id);
+               eicon_log(card, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
+                       chan->No, chan->e.B2Id);
                idi_do_req(card, chan, REMOVE, 1);
        }
 
@@ -478,12 +507,14 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
        eicon_REQ *reqbuf;
        eicon_chan_ptr *chan2;
 
+       if ((!card) || (!chan))
+               return 1;
+
         skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
+                       eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
                if (skb) 
                        dev_kfree_skb(skb);
                if (skb2) 
@@ -629,8 +660,7 @@ idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
        skb_queue_tail(&card->sndq, skb2); 
        eicon_schedule_tx(card);
 
-       if (DebugVar & 8)
-               printk(KERN_DEBUG"idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
+       eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
    return(0);
 }
 
@@ -647,9 +677,10 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
        __u16 code;
        isdn_ctrl cmd;
 
-  memset(message, 0, sizeof(idi_ind_message));
+       memset(message, 0, sizeof(idi_ind_message));
+
+       if ((!len) || (!buffer[pos])) return;
 
-  if ((!len) || (!buffer[pos])) return;
   while(pos <= len) {
        w = buffer[pos++];
        if (!w) return;
@@ -679,8 +710,18 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
                else code = w;
                code |= (codeset<<8);
 
+               if (pos + wlen > len) {
+                       eicon_log(ccard, 1, "idi_err: Ch%d: IElen %d of %x exceeds Ind_Length (+%d)\n", chan->No, 
+                                       wlen, code, (pos + wlen) - len);
+                       return;
+               }
+
                switch(code) {
                        case OAD:
+                               if (wlen > sizeof(message->oad)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                j = 1;
                                if (wlen) {
                                        message->plan = buffer[pos++];
@@ -693,11 +734,14 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
                                }
                                for(i=0; i < wlen-j; i++) 
                                        message->oad[i] = buffer[pos++];
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, 
-                                               message->plan, message->screen, message->oad);
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, 
+                                       message->plan, message->screen, message->oad);
                                break;
                        case RDN:
+                               if (wlen > sizeof(message->rdn)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                j = 1;
                                if (wlen) {
                                        if (!(buffer[pos++] & 0x80)) {
@@ -707,92 +751,116 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
                                }
                                for(i=0; i < wlen-j; i++) 
                                        message->rdn[i] = buffer[pos++];
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: RDN= %s\n", chan->No, 
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: RDN= %s\n", chan->No, 
                                                message->rdn);
                                break;
                        case CPN:
+                               if (wlen > sizeof(message->cpn)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->cpn[i] = buffer[pos++];
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
-                                               (__u8)message->cpn[0], message->cpn + 1);
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
+                                       (__u8)message->cpn[0], message->cpn + 1);
                                break;
                        case DSA:
+                               if (wlen > sizeof(message->dsa)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                pos += 2;
                                for(i=0; i < wlen-2; i++) 
                                        message->dsa[i] = buffer[pos++];
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
                                break;
                        case OSA:
+                               if (wlen > sizeof(message->osa)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                pos += 2;
                                for(i=0; i < wlen-2; i++) 
                                        message->osa[i] = buffer[pos++];
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
                                break;
                        case BC:
+                               if (wlen > sizeof(message->bc)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->bc[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
-                                               message->bc[0],message->bc[1],message->bc[2]);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
+                                       message->bc[0],message->bc[1],message->bc[2]);
                                break;
                        case 0x800|BC:
+                               if (wlen > sizeof(message->e_bc)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->e_bc[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
                                break;
                        case LLC:
+                               if (wlen > sizeof(message->llc)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->llc[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
-                                               message->llc[1],message->llc[2],message->llc[3]);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
+                                       message->llc[1],message->llc[2],message->llc[3]);
                                break;
                        case HLC:
+                               if (wlen > sizeof(message->hlc)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->hlc[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
-                                               message->hlc[0], message->hlc[1],
-                                               message->hlc[2], message->hlc[3], message->hlc[4]);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
+                                       message->hlc[0], message->hlc[1],
+                                       message->hlc[2], message->hlc[3], message->hlc[4]);
                                break;
                        case DSP:
                        case 0x600|DSP:
+                               if (wlen > sizeof(message->display)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->display[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: Display: %s\n", chan->No,
-                                               message->display);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: Display: %s\n", chan->No,
+                                       message->display);
                                break;
                        case 0x600|KEY:
+                               if (wlen > sizeof(message->keypad)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->keypad[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: Keypad: %s\n", chan->No,
-                                               message->keypad);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: Keypad: %s\n", chan->No,
+                                       message->keypad);
                                break;
                        case NI:
                        case 0x600|NI:
                                if (wlen) {
-                                       if (DebugVar & 4) {
-                                               switch(buffer[pos] & 127) {
-                                                       case 0:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: User suspended.\n", chan->No);
-                                                               break;
-                                                       case 1:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: User resumed.\n", chan->No);
-                                                               break;
-                                                       case 2:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Bearer service change.\n", chan->No);
-                                                               break;
-                                                       default:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Notification %x.\n", 
-                                                                               chan->No, buffer[pos] & 127);
-                                               }
+                                       switch(buffer[pos] & 127) {
+                                               case 0:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: User suspended.\n", chan->No);
+                                                       break;
+                                               case 1:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: User resumed.\n", chan->No);
+                                                       break;
+                                               case 2:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: Bearer service change.\n", chan->No);
+                                                       break;
+                                               default:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Notification %x.\n", 
+                                                                       chan->No, buffer[pos] & 127);
                                        }
                                        pos += wlen;
                                }
@@ -800,80 +868,91 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
                        case PI:
                        case 0x600|PI:
                                if (wlen > 1) {
-                                       if (DebugVar & 4) {
-                                               switch(buffer[pos+1] & 127) {
-                                                       case 1:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
-                                                               break;
-                                                       case 2:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
-                                                               break;
-                                                       case 3:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
-                                                               break;
-                                                       case 4:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
-                                                               break;
-                                                       case 5:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
-                                                               break;
-                                                       case 8:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: In-band information available.\n", chan->No);
-                                                               break;
-                                                       default:
-                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Progress %x.\n", 
-                                                                               chan->No, buffer[pos+1] & 127);
-                                               }
+                                       switch(buffer[pos+1] & 127) {
+                                               case 1:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
+                                                       break;
+                                               case 2:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
+                                                       break;
+                                               case 3:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
+                                                       break;
+                                               case 4:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
+                                                       break;
+                                               case 5:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
+                                                       break;
+                                               case 8:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: In-band information available.\n", chan->No);
+                                                       break;
+                                               default:
+                                                       eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Progress %x.\n", 
+                                                                       chan->No, buffer[pos+1] & 127);
                                        }
                                }
                                pos += wlen;
                                break;
                        case CAU:
+                               if (wlen > sizeof(message->cau)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->cau[i] = buffer[pos++];
                                memcpy(&chan->cause, &message->cau, 2);
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: CAU=%d %d\n", chan->No,
-                                               message->cau[0],message->cau[1]);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: CAU=%d %d\n", chan->No,
+                                       message->cau[0],message->cau[1]);
                                break;
                        case 0x800|CAU:
+                               if (wlen > sizeof(message->e_cau)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->e_cau[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
-                                               message->e_cau[0],message->e_cau[1]);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
+                                       message->e_cau[0],message->e_cau[1]);
                                break;
                        case 0x800|CHI:
+                               if (wlen > sizeof(message->e_chi)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->e_chi[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
-                                               message->e_cau[0]);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
+                                       message->e_cau[0]);
                                break;
                        case 0x800|0x7a:
                                pos ++;
                                message->e_mt=buffer[pos++];
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
                                break;
                        case DT:
+                               if (wlen > sizeof(message->dt)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->dt[i] = buffer[pos++];
-                               if (DebugVar & 4)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
-                                               message->dt[2], message->dt[1], message->dt[0],
-                                               message->dt[3], message->dt[4], message->dt[5]);
+                               eicon_log(ccard, 4, "idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
+                                       message->dt[2], message->dt[1], message->dt[0],
+                                       message->dt[3], message->dt[4], message->dt[5]);
                                break;
                        case 0x600|SIN:
+                               if (wlen > sizeof(message->sin)) {
+                                       pos += wlen;
+                                       break;
+                               }
                                for(i=0; i < wlen; i++) 
                                        message->sin[i] = buffer[pos++];
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: SIN=%d %d\n", chan->No,
-                                               message->sin[0],message->sin[1]);
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: SIN=%d %d\n", chan->No,
+                                       message->sin[0],message->sin[1]);
                                break;
                        case 0x600|CPS:
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
                                pos += wlen;
                                break;
                        case 0x600|CIF:
@@ -881,8 +960,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
                                        if (buffer[pos + i] != '0') break;
                                memcpy(&cmd.parm.num, &buffer[pos + i], wlen - i);
                                cmd.parm.num[wlen - i] = 0;
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
                                pos += wlen;
                                cmd.driver = ccard->myid;
                                cmd.command = ISDN_STAT_CINF;
@@ -890,8 +968,11 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
                                ccard->interface.statcallb(&cmd);
                                break;
                        case 0x600|DATE:
-                               if (DebugVar & 2)
-                                       printk(KERN_DEBUG"idi_inf: Ch%d: Date in ind\n", chan->No);
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: Date in ind\n", chan->No);
+                               pos += wlen;
+                               break;
+                       case 0xa1: 
+                               eicon_log(ccard, 2, "idi_inf: Ch%d: Sending Complete in ind.\n", chan->No);
                                pos += wlen;
                                break;
                        case 0xe08: 
@@ -911,8 +992,7 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
                        case 0x880:
                                /* Managment Information Element */
                                if (!manbuf) {
-                                       if (DebugVar & 1)
-                                               printk(KERN_WARNING"idi_err: manbuf not allocated\n");
+                                       eicon_log(ccard, 1, "idi_err: manbuf not allocated\n");
                                }
                                else {
                                        memcpy(&manbuf->data[manbuf->pos], &buffer[pos], wlen);
@@ -924,9 +1004,8 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
                                break;
                        default:
                                pos += wlen;
-                               if (DebugVar & 6)
-                                       printk(KERN_WARNING"idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", 
-                                               chan->No, code, wlen);
+                               eicon_log(ccard, 6, "idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", 
+                                       chan->No, code, wlen);
                }
        }
   }
@@ -967,110 +1046,1095 @@ idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned ch
 int
 idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer)
 {
+       eicon_t30_s     *t30 = (eicon_t30_s *) buffer;
 
-       /* TODO , code follows */
+       if (!chan->fax) {
+               eicon_log(NULL, 1,"idi_T30: fill_in with NULL fax struct, ERROR\n");
+               return 0;
+       }
+       memset(t30, 0, sizeof(eicon_t30_s));
+       t30->station_id_len = EICON_FAXID_LEN;
+       memcpy(&t30->station_id[0], &chan->fax->id[0], EICON_FAXID_LEN);
+       t30->resolution = chan->fax->resolution;
+       t30->rate = chan->fax->rate + 1;        /* eicon rate starts with 1 */
+       t30->format = T30_FORMAT_SFF;
+       t30->pages_low = 0;
+       t30->pages_high = 0;
+       t30->atf = 1;                           /* optimised for AT+F command set */
+       t30->code = 0;
+       t30->feature_bits_low = 0;
+       t30->feature_bits_high = 0;
+       t30->control_bits_low = 0;
+       t30->control_bits_high = 0;
+
+       if (chan->fax->nbc) {
+               /* set compression by DCC value */
+         switch(chan->fax->compression) {
+               case (0):       /* 1-D modified */
+                       break;
+               case (1):       /* 2-D modified Read */
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+                       break;
+               case (2):       /* 2-D uncompressed */
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+                       break;
+               case (3):       /* 2-D modified Read */
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+                       break;
+         }
+       } else {
+               /* set compression to best */
+               t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
+               t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+               t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+               t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+               t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
+               t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+               t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+               t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+       }
+       switch(chan->fax->ecm) {
+               case (0):       /* disable ECM */
+                       break;
+               case (1):
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+                       t30->control_bits_low |= T30_CONTROL_BIT_ECM_64_BYTES;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_ECM_64_BYTES;
+                       break;
+               case (2):
+                       t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+                       t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+                       break;
+       }
 
-       return(0);
+       if (DebugVar & 128) {
+               char st[40];
+               eicon_log(NULL, 128, "sT30:code = %x\n", t30->code);
+               eicon_log(NULL, 128, "sT30:rate = %x\n", t30->rate);
+               eicon_log(NULL, 128, "sT30:res  = %x\n", t30->resolution);
+               eicon_log(NULL, 128, "sT30:format = %x\n", t30->format);
+               eicon_log(NULL, 128, "sT30:pages_low = %x\n", t30->pages_low);
+               eicon_log(NULL, 128, "sT30:pages_high = %x\n", t30->pages_high);
+               eicon_log(NULL, 128, "sT30:atf  = %x\n", t30->atf);
+               eicon_log(NULL, 128, "sT30:control_bits_low = %x\n", t30->control_bits_low);
+               eicon_log(NULL, 128, "sT30:control_bits_high = %x\n", t30->control_bits_high);
+               eicon_log(NULL, 128, "sT30:feature_bits_low = %x\n", t30->feature_bits_low);
+               eicon_log(NULL, 128, "sT30:feature_bits_high = %x\n", t30->feature_bits_high);
+               //eicon_log(NULL, 128, "sT30:universal_5 = %x\n", t30->universal_5);
+               //eicon_log(NULL, 128, "sT30:universal_6 = %x\n", t30->universal_6);
+               //eicon_log(NULL, 128, "sT30:universal_7 = %x\n", t30->universal_7);
+               eicon_log(NULL, 128, "sT30:station_id_len = %x\n", t30->station_id_len);
+               eicon_log(NULL, 128, "sT30:head_line_len = %x\n", t30->head_line_len);
+               strncpy(st, t30->station_id, t30->station_id_len);
+               st[t30->station_id_len] = 0;
+               eicon_log(NULL, 128, "sT30:station_id = <%s>\n", st);
+       }
+       return(sizeof(eicon_t30_s));
 }
 
 /* send fax struct */
 int
 idi_send_edata(eicon_card *card, eicon_chan *chan)
 {
+       struct sk_buff *skb;
+       struct sk_buff *skb2;
+       eicon_REQ *reqbuf;
+       eicon_chan_ptr *chan2;
+
+       if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
+               eicon_log(card, 1, "idi_snd: Ch%d: send edata on state %d !\n", chan->No, chan->fsm_state);
+               return -ENODEV;
+       }
+       eicon_log(card, 128, "idi_snd: Ch%d: edata (fax)\n", chan->No);
 
-       /* TODO , code follows */
+       skb = alloc_skb(sizeof(eicon_REQ) + sizeof(eicon_t30_s), GFP_ATOMIC);
+       skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
+       if ((!skb) || (!skb2)) {
+               eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_edata()\n", chan->No);
+               if (skb) 
+                       dev_kfree_skb(skb);
+               if (skb2) 
+                       dev_kfree_skb(skb2);
+               return -ENOMEM;
+       }
+
+       chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+       chan2->ptr = chan;
+
+       reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
+
+       reqbuf->Req = IDI_N_EDATA;
+       reqbuf->ReqCh = 0;
+       reqbuf->ReqId = 1;
+
+       reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P);
+       reqbuf->Reference = 1; /* Net Entity */
+
+       skb_queue_tail(&chan->e.X, skb);
+       skb_queue_tail(&card->sndq, skb2);
+       eicon_schedule_tx(card);
        return (0);
 }
 
 void
 idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
 {
+       eicon_t30_s *p = (eicon_t30_s *)buffer;
+       int i;
 
-       /* TODO , code follows */
+       if (DebugVar & 128) {
+               char st[40];
+               eicon_log(ccard, 128, "rT30:len %d , size %d\n", len, sizeof(eicon_t30_s));
+               eicon_log(ccard, 128, "rT30:code = %x\n", p->code);
+               eicon_log(ccard, 128, "rT30:rate = %x\n", p->rate);
+               eicon_log(ccard, 128, "rT30:res  = %x\n", p->resolution);
+               eicon_log(ccard, 128, "rT30:format = %x\n", p->format);
+               eicon_log(ccard, 128, "rT30:pages_low = %x\n", p->pages_low);
+               eicon_log(ccard, 128, "rT30:pages_high = %x\n", p->pages_high);
+               eicon_log(ccard, 128, "rT30:atf  = %x\n", p->atf);
+               eicon_log(ccard, 128, "rT30:control_bits_low = %x\n", p->control_bits_low);
+               eicon_log(ccard, 128, "rT30:control_bits_high = %x\n", p->control_bits_high);
+               eicon_log(ccard, 128, "rT30:feature_bits_low = %x\n", p->feature_bits_low);
+               eicon_log(ccard, 128, "rT30:feature_bits_high = %x\n", p->feature_bits_high);
+               //eicon_log(ccard, 128, "rT30:universal_5 = %x\n", p->universal_5);
+               //eicon_log(ccard, 128, "rT30:universal_6 = %x\n", p->universal_6);
+               //eicon_log(ccard, 128, "rT30:universal_7 = %x\n", p->universal_7);
+               eicon_log(ccard, 128, "rT30:station_id_len = %x\n", p->station_id_len);
+               eicon_log(ccard, 128, "rT30:head_line_len = %x\n", p->head_line_len);
+               strncpy(st, p->station_id, p->station_id_len);
+               st[p->station_id_len] = 0;
+               eicon_log(ccard, 128, "rT30:station_id = <%s>\n", st);
+       }
+       if (!chan->fax) {
+               eicon_log(ccard, 1, "idi_edata: parse to NULL fax struct, ERROR\n");
+               return;
+       }
+       chan->fax->code = p->code;
+       i = (p->station_id_len < FAXIDLEN) ? p->station_id_len : (FAXIDLEN - 1);
+       memcpy(chan->fax->r_id, p->station_id, i);
+       chan->fax->r_id[i] = 0;
+       chan->fax->r_resolution = p->resolution;
+       chan->fax->r_rate = p->rate - 1;
+       chan->fax->r_binary = 0; /* no binary support */
+       chan->fax->r_width = 0;
+       chan->fax->r_length = 2;
+       chan->fax->r_scantime = 0;
+       chan->fax->r_compression = 0;
+       chan->fax->r_ecm = 0;
+       if (p->feature_bits_low & T30_FEATURE_BIT_2D_CODING) {
+               chan->fax->r_compression = 1;
+               if (p->feature_bits_low & T30_FEATURE_BIT_UNCOMPR_ENABLED) {
+                       chan->fax->r_compression = 2;
+               }
+       }
+       if (p->feature_bits_low & T30_FEATURE_BIT_T6_CODING) {
+               chan->fax->r_compression = 3;
+       }
 
+       if (p->feature_bits_low & T30_FEATURE_BIT_ECM) {
+               chan->fax->r_ecm = 2;
+               if (p->feature_bits_low & T30_FEATURE_BIT_ECM_64_BYTES)
+                       chan->fax->r_ecm = 1;
+       }
 }
 
 void
 idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header)
 {
+       static __u16 wd2sff[] = {
+               1728, 2048, 2432, 1216, 864
+       };
+       static __u16 ln2sff[2][3] = {
+               { 1143, 1401, 0 } , { 2287, 2802, 0 }
+       };
+       struct sk_buff *skb;
+       eicon_sff_dochead *doc;
+       eicon_sff_pagehead *page;
+       u_char *docp;
 
-       /* TODO , code follows */
+       if (!chan->fax) {
+               eicon_log(card, 1, "idi_fax: send head with NULL fax struct, ERROR\n");
+               return;
+       }
+       if (header == 2) { /* DocHeader + PageHeader */
+               skb = alloc_skb(sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead), GFP_ATOMIC);
+       } else {
+               skb = alloc_skb(sizeof(eicon_sff_pagehead), GFP_ATOMIC);
+       }
+       if (!skb) {
+               eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_header()\n", chan->No);
+               return;
+       }
+
+       if (header == 2) { /* DocHeader + PageHeader */
+               docp = skb_put(skb, sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead));
+               doc = (eicon_sff_dochead *) docp;
+               page = (eicon_sff_pagehead *) (docp + sizeof(eicon_sff_dochead));
+               memset(docp, 0,sizeof(eicon_sff_dochead)  + sizeof(eicon_sff_pagehead));
+               doc->id = 0x66666653;
+               doc->version = 0x01;
+               doc->off1pagehead = sizeof(eicon_sff_dochead);
+       } else {
+               page = (eicon_sff_pagehead *)skb_put(skb, sizeof(eicon_sff_pagehead));
+               memset(page, 0, sizeof(eicon_sff_pagehead));
+       }
 
+       switch(header) {
+               case 1: /* PageHeaderEnd */
+                       page->pageheadid = 254;
+                       page->pageheadlen = 0; 
+                       break;
+               case 0: /* PageHeader */
+               case 2: /* DocHeader + PageHeader */
+                       page->pageheadid = 254;
+                       page->pageheadlen = sizeof(eicon_sff_pagehead) - 2;
+                       page->resvert = chan->fax->resolution;
+                       page->reshoriz = 0; /* always 203 dpi */
+                       page->coding = 0; /* always 1D */
+                       page->linelength = wd2sff[chan->fax->width];
+                       page->pagelength = ln2sff[chan->fax->resolution][chan->fax->length]; 
+                       eicon_log(card, 128, "sSFF-Head: linelength = %d\n", page->linelength);
+                       eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength);
+                       break;
+       }
+       idi_send_data(card, chan, 0, skb, 0);
 }
 
 void
 idi_fax_cmd(eicon_card *card, eicon_chan *chan) 
 {
+       isdn_ctrl cmd;
+
+       if ((!card) || (!chan))
+               return;
 
-       /* TODO , code follows */
+       if (!chan->fax) {
+               eicon_log(card, 1, "idi_fax: cmd with NULL fax struct, ERROR\n");
+               return;
+       }
+       switch (chan->fax->code) {
+               case ISDN_TTY_FAX_DT:
+                       if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+                               idi_send_edata(card, chan);
+                               break;
+                       }
+                       if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+                               idi_send_edata(card, chan);
+                               break;
+                       }
+                       break;
+
+               case ISDN_TTY_FAX_DR:
+                       if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+                               idi_send_edata(card, chan);
+
+                               cmd.driver = card->myid;
+                               cmd.command = ISDN_STAT_FAXIND;
+                               cmd.arg = chan->No;
+                               chan->fax->r_code = ISDN_TTY_FAX_CFR;
+                               card->interface.statcallb(&cmd);
+
+                               cmd.driver = card->myid;
+                               cmd.command = ISDN_STAT_FAXIND;
+                               cmd.arg = chan->No;
+                               chan->fax->r_code = ISDN_TTY_FAX_RID;
+                               card->interface.statcallb(&cmd);
+
+                               /* telling 1-D compression */
+                               chan->fax->r_compression = 0;
+                               cmd.driver = card->myid;
+                               cmd.command = ISDN_STAT_FAXIND;
+                               cmd.arg = chan->No;
+                               chan->fax->r_code = ISDN_TTY_FAX_DCS;
+                               card->interface.statcallb(&cmd);
 
+                               chan->fax2.NextObject = FAX_OBJECT_DOCU;
+                               chan->fax2.PrevObject = FAX_OBJECT_DOCU;
+
+                               break;
+                       }
+                       if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+                               idi_send_edata(card, chan);
+                               break;
+                       }
+                       break;
+
+               case ISDN_TTY_FAX_ET:
+                               switch(chan->fax->fet) {
+                                       case 0:
+                                       case 1:
+                                               idi_fax_send_header(card, chan, 0);
+                                               break;
+                                       case 2:
+                                               idi_fax_send_header(card, chan, 1);
+                                               break;
+                               }
+                       break;
+       }
 }
 
 void
 idi_edata_rcveop(eicon_card *card, eicon_chan *chan)
 {
+       isdn_ctrl cmd;
 
-       /* TODO , code follows */
-
+       if (!chan->fax) {
+               eicon_log(card, 1, "idi_edata: rcveop with NULL fax struct, ERROR\n");
+               return;
+       }
+       cmd.driver = card->myid;
+       cmd.command = ISDN_STAT_FAXIND;
+       cmd.arg = chan->No;
+       chan->fax->r_code = ISDN_TTY_FAX_ET;
+       card->interface.statcallb(&cmd);
 }
 
 void
 idi_reset_fax_stat(eicon_chan *chan)
 {
-
-       /* TODO , code follows */
-
+       chan->fax2.LineLen = 0;
+       chan->fax2.LineData = 0;
+       chan->fax2.LineDataLen = 0;
+       chan->fax2.NullByteExist = 0;
+       chan->fax2.Dle = 0;
+       chan->fax2.PageCount = 0;
+       chan->fax2.Eop = 0;
 }
 
 void
 idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
 {
+       isdn_ctrl cmd;
+
+       if (!chan->fax) {
+               eicon_log(ccard, 1, "idi_edata: action with NULL fax struct, ERROR\n");
+               return;
+       }
+       if (chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) {
+               idi_parse_edata(ccard, chan, buffer, len);
+
+               if (chan->fax->phase == ISDN_FAX_PHASE_A) {
+                       idi_reset_fax_stat(chan);
+
+                       chan->fsm_state = EICON_STATE_ACTIVE;
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_BCONN;
+                       cmd.arg = chan->No;
+                       ccard->interface.statcallb(&cmd);
+
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_FAXIND;
+                       cmd.arg = chan->No;
+                       chan->fax->r_code = ISDN_TTY_FAX_FCON;
+                       ccard->interface.statcallb(&cmd);
+
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_FAXIND;
+                       cmd.arg = chan->No;
+                       chan->fax->r_code = ISDN_TTY_FAX_RID;
+                       ccard->interface.statcallb(&cmd);
+
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_FAXIND;
+                       cmd.arg = chan->No;
+                       chan->fax->r_code = ISDN_TTY_FAX_DIS;
+                       ccard->interface.statcallb(&cmd);
+
+                       if (chan->fax->r_compression != 0) {
+                       /* telling fake compression in second DIS message */
+                               chan->fax->r_compression = 0;
+                               cmd.driver = ccard->myid;
+                               cmd.command = ISDN_STAT_FAXIND;
+                               cmd.arg = chan->No;
+                               chan->fax->r_code = ISDN_TTY_FAX_DIS;
+                               ccard->interface.statcallb(&cmd);
+                       }
+
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_FAXIND;
+                       cmd.arg = chan->No;
+                       chan->fax->r_code = ISDN_TTY_FAX_SENT; /* OK message */
+                       ccard->interface.statcallb(&cmd);
+               } else
+               if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+
+                       if ((chan->fax->code == EDATA_T30_MCF) &&
+                           (chan->fax->fet != 2)) {
+                               cmd.driver = ccard->myid;
+                               cmd.command = ISDN_STAT_FAXIND;
+                               cmd.arg = chan->No;
+                               chan->fax->r_code = ISDN_TTY_FAX_PTS;
+                               ccard->interface.statcallb(&cmd);
+                       }
+
+                       switch(chan->fax->fet) {
+                               case 0: /* new page */
+                                       /* stay in phase D , wait on cmd +FDT */
+                                       break;
+                               case 1: /* new document */
+                                       /* link-level switch to phase B */
+                                       break;
+                               case 2: /* session end */
+                               default:
+                                       /* idi_send_edata(ccard, chan); */
+                                       break;
+                       }
+               }
+       }
+
+       if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+               idi_parse_edata(ccard, chan, buffer, len);
+
+               if ((chan->fax->code == EDATA_T30_DCS) &&
+                   (chan->fax->phase == ISDN_FAX_PHASE_A)) {
+                       idi_reset_fax_stat(chan);
+
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_BCONN;
+                       cmd.arg = chan->No;
+                       ccard->interface.statcallb(&cmd);
 
-       /* TODO , code follows */
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_FAXIND;
+                       cmd.arg = chan->No;
+                       chan->fax->r_code = ISDN_TTY_FAX_FCON_I;
+                       ccard->interface.statcallb(&cmd);
+               } else
+               if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
+                   (chan->fax->phase == ISDN_FAX_PHASE_A)) {
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_FAXIND;
+                       cmd.arg = chan->No;
+                       chan->fax->r_code = ISDN_TTY_FAX_RID;
+                       ccard->interface.statcallb(&cmd);
 
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_FAXIND;
+                       cmd.arg = chan->No;
+                       chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
+                       ccard->interface.statcallb(&cmd);
+               } else
+               if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
+                   (chan->fax->phase == ISDN_FAX_PHASE_B)) {
+                       cmd.driver = ccard->myid;
+                       cmd.command = ISDN_STAT_FAXIND;
+                       cmd.arg = chan->No;
+                       chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
+                       ccard->interface.statcallb(&cmd);
+               } else
+               if (chan->fax->phase == ISDN_FAX_PHASE_C) {
+                       switch(chan->fax->code) {
+                               case EDATA_T30_TRAIN_OK:
+                                       idi_send_edata(ccard, chan);
+                                       break;
+                               case EDATA_T30_MPS:
+                                       chan->fax->fet = 0;
+                                       idi_edata_rcveop(ccard, chan);
+                                       break;
+                               case EDATA_T30_EOM:
+                                       chan->fax->fet = 1;
+                                       idi_edata_rcveop(ccard, chan);
+                                       break;
+                               case EDATA_T30_EOP:
+                                       chan->fax->fet = 2;
+                                       idi_edata_rcveop(ccard, chan);
+                                       break;
+                       }
+               }
+       }
 }
 
 void
 fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len)
 {
-
-       /* TODO , code follows */
-
+       struct sk_buff *skb;
+       
+        skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC);
+       if (!skb) {
+               eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_put_rcv()\n", chan->No);
+               return;
+       }
+       skb_reserve(skb, MAX_HEADER_LEN);
+       memcpy(skb_put(skb, len), Data, len);
+       ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
 }
 
 void
 idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
 {
+       eicon_OBJBUFFER InBuf;
+       eicon_OBJBUFFER LineBuf;
+       unsigned int Length = 0;
+       unsigned int aLength = 0;
+       unsigned int ObjectSize = 0;
+       unsigned int ObjHeadLen = 0;
+       unsigned int ObjDataLen = 0;
+       __u8 Recordtype;
+       __u8 PageHeaderLen;     
+       __u8 Event;
+       eicon_sff_pagehead *ob_page;
+
+       __u16 Cl2Eol = 0x8000;
+
+#      define EVENT_NONE       0
+#      define EVENT_NEEDDATA   1
+
+       if (!chan->fax) {
+               eicon_log(ccard, 1, "idi_fax: rcvdata with NULL fax struct, ERROR\n");
+               return;
+       }
+
+
+       
+       if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+               InBuf.Data = skb->data;
+               InBuf.Size = skb->len;
+               InBuf.Len  = 0;
+               InBuf.Next = InBuf.Data;
+               LineBuf.Data = chan->fax2.abLine;
+               LineBuf.Size = sizeof(chan->fax2.abLine);
+               LineBuf.Len  = chan->fax2.LineLen;
+               LineBuf.Next = LineBuf.Data + LineBuf.Len;
+
+               Event = EVENT_NONE;
+               while (Event == EVENT_NONE) {
+                       switch(chan->fax2.NextObject) {
+                               case FAX_OBJECT_DOCU:
+                                               Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+                                               if (Length < sizeof(eicon_sff_dochead)) {
+                                                       Event = EVENT_NEEDDATA;
+                                                       break;
+                                               }
+                                               ObjectSize = sizeof(eicon_sff_dochead);
+                                               Length = ObjectSize;
+                                               if (LineBuf.Len < Length) {
+                                                       Length -= LineBuf.Len;
+                                                       LineBuf.Len = 0;
+                                                       LineBuf.Next = LineBuf.Data;
+                                                       InBuf.Len += Length;
+                                                       InBuf.Next += Length;
+                                               } else {
+                                                       LineBuf.Len -= Length;
+                                                       LineBuf.Next = LineBuf.Data + LineBuf.Len;
+                                                       memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+                                               }
+                                               chan->fax2.PrevObject = FAX_OBJECT_DOCU;
+                                               chan->fax2.NextObject = FAX_OBJECT_PAGE;
+                                       break;
+
+                               case FAX_OBJECT_PAGE:
+                                               Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+                                               if (Length < 2) {
+                                                       Event = EVENT_NEEDDATA;
+                                                       break;
+                                               }
+                                               if (LineBuf.Len == 0) {
+                                                       *LineBuf.Next++ = *InBuf.Next++;
+                                                       LineBuf.Len++;
+                                                       InBuf.Len++;
+                                               }
+                                               if (LineBuf.Len == 1) {
+                                                       *LineBuf.Next++ = *InBuf.Next++;
+                                                       LineBuf.Len++;
+                                                       InBuf.Len++;
+                                               }
+                                               PageHeaderLen = *(LineBuf.Data + 1);
+                                               ObjectSize = (PageHeaderLen == 0) ? 2 : sizeof(eicon_sff_pagehead);
+                                               if (Length < ObjectSize) {
+                                                       Event = EVENT_NEEDDATA;
+                                                       break;
+                                               }
+                                               Length = ObjectSize;
+                                               /* extract page dimensions */
+                                               if (LineBuf.Len < Length) {
+                                                       aLength = Length - LineBuf.Len;
+                                                       memcpy(LineBuf.Next, InBuf.Next, aLength);
+                                                       LineBuf.Next += aLength;
+                                                       InBuf.Next += aLength;
+                                                       LineBuf.Len += aLength;
+                                                       InBuf.Len += aLength;
+                                               }
+                                               if (Length > 2) {
+                                                       ob_page = (eicon_sff_pagehead *)LineBuf.Data;
+                                                       switch(ob_page->linelength) {
+                                                               case 2048:
+                                                                       chan->fax->r_width = 1;
+                                                                       break;
+                                                               case 2432:
+                                                                       chan->fax->r_width = 2;
+                                                                       break;
+                                                               case 1216:
+                                                                       chan->fax->r_width = 3;
+                                                                       break;
+                                                               case 864:
+                                                                       chan->fax->r_width = 4;
+                                                                       break;
+                                                               case 1728:
+                                                               default:
+                                                                       chan->fax->r_width = 0;
+                                                       }
+                                                       switch(ob_page->pagelength) {
+                                                               case 1143:
+                                                               case 2287:
+                                                                       chan->fax->r_length = 0;
+                                                                       break;
+                                                               case 1401:
+                                                               case 2802:
+                                                                       chan->fax->r_length = 1;
+                                                                       break;
+                                                               default:
+                                                                       chan->fax->r_length = 2;
+                                                       }
+                                                       eicon_log(ccard, 128, "rSFF-Head: linelength = %d\n", ob_page->linelength);
+                                                       eicon_log(ccard, 128, "rSFF-Head: pagelength = %d\n", ob_page->pagelength);
+                                               }
+                                               LineBuf.Len -= Length;
+                                               LineBuf.Next = LineBuf.Data + LineBuf.Len;
+                                               memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+
+                                               chan->fax2.PrevObject = FAX_OBJECT_PAGE;
+                                               chan->fax2.NextObject = FAX_OBJECT_LINE;
+                                       break;
+
+                               case FAX_OBJECT_LINE:
+                                               Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+                                               if (Length < 1) {
+                                                       Event = EVENT_NEEDDATA;
+                                                       break;
+                                               }
+                                               if (LineBuf.Len == 0) {
+                                                       *LineBuf.Next++ = *InBuf.Next++;
+                                                       LineBuf.Len++;
+                                                       InBuf.Len++;
+                                               }
+                                               Recordtype = *LineBuf.Data;
+                                               if (Recordtype == 0) {
+                                                       /* recordtype pixel row (2 byte length) */
+                                                       ObjHeadLen = 3;
+                                                       if (Length < ObjHeadLen) {
+                                                               Event = EVENT_NEEDDATA;
+                                                               break;
+                                                       }
+                                                       while (LineBuf.Len < ObjHeadLen) {
+                                                               *LineBuf.Next++ = *InBuf.Next++;
+                                                               LineBuf.Len++;
+                                                               InBuf.Len++;
+                                                       }
+                                                       ObjDataLen = *((__u16*) (LineBuf.Data + 1));
+                                                       ObjectSize = ObjHeadLen + ObjDataLen;
+                                                       if (Length < ObjectSize) {
+                                                               Event = EVENT_NEEDDATA;
+                                                               break;
+                                                       }
+                                               } else
+                                               if ((Recordtype >= 1) && (Recordtype <= 216)) {
+                                                       /* recordtype pixel row (1 byte length) */
+                                                       ObjHeadLen = 1;
+                                                       ObjDataLen = Recordtype;
+                                                       ObjectSize = ObjHeadLen + ObjDataLen;
+                                                       if (Length < ObjectSize) {
+                                                               Event = EVENT_NEEDDATA;
+                                                               break;
+                                                       }
+                                               } else
+                                               if ((Recordtype >= 217) && (Recordtype <= 253)) {
+                                                       /* recordtype empty lines */
+                                                       ObjHeadLen = 1;
+                                                       ObjDataLen = 0;
+                                                       ObjectSize = ObjHeadLen + ObjDataLen;
+                                                       LineBuf.Len--;
+                                                       LineBuf.Next = LineBuf.Data + LineBuf.Len;
+                                                       memmove(LineBuf.Data, LineBuf.Data + 1, LineBuf.Len);
+                                                       break;
+                                               } else
+                                               if (Recordtype == 254) {
+                                                       /* recordtype page header */
+                                                       chan->fax2.PrevObject = FAX_OBJECT_LINE;
+                                                       chan->fax2.NextObject = FAX_OBJECT_PAGE;
+                                                       break;
+                                               } else {
+                                                       /* recordtype user information */
+                                                       ObjHeadLen = 2;
+                                                       if (Length < ObjHeadLen) {
+                                                               Event = EVENT_NEEDDATA;
+                                                               break;
+                                                       }
+                                                       while (LineBuf.Len < ObjHeadLen) {
+                                                               *LineBuf.Next++ = *InBuf.Next++;
+                                                               LineBuf.Len++;
+                                                               InBuf.Len++;
+                                                       }
+                                                       ObjDataLen = *(LineBuf.Data + 1);
+                                                       ObjectSize = ObjHeadLen + ObjDataLen;
+                                                       if (ObjDataLen == 0) {
+                                                               /* illegal line coding */
+                                                               LineBuf.Len -= ObjHeadLen;
+                                                               LineBuf.Next = LineBuf.Data + LineBuf.Len;
+                                                               memmove(LineBuf.Data, LineBuf.Data + ObjHeadLen, LineBuf.Len);
+                                                               break;
+                                                       } else {
+                                                               /* user information */
+                                                               if (Length < ObjectSize) {
+                                                                       Event = EVENT_NEEDDATA;
+                                                                       break;
+                                                               }
+                                                               Length = ObjectSize;
+                                                               if (LineBuf.Len < Length) {
+                                                                       Length -= LineBuf.Len;
+                                                                       LineBuf.Len = 0;
+                                                                       LineBuf.Next = LineBuf.Data;
+                                                                       InBuf.Len += Length;
+                                                                       InBuf.Next += Length;
+                                                               } else {
+                                                                       LineBuf.Len -= Length;
+                                                                       LineBuf.Next = LineBuf.Data + LineBuf.Len;
+                                                                       memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+                                                               }
+                                                       }
+                                                       break;  
+                                               }
+                                               Length = ObjectSize;
+                                               if (LineBuf.Len > ObjHeadLen) {
+                                                       fax_put_rcv(ccard, chan, LineBuf.Data + ObjHeadLen,
+                                                                       (LineBuf.Len - ObjHeadLen));
+                                               }
+                                               Length -= LineBuf.Len;
+                                               LineBuf.Len = 0;
+                                               LineBuf.Next = LineBuf.Data;
+                                               if (Length > 0) {
+                                                       fax_put_rcv(ccard, chan, InBuf.Next, Length);
+                                                       InBuf.Len += Length;
+                                                       InBuf.Next += Length;
+                                               }
+                                               fax_put_rcv(ccard, chan, (__u8 *)&Cl2Eol, sizeof(Cl2Eol));
+                                       break;
+                       } /* end of switch (chan->fax2.NextObject) */
+               } /* end of while (Event==EVENT_NONE) */
+               if (InBuf.Len < InBuf.Size) {
+                       Length = InBuf.Size - InBuf.Len;
+                       if ((LineBuf.Len + Length) > LineBuf.Size) {
+                               eicon_log(ccard, 1, "idi_fax: Ch%d: %d bytes dropping, small buffer\n", chan->No,
+                                       Length);
+                               } else {
+                                       memcpy(LineBuf.Next, InBuf.Next, Length);
+                                       LineBuf.Len += Length;
+                               }
+               }
+               chan->fax2.LineLen = LineBuf.Len;
+       } else { /* CONN_OUT */
+               /* On CONN_OUT we do not need incoming data, drop it */
+               /* maybe later for polling */
+       }
 
-       /* TODO , code follows */
+#      undef EVENT_NONE
+#      undef EVENT_NEEDDATA
 
+       return;
 }
 
 int
 idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf)
 {
+       struct sk_buff *skb;
+
+       skb = alloc_skb(OutBuf->Len, GFP_ATOMIC);
+       if (!skb) {
+               eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_outbuf()\n", chan->No);
+               return(-1);
+       }
+       memcpy(skb_put(skb, OutBuf->Len), OutBuf->Data, OutBuf->Len);
 
-       /* TODO , code follows */
+       OutBuf->Len = 0;
+       OutBuf->Next = OutBuf->Data;
 
-       return(0);
+       return(idi_send_data(ccard, chan, 0, skb, 1));
 }
 
 int
 idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
 {
+       isdn_ctrl cmd;
+       eicon_OBJBUFFER InBuf;
+       __u8 InData;
+       __u8 InMask;
+       eicon_OBJBUFFER OutBuf;
+       eicon_OBJBUFFER LineBuf;
+       __u32 LineData;
+       unsigned int LineDataLen;
+       __u8 Byte;
+       __u8 Event;
+       int ret = 1;
+
+#      define EVENT_NONE       0
+#      define EVENT_EOD        1
+#      define EVENT_EOL        2
+#      define EVENT_EOP        3
+
+       if ((!ccard) || (!chan))
+               return -1;
 
-       /* TODO , code follows */
+       if (!chan->fax) {
+               eicon_log(ccard, 1, "idi_fax: senddata with NULL fax struct, ERROR\n");
+               return -1;
+       }
 
-       return(0);
+       if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+               /* Simply ignore any data written in data mode when receiving a fax.    */
+               /* This is not completely correct because only XON's should come here.  */
+               dev_kfree_skb(skb);
+               return 1;
+       }
+
+       if (chan->fax->phase != ISDN_FAX_PHASE_C) {
+               dev_kfree_skb(skb);
+               return 1;
+       }
+
+        if (chan->queued + skb->len > 1200)
+                return 0;
+
+       InBuf.Data = skb->data;
+       InBuf.Size = skb->len;
+       InBuf.Len  = 0;
+       InBuf.Next = InBuf.Data;
+       InData = 0;
+       InMask = 0;
+
+       LineBuf.Data = chan->fax2.abLine;
+       LineBuf.Size = sizeof(chan->fax2.abLine);
+       LineBuf.Len  = chan->fax2.LineLen;
+       LineBuf.Next = LineBuf.Data + LineBuf.Len;
+       LineData = chan->fax2.LineData;
+       LineDataLen = chan->fax2.LineDataLen;
+
+       OutBuf.Data = chan->fax2.abFrame;
+       OutBuf.Size = sizeof(chan->fax2.abFrame);
+       OutBuf.Len = 0;
+       OutBuf.Next = OutBuf.Data;
+
+       Event = EVENT_NONE;
+
+       chan->fax2.Eop = 0;
+
+       for (;;) {
+         for (;;) {
+               if (InMask == 0) {
+                       if (InBuf.Len >= InBuf.Size) {
+                               Event = EVENT_EOD;
+                               break;
+                       }
+                       if ((chan->fax2.Dle != _DLE_) && *InBuf.Next == _DLE_) {
+                               chan->fax2.Dle = _DLE_;
+                               InBuf.Next++;
+                               InBuf.Len++;
+                               if (InBuf.Len >= InBuf.Size) {
+                                       Event = EVENT_EOD;
+                                       break;
+                               }
+                       }
+                       if (chan->fax2.Dle == _DLE_) {
+                               chan->fax2.Dle = 0;
+                               if (*InBuf.Next == _ETX_) {
+                                       Event = EVENT_EOP;
+                                       break;
+                               } else
+                               if (*InBuf.Next == _DLE_) {
+                                       /* do nothing */
+                               } else {
+                                       eicon_log(ccard, 1,
+                                               "idi_err: Ch%d: unknown DLE escape %02x found\n",
+                                                       chan->No, *InBuf.Next);
+                                       InBuf.Next++;
+                                       InBuf.Len++;
+                                       if (InBuf.Len >= InBuf.Size) {
+                                               Event = EVENT_EOD;
+                                               break;
+                                       }
+                               }
+                       }
+                       InBuf.Len++;
+                       InData = *InBuf.Next++;
+                       InMask = (chan->fax->bor) ? 0x80 : 0x01;
+               }
+               while (InMask) {
+                       LineData >>= 1;
+                       LineDataLen++;
+                       if (InData & InMask)
+                               LineData |= 0x80000000;
+                       if (chan->fax->bor)
+                               InMask >>= 1;
+                       else
+                               InMask <<= 1;
+
+                       if ((LineDataLen >= T4_EOL_BITSIZE) &&
+                          ((LineData & T4_EOL_MASK_DWORD) == T4_EOL_DWORD)) {
+                               Event = EVENT_EOL;
+                               if (LineDataLen > T4_EOL_BITSIZE) {
+                                       Byte = (__u8)
+                                               ((LineData & ~T4_EOL_MASK_DWORD) >>
+                                               (32 - LineDataLen));
+                                       if (Byte == 0) {
+                                               if (! chan->fax2.NullByteExist) {
+                                                       chan->fax2.NullBytesPos = LineBuf.Len;
+                                                       chan->fax2.NullByteExist = 1;
+                                               }
+                                       } else {
+                                               chan->fax2.NullByteExist = 0;
+                                       }
+                                       if (LineBuf.Len < LineBuf.Size) {
+                                               *LineBuf.Next++  = Byte;
+                                               LineBuf.Len++;
+                                       }
+                               }
+                               LineDataLen = 0;
+                               break;
+                       }
+                       if (LineDataLen >= T4_EOL_BITSIZE + 8) {
+                               Byte = (__u8)
+                                       ((LineData & ~T4_EOL_MASK_DWORD) >>
+                                       (32 - T4_EOL_BITSIZE - 8));
+                               LineData &= T4_EOL_MASK_DWORD;
+                               LineDataLen = T4_EOL_BITSIZE;
+                               if (Byte == 0) {
+                                       if (! chan->fax2.NullByteExist) {
+                                               chan->fax2.NullBytesPos = LineBuf.Len;
+                                               chan->fax2.NullByteExist = 1;
+                                       }
+                               } else {
+                                       chan->fax2.NullByteExist = 0;
+                               }
+                               if (LineBuf.Len < LineBuf.Size) {
+                                       *LineBuf.Next++  = Byte; 
+                                       LineBuf.Len++;
+                               }
+                       }
+               }
+               if (Event != EVENT_NONE)
+                       break;
+         }
+
+               if ((Event != EVENT_EOL) && (Event != EVENT_EOP))
+                       break;
+
+               if ((Event == EVENT_EOP) && (LineDataLen > 0)) {
+                       LineData >>= 32 - LineDataLen;
+                       LineDataLen = 0;
+                       while (LineData != 0) {
+                               Byte = (__u8) LineData;
+                               LineData >>= 8;
+                               if (Byte == 0) {
+                                       if (! chan->fax2.NullByteExist) {
+                                               chan->fax2.NullBytesPos = LineBuf.Len;
+                                               chan->fax2.NullByteExist = 1;
+                                       }
+                               } else {
+                                       chan->fax2.NullByteExist = 0;
+                               }
+                               if (LineBuf.Len < LineBuf.Size) {
+                                       *LineBuf.Next++  = Byte;
+                                       LineBuf.Len++;
+                               }
+                               
+                       }
+               }
+               if (chan->fax2.NullByteExist) {
+                       if (chan->fax2.NullBytesPos == 0) {
+                               LineBuf.Len = 0;
+                       } else {
+                               LineBuf.Len = chan->fax2.NullBytesPos + 1;
+                       }
+               }
+               if (LineBuf.Len > 0) {
+                       if (OutBuf.Len + LineBuf.Len + SFF_LEN_FLD_SIZE > OutBuf.Size) {
+                               ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
+                       }
+                       if (LineBuf.Len <= 216) {
+                               *OutBuf.Next++ = (__u8) LineBuf.Len;
+                               OutBuf.Len++;
+                       } else {
+                               *OutBuf.Next++ = 0;
+                               *((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len;
+                               OutBuf.Len += 3;
+                       }
+                       memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len);
+                       OutBuf.Next += LineBuf.Len;
+                       OutBuf.Len  += LineBuf.Len;
+               }
+               LineBuf.Len = 0;
+               LineBuf.Next = LineBuf.Data;
+               chan->fax2.NullByteExist = 0;
+               if (Event == EVENT_EOP)
+                       break;
+
+               Event = EVENT_NONE;
+       }
+
+       if (Event == EVENT_EOP) {
+               chan->fax2.Eop = 1;
+               chan->fax2.PageCount++;
+               cmd.driver = ccard->myid;
+               cmd.command = ISDN_STAT_FAXIND;
+               cmd.arg = chan->No;
+               chan->fax->r_code = ISDN_TTY_FAX_EOP;
+               ccard->interface.statcallb(&cmd);
+       }
+       if (OutBuf.Len > 0) {
+               ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
+       }
+
+       chan->fax2.LineLen = LineBuf.Len;
+       chan->fax2.LineData = LineData;
+       chan->fax2.LineDataLen = LineDataLen;
+
+#      undef EVENT_NONE
+#      undef EVENT_EOD
+#      undef EVENT_EOL
+#      undef EVENT_EOP
+
+       if (ret >= 0)
+               dev_kfree_skb(skb);
+       if (ret == 0)
+               ret = 1;
+       return(ret);
 }
 
 void
 idi_fax_hangup(eicon_card *ccard, eicon_chan *chan)
 {
+       isdn_ctrl cmd;
 
-       /* TODO , code follows */
-
+       if (!chan->fax) {
+               eicon_log(ccard, 1, "idi_fax: hangup with NULL fax struct, ERROR\n");
+               return;
+       }
+       if ((chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) &&
+           (chan->fax->code == 0)) {
+               cmd.driver = ccard->myid;
+               cmd.command = ISDN_STAT_FAXIND;
+               cmd.arg = chan->No;
+               chan->fax->r_code = ISDN_TTY_FAX_PTS;
+               ccard->interface.statcallb(&cmd);
+       }
+       if ((chan->fax->code > 1) && (chan->fax->code < 120))
+               chan->fax->code += 120;
+       chan->fax->r_code = ISDN_TTY_FAX_HNG;
+       cmd.driver = ccard->myid;
+       cmd.command = ISDN_STAT_FAXIND;
+       cmd.arg = chan->No;
+       ccard->interface.statcallb(&cmd);
 }
 
 #endif /******** FAX ********/
@@ -1084,20 +2148,17 @@ idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int
        eicon_chan_ptr *chan2;
 
        if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
-               if (DebugVar & 1)
-                       printk(KERN_DEBUG"idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
+               eicon_log(card, 1, "idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
                return -ENODEV;
        }
-       if (DebugVar & 8)
-               printk(KERN_DEBUG"idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
-                               UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
+       eicon_log(card, 8, "idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
+                       UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
 
        skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC);
        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
        if ((!skb) || (!skb2)) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
+               eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
                if (skb) 
                        dev_kfree_skb(skb);
                if (skb2) 
@@ -1131,6 +2192,9 @@ idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value)
        u_char buf[6];
        struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf;
 
+       if ((!ccard) || (!chan))
+               return;
+
        memset(buf, 0, 6);
        switch(cmd) {
                case ISDN_AUDIO_SETDD:
@@ -1162,14 +2226,15 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
        '1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'
        };
 
+       if ((!ccard) || (!chan))
+               return;
+
        switch (buffer[0]) {
                case DSP_UDATA_INDICATION_SYNC:
-                       if (DebugVar & 16)
-                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
+                       eicon_log(ccard, 16, "idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
                        break;
                case DSP_UDATA_INDICATION_DCD_OFF:
-                       if (DebugVar & 8)
-                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
                        break;
                case DSP_UDATA_INDICATION_DCD_ON:
                        if ((chan->l2prot == ISDN_PROTO_L2_MODEM) &&
@@ -1181,31 +2246,24 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
                                sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]);
                                ccard->interface.statcallb(&cmd);
                        }
-                       if (DebugVar & 8) {
-                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
-                               printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No,
-                                           p->norm, p->options, p->speed, p->delay); 
-                           }
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+                               p->norm, p->options, p->speed, p->delay); 
                        break;
                case DSP_UDATA_INDICATION_CTS_OFF:
-                       if (DebugVar & 8)
-                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
                        break;
                case DSP_UDATA_INDICATION_CTS_ON:
-                       if (DebugVar & 8) {
-                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
-                               printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No,
-                                           p->norm, p->options, p->speed, p->delay); 
-                       }
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+                               p->norm, p->options, p->speed, p->delay); 
                        break;
                case DSP_UDATA_INDICATION_DISCONNECT:
-                       if (DebugVar & 8)
-                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
                        break;
                case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED:
-                       if (DebugVar & 8)
-                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
-                                       dtmf_code[buffer[1]]);
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
+                               dtmf_code[buffer[1]]);
                        cmd.driver = ccard->myid;
                        cmd.command = ISDN_STAT_AUDIO;
                        cmd.parm.num[0] = ISDN_AUDIO_DTMF;
@@ -1214,8 +2272,7 @@ idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int
                        ccard->interface.statcallb(&cmd);
                        break;
                default:
-                       if (DebugVar & 8)
-                               printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
+                       eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
        }
 }
 
@@ -1223,23 +2280,35 @@ void
 idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
 {
        int tmp;
+       char tnum[64];
+       int dlev;
        int free_buff;
+       ulong flags;
        struct sk_buff *skb2;
         eicon_IND *ind = (eicon_IND *)skb->data;
        eicon_chan *chan;
        idi_ind_message message;
        isdn_ctrl cmd;
 
+       if (!ccard) {
+               eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ind\n");
+               dev_kfree_skb(skb);
+               return;
+       }
+
        if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+               eicon_log(ccard, 1, "idi_err: Ch??: null chan in handle_ind\n");
                dev_kfree_skb(skb);
                return;
        }
        
-       if ((DebugVar & 128) || 
-          ((DebugVar & 16) && (ind->Ind != 8))) {
-               printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
-                       ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
-       }
+       if (ind->Ind != 8)
+               dlev = 144;
+       else
+               dlev = 128;
+
+               eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
+               ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
 
        free_buff = 1;
        /* Signal Layer */
@@ -1247,15 +2316,16 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
                switch(ind->Ind) {
                        case HANGUP:
-                               if (DebugVar & 8)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: Hangup\n", chan->No);
+                               eicon_log(ccard, 8, "idi_ind: Ch%d: Hangup\n", chan->No);
                                while((skb2 = skb_dequeue(&chan->e.X))) {
                                        dev_kfree_skb(skb2);
                                }
-                               chan->e.busy = 0;
+                               save_flags(flags);
+                               cli();
                                chan->queued = 0;
                                chan->waitq = 0;
                                chan->waitpq = 0;
+                               restore_flags(flags);
                                if (message.e_cau[0] & 0x7f) {
                                        cmd.driver = ccard->myid;
                                        cmd.arg = chan->No;
@@ -1269,8 +2339,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                if (!chan->e.B2Id)
                                        chan->fax = 0;
 #endif
-                               if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
-                                   (chan->fsm_state == EICON_STATE_WMCONN)) {
+                               if (((chan->fsm_state == EICON_STATE_ACTIVE) ||
+                                   (chan->fsm_state == EICON_STATE_WMCONN)) ||
+                                   ((chan->l2prot == ISDN_PROTO_L2_FAX) &&
+                                   (chan->fsm_state == EICON_STATE_OBWAIT))) {
                                        chan->fsm_state = EICON_STATE_NULL;
                                } else {
                                        if (chan->e.B2Id)
@@ -1284,51 +2356,62 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                }
                                break;
                        case INDICATE_IND:
-                               if (DebugVar & 8)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: Indicate_Ind\n", chan->No);
+                               eicon_log(ccard, 8, "idi_ind: Ch%d: Indicate_Ind\n", chan->No);
+                               if (chan->fsm_state != EICON_STATE_LISTEN) {
+                                       eicon_log(ccard, 1, "idi_err: Ch%d: Incoming call on wrong state (%d).\n",
+                                               chan->No, chan->fsm_state);
+                                       idi_do_req(ccard, chan, HANGUP, 0);
+                                       break;
+                               }
                                chan->fsm_state = EICON_STATE_ICALL;
                                idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2);
                                strcpy(chan->cpn, message.cpn + 1);
-                               if (strlen(message.dsa)) {
-                                       strcat(chan->cpn, ".");
-                                       strcat(chan->cpn, message.dsa);
-                               }
                                strcpy(chan->oad, message.oad);
-                               if (strlen(message.osa)) {
-                                       strcat(chan->oad, ".");
-                                       strcat(chan->oad, message.osa);
-                               }
+                               strcpy(chan->dsa, message.dsa);
+                               strcpy(chan->osa, message.osa);
+                               chan->plan = message.plan;
+                               chan->screen = message.screen;
                                try_stat_icall_again: 
                                cmd.driver = ccard->myid;
                                cmd.command = ISDN_STAT_ICALL;
                                cmd.arg = chan->No;
                                cmd.parm.setup.si1 = chan->si1;
                                cmd.parm.setup.si2 = chan->si2;
-                               strcpy(cmd.parm.setup.eazmsn, chan->cpn);
-                               strcpy(cmd.parm.setup.phone, chan->oad);
-                               cmd.parm.setup.plan = message.plan;
-                               cmd.parm.setup.screen = message.screen;
+                               strcpy(tnum, chan->cpn);
+                               if (strlen(chan->dsa)) {
+                                       strcat(tnum, ".");
+                                       strcat(tnum, chan->dsa);
+                               }
+                               tnum[ISDN_MSNLEN - 1] = 0;
+                               strcpy(cmd.parm.setup.eazmsn, tnum);
+                               strcpy(tnum, chan->oad);
+                               if (strlen(chan->osa)) {
+                                       strcat(tnum, ".");
+                                       strcat(tnum, chan->osa);
+                               }
+                               tnum[ISDN_MSNLEN - 1] = 0;
+                               strcpy(cmd.parm.setup.phone, tnum);
+                               cmd.parm.setup.plan = chan->plan;
+                               cmd.parm.setup.screen = chan->screen;
                                tmp = ccard->interface.statcallb(&cmd);
                                switch(tmp) {
                                        case 0: /* no user responding */
                                                idi_do_req(ccard, chan, HANGUP, 0);
+                                               chan->fsm_state = EICON_STATE_NULL;
                                                break;
                                        case 1: /* alert */
-                                               if (DebugVar & 8)
-                                                       printk(KERN_DEBUG"idi_req: Ch%d: Call Alert\n", chan->No);
+                                               eicon_log(ccard, 8, "idi_req: Ch%d: Call Alert\n", chan->No);
                                                if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_ICALLW)) {
                                                        chan->fsm_state = EICON_STATE_ICALL;
                                                        idi_do_req(ccard, chan, CALL_ALERT, 0);
                                                }
                                                break;
                                        case 2: /* reject */
-                                               if (DebugVar & 8)
-                                                       printk(KERN_DEBUG"idi_req: Ch%d: Call Reject\n", chan->No);
+                                               eicon_log(ccard, 8, "idi_req: Ch%d: Call Reject\n", chan->No);
                                                idi_do_req(ccard, chan, REJECT, 0);
                                                break;
                                        case 3: /* incomplete number */
-                                               if (DebugVar & 8)
-                                                       printk(KERN_DEBUG"idi_req: Ch%d: Incomplete Number\n", chan->No);
+                                               eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No);
                                                switch(ccard->type) {
                                                        case EICON_CTYPE_MAESTRAP:
                                                        case EICON_CTYPE_S2M:
@@ -1342,8 +2425,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                }
                                break;
                        case INFO_IND:
-                               if (DebugVar & 8)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: Info_Ind\n", chan->No);
+                               eicon_log(ccard, 8, "idi_ind: Ch%d: Info_Ind\n", chan->No);
                                if ((chan->fsm_state == EICON_STATE_ICALLW) &&
                                    (message.cpn[0])) {
                                        strcat(chan->cpn, message.cpn + 1);
@@ -1351,8 +2433,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                }
                                break;
                        case CALL_IND:
-                               if (DebugVar & 8)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: Call_Ind\n", chan->No);
+                               eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Ind\n", chan->No);
                                if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_IWAIT)) {
                                        chan->fsm_state = EICON_STATE_IBWAIT;
                                        cmd.driver = ccard->myid;
@@ -1376,8 +2457,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                        idi_hangup(ccard, chan);
                                break;
                        case CALL_CON:
-                               if (DebugVar & 8)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: Call_Con\n", chan->No);
+                               eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
                                if (chan->fsm_state == EICON_STATE_OCALL) {
                                        chan->fsm_state = EICON_STATE_OBWAIT;
                                        cmd.driver = ccard->myid;
@@ -1387,9 +2467,8 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
 
                                        /* check if old NetID has been removed */
                                        if (chan->e.B2Id) {
-                                               if (DebugVar & 1)
-                                                       printk(KERN_WARNING "idi_err: Ch%d: Old NetID %x was not removed.\n",
-                                                               chan->No, chan->e.B2Id);
+                                               eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
+                                                       chan->No, chan->e.B2Id);
                                                idi_do_req(ccard, chan, REMOVE, 1);
                                        }
 
@@ -1405,12 +2484,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                idi_hangup(ccard, chan);
                                break;
                        case AOC_IND:
-                               if (DebugVar & 8)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: Advice of Charge\n", chan->No);
+                               eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No);
                                break;
                        default:
-                               if (DebugVar & 8)
-                                       printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
+                               eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
                }
        }
        /* Network Layer */
@@ -1424,8 +2501,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                else
                switch(ind->Ind) {
                        case IDI_N_CONNECT_ACK:
-                               if (DebugVar & 16)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
+                               eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
                                if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
                                        chan->fsm_state = EICON_STATE_WMCONN;
                                        break;
@@ -1445,8 +2521,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                                }
                                        }
                                        else {
-                                               if (DebugVar & 1)
-                                                       printk(KERN_DEBUG "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
+                                               eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
                                        }
 #endif
                                        break;
@@ -1458,8 +2533,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                ccard->interface.statcallb(&cmd);
                                break; 
                        case IDI_N_CONNECT:
-                               if (DebugVar & 16)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect\n", chan->No);
+                               eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
                                if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
                                if (chan->l2prot == ISDN_PROTO_L2_FAX) {
                                        break;
@@ -1475,9 +2549,11 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                ccard->interface.statcallb(&cmd);
                                break; 
                        case IDI_N_DISC:
-                               if (DebugVar & 16)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC\n", chan->No);
+                               eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No);
                                if (chan->e.B2Id) {
+                                       while((skb2 = skb_dequeue(&chan->e.X))) {
+                                               dev_kfree_skb(skb2);
+                                       }
                                        idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
                                        idi_do_req(ccard, chan, REMOVE, 1);
                                }
@@ -1487,9 +2563,12 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                        idi_fax_hangup(ccard, chan);
                                }
 #endif
+                               save_flags(flags);
+                               cli();
                                chan->queued = 0;
                                chan->waitq = 0;
                                chan->waitpq = 0;
+                               restore_flags(flags);
                                idi_do_req(ccard, chan, HANGUP, 0);
                                if (chan->fsm_state == EICON_STATE_ACTIVE) {
                                        cmd.driver = ccard->myid;
@@ -1503,8 +2582,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
 #endif
                                break; 
                        case IDI_N_DISC_ACK:
-                               if (DebugVar & 16)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+                               eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
 #ifdef CONFIG_ISDN_TTY_FAX
                                if (chan->l2prot == ISDN_PROTO_L2_FAX) {
                                        idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
@@ -1513,13 +2591,11 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
 #endif
                                break; 
                        case IDI_N_DATA_ACK:
-                               if (DebugVar & 16)
-                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
+                               eicon_log(ccard, 16, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
                                break;
                        case IDI_N_DATA:
                                skb_pull(skb, sizeof(eicon_IND) - 1);
-                               if (DebugVar & 128)
-                                       printk(KERN_DEBUG"idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
+                               eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
                                if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 #ifdef CONFIG_ISDN_TTY_FAX
                                        idi_faxdata_rcv(ccard, chan, skb);
@@ -1538,27 +2614,26 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
                                break; 
 #endif
                        default:
-                               if (DebugVar & 8)
-                                       printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
+                               eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
                }
        }
        else {
-               if (DebugVar & 1)
-                       printk(KERN_ERR "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
+               eicon_log(ccard, 1, "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
        }
-   if (free_buff) dev_kfree_skb(skb);
+   if (free_buff)
+       dev_kfree_skb(skb);
 }
 
 int
 idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
 {
+       ulong flags;
        isdn_ctrl cmd;
 
        if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
                /* I dont know why this happens, just ignoring this RC */
-               if (DebugVar & 16)
-                       printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, 
-                               ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
+               eicon_log(ccard, 16, "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, 
+                       ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
                return 1;
        }
 
@@ -1572,27 +2647,27 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
        /* Remove an Id */
        if (chan->e.Req == REMOVE) {
                if (ack->Reference != chan->e.ref) {
-                       if (DebugVar & 16)
-                               printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
-                                       ack->Reference, chan->e.ref);
+                       eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
+                               ack->Reference, chan->e.ref);
                        return 0;
                }
+               save_flags(flags);
+               cli();
                ccard->IdTable[ack->RcId] = NULL;
-               if (DebugVar & 16)
-                       printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
-                               ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
+               eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+                       ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
                if (!chan->e.ReqCh) 
                        chan->e.D3Id = 0;
                else
                        chan->e.B2Id = 0;
+               restore_flags(flags);
                return 1;
        }
 
        /* Signal layer */
        if (!chan->e.ReqCh) {
-               if (DebugVar & 16)
-                       printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
-                               ack->RcId, ack->RcCh, ack->Reference);
+               eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+                       ack->RcId, ack->RcCh, ack->Reference);
        } else {
        /* Network layer */
                switch(chan->e.Req & 0x0f) {
@@ -1606,7 +2681,10 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
                                                cmd.parm.length = chan->waitpq;
                                                ccard->interface.statcallb(&cmd);
                                        }
+                                       save_flags(flags);
+                                       cli();
                                        chan->waitpq = 0;
+                                       restore_flags(flags);
 #ifdef CONFIG_ISDN_TTY_FAX
                                        if (chan->l2prot == ISDN_PROTO_L2_FAX) {
                                                if (((chan->queued - chan->waitq) < 1) &&
@@ -1620,20 +2698,21 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
                                                                ccard->interface.statcallb(&cmd);
                                                        }
                                                        else {
-                                                               if (DebugVar & 1)
-                                                                       printk(KERN_DEBUG "idi_ack: Sent with NULL fax struct, ERROR\n");
+                                                               eicon_log(ccard, 1, "idi_ack: Sent with NULL fax struct, ERROR\n");
                                                        }
                                                }
                                        }
 #endif
                                }
+                               save_flags(flags);
+                               cli();
                                chan->queued -= chan->waitq;
                                if (chan->queued < 0) chan->queued = 0;
+                               restore_flags(flags);
                                break;
                        default:
-                               if (DebugVar & 16)
-                                       printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
-                                               ack->RcId, ack->RcCh, ack->Reference);
+                               eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+                                       ack->RcId, ack->RcCh, ack->Reference);
                }
        }
        return 1;
@@ -1643,22 +2722,30 @@ void
 idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
 {
        int j;
+       ulong flags;
         eicon_RC *ack = (eicon_RC *)skb->data;
        eicon_chan *chan;
        isdn_ctrl cmd;
        int dCh = -1;
 
+       if (!ccard) {
+               eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ack\n");
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       save_flags(flags);
+       cli();
        if ((chan = ccard->IdTable[ack->RcId]) != NULL)
                dCh = chan->No;
-       
+       restore_flags(flags);
 
        switch (ack->Rc) {
                case OK_FC:
                case N_FLOW_CONTROL:
                case ASSIGN_RC:
-                       if (DebugVar & 1)
-                               printk(KERN_ERR "idi_ack: Ch%d: unhandled RC 0x%x\n",
-                                       dCh, ack->Rc);
+                       eicon_log(ccard, 1, "idi_ack: Ch%d: unhandled RC 0x%x\n",
+                               dCh, ack->Rc);
                        break;
                case READY_INT:
                case TIMER_INT:
@@ -1667,8 +2754,7 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
 
                case OK:
                        if (!chan) {
-                               if (DebugVar & 1)
-                                       printk(KERN_ERR "idi_ack: Ch%d: OK on chan without Id\n", dCh);
+                               eicon_log(ccard, 1, "idi_ack: Ch%d: OK on chan without Id\n", dCh);
                                break;
                        }
                        if (!idi_handle_ack_ok(ccard, chan, ack))
@@ -1677,29 +2763,29 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
 
                case ASSIGN_OK:
                        if (chan) {
-                               if (DebugVar & 1)
-                                       printk(KERN_ERR "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
-                                               chan->No, chan->e.D3Id, chan->e.B2Id);
+                               eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
+                                       chan->No, chan->e.D3Id, chan->e.B2Id);
                        }
+                       save_flags(flags);
+                       cli();
                        for(j = 0; j < ccard->nchannels + 1; j++) {
-                               if (ccard->bch[j].e.ref == ack->Reference) {
+                               if ((ccard->bch[j].e.ref == ack->Reference) &&
+                                       (ccard->bch[j].e.Req == ASSIGN)) {
                                        if (!ccard->bch[j].e.ReqCh) 
                                                ccard->bch[j].e.D3Id  = ack->RcId;
                                        else
                                                ccard->bch[j].e.B2Id  = ack->RcId;
                                        ccard->IdTable[ack->RcId] = &ccard->bch[j];
-                                       ccard->bch[j].e.busy = 0;
-                                       ccard->bch[j].e.ref = 0;
-                                       if (DebugVar & 16)
-                                               printk(KERN_DEBUG"idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
-                                                       ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
+                                       chan = &ccard->bch[j];
+                                       eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
+                                               ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
                                        break;
                                }
                        }               
+                       restore_flags(flags);
                        if (j > ccard->nchannels) {
-                               if (DebugVar & 24)
-                                       printk(KERN_DEBUG"idi_ack: Ch??: ref %d not found for Id %d\n", 
-                                               ack->Reference, ack->RcId);
+                               eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", 
+                                       ack->Reference, ack->RcId);
                        }
                        break;
 
@@ -1711,9 +2797,19 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
                case UNKNOWN_IE:
                case WRONG_IE:
                default:
-                       if (DebugVar & 1)
-                               printk(KERN_ERR "eicon_ack: Ch%d: Not OK !!: Rc=%d Id=%x Ch=%d\n", dCh, 
-                                       ack->Rc, ack->RcId, ack->RcCh);
+                       if (!chan) {
+                               eicon_log(ccard, 1, "idi_ack: Ch%d: Not OK !! on chan without Id\n", dCh);
+                               break;
+                       } else
+                       switch (chan->e.Req) {
+                               case 12:        /* Alert */
+                                       eicon_log(ccard, 2, "eicon_err: Ch%d: Alert Not OK : Rc=%d Id=%x Ch=%d\n",
+                                               dCh, ack->Rc, ack->RcId, ack->RcCh);
+                                       break;
+                               default:
+                                       eicon_log(ccard, 1, "eicon_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
+                                               dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
+                       }
                        if (dCh == ccard->nchannels) { /* Management */
                                chan->fsm_state = 2;
                        } else if (dCh >= 0) {
@@ -1726,8 +2822,13 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
                                ccard->interface.statcallb(&cmd);
                        }
        }
-       if (chan)
+       save_flags(flags);
+       cli();
+       if (chan) {
+               chan->e.ref = 0;
                chan->e.busy = 0;
+       }
+       restore_flags(flags);
        dev_kfree_skb(skb);
        eicon_schedule_tx(ccard);
 }
@@ -1742,21 +2843,25 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
         int len, plen = 0, offset = 0;
        unsigned long flags;
 
+       if ((!card) || (!chan)) {
+               eicon_log(card, 1, "idi_err: Ch??: null card/chan in send_data\n");
+               return -1;
+       }
+
         if (chan->fsm_state != EICON_STATE_ACTIVE) {
-               if (DebugVar & 1)
-                       printk(KERN_DEBUG"idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
+               eicon_log(card, 1, "idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
                 return -ENODEV;
        }
 
         len = skb->len;
-       if (len > 2138) /* too much for the shared memory */
+       if (len > EICON_MAX_QUEUE)      /* too much for the shared memory */
                return -1;
         if (!len)
                 return 0;
-       if (chan->queued + len > ((chan->l2prot == ISDN_PROTO_L2_TRANS) ? 4000 : EICON_MAX_QUEUED))
+       if (chan->queued + len > EICON_MAX_QUEUE)
                return 0;
-       if (DebugVar & 128)
-               printk(KERN_DEBUG"idi_snd: Ch%d: %d bytes\n", chan->No, len);
+
+       eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len);
 
        save_flags(flags);
        cli();
@@ -1769,8 +2874,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
 
                if ((!xmit_skb) || (!skb2)) {
                        restore_flags(flags);
-                       if (DebugVar & 1)
-                               printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
+                       eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
                        if (xmit_skb) 
                                dev_kfree_skb(skb);
                        if (skb2) 
@@ -1824,8 +2928,7 @@ eicon_idi_manage_assign(eicon_card *card)
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err: alloc_skb failed in manage_assign()\n");
+               eicon_log(card, 1, "idi_err: alloc_skb failed in manage_assign()\n");
                if (skb) 
                        dev_kfree_skb(skb);
                if (skb2) 
@@ -1867,8 +2970,7 @@ eicon_idi_manage_remove(eicon_card *card)
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err: alloc_skb failed in manage_remove()\n");
+                       eicon_log(card, 1, "idi_err: alloc_skb failed in manage_remove()\n");
                if (skb) 
                        dev_kfree_skb(skb);
                if (skb2) 
@@ -1934,8 +3036,7 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
        chan->fsm_state = 0;
 
        if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err: alloc_manifbuf failed\n");
+                       eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n");
                chan->e.D3Id = 0;
                return -ENOMEM;
        }
@@ -1949,8 +3050,7 @@ eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
         skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
         if ((!skb) || (!skb2)) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err_manif: alloc_skb failed in manage()\n");
+                       eicon_log(card, 1, "idi_err_manif: alloc_skb failed in manage()\n");
                if (skb) 
                        dev_kfree_skb(skb);
                if (skb2) 
index 54f8b11a7a321b7065d43493a2f32e8d1889492b..779f241e0a9c550eb70b345b339c55e6e94ef5cf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.5 1999/08/31 11:20:11 paul Exp $
+/* $Id: eicon_io.c,v 1.8 1999/10/08 22:09:34 armin Exp $
  *
  * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
  * Code for communicating with hardware.
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_io.c,v $
+ * Revision 1.8  1999/10/08 22:09:34  armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.7  1999/09/26 14:17:53  armin
+ * Improved debug and log via readstat()
+ *
+ * Revision 1.6  1999/09/21 20:35:43  armin
+ * added more error checking.
+ *
  * Revision 1.5  1999/08/31 11:20:11  paul
  * various spelling corrections (new checksums may be needed, Karsten!)
  *
 
 void
 eicon_io_rcv_dispatch(eicon_card *ccard) {
+       ulong flags;
         struct sk_buff *skb, *skb2, *skb_new;
         eicon_IND *ind, *ind2, *ind_new;
         eicon_chan *chan;
 
         if (!ccard) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "eicon_io_rcv_dispatch: NULL card!\n");
+               eicon_log(ccard, 1, "eicon_err: NULL card in rcv_dispatch !\n");
                 return;
         }
 
        while((skb = skb_dequeue(&ccard->rcvq))) {
                ind = (eicon_IND *)skb->data;
 
+               save_flags(flags);
+               cli();
                if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
                        if (DebugVar & 1) {
                                switch(ind->Ind) {
@@ -74,14 +87,16 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
                                                /* doesn't matter if this happens */ 
                                                break;
                                        default: 
-                                               printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
-                                               printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+                                               eicon_log(ccard, 1, "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
+                                               eicon_log(ccard, 1, "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
                                                        ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
                                }
                        }
+                       restore_flags(flags);
                        dev_kfree_skb(skb);
                        continue;
                }
+               restore_flags(flags);
 
                if (chan->e.complete) { /* check for rec-buffer chaining */
                        if (ind->MLength == ind->RBuffer.length) {
@@ -97,10 +112,12 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
                        }
                }
                else {
+                       save_flags(flags);
+                       cli();
                        if (!(skb2 = skb_dequeue(&chan->e.R))) {
                                chan->e.complete = 1;
-                               if (DebugVar & 1)
-                                       printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n");
+                               eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n");
+                               restore_flags(flags);
                                dev_kfree_skb(skb);
                                continue;       
                        }
@@ -108,8 +125,8 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
                        skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length),
                                        GFP_ATOMIC);
                        if (!skb_new) {
-                               if (DebugVar & 1)
-                                       printk(KERN_ERR "eicon_io: skb_alloc failed in rcv_dispatch()\n");
+                               eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n");
+                               restore_flags(flags);
                                dev_kfree_skb(skb);
                                dev_kfree_skb(skb2);
                                continue;       
@@ -128,12 +145,14 @@ eicon_io_rcv_dispatch(eicon_card *ccard) {
                        dev_kfree_skb(skb2);
                        if (ind->MLength == ind->RBuffer.length) {
                                chan->e.complete = 2;
+                               restore_flags(flags);
                                idi_handle_ind(ccard, skb_new);
                                continue;
                        }
                        else {
                                chan->e.complete = 0;
                                skb_queue_tail(&chan->e.R, skb_new);
+                               restore_flags(flags);
                                continue;
                        }
                }
@@ -145,8 +164,7 @@ eicon_io_ack_dispatch(eicon_card *ccard) {
         struct sk_buff *skb;
 
         if (!ccard) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "eicon_io_ack_dispatch: NULL card!\n");
+               eicon_log(ccard, 1, "eicon_err: NULL card in ack_dispatch!\n");
                 return;
         }
        while((skb = skb_dequeue(&ccard->rackq))) {
@@ -402,13 +420,13 @@ eicon_io_transmit(eicon_card *ccard) {
        int scom = 0;
        int tmp = 0;
        int quloop = 1;
+       int dlev = 0;
 
        pci_card = &ccard->hwif.pci;
        isa_card = &ccard->hwif.isa;
 
         if (!ccard) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "eicon_transmit: NULL card!\n");
+                       eicon_log(ccard, 1, "eicon_transmit: NULL card!\n");
                 return;
         }
 
@@ -441,7 +459,7 @@ eicon_io_transmit(eicon_card *ccard) {
                        prram = 0;
                        break;
                default:
-                       printk(KERN_WARNING "eicon_transmit: unsupported card-type!\n");
+                       eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n");
                        return;
        }
 
@@ -460,16 +478,14 @@ eicon_io_transmit(eicon_card *ccard) {
                                }
                                restore_flags(flags);
                                skb_queue_head(&ccard->sndq, skb2);
-                               if (DebugVar & 32)
-                                       printk(KERN_INFO "eicon: transmit: Card not ready\n");
+                                       eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
                                return;
                        }
                } else {
                        if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) {
                                restore_flags(flags);
                                skb_queue_head(&ccard->sndq, skb2);
-                               if (DebugVar & 32)
-                                       printk(KERN_INFO "eicon: transmit: Card not ready\n");
+                                       eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
                                return;
                        }
                }
@@ -482,8 +498,7 @@ eicon_io_transmit(eicon_card *ccard) {
                  cli();
                  reqbuf = (eicon_REQ *)skb->data;
                  if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
-                       if (DebugVar & 16)
-                               printk(KERN_WARNING "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); 
+                       eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); 
                  } else {
                        if (scom) {
                                ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
@@ -498,7 +513,7 @@ eicon_io_transmit(eicon_card *ccard) {
                                ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh);
                                ram_outb(ccard, &ReqOut->Req, reqbuf->Req); 
                        }
-
+                       dlev = 160;
                        if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
 
                                if (!reqbuf->Reference) { /* Signal Layer */
@@ -520,6 +535,7 @@ eicon_io_transmit(eicon_card *ccard) {
                                           ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
                                                chan->waitq = reqbuf->XBuffer.length;
                                                chan->waitpq += reqbuf->XBuffer.length;
+                                               dlev = 128;
                                        }
                                }
 
@@ -547,13 +563,12 @@ eicon_io_transmit(eicon_card *ccard) {
                        else
                                ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); 
 
-                       chan->e.busy = 1; 
-                       if (DebugVar & 32)
-                               printk(KERN_DEBUG "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", 
-                                                       reqbuf->Req, 
-                                                       ram_inb(ccard, &ReqOut->ReqId),
-                                                       reqbuf->ReqCh, reqbuf->XBuffer.length,
-                                                       chan->e.ref); 
+                       chan->e.busy = 1;
+                       eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", 
+                                       reqbuf->Req, 
+                                       ram_inb(ccard, &ReqOut->ReqId),
+                                       reqbuf->ReqCh, reqbuf->XBuffer.length,
+                                       chan->e.ref); 
                  }
                  restore_flags(flags);
                  dev_kfree_skb(skb);
@@ -562,8 +577,7 @@ eicon_io_transmit(eicon_card *ccard) {
                } 
                else {
                skb_queue_tail(&ccard->sackq, skb2);
-               if (DebugVar & 32)
-                       printk(KERN_INFO "eicon: transmit: busy chan %d\n", chan->No); 
+                       eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); 
                }
 
                if (scom)
@@ -604,10 +618,11 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
        unsigned char *irqprobe = 0;
        int scom = 0;
        int tmp = 0;
+       int dlev = 0;
 
 
         if (!ccard) {
-                printk(KERN_WARNING "eicon_irq: spurious interrupt %d\n", irq);
+                eicon_log(ccard, 1, "eicon_irq: spurious interrupt %d\n", irq);
                 return;
         }
 
@@ -659,7 +674,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
                        prram = 0;
                        break;
                default:
-                       printk(KERN_WARNING "eicon_irq: unsupported card-type!\n");
+                       eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n");
                        return;
        }
 
@@ -709,24 +724,21 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
                case EICON_CTYPE_QUADRO:
                case EICON_CTYPE_S2M:
                        if (!(readb(isa_card->intack))) { /* card did not interrupt */
-                               if (DebugVar & 1)
-                                       printk(KERN_DEBUG "eicon: IRQ: card reports no interrupt!\n");
+                               eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
                                return;
                        } 
                        break;
 #endif
                case EICON_CTYPE_MAESTRAP:
                        if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
-                               if (DebugVar & 1)
-                                       printk(KERN_DEBUG "eicon: IRQ: card reports no interrupt!\n");
+                               eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
                                return;
                        } 
                        break;
                case EICON_CTYPE_MAESTRA:
                        outw(0x3fe, pci_card->PCIreg + M_ADDR);
                        if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */
-                               if (DebugVar & 1)
-                                       printk(KERN_DEBUG "eicon: IRQ: card reports no interrupt!\n");
+                               eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
                                return;
                        } 
                        break;
@@ -738,8 +750,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
        if ((tmp = ram_inb(ccard, &com->Rc))) {
                eicon_RC *ack;
                if (tmp == READY_INT) {
-                       if (DebugVar & 64)
-                               printk(KERN_INFO "eicon: IRQ Rc=READY_INT\n");
+                               eicon_log(ccard, 64, "eicon: IRQ Rc=READY_INT\n");
                        if (ccard->ReadyInt) {
                                ccard->ReadyInt--;
                                ram_outb(ccard, &com->Rc, 0);
@@ -747,17 +758,15 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
                } else {
                        skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
                        if (!skb) {
-                               if (DebugVar & 1)
-                                       printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+                               eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
                        } else {
                                ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
                                ack->Rc = tmp;
                                ack->RcId = ram_inb(ccard, &com->RcId);
                                ack->RcCh = ram_inb(ccard, &com->RcCh);
                                ack->Reference = ccard->ref_in++;
-                               if (DebugVar & 64)
-                                       printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
-                                               tmp,ack->RcId,ack->RcCh,ack->Reference);
+                                       eicon_log(ccard, 128, "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
+                                       tmp,ack->RcId,ack->RcCh,ack->Reference);
                                skb_queue_tail(&ccard->rackq, skb);
                                eicon_schedule_ack(ccard);
                        }
@@ -773,8 +782,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
                        int len = ram_inw(ccard, &com->RBuffer.length);
                        skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
                        if (!skb) {
-                               if (DebugVar & 1)
-                                       printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+                               eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
                        } else {
                                ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
                                ind->Ind = tmp;
@@ -782,9 +790,12 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
                                ind->IndCh = ram_inb(ccard, &com->IndCh);
                                ind->MInd  = ram_inb(ccard, &com->MInd);
                                ind->MLength = ram_inw(ccard, &com->MLength);
-                               ind->RBuffer.length = len; 
-                               if (DebugVar & 64)
-                                       printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+                               ind->RBuffer.length = len;
+                               if ((tmp == 1) || (tmp == 8))
+                                       dlev = 128;
+                               else
+                                       dlev = 192;
+                                       eicon_log(ccard, dlev, "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
                                        tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
                                ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len);
                                skb_queue_tail(&ccard->rcvq, skb);
@@ -807,17 +818,15 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
                         if((Rc=ram_inb(ccard, &RcIn->Rc))) {
                                skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
                                if (!skb) {
-                                       if (DebugVar & 1)
-                                               printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+                                       eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
                                } else {
                                        ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
                                        ack->Rc = Rc;
                                        ack->RcId = ram_inb(ccard, &RcIn->RcId);
                                        ack->RcCh = ram_inb(ccard, &RcIn->RcCh);
                                        ack->Reference = ram_inw(ccard, &RcIn->Reference);
-                                       if (DebugVar & 64)
-                                               printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
-                                                       Rc,ack->RcId,ack->RcCh,ack->Reference);
+                                       eicon_log(ccard, 128, "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
+                                               Rc,ack->RcId,ack->RcCh,ack->Reference);
                                        skb_queue_tail(&ccard->rackq, skb);
                                        eicon_schedule_ack(ccard);
                                }
@@ -842,8 +851,7 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
                                int len = ram_inw(ccard, &IndIn->RBuffer.length);
                                skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
                                if (!skb) {
-                                       if (DebugVar & 1)
-                                               printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n");
+                                       eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
                                } else {
                                        ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
                                        ind->Ind = Ind;
@@ -852,8 +860,11 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
                                        ind->MInd  = ram_inb(ccard, &IndIn->MInd);
                                        ind->MLength = ram_inw(ccard, &IndIn->MLength);
                                        ind->RBuffer.length = len;
-                                       if (DebugVar & 64)
-                                               printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+                                       if ((Ind == 1) || (Ind == 8))
+                                               dlev = 128;
+                                       else
+                                               dlev = 192;
+                                       eicon_log(ccard, dlev, "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
                                                Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
                                        ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len);
                                        skb_queue_tail(&ccard->rcvq, skb);
index 7f86bd9ff4efcc1755d12bc63ea463e984af64b8..b0d0b0eb9e1ca965a12d58903995c7ef7e6386a9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.h,v 1.5 1999/09/08 20:17:31 armin Exp $
+/* $Id: eicon_isa.h,v 1.6 1999/11/15 19:37:04 keil Exp $
  *
  * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
  *
@@ -21,6 +21,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_isa.h,v $
+ * Revision 1.6  1999/11/15 19:37:04  keil
+ * need config.h
+ *
  * Revision 1.5  1999/09/08 20:17:31  armin
  * Added microchannel patch from Erik Weber.
  *
@@ -48,6 +51,7 @@
 #define eicon_isa_h
 
 #ifdef __KERNEL__
+#include <linux/config.h>
 
 /* Factory defaults for ISA-Cards */
 #define EICON_ISA_MEMBASE 0xd0000
index fca7b879f6bada4d9dea46651196c048c0e10130..a6a1ffd425b1fd375c8f031717b9909b706c1760 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.15 1999/09/08 20:17:31 armin Exp $
+/* $Id: eicon_mod.c,v 1.19 1999/11/12 13:21:44 armin Exp $
  *
  * ISDN lowlevel-module for Eicon.Diehl active cards.
  * 
  *
  *              Deutsche Telekom AG for S2M support.
  *
+ *             Deutsche Mailbox Saar-Lor-Lux GmbH
+ *             for sponsoring and testing fax
+ *             capabilities with Diva Server cards.
+ *             (dor@deutschemailbox.de)
+ *
  * 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, or (at your option)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: eicon_mod.c,v $
+ * Revision 1.19  1999/11/12 13:21:44  armin
+ * Bugfix of undefined reference with CONFIG_MCA
+ *
+ * Revision 1.18  1999/10/11 18:13:25  armin
+ * Added fax capabilities for Eicon Diva Server cards.
+ *
+ * Revision 1.17  1999/10/08 22:09:34  armin
+ * Some fixes of cards interface handling.
+ * Bugfix of NULL pointer occurence.
+ * Changed a few log outputs.
+ *
+ * Revision 1.16  1999/09/26 14:17:53  armin
+ * Improved debug and log via readstat()
+ *
  * Revision 1.15  1999/09/08 20:17:31  armin
  * Added microchannel patch from Erik Weber.
  *
 static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
                                                      start of card-list   */
 
-static char *eicon_revision = "$Revision: 1.15 $";
+static char *eicon_revision = "$Revision: 1.19 $";
 
 extern char *eicon_pci_revision;
 extern char *eicon_isa_revision;
@@ -185,8 +204,7 @@ find_channel(eicon_card *card, int channel)
 {
        if ((channel >= 0) && (channel < card->nchannels))
                return &(card->bch[channel]);
-       if (DebugVar & 1)
-               printk(KERN_WARNING "eicon: Invalid channel %d\n", channel);
+       eicon_log(card, 1, "eicon: Invalid channel %d\n", channel);
        return NULL;
 }
 
@@ -263,9 +281,8 @@ eicon_rcv_dispatch(struct eicon_card *card)
                        eicon_io_rcv_dispatch(card);
                        break;
                default:
-                       if (DebugVar & 1)
-                               printk(KERN_WARNING
-                                      "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
+                       eicon_log(card, 1,
+                              "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
        }
 }
 
@@ -279,9 +296,8 @@ eicon_ack_dispatch(struct eicon_card *card)
                        eicon_io_ack_dispatch(card);
                        break;
                default:
-                       if (DebugVar & 1)
-                               printk(KERN_WARNING
-                                       "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
+                       eicon_log(card, 1,
+                               "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
        }
 }
 
@@ -295,9 +311,8 @@ eicon_transmit(struct eicon_card *card)
                        eicon_io_transmit(card);
                        break;
                default:
-                       if (DebugVar & 1)
-                               printk(KERN_WARNING
-                                      "eicon_transmit: Illegal bustype %d\n", card->bus);
+                       eicon_log(card, 1,
+                              "eicon_transmit: Illegal bustype %d\n", card->bus);
        }
 }
 
@@ -307,8 +322,7 @@ static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq)
        int ret_val;
 
        if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) {
-               if (DebugVar & 1)
-                       printk(KERN_WARNING "idi_err: alloc_xlogreq_t failed\n");
+               eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n");
                return -ENOMEM;
        }
        if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) {
@@ -338,9 +352,8 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
        int ret = 0;
        unsigned long flags;
  
-       if (DebugVar & 16)
-               printk(KERN_WARNING "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n",
-                       c->command, c->arg, (ulong) *c->parm.num);
+       eicon_log(card, 16, "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n",
+               c->command, c->arg, (ulong) *c->parm.num);
 
         switch (c->command) {
                case ISDN_CMD_IOCTL:
@@ -360,9 +373,8 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                                                        return card->hwif.pci.PCIram;
 #endif
                                                default:
-                                                       if (DebugVar & 1)
-                                                               printk(KERN_WARNING
-                                                                      "eicon: Illegal BUS type %d\n",
+                                                       eicon_log(card, 1,
+                                                              "eicon: Illegal BUS type %d\n",
                                                               card->bus);
                                                        ret = -ENODEV;
                                        }
@@ -389,9 +401,8 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                                                        return 0;
 #endif /* CONFIG_MCA */
                                                default:
-                                                       if (DebugVar & 1)
-                                                               printk(KERN_WARNING
-                                                                       "eicon: Illegal BUS type %d\n",
+                                                       eicon_log(card, 1,
+                                                               "eicon: Illegal BUS type %d\n",
                                                               card->bus);
                                                        ret = -ENODEV;
                                        }                                       
@@ -406,9 +417,8 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                                                        return card->hwif.pci.irq;
 #endif
                                                default:
-                                                       if (DebugVar & 1)
-                                                               printk(KERN_WARNING
-                                                                      "eicon: Illegal BUS type %d\n",
+                                                       eicon_log(card, 1,
+                                                              "eicon: Illegal BUS type %d\n",
                                                               card->bus);
                                                        ret = -ENODEV;
                                        }
@@ -423,9 +433,8 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                                                        card->hwif.isa.irq = a;
                                                        return 0;
                                                default:
-                                                       if (DebugVar & 1)
-                                                               printk(KERN_WARNING
-                                                                       "eicon: Illegal BUS type %d\n",
+                                                       eicon_log(card, 1,
+                                                               "eicon: Illegal BUS type %d\n",
                                                               card->bus);
                                                        ret = -ENODEV;
                                        }                                       
@@ -441,9 +450,8 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                                                                &(((eicon_codebuf *)a)->isa));
                                                        break;
                                                default:
-                                                       if (DebugVar & 1)
-                                                               printk(KERN_WARNING
-                                                                      "eicon: Illegal BUS type %d\n",
+                                                       eicon_log(card, 1,
+                                                              "eicon: Illegal BUS type %d\n",
                                                               card->bus);
                                                        ret = -ENODEV;
                                        }
@@ -475,9 +483,8 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                                                        }
                                                        break;
                                                default:
-                                                       if (DebugVar & 1)
-                                                               printk(KERN_WARNING
-                                                                      "eicon: Illegal BUS type %d\n",
+                                                       eicon_log(card, 1,
+                                                              "eicon: Illegal BUS type %d\n",
                                                               card->bus);
                                                        ret = -ENODEV;
                                        }
@@ -541,7 +548,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                                        return 0;
                                case EICON_IOCTL_DEBUGVAR:
                                        DebugVar = a;
-                                       printk(KERN_DEBUG"Eicon: Debug Value set to %ld\n", DebugVar);
+                                       eicon_log(card, 1, "Eicon: Debug Value set to %ld\n", DebugVar);
                                        return 0;
 #ifdef MODULE
                                case EICON_IOCTL_FREEIT:
@@ -562,8 +569,7 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                        cli();
                        if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) {
                                restore_flags(flags);
-                               if (DebugVar & 1)
-                                       printk(KERN_WARNING "Dial on channel %d with state %d\n",
+                               eicon_log(card, 1, "Dial on channel %d with state %d\n",
                                        chan->No, chan->fsm_state);
                                return -EBUSY;
                        }
@@ -572,7 +578,6 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                        else
                                tmp[0] = c->parm.setup.eazmsn[0];
                        chan->fsm_state = EICON_STATE_OCALL;
-                       chan->callref = 0xffff;
                        restore_flags(flags);
                        
                        ret = idi_connect_req(card, chan, c->parm.setup.phone,
@@ -667,20 +672,17 @@ eicon_command(eicon_card * card, isdn_ctrl * c)
                case ISDN_CMD_GETEAZ:
                        if (!card->flags & EICON_FLAGS_RUNNING)
                                return -ENODEV;
-                       if (DebugVar & 1)
-                               printk(KERN_DEBUG "eicon CMD_GETEAZ not implemented\n");
+                       eicon_log(card, 1, "eicon CMD_GETEAZ not implemented\n");
                        return 0;
                case ISDN_CMD_SETSIL:
                        if (!card->flags & EICON_FLAGS_RUNNING)
                                return -ENODEV;
-                       if (DebugVar & 1)
-                               printk(KERN_DEBUG "eicon CMD_SETSIL not implemented\n");
+                       eicon_log(card, 1, "eicon CMD_SETSIL not implemented\n");
                        return 0;
                case ISDN_CMD_GETSIL:
                        if (!card->flags & EICON_FLAGS_RUNNING)
                                return -ENODEV;
-                       if (DebugVar & 1)
-                               printk(KERN_DEBUG "eicon CMD_GETSIL not implemented\n");
+                       eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n");
                        return 0;
                case ISDN_CMD_LOCK:
                        MOD_INC_USE_COUNT;
@@ -752,6 +754,52 @@ if_writecmd(const u_char * buf, int len, int user, int id, int channel)
 static int
 if_readstatus(u_char * buf, int len, int user, int id, int channel)
 {
+       int count = 0;
+       int cnt = 0;
+       ulong flags = 0;
+       u_char *p = buf;
+       struct sk_buff *skb;
+
+        eicon_card *card = eicon_findcard(id);
+       
+        if (card) {
+                if (!card->flags & EICON_FLAGS_RUNNING)
+                        return -ENODEV;
+       
+               save_flags(flags);
+               cli();
+               while((skb = skb_dequeue(&card->statq))) {
+
+                       if ((skb->len + count) > len)
+                               cnt = len - count;
+                       else
+                               cnt = skb->len;
+
+                       if (user)
+                               copy_to_user(p, skb->data, cnt);
+                       else
+                               memcpy(p, skb->data, cnt);
+
+                       count += cnt;
+                       p += cnt;
+
+                       if (cnt == skb->len) {
+                               dev_kfree_skb(skb);
+                               if (card->statq_entries > 0)
+                                       card->statq_entries--;
+                       } else {
+                               skb_pull(skb, cnt);
+                               skb_queue_head(&card->statq, skb);
+                               restore_flags(flags);
+                               return count;
+                       }
+               }
+               card->statq_entries = 0;
+               restore_flags(flags);
+               return count;
+        }
+        printk(KERN_ERR
+               "eicon: if_readstatus called with invalid driverId!\n");
         return 0;
 }
 
@@ -766,14 +814,11 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
        len = skb->len;
        
         if (card) {
-                if (!card->flags & EICON_FLAGS_RUNNING) {
-                       dev_kfree_skb(skb);
+                if (!card->flags & EICON_FLAGS_RUNNING)
                         return -ENODEV;
-               }
-               if (!(chan = find_channel(card, channel))) {
-                       dev_kfree_skb(skb);
+               if (!(chan = find_channel(card, channel)))
                        return -ENODEV;
-               }
+
                if (chan->fsm_state == EICON_STATE_ACTIVE) {
 #ifdef CONFIG_ISDN_TTY_FAX
                        if (chan->l2prot == ISDN_PROTO_L2_FAX) {
@@ -785,16 +830,115 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
                                ret = idi_send_data(card, chan, ack, skb, 1);
                        return (ret);
                } else {
-                       dev_kfree_skb(skb);
                        return -ENODEV;
                }
         }
         printk(KERN_ERR
                "eicon: if_sendbuf called with invalid driverId!\n");
-       dev_kfree_skb(skb);
         return -ENODEV;
 }
 
+/* jiftime() copied from HiSax */
+inline int
+jiftime(char *s, long mark)
+{
+        s += 8;
+
+        *s-- = '\0';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = '.';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 6 + '0';
+        mark /= 6;
+        *s-- = ':';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 10 + '0';
+        return(8);
+}
+
+void
+eicon_putstatus(eicon_card * card, char * buf)
+{
+       ulong flags;
+       int count;
+       isdn_ctrl cmd;
+       u_char *p;
+       struct sk_buff *skb;
+
+       if (!card)
+               return;
+
+       save_flags(flags);
+       cli();
+       count = strlen(buf);
+       skb = alloc_skb(count, GFP_ATOMIC);
+       if (!skb) {
+               restore_flags(flags);
+               printk(KERN_ERR "eicon: could not alloc skb in putstatus\n");
+               return;
+       }
+       p = skb_put(skb, count);
+       memcpy(p, buf, count);
+
+       skb_queue_tail(&card->statq, skb);
+
+       if (card->statq_entries >= MAX_STATUS_BUFFER) {
+               if ((skb = skb_dequeue(&card->statq))) {
+                       count -= skb->len;
+                       dev_kfree_skb(skb);
+               } else
+                       count = 0;
+       } else
+               card->statq_entries++;
+
+       restore_flags(flags);
+        if (count) {
+                cmd.command = ISDN_STAT_STAVAIL;
+                cmd.driver = card->myid;
+                cmd.arg = count;
+               card->interface.statcallb(&cmd);
+        }
+}
+
+/*
+ * Debug and Log 
+ */
+void
+eicon_log(eicon_card * card, int level, const char *fmt, ...)
+{
+       va_list args;
+       char Line[160];
+       u_char *p;
+
+
+       if ((DebugVar & level) || (DebugVar & 256)) {
+               va_start(args, fmt);
+
+               if (DebugVar & level) {
+                       if (DebugVar & 256) {
+                               /* log-buffer */
+                               p = Line;
+                               p += jiftime(p, jiffies);
+                               *p++ = 32;
+                               p += vsprintf(p, fmt, args);
+                               *p = 0; 
+                               eicon_putstatus(card, Line);
+                       } else {
+                               /* printk, syslogd */
+                               vsprintf(Line, fmt, args);
+                               printk(KERN_DEBUG "%s", Line);
+                       }
+               }
+
+               va_end(args);
+       }
+}
+
 
 /*
  * Allocate a new card-struct, initialize it
@@ -817,7 +961,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
        qloop = (Type == EICON_CTYPE_QUADRO)?2:0;
        for (i = 0; i <= qloop; i++) {
                if (!(card = (eicon_card *) kmalloc(sizeof(eicon_card), GFP_KERNEL))) {
-                       printk(KERN_WARNING
+                       eicon_log(card, 1,
                               "eicon: (%s) Could not allocate card-struct.\n", id);
                        return;
                }
@@ -826,6 +970,8 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
                skb_queue_head_init(&card->rcvq);
                skb_queue_head_init(&card->rackq);
                skb_queue_head_init(&card->sackq);
+               skb_queue_head_init(&card->statq);
+               card->statq_entries = 0;
                card->snd_tq.routine = (void *) (void *) eicon_transmit;
                card->snd_tq.data = card;
                card->rcv_tq.routine = (void *) (void *) eicon_rcv_dispatch;
@@ -897,7 +1043,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
                                                p = p->next;
                                        }
                                        if (!p) {
-                                               printk(KERN_WARNING "eicon_alloccard: Quadro Master not found.\n");
+                                               eicon_log(card, 1, "eicon_alloccard: Quadro Master not found.\n");
                                                kfree(card);
                                                return;
                                        }
@@ -919,7 +1065,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
                                        ISDN_FEATURE_L2_V11019 |
                                        ISDN_FEATURE_L2_V11038 |
                                        ISDN_FEATURE_L2_MODEM |
-                                       /* ISDN_FEATURE_L2_FAX | */ 
+                                       ISDN_FEATURE_L2_FAX | 
                                        ISDN_FEATURE_L3_TRANSDSP |
                                        ISDN_FEATURE_L3_FAX;
                                 card->hwif.pci.card = (void *)card;
@@ -943,7 +1089,7 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
                                        ISDN_FEATURE_L2_V11019 |
                                        ISDN_FEATURE_L2_V11038 |
                                        ISDN_FEATURE_L2_MODEM |
-                                       /* ISDN_FEATURE_L2_FAX | */
+                                       ISDN_FEATURE_L2_FAX |
                                        ISDN_FEATURE_L3_TRANSDSP |
                                        ISDN_FEATURE_L3_FAX;
                                 card->hwif.pci.card = (void *)card;
@@ -992,13 +1138,13 @@ eicon_alloccard(int Type, int membase, int irq, char *id)
                                break;
 #endif
                        default:
-                               printk(KERN_WARNING "eicon_alloccard: Invalid type %d\n", Type);
+                               eicon_log(card, 1, "eicon_alloccard: Invalid type %d\n", Type);
                                kfree(card);
                                return;
                }
                if (!(card->bch = (eicon_chan *) kmalloc(sizeof(eicon_chan) * (card->nchannels + 1)
                                                         , GFP_KERNEL))) {
-                       printk(KERN_WARNING
+                       eicon_log(card, 1,
                               "eicon: (%s) Could not allocate bch-struct.\n", id);
                        kfree(card);
                        return;
@@ -1044,9 +1190,8 @@ eicon_registercard(eicon_card * card)
                        break;
 #endif
                default:
-                       if (DebugVar & 1)
-                               printk(KERN_WARNING
-                                      "eicon_registercard: Illegal BUS type %d\n",
+                       eicon_log(card, 1,
+                              "eicon_registercard: Illegal BUS type %d\n",
                               card->bus);
                        return -1;
         }
@@ -1085,9 +1230,8 @@ unregister_card(eicon_card * card)
                        break;
 #endif
                default:
-                       if (DebugVar & 1)
-                               printk(KERN_WARNING
-                                      "eicon: Invalid BUS type %d\n",
+                       eicon_log(card, 1,
+                              "eicon: Invalid BUS type %d\n",
                               card->bus);
                        break;
         }
@@ -1096,6 +1240,26 @@ unregister_card(eicon_card * card)
 
 static void
 eicon_freecard(eicon_card *card) {
+       int i;
+       struct sk_buff *skb;
+
+       for(i = 0; i < (card->nchannels + 1); i++) {
+               while((skb = skb_dequeue(&card->bch[i].e.X)))
+                       dev_kfree_skb(skb);
+               while((skb = skb_dequeue(&card->bch[i].e.R)))
+                       dev_kfree_skb(skb);
+       }
+       while((skb = skb_dequeue(&card->sndq)))
+               dev_kfree_skb(skb);
+       while((skb = skb_dequeue(&card->rcvq)))
+               dev_kfree_skb(skb);
+       while((skb = skb_dequeue(&card->rackq)))
+               dev_kfree_skb(skb);
+       while((skb = skb_dequeue(&card->sackq)))
+               dev_kfree_skb(skb);
+       while((skb = skb_dequeue(&card->statq)))
+               dev_kfree_skb(skb);
+
        eicon_clear_msn(card);
        kfree(card->bch);
        kfree(card);
@@ -1141,9 +1305,8 @@ eicon_addcard(int Type, int membase, int irq, char *id)
                                        break;
 #endif
                                default:
-                                       if (DebugVar & 1)
-                                               printk(KERN_WARNING
-                                                      "eicon: addcard: Invalid BUS type %d\n",
+                                       printk(KERN_ERR
+                                              "eicon: addcard: Invalid BUS type %d\n",
                                               p->bus);
                        }
                } else
@@ -1155,7 +1318,7 @@ eicon_addcard(int Type, int membase, int irq, char *id)
                         p = p->next;
                 } else {
                         /* registering failed, remove card from list, free memory */
-                        printk(KERN_WARNING
+                        printk(KERN_ERR
                                "eicon: Initialization of %s failed\n",
                                p->interface.id);
                         if (q) {
@@ -1222,10 +1385,9 @@ eicon_init(void)
                 printk(KERN_INFO
                         "eicon: No MCA bus, ISDN-interfaces  not probed.\n");
         } else {
-               if (DebugVar & 8)
-                               printk(KERN_DEBUG
-                              "eicon_mca_find_card, irq=%d.\n", 
-                                irq);
+               eicon_log(NULL, 8,
+                       "eicon_mca_find_card, irq=%d.\n", 
+                               irq);
                        if (!eicon_mca_find_card(0, membase, irq, id))
                        card_count++;
         };
@@ -1346,10 +1508,9 @@ int eicon_mca_find_card(int type,          /* type-idx of eicon-card          */
 {
        int j, curr_slot = 0;
 
-       if (DebugVar & 8)
-               printk(KERN_DEBUG
-                       "eicon_mca_find_card type: %d, membase: %#x, irq %d \n",
-                       type, membase, irq);
+               eicon_log(NULL, 8,
+               "eicon_mca_find_card type: %d, membase: %#x, irq %d \n",
+               type, membase, irq);
        /* find a no-driver-assigned eicon card                               */
        for (j=0; eicon_mca_adapters[j].adf_id != 0; j++) 
                {
@@ -1414,11 +1575,10 @@ int eicon_mca_probe(int slot,  /* slot-nr where the card was detected         */
        int irq_array1[]={3,4,0,0,2,10,11,12};
 
         adf_pos0 = mca_read_stored_pos(slot,2);
-       if (DebugVar & 8)
-               printk(KERN_DEBUG
-                       "eicon_mca_probe irq=%d, membase=%d\n", 
-                        irq,
-                        membase);
+       eicon_log(NULL, 8,
+               "eicon_mca_probe irq=%d, membase=%d\n", 
+               irq,
+               membase);
        switch (a_idx) {
                case 0:                /* P/2-Adapter (== PRI/S2M ? )         */
                        cards_membase= 0xC0000+((adf_pos0>>4)*0x4000);
@@ -1473,7 +1633,7 @@ int eicon_mca_probe(int slot,  /* slot-nr where the card was detected         */
                default:
                        return  ENODEV;
        };
-       /* Uebereinstimmung vorgegebener membase & irq */
+       /* matching membase & irq */
        if ( 1 == eicon_addcard(type, membase, irq, id)) { 
                mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name);
                mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards);
@@ -1486,10 +1646,9 @@ int eicon_mca_probe(int slot,  /* slot-nr where the card was detected         */
                /* reset card */
                outb_p(0,cards_io+1);
 
-               if (DebugVar & 8)
-                       printk(KERN_INFO "eicon_addcard: successful for slot # %d.\n", 
+               eicon_log(NULL, 8, "eicon_addcard: successful for slot # %d.\n", 
                        cards->mca_slot+1);
-               return  0 ; /* eicon_addcard hat eine Karte zugefuegt */
+               return  0 ; /* eicon_addcard added a card */
        } else {
                return ENODEV;
        };
index 3bd1ffa69922f06ccc082d58e7960f053fcd585c..e4c26d9debd2c3a08aaf68b52d0f5c8c81333997 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.37 1999/09/20 19:49:47 keil Exp $
+/* $Id: callc.c,v 2.39 1999/10/14 20:25:28 keil Exp $
 
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: callc.c,v $
+ * Revision 2.39  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
+ * Revision 2.38  1999/10/11 22:16:27  keil
+ * Suspend/Resume is possible without explicit ID too
+ *
  * Revision 2.37  1999/09/20 19:49:47  keil
  * Fix wrong init of PStack
  *
 #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
 #endif /* MODULE */
 
-const char *lli_revision = "$Revision: 2.37 $";
+const char *lli_revision = "$Revision: 2.39 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
@@ -1477,11 +1483,6 @@ leased_l1l2(struct PStack *st, int pr, void *arg)
        }
 }
 
-static void
-channel_report(struct Channel *chanp)
-{
-}
-
 static void
 distr_debug(struct IsdnCardState *csta, int debugflags)
 {
@@ -1515,7 +1516,6 @@ capi_debug(struct Channel *chanp, capi_msg *cm)
 {
        char *t = tmpbuf;
 
-       t += sprintf(tmpbuf, "%d CAPIMSG", chanp->chan);
        t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length);
        t--;
        *t= 0;
@@ -1532,20 +1532,16 @@ lli_got_fac_req(struct Channel *chanp, capi_msg *cm) {
                return;
        switch(cm->para[3]) {
                case 4: /* Suspend */
-                       if (cm->para[5]) {
-                               strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
-                               FsmEvent(&chanp->fi, EV_SUSPEND, cm);
-                       }
+                       strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
+                       FsmEvent(&chanp->fi, EV_SUSPEND, cm);
                        break;
                case 5: /* Resume */
-                       if (cm->para[5]) {
-                               strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
-                               if (chanp->fi.state == ST_NULL) {
-                                       FsmEvent(&chanp->fi, EV_RESUME, cm);
-                               } else {
-                                       FsmDelTimer(&chanp->dial_timer, 72);
-                                       FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73);
-                               }
+                       strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
+                       if (chanp->fi.state == ST_NULL) {
+                               FsmEvent(&chanp->fi, EV_RESUME, cm);
+                       } else {
+                               FsmDelTimer(&chanp->dial_timer, 72);
+                               FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73);
                        }
                        break;
        }
@@ -1697,9 +1693,8 @@ HiSax_command(isdn_ctrl * ic)
                case (ISDN_CMD_IOCTL):
                        switch (ic->arg) {
                                case (0):
-                                       HiSax_reportcard(csta->cardnr);
-                                       for (i = 0; i < 2; i++)
-                                               channel_report(&csta->channel[i]);
+                                       num = *(unsigned int *) ic->parm.num;
+                                       HiSax_reportcard(csta->cardnr, num);
                                        break;
                                case (1):
                                        num = *(unsigned int *) ic->parm.num;
index 700708c07a662f03aba2f7117af8c01d9e599448..af28241b66ff3aca67b67d67660e2bef025c7fc7 100644 (file)
@@ -1,10 +1,19 @@
-/* $Id: config.c,v 2.37 1999/09/20 12:11:08 keil Exp $
+/* $Id: config.c,v 2.40 1999/10/30 13:09:45 keil Exp $
 
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
  *
  * $Log: config.c,v $
+ * Revision 2.40  1999/10/30 13:09:45  keil
+ * Version 3.3c
+ *
+ * Revision 2.39  1999/10/16 14:44:45  keil
+ * Fix module parm if only NICCY was selected
+ *
+ * Revision 2.38  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 2.37  1999/09/20 12:11:08  keil
  * Fix hang if no protocol was selected
  *
@@ -483,10 +492,10 @@ MODULE_PARM(io, "1-8i");
 MODULE_PARM(irq, "1-8i");
 MODULE_PARM(mem, "1-8i");
 MODULE_PARM(id, "s");
-#ifdef CONFIG_HISAX_16_3       /* For Creatix/Teles PnP */
+#ifdef IO0_IO1
 MODULE_PARM(io0, "1-8i");
 MODULE_PARM(io1, "1-8i");
-#endif /* CONFIG_HISAX_16_3 */
+#endif /* IO0_IO1 */
 #endif /* MODULE */
 
 int nrcards;
@@ -519,9 +528,9 @@ HiSaxVersion(void))
 
        printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
 #ifdef MODULE
-       printk(KERN_INFO "HiSax: Version 3.3a (module)\n");
+       printk(KERN_INFO "HiSax: Version 3.3c (module)\n");
 #else
-       printk(KERN_INFO "HiSax: Version 3.3a (kernel)\n");
+       printk(KERN_INFO "HiSax: Version 3.3c (kernel)\n");
 #endif
        strcpy(tmp, l1_revision);
        printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
@@ -1369,12 +1378,9 @@ HiSax_closecard(int cardnr)
 }
 
 void
-HiSax_reportcard(int cardnr)
+HiSax_reportcard(int cardnr, int sel)
 {
        struct IsdnCardState *cs = cards[cardnr].cs;
-       struct PStack *stptr;
-       struct l3_process *pc;
-       int j, i = 1;
 
        printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1);
        printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]);
@@ -1382,45 +1388,33 @@ HiSax_reportcard(int cardnr)
        printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
                (ulong) & HiSax_reportcard);
        printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
-       printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc0 flg %x\n",
+       printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc1 flg %x\n",
                cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
        printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
                cs->bcs[0].mode, cs->bcs[0].channel);
        printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
                cs->bcs[1].mode, cs->bcs[1].channel);
-       printk(KERN_DEBUG "HiSax: cs setstack_d 0x%lX\n", (ulong) cs->setstack_d);
-       printk(KERN_DEBUG "HiSax: cs stl 0x%lX\n", (ulong) & (cs->stlist));
-       stptr = cs->stlist;
-       while (stptr != NULL) {
-               printk(KERN_DEBUG "HiSax: dst%d 0x%lX\n", i, (ulong) stptr);
-               printk(KERN_DEBUG "HiSax: dst%d stp 0x%lX\n", i, (ulong) stptr->l1.stlistp);
-               printk(KERN_DEBUG "HiSax: dst%d l1.l1hw 0x%lX\n", i, (ulong) stptr->l1.l1hw);
-               printk(KERN_DEBUG "HiSax:   tei %d sapi %d\n",
-                      stptr->l2.tei, stptr->l2.sap);
-               printk(KERN_DEBUG "HiSax:      man 0x%lX\n", (ulong) stptr->ma.layer);
-               pc = stptr->l3.proc;
-               while (pc) {
-                       printk(KERN_DEBUG "HiSax: l3proc %x 0x%lX\n", pc->callref,
-                              (ulong) pc);
-                       printk(KERN_DEBUG "HiSax:    state %d  st 0x%lX chan 0x%lX\n",
-                           pc->state, (ulong) pc->st, (ulong) pc->chan);
-                       pc = pc->next;
-               }
-               stptr = stptr->next;
-               i++;
-       }
-       for (j = 0; j < 2; j++) {
-               printk(KERN_DEBUG "HiSax: ch%d 0x%lX\n", j,
-                      (ulong) & cs->channel[j]);
-               stptr = cs->channel[j].b_st;
-               i = 1;
-               while (stptr != NULL) {
-                       printk(KERN_DEBUG "HiSax:  b_st%d 0x%lX\n", i, (ulong) stptr);
-                       printk(KERN_DEBUG "HiSax:    man 0x%lX\n", (ulong) stptr->ma.layer);
-                       stptr = stptr->next;
-                       i++;
-               }
+#ifdef ERROR_STATISTIC
+       printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n",
+               cs->err_rx, cs->err_crc, cs->err_tx);
+       printk(KERN_DEBUG "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+               cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, cs->bcs[0].err_tx);
+       printk(KERN_DEBUG "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n",
+               cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, cs->bcs[1].err_tx);
+       if (sel == 99) {
+               cs->err_rx  = 0;
+               cs->err_crc = 0;
+               cs->err_tx  = 0;
+               cs->bcs[0].err_inv = 0;
+               cs->bcs[0].err_rdo = 0;
+               cs->bcs[0].err_crc = 0;
+               cs->bcs[0].err_tx  = 0;
+               cs->bcs[1].err_inv = 0;
+               cs->bcs[1].err_rdo = 0;
+               cs->bcs[1].err_crc = 0;
+               cs->bcs[1].err_tx  = 0;
        }
+#endif
 }
 
 
@@ -1599,9 +1593,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 
        nrcards = 0;
        HiSaxVersion();
-       if (id)                 /* If id= string used */
-               HiSax_id = id;
-       /* Initialize all 8 structs, even though we only accept
+       /* Initialize all structs, even though we only accept
           two pcmcia cards
           */
        for (i = 0; i < HISAX_MAX_CARDS; i++) {
@@ -1650,9 +1642,7 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 
        nrcards = 0;
        HiSaxVersion();
-       if (id)                 /* If id= string used */
-               HiSax_id = id;
-       /* Initialize all 8 structs, even though we only accept
+       /* Initialize all structs, even though we only accept
           two pcmcia cards
           */
        for (i = 0; i < HISAX_MAX_CARDS; i++) {
@@ -1701,12 +1691,10 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 
        nrcards = 0;
        HiSaxVersion();
-       if (id)                 /* If id= string used */
-               HiSax_id = id;
-       /* Initialize all 16 structs, even though we only accept
+       /* Initialize all structs, even though we only accept
           two pcmcia cards
           */
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < HISAX_MAX_CARDS; i++) {
                cards[i].para[0] = irq[i];
                cards[i].para[1] = io[i];
                cards[i].typ = type[i];
index 5a1a9b03f808d34f330d7c463af195b20ea6c51c..bb388c5c28c742795d6c1b6d4eda5df3efdcb054 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.c,v 1.9 1999/07/01 08:11:35 keil Exp $
+/* $Id: hfc_2bds0.c,v 1.10 1999/10/14 20:25:28 keil Exp $
  *
  *  specific routines for CCD's HFC 2BDS0
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: hfc_2bds0.c,v $
+ * Revision 1.10  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.9  1999/07/01 08:11:35  keil
  * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
  *
@@ -260,6 +263,9 @@ static struct sk_buff
                if (cs->debug & L1_DEB_WARN)
                        debugl1(cs, "hfc_empty_fifo: incoming packet too small");
                cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);
+#ifdef ERROR_STATISTIC
+               bcs->err_inv++;
+#endif
                cli();
                while ((idx++ < count) && WaitNoBusy(cs))
                        ReadReg(cs, HFCD_DATA_NODEB, cip);
@@ -302,6 +308,9 @@ static struct sk_buff
                                debugl1(cs, "FIFO CRC error");
                                dev_kfree_skb(skb);
                                skb = NULL;
+#ifdef ERROR_STATISTIC
+                               bcs->err_crc++;
+#endif
                        }
                }
        }
@@ -741,6 +750,9 @@ int receive_dmsg(struct IsdnCardState *cs)
                                printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n");
                                dev_kfree_skb(skb);
                                skb = NULL;
+#ifdef ERROR_STATISTIC
+                               cs->err_rx++;
+#endif
                        } else {
                                cli();
                                WaitNoBusy(cs);
@@ -757,6 +769,9 @@ int receive_dmsg(struct IsdnCardState *cs)
                                        debugl1(cs, "FIFO CRC error");
                                        dev_kfree_skb(skb);
                                        skb = NULL;
+#ifdef ERROR_STATISTIC
+                                       cs->err_crc++;
+#endif
                                } else {
                                        skb_queue_tail(&cs->rq, skb);
                                        sched_event_D(cs, D_RCVBUFREADY);
index 877eac7cfaac352c0c3c27711e94f4488fa93949..6620b90ecee3db4bb9bc19d903358fa475242fbb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.c,v 1.9 1999/07/01 08:11:36 keil Exp $
+/* $Id: hfc_2bs0.c,v 1.10 1999/10/14 20:25:28 keil Exp $
 
  *  specific routines for CCD's HFC 2BS0
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: hfc_2bs0.c,v $
+ * Revision 1.10  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.9  1999/07/01 08:11:36  keil
  * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
  *
@@ -217,6 +220,9 @@ hfc_empty_fifo(struct BCState *bcs, int count)
                stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
                                       HFC_CHANNEL(bcs->channel));
                WaitForBusy(cs);
+#ifdef ERROR_STATISTIC
+               bcs->err_inv++;
+#endif
                return (NULL);
        }
        if (!(skb = dev_alloc_skb(count - 3)))
@@ -252,6 +258,9 @@ hfc_empty_fifo(struct BCState *bcs, int count)
                        debugl1(cs, "FIFO CRC error");
                        dev_kfree_skb(skb);
                        skb = NULL;
+#ifdef ERROR_STATISTIC
+                       bcs->err_crc++;
+#endif
                }
                WaitNoBusy(cs);
                stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
index c7bd5b013bbdf862f14f812fea7e820755789802..44eb6c132975b623c1082c9295c5b417e6e879bc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.20 1999/09/07 06:18:55 werner Exp $
+/* $Id: hfc_pci.c,v 1.23 1999/11/07 17:01:55 keil Exp $
 
  * hfc_pci.c     low level driver for CCD´s hfc-pci based cards
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: hfc_pci.c,v $
+ * Revision 1.23  1999/11/07 17:01:55  keil
+ * fix for 2.3 pci structs
+ *
+ * Revision 1.22  1999/10/10 20:14:27  werner
+ *
+ * Correct B2-chan usage in conjuntion with echo mode. First implementation of NT-leased line mode.
+ *
+ * Revision 1.21  1999/10/02 17:47:49  werner
+ *
+ * Changed init order, added correction for page alignment with shared mem
+ *
  * Revision 1.20  1999/09/07 06:18:55  werner
  *
  * Added io parameter for HFC-PCI based cards. Needed only with multiple cards
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.20 $";
+static const char *hfcpci_revision = "$Revision: 1.23 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
-  int vendor_id; 
-  int device_id;
-  char *vendor_name;
-  char *card_name;
-  } PCI_ENTRY;
-
-static const PCI_ENTRY id_list[] = {
-  {0x1397,0x2BD0,"CCD/Billion/Asuscom","2BD0"},
-  {0x1397,0xB000,"Billion","B000"},
-  {0x1397,0xB006,"Billion","B006"},
-  {0x1397,0xB007,"Billion","B007"},
-  {0x1397,0xB008,"Billion","B008"},
-  {0x1397,0xB009,"Billion","B009"},
-  {0x1397,0xB00A,"Billion","B00A"},
-  {0x1397,0xB00B,"Billion","B00B"},
-  {0x1397,0xB00C,"Billion","B00C"},
-  {0x1043,0x0675,"Asuscom/Askey","675"},
-  {0x0871,0xFFA2,"German telekom","T-Concept"},
-  {0x0871,0xFFA1,"German telekom","A1T"},
-  {0x1051,0x0100,"Motorola MC145575","MC145575"},
-  {0x1397,0xB100,"Seyeon","B100"},
-  {0x15B0,0x2BD0,"Zoltrix","2BD0"},
-  {0,0,NULL,NULL},      
+       int vendor_id;
+       int device_id;
+       char *vendor_name;
+       char *card_name;
+} PCI_ENTRY;
+
+#define NT_T1_COUNT 20         /* number of 3.125ms interrupts for G2 timeout */
+
+static const PCI_ENTRY id_list[] =
+{
+       {0x1397, 0x2BD0, "CCD/Billion/Asuscom", "2BD0"},
+       {0x1397, 0xB000, "Billion", "B000"},
+       {0x1397, 0xB006, "Billion", "B006"},
+       {0x1397, 0xB007, "Billion", "B007"},
+       {0x1397, 0xB008, "Billion", "B008"},
+       {0x1397, 0xB009, "Billion", "B009"},
+       {0x1397, 0xB00A, "Billion", "B00A"},
+       {0x1397, 0xB00B, "Billion", "B00B"},
+       {0x1397, 0xB00C, "Billion", "B00C"},
+       {0x1043, 0x0675, "Asuscom/Askey", "675"},
+       {0x0871, 0xFFA2, "German telekom", "T-Concept"},
+       {0x0871, 0xFFA1, "German telekom", "A1T"},
+       {0x1051, 0x0100, "Motorola MC145575", "MC145575"},
+       {0x1397, 0xB100, "Seyeon", "B100"},
+       {0x15B0, 0x2BD0, "Zoltrix", "2BD0"},
+       {0, 0, NULL, NULL},
 };
 
 
@@ -156,9 +170,21 @@ releasehfcpci(struct IsdnCardState *cs)
 void
 release_io_hfcpci(struct IsdnCardState *cs)
 {
+       int flags;
+
+       save_flags(flags);
+       cli();
+       cs->hw.hfcpci.int_m2 = 0;       /* interrupt output off ! */
+       Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+       restore_flags(flags);
+       Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);       /* Reset On */
+       sti();
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout((30 * HZ) / 1000);     /* Timeout 30ms */
+       Write_hfc(cs, HFCPCI_CIRM, 0);  /* Reset Off */
 #if CONFIG_PCI
-       pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);  /* disabe memory mapped ports + busmaster */
-#endif /* CONFIG_PCI */
+       pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);  /* disable memory mapped ports + busmaster */
+#endif                         /* CONFIG_PCI */
        releasehfcpci(cs);
        del_timer(&cs->hw.hfcpci.timer);
        kfree(cs->hw.hfcpci.share_start);
@@ -175,11 +201,15 @@ reset_hfcpci(struct IsdnCardState *cs)
 {
        long flags;
 
+       save_flags(flags);
+       cli();
        pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO);      /* enable memory mapped ports, disable busmaster */
+       cs->hw.hfcpci.int_m2 = 0;       /* interrupt output off ! */
+       Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+
        printk(KERN_INFO "HFC_PCI: resetting card\n");
        pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER);     /* enable memory ports + busmaster */
        Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);       /* Reset On */
-       save_flags(flags);
        sti();
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout((30 * HZ) / 1000);     /* Timeout 30ms */
@@ -192,25 +222,23 @@ reset_hfcpci(struct IsdnCardState *cs)
        cs->hw.hfcpci.fifo_en = 0x30;   /* only D fifos enabled */
        Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
 
-       cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */
+       cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK;        /* no echo connect , threshold */
        Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
 
        Write_hfc(cs, HFCPCI_CLKDEL, 0x0e);     /* ST-Bit delay for TE-Mode */
        cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;
        Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);   /* S/T Auto awake */
-       cs->hw.hfcpci.bswapped = 0; /* no exchange */
+       cs->hw.hfcpci.bswapped = 0;     /* no exchange */
+       cs->hw.hfcpci.nt_mode = 0;      /* we are in TE mode */
        cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;
        Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
 
-       cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
-       cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | 
-                              HFCPCI_INTS_L1STATE | HFCPCI_CLTIMER;
+       cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |
+           HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;
        Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-       Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
 
        /* Clear already pending ints */
        if (Read_hfc(cs, HFCPCI_INT_S1));
-       if (Read_hfc(cs, HFCPCI_INT_S2));
 
        Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2);    /* HFC ST 2 */
        udelay(10);
@@ -218,24 +246,29 @@ reset_hfcpci(struct IsdnCardState *cs)
        cs->hw.hfcpci.mst_m = HFCPCI_MASTER;    /* HFC Master Mode */
 
        Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
-       cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
+       cs->hw.hfcpci.sctrl = 0x40;     /* set tx_lo mode, error in datasheet ! */
        Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
        cs->hw.hfcpci.sctrl_r = 0;
        Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
 
-        /* Init GCI/IOM2 in master mode */
+       /* Init GCI/IOM2 in master mode */
        /* Slots 0 and 1 are set for B-chan 1 and 2 */
        /* D- and monitor/CI channel are not enabled */
        /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */
-       /* STIO2 is used as data input, B1+B2 from IOM->ST */ 
+       /* STIO2 is used as data input, B1+B2 from IOM->ST */
        /* ST B-channel send disabled -> continous 1s */
        /* The IOM slots are always enabled */
-       cs->hw.hfcpci.conn = 0x36; /* set data flow directions */
+       cs->hw.hfcpci.conn = 0x36;      /* set data flow directions */
        Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
-       Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */
-       Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */
-       Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */
-       Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */
+       Write_hfc(cs, HFCPCI_B1_SSL, 0x80);     /* B1-Slot 0 STIO1 out enabled */
+       Write_hfc(cs, HFCPCI_B2_SSL, 0x81);     /* B2-Slot 1 STIO1 out enabled */
+       Write_hfc(cs, HFCPCI_B1_RSL, 0x80);     /* B1-Slot 0 STIO2 in enabled */
+       Write_hfc(cs, HFCPCI_B2_RSL, 0x81);     /* B2-Slot 1 STIO2 in enabled */
+
+       /* Finally enable IRQ output */
+       cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;
+       Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+       if (Read_hfc(cs, HFCPCI_INT_S2));
        restore_flags(flags);
 }
 
@@ -326,7 +359,7 @@ hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int cou
                count -= 3;
                ptr = skb_put(skb, count);
 
-               if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
+               if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)
                        maxlen = count;         /* complete transfer */
                else
                        maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;      /* maximum */
@@ -418,54 +451,56 @@ receive_dmsg(struct IsdnCardState *cs)
 /*******************************************************************************/
 /* check for transparent receive data and read max one threshold size if avail */
 /*******************************************************************************/
-int hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type *bz, u_char *bdata)
-{ unsigned short *z1r, *z2r;
-  int new_z2, fcnt, maxlen;
-  struct sk_buff *skb;
-  u_char *ptr, *ptr1;
+int
+hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
+{
+       unsigned short *z1r, *z2r;
+       int new_z2, fcnt, maxlen;
+       struct sk_buff *skb;
+       u_char *ptr, *ptr1;
 
-  z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
-  z2r = z1r + 1; 
+       z1r = &bz->za[MAX_B_FRAMES].z1;         /* pointer to z reg */
+       z2r = z1r + 1;
 
-  if (!(fcnt = *z1r - *z2r)) 
-    return(0); /* no data avail */
+       if (!(fcnt = *z1r - *z2r))
+               return (0);     /* no data avail */
 
-  if (fcnt <= 0) 
-    fcnt += B_FIFO_SIZE; /* bytes actually buffered */  
-  if (fcnt > HFCPCI_BTRANS_THRESHOLD)
-    fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */
+       if (fcnt <= 0)
+               fcnt += B_FIFO_SIZE;    /* bytes actually buffered */
+       if (fcnt > HFCPCI_BTRANS_THRESHOLD)
+               fcnt = HFCPCI_BTRANS_THRESHOLD;         /* limit size */
 
-  new_z2 = *z2r + fcnt;        /* new position in fifo */
-  if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
-    new_z2 -= B_FIFO_SIZE;     /* buffer wrap */
+       new_z2 = *z2r + fcnt;   /* new position in fifo */
+       if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
+               new_z2 -= B_FIFO_SIZE;  /* buffer wrap */
 
-  if (!(skb = dev_alloc_skb(fcnt)))
+       if (!(skb = dev_alloc_skb(fcnt)))
                printk(KERN_WARNING "HFCPCI: receive out of memory\n");
-  else {
-    ptr = skb_put(skb, fcnt);
-    if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
-      maxlen = fcnt; /* complete transfer */
-    else
-      maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r; /* maximum */
-
-    ptr1 = bdata + (*z2r - B_SUB_VAL); /* start of data */
-    memcpy(ptr, ptr1, maxlen); /* copy data */
-    fcnt -= maxlen;
-
-    if (fcnt) {        /* rest remaining */
-      ptr += maxlen;
-      ptr1 = bdata;    /* start of buffer */
-      memcpy(ptr, ptr1, fcnt); /* rest */
-    }
-    cli();
-    skb_queue_tail(&bcs->rqueue, skb);
-    sti();
-    hfcpci_sched_event(bcs, B_RCVBUFREADY); 
-  }
-  
-  *z2r = new_z2; /* new position */
-  return(1);
-} /* hfcpci_empty_fifo_trans */ 
+       else {
+               ptr = skb_put(skb, fcnt);
+               if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
+                       maxlen = fcnt;  /* complete transfer */
+               else
+                       maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r;        /* maximum */
+
+               ptr1 = bdata + (*z2r - B_SUB_VAL);      /* start of data */
+               memcpy(ptr, ptr1, maxlen);      /* copy data */
+               fcnt -= maxlen;
+
+               if (fcnt) {     /* rest remaining */
+                       ptr += maxlen;
+                       ptr1 = bdata;   /* start of buffer */
+                       memcpy(ptr, ptr1, fcnt);        /* rest */
+               }
+               cli();
+               skb_queue_tail(&bcs->rqueue, skb);
+               sti();
+               hfcpci_sched_event(bcs, B_RCVBUFREADY);
+       }
+
+       *z2r = new_z2;          /* new position */
+       return (1);
+}                              /* hfcpci_empty_fifo_trans */
 
 /**********************************/
 /* B-channel main receive routine */
@@ -526,11 +561,10 @@ main_rec_hfcpci(struct BCState *bcs)
                        receive = 1;
                else
                        receive = 0;
-       } else 
-         if (bcs->mode == L1_MODE_TRANS)
-           receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
-         else
-           receive = 0;
+       } else if (bcs->mode == L1_MODE_TRANS)
+               receive = hfcpci_empty_fifo_trans(bcs, bz, bdata);
+       else
+               receive = 0;
        test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
        if (count && receive)
                goto Begin;
@@ -622,7 +656,7 @@ hfcpci_fill_fifo(struct BCState *bcs)
        bzfifo_type *bz;
        u_char *bdata;
        u_char new_f1, *src, *dst;
-        unsigned short *z1t, *z2t;
+       unsigned short *z1t, *z2t;
 
        if (!bcs->tx_skb)
                return;
@@ -641,57 +675,53 @@ hfcpci_fill_fifo(struct BCState *bcs)
        }
 
        if (bcs->mode == L1_MODE_TRANS) {
-         z1t = &bz->za[MAX_B_FRAMES].z1;
-         z2t = z1t + 1;
-         if (cs->debug & L1_DEB_HSCX)
-                 debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
-                 bcs->channel, *z1t, *z2t);
-         fcnt = *z2t - *z1t;
-         if (fcnt <= 0)
-                 fcnt += B_FIFO_SIZE;  /* fcnt contains available bytes in fifo */
-         fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */
-
-         while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
-           if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) { 
-             /* data is suitable for fifo */
-             count = bcs->tx_skb->len;
-
-             new_z1 = *z1t + count;    /* new buffer Position */
-             if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
-               new_z1 -= B_FIFO_SIZE;  /* buffer wrap */
-             src = bcs->tx_skb->data;  /* source pointer */
-             dst = bdata + (*z1t - B_SUB_VAL);
-             maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */
-             if (maxlen > count)
-               maxlen = count; /* limit size */
-             memcpy(dst, src, maxlen); /* first copy */
+               z1t = &bz->za[MAX_B_FRAMES].z1;
+               z2t = z1t + 1;
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)",
+                               bcs->channel, *z1t, *z2t);
+               fcnt = *z2t - *z1t;
+               if (fcnt <= 0)
+                       fcnt += B_FIFO_SIZE;    /* fcnt contains available bytes in fifo */
+               fcnt = B_FIFO_SIZE - fcnt;      /* remaining bytes to send */
+
+               while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) {
+                       if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) {
+                               /* data is suitable for fifo */
+                               count = bcs->tx_skb->len;
+
+                               new_z1 = *z1t + count;  /* new buffer Position */
+                               if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
+                                       new_z1 -= B_FIFO_SIZE;  /* buffer wrap */
+                               src = bcs->tx_skb->data;        /* source pointer */
+                               dst = bdata + (*z1t - B_SUB_VAL);
+                               maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t;      /* end of fifo */
+                               if (maxlen > count)
+                                       maxlen = count;         /* limit size */
+                               memcpy(dst, src, maxlen);       /* first copy */
+
+                               count -= maxlen;        /* remaining bytes */
+                               if (count) {
+                                       dst = bdata;    /* start of buffer */
+                                       src += maxlen;  /* new position */
+                                       memcpy(dst, src, count);
+                               }
+                               bcs->tx_cnt -= bcs->tx_skb->len;
+                               fcnt += bcs->tx_skb->len;
+                               *z1t = new_z1;  /* now send data */
+                       } else if (cs->debug & L1_DEB_HSCX)
+                               debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
+                                       bcs->channel, bcs->tx_skb->len);
 
-             count -= maxlen;  /* remaining bytes */
-             if (count) {
-               dst = bdata;    /* start of buffer */
-               src += maxlen;  /* new position */
-               memcpy(dst, src, count);
-             }
-             bcs->tx_cnt -= bcs->tx_skb->len;
-             fcnt += bcs->tx_skb->len;
-             *z1t = new_z1; /* now send data */
-           }
-            else 
-             if (cs->debug & L1_DEB_HSCX)
-               debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
-                       bcs->channel, bcs->tx_skb->len);
-
-           dev_kfree_skb(bcs->tx_skb);
-            cli();
-            bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
-            sti();
-         }  
-         test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
-         restore_flags(flags);
-         return;
+                       dev_kfree_skb(bcs->tx_skb);
+                       cli();
+                       bcs->tx_skb = skb_dequeue(&bcs->squeue);        /* fetch next data */
+                       sti();
+               }
+               test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               restore_flags(flags);
+               return;
        }
-
-
        if (cs->debug & L1_DEB_HSCX)
                debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)",
                        bcs->channel, bz->f1, bz->f2,
@@ -757,51 +787,107 @@ hfcpci_fill_fifo(struct BCState *bcs)
        return;
 }
 
+/**********************************************/
+/* D-channel l1 state call for leased NT-mode */
+/**********************************************/
+static void
+dch_nt_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+
+       switch (pr) {
+               case (PH_DATA | REQUEST):
+               case (PH_PULL | REQUEST):
+               case (PH_PULL | INDICATION):
+                       st->l1.l1hw(st, pr, arg);
+                       break;
+               case (PH_ACTIVATE | REQUEST):
+                       st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+                       break;
+               case (PH_TESTLOOP | REQUEST):
+                       if (1 & (long) arg)
+                               debugl1(cs, "PH_TEST_LOOP B1");
+                       if (2 & (long) arg)
+                               debugl1(cs, "PH_TEST_LOOP B2");
+                       if (!(3 & (long) arg))
+                               debugl1(cs, "PH_TEST_LOOP DISABLED");
+                       st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
+                       break;
+               default:
+                       if (cs->debug)
+                               debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr);
+                       break;
+       }
+}
+
+
+
 /***********************/
 /* set/reset echo mode */
-/***********************/ 
+/***********************/
 static int
-hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic)
+hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic)
 {
-  int flags;
-  int i = *(unsigned int *) ic->parm.num;
-  
-  if (cs->chanlimit > 1)
-    return(-EINVAL);
-
-  save_flags(flags);
-  cli();
-  if (i) {
-    cs->logecho = 1;
-    cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */
-    cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
-    cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
-  }
-  else {
-    cs->logecho = 0;
-    cs->hw.hfcpci.trm &= ~0x20; /* enable echo chan */
-    cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
-    cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
-  }
-    cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
-    cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
-    cs->hw.hfcpci.conn |= 0x10; /* B2-IOM -> B2-ST */ 
-    cs->hw.hfcpci.ctmt &= ~2;
-  Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
-  Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
-  Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
-  Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
-  Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
-  Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-  Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-  restore_flags(flags);
-  return(0);
-} /* hfcpci_auxcmd */ 
+       int flags;
+       int i = *(unsigned int *) ic->parm.num;
+
+       if ((ic->arg == 98) &&
+           (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
+               save_flags(flags);
+               cli();
+               Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0);    /* HFC ST G0 */
+               udelay(10);
+               cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT;
+               Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);       /* set NT-mode */
+               udelay(10);
+               Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1);    /* HFC ST G1 */
+               udelay(10);
+               Write_hfc(cs, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
+               cs->dc.hfcpci.ph_state = 1;
+               cs->hw.hfcpci.nt_mode = 1;
+               cs->hw.hfcpci.nt_timer = 0;
+               cs->stlist->l2.l2l1 = dch_nt_l2l1;
+               restore_flags(flags);
+               debugl1(cs, "NT mode activated");
+               return (0);
+       }
+       if ((cs->chanlimit > 1) || (cs->hw.hfcpci.bswapped) ||
+           (cs->hw.hfcpci.nt_mode) || (ic->arg != 12))
+               return (-EINVAL);
+
+       save_flags(flags);
+       cli();
+       if (i) {
+               cs->logecho = 1;
+               cs->hw.hfcpci.trm |= 0x20;      /* enable echo chan */
+               cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC;
+               cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX;
+       } else {
+               cs->logecho = 0;
+               cs->hw.hfcpci.trm &= ~0x20;     /* disable echo chan */
+               cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC;
+               cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX;
+       }
+       cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
+       cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
+       cs->hw.hfcpci.conn |= 0x10;     /* B2-IOM -> B2-ST */
+       cs->hw.hfcpci.ctmt &= ~2;
+       Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
+       Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
+       Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
+       Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+       Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+       Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
+       Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+       restore_flags(flags);
+       return (0);
+}                              /* hfcpci_auxcmd */
 
 /*****************************/
 /* E-channel receive routine */
 /*****************************/
-static void receive_emsg(struct IsdnCardState *cs)
+static void
+receive_emsg(struct IsdnCardState *cs)
 {
        long flags;
        int rcnt;
@@ -838,55 +924,54 @@ static void receive_emsg(struct IsdnCardState *cs)
                if (cs->debug & L1_DEB_ISAC)
                        debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)",
                                zp->z1, zp->z2, rcnt);
-                new_z2 = zp->z2 + rcnt; /* new position in fifo */
+               new_z2 = zp->z2 + rcnt;         /* new position in fifo */
                if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
-                 new_z2 -= B_FIFO_SIZE; /* buffer wrap */
+                       new_z2 -= B_FIFO_SIZE;  /* buffer wrap */
                new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;
-               if ((rcnt > 256 + 3) || (count < 4) ||
+               if ((rcnt > 256 + 3) || (count < 4) ||
                    (*(bdata + (zp->z1 - B_SUB_VAL)))) {
-                 if (cs->debug & L1_DEB_WARN)
-                       debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
-                 bz->za[new_f2].z2 = new_z2;
-                 bz->f2 = new_f2;      /* next buffer */
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt);
+                       bz->za[new_f2].z2 = new_z2;
+                       bz->f2 = new_f2;        /* next buffer */
                } else {
-                   total = rcnt;
-                   rcnt -= 3;
-                   ptr = e_buffer;
-
-                   if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
-                       maxlen = rcnt;          /* complete transfer */
-                   else
-                       maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;      /* maximum */
+                       total = rcnt;
+                       rcnt -= 3;
+                       ptr = e_buffer;
 
-                   ptr1 = bdata + (zp->z2 - B_SUB_VAL);        /* start of data */
-                   memcpy(ptr, ptr1, maxlen);  /* copy data */
-                   rcnt -= maxlen;
+                       if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL)
+                               maxlen = rcnt;  /* complete transfer */
+                       else
+                               maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;      /* maximum */
 
-                   if (rcnt) { /* rest remaining */
-                       ptr += maxlen;
-                       ptr1 = bdata;   /* start of buffer */
-                       memcpy(ptr, ptr1, rcnt);        /* rest */
-                   }
-                   bz->za[new_f2].z2 = new_z2;
-                   bz->f2 = new_f2;    /* next buffer */
-                   if (cs->debug & DEB_DLOG_HEX) {
-                       ptr = cs->dlog;
-                       if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
-                         *ptr++ = 'E';
-                         *ptr++ = 'C';
-                         *ptr++ = 'H';
-                         *ptr++ = 'O';
-                         *ptr++ = ':';
-                         ptr += QuickHex(ptr, e_buffer, total - 3);
-                         ptr--;
-                         *ptr++ = '\n';
-                         *ptr = 0;
-                         HiSax_putstatus(cs, NULL, cs->dlog);
-                       } else
-                         HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
-                   }
+                       ptr1 = bdata + (zp->z2 - B_SUB_VAL);    /* start of data */
+                       memcpy(ptr, ptr1, maxlen);      /* copy data */
+                       rcnt -= maxlen;
 
-       }
+                       if (rcnt) {     /* rest remaining */
+                               ptr += maxlen;
+                               ptr1 = bdata;   /* start of buffer */
+                               memcpy(ptr, ptr1, rcnt);        /* rest */
+                       }
+                       bz->za[new_f2].z2 = new_z2;
+                       bz->f2 = new_f2;        /* next buffer */
+                       if (cs->debug & DEB_DLOG_HEX) {
+                               ptr = cs->dlog;
+                               if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) {
+                                       *ptr++ = 'E';
+                                       *ptr++ = 'C';
+                                       *ptr++ = 'H';
+                                       *ptr++ = 'O';
+                                       *ptr++ = ':';
+                                       ptr += QuickHex(ptr, e_buffer, total - 3);
+                                       ptr--;
+                                       *ptr++ = '\n';
+                                       *ptr = 0;
+                                       HiSax_putstatus(cs, NULL, cs->dlog);
+                               } else
+                                       HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
+                       }
+               }
 
                rcnt = bz->f1 - bz->f2;
                if (rcnt < 0)
@@ -902,7 +987,7 @@ static void receive_emsg(struct IsdnCardState *cs)
                goto Begin;
        restore_flags(flags);
        return;
-} /* receive_emsg */
+}                              /* receive_emsg */
 
 /*********************/
 /* Interrupt handler */
@@ -921,6 +1006,9 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                printk(KERN_WARNING "HFC-PCI: Spurious interrupt!\n");
                return;
        }
+       if (!(cs->hw.hfcpci.int_m2 & 0x08))
+               return;         /* not initialised */
+
        if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) {
                val = Read_hfc(cs, HFCPCI_INT_S1);
                if (cs->debug & L1_DEB_ISAC)
@@ -933,7 +1021,7 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                        test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ?
                        "locked" : "unlocked");
        val &= cs->hw.hfcpci.int_m1;
-       if (val & 0x40) {       /* TE state machine irq */
+       if (val & 0x40) {       /* state machine irq */
                exval = Read_hfc(cs, HFCPCI_STATES) & 0xf;
                if (cs->debug & L1_DEB_ISAC)
                        debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state,
@@ -942,6 +1030,14 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                sched_event_D_pci(cs, D_L1STATECHANGE);
                val &= ~0x40;
        }
+       if (val & 0x80) {       /* timer irq */
+               if (cs->hw.hfcpci.nt_mode) {
+                       if ((--cs->hw.hfcpci.nt_timer) < 0)
+                               sched_event_D_pci(cs, D_L1STATECHANGE);
+               }
+               val &= ~0x80;
+               Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+       }
        while (val) {
                save_flags(flags);
                cli();
@@ -956,24 +1052,23 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                        cs->hw.hfcpci.int_s1 = exval;
                }
                if (val & 0x08) {
-                       if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) {
+                       if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
                                if (cs->debug)
                                        debugl1(cs, "hfcpci spurious 0x08 IRQ");
                        } else
                                main_rec_hfcpci(bcs);
                }
-               if (val & 0x10) { 
-                       if (cs->logecho)
-                         receive_emsg(cs);
-                       else    
-                       if (!(bcs = Sel_BCS(cs, 1))) {
+               if (val & 0x10) {
+                       if (cs->logecho)
+                               receive_emsg(cs);
+                       else if (!(bcs = Sel_BCS(cs, 1))) {
                                if (cs->debug)
                                        debugl1(cs, "hfcpci spurious 0x10 IRQ");
                        } else
                                main_rec_hfcpci(bcs);
                }
                if (val & 0x01) {
-                       if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1:0))) {
+                       if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) {
                                if (cs->debug)
                                        debugl1(cs, "hfcpci spurious 0x01 IRQ");
                        } else {
@@ -1082,6 +1177,7 @@ HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
 {
        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
        struct sk_buff *skb = arg;
+       int flags;
 
        switch (pr) {
                case (PH_DATA | REQUEST):
@@ -1157,13 +1253,46 @@ HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
                        Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
                        break;
                case (HW_DEACTIVATE | REQUEST):
-                       cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
+                       cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
                        Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
                        break;
                case (HW_INFO3 | REQUEST):
                        cs->hw.hfcpci.mst_m |= HFCPCI_MASTER;
                        Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);
                        break;
+               case (HW_TESTLOOP | REQUEST):
+                       switch ((int) arg) {
+                               case (1):
+                                       Write_hfc(cs, HFCPCI_B1_SSL, 0x80);     /* tx slot */
+                                       Write_hfc(cs, HFCPCI_B1_RSL, 0x80);     /* rx slot */
+                                       save_flags(flags);
+                                       cli();
+                                       cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~7) | 1;
+                                       Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+                                       restore_flags(flags);
+                                       break;
+
+                               case (2):
+                                       Write_hfc(cs, HFCPCI_B2_SSL, 0x81);     /* tx slot */
+                                       Write_hfc(cs, HFCPCI_B2_RSL, 0x81);     /* rx slot */
+                                       save_flags(flags);
+                                       cli();
+                                       cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~0x38) | 0x08;
+                                       Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+                                       restore_flags(flags);
+                                       break;
+
+                               default:
+                                       if (cs->debug & L1_DEB_WARN)
+                                               debugl1(cs, "hfcpci_l1hw loop invalid %4x", (int) arg);
+                                       return;
+                       }
+                       save_flags(flags);
+                       cli();
+                       cs->hw.hfcpci.trm |= 0x80;      /* enable IOM-loop */
+                       Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
+                       restore_flags(flags);
+                       break;
                default:
                        if (cs->debug & L1_DEB_WARN)
                                debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr);
@@ -1203,113 +1332,127 @@ mode_hfcpci(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
        bzfifo_type *bzr, *bzt;
-       int flags;
+       int flags, fifo2;
 
        if (cs->debug & L1_DEB_HSCX)
                debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d",
                        mode, bc, bcs->channel);
        bcs->mode = mode;
        bcs->channel = bc;
-       if (cs->chanlimit > 1) { 
-         cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
-         cs->hw.hfcpci.sctrl_e &= ~0x80; 
-       }
-       else {
-         if (bc) {
-           cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */
-           cs->hw.hfcpci.sctrl_e |= 0x80;
-           bc = 0; /* B1 controller used */
-         }
-         else {
-           cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */
-           cs->hw.hfcpci.sctrl_e &= ~0x80; 
-         }  
-       }  
+       fifo2 = bc;
        save_flags(flags);
        cli();
+       if (cs->chanlimit > 1) {
+               cs->hw.hfcpci.bswapped = 0;     /* B1 and B2 normal mode */
+               cs->hw.hfcpci.sctrl_e &= ~0x80;
+       } else {
+               if (bc) {
+                       if (mode != L1_MODE_NULL) {
+                               cs->hw.hfcpci.bswapped = 1;     /* B1 and B2 exchanged */
+                               cs->hw.hfcpci.sctrl_e |= 0x80;
+                       } else {
+                               cs->hw.hfcpci.bswapped = 0;     /* B1 and B2 normal mode */
+                               cs->hw.hfcpci.sctrl_e &= ~0x80;
+                       }
+                       fifo2 = 0;
+               } else {
+                       cs->hw.hfcpci.bswapped = 0;     /* B1 and B2 normal mode */
+                       cs->hw.hfcpci.sctrl_e &= ~0x80;
+               }
+       }
        switch (mode) {
                case (L1_MODE_NULL):
                        if (bc) {
                                cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA;
                                cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA;
-                               cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
-                               cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
                        } else {
                                cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA;
                                cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA;
+                       }
+                       if (fifo2) {
+                               cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
+                               cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+                       } else {
                                cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
-                               cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+                               cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
                        }
                        break;
                case (L1_MODE_TRANS):
                        if (bc) {
-                               cs->hw.hfcpci.ctmt |= 2;
-                               cs->hw.hfcpci.conn &= ~0x18;
                                cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
                                cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
-                               cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
-                               cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
-                               bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
-                               bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
                        } else {
-                               cs->hw.hfcpci.ctmt |= 1;
-                               cs->hw.hfcpci.conn &= ~0x03;
                                cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
                                cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+                       }
+                       if (fifo2) {
+                               cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
+                               cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+                               cs->hw.hfcpci.ctmt |= 2;
+                               cs->hw.hfcpci.conn &= ~0x18;
+                               bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;
+                               bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;
+                       } else {
                                cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
-                               cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
-                               bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
-                               bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
+                               cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+                               cs->hw.hfcpci.ctmt |= 1;
+                               cs->hw.hfcpci.conn &= ~0x03;
+                               bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;
+                               bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;
                        }
                        bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
-                        bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; 
+                       bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;
                        bzr->f1 = MAX_B_FRAMES;
-                       bzr->f2 = bzr->f1; /* init F pointers to remain constant */
+                       bzr->f2 = bzr->f1;      /* init F pointers to remain constant */
                        bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;
-                        bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; 
+                       bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;
                        bzt->f1 = MAX_B_FRAMES;
-                       bzt->f2 = bzt->f1; /* init F pointers to remain constant */
+                       bzt->f2 = bzt->f1;      /* init F pointers to remain constant */
                        break;
                case (L1_MODE_HDLC):
                        if (bc) {
-                               cs->hw.hfcpci.ctmt &= ~2;
-                               cs->hw.hfcpci.conn &= ~0x18;
                                cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
                                cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
-                               cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
-                               cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
                        } else {
-                               cs->hw.hfcpci.ctmt &= ~1;
-                               cs->hw.hfcpci.conn &= ~0x3;
                                cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
                                cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
+                       }
+                       if (fifo2) {
+                               cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
+                               cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
+                               cs->hw.hfcpci.ctmt &= ~2;
+                               cs->hw.hfcpci.conn &= ~0x18;
+                       } else {
                                cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
-                               cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+                               cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
+                               cs->hw.hfcpci.ctmt &= ~1;
+                               cs->hw.hfcpci.conn &= ~0x03;
                        }
                        break;
                case (L1_MODE_EXTRN):
                        if (bc) {
-                               cs->hw.hfcpci.conn |= 0x10;
+                               cs->hw.hfcpci.conn |= 0x10;
                                cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA;
                                cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA;
                                cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2;
-                               cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS+HFCPCI_INTS_B2REC);
+                               cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
                        } else {
-                               cs->hw.hfcpci.conn |= 0x02;
+                               cs->hw.hfcpci.conn |= 0x02;
                                cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA;
                                cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
                                cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1;
-                               cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS+HFCPCI_INTS_B1REC);
+                               cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
                        }
                        break;
        }
+       Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);
        Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
-       restore_flags(flags);
        Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
        Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);
        Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);
        Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);
        Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);
+       restore_flags(flags);
 }
 
 /******************************/
@@ -1429,29 +1572,72 @@ setstack_2b(struct PStack *st, struct BCState *bcs)
 static void
 hfcpci_bh(struct IsdnCardState *cs)
 {
+       int flags;
 /*      struct PStack *stptr;
  */
        if (!cs)
                return;
        if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
-               switch (cs->dc.hfcpci.ph_state) {
-                       case (0):
-                               l1_msg(cs, HW_RESET | INDICATION, NULL);
-                               break;
-                       case (3):
-                               l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
-                               break;
-                       case (8):
-                               l1_msg(cs, HW_RSYNC | INDICATION, NULL);
-                               break;
-                       case (6):
-                               l1_msg(cs, HW_INFO2 | INDICATION, NULL);
-                               break;
-                       case (7):
-                               l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
-                               break;
-                       default:
-                               break;
+               if (!cs->hw.hfcpci.nt_mode)
+                       switch (cs->dc.hfcpci.ph_state) {
+                               case (0):
+                                       l1_msg(cs, HW_RESET | INDICATION, NULL);
+                                       break;
+                               case (3):
+                                       l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+                                       break;
+                               case (8):
+                                       l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+                                       break;
+                               case (6):
+                                       l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+                                       break;
+                               case (7):
+                                       l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                                       break;
+                               default:
+                                       break;
+               } else {
+                       switch (cs->dc.hfcpci.ph_state) {
+                               case (2):
+                                       save_flags(flags);
+                                       cli();
+                                       if (cs->hw.hfcpci.nt_timer < 0) {
+                                               cs->hw.hfcpci.nt_timer = 0;
+                                               cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
+                                               Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+                                               /* Clear already pending ints */
+                                               if (Read_hfc(cs, HFCPCI_INT_S1));
+
+                                               Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
+                                               udelay(10);
+                                               Write_hfc(cs, HFCPCI_STATES, 4);
+                                               cs->dc.hfcpci.ph_state = 4;
+                                       } else {
+                                               cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_TIMER;
+                                               Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+                                               cs->hw.hfcpci.ctmt &= ~HFCPCI_AUTO_TIMER;
+                                               cs->hw.hfcpci.ctmt |= HFCPCI_TIM3_125;
+                                               Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+                                               Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER);
+                                               cs->hw.hfcpci.nt_timer = NT_T1_COUNT;
+                                               Write_hfc(cs, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3);      /* allow G2 -> G3 transition */
+                                       }
+                                       restore_flags(flags);
+                                       break;
+                               case (1):
+                               case (3):
+                               case (4):
+                                       save_flags(flags);
+                                       cli();
+                                       cs->hw.hfcpci.nt_timer = 0;
+                                       cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
+                                       Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+                                       restore_flags(flags);
+                                       break;
+                               default:
+                                       break;
+                       }
                }
        }
        if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
@@ -1551,9 +1737,10 @@ __initfunc(int
           setup_hfcpci(struct IsdnCard *card))
 {
        struct IsdnCardState *cs = card->cs;
+       unsigned short cmd;
        char tmp[64];
        int i;
-        struct pci_dev *tmp_hfcpci = NULL;
+       struct pci_dev *tmp_hfcpci = NULL;
 
        strcpy(tmp, hfcpci_revision);
        printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
@@ -1569,22 +1756,22 @@ __initfunc(int
                        return (0);
                }
                i = 0;
-                while (id_list[i].vendor_id) {
-                 tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
-                                              id_list[i].device_id,
-                                              dev_hfcpci);
-                 i++;
-                 if (tmp_hfcpci) {
-                   if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)))
-                     continue;
-                   else
-                     break;
-                 }  
-               }  
-                                             
+               while (id_list[i].vendor_id) {
+                       tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+                                                    id_list[i].device_id,
+                                                    dev_hfcpci);
+                       i++;
+                       if (tmp_hfcpci) {
+                               if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK)))
+                                       continue;
+                               else
+                                       break;
+                       }
+               }
+
                if (tmp_hfcpci) {
-                       i--;
-                       dev_hfcpci = tmp_hfcpci; /* old device */
+                       i--;
+                       dev_hfcpci = tmp_hfcpci;        /* old device */
                        cs->hw.hfcpci.pci_bus = dev_hfcpci->bus->number;
                        cs->hw.hfcpci.pci_device_fn = dev_hfcpci->devfn;
                        cs->irq = dev_hfcpci->irq;
@@ -1593,11 +1780,44 @@ __initfunc(int
                                return (0);
                        }
                        cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->base_address[ 1];
-                       printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name);
+                       printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
                } else {
                        printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
                        return (0);
                }
+               if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
+                       printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n");
+                       pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+                                            cs->hw.hfcpci.pci_device_fn,
+                                                 PCI_COMMAND,
+                                                 0x0103);      /* set SERR */
+                       pcibios_read_config_word(cs->hw.hfcpci.pci_bus,
+                                            cs->hw.hfcpci.pci_device_fn,
+                                                PCI_COMMAND,
+                                                &cmd);
+                       pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+                                            cs->hw.hfcpci.pci_device_fn,
+                                                 PCI_COMMAND,
+                                                 cmd & ~2);
+                       (int) cs->hw.hfcpci.pci_io &= ~(PAGE_SIZE - 1);
+                       pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
+                                            cs->hw.hfcpci.pci_device_fn,
+                                                  PCI_BASE_ADDRESS_1,
+                                            (int) cs->hw.hfcpci.pci_io);
+                       pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
+                                            cs->hw.hfcpci.pci_device_fn,
+                                                 PCI_COMMAND,
+                                                 cmd);
+                       pcibios_read_config_dword(cs->hw.hfcpci.pci_bus,
+                                            cs->hw.hfcpci.pci_device_fn,
+                                                 PCI_BASE_ADDRESS_1,
+                                        (void *) &cs->hw.hfcpci.pci_io);
+                       if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
+                               printk(KERN_WARNING "HFC-PCI unable to align address %x\n", (unsigned) cs->hw.hfcpci.pci_io);
+                               return (0);
+                       }
+                       dev_hfcpci->base_address[1] = (int) cs->hw.hfcpci.pci_io;
+               }
                if (!cs->hw.hfcpci.pci_io) {
                        printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
                        return (0);
@@ -1613,16 +1833,16 @@ __initfunc(int
                    (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
                pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
                                       cs->hw.hfcpci.pci_device_fn, 0x80,
-                                          (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
+                              (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
                cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
                printk(KERN_INFO
-                "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
+                      "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
                       (u_int) cs->hw.hfcpci.pci_io,
                       (u_int) cs->hw.hfcpci.fifos,
                       (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
                       cs->irq, HZ);
                pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO);      /* enable memory mapped ports, disable busmaster */
-               cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */
+               cs->hw.hfcpci.int_m2 = 0;       /* disable alle interrupts */
                cs->hw.hfcpci.int_m1 = 0;
                Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
                Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
@@ -1647,7 +1867,7 @@ __initfunc(int
 
        reset_hfcpci(cs);
        cs->cardmsg = &hfcpci_card_msg;
-       cs->auxcmd  = &hfcpci_auxcmd;
+       cs->auxcmd = &hfcpci_auxcmd;
        return (1);
 #else
        printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");
index ae04d3d16af9734bf8f7f243b56595c5b9c575ba..e8597d73049ed1aeaa41733e25f9faf0d0cb487c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.h,v 1.6 1999/08/28 21:04:29 werner Exp $
+/* $Id: hfc_pci.h,v 1.7 1999/10/10 20:13:06 werner Exp $
 
  *  specific defines for CCD's HFC 2BDS0 PCI chips
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: hfc_pci.h,v $
+ * Revision 1.7  1999/10/10 20:13:06  werner
+ *
+ * Corrected timer constant
+ *
  * Revision 1.6  1999/08/28 21:04:29  werner
  * Implemented full audio support (transparent mode)
  *
 
 /* bits in CTMT (Write) */
 #define HFCPCI_CLTIMER    0x80
-#define HFCPCI_TIM3_125   0x00
+#define HFCPCI_TIM3_125   0x04
 #define HFCPCI_TIM25      0x10
 #define HFCPCI_TIM50      0x14
 #define HFCPCI_TIM400     0x18
index 43c5e44053999ecbdf2c980061d884f7bff47367..593dedc72ee33fa5a9d1044e4c5775208f91ef02 100644 (file)
@@ -1,8 +1,18 @@
-/* $Id: hisax.h,v 2.35 1999/09/04 06:35:09 keil Exp $
+/* $Id: hisax.h,v 2.38 1999/11/14 23:37:03 keil Exp $
 
  *   Basic declarations, defines and prototypes
  *
  * $Log: hisax.h,v $
+ * Revision 2.38  1999/11/14 23:37:03  keil
+ * new ISA memory mapped IO
+ *
+ * Revision 2.37  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
+ * Revision 2.36  1999/10/10 20:16:15  werner
+ *
+ * Added variable to hfcpci union.
+ *
  * Revision 2.35  1999/09/04 06:35:09  keil
  * Winbond W6692 support
  *
 #include <linux/tty.h>
 #include <linux/serial_reg.h>
 
+#undef ERROR_STATISTIC
+
 #define REQUEST                0
 #define CONFIRM                1
 #define INDICATION     2
@@ -581,6 +593,12 @@ struct BCState {
        int event;
        int  (*BC_SetStack) (struct PStack *, struct BCState *);
        void (*BC_Close) (struct BCState *);
+#ifdef ERROR_STATISTIC
+       int err_crc;
+       int err_tx;
+       int err_rdo;
+       int err_inv;
+#endif
        union {
                struct hscx_hw hscx;
                struct hdlc_hw hdlc;
@@ -648,7 +666,8 @@ struct teles3_hw {
 
 struct teles0_hw {
        unsigned int cfg_reg;
-       unsigned int membase;
+       unsigned long membase;
+       unsigned long phymem;
 };
 
 struct avm_hw {
@@ -755,7 +774,8 @@ struct hfcPCI_hw {
        unsigned char fifo;
         unsigned char fifo_en;
         unsigned char bswapped;
-  /*   unsigned int *send; */
+        unsigned char nt_mode;
+        int nt_timer;
        unsigned char pci_bus;
         unsigned char pci_device_fn;
         unsigned char *pci_io; /* start of PCI IO memory */
@@ -787,8 +807,9 @@ struct hfcD_hw {
 
 struct isurf_hw {
        unsigned int reset;
-       unsigned int isac;
-       unsigned int isar;
+       unsigned long phymem;
+       unsigned long isac;
+       unsigned long isar;
        struct isar_reg isar_r;
 };
 
@@ -961,6 +982,11 @@ struct IsdnCardState {
        int event;
        struct tq_struct tqueue;
        struct timer_list dbusytimer;
+#ifdef ERROR_STATISTIC
+       int err_crc;
+       int err_tx;
+       int err_rx;
+#endif
 };
 
 #define  MON0_RX       1
@@ -1355,7 +1381,7 @@ int HiSax_command(isdn_ctrl * ic);
 int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
 void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
 void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
-void HiSax_reportcard(int cardnr);
+void HiSax_reportcard(int cardnr, int sel);
 int QuickHex(char *txt, u_char * p, int cnt);
 void LogFrame(struct IsdnCardState *cs, u_char * p, int size);
 void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
index e0681c43b785054d494ab004ec07f432beecac52..655508f704e99e0e23b22a67e4ece78dcce35b4f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hscx_irq.c,v 1.12 1999/07/01 08:11:42 keil Exp $
+/* $Id: hscx_irq.c,v 1.13 1999/10/14 20:25:28 keil Exp $
 
  * hscx_irq.c     low level b-channel stuff for Siemens HSCX
  *
@@ -7,6 +7,9 @@
  * This is an include file for fast inline IRQ stuff
  *
  * $Log: hscx_irq.c,v $
+ * Revision 1.13  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.12  1999/07/01 08:11:42  keil
  * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
  *
@@ -181,16 +184,28 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
        if (val & 0x80) {       /* RME */
                r = READHSCX(cs, hscx, HSCX_RSTA);
                if ((r & 0xf0) != 0xa0) {
-                       if (!(r & 0x80))
+                       if (!(r & 0x80)) {
                                if (cs->debug & L1_DEB_WARN)
                                        debugl1(cs, "HSCX invalid frame");
-                       if ((r & 0x40) && bcs->mode)
+#ifdef ERROR_STATISTIC
+                               bcs->err_inv++;
+#endif
+                       }
+                       if ((r & 0x40) && bcs->mode) {
                                if (cs->debug & L1_DEB_WARN)
                                        debugl1(cs, "HSCX RDO mode=%d",
                                                bcs->mode);
-                       if (!(r & 0x20))
+#ifdef ERROR_STATISTIC
+                               bcs->err_rdo++;
+#endif
+                       }
+                       if (!(r & 0x20)) {
                                if (cs->debug & L1_DEB_WARN)
                                        debugl1(cs, "HSCX CRC error");
+#ifdef ERROR_STATISTIC
+                               bcs->err_crc++;
+#endif
+                       }
                        WriteHSCXCMDR(cs, hscx, 0x80);
                } else {
                        count = READHSCX(cs, hscx, HSCX_RBCL) & (
@@ -265,6 +280,9 @@ hscx_int_main(struct IsdnCardState *cs, u_char val)
                        if (bcs->mode == 1)
                                hscx_fill_fifo(bcs);
                        else {
+#ifdef ERROR_STATISTIC
+                               bcs->err_tx++;
+#endif
                                /* Here we lost an TX interrupt, so
                                   * restart transmitting the whole frame.
                                 */
@@ -295,6 +313,9 @@ hscx_int_main(struct IsdnCardState *cs, u_char val)
                                /* Here we lost an TX interrupt, so
                                   * restart transmitting the whole frame.
                                 */
+#ifdef ERROR_STATISTIC
+                               bcs->err_tx++;
+#endif
                                if (bcs->tx_skb) {
                                        skb_push(bcs->tx_skb, bcs->hw.hscx.count);
                                        bcs->tx_cnt += bcs->hw.hscx.count;
index 140ebca942e672e8825be24018e051ac421fc02b..a992f76c48ee092347666e182912789edb2e743c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isac.c,v 1.23 1999/08/25 16:50:52 keil Exp $
+/* $Id: isac.c,v 1.24 1999/10/14 20:25:28 keil Exp $
 
  * isac.c   ISAC specific routines
  *
@@ -9,6 +9,9 @@
  *             ../../../Documentation/isdn/HiSax.cert
  *
  * $Log: isac.c,v $
+ * Revision 1.24  1999/10/14 20:25:28  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.23  1999/08/25 16:50:52  keil
  * Fix bugs which cause 2.3.14 hangs (waitqueue init)
  *
@@ -281,12 +284,20 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
        if (val & 0x80) {       /* RME */
                exval = cs->readisac(cs, ISAC_RSTA);
                if ((exval & 0x70) != 0x20) {
-                       if (exval & 0x40)
+                       if (exval & 0x40) {
                                if (cs->debug & L1_DEB_WARN)
                                        debugl1(cs, "ISAC RDO");
-                       if (!(exval & 0x20))
+#ifdef ERROR_STATISTIC
+                               cs->err_rx++;
+#endif
+                       }
+                       if (!(exval & 0x20)) {
                                if (cs->debug & L1_DEB_WARN)
                                        debugl1(cs, "ISAC CRC error");
+#ifdef ERROR_STATISTIC
+                               cs->err_crc++;
+#endif
+                       }
                        cs->writeisac(cs, ISAC_CMDR, 0x80);
                } else {
                        count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
@@ -371,6 +382,9 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
                if (exval & 0x40) {  /* XDU */
                        debugl1(cs, "ISAC XDU");
                        printk(KERN_WARNING "HiSax: ISAC XDU\n");
+#ifdef ERROR_STATISTIC
+                       cs->err_tx++;
+#endif
                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
                                del_timer(&cs->dbusytimer);
                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
index 64a78156b50860d5f6c3e3d1fab3585659c522fc..417f2157dbdeb0f5a67e326eb32927aa40cb6445 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.6 1999/08/31 11:20:20 paul Exp $
+/* $Id: isar.c,v 1.7 1999/10/14 20:25:29 keil Exp $
 
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: isar.c,v $
+ * Revision 1.7  1999/10/14 20:25:29  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.6  1999/08/31 11:20:20  paul
  * various spelling corrections (new checksums may be needed, Karsten!)
  *
@@ -480,6 +483,12 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
                        if (cs->debug & L1_DEB_WARN)
                                debugl1(cs, "isar frame error %x len %d",
                                        ireg->cmsb, ireg->clsb);
+#ifdef ERROR_STATISTIC
+                       if (ireg->cmsb & HDLC_ERR_RER)
+                               bcs->err_inv++;
+                       if (ireg->cmsb & HDLC_ERR_CER)
+                               bcs->err_crc++;
+#endif
                        bcs->hw.isar.rcvidx = 0;
                        cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
                } else {
@@ -790,10 +799,19 @@ isar_int_main(struct IsdnCardState *cs)
                        check_send(cs, ireg->cmsb);
                        break;
                case ISAR_IIS_BSTEV:
-                       cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+#ifdef ERROR_STATISTIC
+                       if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
+                               if (ireg->cmsb == BSTEV_TBO)
+                                       bcs->err_tx++;
+                               if (ireg->cmsb == BSTEV_RBO)
+                                       bcs->err_rdo++;
+                       }
+#endif
                        if (cs->debug & L1_DEB_WARN)
                                debugl1(cs, "Buffer STEV dpath%d msb(%x)",
                                        ireg->iis>>6, ireg->cmsb);
+                       cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+                       break;
                case ISAR_IIS_PSTEV:
                        if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
                                rcv_mbox(cs, ireg, (u_char *)ireg->par);
index c6ac6532b231e17ff6ec4f1f10332f152888f656..f2bc4820a92d1ca9bd87173aea94ff1069ed3545 100644 (file)
@@ -1,10 +1,13 @@
-/* $Id: isar.h,v 1.5 1999/08/25 16:59:59 keil Exp $
+/* $Id: isar.h,v 1.6 1999/10/14 20:25:29 keil Exp $
  * isar.h   ISAR (Siemens PSB 7110) specific defines
  *
  * Author Karsten Keil (keil@isdn4linux.de)
  *
  *
  * $Log: isar.h,v $
+ * Revision 1.6  1999/10/14 20:25:29  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.5  1999/08/25 16:59:59  keil
  * Make ISAR V32bis modem running
  * Make LL->HL interface open for additional commands
 #define HDLC_FSD       0x20
 #define HDLC_FST       0x20
 #define HDLC_ERROR     0x1c
+#define HDLC_ERR_FAD   0x10
+#define HDLC_ERR_RER   0x08
+#define HDLC_ERR_CER   0x01
 #define SART_NMD       0x01
 
 #define BSTAT_RDM0     0x1
 #define BSTAT_RDM1     0x2
 #define BSTAT_RDM2     0x4
 #define BSTAT_RDM3     0x8
+#define BSTEV_TBO      0x1f
+#define BSTEV_RBO      0x2f
 
 extern int ISARVersion(struct IsdnCardState *cs, char *s);
 extern void isar_int_main(struct IsdnCardState *cs);
index a4061939e2d646f97c1dd94e429a69c5a3163f7e..c7f2482af24221cf85f1875265ec52d527fdaf50 100644 (file)
@@ -1,10 +1,13 @@
-/* $Id: isurf.c,v 1.6 1999/09/04 06:20:06 keil Exp $
+/* $Id: isurf.c,v 1.7 1999/11/14 23:37:03 keil Exp $
 
  * isurf.c  low level stuff for Siemens I-Surf/I-Talk cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * $Log: isurf.c,v $
+ * Revision 1.7  1999/11/14 23:37:03  keil
+ * new ISA memory mapped IO
+ *
  * Revision 1.6  1999/09/04 06:20:06  keil
  * Changes from kernel set_current_state()
  *
@@ -37,7 +40,7 @@
 
 extern const char *CardType[];
 
-static const char *ISurf_revision = "$Revision: 1.6 $";
+static const char *ISurf_revision = "$Revision: 1.7 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -50,7 +53,7 @@ static const char *ISurf_revision = "$Revision: 1.6 $";
 
 #define ISURF_ISAR_OFFSET      0
 #define ISURF_ISAC_OFFSET      0x100
-
+#define ISURF_IOMEM_SIZE       0x400
 /* Interface functions */
 
 static u_char
@@ -223,8 +226,7 @@ setup_isurf(struct IsdnCard *card))
                return(0);
        if (card->para[1] && card->para[2]) {
                cs->hw.isurf.reset = card->para[1];
-               cs->hw.isurf.isar = card->para[2] + ISURF_ISAR_OFFSET;
-               cs->hw.isurf.isac = card->para[2] + ISURF_ISAC_OFFSET;
+               cs->hw.isurf.phymem = card->para[2];
                cs->irq = card->para[0];
        } else {
                printk(KERN_WARNING "HiSax: %s port/mem not set\n",
@@ -240,11 +242,12 @@ setup_isurf(struct IsdnCard *card))
        } else {
                request_region(cs->hw.isurf.reset, 1, "isurf isdn");
        }
-
+       cs->hw.isurf.isar = cs->hw.isurf.phymem + ISURF_ISAR_OFFSET;
+       cs->hw.isurf.isac = cs->hw.isurf.phymem + ISURF_ISAC_OFFSET;
        printk(KERN_INFO
-              "ISurf: defined at 0x%x 0x%x IRQ %d\n",
+              "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
               cs->hw.isurf.reset,
-              cs->hw.isurf.isar,
+              cs->hw.isurf.phymem,
               cs->irq);
 
        cs->cardmsg = &ISurf_card_msg;
index 6429057c974dd0e84fd74295cd11153d9b223155..035ee54ca32d5798794271caedaf633ec93cbfa8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.19 1999/08/25 16:55:23 keil Exp $
+/* $Id: l3dss1.c,v 2.20 1999/10/11 22:16:27 keil Exp $
 
  * EURO/DSS1 D-channel protocol
  *
@@ -13,6 +13,9 @@
  *              Fritz Elfert
  *
  * $Log: l3dss1.c,v $
+ * Revision 2.20  1999/10/11 22:16:27  keil
+ * Suspend/Resume is possible without explicit ID too
+ *
  * Revision 2.19  1999/08/25 16:55:23  keil
  * Fix for test case TC10011
  *
@@ -90,7 +93,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.19 $";
+const char *dss1_revision = "$Revision: 2.20 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -2520,14 +2523,13 @@ l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
        u_char *msg = pc->chan->setup.phone;
 
        MsgHead(p, pc->callref, MT_SUSPEND);
-
-       *p++ = IE_CALL_ID;
        l = *msg++;
        if (l && (l <= 10)) {   /* Max length 10 octets */
+               *p++ = IE_CALL_ID;
                *p++ = l;
                for (i = 0; i < l; i++)
                        *p++ = *msg++;
-       } else {
+       } else if (l) {
                l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
                return;
        }
@@ -2596,13 +2598,13 @@ l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg)
 
        MsgHead(p, pc->callref, MT_RESUME);
 
-       *p++ = IE_CALL_ID;
        l = *msg++;
        if (l && (l <= 10)) {   /* Max length 10 octets */
+               *p++ = IE_CALL_ID;
                *p++ = l;
                for (i = 0; i < l; i++)
                        *p++ = *msg++;
-       } else {
+       } else if (l) {
                l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
                return;
        }
index e21f7d102603c1d5c39368dfd737754bb1762543..f85533e125779d533d481d496a75840b703be6e7 100644 (file)
@@ -6,14 +6,14 @@
 # Eicon Technology Diva 2.01 PCI cards in the moment.
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
-2760872030085b2d36aa203b44e9570e  isac.c
+3c2b1c96274cba97a8261d1cecc662b8  isac.c
 a9a15d069dbacb383cc24c238cb5ebbe  isdnl1.c
 bb51bd223040b511c18f091da5ab6456  isdnl2.c
 b7aa7f97b2374967a4aca7c52991142c  isdnl3.c
 a23fbf8879c1432b04640b8b04bdf419  tei.c
-c07fd0729b93ebffc3dbfc88cc334be1  callc.c
+d7072dbbeeb7c4c45f3810ed13cf5545  callc.c
 bf9605b36429898f7be6630034e83230  cert.c
-3fe91ac7175e1c15ad5f15b6d71b2756  l3dss1.c
+0e500813968adacaea2ef22c9cdd89eb  l3dss1.c
 2d748ced0eea375b21fe7ea91ca7917c  l3_1tr6.c
 72ee065c70473949a676f06f8ce83ebf  elsa.c
 1b26dd9b0f132744a7be2ce2ab1eda83  diva.c
@@ -23,9 +23,9 @@ bf9605b36429898f7be6630034e83230  cert.c
 Version: 2.6.3i
 Charset: noconv
 
-iQCVAwUBN+/NfDpxHvX/mS9tAQEC4gQAlAfRvVnILSrDUtH83RzPd6nCLONiHpKn
-nmyE3BkGk2DO1D8azCjx3X/9x7ozEm8pL5UN2kZuu5p9EO0ISzM5ZmcCi0jxAOq5
-c493UJmnWWOw02G0pNw+EsmRH9mUh1t7IyUEL+UpUMNyAEQRqq66k764YyUkKF88
-fup3c64mSKw=
-=bmv8
+iQCVAwUBOCwLCTpxHvX/mS9tAQEZ5wP7B6kHy8fHHHANxqU1XAiJR5DvttJtJGi1
+0MDX2lNAPbfZQolTkkmmWgYBSnLTLVpM2jxj5pdnKWMoEp0embrb0fw1Nx+DkcJ1
+OfogKy0HvBPfZdwyKV+CZymXZystw/n47hekOTSNLkAOMA6BXcWrS6SLpfv6fEri
+Cdp0XgIaIWQ=
+=Cmob
 -----END PGP SIGNATURE-----
index 0f0bfc2e9949bf48eca4a45b9ba89c7af797659c..c7a4929fc6224054b564435a55a3e943b7daf4e3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.15 1999/09/04 06:20:06 keil Exp $
+/* $Id: netjet.c,v 1.16 1999/10/14 20:25:29 keil Exp $
 
  * netjet.c     low level stuff for Traverse Technologie NETJet ISDN cards
  *
@@ -7,6 +7,9 @@
  * Thanks to Traverse Technologie Australia for documents and informations
  *
  * $Log: netjet.c,v $
+ * Revision 1.16  1999/10/14 20:25:29  keil
+ * add a statistic for error monitoring
+ *
  * Revision 1.15  1999/09/04 06:20:06  keil
  * Changes from kernel set_current_state()
  *
@@ -78,7 +81,7 @@
 
 extern const char *CardType[];
 
-const char *NETjet_revision = "$Revision: 1.15 $";
+const char *NETjet_revision = "$Revision: 1.16 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -528,19 +531,26 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
                                                        debugl1(bcs->cs, "tiger: frame not byte aligned");
                                                        state=HDLC_FLAG_SEARCH;
                                                        bcs->hw.tiger.r_err++;
+#ifdef ERROR_STATISTIC
+                                                       bcs->err_inv++;
+#endif
                                                } else {
                                                        if (bcs->cs->debug & L1_DEB_HSCX)
                                                                debugl1(bcs->cs,"tiger frame end(%d,%d): fcs(%x) i %x",
                                                                        i,j,bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0);
                                                        if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) {
                                                                got_frame(bcs, (bitcnt>>3)-3);
-                                                       } else
+                                                       } else {
                                                                if (bcs->cs->debug) {
                                                                        debugl1(bcs->cs, "tiger FCS error");
                                                                        printframe(bcs->cs, bcs->hw.tiger.rcvbuf,
                                                                                (bitcnt>>3)-1, "rec");
                                                                        bcs->hw.tiger.r_err++;
                                                                }
+#ifdef ERROR_STATISTIC
+                                                       bcs->err_crc++;
+#endif
+                                                       }
                                                        state=HDLC_FLAG_FOUND;
                                                }
                                                bitcnt=0;
@@ -562,6 +572,9 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
                                                r_val=0; 
                                                state=HDLC_FLAG_SEARCH;
                                                bcs->hw.tiger.r_err++;
+#ifdef ERROR_STATISTIC
+                                               bcs->err_inv++;
+#endif
                                        } else {
                                                bcs->hw.tiger.rcvbuf[(bitcnt>>3)-1] = r_val;
                                                bcs->hw.tiger.r_fcs = 
@@ -586,6 +599,12 @@ static void read_tiger(struct IsdnCardState *cs) {
        if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) {
                debugl1(cs,"tiger warn read double dma %x/%x",
                        cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
+#ifdef ERROR_STATISTIC
+               if (cs->bcs[0].mode)
+                       cs->bcs[0].err_rdo++;
+               if (cs->bcs[1].mode)
+                       cs->bcs[1].err_rdo++;
+#endif
                return;
        } else {
                cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ;
@@ -757,6 +776,12 @@ static void write_tiger(struct IsdnCardState *cs) {
        if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
                debugl1(cs,"tiger warn write double dma %x/%x",
                        cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
+#ifdef ERROR_STATISTIC
+               if (cs->bcs[0].mode)
+                       cs->bcs[0].err_tx++;
+               if (cs->bcs[1].mode)
+                       cs->bcs[1].err_tx++;
+#endif
                return;
        } else {
                cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE;
index 777c0cae9e1a591907a5b09cb43358dc6af64064..a8fedf9ea4ef9781f73d00b26c06a77f3740733b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.17 1999/09/04 06:20:06 keil Exp $
+/* $Id: sedlbauer.c,v 1.18 1999/11/13 21:25:03 keil Exp $
 
  * sedlbauer.c  low level stuff for Sedlbauer cards
  *              includes support for the Sedlbauer speed star (speed star II),
@@ -17,6 +17,9 @@
  *            Edgar Toernig
  *
  * $Log: sedlbauer.c,v $
+ * Revision 1.18  1999/11/13 21:25:03  keil
+ * Support for Speedfax+ PCI
+ *
  * Revision 1.17  1999/09/04 06:20:06  keil
  * Changes from kernel set_current_state()
  *
  * ---------------------------------------------------------------------
  * Speed Card  ISAC_HSCX       DIP-SWITCH
  * Speed Win   ISAC_HSCX       ISAPNP
- * Speed Fax+  ISAC_ISAR       ISAPNP          #HDLC works#
+ * Speed Fax+  ISAC_ISAR       ISAPNP          Full analog support
  * Speed Star  ISAC_HSCX       CARDMGR
  * Speed Win2  IPAC            ISAPNP
  * ISDN PC/104 IPAC            DIP-SWITCH
  * Speed Star2 IPAC            CARDMGR
- * Speed PCI   IPAC            PNP             
+ * Speed PCI   IPAC            PCI PNP         
+ * Speed Fax+  ISAC_ISAR       PCI PNP         Full analog support
  *
  * Important:
  * For the sedlbauer speed fax+ to work properly you have to download 
 
 extern const char *CardType[];
 
-const char *Sedlbauer_revision = "$Revision: 1.17 $";
+const char *Sedlbauer_revision = "$Revision: 1.18 $";
 
 const char *Sedlbauer_Types[] =
        {"None", "speed card/win", "speed star", "speed fax+", 
-       "speed win II / ISDN PC/104", "speed star II", "speed pci"};
+       "speed win II / ISDN PC/104", "speed star II", "speed pci",
+       "speed fax+ pci"};
 
 #ifdef SEDLBAUER_PCI
 #define PCI_VENDOR_SEDLBAUER   0xe159
-#define PCI_SPEEDPCI_ID        0x02
+#define PCI_SPEEDPCI_ID                0x02
+#define PCI_SUBVENDOR_SEDLBAUER        0x51
+#define PCI_SUB_ID_SPEEDFAXP   0x01
 #endif
  
 #define SEDL_SPEED_CARD_WIN    1
@@ -123,6 +130,7 @@ const char *Sedlbauer_Types[] =
 #define SEDL_SPEED_WIN2_PC104  4
 #define SEDL_SPEED_STAR2       5
 #define SEDL_SPEED_PCI         6
+#define SEDL_SPEEDFAX_PCI      7
 
 #define SEDL_CHIP_TEST         0
 #define SEDL_CHIP_ISAC_HSCX    1
@@ -153,12 +161,19 @@ const char *Sedlbauer_Types[] =
 #define SEDL_ISAR_ISA_ISAR_RESET_ON    10
 #define SEDL_ISAR_ISA_ISAR_RESET_OFF   12
 
-#define SEDL_IPAC_ANY_ADR      0
-#define SEDL_IPAC_ANY_IPAC     2
+#define SEDL_IPAC_ANY_ADR              0
+#define SEDL_IPAC_ANY_IPAC             2
 
-#define SEDL_IPAC_PCI_BASE     0
-#define SEDL_IPAC_PCI_ADR      0xc0
-#define SEDL_IPAC_PCI_IPAC     0xc8
+#define SEDL_IPAC_PCI_BASE             0
+#define SEDL_IPAC_PCI_ADR              0xc0
+#define SEDL_IPAC_PCI_IPAC             0xc8
+#define SEDL_ISAR_PCI_ADR              0xc8
+#define SEDL_ISAR_PCI_ISAC             0xd0
+#define SEDL_ISAR_PCI_ISAR             0xe0
+#define SEDL_ISAR_PCI_ISAR_RESET_ON    0x01
+#define SEDL_ISAR_PCI_ISAR_RESET_OFF   0x18
+#define SEDL_ISAR_PCI_LED1             0x08
+#define SEDL_ISAR_PCI_LED2             0x10
 
 #define SEDL_RESET      0x3    /* same as DOS driver */
 
@@ -235,24 +250,25 @@ WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 static u_char
 ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-        return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));}
+       return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));
+}
 
 static void
 WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-        writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value);
+       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value);
 }
 
 static void
 ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-        readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
+       readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
 }
 
 static void
 WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-        writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
+       writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
 }
 
 static u_char
@@ -485,6 +501,17 @@ reset_sedlbauer(struct IsdnCardState *cs)
                        writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
                        writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
                        restore_flags(flags);
+               } else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) &&
+                       (cs->hw.sedl.bus == SEDL_BUS_PCI)) {
+                       byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+                       save_flags(flags);
+                       sti();
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout((20*HZ)/1000);
+                       byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout((20*HZ)/1000);
+                       restore_flags(flags);
                } else {                
                        byteout(cs->hw.sedl.reset_on, SEDL_RESET);      /* Reset On */
                        save_flags(flags);
@@ -537,6 +564,24 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        return(0);
                case CARD_TEST:
                        return(0);
+               case MDL_INFO_CONN:
+                       if (cs->subtyp != SEDL_SPEEDFAX_PCI)
+                               return(0);
+                       if ((long) arg)
+                               cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
+                       else
+                               cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1;
+                       byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+                       break;
+               case MDL_INFO_REL:
+                       if (cs->subtyp != SEDL_SPEEDFAX_PCI)
+                               return(0);
+                       if ((long) arg)
+                               cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2;
+                       else
+                               cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1;
+                       byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+                       break;
        }
        return(0);
 }
@@ -551,6 +596,8 @@ setup_sedlbauer(struct IsdnCard *card))
        int bytecnt, ver, val;
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
+       u16 sub_vendor_id, sub_id;
+       long flags;
 
        strcpy(tmp, Sedlbauer_revision);
        printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -598,15 +645,40 @@ setup_sedlbauer(struct IsdnCard *card))
                        printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
                        return(0);
                }
-                cs->irq_flags |= SA_SHIRQ;
+               cs->irq_flags |= SA_SHIRQ;
                cs->hw.sedl.bus = SEDL_BUS_PCI;
-               cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-               cs->subtyp = SEDL_SPEED_PCI;
+               pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_VENDOR_ID,
+                       &sub_vendor_id);
+               pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_ID,
+                       &sub_id);
+               printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+                       sub_vendor_id, sub_id);
+               printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+                       cs->hw.sedl.cfg_reg);
+               if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) &&
+                       (sub_id == PCI_SUB_ID_SPEEDFAXP)) {
+                       cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+                       cs->subtyp = SEDL_SPEEDFAX_PCI;
+                       cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
+                                               SEDL_ISAR_PCI_ISAR_RESET_ON;
+                       cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
+                                               SEDL_ISAR_PCI_ISAR_RESET_OFF;
+               } else {
+                       cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+                       cs->subtyp = SEDL_SPEED_PCI;
+               }
                bytecnt = 256;
                byteout(cs->hw.sedl.cfg_reg, 0xff);
                byteout(cs->hw.sedl.cfg_reg, 0x00);
                byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
                byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
+               byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+               save_flags(flags);
+               sti();
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout((10*HZ)/1000);
+               byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+               restore_flags(flags);
 #else
                printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
                return (0);
@@ -688,7 +760,7 @@ setup_sedlbauer(struct IsdnCard *card))
                 cs->writeisacfifo = &WriteISACfifo_IPAC;
                 cs->irq_func = &sedlbauer_interrupt_ipac;
 
-               val = readreg(cs->hw.sedl.adr,cs->hw.sedl.isac, IPAC_ID);
+               val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID);
                 printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val);
                reset_sedlbauer(cs);
        } else {
@@ -698,18 +770,31 @@ setup_sedlbauer(struct IsdnCard *card))
                cs->readisacfifo = &ReadISACfifo;
                cs->writeisacfifo = &WriteISACfifo;
                if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
-                       cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ADR;
-                       cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAC;
-                       cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR;
-                       cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_ON;
-                       cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_OFF;
+                       if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
+                               cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
+                                                       SEDL_ISAR_PCI_ADR;
+                               cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
+                                                       SEDL_ISAR_PCI_ISAC;
+                               cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
+                                                       SEDL_ISAR_PCI_ISAR;
+                       } else {
+                               cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
+                                                       SEDL_ISAR_ISA_ADR;
+                               cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
+                                                       SEDL_ISAR_ISA_ISAC;
+                               cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
+                                                       SEDL_ISAR_ISA_ISAR;
+                               cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
+                                                       SEDL_ISAR_ISA_ISAR_RESET_ON;
+                               cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
+                                                       SEDL_ISAR_ISA_ISAR_RESET_OFF;
+                       }
                        cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
                        cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
                        test_and_set_bit(HW_ISAR, &cs->HW_Flags);
                        cs->irq_func = &sedlbauer_interrupt_isar;
                        cs->auxcmd = &isar_auxcmd;
                        ISACVersion(cs, "Sedlbauer:");
-               
                        cs->BC_Read_Reg = &ReadISAR;
                        cs->BC_Write_Reg = &WriteISAR;
                        cs->BC_Send_Data = &isar_fill_fifo;
index 866e8dac5effc29f1b5f4d2f02aaa885b0d5f290..582b49af501463f9201e402894a318f8c462e66e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 2.9 1999/07/12 21:05:31 keil Exp $
+/* $Id: teles0.c,v 2.10 1999/11/14 23:37:03 keil Exp $
 
  * teles0.c     low level stuff for Teles Memory IO isdn cards
  *              based on the teles driver from Jan den Ouden
@@ -10,6 +10,9 @@
  *              Beat Doebeli
  *
  * $Log: teles0.c,v $
+ * Revision 2.10  1999/11/14 23:37:03  keil
+ * new ISA memory mapped IO
+ *
  * Revision 2.9  1999/07/12 21:05:31  keil
  * fix race in IRQ handling
  * added watchdog for lost IRQs
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 2.9 $";
+const char *teles0_revision = "$Revision: 2.10 $";
 
+#define TELES_IOMEM_SIZE       0x400
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
 static inline u_char
-readisac(unsigned int adr, u_char off)
+readisac(unsigned long adr, u_char off)
 {
        return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
 }
 
 static inline void
-writeisac(unsigned int adr, u_char off, u_char data)
+writeisac(unsigned long adr, u_char off, u_char data)
 {
        writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
 }
 
 
 static inline u_char
-readhscx(unsigned int adr, int hscx, u_char off)
+readhscx(unsigned long adr, int hscx, u_char off)
 {
        return readb(adr + (hscx ? 0x1c0 : 0x180) +
                     ((off & 1) ? 0x1ff : 0) + off);
 }
 
 static inline void
-writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+writehscx(unsigned long adr, int hscx, u_char off, u_char data)
 {
        writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
               ((off & 1) ? 0x1ff : 0) + off); mb();
 }
 
 static inline void
-read_fifo_isac(unsigned int adr, u_char * data, int size)
+read_fifo_isac(unsigned long adr, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *) ((long)adr + 0x100);
+       register u_char *ad = (u_char *)adr + 0x100;
        for (i = 0; i < size; i++)
                data[i] = readb(ad);
 }
 
 static inline void
-write_fifo_isac(unsigned int adr, u_char * data, int size)
+write_fifo_isac(unsigned long adr, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *) ((long)adr + 0x100);
+       register u_char *ad = (u_char *)adr + 0x100;
        for (i = 0; i < size; i++) {
                writeb(data[i], ad); mb();
        }
 }
 
 static inline void
-read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180));
+       register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
        for (i = 0; i < size; i++)
                data[i] = readb(ad);
 }
 
 static inline void
-write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
        int i;
-       register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180));
+       register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
        for (i = 0; i < size; i++) {
                writeb(data[i], ad); mb();
        }
@@ -262,7 +266,7 @@ reset_teles0(struct IsdnCardState *cs)
                        default:
                                return(1);
                }
-               cfval |= ((cs->hw.teles0.membase >> 9) & 0xF0);
+               cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0);
                byteout(cs->hw.teles0.cfg_reg + 4, cfval);
                HZDELAY(HZ / 10 + 1);
                byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
@@ -318,10 +322,9 @@ setup_teles0(struct IsdnCard *card))
                   "Teles0: membase configured DOSish, assuming 0x%lx\n",
                       (unsigned long) card->para[1]);
        }
-       cs->hw.teles0.membase = card->para[1];
        cs->irq = card->para[0];
        if (cs->hw.teles0.cfg_reg) {
-               if (check_region((cs->hw.teles0.cfg_reg), 8)) {
+               if (check_region(cs->hw.teles0.cfg_reg, 8)) {
                        printk(KERN_WARNING
                          "HiSax: %s config port %x-%x already in use\n",
                               CardType[card->typ],
@@ -358,8 +361,10 @@ setup_teles0(struct IsdnCard *card))
        }
        /* 16.0 and 8.0 designed for IOM1 */
        test_and_set_bit(HW_IOM1, &cs->HW_Flags);
+       cs->hw.teles0.phymem = card->para[1];
+       cs->hw.teles0.membase = cs->hw.teles0.phymem;
        printk(KERN_INFO
-              "HiSax: %s config irq:%d mem:0x%X cfg:0x%X\n",
+              "HiSax: %s config irq:%d mem:0x%lX cfg:0x%X\n",
               CardType[cs->typ], cs->irq,
               cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
        if (reset_teles0(cs)) {
index e98e4d742b562ea7430a442c8e15b1807930ceb0..31c7365bc3d4d9a5b29000c50ea48be05fb5b66b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: telespci.c,v 2.9 1999/08/11 21:01:34 keil Exp $
+/* $Id: telespci.c,v 2.10 1999/11/15 14:20:05 keil Exp $
 
  * telespci.c     low level stuff for Teles PCI isdn cards
  *
@@ -7,6 +7,9 @@
  *
  *
  * $Log: telespci.c,v $
+ * Revision 2.10  1999/11/15 14:20:05  keil
+ * 64Bit compatibility
+ *
  * Revision 2.9  1999/08/11 21:01:34  keil
  * new PCI codefix
  *
@@ -44,7 +47,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.9 $";
+const char *telespci_revision = "$Revision: 2.10 $";
 
 #define ZORAN_PO_RQ_PEN        0x02000000
 #define ZORAN_PO_WR    0x00800000
@@ -66,7 +69,7 @@ const char *telespci_revision = "$Revision: 2.9 $";
                                } while (portdata & ZORAN_PO_RQ_PEN)
 
 static inline u_char
-readisac(unsigned int adr, u_char off)
+readisac(unsigned long adr, u_char off)
 {
        register unsigned int portdata;
 
@@ -83,7 +86,7 @@ readisac(unsigned int adr, u_char off)
 }
 
 static inline void
-writeisac(unsigned int adr, u_char off, u_char data)
+writeisac(unsigned long adr, u_char off, u_char data)
 {
        register unsigned int portdata;
 
@@ -99,7 +102,7 @@ writeisac(unsigned int adr, u_char off, u_char data)
 }
 
 static inline u_char
-readhscx(unsigned int adr, int hscx, u_char off)
+readhscx(unsigned long adr, int hscx, u_char off)
 {
        register unsigned int portdata;
 
@@ -115,7 +118,7 @@ readhscx(unsigned int adr, int hscx, u_char off)
 }
 
 static inline void
-writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+writehscx(unsigned long adr, int hscx, u_char off, u_char data)
 {
        register unsigned int portdata;
 
@@ -130,7 +133,7 @@ writehscx(unsigned int adr, int hscx, u_char off, u_char data)
 }
 
 static inline void
-read_fifo_isac(unsigned int adr, u_char * data, int size)
+read_fifo_isac(unsigned long adr, u_char * data, int size)
 {
        register unsigned int portdata;
        register int i;
@@ -148,7 +151,7 @@ read_fifo_isac(unsigned int adr, u_char * data, int size)
 }
 
 static void
-write_fifo_isac(unsigned int adr, u_char * data, int size)
+write_fifo_isac(unsigned long adr, u_char * data, int size)
 {
        register unsigned int portdata;
        register int i;
@@ -165,7 +168,7 @@ write_fifo_isac(unsigned int adr, u_char * data, int size)
 }
 
 static inline void
-read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+read_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
        register unsigned int portdata;
        register int i;
@@ -183,7 +186,7 @@ read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
 }
 
 static inline void
-write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+write_fifo_hscx(unsigned long adr, int hscx, u_char * data, int size)
 {
        unsigned int portdata;
        register int i;
@@ -324,7 +327,7 @@ setup_telespci(struct IsdnCard *card))
                        printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
                        return(0);
                }
-               cs->hw.teles0.membase = (u_int) ioremap(dev_tel->base_address[ 0],
+               cs->hw.teles0.membase = (u_long) ioremap(dev_tel->base_address[ 0],
                        PAGE_SIZE);
                printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
                        dev_tel->base_address[ 0], dev_tel->irq);
@@ -348,7 +351,7 @@ setup_telespci(struct IsdnCard *card))
        /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
 
        printk(KERN_INFO
-              "HiSax: %s config irq:%d mem:%x\n",
+              "HiSax: %s config irq:%d mem:%lx\n",
               CardType[cs->typ], cs->irq,
               cs->hw.teles0.membase);
 
index f72de9a3085a656e157d9e98238e20383e08fa60..aca4f35ad72ca46f8e57dbb7110551c38c33f67e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.87 1999/09/12 16:19:39 detabc Exp $
+/* $Id: isdn_common.c,v 1.93 1999/11/04 13:11:36 keil Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.93  1999/11/04 13:11:36  keil
+ * Reinit of v110 structs
+ *
+ * Revision 1.92  1999/10/31 15:59:50  he
+ * more skb headroom checks
+ *
+ * Revision 1.91  1999/10/28 22:48:45  armin
+ * Bugfix: isdn_free_channel() now frees the channel,
+ * even when the usage of the ttyI has changed.
+ *
+ * Revision 1.90  1999/10/27 21:21:17  detabc
+ * Added support for building logically-bind-group's per interface.
+ * usefull for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
+ * Revision 1.89  1999/10/16 14:46:47  keil
+ * replace kmalloc with vmalloc for the big dev struct
+ *
+ * Revision 1.88  1999/10/02 00:39:26  he
+ * Fixed a 2.3.x wait queue initialization (was causing panics)
+ *
  * Revision 1.87  1999/09/12 16:19:39  detabc
  * added abc features
  * low cost routing for net-interfaces (only the HL side).
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/poll.h>
+#include <linux/vmalloc.h>
 #include <linux/isdn.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static char *isdn_revision = "$Revision: 1.87 $";
+static char *isdn_revision = "$Revision: 1.93 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -2098,13 +2124,19 @@ isdn_free_channel(int di, int ch, int usage)
        save_flags(flags);
        cli();
        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-               if (((dev->usage[i] & ISDN_USAGE_MASK) == usage) &&
+               if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
                    (dev->drvmap[i] == di) &&
                    (dev->chanmap[i] == ch)) {
                        dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
                        strcpy(dev->num[i], "???");
                        dev->ibytes[i] = 0;
                        dev->obytes[i] = 0;
+// 20.10.99 JIM, try to reinitialize v110 !
+                       dev->v110emu[i] = 0;
+                       atomic_set(&(dev->v110use[i]), 0);
+                       isdn_v110_close(dev->v110[i]);
+                       dev->v110[i] = NULL;
+// 20.10.99 JIM, try to reinitialize v110 !
                        isdn_info_update();
                        isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
                }
@@ -2186,8 +2218,33 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
                /* V.110 must always be acknowledged */
                ack = 1;
                ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
-       } else
-               ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
+       } else {
+               int hl = dev->drv[drvidx]->interface->hl_hdrlen;
+
+               if( skb_headroom(skb) < hl ){
+                       /* 
+                        * This should only occur when new HL driver with
+                        * increased hl_hdrlen was loaded after netdevice
+                        * was created and connected to the new driver.
+                        *
+                        * The V.110 branch (re-allocates on its own) does
+                        * not need this
+                        */
+                       struct sk_buff * skb_tmp;
+
+                       skb_tmp = skb_realloc_headroom(skb, hl);
+                       printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
+                       if (!skb_tmp) return -ENOMEM; /* 0 better? */
+                       ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp);
+                       if( ret > 0 ){
+                               dev_kfree_skb(skb);
+                       } else {
+                               dev_kfree_skb(skb_tmp);
+                       }
+               } else {
+                       ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
+               }
+       }
        if (ret > 0) {
                dev->obytes[idx] += ret;
                if (dev->v110[idx]) {
@@ -2470,8 +2527,7 @@ isdn_init(void)
        int i;
        char tmprev[50];
 
-       sti();
-       if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
+       if (!(dev = (isdn_dev *) vmalloc(sizeof(isdn_dev)))) {
                printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
                return -EIO;
        }
@@ -2487,7 +2543,7 @@ isdn_init(void)
        }
        if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
                printk(KERN_WARNING "isdn: Could not register control devices\n");
-               kfree(dev);
+               vfree(dev);
                return -EIO;
        }
        if ((i = isdn_tty_modem_init()) < 0) {
@@ -2496,7 +2552,7 @@ isdn_init(void)
                        tty_unregister_driver(&dev->mdm.cua_modem);
                if (i <= -2)
                        tty_unregister_driver(&dev->mdm.tty_modem);
-               kfree(dev);
+               vfree(dev);
                unregister_chrdev(ISDN_MAJOR, "isdn");
                return -EIO;
        }
@@ -2508,7 +2564,7 @@ isdn_init(void)
                for (i = 0; i < ISDN_MAX_CHANNELS; i++)
                        kfree(dev->mdm.info[i].xmit_buf - 4);
                unregister_chrdev(ISDN_MAJOR, "isdn");
-               kfree(dev);
+               vfree(dev);
                return -EIO;
        }
 #endif                          /* CONFIG_ISDN_PPP */
@@ -2577,7 +2633,7 @@ cleanup_module(void)
                printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
        } else {
                del_timer(&dev->timer);
-               kfree(dev);
+               vfree(dev);
                printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
        }
        restore_flags(flags);
index 23c6fe94af21a42b91cc834a1ace4cb901b842af..83caab9c51e56cc06d5088ee693246c16beed6c1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.16 1999/07/01 08:29:54 keil Exp $
+/* $Id: isdn_common.h,v 1.17 1999/10/27 21:21:17 detabc Exp $
 
  * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.h,v $
+ * Revision 1.17  1999/10/27 21:21:17  detabc
+ * Added support for building logically-bind-group's per interface.
+ * usefull for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
  * Revision 1.16  1999/07/01 08:29:54  keil
  * compatibility to 2.3 kernel
  *
index ada4a4902d37d9cc344f812767cc99695bc80f42..ae953c11b69a7d076d6001eb25fb7962e4df5499 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.92 1999/09/13 23:25:17 he Exp $
+/* $Id: isdn_net.c,v 1.95 1999/10/27 21:21:17 detabc Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.95  1999/10/27 21:21:17  detabc
+ * Added support for building logically-bind-group's per interface.
+ * usefull for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
+ * Revision 1.94  1999/10/02 11:07:02  he
+ * Changed tbusy logic in indn_net.c
+ *
+ * Revision 1.93  1999/09/23 22:22:41  detabc
+ * added tcp-keepalive-detect with local response (ipv4 only)
+ * added host-only-interface support
+ * (source ipaddr == interface ipaddr) (ipv4 only)
+ * ok with kernel 2.3.18 and 2.2.12
+ *
  * Revision 1.92  1999/09/13 23:25:17  he
  * serialized xmitting frames from isdn_ppp and BSENT statcallb
  *
 #endif
 
 
+#ifndef ISDN_NEW_TBUSY
+#define ISDN_NEW_TBUSY
+#endif
+#ifdef ISDN_NEW_TBUSY
+/*
+ * Outline of new tbusy handling: 
+ *
+ * Old method, roughly spoken, consisted of setting tbusy when entering
+ * isdn_net_start_xmit() and at several other locations and clearing
+ * it from isdn_net_start_xmit() thread when sending was successful.
+ *
+ * With 2.3.x multithreaded network core, to prevent problems, tbusy should
+ * only be set by the isdn_net_start_xmit() thread and only when a tx-busy
+ * condition is detected. Other threads (in particular isdn_net_stat_callb())
+ * are only allowed to clear tbusy.
+ *
+ * -HE
+ */
+
+/*
+ * Tell upper layers that the network device is ready to xmit more frames.
+ */
+static void __inline__ isdn_net_dev_xon(struct device * dev)
+{
+       dev->tbusy = 0;
+       mark_bh(NET_BH);
+}
+
+static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
+{
+       lp->netdev->dev.tbusy = 0;
+       if(lp->master) lp->master->tbusy = 0;
+       mark_bh(NET_BH);
+}
+
+/*
+ * Ask upper layers to temporarily cease passing us more xmit frames.
+ */
+static void __inline__ isdn_net_dev_xoff(struct device * dev)
+{
+       dev->tbusy = 1;
+}
+#endif
 
 /* Prototypes */
 
@@ -382,7 +443,7 @@ int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
 static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
 
-char *isdn_net_revision = "$Revision: 1.92 $";
+char *isdn_net_revision = "$Revision: 1.95 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -424,7 +485,11 @@ isdn_net_reset(struct device *dev)
        save_flags(flags);
        cli();                  /* Avoid glitch on writes to CMD regs */
        dev->interrupt = 0;
+#ifdef ISDN_NEW_TBUSY
+       isdn_net_dev_xon(dev);
+#else
        dev->tbusy = 0;
+#endif
 #ifdef CONFIG_ISDN_X25
        if( cprot && cprot -> pops && dops )
                cprot -> pops -> restart ( cprot, dev, dops );
@@ -638,13 +703,19 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
                                                        mdev = &lp->netdev->dev;
                                                if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
                                                        lp->sav_skb = NULL;
+#ifndef ISDN_NEW_TBUSY
                                                        mark_bh(NET_BH);
+#endif
                                                } else {
                                                        return 1;
                                                }
                                        }
+#ifdef ISDN_NEW_TBUSY
+                                       isdn_net_lp_xon(lp);
+#else
                                        if (test_and_clear_bit(0, (void *) &(p->dev.tbusy)))
                                                mark_bh(NET_BH);
+#endif
                                }
                                return 1;
                        case ISDN_STAT_DCONN:
@@ -727,7 +798,6 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
                                                lp->dialstarted = 0;
                                                lp->dialwait_timer = 0;
 
-                                               /* Immediately send first skb to speed up arp */
 #ifdef CONFIG_ISDN_PPP
                                                if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
                                                        isdn_ppp_wakeup_daemon(lp);
@@ -738,11 +808,15 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
                                                        if( pops->connect_ind)
                                                                pops->connect_ind(cprot);
 #endif /* CONFIG_ISDN_X25 */
+                                               /* Immediately send first skb to speed up arp */
                                                if (lp->first_skb) {
 
                                                        if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
                                                                lp->first_skb = NULL;
                                                }
+#ifdef ISDN_NEW_TBUSY
+                                               if(! lp->first_skb) isdn_net_lp_xon(lp);
+#else
                                                else {
                                                        /*
                                                         * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb).
@@ -751,6 +825,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
                                                        lp->netdev->dev.tbusy = 0;
                                                        mark_bh(NET_BH);
                                                }
+#endif /* ISDN_NEW_TBUSY */
                                                return 1;
                                }
                                break;
@@ -1185,6 +1260,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
                                        break;
                        }
                        printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
+
                               p[12], p[13], p[14], p[15],
                               p[16], p[17], p[18], p[19],
                               addinfo);
@@ -1203,8 +1279,12 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
  * standard send-routine, else send directly.
  *
  * Return: 0 on success, !0 on failure.
+ */
+#ifndef ISDN_NEW_TBUSY
+/*
  * Side-effects: ndev->tbusy is cleared on success.
  */
+#endif
 int
 isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
                  struct sk_buff *skb)
@@ -1215,13 +1295,17 @@ isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
        ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
        if (ret == len) {
                lp->transcount += len;
+#ifndef ISDN_NEW_TBUSY
                clear_bit(0, (void *) &(ndev->tbusy));
+#endif
                return 0;
        }
        if (ret < 0) {
                dev_kfree_skb(skb);
                lp->stats.tx_errors++;
+#ifndef ISDN_NEW_TBUSY
                clear_bit(0, (void *) &(ndev->tbusy));
+#endif
                return 0;
        }
        return 1;
@@ -1267,7 +1351,11 @@ isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
                        if (lp->srobin == ndev)
                                ret = isdn_net_send_skb(ndev, lp, skb);
                        else
+#ifdef ISDN_NEW_TBUSY
+                               ret = isdn_net_start_xmit(skb, lp->srobin);
+#else
                                ret = ndev->tbusy = isdn_net_start_xmit(skb, lp->srobin);
+#endif
                        lp->srobin = (slp->slave) ? slp->slave : ndev;
                        slp = (isdn_net_local *) (lp->srobin->priv);
                        if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
@@ -1327,8 +1415,13 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                if (!lp->dialstate)
                        lp->stats.tx_errors++;
                ndev->trans_start = jiffies;
+#ifdef ISDN_NEW_TBUSY
+               isdn_net_dev_xon(ndev);
+#endif
        }
+#ifndef ISDN_NEW_TBUSY
        ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
+#endif
 #ifdef CONFIG_ISDN_X25
 /* At this point hard_start_xmit() passes control to the encapsulation
    protocol (if present).
@@ -1342,7 +1435,11 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
    when a dl_establish request is received from the upper layer.
 */
        if( cprot ) {
-               return  cprot -> pops -> encap_and_xmit ( cprot , skb);
+               int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
+#ifdef ISDN_NEW_TBUSY
+               if(ret) isdn_net_dev_xoff(ndev);
+#endif
+               return ret;
        } else
 #endif
        /* auto-dialing xmit function */
@@ -1361,7 +1458,9 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                        if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
                                isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
                                dev_kfree_skb(skb);
+#ifndef ISDN_NEW_TBUSY
                                ndev->tbusy = 0;
+#endif
                                return 0;
                        }
                        if (lp->phone[1]) {
@@ -1377,7 +1476,9 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                        if(jiffies < lp->dialwait_timer) {
                                                isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
                                                dev_kfree_skb(skb);
+#ifndef ISDN_NEW_TBUSY
                                                ndev->tbusy = 0;
+#endif
                                                restore_flags(flags);
                                                return 0;
                                        } else
@@ -1386,22 +1487,28 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
 
                                /* Grab a free ISDN-Channel */
                                if (((chi =
-                                    isdn_get_free_channel(ISDN_USAGE_NET,
-                                                          lp->l2_proto,
-                                                          lp->l3_proto,
-                                                          lp->pre_device,
-                                                lp->pre_channel)) < 0) &&
+                                    isdn_get_free_channel(
+                                                       ISDN_USAGE_NET,
+                                                       lp->l2_proto,
+                                                       lp->l3_proto,
+                                                       lp->pre_device,
+                                                       lp->pre_channel)
+                                                       ) < 0) &&
                                        ((chi =
-                                    isdn_get_free_channel(ISDN_USAGE_NET,
-                                                          lp->l2_proto,
-                                                          lp->l3_proto,
-                                                          lp->pre_device,
-                                                lp->pre_channel^1)) < 0)) {
+                                    isdn_get_free_channel(
+                                                       ISDN_USAGE_NET,
+                                                       lp->l2_proto,
+                                                       lp->l3_proto,
+                                                       lp->pre_device,
+                                                   lp->pre_channel^1)
+                                                       ) < 0)) {
                                        restore_flags(flags);
                                        isdn_net_unreachable(ndev, skb,
                                                           "No channel");
                                        dev_kfree_skb(skb);
+#ifndef ISDN_NEW_TBUSY
                                        ndev->tbusy = 0;
+#endif
                                        return 0;
                                }
                                /* Log packet, which triggered dialing */
@@ -1421,6 +1528,9 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                        }
                                        restore_flags(flags);
                                        isdn_net_dial();        /* Initiate dialing */
+#ifdef ISDN_NEW_TBUSY
+                                       isdn_net_dev_xoff(ndev);
+#endif
                                        return 1;       /* let upper layer requeue skb packet */
                                }
 #endif
@@ -1434,7 +1544,9 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                }
                                lp->first_skb = skb;
                                /* Initiate dialing */
+#ifndef ISDN_NEW_TBUSY
                                ndev->tbusy = 0;
+#endif
                                restore_flags(flags);
                                isdn_net_dial();
                                return 0;
@@ -1442,21 +1554,37 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                isdn_net_unreachable(ndev, skb,
                                                     "No phone number");
                                dev_kfree_skb(skb);
+#ifndef ISDN_NEW_TBUSY
                                ndev->tbusy = 0;
+#endif
                                return 0;
                        }
                } else {
-                       /* Connection is established, try sending */
+                       /* Device is connected to an ISDN channel */ 
                        ndev->trans_start = jiffies;
                        if (!lp->dialstate) {
+                               /* ISDN connection is established, try sending */
+                               int ret;
                                if (lp->first_skb) {
-                                       if (isdn_net_xmit(ndev, lp, lp->first_skb))
+                                       if (isdn_net_xmit(ndev, lp, lp->first_skb)){
+#ifdef ISDN_NEW_TBUSY
+                                               isdn_net_dev_xoff(ndev);
+#endif
                                                return 1;
+}
                                        lp->first_skb = NULL;
                                }
-                               return (isdn_net_xmit(ndev, lp, skb));
+                               ret = (isdn_net_xmit(ndev, lp, skb));
+#ifdef ISDN_NEW_TBUSY
+                               if(ret) isdn_net_dev_xoff(ndev);
+#endif
+                               return ret;
                        } else
+#ifdef ISDN_NEW_TBUSY
+                               isdn_net_dev_xoff(ndev);
+#else
                                ndev->tbusy = 1;
+#endif
                }
        }
        return 1;
@@ -2068,7 +2196,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
        isdn_net_phone *n;
        ulong flags;
        char nr[32];
-
        /* Search name in netdev-chain */
        save_flags(flags);
        cli();
@@ -2280,10 +2407,15 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                               lp->name, nr, eaz);
                                        if (lp->phone[1]) {
                                                /* Grab a free ISDN-Channel */
-                                               if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
+                                               if ((chi = 
+                                                       isdn_get_free_channel(
+                                                               ISDN_USAGE_NET,
+                                                               lp->l2_proto,
                                                            lp->l3_proto,
-                                                         lp->pre_device,
-                                                lp->pre_channel)) < 0) {
+                                                               lp->pre_device,
+                                                               lp->pre_channel)
+                                                               ) < 0) {
+
                                                        printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
                                                        restore_flags(flags);
                                                        return 0;
@@ -2390,10 +2522,14 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
                        cli();
 
                        /* Grab a free ISDN-Channel */
-                       if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
-                                                        lp->l3_proto,
-                                                        lp->pre_device,
-                                                lp->pre_channel)) < 0) {
+                       if ((chi = 
+                                               isdn_get_free_channel(
+                                                       ISDN_USAGE_NET,
+                                                       lp->l2_proto,
+                                                       lp->l3_proto,
+                                                       lp->pre_device,
+                                                       lp->pre_channel)
+                                                       ) < 0) {
                                printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
                                restore_flags(flags);
                                return -EAGAIN;
@@ -3153,4 +3289,3 @@ isdn_net_rmall(void)
        restore_flags(flags);
        return 0;
 }
-
index 150468eaef701eb027020f2c25099f71ed3fe411..df69bce3a4f85e3d629de77b95bc2e0a7ee6bec2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.54 1999/09/13 23:25:17 he Exp $
+/* $Id: isdn_ppp.c,v 1.60 1999/11/04 20:29:55 he Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.60  1999/11/04 20:29:55  he
+ * applied Andre Beck's reset_free fix
+ *
+ * Revision 1.59  1999/10/31 15:59:50  he
+ * more skb headroom checks
+ *
+ * Revision 1.58  1999/10/30 13:13:01  keil
+ * Henners isdn_ppp_skb_push:under fix
+ *
+ * Revision 1.57  1999/10/05 22:47:17  he
+ * Removed dead ISDN_SYNCPPP_READDRESS code (obsoleted by sysctl_ip_dynaddr
+ * and network address translation)
+ *
+ * Revision 1.56  1999/09/29 16:01:06  he
+ * replaced dev_alloc_skb() for downstream skbs by equivalent alloc_skb()
+ *
+ * Revision 1.55  1999/09/23 22:07:51  detabc
+ *
+ * make ipc_head common usable (for use compressor with raw-ip)
+ * add function before netif_rx(). needed for ipv4-tcp-keepalive-detect.
+ * ~
+ *
  * Revision 1.54  1999/09/13 23:25:17  he
  * serialized xmitting frames from isdn_ppp and BSENT statcallb
  *
 
 /* TODO: right tbusy handling when using MP */
 
-/*
- * experimental for dynamic addressing: readdress IP frames
- */
-#undef ISDN_SYNCPPP_READDRESS
 #define CONFIG_ISDN_CCP 1
 
 #include <linux/config.h>
@@ -264,6 +282,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
                                    unsigned char code, unsigned char id,
                                    unsigned char *data, int len);
 static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
+static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);
 static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
                                          unsigned char id);
 static void isdn_ppp_ccp_timer_callback(unsigned long closure);
@@ -287,9 +306,10 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
 static void isdn_ppp_free_mpqueue(isdn_net_dev *);
 #endif
 
-char *isdn_ppp_revision = "$Revision: 1.54 $";
+char *isdn_ppp_revision = "$Revision: 1.60 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+
 static struct isdn_ppp_compressor *ipc_head = NULL;
 
 /*
@@ -360,10 +380,6 @@ isdn_ppp_free(isdn_net_local * lp)
                printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
 
        is->lp = NULL;          /* link is down .. set lp to NULL */
-#ifdef ISDN_SYNCPPP_READDRESS
-       is->old_pa_addr = 0x0;
-       is->old_pa_dstaddr = 0x0;
-#endif
        lp->ppp_slot = -1;      /* is this OK ?? */
        restore_flags(flags);
 
@@ -608,9 +624,9 @@ isdn_ppp_release(int min, struct file *file)
        is->comp_stat    = is->link_comp_stat    = NULL;
         is->decomp_stat  = is->link_decomp_stat  = NULL;
 
+       /* Clean up if necessary */
        if(is->reset)
-               kfree(is->reset);
-       is->reset = NULL;
+               isdn_ppp_ccp_reset_free(is);
 
        /* this slot is ready for new connections */
        is->state = 0;
@@ -1462,12 +1478,6 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *netdev)
        ipts = ippp_table[mlp->ppp_slot];
 
        if (!(ipts->pppcfg & SC_ENABLE_IP)) {   /* PPP connected ? */
-#ifdef ISDN_SYNCPPP_READDRESS
-               if (!ipts->old_pa_addr)
-                       ipts->old_pa_addr = mdev->pa_addr;
-               if (!ipts->old_pa_dstaddr)
-                       ipts->old_pa_dstaddr = mdev->pa_dstaddr;
-#endif
                if (ipts->debug & 0x1)
                        printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
                return 1;
@@ -1476,21 +1486,6 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *netdev)
        switch (ntohs(skb->protocol)) {
                case ETH_P_IP:
                        proto = PPP_IP;
-#ifdef ISDN_SYNCPPP_READDRESS
-                       if (ipts->old_pa_addr != mdev->pa_addr) {
-                               struct iphdr *ipfr;
-                               ipfr = (struct iphdr *) skb->data;
-                               if(ipts->debug & 0x4)
-                                       printk(KERN_DEBUG "IF-address changed from %lx to %lx\n", ipts->old_pa_addr, mdev->pa_addr);
-                               if (ipfr->version == 4) {
-                                       if (ipfr->saddr == ipts->old_pa_addr) {
-                                               printk(KERN_DEBUG "readdressing %lx to %lx\n", ipfr->saddr, mdev->pa_addr);
-                                               ipfr->saddr = mdev->pa_addr;
-                                       }
-                               }
-                       }
-                       /* dstaddr change not so important */
-#endif
                        break;
                case ETH_P_IPX:
                        proto = PPP_IPX;        /* untested */
@@ -1521,8 +1516,6 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *netdev)
 
        /* Pull off the fake header we stuck on earlier to keep
      * the fragemntation code happy.
-     * this will break the ISDN_SYNCPPP_READDRESS hack a few lines
-     * above. So, enabling this is no longer allowed
      */
        skb_pull(skb,IPPP_MAX_HEADER);
 
@@ -2233,18 +2226,20 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
 {
        struct sk_buff *skb;
        unsigned char *p;
-       int count;
+       int count, hl;
        unsigned long flags;
        int cnt = 0;
        isdn_net_local *lp = is->lp;
 
        /* Alloc large enough skb */
-       skb = dev_alloc_skb(len + 16);
+       hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
+       skb = alloc_skb(len + hl + 16,GFP_ATOMIC);
        if(!skb) {
                printk(KERN_WARNING
                       "ippp: CCP cannot send reset - out of memory\n");
                return;
        }
+       skb_reserve(skb, hl);
 
        /* We may need to stuff an address and control field first */
        if(!(is->pppcfg & SC_COMP_AC)) {
@@ -2299,15 +2294,34 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
 static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
 {
        struct ippp_ccp_reset *r;
-       printk(KERN_DEBUG "ippp_ccp: allocating reset data structure\n");
        r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
-       if(!r)
+       if(!r) {
+               printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
+                      " structure - no mem\n");
                return NULL;
+       }
        memset(r, 0, sizeof(struct ippp_ccp_reset));
+       printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
        is->reset = r;
        return r;
 }
 
+/* Destroy the reset state vector. Kill all pending timers first. */
+static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
+{
+       unsigned int id;
+
+       printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
+              is->reset);
+       for(id = 0; id < 256; id++) {
+               if(is->reset->rs[id]) {
+                       isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
+               }
+       }
+       kfree(is->reset);
+       is->reset = NULL;
+}
+
 /* Free a given state and clear everything up for later reallocation */
 static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
                                          unsigned char id)
@@ -2673,7 +2687,8 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
        }
 
        /* Allow for at least 150 % expansion (for now) */
-       skb_out = dev_alloc_skb(skb_in->len + skb_in->len/2 + 32 + skb_headroom(skb_in));
+       skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 +
+               skb_headroom(skb_in), GFP_ATOMIC);
        if(!skb_out)
                return skb_in;
        skb_reserve(skb_out, skb_headroom(skb_in));
@@ -2905,7 +2920,6 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
        }
 }
 
-
 int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
 {
        ipc->next = ipc_head;
@@ -2940,6 +2954,16 @@ static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_
                printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit,
                        (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num);
 
+       /* If is has no valid reset state vector, we cannot allocate a
+          decompressor. The decompressor would cause reset transactions
+          sooner or later, and they need that vector. */
+
+       if(!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
+               printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
+                      " allow decompression.\n");
+               return -ENOMEM;
+       }
+
        while(ipc) {
                if(ipc->num == num) {
                        stat = ipc->alloc(data);
index 77a7f5dc1e381b01b09582fe66955f703bb41099..f11bba779c85cd858d2faa4450af99ac7b362b9c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.74 1999/09/04 06:20:04 keil Exp $
+/* $Id: isdn_tty.c,v 1.80 1999/11/07 13:34:30 armin Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.80  1999/11/07 13:34:30  armin
+ * Fixed AT command line editor
+ *
+ * Revision 1.79  1999/10/29 18:35:08  armin
+ * Check number len in isdn_get_msnstr() to avoid buffer overflow.
+ *
+ * Revision 1.78  1999/10/28 23:03:51  armin
+ * Bugfix: now freeing channel on modem_hup() even when
+ * usage on ttyI has changed and error-report for
+ * AT-commands on wrong channel-state.
+ *
+ * Revision 1.77  1999/10/26 21:13:14  armin
+ * using define for checking phone number len in isdn_tty_getdial()
+ *
+ * Revision 1.76  1999/10/11 22:16:26  keil
+ * Suspend/Resume is possible without explicit ID too
+ *
+ * Revision 1.75  1999/10/08 18:59:32  armin
+ * Bugfix of too small MSN buffer and checking phone number
+ * in isdn_tty_getdial()
+ *
  * Revision 1.74  1999/09/04 06:20:04  keil
  * Changes from kernel set_current_state()
  *
@@ -351,7 +372,7 @@ static int bit2si[8] =
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.74 $";
+char *isdn_tty_revision = "$Revision: 1.80 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -1017,7 +1038,6 @@ void
 isdn_tty_modem_hup(modem_info * info, int local)
 {
        isdn_ctrl cmd;
-       int usage;
 
        if (!info)
                return;
@@ -1071,10 +1091,7 @@ isdn_tty_modem_hup(modem_info * info, int local)
                }
                isdn_all_eaz(info->isdn_driver, info->isdn_channel);
                info->emu.mdmreg[REG_RINGCNT] = 0;
-               usage = isdn_calc_usage(info->emu.mdmreg[REG_SI1I],
-                                       info->emu.mdmreg[REG_L2PROT]);
-               isdn_free_channel(info->isdn_driver, info->isdn_channel,
-                                 usage);
+               isdn_free_channel(info->isdn_driver, info->isdn_channel, 0);
        }
        info->isdn_driver = -1;
        info->isdn_channel = -1;
@@ -1111,8 +1128,8 @@ isdn_tty_suspend(char *id, modem_info * info, atemu * m)
        printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
 #endif
        l = strlen(id);
-       if ((info->isdn_driver >= 0) && l) {
-               cmd.parm.cmsg.Length = l+17;
+       if ((info->isdn_driver >= 0)) {
+               cmd.parm.cmsg.Length = l+18;
                cmd.parm.cmsg.Command = CAPI_FACILITY;
                cmd.parm.cmsg.Subcommand = CAPI_REQ;
                cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
@@ -1150,10 +1167,6 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
        int l;
 
        l = strlen(id);
-       if (!l) {
-               isdn_tty_modem_result(4, info);
-               return;
-       }
        for (j = 7; j >= 0; j--)
                if (m->mdmreg[REG_SI1] & (1 << j)) {
                        si = bit2si[j];
@@ -1207,7 +1220,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
                isdn_command(&cmd);
                cmd.driver = info->isdn_driver;
                cmd.arg = info->isdn_channel;
-               cmd.parm.cmsg.Length = l+17;
+               cmd.parm.cmsg.Length = l+18;
                cmd.parm.cmsg.Command = CAPI_FACILITY;
                cmd.parm.cmsg.Subcommand = CAPI_REQ;
                cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
@@ -3091,9 +3104,12 @@ isdn_tty_show_profile(int ridx, modem_info * info)
 static void
 isdn_tty_get_msnstr(char *n, char **p)
 {
-       while ((*p[0] >= '0' && *p[0] <= '9') ||
+       int limit = ISDN_MSNLEN - 1;
+
+       while (((*p[0] >= '0' && *p[0] <= '9') ||
               /* Why a comma ??? */
-              (*p[0] == ','))
+              (*p[0] == ',')) &&
+               (limit--))
                *n++ = *p[0]++;
        *n = '\0';
 }
@@ -3105,16 +3121,18 @@ static void
 isdn_tty_getdial(char *p, char *q,int cnt)
 {
        int first = 1;
-       int limit=39;   /* MUST match the size in isdn_tty_parse to avoid
-                               buffer overflow */
+       int limit = ISDN_MSNLEN - 1;    /* MUST match the size of interface var to avoid
+                                       buffer overflow */
 
        while (strchr(" 0123456789,#.*WPTS-", *p) && *p && --cnt>0) {
                if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) ||
-                   (*p == '*') || (*p == '#'))
+                   (*p == '*') || (*p == '#')) {
                        *q++ = *p;
-               p++;
-               if(!--limit)
+                       limit--;
+               }
+               if(!limit)
                        break;
+               p++;
                first = 0;
        }
        *q = 0;
@@ -3258,6 +3276,8 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
                case 'F':
                        /* &F -Set Factory-Defaults */
                        p[0]++;
+                       if (info->msr & UART_MSR_DCD)
+                               PARSE_ERROR1;
                        isdn_tty_reset_profile(m);
                        isdn_tty_modem_reset_regs(info, 1);
                        break;
@@ -3909,6 +3929,12 @@ isdn_tty_parse_at(modem_info * info)
                                break;
                        case 'D':
                                /* D - Dial */
+                               if (info->msr & UART_MSR_DCD)
+                                       PARSE_ERROR;
+                               if (info->msr & UART_MSR_RI) {
+                                       isdn_tty_modem_result(3, info);
+                                       return;
+                               }
                                isdn_tty_getdial(++p, ds, sizeof ds);
                                p += strlen(p);
                                if (!strlen(m->msn))
@@ -4103,7 +4129,7 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
                        c = *p;
                total++;
                if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
-                       /* Separator (CR oder LF) */
+                       /* Separator (CR or LF) */
                        m->mdmcmd[m->mdmcmdl] = 0;
                        if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
                                eb[0] = c;
@@ -4116,7 +4142,7 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
                        continue;
                }
                if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
-                       /* Backspace-Funktion */
+                       /* Backspace-Function */
                        if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
                                if (m->mdmcmdl)
                                        m->mdmcmdl--;
@@ -4134,18 +4160,24 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
                        if (m->mdmcmdl < 255) {
                                c = my_toupper(c);
                                switch (m->mdmcmdl) {
-                                       case 0:
-                                               if (c == 'A')
-                                                       m->mdmcmd[m->mdmcmdl] = c;
-                                               break;
                                        case 1:
-                                               if (c == 'T')
+                                               if (c == 'T') {
+                                                       m->mdmcmd[m->mdmcmdl] = c;
+                                                       m->mdmcmd[++m->mdmcmdl] = 0;
+                                                       break;
+                                               } else
+                                                       m->mdmcmdl = 0;
+                                               /* Fall through, check for 'A' */
+                                       case 0:
+                                               if (c == 'A') {
                                                        m->mdmcmd[m->mdmcmdl] = c;
+                                                       m->mdmcmd[++m->mdmcmdl] = 0;
+                                               }
                                                break;
                                        default:
                                                m->mdmcmd[m->mdmcmdl] = c;
+                                               m->mdmcmd[++m->mdmcmdl] = 0;
                                }
-                               m->mdmcmd[++m->mdmcmdl] = 0;
                        }
                }
        }
index bf09073efe6ff7e3a7336cfe60cb5ce5c2ff2534..a3ac19caf09bd2918e09465a2d96186db2bd1396 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.c,v 1.2 1998/02/22 19:44:25 fritz Exp $
+/* $Id: isdn_v110.c,v 1.3 1999/10/30 09:49:28 keil Exp $
 
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_v110.c,v $
+ * Revision 1.3  1999/10/30 09:49:28  keil
+ * Reinit of v110 structs
+ *
  * Revision 1.2  1998/02/22 19:44:25  fritz
  * Bugfixes and improvements regarding V.110, V.110 now running.
  *
@@ -36,7 +39,7 @@
 
 #undef ISDN_V110_DEBUG
 
-char *isdn_v110_revision = "$Revision: 1.2 $";
+char *isdn_v110_revision = "$Revision: 1.3 $";
 
 #define V110_38400 255
 #define V110_19200  15
@@ -148,7 +151,7 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
 }
 
 /* isdn_v110_close frees private V.110 data structures */
-static void
+void
 isdn_v110_close(isdn_v110_stream * v)
 {
        if (v == NULL)
index 9ab5a93f36181518866927c9f9cf85ee19fd59ac..4bb6948498430d2f151fbac55c5d34af196770fa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.h,v 1.1 1998/02/20 17:32:11 fritz Exp $
+/* $Id: isdn_v110.h,v 1.2 1999/10/30 09:49:28 keil Exp $
 
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_v110.h,v $
+ * Revision 1.2  1999/10/30 09:49:28  keil
+ * Reinit of v110 structs
+ *
  * Revision 1.1  1998/02/20 17:32:11  fritz
  * First checkin (not yet completely functionable).
  *
@@ -41,5 +44,6 @@ extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
 extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
 
 extern int isdn_v110_stat_callback(int, isdn_ctrl *);
+extern void isdn_v110_close(isdn_v110_stream * v);
 
 #endif
index 2af614b2ee71d2338869c6db823472a1386ed883..f52b59d0397da7d0c7d9e4210c3b0b587dcd626d 100644 (file)
@@ -87,9 +87,11 @@ int pcbit_init_dev(int board, int mem_base, int irq)
        dev_pcbit[board] = dev;
        memset(dev, 0, sizeof(struct pcbit_dev));
 
-       if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF )
+       if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) {
+               dev->ph_mem = mem_base;
                dev->sh_mem = (unsigned char*) mem_base;
-       else
+       }
+       else 
        {
                printk("memory address invalid");
                kfree(dev);
index 20051bf3ec13552035708aceb850e5799ed51e7b..92a561d29981c0e58e10f1916eecabd03c387d7a 100644 (file)
@@ -46,6 +46,7 @@ struct pcbit_dev {
        /* board */
 
        volatile unsigned char* sh_mem;         /* RDP address  */
+       unsigned long ph_mem;
        unsigned int irq;
        unsigned int id;
        unsigned int interrupt;                 /* set during interrupt 
@@ -166,10 +167,3 @@ struct pcbit_ioctl {
 #define L2_ERROR    6
 
 #endif
-
-
-
-
-
-
-
index 49d24dd148d1a49961b9f72888414d062d0a2e14..d00563a020b577e2061b7c7483d22ee8bbeee6fa 100644 (file)
@@ -94,7 +94,6 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
-      tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900
       tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
   fi
   bool 'Other ISA cards' CONFIG_NET_ISA
@@ -144,6 +143,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
     tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
     tristate 'TI ThunderLAN support' CONFIG_TLAN
     tristate 'VIA Rhine support' CONFIG_VIA_RHINE
+    tristate 'SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
       tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
index 659824e92e3e04d8158218b7749b88d3eb3c584a..6538d646779fac9187cb45a0845ec3f70fc38482 100644 (file)
@@ -222,11 +222,11 @@ static inline int myri_load_lanai(struct myri_eth *mp)
        }
 
        if(i == 5000)
-               printk("myricom: Chip would not reset after firmware load.\n");
+               printk(KERN_ERR "myricom: Chip would not reset after firmware load.\n");
 
        i = myri_do_handshake(mp);
        if(i)
-               printk("myricom: Handshake with LANAI failed.\n");
+               printk(KERN_ERR "myricom: Handshake with LANAI failed.\n");
 
        if(mp->eeprom.cpuvers == CPUVERS_4_0)
                mp->lregs->vers = 0;
@@ -575,7 +575,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct device *dev)
                        return 1;
                } else {
                        DTX(("resetting, return 0\n"));
-                       printk("%s: transmit timed out, resetting\n", dev->name);
+                       printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
                        mp->enet_stats.tx_errors++;
                        myri_init(mp, in_interrupt());
                        dev->tbusy = 0;
index 897cafd4c972cf3b96da5d3578ce58b46bbfa42d..117652d965d4f7681b5b93b1f18bfe9c1fb95e2a 100644 (file)
@@ -557,6 +557,13 @@ static int shaper_ioctl(struct device *dev,  struct ifreq *ifr, int cmd)
 {
        struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_data;
        struct shaper *sh=dev->priv;
+       
+       if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED)
+       {
+               if(!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+       }
+       
        switch(ss->ss_cmd)
        {
                case SHAPER_SET_DEV:
index 772f50649eb8581f3f4ceffb927c01c44d41eb91..fafab0364330bbe980438433fa526872a5d2352b 100644 (file)
@@ -85,7 +85,7 @@ static inline int qec_global_reset(struct qe_globreg *gregs)
        }
        if(tries)
                return 0;
-       printk("BigMAC: Cannot reset the QEC.\n");
+       printk(KERN_ERR "BigMAC: Cannot reset the QEC.\n");
        return -1;
 }
 
@@ -133,8 +133,8 @@ static inline void bigmac_tx_reset(struct BIG_MAC_regs *bregs)
                udelay(20);
 
        if(!tries) {
-               printk("BIGMAC: Transmitter will not reset.\n");
-               printk("BIGMAC: tx_cfg is %08x\n", bregs->tx_cfg);
+               printk(KERN_ERR "BIGMAC: Transmitter will not reset.\n");
+               printk(KERN_ERR "BIGMAC: tx_cfg is %08x\n", bregs->tx_cfg);
        }
 }
 
@@ -147,8 +147,8 @@ static inline void bigmac_rx_reset(struct BIG_MAC_regs *bregs)
                udelay(20);
 
        if(!tries) {
-               printk("BIGMAC: Receiver will not reset.\n");
-               printk("BIGMAC: rx_cfg is %08x\n", bregs->rx_cfg);
+               printk(KERN_ERR "BIGMAC: Receiver will not reset.\n");
+               printk(KERN_ERR "BIGMAC: rx_cfg is %08x\n", bregs->rx_cfg);
        }
 }
 
@@ -292,7 +292,7 @@ static void write_tcvr_bit(struct bigmac *bp, struct bmac_tcvr *tregs, int bit)
                                         MGMT_PAL_DCLOCK);
                garbage = tregs->mgmt_pal;
        } else {
-               printk("write_tcvr_bit: No transceiver type known!\n");
+               printk(KERN_ERR "write_tcvr_bit: No transceiver type known!\n");
        }
 }
 
@@ -314,7 +314,7 @@ static int read_tcvr_bit(struct bigmac *bp, struct bmac_tcvr *tregs)
                garbage = tregs->mgmt_pal;
                retval = (tregs->mgmt_pal & MGMT_PAL_EXT_MDIO) >> 2;
        } else {
-               printk("read_tcvr_bit: No transceiver type known!\n");
+               printk(KERN_ERR "read_tcvr_bit: No transceiver type known!\n");
        }
        return retval;
 }
@@ -337,7 +337,7 @@ static int read_tcvr_bit2(struct bigmac *bp, struct bmac_tcvr *tregs)
                tregs->mgmt_pal = (MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK);
                garbage = tregs->mgmt_pal;
        } else {
-               printk("read_tcvr_bit2: No transceiver type known!\n");
+               printk(KERN_ERR "read_tcvr_bit2: No transceiver type known!\n");
        }
        return retval;
 }
@@ -367,7 +367,7 @@ static void bigmac_tcvr_write(struct bigmac *bp, struct bmac_tcvr *tregs,
                break;
 
        default:
-               printk("bigmac_tcvr_read: Whoops, no known transceiver type.\n");
+               printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n");
                return;
        };
 
@@ -406,7 +406,7 @@ static unsigned short bigmac_tcvr_read(struct bigmac *bp,
                break;
 
        default:
-               printk("bigmac_tcvr_read: Whoops, no known transceiver type.\n");
+               printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n");
                return 0xffff;
        };
 
@@ -493,9 +493,9 @@ static void bigmac_tcvr_init(struct bigmac *bp)
                                    TCVR_PAL_LTENABLE);
                garbage = tregs->tcvr_pal;
        } else {
-               printk("BIGMAC: AIEEE, neither internal nor "
+               printk(KERN_ERR "BIGMAC: AIEEE, neither internal nor "
                       "external MDIO available!\n");
-               printk("BIGMAC: mgmt_pal[%08x] tcvr_pal[%08x]\n",
+               printk(KERN_ERR "BIGMAC: mgmt_pal[%08x] tcvr_pal[%08x]\n",
                       tregs->mgmt_pal, tregs->tcvr_pal);
        }
 }
@@ -521,7 +521,7 @@ static int try_next_permutation(struct bigmac *bp, struct bmac_tcvr *tregs)
                        udelay(20);
                }
                if(timeout == 0)
-                       printk("%s: PHY reset failed.\n", bp->dev->name);
+                       printk(KERN_ERR "%s: PHY reset failed.\n", bp->dev->name);
 
                bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
 
@@ -546,7 +546,7 @@ static void bigmac_timer(unsigned long data)
                bp->sw_bmsr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMSR);
                bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
                if(bp->sw_bmsr & BMSR_LSTATUS) {
-                       printk("%s: Link is now up at %s.\n",
+                       printk(KERN_INFO "%s: Link is now up at %s.\n",
                               bp->dev->name,
                               (bp->sw_bmcr & BMCR_SPEED100) ?
                               "100baseT" : "10baseT");
@@ -558,11 +558,11 @@ static void bigmac_timer(unsigned long data)
 
                                ret = try_next_permutation(bp, tregs);
                                if(ret == -1) {
-                                       printk("%s: Link down, cable problem?\n",
+                                       printk(KERN_ERR "%s: Link down, cable problem?\n",
                                               bp->dev->name);
                                        ret = bigmac_init(bp, 0);
                                        if(ret) {
-                                               printk("%s: Error, cannot re-init the "
+                                               printk(KERN_ERR "%s: Error, cannot re-init the "
                                                       "BigMAC.\n", bp->dev->name);
                                        }
                                        return;
@@ -575,7 +575,7 @@ static void bigmac_timer(unsigned long data)
                }
        } else {
                /* Can't happens.... */
-               printk("%s: Aieee, link timer is asleep but we got one anyways!\n",
+               printk(KERN_ERR "%s: Aieee, link timer is asleep but we got one anyways!\n",
                       bp->dev->name);
                restart_timer = 0;
                bp->timer_ticks = 0;
@@ -614,7 +614,7 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
                udelay(20);
        }
        if(timeout == 0)
-               printk("%s: PHY reset failed.\n", bp->dev->name);
+               printk(KERN_ERR "%s: PHY reset failed.\n", bp->dev->name);
 
        bp->sw_bmcr = bigmac_tcvr_read(bp, tregs, BIGMAC_BMCR);
 
@@ -724,7 +724,7 @@ static void bigmac_is_medium_rare(struct bigmac *bp,
                                  unsigned int qec_status,
                                  unsigned int bmac_status)
 {
-       printk("bigmac_is_medium_rare: ");
+       printk(KERN_ERR "bigmac_is_medium_rare: ");
        if(qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) {
                if(qec_status & GLOB_STAT_ER)
                        printk("QEC_ERROR, ");
@@ -838,7 +838,7 @@ static inline void bigmac_rx(struct bigmac *bp)
 #ifdef NEED_DMA_SYNCHRONIZATION
 #ifdef __sparc_v9__
                if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) {
-                       printk("sunbmac: Bogus DMA buffer address "
+                       printk(KERN_CRIT "sunbmac: Bogus DMA buffer address "
                               "[%016lx]\n", ((unsigned long) skb->data));
                        panic("DMA address too large, tell DaveM");
                }
@@ -895,7 +895,7 @@ static inline void bigmac_rx(struct bigmac *bp)
        }
        bp->rx_new = elem;
        if(drops)
-               printk("%s: Memory squeeze, deferring packet.\n", bp->dev->name);
+               printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name);
 }
 
 #ifndef __sparc_v9__
@@ -948,7 +948,7 @@ static inline void sun4c_bigmac_rx(struct bigmac *bp)
        }
        bp->rx_new = elem;
        if(drops)
-               printk("%s: Memory squeeze, deferring packet.\n", bp->dev->name);
+               printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name);
 }
 #endif
 
@@ -1024,14 +1024,14 @@ static int bigmac_open(struct device *dev)
        if(sparc_cpu_model == sun4c) {
                if(request_irq(dev->irq, &sun4c_bigmac_interrupt,
                               SA_SHIRQ, "BIG MAC", (void *) bp)) {
-                       printk("BIGMAC: Can't order irq %d to go.\n", dev->irq);
+                       printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq);
                        return -EAGAIN;
                }
        } else
 #endif
        if(request_irq(dev->irq, &bigmac_interrupt,
                       SA_SHIRQ, "BIG MAC", (void *) bp)) {
-               printk("BIGMAC: Can't order irq %d to go.\n", dev->irq);
+               printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq);
                return -EAGAIN;
        }
        init_timer(&bp->bigmac_timer);
@@ -1069,7 +1069,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct device *dev)
                if (tickssofar < 40) {
                        return 1;
                } else {
-                       printk ("%s: transmit timed out, resetting\n", dev->name);
+                       printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
                        bp->enet_stats.tx_errors++;
                        bigmac_init(bp, 0);
                        dev->tbusy = 0;
@@ -1080,7 +1080,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct device *dev)
        }
 
        if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-               printk("%s: Transmitter access conflict.\n", dev->name);
+               printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
                return 1;
        }
 
@@ -1138,7 +1138,7 @@ static int sun4c_bigmac_start_xmit(struct sk_buff *skb, struct device *dev)
                if (tickssofar < 40) {
                        return 1;
                } else {
-                       printk ("%s: transmit timed out, resetting\n", dev->name);
+                       printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
                        bp->enet_stats.tx_errors++;
                        bigmac_init(bp, 0);
                        dev->tbusy = 0;
@@ -1148,7 +1148,7 @@ static int sun4c_bigmac_start_xmit(struct sk_buff *skb, struct device *dev)
        }
 
        if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-               printk("%s: Transmitter access conflict.\n", dev->name);
+               printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
                return 1;
        }
 
@@ -1266,10 +1266,10 @@ __initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_de
        dev = init_etherdev(0, sizeof(struct bigmac));
 
        if(version_printed++ == 0)
-               printk(version);
+               printk(KERN_INFO "%s", version);
 
        /* Report what we have found to the user. */
-       printk("%s: BigMAC 100baseT Ethernet ", dev->name);
+       printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
        dev->base_addr = (long) qec_sdev;
        for(i = 0; i < 6; i++)
                printk("%2.2x%c", dev->dev_addr[i] = idprom->id_ethaddr[i],
@@ -1287,10 +1287,10 @@ __initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_de
        /* Verify the registers we expect, are actually there. */
        if((bp->bigmac_sbus_dev->num_registers != 3) ||
           (bp->qec_sbus_dev->num_registers != 2)) {
-               printk("BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",
+               printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",
                       bp->qec_sbus_dev->num_registers,
                       bp->bigmac_sbus_dev->num_registers);
-               printk("BIGMAC: Would you like that for here or to go?\n");
+               printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n");
                goto fail_and_cleanup;
        }
 
@@ -1309,7 +1309,7 @@ __initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_de
                                   qranges[k].ot_child_space)
                                        break;
                        if(k >= num_qranges) {
-                               printk("BigMAC: Aieee, bogus QEC range for space %08x\n",
+                               printk(KERN_ERR "BigMAC: Aieee, bogus QEC range for space %08x\n",
                                       bp->bigmac_sbus_dev->reg_addrs[j].which_io);
                                goto fail_and_cleanup;
                        }
@@ -1338,13 +1338,13 @@ __initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_de
                                   bp->qec_sbus_dev->reg_addrs[0].which_io,
                                   0);
        if(!bp->gregs) {
-               printk("BIGMAC: Cannot map QEC global registers.\n");
+               printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n");
                goto fail_and_cleanup;
        }
 
        /* Make sure QEC is in BigMAC mode. */
        if((bp->gregs->ctrl & 0xf0000000) != GLOB_CTRL_BMODE) {
-               printk("BigMAC: AIEEE, QEC is not in BigMAC mode!\n");
+               printk(KERN_ERR "BigMAC: AIEEE, QEC is not in BigMAC mode!\n");
                goto fail_and_cleanup;
        }
 
@@ -1380,7 +1380,7 @@ __initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_de
                                  bp->bigmac_sbus_dev->reg_addrs[0].which_io,
                                  0);
        if(!bp->creg) {
-               printk("BIGMAC: Cannot map QEC channel registers.\n");
+               printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n");
                goto fail_and_cleanup;
        }
 
@@ -1392,7 +1392,7 @@ __initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_de
                                   bp->bigmac_sbus_dev->reg_addrs[1].which_io,
                                   0);
        if(!bp->bregs) {
-               printk("BIGMAC: Cannot map BigMAC primary registers.\n");
+               printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n");
                goto fail_and_cleanup;
        }
 
@@ -1406,7 +1406,7 @@ __initfunc(static int bigmac_ether_init(struct device *dev, struct linux_sbus_de
                                   bp->bigmac_sbus_dev->reg_addrs[2].which_io,
                                   0);
        if(!bp->tregs) {
-               printk("BIGMAC: Cannot map BigMAC transceiver registers.\n");
+               printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n");
                goto fail_and_cleanup;
        }
 
index da00091f94c375ed2d7ed3651e3440c77a4d89ff..3150b2b325373e509d2abafdb51dd4759dedca11 100644 (file)
@@ -297,7 +297,7 @@ static inline int happy_meal_tcvr_read(struct happy_meal *hp,
        while(!(hme_read32(hp, &tregs->frame) & 0x10000) && --tries)
                udelay(20);
        if(!tries) {
-               printk("happy meal: Aieee, transceiver MIF read bolixed\n");
+               printk(KERN_ERR "happy meal: Aieee, transceiver MIF read bolixed\n");
                return TCVR_FAILURE;
        }
        retval = hme_read32(hp, &tregs->frame) & 0xffff;
@@ -328,7 +328,7 @@ static inline void happy_meal_tcvr_write(struct happy_meal *hp,
 
        /* Anything else? */
        if(!tries)
-               printk("happy meal: Aieee, transceiver MIF write bolixed\n");
+               printk(KERN_ERR "happy meal: Aieee, transceiver MIF write bolixed\n");
 
        /* Fifty-two cents is your change, have a nice day. */
 }
@@ -391,7 +391,7 @@ static int try_next_permutation(struct happy_meal *hp, struct hmeal_tcvregs *tre
 
 static void display_link_mode(struct happy_meal *hp, struct hmeal_tcvregs *tregs)
 {
-       printk("%s: Link is up using ", hp->dev->name);
+       printk(KERN_INFO "%s: Link is up using ", hp->dev->name);
        if(hp->tcvr_type == external)
                printk("external ");
        else
@@ -413,7 +413,7 @@ static void display_link_mode(struct happy_meal *hp, struct hmeal_tcvregs *tregs
 
 static void display_forced_link_mode(struct happy_meal *hp, struct hmeal_tcvregs *tregs)
 {
-       printk("%s: Link has been forced up using ", hp->dev->name);
+       printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name);
        if(hp->tcvr_type == external)
                printk("external ");
        else
@@ -492,6 +492,25 @@ no_response:
 
 static int happy_meal_init(struct happy_meal *hp, int from_irq);
 
+static int is_lucent_phy(struct happy_meal *hp)
+{
+       struct hmeal_tcvregs *tregs = hp->tcvregs;
+       unsigned short mr2, mr3;
+       int ret = 0;
+
+       mr2 = happy_meal_tcvr_read(hp, tregs, 2);
+       mr3 = happy_meal_tcvr_read(hp, tregs, 3);
+       if ((mr2 & 0xffff) == 0x0180 &&
+           ((mr3 & 0xffff) >> 10) == 0x1d) {
+#if 0
+               printk("HMEDEBUG: Lucent PHY detected.\n");
+#endif
+               ret = 1;
+       }
+
+       return ret;
+}
+
 static void happy_meal_timer(unsigned long data)
 {
        struct happy_meal *hp = (struct happy_meal *) data;
@@ -508,19 +527,22 @@ static void happy_meal_timer(unsigned long data)
                        /* Enter force mode. */
        do_force_mode:
                        hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
-                       printk("%s: Auto-Negotiation unsuccessful, trying force link mode\n",
+                       printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful, trying force link mode\n",
                               hp->dev->name);
                        hp->sw_bmcr = BMCR_SPEED100;
                        happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
 
-                       /* OK, seems we need do disable the transceiver for the first
-                        * tick to make sure we get an accurate link state at the
-                        * second tick.
-                        */
-                       hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
-                       hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
-                       happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);
-
+                       if (!is_lucent_phy(hp)) {
+                               /* OK, seems we need do disable the transceiver for
+                                * the first tick to make sure we get an accurate
+                                * link state at the second tick.
+                                */
+                               hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
+                                                                      DP83840_CSCONFIG);
+                               hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+                               happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
+                                                     hp->sw_csconfig);
+                       }
                        hp->timer_state = ltrywait;
                        hp->timer_ticks = 0;
                        restart_timer = 1;
@@ -567,7 +589,7 @@ static void happy_meal_timer(unsigned long data)
                        restart_timer = 0;
                } else {
                        if(hp->timer_ticks >= 10) {
-                               printk("%s: Auto negotiation successful, link still "
+                               printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
                                       "not completely up.\n", hp->dev->name);
                                hp->timer_ticks = 0;
                                restart_timer = 1;
@@ -587,15 +609,24 @@ static void happy_meal_timer(unsigned long data)
                hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
                if(hp->timer_ticks == 1) {
                        /* Re-enable transceiver, we'll re-enable the transceiver next
-                        * tick, then check link state on the following tick. */
-                       hp->sw_csconfig |= CSCONFIG_TCVDISAB;
-                       happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);
+                        * tick, then check link state on the following tick.
+                        * XXX But dont do this on Lucent PHY -DaveM
+                        */
+                       if (!is_lucent_phy(hp)) {
+                               hp->sw_csconfig |= CSCONFIG_TCVDISAB;
+                               happy_meal_tcvr_write(hp, tregs,
+                                                     DP83840_CSCONFIG, hp->sw_csconfig);
+                       }
                        restart_timer = 1;
                        break;
                }
                if(hp->timer_ticks == 2) {
-                       hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
-                       happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);
+                       /* XXX See above about Lucent PHY -DaveM */
+                       if (!is_lucent_phy(hp)) {
+                               hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+                               happy_meal_tcvr_write(hp, tregs,
+                                                     DP83840_CSCONFIG, hp->sw_csconfig);
+                       }
                        restart_timer = 1;
                        break;
                }
@@ -616,20 +647,25 @@ static void happy_meal_timer(unsigned long data)
                                         */
 
                                        /* Let the user know... */
-                                       printk("%s: Link down, cable problem?\n",
+                                       printk(KERN_NOTICE "%s: Link down, cable problem?\n",
                                               hp->dev->name);
 
                                        ret = happy_meal_init(hp, 0);
                                        if(ret) {
                                                /* ho hum... */
-                                               printk("%s: Error, cannot re-init the "
+                                               printk(KERN_ERR "%s: Error, cannot re-init the "
                                                       "Happy Meal.\n", hp->dev->name);
                                        }
                                        return;
                                }
-                               hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
-                               hp->sw_csconfig |= CSCONFIG_TCVDISAB;
-                               happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);
+                               hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
+                                                                      DP83840_CSCONFIG);
+                               if (!is_lucent_phy(hp)) {
+                                       hp->sw_csconfig |= CSCONFIG_TCVDISAB;
+                                       happy_meal_tcvr_write(hp, tregs,
+                                                             DP83840_CSCONFIG,
+                                                             hp->sw_csconfig);
+                               }
                                hp->timer_ticks = 0;
                                restart_timer = 1;
                        } else {
@@ -641,7 +677,7 @@ static void happy_meal_timer(unsigned long data)
        case asleep:
        default:
                /* Can't happens.... */
-               printk("%s: Aieee, link timer is asleep but we got one anyways!\n",
+               printk(KERN_ERR "%s: Aieee, link timer is asleep but we got one anyways!\n",
                       hp->dev->name);
                restart_timer = 0;
                hp->timer_ticks = 0;
@@ -672,7 +708,7 @@ static inline void happy_meal_tx_reset(struct happy_meal *hp,
 
        /* Lettuce, tomato, buggy hardware (no extra charge)? */
        if(!tries)
-               printk("happy meal: Transceiver BigMac ATTACK!");
+               printk(KERN_ERR "happy meal: Transceiver BigMac ATTACK!");
 
        /* Take care. */
        HMD(("done\n"));
@@ -692,7 +728,7 @@ static inline void happy_meal_rx_reset(struct happy_meal *hp,
 
        /* Will that be all? */
        if(!tries)
-               printk("happy meal: Receiver BigMac ATTACK!");
+               printk(KERN_ERR "happy meal: Receiver BigMac ATTACK!");
 
        /* Don't forget your vik_1137125_wa.  Have a nice day. */
        HMD(("done\n"));
@@ -714,7 +750,7 @@ static inline void happy_meal_stop(struct happy_meal *hp,
 
        /* Come back next week when we are "Sun Microelectronics". */
        if(!tries)
-               printk("happy meal: Fry guys.");
+               printk(KERN_ERR "happy meal: Fry guys.");
 
        /* Remember: "Different name, same old buggy as shit hardware." */
        HMD(("done\n"));
@@ -910,8 +946,11 @@ static int happy_meal_tcvr_reset(struct happy_meal *hp,
                return -1;
        }
        ASD((" SUCCESS and CSCONFIG_DFBYPASS\n"));
-       result = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
-       happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, (result | CSCONFIG_DFBYPASS));
+       if (!is_lucent_phy(hp)) {
+               result = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
+               happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
+                                     (result | CSCONFIG_DFBYPASS));
+       }
        return 0;
 }
 
@@ -972,7 +1011,7 @@ static void happy_meal_transceiver_check(struct happy_meal *hp,
                                hp->tcvr_type = internal;
                                ASD(("<internal>\n"));
                        } else {
-                               printk("happy meal: Transceiver and a coke please.");
+                               printk(KERN_ERR "happy meal: Transceiver and a coke please.");
                                hp->tcvr_type = none; /* Grrr... */
                                ASD(("<none>\n"));
                        }
@@ -1201,9 +1240,9 @@ static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
                        udelay(10);
                }
                if(!timeout) {
-                       printk("%s: Happy Meal would not start auto negotiation "
+                       printk(KERN_ERR "%s: Happy Meal would not start auto negotiation "
                               "BMCR=0x%04x\n", hp->dev->name, hp->sw_bmcr);
-                       printk("%s: Performing force link detection.\n",
+                       printk(KERN_NOTICE "%s: Performing force link detection.\n",
                               hp->dev->name);
                        goto force_link;
                } else {
@@ -1230,17 +1269,17 @@ force_link:
                                hp->sw_bmcr |= BMCR_FULLDPLX;
                }
                happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
-
-               /* OK, seems we need do disable the transceiver for the first
-                * tick to make sure we get an accurate link state at the
-                * second tick.
-                */
-               hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
-                                                      DP83840_CSCONFIG);
-               hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
-               happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
-                                     hp->sw_csconfig);
-
+               if (!is_lucent_phy(hp)) {
+                       /* OK, seems we need do disable the transceiver for the first
+                        * tick to make sure we get an accurate link state at the
+                        * second tick.
+                        */
+                       hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
+                                                              DP83840_CSCONFIG);
+                       hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
+                       happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
+                                             hp->sw_csconfig);
+               }
                hp->timer_state = ltrywait;
        }
 
@@ -1479,8 +1518,8 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
        regtmp = hme_read32(hp, &erxregs->cfg);
        hme_write32(hp, &erxregs->cfg, ERX_CFG_DEFAULT(RX_OFFSET));
        if(hme_read32(hp, &erxregs->cfg) != ERX_CFG_DEFAULT(RX_OFFSET)) {
-               printk("happy meal: Eieee, rx config register gets greasy fries.\n");
-               printk("happy meal: Trying to set %08x, reread gives %08lx\n",
+               printk(KERN_ERR "happy meal: Eieee, rx config register gets greasy fries.\n");
+               printk(KERN_ERR "happy meal: Trying to set %08x, reread gives %08lx\n",
                       ERX_CFG_DEFAULT(RX_OFFSET), regtmp);
                /* XXX Should return failure here... */
        }
@@ -1605,24 +1644,24 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp,
                     GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR |
                     GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR |
                     GREG_STAT_SLVPERR))
-               printk("%s: Error interrupt for happy meal, status = %08lx\n",
+               printk(KERN_ERR "%s: Error interrupt for happy meal, status = %08lx\n",
                       hp->dev->name, status);
 
        if(status & GREG_STAT_RFIFOVF) {
                /* The receive FIFO overflowwed, usually a DMA error. */
-               printk("%s: Happy Meal receive FIFO overflow.\n", hp->dev->name);
+               printk(KERN_ERR "%s: Happy Meal receive FIFO overflow.\n", hp->dev->name);
                reset = 1;
        }
 
        if(status & GREG_STAT_STSTERR) {
                /* BigMAC SQE link test failed. */
-               printk("%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name);
+               printk(KERN_ERR "%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name);
                reset = 1;
        }
 
        if(status & GREG_STAT_TFIFO_UND) {
                /* Transmit FIFO underrun, again DMA error likely. */
-               printk("%s: Happy Meal transmitter FIFO underrun, DMA error.\n",
+               printk(KERN_ERR "%s: Happy Meal transmitter FIFO underrun, DMA error.\n",
                       hp->dev->name);
                reset = 1;
        }
@@ -1631,7 +1670,7 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp,
                /* Driver error, tried to transmit something larger
                 * than ethernet max mtu.
                 */
-               printk("%s: Happy Meal MAX Packet size error.\n", hp->dev->name);
+               printk(KERN_ERR "%s: Happy Meal MAX Packet size error.\n", hp->dev->name);
                reset = 1;
        }
 
@@ -1648,7 +1687,7 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp,
 
        if(status & (GREG_STAT_RXERR|GREG_STAT_RXPERR|GREG_STAT_RXTERR)) {
                /* All sorts of DMA receive errors. */
-               printk("%s: Happy Meal rx DMA errors [ ", hp->dev->name);
+               printk(KERN_ERR "%s: Happy Meal rx DMA errors [ ", hp->dev->name);
                if(status & GREG_STAT_RXERR)
                        printk("GenericError ");
                if(status & GREG_STAT_RXPERR)
@@ -1663,20 +1702,20 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp,
                /* Driver bug, didn't set EOP bit in tx descriptor given
                 * to the happy meal.
                 */
-               printk("%s: EOP not set in happy meal transmit descriptor!\n",
+               printk(KERN_ERR "%s: EOP not set in happy meal transmit descriptor!\n",
                       hp->dev->name);
                reset = 1;
        }
 
        if(status & GREG_STAT_MIFIRQ) {
                /* MIF signalled an interrupt, were we polling it? */
-               printk("%s: Happy Meal MIF interrupt.\n", hp->dev->name);
+               printk(KERN_ERR "%s: Happy Meal MIF interrupt.\n", hp->dev->name);
        }
 
        if(status &
           (GREG_STAT_TXEACK|GREG_STAT_TXLERR|GREG_STAT_TXPERR|GREG_STAT_TXTERR)) {
                /* All sorts of transmit DMA errors. */
-               printk("%s: Happy Meal tx DMA errors [ ", hp->dev->name);
+               printk(KERN_ERR "%s: Happy Meal tx DMA errors [ ", hp->dev->name);
                if(status & GREG_STAT_TXEACK)
                        printk("GenericError ");
                if(status & GREG_STAT_TXLERR)
@@ -1693,14 +1732,14 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp,
                /* Bus or parity error when cpu accessed happy meal registers
                 * or it's internal FIFO's.  Should never see this.
                 */
-               printk("%s: Happy Meal register access SBUS slave (%s) error.\n",
+               printk(KERN_ERR "%s: Happy Meal register access SBUS slave (%s) error.\n",
                       hp->dev->name,
                       (status & GREG_STAT_SLVPERR) ? "parity" : "generic");
                reset = 1;
        }
 
        if(reset) {
-               printk("%s: Resetting...\n", hp->dev->name);
+               printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name);
                happy_meal_init(hp, 1);
                return 1;
        }
@@ -1711,22 +1750,22 @@ static inline void happy_meal_mif_interrupt(struct happy_meal *hp,
                                            struct hmeal_gregs *gregs,
                                            struct hmeal_tcvregs *tregs)
 {
-       printk("%s: Link status change.\n", hp->dev->name);
+       printk(KERN_INFO "%s: Link status change.\n", hp->dev->name);
        hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
        hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);
 
        /* Use the fastest transmission protocol possible. */
        if(hp->sw_lpa & LPA_100FULL) {
-               printk("%s: Switching to 100Mbps at full duplex.", hp->dev->name);
+               printk(KERN_INFO "%s: Switching to 100Mbps at full duplex.", hp->dev->name);
                hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_SPEED100);
        } else if(hp->sw_lpa & LPA_100HALF) {
-               printk("%s: Switching to 100MBps at half duplex.", hp->dev->name);
+               printk(KERN_INFO "%s: Switching to 100MBps at half duplex.", hp->dev->name);
                hp->sw_bmcr |= BMCR_SPEED100;
        } else if(hp->sw_lpa & LPA_10FULL) {
-               printk("%s: Switching to 10MBps at full duplex.", hp->dev->name);
+               printk(KERN_INFO "%s: Switching to 10MBps at full duplex.", hp->dev->name);
                hp->sw_bmcr |= BMCR_FULLDPLX;
        } else {
-               printk("%s: Using 10Mbps at half duplex.", hp->dev->name);
+               printk(KERN_INFO "%s: Using 10Mbps at half duplex.", hp->dev->name);
        }
        happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
 
@@ -1942,7 +1981,7 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev,
        }
        hp->rx_new = elem;
        if(drops)
-               printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+               printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);
        RXD((">"));
 }
 
@@ -2061,7 +2100,7 @@ static inline void pci_happy_meal_rx(struct happy_meal *hp, struct device *dev,
        }
        hp->rx_new = elem;
        if(drops)
-               printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+               printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);
        RXD((">"));
 }
 #endif
@@ -2126,7 +2165,7 @@ static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev
        }
        hp->rx_new = elem;
        if(drops)
-               printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+               printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);
        RXD((">"));
 }
 
@@ -2235,7 +2274,7 @@ static inline void sun4d_happy_meal_rx(struct happy_meal *hp, struct device *dev
        }
        hp->rx_new = elem;
        if(drops)
-               printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+               printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name);
        RXD((">"));
 }
 #endif
@@ -2487,14 +2526,14 @@ static int happy_meal_open(struct device *dev)
                if(request_irq(dev->irq, &sun4c_happy_meal_interrupt,
                               SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
                        HMD(("EAGAIN\n"));
-                       printk("happy meal: Can't order irq %d to go.\n", dev->irq);
+                       printk(KERN_ERR "happy meal: Can't order irq %d to go.\n", dev->irq);
                        return -EAGAIN;
                }
        } else if (sparc_cpu_model == sun4d) {
                if(request_irq(dev->irq, &sun4d_happy_meal_interrupt,
                               SA_SHIRQ, "HAPPY MEAL", (void *) dev)) {
                        HMD(("EAGAIN\n"));
-                       printk("happy_meal(SBUS): Can't order irq %s to go.\n",
+                       printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
                               __irq_itoa(dev->irq));
                        return -EAGAIN;
                }
@@ -2505,7 +2544,7 @@ static int happy_meal_open(struct device *dev)
                if(request_irq(dev->irq, &pci_happy_meal_interrupt,
                               SA_SHIRQ, "HAPPY MEAL (PCI)", dev)) {
                HMD(("EAGAIN\n"));
-               printk("happy_meal(PCI: Can't order irq %s to go.\n",
+               printk(KERN_ERR "happy_meal(PCI: Can't order irq %s to go.\n",
                       __irq_itoa(dev->irq));
                        return -EAGAIN;
                }
@@ -2514,7 +2553,7 @@ static int happy_meal_open(struct device *dev)
        if(request_irq(dev->irq, &happy_meal_interrupt,
                       SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
                HMD(("EAGAIN\n"));
-               printk("happy_meal(SBUS): Can't order irq %s to go.\n",
+               printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
                       __irq_itoa(dev->irq));
                return -EAGAIN;
        }
@@ -2568,10 +2607,10 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
                int tickssofar = jiffies - dev->trans_start;
            
                if (tickssofar >= 40) {
-                       printk ("%s: transmit timed out, resetting\n", dev->name);
+                       printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
                        hp->net_stats.tx_errors++;
                        tx_dump_log();
-                       printk ("%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
+                       printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
                                hme_read32(hp, &hp->gregs->stat),
                                hme_read32(hp, &hp->etxregs->cfg),
                                hme_read32(hp, &hp->bigmacregs->tx_cfg));
@@ -2633,7 +2672,7 @@ static int pci_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
                if (tickssofar >= 40) {
                        unsigned long flags;
 
-                       printk ("%s: transmit timed out, resetting\n", dev->name);
+                       printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 
                        save_and_cli(flags);
                        tx_dump_log();
@@ -2690,7 +2729,7 @@ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
                if (tickssofar < 40) {
                        return 1;
                } else {
-                       printk ("%s: transmit timed out, resetting\n", dev->name);
+                       printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
                        hp->net_stats.tx_errors++;
                        happy_meal_init(hp, 0);
                        dev->tbusy = 0;
@@ -2700,7 +2739,7 @@ static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
        }
 
        if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-               printk("happy meal: Transmitter access conflict.\n");
+               printk(KERN_ERR "happy meal: Transmitter access conflict.\n");
                return 1;
        }
 
@@ -2742,10 +2781,10 @@ static int sun4d_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
                int tickssofar = jiffies - dev->trans_start;
            
                if (tickssofar >= 40) {
-                       printk ("%s: transmit timed out, resetting\n", dev->name);
+                       printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
                        hp->net_stats.tx_errors++;
                        tx_dump_log();
-                       printk ("%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
+                       printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
                                hme_read32(hp, &hp->gregs->stat),
                                hme_read32(hp, &hp->etxregs->cfg),
                                hme_read32(hp, &hp->bigmacregs->tx_cfg));
@@ -3085,7 +3124,7 @@ static void __init quattro_sbus_register_irqs(void)
                                  SA_SHIRQ, "Quattro",
                                  qp);
                if(err != 0) {
-                       printk("Quattro: Fatal IRQ registery error %d.\n", err);
+                       printk(KERN_ERR "Quattro: Fatal IRQ registery error %d.\n", err);
                        panic("QFE request irq");
                }
        }
@@ -3117,13 +3156,13 @@ static int __init happy_meal_ether_init(struct device *dev, struct linux_sbus_de
                        return -ENOMEM;
        }
        if(hme_version_printed++ == 0)
-               printk(version);
+               printk(KERN_INFO "%s", version);
 
        if(qfe_slot != -1)
-               printk("%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
+               printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
                       dev->name, qfe_slot);
        else
-               printk("%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
+               printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
                       dev->name);
 
        dev->base_addr = (long) sdev;
@@ -3148,9 +3187,9 @@ static int __init happy_meal_ether_init(struct device *dev, struct linux_sbus_de
 #endif
 
        if(sdev->num_registers != 5) {
-               printk("happymeal: Device does not have 5 regs, it has %d.\n",
+               printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
                       sdev->num_registers);
-               printk("happymeal: Would you like that for here or to go?\n");
+               printk(KERN_ERR "happymeal: Would you like that for here or to go?\n");
                return ENODEV;
        }
 
@@ -3168,7 +3207,7 @@ static int __init happy_meal_ether_init(struct device *dev, struct linux_sbus_de
                                   "Happy Meal Global Regs",
                                   sdev->reg_addrs[0].which_io, 0);
        if(!hp->gregs) {
-               printk("happymeal: Cannot map Happy Meal global registers.\n");
+               printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n");
                return ENODEV;
        }
 
@@ -3177,7 +3216,7 @@ static int __init happy_meal_ether_init(struct device *dev, struct linux_sbus_de
                                     "Happy Meal MAC TX Regs",
                                     sdev->reg_addrs[1].which_io, 0);
        if(!hp->etxregs) {
-               printk("happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
+               printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
                return ENODEV;
        }
 
@@ -3186,7 +3225,7 @@ static int __init happy_meal_ether_init(struct device *dev, struct linux_sbus_de
                                     "Happy Meal MAC RX Regs",
                                     sdev->reg_addrs[2].which_io, 0);
        if(!hp->erxregs) {
-               printk("happymeal: Cannot map Happy Meal MAC Receive registers.\n");
+               printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n");
                return ENODEV;
        }
 
@@ -3195,7 +3234,7 @@ static int __init happy_meal_ether_init(struct device *dev, struct linux_sbus_de
                                        "Happy Meal BIGMAC Regs",
                                        sdev->reg_addrs[3].which_io, 0);
        if(!hp->bigmacregs) {
-               printk("happymeal: Cannot map Happy Meal BIGMAC registers.\n");
+               printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n");
                return ENODEV;
        }
 
@@ -3204,7 +3243,7 @@ static int __init happy_meal_ether_init(struct device *dev, struct linux_sbus_de
                                     "Happy Meal Tranceiver Regs",
                                     sdev->reg_addrs[4].which_io, 0);
        if(!hp->tcvregs) {
-               printk("happymeal: Cannot map Happy Meal Tranceiver registers.\n");
+               printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n");
                return ENODEV;
        }
 
@@ -3299,7 +3338,7 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)
        /* Now make sure pci_dev cookie is there. */
        pcp = pdev->sysdata;
        if(pcp == NULL || pcp->prom_node == -1) {
-               printk("happymeal(PCI): Some PCI device info missing\n");
+               printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
                return ENODEV;
        }
        node = pcp->prom_node;
@@ -3323,7 +3362,7 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)
                        return -ENOMEM;
        }
        if(hme_version_printed++ == 0)
-               printk(version);
+               printk(KERN_INFO "%s", version);
 
        if (!qfe_slot) {
                prom_name[0] = 0;
@@ -3331,7 +3370,7 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)
                        int i = simple_strtoul(dev->name + 3, NULL, 10);
                        sprintf(prom_name, "-%d", i + 3);
                }
-               printk("%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
+               printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
                if (qp->quattro_pci_dev->vendor == PCI_VENDOR_ID_DEC &&
                    qp->quattro_pci_dev->device == PCI_DEVICE_ID_DEC_21153)
                        printk("DEC 21153 PCI Bridge\n");
@@ -3340,10 +3379,10 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)
                                qp->quattro_pci_dev->vendor, qp->quattro_pci_dev->device);
        }
        if(qfe_slot != -1)
-               printk("%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
+               printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
                       dev->name, qfe_slot);
        else
-               printk("%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
+               printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
                       dev->name);
 
        dev->base_addr = (long) pdev;
@@ -3362,7 +3401,7 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)
 
        hpreg_base = pdev->base_address[0];
        if((hpreg_base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
-               printk("happymeal(PCI): Cannot find proper PCI device base address.\n");
+               printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
                return ENODEV;
        }
        hpreg_base &= PCI_BASE_ADDRESS_MEM_MASK;
@@ -3404,7 +3443,7 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)
 
        hp->happy_block = (struct hmeal_init_block *) get_free_page(GFP_DMA);
        if(!hp->happy_block) {
-               printk("happymeal(PCI): Cannot get hme init block.\n");
+               printk(KERN_ERR "happymeal(PCI): Cannot get hme init block.\n");
                return ENODEV;
        }
 
@@ -3443,6 +3482,9 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)
         * PROM leaves it at zero.
         */
        {
+#if 1
+               unsigned char latency_timer = 64;
+#else
                unsigned char min_gnt, latency_timer;
 
                pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt);
@@ -3450,6 +3492,7 @@ static int __init happy_meal_pci_init(struct device *dev, struct pci_dev *pdev)
                        latency_timer = 64;
                else
                        latency_timer = ((min_gnt << 3) & 0xff);
+#endif
                pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer);
        }
 #ifdef __sparc_v9__
index 3485a2a84d8ab129b44cc998c67e54cb91a1e4c2..94907a15eae805660c466b0f24e6f5eb5163b387 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.85 1999/03/21 05:22:05 davem Exp $
+/* $Id: sunlance.c,v 1.85.2.1 1999/10/09 06:03:38 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *     Written 1995, 1996 by Miguel de Icaza
@@ -428,7 +428,7 @@ static int init_restart_lance (struct lance_private *lp)
        for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++)
                barrier();
        if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
-               printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
+               printk (KERN_ERR "LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
                if (lp->ledma)
                        printk ("dcsr=%8.8x\n",
                                (unsigned int) lp->ledma->regs->cond_reg);
@@ -489,7 +489,7 @@ static int lance_rx (struct device *dev)
                        skb = dev_alloc_skb (len+2);
 
                        if (skb == 0) {
-                               printk ("%s: Memory squeeze, deferring packet.\n",
+                               printk (KERN_INFO "%s: Memory squeeze, deferring packet.\n",
                                        dev->name);
                                lp->stats.rx_dropped++;
                                rd->mblength = 0;
@@ -547,7 +547,7 @@ static int lance_tx (struct device *dev)
                                lp->stats.tx_carrier_errors++;
                                if (lp->auto_select) {
                                        lp->tpe = 1 - lp->tpe;
-                                       printk("%s: Carrier Lost, trying %s\n",
+                                       printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n",
                                               dev->name, lp->tpe?"TPE":"AUI");
                                        /* Stop the lance */
                                        ll->rap = LE_CSR0;
@@ -565,7 +565,7 @@ static int lance_tx (struct device *dev)
                        if (status & (LE_T3_BUF|LE_T3_UFL)) {
                                lp->stats.tx_fifo_errors++;
 
-                               printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
+                               printk (KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
                                        dev->name);
                                /* Stop the lance */
                                ll->rap = LE_CSR0;
@@ -606,7 +606,7 @@ static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
        int csr0;
     
        if (dev->interrupt)
-               printk ("%s: again", dev->name);
+               printk (KERN_ERR "%s: again", dev->name);
     
        dev->interrupt = 1;
 
@@ -643,7 +643,7 @@ static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
                struct sparc_dma_registers *dregs = lp->ledma->regs;
                unsigned long tst = (unsigned long)dregs->st_addr;
 
-               printk ("%s: Memory error, status %04x, addr %06lx\n",
+               printk (KERN_ERR "%s: Memory error, status %04x, addr %06lx\n",
                        dev->name, csr0, tst & 0xffffff);
 
                ll->rdp = LE_C0_STOP;
@@ -674,7 +674,7 @@ static int lance_open (struct device *dev)
 
        if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ,
                         lancestr, (void *) dev)) {
-               printk ("Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
+               printk (KERN_ERR "Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
                return -EAGAIN;
        }
 
@@ -775,7 +775,7 @@ static inline int lance_reset (struct device *dev)
 
        /* On the 4m, reset the dma too */
        if (lp->ledma) {
-               printk ("resetting ledma\n");
+               printk (KERN_NOTICE "resetting ledma\n");
                lp->ledma->regs->cond_reg |= DMA_RST_ENET;
                udelay (200);
                lp->ledma->regs->cond_reg &= ~DMA_RST_ENET;
@@ -789,7 +789,7 @@ static inline int lance_reset (struct device *dev)
        dev->tbusy = 0;
        status = init_restart_lance (lp);
 #ifdef DEBUG_DRIVER
-       printk ("Lance restart=%d\n", status);
+       printk (KERN_DEBUG "Lance restart=%d\n", status);
 #endif
        return status;
 }
@@ -809,7 +809,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
                if (tickssofar < 100)
                        return 1;
 
-               printk ("%s: transmit timed out, status %04x, reset\n",
+               printk (KERN_ERR "%s: transmit timed out, status %04x, reset\n",
                        dev->name, ll->rdp);
                lp->stats.tx_errors++;
                lance_reset (dev);
@@ -986,9 +986,9 @@ sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev,
                memset(dev->priv, 0, sizeof (struct lance_private) + 8);
        }
        if (sparc_lance_debug && version_printed++ == 0)
-               printk (version);
+               printk (KERN_INFO "%s", version);
 
-       printk ("%s: LANCE ", dev->name);
+       printk (KERN_INFO "%s: LANCE ", dev->name);
        /* Fill the dev fields */
        dev->base_addr = (long) sdev;
 
@@ -1061,7 +1061,7 @@ sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev,
                if (prop[0] == 0) {
                        int topnd, nd;
 
-                       printk("%s: using auto-carrier-detection.\n",
+                       printk(KERN_INFO "%s: using auto-carrier-detection.\n",
                               dev->name);
 
                        /* Is this found at /options .attributes in all
@@ -1081,9 +1081,9 @@ sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev,
                                       sizeof(prop));
 
                        if (strcmp(prop, "true")) {
-                               printk("%s: warning: overriding option "
+                               printk(KERN_NOTICE "%s: warning: overriding option "
                                       "'tpe-link-test?'\n", dev->name);
-                               printk("%s: warning: mail any problems "
+                               printk(KERN_NOTICE "%s: warning: mail any problems "
                                       "to ecd@skynet.be\n", dev->name);
                                set_auxio(AUXIO_LINK_TEST, 0);
                        }
@@ -1106,7 +1106,7 @@ no_link_test:
 
        /* This should never happen. */
        if ((unsigned long)(lp->init_block->brx_ring) & 0x07) {
-               printk("%s: ERROR: Rx and Tx rings not on even boundary.\n",
+               printk(KERN_ERR "%s: ERROR: Rx and Tx rings not on even boundary.\n",
                       dev->name);
                return ENODEV;
        }
index f57ad37317e9b6ae2ee5e723b8ba3d3ff8177996..8eed1fa879d95896e9b154caae57f3f924eabc69 100644 (file)
@@ -67,7 +67,7 @@ static inline int qec_global_reset(struct qe_globreg *gregs)
        }
        if(tries)
                return 0;
-       printk("QuadEther: AIEEE cannot reset the QEC!\n");
+       printk(KERN_ERR "QuadEther: AIEEE cannot reset the QEC!\n");
        return -1;
 }
 
@@ -91,7 +91,7 @@ static inline int qe_stop(struct sunqe *qep)
                break;
        }
        if(!tries) {
-               printk("QuadEther: AIEEE cannot reset the MACE!\n");
+               printk(KERN_ERR "QuadEther: AIEEE cannot reset the MACE!\n");
                return -1;
        }
 
@@ -105,7 +105,7 @@ static inline int qe_stop(struct sunqe *qep)
                break;
        }
        if(!tries) {
-               printk("QuadEther: Cannot reset QE channel!\n");
+               printk(KERN_ERR "QuadEther: Cannot reset QE channel!\n");
                return -1;
        }
        return 0;
@@ -216,7 +216,7 @@ static int qe_init(struct sunqe *qep, int from_irq)
                                break;
                }
                if (tries == 0)
-                       printk("%s: Warning, link state is down.\n", qep->dev->name);
+                       printk(KERN_NOTICE "%s: Warning, link state is down.\n", qep->dev->name);
        }
 
        /* Missed packet counter is cleared on a read. */
@@ -240,41 +240,41 @@ static int qe_is_bolixed(struct sunqe *qep, unsigned int qe_status)
        int mace_hwbug_workaround = 0;
 
        if(qe_status & CREG_STAT_EDEFER) {
-               printk("%s: Excessive transmit defers.\n", dev->name);
+               printk(KERN_ERR "%s: Excessive transmit defers.\n", dev->name);
                qep->net_stats.tx_errors++;
        }
 
        if(qe_status & CREG_STAT_CLOSS) {
-               printk("%s: Carrier lost, link down?\n", dev->name);
+               printk(KERN_ERR "%s: Carrier lost, link down?\n", dev->name);
                qep->net_stats.tx_errors++;
                qep->net_stats.tx_carrier_errors++;
        }
 
        if(qe_status & CREG_STAT_ERETRIES) {
-               printk("%s: Excessive transmit retries (more than 16).\n", dev->name);
+               printk(KERN_ERR "%s: Excessive transmit retries (more than 16).\n", dev->name);
                qep->net_stats.tx_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_LCOLL) {
-               printk("%s: Late transmit collision.\n", dev->name);
+               printk(KERN_ERR "%s: Late transmit collision.\n", dev->name);
                qep->net_stats.tx_errors++;
                qep->net_stats.collisions++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_FUFLOW) {
-               printk("%s: Transmit fifo underflow, driver bug.\n", dev->name);
+               printk(KERN_ERR "%s: Transmit fifo underflow, driver bug.\n", dev->name);
                qep->net_stats.tx_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_JERROR) {
-               printk("%s: Jabber error.\n", dev->name);
+               printk(KERN_ERR "%s: Jabber error.\n", dev->name);
        }
 
        if(qe_status & CREG_STAT_BERROR) {
-               printk("%s: Babble error.\n", dev->name);
+               printk(KERN_ERR "%s: Babble error.\n", dev->name);
        }
 
        if(qe_status & CREG_STAT_CCOFLOW) {
@@ -283,27 +283,27 @@ static int qe_is_bolixed(struct sunqe *qep, unsigned int qe_status)
        }
 
        if(qe_status & CREG_STAT_TXDERROR) {
-               printk("%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
+               printk(KERN_ERR "%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
                qep->net_stats.tx_errors++;
                qep->net_stats.tx_aborted_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_TXLERR) {
-               printk("%s: Transmit late error.\n", dev->name);
+               printk(KERN_ERR "%s: Transmit late error.\n", dev->name);
                qep->net_stats.tx_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_TXPERR) {
-               printk("%s: Transmit DMA parity error.\n", dev->name);
+               printk(KERN_ERR "%s: Transmit DMA parity error.\n", dev->name);
                qep->net_stats.tx_errors++;
                qep->net_stats.tx_aborted_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_TXSERR) {
-               printk("%s: Transmit DMA sbus error ack.\n", dev->name);
+               printk(KERN_ERR "%s: Transmit DMA sbus error ack.\n", dev->name);
                qep->net_stats.tx_errors++;
                qep->net_stats.tx_aborted_errors++;
                mace_hwbug_workaround = 1;
@@ -325,13 +325,13 @@ static int qe_is_bolixed(struct sunqe *qep, unsigned int qe_status)
        }
 
        if(qe_status & CREG_STAT_RXFOFLOW) {
-               printk("%s: Receive fifo overflow.\n", dev->name);
+               printk(KERN_ERR "%s: Receive fifo overflow.\n", dev->name);
                qep->net_stats.rx_errors++;
                qep->net_stats.rx_over_errors++;
        }
 
        if(qe_status & CREG_STAT_RLCOLL) {
-               printk("%s: Late receive collision.\n", dev->name);
+               printk(KERN_ERR "%s: Late receive collision.\n", dev->name);
                qep->net_stats.rx_errors++;
                qep->net_stats.collisions++;
        }
@@ -347,33 +347,33 @@ static int qe_is_bolixed(struct sunqe *qep, unsigned int qe_status)
        }
 
        if(qe_status & CREG_STAT_RXDROP) {
-               printk("%s: Receive packet dropped.\n", dev->name);
+               printk(KERN_INFO "%s: Receive packet dropped.\n", dev->name);
                qep->net_stats.rx_errors++;
                qep->net_stats.rx_dropped++;
                qep->net_stats.rx_missed_errors++;
        }
 
        if(qe_status & CREG_STAT_RXSMALL) {
-               printk("%s: Receive buffer too small, driver bug.\n", dev->name);
+               printk(KERN_ERR "%s: Receive buffer too small, driver bug.\n", dev->name);
                qep->net_stats.rx_errors++;
                qep->net_stats.rx_length_errors++;
        }
 
        if(qe_status & CREG_STAT_RXLERR) {
-               printk("%s: Receive late error.\n", dev->name);
+               printk(KERN_ERR "%s: Receive late error.\n", dev->name);
                qep->net_stats.rx_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_RXPERR) {
-               printk("%s: Receive DMA parity error.\n", dev->name);
+               printk(KERN_ERR "%s: Receive DMA parity error.\n", dev->name);
                qep->net_stats.rx_errors++;
                qep->net_stats.rx_missed_errors++;
                mace_hwbug_workaround = 1;
        }
 
        if(qe_status & CREG_STAT_RXSERR) {
-               printk("%s: Receive DMA sbus error ack.\n", dev->name);
+               printk(KERN_ERR "%s: Receive DMA sbus error ack.\n", dev->name);
                qep->net_stats.rx_errors++;
                qep->net_stats.rx_missed_errors++;
                mace_hwbug_workaround = 1;
@@ -437,7 +437,7 @@ static void qe_rx(struct sunqe *qep)
        }
        qep->rx_new = elem;
        if(drops)
-               printk("%s: Memory squeeze, deferring packet.\n", qep->dev->name);
+               printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", qep->dev->name);
 }
 
 /* Interrupts for all QE's get filtered out via the QEC master controller,
@@ -538,7 +538,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct device *dev)
                long tickssofar = jiffies - dev->trans_start;
 
                if (tickssofar >= 40) {
-                       printk("%s: transmit timed out, resetting\n", dev->name);
+                       printk(KERN_NOTICE "%s: transmit timed out, resetting\n", dev->name);
                        qe_init(qep, 1);
                        dev->tbusy = 0;
                        dev->trans_start = jiffies;
@@ -711,7 +711,7 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
                qe_devs[0]->dev_addr[j] = idprom->id_ethaddr[j];
 
        if(version_printed++ == 0)
-               printk(version);
+               printk(KERN_INFO "%s", version);
 
        qe_devs[1] = qe_devs[2] = qe_devs[3] = NULL;
        for(i = 1; i < 4; i++) {
@@ -777,7 +777,7 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
                                           qranges[k].ot_child_space)
                                                break;
                                if(k >= num_qranges)
-                                       printk("QuadEther: Aieee, bogus QEC range for "
+                                       printk(KERN_ERR "QuadEther: Aieee, bogus QEC range for "
                                               "space %08x\n",qesdevs[i]->reg_addrs[j].which_io);
                                qesdevs[i]->reg_addrs[j].which_io = qranges[k].ot_parent_space;
                                qesdevs[i]->reg_addrs[j].phys_addr += qranges[k].ot_parent_base;
@@ -796,14 +796,14 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
                                     "QEC Global Registers",
                                     sdev->reg_addrs[0].which_io, 0);
        if(!qecp->gregs) {
-               printk("QuadEther: Cannot map QEC global registers.\n");
+               printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n");
                res = ENODEV;
                goto qec_free_devs;
        }
 
        /* Make sure the QEC is in MACE mode. */
        if((qecp->gregs->ctrl & 0xf0000000) != GLOB_CTRL_MMODE) {
-               printk("QuadEther: AIEEE, QEC is not in MACE mode!\n");
+               printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n");
                res = ENODEV;
                goto qec_free_devs;
        }
@@ -841,7 +841,7 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
                                                 "QEC Per-Channel Registers",
                                                 qesdevs[i]->reg_addrs[0].which_io, 0);
                if(!qeps[i]->qcregs) {
-                       printk("QuadEther: Cannot map QE %d's channel registers.\n", i);
+                       printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i);
                        res = ENODEV;
                        goto qec_free_devs;
                }
@@ -852,7 +852,7 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
                                                "QE MACE Registers",
                                                qesdevs[i]->reg_addrs[1].which_io, 0);
                if(!qeps[i]->mregs) {
-                       printk("QuadEther: Cannot map QE %d's MACE registers.\n", i);
+                       printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i);
                        res = ENODEV;
                        goto qec_free_devs;
                }
@@ -888,14 +888,14 @@ static inline int qec_ether_init(struct device *dev, struct linux_sbus_device *s
         */
        if(request_irq(sdev->irqs[0], &qec_interrupt,
                       SA_SHIRQ, "QuadEther", (void *) qecp)) {
-               printk("QuadEther: Can't register QEC master irq handler.\n");
+               printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n");
                res = EAGAIN;
                goto qec_free_devs;
        }
 
        /* Report the QE channels. */
        for(i = 0; i < 4; i++) {
-               printk("%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);
+               printk(KERN_INFO "%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);
                for(j = 0; j < 6; j++)
                        printk ("%2.2x%c",
                                qe_devs[i]->dev_addr[j],
index 5c515755e538005e832f58d1b97f55c3c928175a..fe4c30ca0d2f3b54de9f91ee285d2115eb75fbfe 100644 (file)
@@ -135,7 +135,7 @@ struct amd7930_channel {
        unsigned char xmit_idle_char;
 
        /* Callback routine (and argument) when output is done on */
-       void (*output_callback)();
+       void (*output_callback)(void *, unsigned char);
        void * output_callback_arg;
 
        /* Current buffer that the driver is recording on channel */
@@ -144,7 +144,7 @@ struct amd7930_channel {
        volatile unsigned long input_limit;
 
        /* Callback routine (and argument) when input is done on */
-       void (*input_callback)();
+       void (*input_callback)(void *, unsigned char, unsigned long);
        void * input_callback_arg;
 };
 
@@ -520,7 +520,7 @@ static void transceive_Bchannel(struct amd7930_channel *channel,
                        channel->input_count = 0;
                        if (channel->input_callback)
                                (*channel->input_callback)
-                                       (channel->input_callback_arg, 1);
+                                       (channel->input_callback_arg, 1, 0);
                }
        }
 }
index ff5367d6dbbfe75839841e7a325f4b0542da612b..de90e2f244b0c3e30e3109e1d3730b1b5296c649 100644 (file)
 struct cs4215 {
        __u8    data[4];        /* Data mode: Time slots 5-8 */
        __u8    ctrl[4];        /* Ctrl mode: Time slots 1-4 */
-       __volatile__ struct dbri_mem td;
-       __volatile__ struct dbri_mem rd;
        __u8    onboard;
-       __u32   status;
-        __u32  version;
+       __volatile__ __u32      status;
+        __volatile__ __u32     version;
+        int offset;
+        int ctrlmode;
+        int datamode;
 };
 
 
index a5ffefcc23867b24f4278189b0eafe56d7282892..14bfc625737772c9550603dc4323aa06e3db15d2 100644 (file)
@@ -904,8 +904,9 @@ static int cs4231_record_gain(struct sparcaudio_driver *drv, int value, unsigned
     if (l < 0) l = 0;
   }
 
-  l_adj = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
-  r_adj = r * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
+  /* See cs4231_play_gain for why we do things this way. -DaveM */
+  l_adj = ((l * (CS4231_MAX_GAIN + 1)) + AUDIO_MAX_GAIN) / (AUDIO_MAX_GAIN + 1);
+  r_adj = ((r * (CS4231_MAX_GAIN + 1)) + AUDIO_MAX_GAIN) / (AUDIO_MAX_GAIN + 1);
   
   CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x0);
   old_gain = CS4231_READ8(cs4231_chip, &(cs4231_chip->regs->idr));
@@ -932,7 +933,7 @@ static int cs4231_play_gain(struct sparcaudio_driver *drv, int value, unsigned c
   int tmp = 0, r, l, r_adj, l_adj;
   unsigned char old_gain;
 
-  tprintk(("in play_gain: %d %c\n", value, balance));
+  tprintk(("in play_gain: %d %x, ", value, balance));
   r = l = value;
   if (balance < AUDIO_MID_BALANCE) {
     r = (int)(value - ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT));
@@ -942,11 +943,15 @@ static int cs4231_play_gain(struct sparcaudio_driver *drv, int value, unsigned c
     if (l < 0) l = 0;
   }
 
+  /* We have to round up else several OSS programs
+   * get confused because for small increments we
+   * would otherwise not increase the volume ever. -DaveM
+   */
   (l == 0) ? (l_adj = CS4231_MAX_DEV_ATEN) : (l_adj = CS4231_MAX_ATEN - 
-                                              (l * (CS4231_MAX_ATEN + 1) / 
+                              (((l * (CS4231_MAX_ATEN + 1)) + AUDIO_MAX_GAIN) / 
                                                (AUDIO_MAX_GAIN + 1)));
   (r == 0) ? (r_adj = CS4231_MAX_DEV_ATEN) : (r_adj = CS4231_MAX_ATEN -
-                                              (r * (CS4231_MAX_ATEN + 1) /
+                              (((r * (CS4231_MAX_ATEN + 1)) + AUDIO_MAX_GAIN) /
                                                (AUDIO_MAX_GAIN + 1)));
   
   CS4231_WRITE8(cs4231_chip, &(cs4231_chip->regs->iar), 0x6);
index 59bca71ae5e9dbeee20f79fa374a60733dffe7e8..b68d3ef4e5b098d9d41cee0d93b7d669a8d0d4ae 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
+#include <linux/ioport.h>
 #include <linux/version.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -229,7 +230,7 @@ static void dbri_reset(struct dbri *dbri)
                         dbri->regs->reg8, dbri->regs->reg9)); 
 
        dbri->regs->reg0 = D_R; /* Soft Reset */
-       for(i = 0; (dbri->regs->reg0 & D_R) && i < 10; i++)
+       for(i = 0; (dbri->regs->reg0 & D_R) && i < 64; i++)
                udelay(10);
 }
 
@@ -370,9 +371,9 @@ static void reception_complete_intr(struct dbri *dbri, int pipe)
         int rd;
         int status;
         void *buffer;
-        int count;
+        int count = 0;
         void (*callback)(void *, int, unsigned int) = NULL;
-        void *callback_arg;
+        void *callback_arg = NULL;
 
         if ((pipe < 0) || (pipe > 15)) {
                 printk("DBRI: invalid pipe in reception_complete_intr\n");
@@ -804,6 +805,7 @@ static void link_time_slot(struct dbri *dbri, int pipe,
         dbri_cmdsend(dbri, cmd);
 }
 
+#if 0
 /* unlink_time_slot()
  *
  * I don't use this function, so it's basically untested.
@@ -865,6 +867,7 @@ static void unlink_time_slot(struct dbri *dbri, int pipe,
 
         dbri_cmdsend(dbri, cmd);
 }
+#endif
 
 /* xmit_fixed() / recv_fixed()
  *
@@ -1475,7 +1478,7 @@ static int mmcodec_setctrl(struct dbri *dbri)
          * codec at this location on the CHI, so return false.
          */
 
-        i = 10;
+        i = 64;
         while (((dbri->mm.status & 0xe4) != 0x20) && --i) udelay(125);
         if (i == 0) {
                return 0;
index 598f3b1917ff446d0fac538983255d919e6e0f39..c122800a684ed3b7303a6f9477ac0415ea4d9252 100644 (file)
@@ -209,7 +209,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                                     buf, len);
                restore_flags(flags);
 
-               if (error <= 0)
+               if (error < 0)
                        error = -EINVAL;
                break;
 
index ef19f74b9d565554998a929d13cf6f5d6e979a39..804d19a2019af3803e4bca79f39fc6d4fb2d3302 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.27 1999/05/09 06:40:47 ecd Exp $
+/* $Id: pcikbd.c,v 1.27.2.1 1999/10/01 05:09:36 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -934,10 +934,34 @@ struct file_operations psaux_fops = {
        aux_fasync,
 };
 
+static int aux_no_open(struct inode *inode, struct file *file)
+{
+       return -ENODEV;
+}
+
+struct file_operations psaux_no_fops = {
+       NULL,           /* seek */
+       NULL,
+       NULL,
+       NULL,           /* readdir */
+       NULL,
+       NULL,           /* ioctl */
+       NULL,           /* mmap */
+       aux_no_open,
+       NULL,           /* flush */
+       NULL,
+       NULL,
+       NULL,
+};
+
 static struct miscdevice psaux_mouse = {
        PSMOUSE_MINOR, "ps2aux", &psaux_fops
 };
 
+static struct miscdevice psaux_no_mouse = {
+       PSMOUSE_MINOR, "ps2aux", &psaux_no_fops
+};
+
 __initfunc(int pcimouse_init(void))
 {
        struct linux_ebus *ebus;
@@ -947,7 +971,7 @@ __initfunc(int pcimouse_init(void))
        if (pcikbd_mrcoffee) {
                if ((pcimouse_iobase = pcikbd_iobase) == 0) {
                        printk("pcimouse_init: no 8042 given\n");
-                       return -ENODEV;
+                       goto do_enodev;
                }
                pcimouse_irq = pcikbd_irq;
        } else {
@@ -962,7 +986,7 @@ __initfunc(int pcimouse_init(void))
                        }
                }
                printk("pcimouse_init: no 8042 found\n");
-               return -ENODEV;
+               goto do_enodev;
 
 found:
                pcimouse_iobase = child->base_address[0];
@@ -987,7 +1011,7 @@ found:
                        SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) {
                printk("8042: Cannot register IRQ %s\n",
                       __irq_itoa(pcimouse_irq));
-               return -ENODEV;
+               goto do_enodev;
        }
 
        printk("8042(mouse) at %lx (irq %s)\n", pcimouse_iobase,
@@ -1016,8 +1040,17 @@ found:
        aux_end_atomic();
 
        return 0;
+
+do_enodev:
+       misc_register(&psaux_no_mouse);
+       return -ENODEV;
 }
 
+__initfunc(int pcimouse_no_init(void))
+{
+       misc_register(&psaux_no_mouse);
+       return -ENODEV;
+}
 
 __initfunc(int ps2kbd_probe(unsigned long *memory_start))
 {
@@ -1034,7 +1067,7 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
        len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
        if (len < 0) {
                printk("ps2kbd_probe: no name of root node\n");
-               return -ENODEV;
+               goto do_enodev;
        }
        if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) {
                pcikbd_mrcoffee = 1;    /* Brain damage detected */
@@ -1047,7 +1080,7 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
         node = prom_getchild(prom_root_node);
        node = prom_searchsiblings(node, "aliases");
        if (!node)
-               return -ENODEV;
+               goto do_enodev;
 
        len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
        if (len > 0) {
@@ -1055,7 +1088,7 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
                kbnode = prom_finddevice(prop);
        }
        if (!kbnode)
-               return -ENODEV;
+               goto do_enodev;
 
        len = prom_getproperty(node, "mouse", prop, sizeof(prop));
        if (len > 0) {
@@ -1063,7 +1096,7 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
                msnode = prom_finddevice(prop);
        }
        if (!msnode)
-               return -ENODEV;
+               goto do_enodev;
 
        /*
         * Find matching EBus nodes...
@@ -1131,6 +1164,8 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
                pnode = prom_getsibling(pnode);
                pnode = prom_searchsiblings(pnode, "pci");
        }
+do_enodev:
+       sunkbd_setinitfunc(memory_start, pcimouse_no_init);
        return -ENODEV;
 
 found:
index bbbd7c67040f1eea23291c61bfd53e09d98fe518..08c81583b76e9b23670cf16c48f9f38a1020605a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.30 1999/03/24 11:34:52 davem Exp $
+/* $Id: sab82532.c,v 1.30.2.2 1999/10/12 14:11:20 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
+/* This is (one of many) a special gross hack to allow SU and
+ * SAB serials to co-exist on the same machine. -DaveM
+ */
+#undef SERIAL_BH
+#define SERIAL_BH      AURORA_BH
+
 static struct tty_driver serial_driver, callout_driver;
 static int sab82532_refcount;
 
@@ -250,6 +256,8 @@ static void sab82532_start(struct tty_struct *tty)
 static void batten_down_hatches(struct sab82532 *info)
 {
        unsigned char saved_rfc;
+       
+       if (!stop_a_enabled) return;
 
        /* If we are doing kadb, we call the debugger
         * else we just drop into the boot monitor.
@@ -2136,7 +2144,7 @@ sab82532_kgdb_hook(int line))
 
 __initfunc(static inline void show_serial_version(void))
 {
-       char *revision = "$Revision: 1.30 $";
+       char *revision = "$Revision: 1.30.2.2 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
@@ -2146,6 +2154,8 @@ __initfunc(static inline void show_serial_version(void))
        printk("SAB82532 serial driver version %s\n", serial_version);
 }
 
+extern int su_num_ports;
+
 /*
  * The serial driver boot-time initialization code!
  */
@@ -2169,7 +2179,7 @@ __initfunc(int sab82532_init(void))
        serial_driver.driver_name = "serial";
        serial_driver.name = "ttyS";
        serial_driver.major = TTY_MAJOR;
-       serial_driver.minor_start = 64;
+       serial_driver.minor_start = 64 + su_num_ports;
        serial_driver.num = NR_PORTS;
        serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
        serial_driver.subtype = SERIAL_TYPE_NORMAL;
@@ -2267,7 +2277,7 @@ __initfunc(int sab82532_init(void))
        
                printk(KERN_INFO
                       "ttyS%02d at 0x%lx (irq = %s) is a SAB82532 %s\n",
-                      info->line, (unsigned long)info->regs,
+                      info->line + su_num_ports, (unsigned long)info->regs,
                       __irq_itoa(info->irq), sab82532_version[info->type]);
        }
 
@@ -2565,8 +2575,9 @@ static struct console sab82532_console = {
 __initfunc(int sab82532_console_init(void))
 {
        extern int con_is_present(void);
+       extern int su_console_registered;
 
-       if (con_is_present())
+       if (con_is_present() || su_console_registered)
                return 0;
 
        if (!sab82532_chain) {
index 70e4f36579582af34fd13a09512d3ece24a85ab1..02859bc0f35a1efe2f5f96b97f09cbc8cf94cef8 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: su.c,v 1.18 1999/01/02 16:47:37 davem Exp $
+/* $Id: su.c,v 1.18.2.5 1999/10/14 08:44:35 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- * Coypright (C) 1998  Pete Zaitcev   (zaitcev@metabyte.com)
+ * Copyright (C) 1998-1999  Pete Zaitcev   (zaitcev@metabyte.com)
  *
  * This is mainly a variation of drivers/char/serial.c,
  * credits go to authors mentioned therein.
@@ -92,6 +92,11 @@ static struct console sercons;
 int su_serial_console_init(void);
 #endif
 
+enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
+static char *su_typev[] = { "???", "mouse", "kbd", "serial" };
+
+#define SU_PROPSIZE    128
+
 /*
  * serial.c saves memory when it allocates async_info upon first open.
  * We have parts of state structure together because we do call startup
@@ -107,8 +112,8 @@ struct su_struct {
        int              line;
        int              cflag;
 
-       int              kbd_node;
-       int              ms_node;
+       enum su_type     port_type;     /* Hookup type: e.g. mouse */
+       int              is_console;
        int              port_node;
 
        char             name[16];
@@ -145,6 +150,18 @@ struct su_struct {
        unsigned long           last_active;    /* For async_struct, to be */
 };
 
+/*
+ * Scan status structure.
+ * "prop" is a local variable but it eats stack to keep it in each
+ * stack frame of a recursive procedure.
+ */
+struct su_probe_scan {
+       int msnode, kbnode;     /* PROM nodes for mouse and keyboard */
+       int msx, kbx;           /* minors for mouse and keyboard */
+       int devices;            /* scan index */
+       char prop[SU_PROPSIZE];
+};
+
 static char *serial_name = "PCIO serial driver";
 static char serial_version[16];
 
@@ -223,8 +240,6 @@ static inline int serial_paranoia_check(struct su_struct *info,
        return 0;
 }
 
-#ifdef __sparc_v9__
-
 static inline
 unsigned int su_inb(struct su_struct *info, unsigned long offset)
 {
@@ -234,20 +249,7 @@ unsigned int su_inb(struct su_struct *info, unsigned long offset)
 static inline void
 su_outb(struct su_struct *info, unsigned long offset, int value)
 {
-       outb(value, info->port + offset);
-}
-
-#else
-
-static inline
-unsigned int su_inb(struct su_struct *info, unsigned long offset)
-{
-       return (unsigned int)(*(volatile unsigned char *)(info->port + offset));
-}
-
-static inline void
-su_outb(struct su_struct *info, unsigned long offset, int value)
-{
+#ifndef __sparc_v9__
        /*
         * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
         * connected with a gate then go to SlavIO. When IRQ4 goes tristated
@@ -257,10 +259,9 @@ su_outb(struct su_struct *info, unsigned long offset, int value)
         * This problem is similar to what Alpha people suffer, see serial.c.
         */
        if (offset == UART_MCR) value |= UART_MCR_OUT2;
-       *(volatile unsigned char *)(info->port + offset) = value;
-}
-
 #endif
+       outb(value, info->port + offset);
+}
 
 #define serial_in(info, off)           su_inb(info, off)
 #define serial_inp(info, off)          su_inb(info, off)
@@ -341,14 +342,14 @@ su_sched_event(struct su_struct *info, int event)
 }
 
 static __inline__ void
-receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs)
+receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs, int is_brk)
 {
        unsigned char status = 0;
        unsigned char ch;
 
        do {
                ch = serial_inp(info, UART_RX);
-               if (info->kbd_node) {
+               if (info->port_type == SU_PORT_KBD) {
                        if(ch == SUNKBD_RESET) {
                                l1a_state.kbd_id = 1;
                                l1a_state.l1_down = 0;
@@ -368,7 +369,7 @@ receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs)
                        }
                        sunkbd_inchar(ch, regs);
                } else {
-                       sun_mouse_inbyte(ch);
+                       sun_mouse_inbyte(ch, is_brk);
                }
 
                status = su_inb(info, UART_LSR);
@@ -380,12 +381,15 @@ receive_serial_chars(struct su_struct *info, int *status, struct pt_regs *regs)
 {
        struct tty_struct *tty = info->tty;
        unsigned char ch;
-       int ignored = 0;
+       int ignored = 0, saw_console_brk = 0;
        struct  async_icount *icount;
 
        icount = &info->icount;
        do {
                ch = serial_inp(info, UART_RX);
+               if (info->is_console &&
+                   (ch == 0 || (*status &UART_LSR_BI)))
+                       saw_console_brk = 1;
                if (tty->flip.count >= TTY_FLIPBUF_SIZE)
                        break;
                *tty->flip.char_buf_ptr = ch;
@@ -461,6 +465,8 @@ receive_serial_chars(struct su_struct *info, int *status, struct pt_regs *regs)
        printk("E%02x.R%d", *status, tty->flip.count);
 #endif
        tty_flip_buffer_push(tty);
+       if (saw_console_brk != 0)
+               batten_down_hatches();
 }
 
 static __inline__ void
@@ -529,7 +535,7 @@ check_modem_status(struct su_struct *info)
                            (status & UART_MSR_DCD))
                                hardpps();
 #endif
-       }
+               }
                if (status & UART_MSR_DCTS)
                        icount->cts++;
                wake_up_interruptible(&info->delta_msr_wait);
@@ -598,8 +604,9 @@ su_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 #ifdef SERIAL_DEBUG_INTR
        printk("status = %x...", status);
 #endif
-       if (status & UART_LSR_DR)
-               receive_kbd_ms_chars(info, regs);
+       if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
+               receive_kbd_ms_chars(info, regs,
+                                    (status & UART_LSR_BI) != 0);
 
 #ifdef SERIAL_DEBUG_INTR
        printk("end.\n");
@@ -775,7 +782,7 @@ startup(struct su_struct *info)
        /*
         * Allocate the IRQ if necessary
         */
-       if (info->kbd_node || info->ms_node) {
+       if (info->port_type != SU_PORT_PORT) {
                retval = request_irq(info->irq, su_kbd_ms_interrupt,
                                     SA_SHIRQ, info->name, info);
        } else {
@@ -956,7 +963,7 @@ change_speed(struct su_struct *info,
        int             bits;
        unsigned long   flags;
 
-       if (!info->kbd_node && !info->ms_node) {
+       if (info->port_type == SU_PORT_PORT) {
                if (!info->tty || !info->tty->termios)
                        return;
                if (!info->port)
@@ -1133,9 +1140,9 @@ static void su_put_char_kbd(unsigned char c)
        struct su_struct *info = su_table;
        int lsr;
 
-       if (!info->kbd_node)
+       if (info->port_type != SU_PORT_KBD)
                ++info;
-       if (!info)
+       if (info->port_type != SU_PORT_KBD)
                return;
 
        do {
@@ -1151,9 +1158,9 @@ su_change_mouse_baud(int baud)
 {
        struct su_struct *info = su_table;
 
-       if (!info->ms_node)
+       if (info->port_type != SU_PORT_MS)
                ++info;
-       if (!info)
+       if (info->port_type != SU_PORT_MS)
                return;
 
        info->cflag &= ~(CBAUDEX | CBAUD);
@@ -2026,6 +2033,8 @@ su_open(struct tty_struct *tty, struct file * filp)
        if ((line < 0) || (line >= NR_PORTS))
                return -ENODEV;
        info = su_table + line;
+       if (info->type == PORT_UNKNOWN)
+               return -ENODEV;
        info->count++;
        tty->driver_data = info;
        info->tty = tty;
@@ -2202,9 +2211,9 @@ done:
 
 /*
  * ---------------------------------------------------------------------
- * su_init() and friends
+ * su_XXX_init() and friends
  *
- * su_init() is called at boot-time to initialize the serial driver.
+ * su_XXX_init() is called at boot-time to initialize the serial driver.
  * ---------------------------------------------------------------------
  */
 
@@ -2215,7 +2224,7 @@ done:
  */
 __initfunc(static __inline__ void show_su_version(void))
 {
-       char *revision = "$Revision: 1.18 $";
+       char *revision = "$Revision: 1.18.2.5 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
@@ -2226,8 +2235,8 @@ __initfunc(static __inline__ void show_su_version(void))
 }
 
 /*
- * This routine is called by su_init() to initialize a specific serial
- * port.  It determines what type of UART chip this serial port is
+ * This routine is called by su_{serial|kbd_ms}_init() to initialize a specific
+ * serial port.  It determines what type of UART chip this serial port is
  * using: 8250, 16450, 16550, 16550A.  The important question is
  * whether or not this UART is a 16550A, since this will determine
  * whether or not we can use its FIFO features.
@@ -2236,38 +2245,38 @@ static void
 autoconfig(struct su_struct *info)
 {
        unsigned char status1, status2, scratch, scratch2;
-#ifdef __sparc_v9__
        struct linux_ebus_device *dev = 0;
        struct linux_ebus *ebus;
-#else
+#ifndef __sparc_v9__
        struct linux_prom_registers reg0;
 #endif
        unsigned long flags;
 
-#ifdef __sparc_v9__
+       if (!info->port_node || !info->port_type)
+               return;
+
+       /*
+        * First we look for Ebus-bases su's
+        */
        for_each_ebus(ebus) {
                for_each_ebusdev(dev, ebus) {
-                       if (!strncmp(dev->prom_name, "su", 2)) {
-                               if (dev->prom_node == info->kbd_node)
-                                       goto ebus_done;
-                               if (dev->prom_node == info->ms_node)
-                                       goto ebus_done;
+                       if (dev->prom_node == info->port_node) {
+                               info->port = dev->base_address[0];
+                               info->irq = dev->irqs[0];
+                               goto ebus_done;
                        }
                }
        }
-ebus_done:
-       if (!dev)
-               return;
 
-       info->port = dev->base_address[0];
-       if (check_region(info->port, 8))
-               return;
-
-       info->irq = dev->irqs[0];
+#ifdef __sparc_v9__
+       /*
+        * Not on Ebus, bailing.
+        */
+       return;
 #else
-       if (!info->port_node)
-               return;
-
+       /*
+        * Not on Ebus, must be OBIO.
+        */
        if (prom_getproperty(info->port_node, "reg",
            (char *)&reg0, sizeof(reg0)) == -1) {
                prom_printf("su: no \"reg\" property\n");
@@ -2279,21 +2288,24 @@ ebus_done:
                prom_printf("su: cannot map\n");
                return;
        }
+
        /*
-        * There is no intr property on MrCoffee, so hardwire it. Krups?
+        * There is no intr property on MrCoffee, so hardwire it.
         */
        info->irq = IRQ_4M(13);
 #endif
 
-#ifdef DEBUG_SERIAL_OPEN
-       printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
-              __irq_itoa(dev->irqs[0]));
+ebus_done:
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Found 'su' at %016lx IRQ %s\n", info->port,
+               __irq_itoa(info->irq));
 #endif
 
        info->magic = SERIAL_MAGIC;
 
        save_flags(flags); cli();
-       
+
        /*
         * Do a simple existence test first; if we fail this, there's
         * no point trying anything else.
@@ -2312,17 +2324,20 @@ ebus_done:
                return;         /* We failed; there's nothing here */
        }
 
-#if 0 /* P3: This does not work on MrCoffee. OUT2 is 0x80 - should work... */
        scratch = serial_inp(info, UART_MCR);
        serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
        serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
        status1 = serial_inp(info, UART_MSR) & 0xF0;
        serial_outp(info, UART_MCR, scratch);
        if (status1 != 0x90) {
+               /*
+                * This code fragment used to fail, now it fixed itself.
+                * We keep the printout for a case.
+                */
+               printk("su: loopback returned status 0x%02x\n", status1);
                restore_flags(flags);
                return;
        } 
-#endif
 
        scratch2 = serial_in(info, UART_LCR);
        serial_outp(info, UART_LCR, 0xBF);      /* set up for StarTech test */
@@ -2389,11 +2404,7 @@ ebus_done:
                return;
        }
 
-       if (info->kbd_node || info->ms_node)
-               sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
-       else
-               strcpy(info->name, "su(serial)");
-
+       sprintf(info->name, "su(%s)", su_typev[info->port_type]);
 #ifdef __sparc_v9__
        request_region(info->port, 8, info->name);
 #endif
@@ -2409,6 +2420,11 @@ ebus_done:
        restore_flags(flags);
 }
 
+/* This is used by the SAB driver to adjust where its minor
+ * numbers start, we always are probed for first.
+ */
+int su_num_ports = 0;
+
 /*
  * The serial driver boot-time initialization code!
  */
@@ -2499,11 +2515,18 @@ __initfunc(int su_serial_init(void))
                if (info->type == PORT_UNKNOWN)
                        continue;
 
-               printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
-                      info->name, info->port, __irq_itoa(info->irq),
+               printk(KERN_INFO "%s at 0x%lx (tty %d irq %s) is a %s\n",
+                      info->name, (long)info->port, i, __irq_itoa(info->irq),
                       uart_config[info->type].name);
        }
 
+       for (i = 0, info = su_table; i < NR_PORTS; i++, info++)
+               if (info->type == PORT_UNKNOWN)
+                       break;
+
+       su_num_ports = i;
+       serial_driver.num = callout_driver.num = i;
+
        return 0;
 }
 
@@ -2519,7 +2542,7 @@ __initfunc(int su_kbd_ms_init(void))
                info->type = PORT_UNKNOWN;
                info->baud_base = BAUD_BASE;
 
-               if (info->kbd_node)
+               if (info->port_type == SU_PORT_KBD)
                        info->cflag = B1200 | CS8 | CLOCAL | CREAD;
                else
                        info->cflag = B4800 | CS8 | CLOCAL | CREAD;
@@ -2528,12 +2551,12 @@ __initfunc(int su_kbd_ms_init(void))
                if (info->type == PORT_UNKNOWN)
                        continue;
 
-               printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
+               printk(KERN_INFO "%s at 0x%lx (irq = %s) is a %s\n",
                       info->name, info->port, __irq_itoa(info->irq),
                       uart_config[info->type].name);
 
                startup(info);
-               if (info->kbd_node)
+               if (info->port_type == SU_PORT_KBD)
                        keyboard_zsinit(su_put_char_kbd);
                else
                        sun_mouse_zsinit();
@@ -2541,154 +2564,131 @@ __initfunc(int su_kbd_ms_init(void))
        return 0;
 }
 
-__initfunc(int su_probe (unsigned long *memory_start))
+/*
+ * We got several platforms which present 'su' in different parts
+ * of device tree. 'su' may be found under obio, ebus, isa and pci.
+ * We walk over the tree and find them wherever PROM hides them.
+ */
+__initfunc(void su_probe_any(struct su_probe_scan *t, int sunode))
 {
-       struct su_struct *info = su_table;
-        int node, enode, tnode, sunode;
-       int kbnode = 0, msnode = 0;
-       int devices = 0;
-       char prop[128];
+       struct su_struct *info;
        int len;
 
-       /*
-        * Find su on MrCoffee. We return OK code if find any.
-        * Then su_init finds every one and initializes them.
-        * We do this early because MrCoffee got no aliases.
-        */
-       node = prom_getchild(prom_root_node);
-       if ((node = prom_searchsiblings(node, "obio")) != 0) {
-               if ((sunode = prom_getchild(node)) != 0) {
-                       if ((sunode = prom_searchsiblings(sunode, "su")) != 0) {
-                               info->port_node = sunode;
-#ifdef CONFIG_SERIAL_CONSOLE
-                               /*
-                                * Console must be initiated after the generic
-                                * initialization.
-                                * sunserial_setinitfunc inverts order, so
-                                * call this before next one.
-                                */
-                               sunserial_setinitfunc(memory_start,
-                                                     su_serial_console_init);
-#endif
-                               sunserial_setinitfunc(memory_start,
-                                                     su_serial_init);
-                               return 0;
+       if (t->devices >= NR_PORTS)
+               return;
+
+       for (; sunode != 0; sunode = prom_getsibling(sunode)) {
+               len = prom_getproperty(sunode, "name", t->prop, SU_PROPSIZE);
+               if (len <= 1)
+                       continue;               /* Broken PROM node */
+               if (strncmp(t->prop, "su", len) == 0 ||
+                   strncmp(t->prop, "serial", len) == 0 ||
+                   strncmp(t->prop, "su_pnp", len) == 0) {
+                       info = &su_table[t->devices];
+                       if (t->kbnode != 0 && sunode == t->kbnode) {
+                               t->kbx = t->devices;
+                               info->port_type = SU_PORT_KBD;
+                       } else if (t->msnode != 0 && sunode == t->msnode) {
+                               t->msx = t->devices;
+                               info->port_type = SU_PORT_MS;
+                       } else {
+                               info->port_type = SU_PORT_PORT;
                        }
+                       info->is_console = 0;
+                       info->port_node = sunode;
+                       ++t->devices;
+               } else {
+                       su_probe_any(t, prom_getchild(sunode));
                }
        }
+}
+
+__initfunc(int su_probe (unsigned long *memory_start))
+{
+       int node;
+       int len;
+       struct su_probe_scan scan;
+
+       /*
+        * First, we scan the tree.
+        */
+       scan.devices = 0;
+       scan.msx = -1;
+       scan.kbx = -1;
+       scan.kbnode = 0;
+       scan.msnode = 0;
 
        /*
         * Get the nodes for keyboard and mouse from 'aliases'...
         */
         node = prom_getchild(prom_root_node);
        node = prom_searchsiblings(node, "aliases");
-       if (!node)
-               return -ENODEV;
+       if (node != 0) {
 
-       len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
-       if (len > 0) {
-               prop[len] = 0;
-               kbnode = prom_finddevice(prop);
-       }
-       if (!kbnode)
-               return -ENODEV;
+               len = prom_getproperty(node, "keyboard", scan.prop,SU_PROPSIZE);
+               if (len > 0) {
+                       scan.prop[len] = 0;
+                       scan.kbnode = prom_finddevice(scan.prop);
+               }
 
-       len = prom_getproperty(node, "mouse", prop, sizeof(prop));
-       if (len > 0) {
-               prop[len] = 0;
-               msnode = prom_finddevice(prop);
+               len = prom_getproperty(node, "mouse", scan.prop, SU_PROPSIZE);
+               if (len > 0) {
+                       scan.prop[len] = 0;
+                       scan.msnode = prom_finddevice(scan.prop);
+               }
        }
-       if (!msnode)
-               return -ENODEV;
 
-       /*
-        * Find matching EBus nodes...
-        */
-        node = prom_getchild(prom_root_node);
-       if ((node = prom_searchsiblings(node, "pci")) == 0) {
-               return -ENODEV;         /* Plain sparc */
-       }
+       su_probe_any(&scan, prom_getchild(prom_root_node));
 
        /*
-        * Check for SUNW,sabre on Ultra 5/10/AXi.
+        * Second, we process the special case of keyboard and mouse.
+        *
+        * Currently if we got keyboard and mouse hooked to "su" ports
+        * we do not use any possible remaining "su" as a serial port.
+        * Thus, we ignore values of .msx and .kbx, then compact ports.
+        * Those who want to address this issue need to merge
+        * su_serial_init() and su_ms_kbd_init().
         */
-       len = prom_getproperty(node, "model", prop, sizeof(prop));
-       if ((len > 0) && !strncmp(prop, "SUNW,sabre", len)) {
-               node = prom_getchild(node);
-               node = prom_searchsiblings(node, "pci");
+       if (scan.msx != -1 && scan.kbx != -1) {
+               su_table[0].port_type = SU_PORT_MS;
+               su_table[0].is_console = 0;
+               su_table[0].port_node = scan.msnode;
+               su_table[1].port_type = SU_PORT_KBD;
+               su_table[1].is_console = 0;
+               su_table[1].port_node = scan.kbnode;
+
+               sunserial_setinitfunc(memory_start, su_kbd_ms_init);
+               rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
+               sunkbd_setinitfunc(memory_start, sun_kbd_init);
+               kbd_ops.compute_shiftstate = sun_compute_shiftstate;
+               kbd_ops.setledstate = sun_setledstate;
+               kbd_ops.getledstate = sun_getledstate;
+               kbd_ops.setkeycode = sun_setkeycode;
+               kbd_ops.getkeycode = sun_getkeycode;
+#ifdef CONFIG_PCI
+               sunkbd_install_keymaps(memory_start, sun_key_maps,
+                   sun_keymap_count, sun_func_buf, sun_func_table,
+                   sun_funcbufsize, sun_funcbufleft,
+                   sun_accent_table, sun_accent_table_size);
+#endif
+               return 0;
        }
+       if (scan.msx != -1 || scan.kbx != -1) {
+               printk("su_probe: cannot match keyboard and mouse, confused\n");
+               return -ENODEV;
+       }
+
+       if (scan.devices == 0)
+               return -ENODEV;
 
+#ifdef CONFIG_SERIAL_CONSOLE
        /*
-        * For each PCI bus...
+        * Console must be initiated after the generic initialization.
+        * sunserial_setinitfunc inverts order, so call this before next one.
         */
-       while (node) {
-               enode = prom_getchild(node);
-               enode = prom_searchsiblings(enode, "ebus");
-
-               /*
-                * For each EBus on this PCI...
-                */
-               while (enode) {
-                       sunode = prom_getchild(enode);
-                       tnode = prom_searchsiblings(sunode, "su");
-                       if (!tnode)
-                               tnode = prom_searchsiblings(sunode, "su_pnp");
-                       sunode = tnode;
-
-                       /*
-                        * For each 'su' on this EBus...
-                        */
-                       while (sunode) {
-                               /*
-                                * Does it match?
-                                */
-                               if (sunode == kbnode) {
-                                       info->kbd_node = sunode;
-                                       ++info;
-                                       ++devices;
-                               }
-                               if (sunode == msnode) {
-                                       info->ms_node = sunode;
-                                       ++info;
-                                       ++devices;
-                               }
-
-                               /*
-                                * Found everything we need?
-                                */
-                               if (devices == 2)
-                                       goto found;
-
-                               sunode = prom_getsibling(sunode);
-                               tnode = prom_searchsiblings(sunode, "su");
-                               if (!tnode)
-                                       tnode = prom_searchsiblings(sunode,
-                                                                   "su_pnp");
-                               sunode = tnode;
-                       }
-                       enode = prom_getsibling(enode);
-                       enode = prom_searchsiblings(enode, "ebus");
-               }
-               node = prom_getsibling(node);
-               node = prom_searchsiblings(node, "pci");
-       }
-       return -ENODEV;
-
-found:
-        sunserial_setinitfunc(memory_start, su_kbd_ms_init);
-        rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
-       sunkbd_setinitfunc(memory_start, sun_kbd_init);
-       kbd_ops.compute_shiftstate = sun_compute_shiftstate;
-       kbd_ops.setledstate = sun_setledstate;
-       kbd_ops.getledstate = sun_getledstate;
-       kbd_ops.setkeycode = sun_setkeycode;
-       kbd_ops.getkeycode = sun_getkeycode;
-#ifdef CONFIG_PCI
-       sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
-                              sun_func_buf, sun_func_table,
-                              sun_funcbufsize, sun_funcbufleft,
-                              sun_accent_table, sun_accent_table_size);
+       sunserial_setinitfunc(memory_start, su_serial_console_init);
 #endif
+       sunserial_setinitfunc(memory_start, su_serial_init);
        return 0;
 }
 
@@ -2910,6 +2910,8 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
        if (su_inb(info, UART_LSR) == 0xff)
                return -1;
 
+       info->is_console = 1;
+
        return 0;
 }
 
@@ -2927,6 +2929,8 @@ static struct console sercons = {
        NULL
 };
 
+int su_console_registered = 0;
+
 /*
  *     Register console.
  */
@@ -2942,6 +2946,7 @@ __initfunc(int su_serial_console_init(void))
                return 0;
        sercons.index = 0;
        register_console(&sercons);
+       su_console_registered = 1;
        return 0;
 }
 
index 076367f5927650d2a4d56bc2425d529854039eef..a5ef1e5318fce4b74aadeb8f4196a193fc77252f 100644 (file)
@@ -1,3 +1,4 @@
+
 /* Do not edit this file! It was automatically generated by   */
 /*    loadkeys --mktable defkeymap.map > defkeymap.c          */
 
@@ -30,7 +31,7 @@ u_short shift_map[NR_KEYS] = {
        0xf110, 0xf111, 0xf112, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf203,
        0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf01b, 0xf021, 0xf040,
        0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a, 0xf028, 0xf029,
-       0xf05f, 0xf02b, 0xf07e, 0xf07f, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf05f, 0xf02b, 0xf07e, 0xf07f, 0xf115, 0xf03d, 0xf30d, 0xf30c,
        0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf009, 0xfb51, 0xfb57,
        0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, 0xfb4f, 0xfb50,
        0xf07b, 0xf07d, 0xf07f, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
@@ -38,7 +39,7 @@ u_short shift_map[NR_KEYS] = {
        0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, 0xf022,
        0xf07c, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
        0xf20b, 0xf200, 0xf208, 0xf700, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
-       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf200,
+       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf00a,
        0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
        0xf200, 0xf020, 0xf200, 0xf20a, 0xf200, 0xf30a, 0xf200, 0xf200,
 };
@@ -49,7 +50,7 @@ u_short altgr_map[NR_KEYS] = {
        0xf512, 0xf513, 0xf514, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf202,
        0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf040,
        0xf200, 0xf024, 0xf200, 0xf200, 0xf07b, 0xf05b, 0xf05d, 0xf07d,
-       0xf05c, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf05c, 0xf200, 0xf200, 0xf200, 0xf115, 0xf03d, 0xf30d, 0xf30c,
        0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xfb71, 0xfb77,
        0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70,
        0xf200, 0xf07e, 0xf200, 0xf20e, 0xf911, 0xf912, 0xf913, 0xf30b,
@@ -57,7 +58,7 @@ u_short altgr_map[NR_KEYS] = {
        0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, 0xf200,
        0xf200, 0xf201, 0xf30e, 0xf90e, 0xf90f, 0xf910, 0xf90a, 0xf200,
        0xf118, 0xf200, 0xf208, 0xf700, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
-       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
+       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf00a,
        0xf90b, 0xf90c, 0xf90d, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
        0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
 };
@@ -68,7 +69,7 @@ u_short ctrl_map[NR_KEYS] = {
        0xf106, 0xf107, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf204,
        0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf000,
        0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf07f, 0xf200, 0xf200,
-       0xf01f, 0xf200, 0xf000, 0xf008, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf01f, 0xf200, 0xf000, 0xf008, 0xf115, 0xf03d, 0xf30d, 0xf30c,
        0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xf011, 0xf017,
        0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010,
        0xf01b, 0xf01d, 0xf008, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
@@ -76,7 +77,7 @@ u_short ctrl_map[NR_KEYS] = {
        0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf007,
        0xf01c, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
        0xf118, 0xf200, 0xf208, 0xf700, 0xf01a, 0xf018, 0xf003, 0xf016,
-       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf200,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf00a,
        0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
        0xf200, 0xf000, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
 };
@@ -87,7 +88,7 @@ u_short shift_ctrl_map[NR_KEYS] = {
        0xf200, 0xf200, 0xf200, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf200,
        0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf000,
        0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf01f, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf01f, 0xf200, 0xf200, 0xf200, 0xf115, 0xf03d, 0xf30d, 0xf30c,
        0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xf011, 0xf017,
        0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010,
        0xf200, 0xf200, 0xf200, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
@@ -95,7 +96,7 @@ u_short shift_ctrl_map[NR_KEYS] = {
        0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf200,
        0xf200, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
        0xf118, 0xf200, 0xf208, 0xf700, 0xf01a, 0xf018, 0xf003, 0xf016,
-       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf00a,
        0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
        0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
 };
@@ -106,15 +107,15 @@ u_short alt_map[NR_KEYS] = {
        0xf506, 0xf507, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209,
        0xf210, 0xf200, 0xf200, 0xf600, 0xf211, 0xf81b, 0xf831, 0xf832,
        0xf833, 0xf834, 0xf835, 0xf836, 0xf837, 0xf838, 0xf839, 0xf830,
-       0xf82d, 0xf83d, 0xf860, 0xf87f, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf82d, 0xf83d, 0xf860, 0xf87f, 0xf115, 0xf03d, 0xf30d, 0xf30c,
        0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf809, 0xf871, 0xf877,
        0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, 0xf86f, 0xf870,
-       0xf85b, 0xf85d, 0xf200, 0xf87f, 0xf907, 0xf908, 0xf909, 0xf30b,
+       0xf85b, 0xf85d, 0xf87f, 0xf20e, 0xf907, 0xf908, 0xf909, 0xf30b,
        0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf861, 0xf873, 0xf864,
        0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, 0xf827,
        0xf85c, 0xf80d, 0xf30e, 0xf904, 0xf905, 0xf906, 0xf900, 0xf200,
        0xf118, 0xf200, 0xf208, 0xf700, 0xf87a, 0xf878, 0xf863, 0xf876,
-       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf200,
+       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf00a,
        0xf901, 0xf902, 0xf903, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
        0xf200, 0xf820, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
 };
@@ -125,7 +126,7 @@ u_short ctrl_alt_map[NR_KEYS] = {
        0xf506, 0xf507, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf200,
        0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf200,
        0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf115, 0xf03d, 0xf30d, 0xf30c,
        0xf200, 0xf200, 0xf20c, 0xf200, 0xf114, 0xf200, 0xf811, 0xf817,
        0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, 0xf80f, 0xf810,
        0xf200, 0xf200, 0xf20c, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b,
@@ -133,7 +134,7 @@ u_short ctrl_alt_map[NR_KEYS] = {
        0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, 0xf200,
        0xf200, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200,
        0xf118, 0xf200, 0xf208, 0xf700, 0xf81a, 0xf818, 0xf803, 0xf816,
-       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
+       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf00a,
        0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207,
        0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200,
 };
@@ -147,6 +148,7 @@ ushort *key_maps[MAX_NR_KEYMAPS] = {
 
 unsigned int keymap_count = 7;
 
+
 /*
  * Philosophy: most people do not define more strings, but they who do
  * often want quite a lot of string space. So, we statically allocate
@@ -184,6 +186,7 @@ char func_buf[] = {
        '\033', '[', 'P', 0, 
 };
 
+
 char *funcbufptr = func_buf;
 int funcbufsize = sizeof(func_buf);
 int funcbufleft = 0;          /* space left */
index 7fa644d1e45a1e5adeeef5b9a8424c92178ddaf8..c141162882ee1c03cb09a63ce51a31196e11974b 100644 (file)
@@ -160,7 +160,7 @@ keycode 0x41 = bracketright braceright      asciitilde
        alt     keycode                         0x41 = Meta_bracketright
 keycode 0x42 = Delete          Delete
        control keycode                         0x42 = BackSpace
-       alt     keycode                         0x43 = Meta_Delete
+       alt     keycode                         0x42 = Meta_Delete
        control alt     keycode                 0x42 = Boot
 keycode 0x43 = Compose
 keycode 0x44 = KP_7
index 8547e47ddb456d5859112c61186f9f79dd55e4ed..b14e124f8af9b8e10b91f9ff76856963ea417e3a 100644 (file)
@@ -81,7 +81,7 @@ struct sun_mouse {
        unsigned int tail;
        union {
                char stream [STREAM_SIZE];
-               Firm_event ev [0];
+               Firm_event ev [EV_SIZE];
        } queue;
 };
 
@@ -142,8 +142,6 @@ push_char (char c)
 }
 
 /* Auto baud rate "detection".  ;-) */
-static int mouse_bogon_bytes = 0;
-static int mouse_baud_changing = 0;    /* For reporting things to the user. */
 static int mouse_baud = 4800;          /* Initial rate set by zilog driver. */
 
 /* Change the baud rate after receiving too many "bogon bytes". */
@@ -161,71 +159,112 @@ void sun_mouse_change_baud(void)
                mouse_baud = 1200;
 
        rs_change_mouse_baud(mouse_baud);
-       mouse_baud_changing = 1;
 }
 
-void mouse_baud_detection(unsigned char c)
+/* This tries to monitor the mouse state so that it
+ * can automatically adjust to the correct baud rate.
+ * The mouse spits out BRKs when the baud rate is
+ * incorrect.
+ *
+ * It returns non-zero if we should ignore this byte.
+ */
+int mouse_baud_detection(unsigned char c, int is_break)
 {
-       static int wait_for_synchron = 1;
+       static int mouse_got_break = 0;
        static int ctr = 0;
 
-       if(wait_for_synchron) {
-               if((c < 0x80) || (c > 0x87))
-                       mouse_bogon_bytes++;
-               else {
-                       ctr = 0;
-                       wait_for_synchron = 0;
-               }
-       } else {
+       if (is_break) {
+               /* Let a few normal bytes go by before
+                * we jump the gun and say we need to
+                * try another baud rate.
+                */
+               if (mouse_got_break && ctr < 8)
+                       return 1;
+
+               /* OK, we need to try another baud rate. */
+               sun_mouse_change_baud();
+               ctr = 0;
+               mouse_got_break = 1;
+               return 1;
+       }
+       if (mouse_got_break) {
                ctr++;
-               if(ctr >= 4) {
-                       ctr = 0;
-                       wait_for_synchron = 1;
-                       if(mouse_baud_changing == 1) {
-                               printk(KERN_DEBUG "sunmouse: Successfully adjusted to %d baud.\n",
-                                      mouse_baud);
-                               mouse_baud_changing = 0;
-                       }
+               if (c == 0x87) {
+                       printk(KERN_INFO "sunmouse: Successfully "
+                              "adjusted to %d baud.\n", mouse_baud);
+                       mouse_got_break = 0;
                }
+               return 1;
        }
-       if(mouse_bogon_bytes > 12) {
-               sun_mouse_change_baud();
-               mouse_bogon_bytes = 0;
-               wait_for_synchron = 1;
-       }
+
+       return 0;
 }
 
-/* The following is called from the zs driver when bytes are received on
- * the Mouse zs8530 channel.
+/* You ask me, why does this cap the lower bound at -127 and not
+ * -128?  Because the xf86 mouse code is crap and treats -128
+ * as an illegal value and resets it's protocol state machine
+ * when it sees this value.
+ */
+#define CLIP(__X)      (((__X) > 127) ? 127 : (((__X) < -127) ? -127 : (__X)))
+
+/* The following is called from the serial driver when bytes/breaks
+ * are received on the Mouse line.
  */
 void
-sun_mouse_inbyte(unsigned char byte)
+sun_mouse_inbyte(unsigned char byte, int is_break)
 {
        signed char mvalue;
        int d, pushed = 0;
        Firm_event ev;
 
        add_mouse_randomness (byte);
+#if 0
+       {
+               static int xxx = 0;
+               printk("mouse(%02x:%d) ",
+                      byte, is_break);
+               if (byte == 0x87) {
+                       xxx = 0;
+                       printk("\n");
+               }
+       }
+#endif
+       if (mouse_baud_detection(byte, is_break))
+               return;
+
        if(!sunmouse.active)
                return;
 
-       mouse_baud_detection(byte);
+       /* Ignore this if it is garbage. */
+       if (sunmouse.byte == 69) {
+               if (byte != 0x87)
+                       return;
 
-       if (!gen_events){
-               push_char (byte);
-               return;
+               /* Ok, we've begun the state machine. */
+               sunmouse.byte = 0;
        }
-
+#if 0
        /* If the mouse sends us a byte from 0x80 to 0x87
         * we are starting at byte zero in the transaction
         * protocol.
         */
        if(byte >= 0x80 && byte <= 0x87)
                sunmouse.byte = 0;
+#endif
 
        mvalue = (signed char) byte;
        switch(sunmouse.byte) {
        case 0:
+               /* If we get a bogus button byte, just skip it.
+                * When we get here the baud detection code has
+                * passed, so the only other things which can
+                * cause this are dropped serial characters and
+                * confused mouse.  We check this because otherwise
+                * begin posting erroneous mouse events.
+                */
+               if ((byte & 0xf0) != 0x80)
+                       return;
+
                /* Button state */
                sunmouse.button_state = (~byte) & 0x7;
 #ifdef SMOUSE_DEBUG
@@ -258,6 +297,7 @@ sun_mouse_inbyte(unsigned char byte)
                printk("DX2<%d>", mvalue);
 #endif
                sunmouse.delta_x += mvalue;
+               sunmouse.delta_x = CLIP(sunmouse.delta_x);
                sunmouse.byte++;
                return;
        case 4:
@@ -266,7 +306,8 @@ sun_mouse_inbyte(unsigned char byte)
                printk("DY2<%d>", mvalue);
 #endif
                sunmouse.delta_y += mvalue;
-               sunmouse.byte = 69;  /* Some ridiculous value */
+               sunmouse.delta_y = CLIP(sunmouse.delta_y);
+               sunmouse.byte = 0;  /* Back to button state */
                break;
        case 69:
                /* Until we get the (0x80 -> 0x87) value we aren't
@@ -279,6 +320,12 @@ sun_mouse_inbyte(unsigned char byte)
                sunmouse.byte = 69;  /* What could cause this? */
                return;
        };
+       if (!gen_events){
+               push_char (~sunmouse.button_state & 0x87);
+               push_char (sunmouse.delta_x);
+               push_char (sunmouse.delta_y);
+               return;
+       }
        d = bstate ^ pstate;
        pstate = bstate;
        if (d){
@@ -389,6 +436,10 @@ sun_mouse_read(struct file *file, char *buffer,
                        if (current->tss.flags & SPARC_FLAG_32BIT) {
                                Firm_event *q = get_from_queue();
                                
+                               if ((end - p) <
+                                   ((sizeof(Firm_event) - sizeof(struct timeval) +
+                                     (sizeof(u32) * 2))))
+                                       break;
                                copy_to_user_ret((Firm_event *)p, q, 
                                                 sizeof(Firm_event)-sizeof(struct timeval),
                                                 -EFAULT);
@@ -400,6 +451,8 @@ sun_mouse_read(struct file *file, char *buffer,
                        } else
 #endif 
                        {       
+                               if ((end - p) < sizeof(Firm_event))
+                                       break;
                                copy_to_user_ret((Firm_event *)p, get_from_queue(),
                                                 sizeof(Firm_event), -EFAULT);
                                p += sizeof (Firm_event);
@@ -409,16 +462,25 @@ sun_mouse_read(struct file *file, char *buffer,
                file->f_dentry->d_inode->i_atime = CURRENT_TIME;
                return p-buffer;
        } else {
-               int c;
-               
-               for (c = count; !queue_empty() && c; c--){
-                       put_user_ret(sunmouse.queue.stream[sunmouse.tail], buffer, -EFAULT);
+               int c, limit = 3;
+
+               if (count < limit)
+                       limit = count;
+               for (c = 0; c < limit; c++) {
+                       put_user(sunmouse.queue.stream[sunmouse.tail], buffer);
                        buffer++;
                        sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
                }
+               while (c < count) {
+                       if (c >= 5)
+                               break;
+                       put_user(0, buffer);
+                       buffer++;
+                       c++;
+               }
                sunmouse.ready = !queue_empty();
                file->f_dentry->d_inode->i_atime = CURRENT_TIME;
-               return count-c;
+               return c;
        }
        /* Only called if nothing was sent */
        if (signal_pending(current))
index 78d9eb73cf70e7f7d595f5bfecdbeba331ac6a68..6f718b917cabee2aed9afdd1a8a90ac691efbbd7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunmouse.h,v 1.1 1997/08/28 02:23:38 ecd Exp $
+/* $Id: sunmouse.h,v 1.1.6.1 1999/10/14 08:44:33 davem Exp $
  * sunmouse.h: Interface to the SUN mouse driver.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -8,6 +8,6 @@
 #define _SPARC_SUNMOUSE_H 1
 
 extern void sun_mouse_zsinit(void);
-extern void sun_mouse_inbyte(unsigned char);
+extern void sun_mouse_inbyte(unsigned char, int);
 
 #endif /* !(_SPARC_SUNMOUSE_H) */
index 075062cf15ff01f2ff7971d2e76f6288c2a7fa4f..0ab3e9beba153cd43f08e4335ba6396a479f4470 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.68 1998/12/09 18:53:51 davem Exp $
+/* $Id: sunserial.c,v 1.68.2.2 1999/10/04 14:57:02 jj Exp $
  * serial.c: Serial port driver infrastructure for the Sparc.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -19,6 +19,7 @@
 #include "sunserial.h"
 
 int serial_console;
+int stop_a_enabled = 1;
 
 __initfunc(int con_is_present(void))
 {
@@ -389,12 +390,10 @@ sun_serial_setup(unsigned long memory_start))
         * So be very careful not to probe for keyboards if we are on a
         * serial console.
         */
-       if (!serial_console) {
-               if (ps2kbd_probe(&memory_start) == 0)
-                       return memory_start;
-               if (su_probe(&memory_start) == 0)
-                       return memory_start;
-       }
+       if (!serial_console)
+               ps2kbd_probe(&memory_start);
+       if (su_probe(&memory_start) == 0)
+               return memory_start;
 #endif
 
        if (!ret)
index e0438051b6b949964c477136b4bd825cea8e445a..da34ddbbab22fac3bbf1ef363a31b78450a51c6d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunserial.h,v 1.17 1997/12/19 07:33:12 ecd Exp $
+/* $Id: sunserial.h,v 1.17.4.1 1999/10/04 14:57:08 jj Exp $
  * sunserial.h: SUN serial driver infrastructure (including keyboards).
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -41,6 +41,7 @@ extern void sunserial_setinitfunc(unsigned long *, int (*) (void));
 extern void sunkbd_setinitfunc(unsigned long *, int (*) (void));
 
 extern int serial_console;
+extern int stop_a_enabled;
 extern void sunserial_console_termios(struct console *);
 
 #ifdef CONFIG_PCI
index 31cce21f510169126ea0f9b1d245480f9abf2084..cd1d72c251dbbd51a58b283a736249122ea2e322 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.41.2.2 1999/09/21 15:50:45 davem Exp $
+/* $Id: zs.c,v 1.41.2.4 1999/10/14 08:44:40 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -374,6 +374,8 @@ static void zs_start(struct tty_struct *tty)
  */
 void batten_down_hatches(void)
 {
+       if (!stop_a_enabled)
+               return;
        /* If we are doing kadb, we call the debugger
         * else we just drop into the boot monitor.
         * Note that we must flush the user windows
@@ -471,7 +473,7 @@ static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs
                        goto next_char;
                }
                if(info->cons_mouse) {
-                       sun_mouse_inbyte(ch);
+                       sun_mouse_inbyte(ch, 0);
                        do_queue_task = 0;
                        goto next_char;
                }
@@ -584,8 +586,12 @@ static _INLINE_ void status_handle(struct sun_serial *info)
         * 'break asserted' status change interrupt, call
         * the boot prom.
         */
-       if((status & BRK_ABRT) && info->break_abort)
-               batten_down_hatches();
+       if(status & BRK_ABRT) {
+               if (info->break_abort)
+                       batten_down_hatches();
+               if (info->cons_mouse)
+                       sun_mouse_inbyte(0, 1);
+       }
 
        /* XXX Whee, put in a buffer somewhere, the status information
         * XXX whee whee whee... Where does the information go...
@@ -1849,7 +1855,7 @@ int zs_open(struct tty_struct *tty, struct file * filp)
 
 static void show_serial_version(void)
 {
-       char *revision = "$Revision: 1.41.2.2 $";
+       char *revision = "$Revision: 1.41.2.4 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
index 969ca8d0e3430d3fff68f049349096973e54a2d0..29f09a0d92ae011653e36ca40b3f9c1ca17f34ae 100644 (file)
@@ -1519,8 +1519,11 @@ do_sync_known:
                 */
                if((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
                   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-                       /* But we are nice and allow tapes to disconnect. */
-                       if(SDptr->type == TYPE_TAPE)
+                       /* But we are nice and allow tapes and removable
+                        * disks (but not CDROMs) to disconnect.
+                        */
+                       if(SDptr->type == TYPE_TAPE ||
+                          (SDptr->type != TYPE_ROM && SDptr->removable))
                                SDptr->disconnect = 1;
                        else
                                SDptr->disconnect = 0;
@@ -1538,7 +1541,8 @@ do_sync_known:
                 */
                if(esp->erev == fashme && !SDptr->wide) {
                        if(!SDptr->borken &&
-                          SDptr->type != TYPE_ROM) {
+                          SDptr->type != TYPE_ROM &&
+                          SDptr->removable == 0) {
                                build_wide_nego_msg(esp, 16);
                                SDptr->wide = 1;
                                esp->wnip = 1;
@@ -1556,6 +1560,11 @@ do_sync_known:
                                         "CDROM.\n", esp->esp_id));
                                cdrom_hwbug_wkaround = 1;
                                build_sync_nego_msg(esp, 0, 0);
+                       } else if (SDptr->removable != 0) {
+                               ESPMISC(("esp%d: Not negotiating sync/wide but "
+                                        "allowing disconnect for removable media.\n",
+                                        esp->esp_id));
+                               build_sync_nego_msg(esp, 0, 0);
                        } else {
                                build_sync_nego_msg(esp, esp->sync_defp, 15);
                        }
@@ -1589,7 +1598,9 @@ after_nego_msg_built:
                 *           Therefore _no_ disconnects for SCSI1 targets
                 *           thank you very much. ;-)
                 */
-               if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
+               if(((SDptr->scsi_level < 3) &&
+                   (SDptr->type != TYPE_TAPE) &&
+                   SDptr->removable == 0) ||
                   cdrom_hwbug_wkaround || SDptr->borken) {
                        ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
                                 "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
index cd5d8ef33a708de81b26d140145e5bb900030257..3909ac9cd78a7dc31bdd4ca0891deca4b4e2af0b 100644 (file)
@@ -302,7 +302,7 @@ static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
 
 static inline unsigned long get_timeout(idescsi_pc_t *pc)
 {
-       return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);
+       return IDE_MAX((30 * HZ), pc->timeout - jiffies);       /* CD-RW drives need long timeouts */
 }
 
 /*
index bfb5444751001c97164be255408db807de1694a6..1f8a209d2278f7b9bb569d2d73f35db0b54ca2cf 100644 (file)
@@ -43,7 +43,7 @@
 #include <linux/module.h>
 
 #define MAX_TARGETS    16
-#define MAX_LUNS       8
+#define MAX_LUNS       8       /* 32 for 1.31 F/W */
 
 #define DEFAULT_LOOP_COUNT     10000
 
@@ -244,6 +244,46 @@ static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int f
        return 0;
 }
 
+static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
+{
+       int i;
+
+       qpti->host_param.initiator_scsi_id = qpti->scsi_id;
+       qpti->host_param.bus_reset_delay = 3;
+       qpti->host_param.retry_count = 0;
+       qpti->host_param.retry_delay = 5;
+       qpti->host_param.async_data_setup_time = 3;
+       qpti->host_param.req_ack_active_negation = 1;
+       qpti->host_param.data_line_active_negation = 1;
+       qpti->host_param.data_dma_burst_enable = 1;
+       qpti->host_param.command_dma_burst_enable = 1;
+       qpti->host_param.tag_aging = 8;
+       qpti->host_param.selection_timeout = 250;
+       qpti->host_param.max_queue_depth = 256;
+
+       for(i = 0; i < MAX_TARGETS; i++) {
+               /*
+                * disconnect, parity, arq, reneg on reset, and, oddly enough
+                * tags...the midlayer's notion of tagged support has to match
+                * our device settings, and since we base whether we enable a
+                * tag on a  per-cmnd basis upon what the midlayer sez, we
+                * actually enable the capability here.
+                */
+               qpti->dev_param[i].device_flags = 0xcd;
+               qpti->dev_param[i].execution_throttle = 16;
+               if (qpti->ultra) {
+                       qpti->dev_param[i].synchronous_period = 12;
+                       qpti->dev_param[i].synchronous_offset = 8;
+               } else {
+                       qpti->dev_param[i].synchronous_period = 25;
+                       qpti->dev_param[i].synchronous_offset = 12;
+               }
+               qpti->dev_param[i].device_enable = 1;
+       }
+       /* this is very important to set! */
+       qpti->sbits = 1 << qpti->scsi_id;
+}
+
 static int qlogicpti_reset_hardware(struct Scsi_Host *host)
 {
        struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
@@ -288,6 +328,10 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
                qregs->risc_mtreg = (RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT);
        }
 
+       /* reset adapter and per-device default values. */
+       /* do it after finding out whether we're ultra mode capable */
+       qlogicpti_set_hostdev_defaults(qpti);
+
        /* Release the RISC processor. */
        qregs->hcctrl = HCCTRL_REL;
 
@@ -365,9 +409,11 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
                param[0] = MBOX_SET_TARGET_PARAMS;
                param[1] = (i << 8);
                param[2] = (qpti->dev_param[i].device_flags << 8);
-               if (qpti->is_pti == 0)  /* really, is it 1.31 f/w or later? */
-                       param[2] |= 0xc0;
-               param[3] = 0;   /* no sync mode at first */
+               /*
+                * Since we're now loading 1.31 f/w, force narrow/async.
+                */
+               param[2] |= 0xc0;
+               param[3] = 0;   /* no offset, we do not have sync mode yet */
                qlogicpti_mbox_command(qpti, param, 0);
        }
 
@@ -392,9 +438,6 @@ __initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti))
        unsigned short param[6];
        unsigned short *risc_code, risc_code_addr, risc_code_length;
        unsigned long flags;
-#if !defined(MODULE) && !defined(__sparc_v9__)
-       unsigned long dvma_addr;
-#endif
        int i, timeout;
 
        risc_code = &sbus_risc_code01[0];
@@ -409,6 +452,7 @@ __initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti))
        for(i = 0; i < risc_code_length; i++)
                csum += risc_code[i];
        if(csum) {
+               restore_flags(flags);
                printk(KERN_EMERG "qlogicpti%d: Aieee, firmware checksum failed!",
                       qpti->qpti_id);
                return 1;
@@ -420,6 +464,7 @@ __initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti))
        while(--timeout && (qregs->sbus_ctrl & SBUS_CTRL_RESET))
                udelay(20);
        if(!timeout) {
+               restore_flags(flags);
                printk(KERN_EMERG "qlogicpti%d: Cannot reset the ISP.", qpti->qpti_id);
                return 1;
        }
@@ -449,6 +494,9 @@ __initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti))
                qpti->differential = 0;
        qregs->hcctrl = HCCTRL_REL;
 
+       /* This shouldn't be necessary- we've reset things so we should be
+          running from the ROM now.. */
+
        param[0] = MBOX_STOP_FIRMWARE;
        param[1] = param[2] = param[3] = param[4] = param[5] = 0;
        if(qlogicpti_mbox_command(qpti, param, 1)) {
@@ -459,38 +507,18 @@ __initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti))
        }               
 
        /* Load the firmware. */
-#if !defined(MODULE) && !defined(__sparc_v9__)
-       if (sparc_cpu_model != sun4d) {
-               dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code[0],
-                                                        (sizeof(u_short) * risc_code_length));
-               param[0] = MBOX_LOAD_RAM;
-               param[1] = risc_code_addr;
-               param[2] = (dvma_addr >> 16);
-               param[3] = (dvma_addr & 0xffff);
-               param[4] = (sizeof(u_short) * risc_code_length);
+       for(i = 0; i < risc_code_length; i++) {
+               param[0] = MBOX_WRITE_RAM_WORD;
+               param[1] = risc_code_addr + i;
+               param[2] = risc_code[i];
                if(qlogicpti_mbox_command(qpti, param, 1) ||
-                  (param[0] != MBOX_COMMAND_COMPLETE)) {
-                       printk(KERN_EMERG "qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
+                  param[0] != MBOX_COMMAND_COMPLETE) {
+                       printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
                               qpti->qpti_id);
                        restore_flags(flags);
                        return 1;
                }
-               mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length));
-       } else
-#endif
-       /* We need to do it this slow way always on Ultra, SS[12]000. */
-               for(i = 0; i < risc_code_length; i++) {
-                       param[0] = MBOX_WRITE_RAM_WORD;
-                       param[1] = risc_code_addr + i;
-                       param[2] = risc_code[i];
-                       if(qlogicpti_mbox_command(qpti, param, 1) ||
-                          param[0] != MBOX_COMMAND_COMPLETE) {
-                               printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
-                                      qpti->qpti_id);
-                               restore_flags(flags);
-                               return 1;
-                       }
-               }
+       }
 
        /* Reset the ISP again. */
        qregs->hcctrl = HCCTRL_RESET;
@@ -530,6 +558,17 @@ __initfunc(static int qlogicpti_load_firmware(struct qlogicpti *qpti))
        qpti->fware_minrev = param[2];
        qpti->fware_micrev = param[3];
 
+       /* Set the clock rate */
+       param[0] = MBOX_SET_CLOCK_RATE;
+       param[1] = qpti->clock;
+       if(qlogicpti_mbox_command(qpti, param, 1) ||
+          (param[0] != MBOX_COMMAND_COMPLETE)) {
+               printk(KERN_EMERG "qlogicpti%d: could not set clock rate.\n",
+                      qpti->qpti_id);
+               restore_flags(flags);
+               return 1;
+       }
+
        if(qpti->is_pti != 0) {
                /* Load scsi initiator ID and interrupt level into sbus static ram. */
                param[0] = MBOX_WRITE_RAM_WORD;
@@ -578,39 +617,6 @@ static int qlogicpti_verify_tmon(struct qlogicpti *qpti)
        return 0;
 }
 
-static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
-{
-       int i;
-
-       qpti->host_param.initiator_scsi_id = qpti->scsi_id;
-       qpti->host_param.bus_reset_delay = 3;
-       qpti->host_param.retry_count = 0;
-       qpti->host_param.retry_delay = 5;
-       qpti->host_param.async_data_setup_time = 3;
-       qpti->host_param.req_ack_active_negation = 1;
-       qpti->host_param.data_line_active_negation = 1;
-       qpti->host_param.data_dma_burst_enable = 1;
-       qpti->host_param.command_dma_burst_enable = 1;
-       qpti->host_param.tag_aging = 8;
-       qpti->host_param.selection_timeout = 250;
-       qpti->host_param.max_queue_depth = 256;
-
-       for(i = 0; i < MAX_TARGETS; i++) {
-               /* disconnect, parity, arq, reneg on reset */
-               qpti->dev_param[i].device_flags = 0xc5;
-               qpti->dev_param[i].execution_throttle = 16;
-               if (qpti->ultra) {
-                       qpti->dev_param[i].synchronous_period = 12;
-                       qpti->dev_param[i].synchronous_offset = 8;
-               } else {
-                       qpti->dev_param[i].synchronous_period = 16;
-                       qpti->dev_param[i].synchronous_offset = 12;
-               }
-               qpti->dev_param[i].device_enable = 1;
-       }
-       qpti->sbits = 1 << qpti->host_param.initiator_scsi_id;
-}
-
 static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
 #ifndef __sparc_v9__
 static void do_qlogicpti_intr_handler_sun4m(int irq, void *dev_id, struct pt_regs *regs);
@@ -629,6 +635,7 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
        int nqptis = 0, nqptis_in_use = 0;
        int qpti_node;
        int is_pti;
+       unsigned int cfreq;
 
        tpnt->proc_dir = &proc_scsi_qlogicpti;
        qptichain = 0;
@@ -735,6 +742,7 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
                                qpti->qdev->reg_addrs[0].reg_size;
 
                        qpti_host->irq = qpti->irq = qpti->qdev->irqs[0];
+                       qpti->gotirq = 0;
 
                        /* On Ultra and S{S1,C2}000 we must always call request_irq for each
                         * qpti, so that imap registers get setup etc.
@@ -757,6 +765,7 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
                                /* XXX Unmap regs, unregister scsi host, free things. */
                                continue;
                        }
+                       qpti->gotirq = 1;
 qpti_irq_acquired:
                        printk("qpti%d: IRQ %s ",
                               qpti->qpti_id, __irq_itoa(qpti->qhost->irq));
@@ -790,6 +799,15 @@ qpti_irq_acquired:
                                bsizes = (DMA_BURST32 - 1);
                        qpti->bursts = bsizes;
 
+                       /* Check for what the clock input to this card is.
+                        * Default to 40Mhz.
+                        */
+                       cfreq = prom_getintdefault(qpti->prom_node,"clock-frequency",40000000);
+                       qpti->clock = (cfreq + 500000)/1000000;
+                       if (qpti->clock == 0) /* bullshit */
+                               qpti->clock = 40;
+
+
                        /* Clear out Scsi_Cmnd array. */
                        memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
 
@@ -809,9 +827,6 @@ qpti_irq_acquired:
 #undef QSIZE
 
 
-                       /* Set adapter and per-device default values. */
-                       qlogicpti_set_hostdev_defaults(qpti);
-                       
                        /* Load the firmware. */
                        if(qlogicpti_load_firmware(qpti))
                                panic("SBUS Qlogic/ISP firmware load failed");
@@ -856,17 +871,15 @@ int qlogicpti_release(struct Scsi_Host *host)
 {
        struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
        struct qlogicpti_regs *qregs = qpti->qregs;
-
        /* Shut up the card. */
        qregs->sbus_ctrl = 0;
-
        /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
-       free_irq(host->irq, qpti);
+       if (qpti->gotirq)
+               free_irq(host->irq, qpti);
        unmapioaddr((unsigned long)qregs);
        /* QLGC,isp doesn't have status reg */
        if (strcmp (qpti->prom_name, "QLGC,isp"))
                unmapioaddr((unsigned long)qpti->sreg);
-
        return 0;
 }
 
@@ -1019,30 +1032,28 @@ static void ourdone(Scsi_Cmnd *Cmnd)
        Cmnd->host_scribble = NULL;
 
        if ((qpti->sbits & (1 << tgt)) == 0) {
-               if (Cmnd->cmnd[0] == 0x12 && host_byte(Cmnd->result) == DID_OK) {
+               int ok = host_byte(Cmnd->result) == DID_OK;
+               if (Cmnd->cmnd[0] == 0x12 && ok) {
                        unsigned char *iqd;
                        if (Cmnd->use_sg == 0) {
                                iqd = ((unsigned char *)Cmnd->buffer);
                        } else {
                                iqd = ((struct scatterlist *) Cmnd->request_buffer)->address;
                        }
-                       /* Tags? */
-                       if (iqd[7] & 0x2) {
-                               qpti->dev_param[tgt].device_flags |= 0x8;
-                       }
-                       /* Sync Mode? */
+                       /* tags handled in midlayer */
+                       /* enable sync mode? */
                        if (iqd[7] & 0x10) {
                                qpti->dev_param[tgt].device_flags |= 0x10;
                        } else {
                                qpti->dev_param[tgt].synchronous_offset = 0;
                                qpti->dev_param[tgt].synchronous_period = 0;
                        }
-                       /* Wide Capable? */
+                       /* are we wide capable? */
                        if (iqd[7] & 0x20) {
                                qpti->dev_param[tgt].device_flags |= 0x20;
                        }
                        qpti->sbits |= (1 << tgt);
-               } else if (host_byte(Cmnd->result) != DID_OK) {
+               } else if (!ok) {
                        qpti->sbits |= (1 << tgt);
                }
        }
@@ -1051,28 +1062,64 @@ static void ourdone(Scsi_Cmnd *Cmnd)
 
 int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
 {
+       unsigned long flags;
        struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->host->hostdata;
-       /* check to see if we're done scanning */
+
+       /*
+        * done checking this host adapter?
+        * If not, then rewrite the command
+        * to finish through ourdone so we
+        * can peek at Inquiry data results.
+        */
+       if (qpti->sbits && qpti->sbits != 0xffff) {
+               Cmnd->host_scribble = (char *) done;
+               return qlogicpti_queuecommand(Cmnd, ourdone);
+       }
+       save_flags(flags); cli();
+
+       /*
+        * We've peeked at all targets for this bus- time
+        * to set parameters for devices for real now.
+        */
        if (qpti->sbits == 0xffff) {
                int i;
-               unsigned long flags;
-               save_flags(flags); cli();
                for(i = 0; i < MAX_TARGETS; i++) {
                        u_short param[6];
                        param[0] = MBOX_SET_TARGET_PARAMS;
                        param[1] = (i << 8);
                        param[2] = (qpti->dev_param[i].device_flags << 8);
-                       param[3] = (qpti->dev_param[i].synchronous_offset << 8)|
-                               qpti->dev_param[i].synchronous_period;
-                       qlogicpti_mbox_command(qpti, param, 0);
+                       if (qpti->dev_param[i].device_flags & 0x10) {
+                               param[3] = (qpti->dev_param[i].synchronous_offset << 8) |
+                                       qpti->dev_param[i].synchronous_period;
+                       } else {
+                               param[3] = 0;
+                       }
+                       (void) qlogicpti_mbox_command(qpti, param, 0);
+               }
+               /*
+                * set to zero so any traverse through ourdone
+                * doesn't start the whole process again,
+                */
+               qpti->sbits = 0;
+       }
+
+       /* check to see if we're done with all adapters... */
+       for (qpti = qptichain; qpti != NULL; qpti = qpti->next) {
+               if (qpti->sbits) {
+                       break;
                }
-               restore_flags(flags);
-               Cmnd->host->hostt->queuecommand = qlogicpti_queuecommand;
-               return qlogicpti_queuecommand(Cmnd, done);
-       } else {
-               Cmnd->host_scribble = (char *) done;
-               return qlogicpti_queuecommand(Cmnd, ourdone);
        }
+
+       /*
+        * if we hit the end of the chain w/o finding adapters still
+        * capability-configuring, then we're done with all adapters
+        * and can rock on..
+        */
+       if (qpti == NULL)
+               Cmnd->host->hostt->queuecommand = qlogicpti_queuecommand;
+
+       restore_flags(flags);
+       return qlogicpti_queuecommand(Cmnd, done);
 }
 
 /*
@@ -1140,7 +1187,7 @@ int qlogicpti_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
        return 0;
 }
 
-static int qlogicpti_return_status(struct Status_Entry *sts)
+static int qlogicpti_return_status(struct Status_Entry *sts, int id)
 {
        int host_status = DID_ERROR;
 
@@ -1195,8 +1242,8 @@ static int qlogicpti_return_status(struct Status_Entry *sts)
                host_status = DID_OK;
                break;
              default:
-               printk(KERN_EMERG "qlogicpti : unknown completion status 0x%04x\n",
-                      sts->completion_status);
+               printk(KERN_EMERG "qpti%d: unknown completion status 0x%04x\n",
+                      id, sts->completion_status);
                host_status = DID_ERROR;
                break;
        }
@@ -1259,7 +1306,8 @@ static __inline__ int qlogicpti_intr_handler(struct qlogicpti *qpti)
                               sizeof(Cmnd->sense_buffer));
 
                if(sts->hdr.entry_type == ENTRY_STATUS)
-                       Cmnd->result = qlogicpti_return_status(sts);
+                       Cmnd->result =
+                           qlogicpti_return_status(sts, qpti->qpti_id);
                else
                        Cmnd->result = DID_ERROR << 16;
 
index 8c920fd042739e3f5db031ec9433a04c8492085a..3c3646b0d86b6b72e31499ac14387da3f88076af 100644 (file)
@@ -483,7 +483,7 @@ struct qlogicpti {
        int                       prom_node;
        char                      prom_name[64];
        int                       irq;
-       char                      differential, ultra;
+       char                      differential, ultra, clock;
        unsigned char             bursts;
        struct  host_param        host_param;
        struct  dev_param         dev_param[MAX_TARGETS];
@@ -496,8 +496,10 @@ struct qlogicpti {
 #define SREG_IMASK                0x0c   /* Interrupt level            */
 #define SREG_SPMASK               0x03   /* Mask for switch pack       */
        unsigned char             swsreg;
-       unsigned char             is_pti; /* Non-zero if this is a PTI board. */
-       unsigned short            sbits;
+       unsigned int    
+               gotirq  :       1,      /* this instance got an irq */
+               is_pti  :       1,      /* Non-zero if this is a PTI board. */
+               sbits   :       16;     /* syncmode known bits */
 };
 
 /* How to twiddle them bits... */
index 2cb9b61639e177c4dc1d420bef059f3899055fa7..7492eb2cdf177819b25f467f8ae307b16bc25b3d 100644 (file)
@@ -297,6 +297,7 @@ static struct dev_info device_list[] =
 {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
 {"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST},
 {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST},
+{"HITACHI","GF-1050","*", BLIST_GHOST},        /* Hitachi SCSI DVD-RAM */
 {"TOSHIBA","CDROM","*", BLIST_ISROM},
 /*
  * Must be at end of list...
index 42ac74a0f5a8e048815ce4667315172a162e240c..dc7aecaf6093944358c144bbe7b7959baf89a70f 100644 (file)
@@ -1,6 +1,6 @@
 /*****************************************************************************
  *
- *      ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.2.x
+ *      ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x
  *
  *      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
  *     proprietors of Hack Central for fine lodging.
  *
  *  Supported devices:
- *  /dev/dsp0-7    standard /dev/dsp device, (mostly) OSS compatible
+ *  /dev/dsp0-3    standard /dev/dsp device, (mostly) OSS compatible
  *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
  *
  *  Hardware Description
  *
  *     A working Maestro setup contains the Maestro chip wired to a 
- *     codec or 2.  In the Maestro we have the APUs, the ASP, and the
+ *     codec or 2.  In the Maestro we have the APUs, the ASSP, and the
  *     Wavecache.  The APUs can be though of as virtual audio routing
  *     channels.  They can take data from a number of sources and perform
  *     basic encodings of the data.  The wavecache is a storehouse for
  *     PCM data.  Typically it deals with PCI and interracts with the
- *     APUs.  The ASP is a wacky DSP like device that ESS is loth
+ *     APUs.  The ASSP is a wacky DSP like device that ESS is loth
  *     to release docs on.  Thankfully it isn't required on the Maestro
  *     until you start doing insane things like FM emulation and surround
  *     encoding.  The codecs are almost always AC-97 compliant codecs, 
  *     but it appears that early Maestros may have had PT101 (an ESS
  *     part?) wired to them.  The only real difference in the Maestro
  *     families is external goop like docking capability, memory for
- *     the ASP, and initialization differences.
+ *     the ASSP, and initialization differences.
  *
  *  Driver Operation
  *
  *     /dev/dsp? device.  2 channels for output, and 4 channels for
  *     input.
  *
- *     For output we maintain a ring buffer of data that we are DMAing
- *     to the card.  In mono operation this is nice and easy.  When
- *     we receive data we tack it onto the ring buffer and make sure
- *     the APU assigned to it is playing over the data.  When we fill
- *     the ring buffer we put the client to sleep until there is
- *     room again.  Easy.
+ *     Each APU can do a number of things, but we only really use
+ *     3 basic functions.  For playback we use them to convert PCM
+ *     data fetched over PCI by the wavecahche into analog data that
+ *     is handed to the codec.  One APU for mono, and a pair for stereo.
+ *     When in stereo, the combination of smarts in the APU and Wavecache
+ *     decide which wavecache gets the left or right channel.
  *
- *     However, this starts to stink when we use stereo.  The APUs
- *     supposedly can decode LRLR packed stereo data, but it
- *     doesn't work.  So we're forced to use dual mono APUs walking over
- *     mono encoded data.  This requires us to split the input from
- *     the client and complicates the buffer maths tremendously.  Ick.
- *
- *     This also pollutes the recording paths as well.  We have to use
- *     2 L/R incoming APUs that are fixed at 16bit/48khz.  We then pipe
- *     these through 2 rate converion apus that mix them down to the
- *     requested frequency and write them to memory through the wavecache.
- *     We also apparently need a 512byte region thats used as temp space 
- *     between the incoming APUs and the rate converters.
+ *     For record we still use the old overly mono system.  For each in
+ *     coming channel the data comes in from the codec, through a 'input'
+ *     APU, through another rate converter APU, and then into memory via
+ *     the wavecache and PCI.  If its stereo, we mash it back into LRLR in
+ *     software.  The pass between the 2 APUs is supposedly what requires us
+ *     to have a 512 byte buffer sitting around in wavecache/memory.
  *
  *     The wavecache makes our life even more fun.  First off, it can
  *     only address the first 28 bits of PCI address space, making it
  *     similar.
  *     
  * History
+ *  v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
+ *     brown bag volume max fix..
+ *  v0.11 - Nov 11 1999 - Zach Brown <zab@redhat.com>
+ *     use proper stereo apu decoding, mmap/write should work.
+ *     make volume sliders more useful, tweak rate calculation.
+ *     fix lame 8bit format reporting bug.  duh. apm apu saving buglet also
+ *     fix maestro 1 clock freq "bug", remove pt101 support
  *  v0.10 - Oct 28 1999 - Zach Brown <zab@redhat.com>
  *     aha, so, sometimes the WP writes a status word to offset 0
  *       from one of the PCMBARs.  rearrange allocation accordingly..
+ *       cheers again to Eric for being a good hacker in investigating this.
  *     Jeroen Hoogervorst submits 7500 fix out of nowhere.  yay.  :)
  *  v0.09 - Oct 23 1999 - Zach Brown <zab@redhat.com>
  *     added APM support.
  *
  * TODO
  *     some people get indir reg timeouts?
- *     anyone have a pt101 codec?
- *     mmap(), but beware stereo encoding nastiness.
- *     actually post pci writes
  *     fix bob frequency
+ *     endianness
  *     do smart things with ac97 2.0 bits.
- *     ugh.. non aligned writes in the middle of a data stream.. ugh
- *     sort out 0x34->0x36 crap in init
  *     docking and dual codecs and 978?
- *     pcm_sync?
- *     actually use LRLR
+ *     leave 54->61 open
  *
  *     it also would be fun to have a mode that would not use pci dma at all
  *     but would copy into the wavecache on board memory and use that 
 /*****************************************************************************/
 
 #include <linux/version.h>
-#include <linux/module.h>
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 
+ #ifdef MODULE
+  #include <linux/module.h>
+  #ifdef MODVERSIONS
+   #include <linux/modversions.h>
+  #endif
+ #endif
  #define DECLARE_WAITQUEUE(QUEUE,INIT) struct wait_queue QUEUE = {INIT, NULL}
  #define wait_queue_head_t struct wait_queue *
  #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)
@@ -240,7 +242,7 @@ static int dsps_order=0;
 #endif
 
 /* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.10"
+#define DRIVER_VERSION "0.12"
 
 #ifndef PCI_VENDOR_ESS
 #define PCI_VENDOR_ESS                 0x125D
@@ -270,8 +272,8 @@ static int dsps_order=0;
 #define DAC_RUNNING            1
 #define ADC_RUNNING            2
 
-#define MAX_DSP_ORDER  3
-#define MAX_DSPS       (1<<3)
+#define MAX_DSP_ORDER  2
+#define MAX_DSPS       (1<<MAX_DSP_ORDER)
 #define NR_DSPS                (1<<dsps_order)
 #define NR_IDRS                32
 
@@ -295,6 +297,11 @@ static const char *card_names[]={
        [TYPE_MAESTRO2E] = "ESS Maestro 2E"
 };
 
+static int clock_freq[]={
+       [TYPE_MAESTRO] = (49152000L / 1024L),
+       [TYPE_MAESTRO2] = (50000000L / 1024L),
+       [TYPE_MAESTRO2E] = (50000000L / 1024L)
+};
 
 /* --------------------------------------------------------------------- */
 
@@ -520,7 +527,7 @@ static u16 maestro_ac97_get(int io, u8 cmd)
        [SOUND_MIXER_BASS] =            0x3232,
        [SOUND_MIXER_TREBLE] =          0x3232,
        [SOUND_MIXER_SPEAKER] =         0x3232,
-       [SOUND_MIXER_MIC] =     0x3232,
+       [SOUND_MIXER_MIC] =     0x8000, /* annoying */
        [SOUND_MIXER_LINE] =    0x3232,
        [SOUND_MIXER_CD] =      0x3232,
        [SOUND_MIXER_VIDEO] =   0x3232,
@@ -598,6 +605,23 @@ static int ac97_read_mixer(struct ess_card *card, int mixer)
 /* write the OSS encoded volume to the given OSS encoded mixer,
        again caller's job to make sure all is well in arg land,
        call with spinlock held */
+       
+/* linear scale -> log */
+unsigned char lin2log[101] = 
+{
+0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
+50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
+63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 ,
+72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 ,
+78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 ,
+83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 ,
+87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 ,
+90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 ,
+93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 ,
+95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 ,
+97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99 
+};
+
 static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right)
 {
        u16 val=0;
@@ -613,12 +637,13 @@ static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left,
                        right = (right * mh->scale) / 100;
                        left = (left * mh->scale) / 100;
                        if ((left == 0) && (right == 0))
-                               val |= 0x8000; 
-               } else {
-                       right = ((100 - right) * mh->scale) / 100;
-                       left = ((100 - left) * mh->scale) / 100;
-                       if((left == mh->scale) && (right == mh->scale))
                                val |= 0x8000;
+               } else {
+                       /* log conversion for the stereo controls */
+                       if((left == 0) && (right == 0))
+                               val = 0x8000;
+                       right = ((100 - lin2log[right]) * mh->scale) / 100;
+                       left = ((100 - lin2log[left]) * mh->scale) / 100;
                }
 
                val |= (left << 8) | right;
@@ -771,6 +796,8 @@ static u16 maestro_ac97_init(struct ess_card *card, int iobase)
        return 0;
 }
 
+#if 0  /* there has been 1 person on the planet with a pt101 that we
+       know of.  If they care, they can put this back in :) */
 static u16 maestro_pt101_init(struct ess_card *card,int iobase)
 {
        printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
@@ -791,6 +818,7 @@ static u16 maestro_pt101_init(struct ess_card *card,int iobase)
        maestro_ac97_set(iobase, 0x0E, 0x801F);
        return 0;
 }
+#endif
 
 /* this is very magic, and very slow.. */
 static void 
@@ -1064,13 +1092,12 @@ static void sound_reset(int ioaddr)
 /* sets the play formats of these apus, should be passed the already shifted format */
 static void set_apu_fmt(struct ess_state *s, int apu, int mode)
 {
-       if(mode&ESS_FMT_16BIT) { 
-               s->apu_mode[apu] = 0x10;
-               s->apu_mode[apu+1] = 0x10;
-       } else {
-               s->apu_mode[apu] = 0x30;
-               s->apu_mode[apu+1] = 0x30;
-       }
+       int apu_fmt = 0x10;
+
+       if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20; 
+       if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10; 
+       s->apu_mode[apu]   = apu_fmt;
+       s->apu_mode[apu+1] = apu_fmt;
 }
 
 /* this only fixes the output apu mode to be later set by start_dac and
@@ -1081,18 +1108,21 @@ static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
        set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);
 }
 
-static u16 compute_rate(u32 freq)
+/* this is off by a little bit.. */
+static u32 compute_rate(struct ess_state *s, u32 freq)
 {
-       if(freq==48000)
-               return 0xFFFF;
-       freq<<=16;
-       freq/=48000;
-       return freq;
+       u32 clock = clock_freq[s->card->card_type];     
+
+       if (freq == 48000) return 0x10000;
+
+       return ((freq / clock) <<16 )+  
+               (((freq % clock) << 16) / clock);
 }
 
-static void set_dac_rate(struct ess_state *s, unsigned rate)
+static void set_dac_rate(struct ess_state *s, unsigned int rate)
 {
        u32 freq;
+       int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
 
        if (rate > 48000)
                rate = 48000;
@@ -1101,12 +1131,12 @@ static void set_dac_rate(struct ess_state *s, unsigned rate)
 
        s->ratedac = rate;
 
-       if(!((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT))
-               rate >>= 1; /* who knows */
+       if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))
+               rate >>= 1;
 
 /*     M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/
 
-       freq = compute_rate(rate);
+       freq = compute_rate(s, rate);
        
        /* Load the frequency, turn on 6dB */
        apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|
@@ -1121,14 +1151,15 @@ static void set_adc_rate(struct ess_state *s, unsigned rate)
 {
        u32 freq;
 
-       if (rate > 48000)
-               rate = 48000;
+       /* Sample Rate conversion APUs don't like 0x10000 for their rate */
+       if (rate > 47999)
+               rate = 47999;
        if (rate < 4000)
                rate = 4000;
 
        s->rateadc = rate;
 
-       freq = compute_rate(rate);
+       freq = compute_rate(s, rate);
        
        /* Load the frequency, turn on 6dB */
        apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|
@@ -1233,27 +1264,21 @@ ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size
        /* all maestro sizes are in 16bit words */
        size >>=1;
 
-       /* we're given the full size of the buffer, but
-       in stereo each channel will only play its half */
        if(mode&ESS_FMT_STEREO) {
-               size >>=1; 
                high_apu++;
+               /* only 16/stereo gets size divided */
+               if(mode&ESS_FMT_16BIT)
+                       size>>=1;
        }
        
        for(channel=0; channel <= high_apu; channel++)
        {
-               int i;
-               
-               if(!channel) 
-                       pa = virt_to_bus(buffer);
-               else
-               /* right channel plays its split half.
-                       *2 accomodates for rampant shifting earlier */
-                       pa = virt_to_bus(buffer + size*2);
+               pa = virt_to_bus(buffer);
 
                /* set the wavecache control reg */
                tmpval = (pa - 0x10) & 0xFFF8;
-               if(!(mode & 2)) tmpval |= 4; /* 8bit */ 
+               if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;
+               if(mode & ESS_FMT_STEREO) tmpval |= 2;
                ess->apu_base[channel]=tmpval;
                wave_set_register(ess, ess->apu[channel]<<3, tmpval);
                
@@ -1261,14 +1286,17 @@ ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size
                pa>>=1; /* words */
                
                /* base offset of dma calcs when reading the pointer
-                       on this left one */
+                       on the left one */
                if(!channel) ess->dma_dac.base = pa&0xFFFF;
                
                pa|=0x00400000;                 /* System RAM */
-               
-               /* Begin loading the APU */             
-               for(i=0;i<15;i++)               /* clear all PBRs */
-                       apu_set_register(ess, channel, i, 0x0000);
+
+               /* XXX the 16bit here might not be needed.. */
+               if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {
+                       if(channel) 
+                               pa|=0x00800000;                 /* Stereo */
+                       pa>>=1;
+               }
                        
 /* XXX think about endianess when writing these registers */
                M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
@@ -1289,16 +1317,17 @@ ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size
                /* dma on, no envelopes, filter to all 1s) */
                apu_set_register(ess, channel, 0, 0x400F);
                
-               if(mode&ESS_FMT_STEREO)
-                       /* set panning: left or right */
-                       apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
-               else
-                       apu_set_register(ess, channel, 10, 0x8F08);
-
                if(mode&ESS_FMT_16BIT)
                        ess->apu_mode[channel]=0x10;
                else
                        ess->apu_mode[channel]=0x30;
+
+               if(mode&ESS_FMT_STEREO) {
+                       /* set panning: left or right */
+                       apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
+                       ess->apu_mode[channel] += 0x10;
+               } else
+                       apu_set_register(ess, channel, 10, 0x8F08);
        }
        
        /* clear WP interupts */
@@ -1659,29 +1688,20 @@ static __inline__ void
 clear_advance(struct ess_state *s)
 {
        unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
+       
        unsigned char *buf = s->dma_dac.rawbuf;
        unsigned bsize = s->dma_dac.dmasize;
-       /* swptr is always in bytes as read from an apu.. */
        unsigned bptr = s->dma_dac.swptr;
        unsigned len = s->dma_dac.fragsize;
-       int i=1;
-
-       if((s->fmt >> ESS_DAC_SHIFT)  & ESS_FMT_STEREO) {
-               i++;
-               bsize >>=1;
-       }
-               
-       for ( ;i; i-- , buf += bsize) {
-
-               if (bptr + len > bsize) {
-                       unsigned x = bsize - bptr;
-                       memset(buf + bptr, c, x);
-                       /* account for wrapping? */
-                       bptr = 0;
-                       len -= x;
-               }
-               memset(buf + bptr, c, len);
+       
+       if (bptr + len > bsize) {
+               unsigned x = bsize - bptr;
+               memset(buf + bptr, c, x);
+               /* account for wrapping? */
+               bptr = 0;
+               len -= x;
        }
+       memset(buf + bptr, c, len);
 }
 
 /* call with spinlock held! */
@@ -1724,8 +1744,13 @@ ess_update_ptr(struct ess_state *s)
        }
        /* update DAC pointer */
        if (s->dma_dac.ready) {
-               /* this is so gross.  */
-               hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize; 
+               hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
+               /* the apu only reports the length it has seen, not the
+                       length of the memory that has been used (the WP
+                       knows that */
+               if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
+                       hwptr<<=1;
+
                diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
 /*             M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
                s->dma_dac.hwptr = hwptr;
@@ -2189,42 +2214,6 @@ rec_return_free:
        return ret;
 }
 
-/* god this is gross..*/
-/* again, the mode passed is shifted/masked */
-static int 
-split_stereo(unsigned char *real_buffer,unsigned char  *tmp_buffer, int offset, 
-       int count, int bufsize, int mode)
-{  
-       /* oh, bother.  stereo decoding APU's don't work in 16bit so we
-       use dual linear decoders.  which means we have to hack up stereo
-       buffer's we're given.  yuck.  */
-
-       unsigned char *so,*left,*right;
-       int i;
-
-       so = tmp_buffer;
-       left = real_buffer + offset;
-       right = real_buffer + bufsize/2 + offset;
-
-       if(mode & ESS_FMT_16BIT) {
-               for(i=count/4; i ; i--) {
-                       *(right++) = (*(so+2));
-                       *(right++) = (*(so+3));
-                       *(left++) = (*so);
-                       *(left++) = (*(so+1));
-                       so+=4;
-               }
-       } else {
-               for(i=count/2; i ; i--) {
-                       *(right++) = (*(so+1));
-                       *(left++) = (*so);
-                       so+=2;
-               }
-       }
-
-       return 0;
-}
-
 static ssize_t 
 ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
@@ -2232,9 +2221,7 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
        ssize_t ret;
        unsigned long flags;
        unsigned swptr;
-       unsigned char *splitbuf = NULL;
        int cnt;
-       int mode = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
        
        VALIDATE_STATE(s);
        if (ppos != &file->f_pos)
@@ -2245,9 +2232,6 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                return ret;
        if (!access_ok(VERIFY_READ, buffer, count))
                return -EFAULT;
-       /* XXX be more clever than this.. */
-       if (!(splitbuf = kmalloc(count,GFP_KERNEL)))
-               return -ENOMEM; 
        ret = 0;
 
        calc_bob_rate(s);
@@ -2261,12 +2245,8 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                }
                swptr = s->dma_dac.swptr;
 
-               if(mode & ESS_FMT_STEREO) {
-                       /* in stereo we have the 'dual' buffers.. */
-                       cnt = ((s->dma_dac.dmasize/2)-swptr)*2;
-               } else {
-                       cnt = s->dma_dac.dmasize-swptr;
-               }
+               cnt = s->dma_dac.dmasize-swptr;
+
                if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
                        cnt = s->dma_dac.dmasize - s->dma_dac.count;
 
@@ -2275,10 +2255,6 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                if (cnt > count)
                        cnt = count;
 
-               /* our goofball stereo splitter can only deal in mults of 4 */
-               if (cnt > 0) 
-                       cnt &= ~3;
-
                if (cnt <= 0) {
                        start_dac(s);
                        if (file->f_flags & O_NONBLOCK) {
@@ -2308,26 +2284,13 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                        }
                        continue;
                }
-               if(mode & ESS_FMT_STEREO) {
-                       if (copy_from_user(splitbuf, buffer, cnt)) {
-                               if (!ret) ret = -EFAULT;
-                               goto return_free;
-                       }
-                       split_stereo(s->dma_dac.rawbuf,splitbuf,swptr,cnt,s->dma_dac.dmasize,
-                               mode);
-               } else {
-                       if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
-                               if (!ret) ret = -EFAULT;
-                               goto return_free;
-                       }
+               if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+                       if (!ret) ret = -EFAULT;
+                       goto return_free;
                }
 
-               if(mode & ESS_FMT_STEREO) {
-                       /* again with the weird pointer magic */
-                       swptr = (swptr + (cnt/2)) % (s->dma_dac.dmasize/2);
-               } else {
-                       swptr = (swptr + cnt) % s->dma_dac.dmasize;
-               }
+               swptr = (swptr + cnt) % s->dma_dac.dmasize;
+
                spin_lock_irqsave(&s->lock, flags);
                s->dma_dac.swptr = swptr;
                s->dma_dac.count += cnt;
@@ -2339,7 +2302,6 @@ ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
                start_dac(s);
        }
 return_free:
-       if (splitbuf) kfree(splitbuf);
        return ret;
 }
 
@@ -2373,8 +2335,6 @@ static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
        return mask;
 }
 
-/* this needs to be fixed to deal with the dual apus/buffers */
-#if 0
 static int ess_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct ess_state *s = (struct ess_state *)file->private_data;
@@ -2387,11 +2347,16 @@ static int ess_mmap(struct file *file, struct vm_area_struct *vma)
                if ((ret = prog_dmabuf(s, 1)) != 0)
                        return ret;
                db = &s->dma_dac;
-       } else if (vma->vm_flags & VM_READ) {
+       } else 
+#if 0
+       /* if we can have the wp/wc do the combining
+               we can turn this back on.  */
+             if (vma->vm_flags & VM_READ) {
                if ((ret = prog_dmabuf(s, 0)) != 0)
                        return ret;
                db = &s->dma_adc;
-       } else 
+       } else  
+#endif
                return -EINVAL;
        if (vma->vm_offset != 0)
                return -EINVAL;
@@ -2403,7 +2368,6 @@ static int ess_mmap(struct file *file, struct vm_area_struct *vma)
        db->mapped = 1;
        return 0;
 }
-#endif
 
 static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -2433,7 +2397,7 @@ static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                return 0;
 
        case SNDCTL_DSP_GETCAPS:
-               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER /*| DSP_CAP_MMAP*/, (int *)arg);
+               return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
                
         case SNDCTL_DSP_RESET:
                if (file->f_mode & FMODE_WRITE) {
@@ -2514,7 +2478,7 @@ static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                                           : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
                
        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
+                return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg);
                
        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
                get_user_ret(val, (int *)arg, -EFAULT);
@@ -2547,7 +2511,7 @@ static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                        (ESS_FMT_16BIT << ESS_ADC_SHIFT) 
                        : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 
                                AFMT_S16_LE : 
-                               AFMT_S8, 
+                               AFMT_U8, 
                        (int *)arg);
                
        case SNDCTL_DSP_POST:
@@ -2937,7 +2901,7 @@ static struct file_operations ess_audio_fops = {
        NULL,  /* readdir */
        &ess_poll,
        &ess_ioctl,
-       NULL,   /* XXX &ess_mmap, */
+       &ess_mmap,
        &ess_open,
        NULL,   /* flush */
        &ess_release,
@@ -2999,7 +2963,7 @@ maestro_config(struct ess_card *card)
        w&=~(1<<7);             /* HWV off */
        w&=~(1<<6);             /* Debounce off */
        w&=~(1<<5);             /* GPIO 4:5 */
-       w|= (1<<4);             /* Disconnect from the CHI.  Enabling this in made a dell 7500 work. */
+       w|= (1<<4);             /* Disconnect from the CHI.  Enabling this made a dell 7500 work. */
        w&=~(1<<3);             /* IDMA off (undocumented) */
        w&=~(1<<2);             /* MIDI fix off (undoc) */
        w&=~(1<<1);             /* reserved, always write 0 */
@@ -3302,7 +3266,8 @@ maestro_install(struct pci_dev *pcidev, int card_type)
        maestro_config(card);
 
        if(maestro_ac97_get(iobase, 0x00)==0x0080) {
-               maestro_pt101_init(card,iobase);
+               printk(KERN_ERR "maestro: my goodness!  you seem to have a pt101 codec, which is quite rare.\n"
+                               "\tyou should tell someone about this.\n");
        } else {
                maestro_ac97_init(card,iobase);
        }
@@ -3450,7 +3415,7 @@ check_suspend(void)
 }
 
 static int 
-maestro_apm_suspend(void)
+maestro_suspend(void)
 {
        struct ess_card *card;
        unsigned long flags;
@@ -3473,7 +3438,7 @@ maestro_apm_suspend(void)
                        stop_dac(s);
                        stop_adc(s);
                        for(j=0;j<6;j++) 
-                               card->apu_map[s->apu[i]][5]=apu_get_register(s,i,5);
+                               card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5);
 
                }
 
@@ -3490,7 +3455,7 @@ maestro_apm_suspend(void)
        return 0;
 }
 static int 
-maestro_apm_resume(void)
+maestro_resume(void)
 {
        struct ess_card *card;
        unsigned long flags;
@@ -3564,11 +3529,11 @@ maestro_apm_callback(apm_event_t ae) {
        case APM_SYS_SUSPEND: 
        case APM_CRITICAL_SUSPEND: 
        case APM_USER_SUSPEND: 
-               maestro_apm_suspend();break;
+               maestro_suspend();break;
        case APM_NORMAL_RESUME: 
        case APM_CRITICAL_RESUME: 
        case APM_STANDBY_RESUME: 
-               maestro_apm_resume();break;
+               maestro_resume();break;
        default: break;
        }
 
index 5698fcd674dd875c47485cb12fce9a0b57a1dd57..634f838627145551fc1faf83e24d94a44d69723b 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.106.2.4 1999/09/02 06:34:46 paulus Exp $
+/*  $Id: atyfb.c,v 1.106.2.6 1999/10/14 08:44:47 davem Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *     Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -227,8 +227,8 @@ struct fb_info_aty {
     } fbcon_cmap;
     u8 blitter_may_be_busy;
 #ifdef __sparc__
-    u8 open;
     u8 mmaped;
+    int open;
     int vtconsole;
     int consolecnt;
 #endif
@@ -1896,10 +1896,8 @@ static int atyfb_open(struct fb_info *info, int user)
     struct fb_info_aty *fb = (struct fb_info_aty *)info;
 
     if (user) {
-       if (fb->open)
-           return -EBUSY;
+       fb->open++;
        fb->mmaped = 0;
-       fb->open = 1;
        fb->vtconsole = -1;
     } else {
        fb->consolecnt++;
@@ -1909,17 +1907,54 @@ static int atyfb_open(struct fb_info *info, int user)
     return(0);
 }
 
+struct fb_var_screeninfo default_var = {
+    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+    640, 480, 640, 480, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+    0, FB_VMODE_NONINTERLACED
+};
+
 static int atyfb_release(struct fb_info *info, int user)
 {
 #ifdef __sparc__
     struct fb_info_aty *fb = (struct fb_info_aty *)info;
 
     if (user) {
-       if (fb->vtconsole != -1)
-           vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
-       fb->open = 0;
-       fb->mmaped = 0;
-       fb->vtconsole = -1;
+       fb->open--;
+       udelay(1000);
+       wait_for_idle(fb);
+       if (!fb->open) {
+               int was_mmaped = fb->mmaped;
+
+               fb->mmaped = 0;
+               if (fb->vtconsole != -1)
+                       vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
+               fb->vtconsole = -1;
+
+               if (was_mmaped) {
+                       struct fb_var_screeninfo var;
+
+                       /* Now reset the default display config, we have no
+                        * idea what the program(s) which mmap'd the chip did
+                        * to the configuration, nor whether it restored it
+                        * correctly.
+                        */
+                       var = default_var;
+                       if (noaccel)
+                               var.accel_flags &= ~FB_ACCELF_TEXT;
+                       else
+                               var.accel_flags |= FB_ACCELF_TEXT;
+                       if (var.yres == var.yres_virtual) {
+                               u32 vram = (fb->total_vram - (PAGE_SIZE << 2));
+                               var.yres_virtual = ((vram * 8) / var.bits_per_pixel) /
+                                       var.xres_virtual;
+                               if (var.yres_virtual < var.yres)
+                                       var.yres_virtual = var.yres;
+                       }
+                       atyfb_set_var(&var, -1, &fb->fb_info);
+               }
+       }
     } else {
        fb->consolecnt--;
     }
@@ -1982,15 +2017,6 @@ static int encode_fix(struct fb_fix_screeninfo *fix,
 }
 
 
-struct fb_var_screeninfo default_var = {
-    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
-    640, 480, 640, 480, 0, 0, 8, 0,
-    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
-    0, FB_VMODE_NONINTERLACED
-};
-
-
     /*
      *  Get the Fixed Part of the Display
      */
index d36acc17ef5d0ec7c289bac901171f7416dceabc..e87427a5301bde140cd97d9485a0edf0017a0941 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bwtwofb.c,v 1.7.2.1 1999/08/26 05:21:13 shadow Exp $
+/* $Id: bwtwofb.c,v 1.7.2.3 1999/10/06 10:52:36 anton Exp $
  * bwtwofb.c: BWtwo frame buffer driver
  *
  * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
@@ -224,7 +224,9 @@ char __init *bwtwofb_init(struct fb_info_sbusfb *fb)
 #endif
        fb->margins = bw2_margins;
        
+#ifndef CONFIG_SUN4
        fb->physbase = __get_phys(fb->sbdp->sbus_vaddrs[0]);
+#endif
        fb->mmap_map = bw2_mmap_map;
 
 #ifdef __sparc_v9__
index 1a6c4ee993667cf403bb24f76061e558f99a302e..949dc3bbfed2d793cbec317823b816e6420e3c3c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cgfourteenfb.c,v 1.4 1999/01/26 10:55:03 jj Exp $
+/* $Id: cgfourteenfb.c,v 1.4.2.1 1999/09/28 15:59:58 davem Exp $
  * cgfourteenfb.c: CGfourteen frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
index 6b5d10646745252b185b6ba0f27ff056df510423..0f1f6274f10ab910d8bdf0e4a3eaf261859f65ba 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cgsixfb.c,v 1.16.2.1 1999/05/25 00:59:35 davem Exp $
+/* $Id: cgsixfb.c,v 1.16.2.2 1999/09/28 15:59:55 davem Exp $
  * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
index 82cfb868ded3479b8ea7180ec5a4d9b46ec23b0b..efdc426bdf07b8893ac79ab153c9e871376d5ac1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: cgthreefb.c,v 1.4 1999/01/26 10:55:01 jj Exp $
+/* $Id: cgthreefb.c,v 1.4.2.1 1999/09/28 16:00:08 davem Exp $
  * cgthreefb.c: CGthree frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
index fbda08fc980d343cc7f063e22c6242827cf330ca..54227667b30dc920f7f5d1d56fdd6f9074814537 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: creatorfb.c,v 1.27 1999/03/28 12:37:12 jj Exp $
+/* $Id: creatorfb.c,v 1.27.2.2 1999/11/05 09:07:56 davem Exp $
  * creatorfb.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -539,6 +539,36 @@ static void ffb_revc(struct display *p, int xx, int yy)
        /* Not used if hw cursor */
 }
 
+#if 0
+static void ffb_blank(struct fb_info_sbusfb *fb)
+{
+       struct ffb_dac *dac = fb->s.ffb.dac;
+       unsigned long flags;
+       u32 tmp;
+
+       spin_lock_irqsave(&fb->lock, flags);
+       dac->type = 0x6000;
+       tmp = (dac->value & ~0x1);
+       dac->type = 0x6000;
+       dac->value = tmp;
+       spin_unlock_irqrestore(&fb->lock, flags);
+}
+#endif
+
+static void ffb_unblank(struct fb_info_sbusfb *fb)
+{
+       struct ffb_dac *dac = fb->s.ffb.dac;
+       unsigned long flags;
+       u32 tmp;
+
+       spin_lock_irqsave(&fb->lock, flags);
+       dac->type = 0x6000;
+       tmp = (dac->value | 0x1);
+       dac->type = 0x6000;
+       dac->value = tmp;
+       spin_unlock_irqrestore(&fb->lock, flags);
+}
+
 static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
 {
        struct ffb_dac *dac = fb->s.ffb.dac;
@@ -726,6 +756,16 @@ __initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb))
        fb->setcurshape = ffb_setcurshape;
        fb->switch_from_graph = ffb_switch_from_graph;
        fb->fill = ffb_fill;
+#if 0
+       /* XXX Can't enable this for now, I've seen cases
+        * XXX where the VC was blanked, and Xsun24 was started
+        * XXX via a remote login, the sunfb code did not
+        * XXX unblank creator when it was mmap'd for some
+        * XXX reason, investigate later... -DaveM
+        */
+       fb->blank = ffb_blank;
+       fb->unblank = ffb_unblank;
+#endif
        
        /* If there are any read errors or fifo overflow conditions,
         * clear them now.
@@ -755,5 +795,12 @@ __initfunc(char *creatorfb_init(struct fb_info_sbusfb *fb))
        if (afb)
                fb->s.ffb.dac_rev = 10;
        
+       /* Unblank it just to be sure.  When there are multiple
+        * FFB/AFB cards in the system, or it is not the OBP
+        * chosen console, it will have video outputs off in
+        * the DAC.
+        */
+       ffb_unblank(fb);
+
        return idstring;
 }
index 24e7ad742b10f255bef61c0389be126c7f24498e..b24707687143d6e76a7f0355750cb358219830ac 100644 (file)
@@ -217,7 +217,7 @@ static int fbcon_is_default = 1;
 static int PROC_CONSOLE(struct fb_info *info)
 {
        int fgc;
-       
+
        if (info->display_fg != NULL)
                fgc = info->display_fg->vc_num;
        else
@@ -353,6 +353,20 @@ static void set_con2fb_map(int unit, int newidx)
        /* tell console var has changed */
        if (newfb->changevar)
           newfb->changevar(unit);
+       /* fixme: this really needs lock protection */
+       conp->vc_display_fg = &newfb->display_fg;
+       if (!newfb->display_fg)
+          newfb->display_fg = conp;
+       if (oldfb != newfb && oldfb->display_fg == conp) {
+          int i;
+          for (i = 0; i < MAX_NR_CONSOLES; i++)
+              if (fb_display[i].conp && con2fb_map[i] == oldidx) {
+                  oldfb->display_fg = fb_display[i].conp;
+                  break;
+              }
+          if (i == MAX_NR_CONSOLES)
+              oldfb->display_fg = NULL;
+       }
     }
 }
 
@@ -447,6 +461,11 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                    for (i = 0; i < MAX_NR_CONSOLES; i++)
                        set_con2fb_map(i, con2fb.framebuffer);
                return 0;
+       case FBIOBLANK:
+               if (info->blank == 0)
+                       return -EINVAL;
+               (*info->blank)(arg, info);
+               return 0;
        default:
                return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info),
                                    info);
@@ -468,12 +487,16 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
                return -ENODEV;
        if (fb->fb_mmap)
                return fb->fb_mmap(info, file, vma);
+#if defined(__sparc__) && !defined(__sparc_v9__)
+       /* Should never get here, all fb drivers should have their own
+          mmap routines */
+       return -EINVAL;
+#else
        fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
 
        /* frame buffer memory */
        start = (unsigned long)fix.smem_start;
        len = (start & ~PAGE_MASK)+fix.smem_len;
-       start &= PAGE_MASK;
        len = (len+~PAGE_MASK) & PAGE_MASK;
        if (vma->vm_offset >= len) {
                /* memory mapped io */
@@ -483,14 +506,37 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
                        return -EINVAL;
                start = (unsigned long)fix.mmio_start;
                len = (start & ~PAGE_MASK)+fix.mmio_len;
-               start &= PAGE_MASK;
                len = (len+~PAGE_MASK) & PAGE_MASK;
        }
+       start &= PAGE_MASK;
        if ((vma->vm_end - vma->vm_start + vma->vm_offset) > len)
                return -EINVAL;
        vma->vm_offset += start;
        if (vma->vm_offset & ~PAGE_MASK)
                return -ENXIO;
+#if defined(__sparc_v9__)
+       vma->vm_flags |= (VM_SHM | VM_LOCKED);
+       {
+               unsigned long align, j;
+               for (align = 0x400000; align > PAGE_SIZE; align >>= 3)
+                       if (len >= align && !((start & ~PAGE_MASK) & (align - 1)))
+                               break;
+               if (align > PAGE_SIZE && vma->vm_start & (align - 1)) {
+                       /* align as much as possible */
+                       struct vm_area_struct *vmm;
+                       j = (-vma->vm_start) & (align - 1);
+                       vmm = find_vma(current->mm, vma->vm_start);
+                       if (!vmm || vmm->vm_start >= vma->vm_end + j) {
+                               vma->vm_start += j;
+                               vma->vm_end += j;
+                       }
+               }
+       }
+       if (io_remap_page_range(vma->vm_start, vma->vm_offset,
+                               vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
+               return -EAGAIN;
+       vma->vm_flags |= VM_IO;
+#else
 #if defined(__mc68000__)
        if (CPU_IS_020_OR_030)
                pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
@@ -503,9 +549,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
        pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
 #elif defined(__alpha__)
        /* Caching is off in the I/O space quadrant by design.  */
-#elif defined(__sparc__)
-       /* Should never get here, all fb drivers should have their own
-          mmap routines */
 #elif defined(__i386__)
        if (boot_cpu_data.x86 > 3)
                pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
@@ -525,7 +568,9 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
        if (remap_page_range(vma->vm_start, vma->vm_offset,
                             vma->vm_end - vma->vm_start, vma->vm_page_prot))
                return -EAGAIN;
+#endif /* !__sparc_v9__ */
        return 0;
+#endif /* ! sparc32 */
 }
 
 static int
index b8bfb44baba3af9dfaef9d11a188dea10f807dea..bf565aef2f037610cd237b95d26d7e6092beb1ed 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: leofb.c,v 1.6 1999/04/01 13:03:25 jj Exp $
+/* $Id: leofb.c,v 1.6.2.1 1999/09/28 16:00:03 davem Exp $
  * leofb.c: Leo (ZX) 24/8bit frame buffer driver
  *
  * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz)
index dfb0f8ae819abe21468985259b73232084e9128c..af849e4b9d441fd218658d2c9764614a09f63bf2 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Permedia2 framebuffer driver.
  * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
  * Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven.
  * --------------------------------------------------------------------------
  * $Id: pm2fb.c,v 1.163 1999/02/21 14:06:49 illo Exp $
 #include <video/fbcon-cfb32.h>
 #include "pm2fb.h"
 #include "cvisionppc.h"
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/fbio.h>
+#endif
 
 #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
 #error "The endianness of the target host has not been defined."
 #endif
 
+#if defined(__BIG_ENDIAN) && !defined(__sparc__)
+#define PM2FB_BE_APERTURE
+#endif
+
+/* Need to debug this some more */
+#undef PM2FB_HW_CURSOR
+
 #if defined(CONFIG_FB_PM2_PCI) && !defined(CONFIG_PCI)
 #undef CONFIG_FB_PM2_PCI
 #warning "support for Permedia2 PCI boards with no generic PCI support!"
 #endif
 
-#define PM2FB_MASTER_DEBUG
+#undef PM2FB_MASTER_DEBUG
 #ifdef PM2FB_MASTER_DEBUG
 #define DPRINTK(a,b...)        printk("pm2fb: %s: " a, __FUNCTION__ , ## b)
 #else
@@ -102,12 +114,20 @@ struct pm2fb_par {
 #define OPTF_OLD_MEM           (1L<<0)
 #define OPTF_YPAN              (1L<<1)
 #define OPTF_VIRTUAL           (1L<<2)
+#define OPTF_USER              (1L<<3)
 static struct {
        char font[40];
        u32 flags;
        struct pm2fb_par user_mode;
 } pm2fb_options =
+#ifdef __sparc__
+       /* For some reason Raptor is not happy with the low-end mode */
+       {"\0", 0L, {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}};
+#else
        {"\0", 0L, {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}};
+#endif
+
+static char curblink __initdata = 1;
 
 static const struct {
        char name[16];
@@ -185,12 +205,30 @@ struct pm2pci_par {
 };
 #endif
 
+#define DEFAULT_CURSOR_BLINK_RATE       (20)
+#define CURSOR_DRAW_DELAY               (2)
+
+struct pm2_cursor {
+    int        enable;
+    int on;
+    int vbl_cnt;
+    int blink_rate;
+    struct {
+        u16 x, y;
+    } pos, hot, size;
+    u8 color[6];
+    u8 bits[8][64];
+    u8 mask[8][64];
+    struct timer_list *timer;
+};
+
 static const char permedia2_name[16]="Permedia2";
 
 static struct pm2fb_info {
        struct fb_info_gen gen;
        int board;                      /* Permedia2 board index (see
                                           board_table[] below) */
+       pm2type_t type;
        struct {
                unsigned char* fb_base; /* framebuffer memory base */
                u32 fb_size;            /* framebuffer memory size */
@@ -233,6 +271,7 @@ static struct pm2fb_info {
                u32 cmap32[16];
 #endif
        } cmap;
+       struct pm2_cursor *cursor;
 } fb_info;
 
 #ifdef CONFIG_FB_PM2_CVPPC
@@ -245,6 +284,18 @@ static int pm2pci_detect(struct pm2fb_info*);
 static void pm2pci_init(struct pm2fb_info*);
 #endif
 
+#ifdef PM2FB_HW_CURSOR
+static void pm2fb_cursor(struct display *p, int mode, int x, int y);
+static int pm2fb_set_font(struct display *d, int width, int height);
+static struct pm2_cursor *pm2_init_cursor(struct pm2fb_info *fb);
+static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue);
+static void pm2v_set_cursor_shape(struct pm2fb_info *fb);
+static u8 cursor_color_map[2] = { 0, 0xff };
+#else
+#define pm2fb_cursor NULL
+#define pm2fb_set_font NULL
+#endif
+
 /*
  * Table of the supported Permedia2 based boards.
  * Three hooks are defined for each board:
@@ -334,7 +385,7 @@ static int pm2fb_release(struct fb_info* info, int user);
 static struct fb_ops pm2fb_ops={
        pm2fb_open, pm2fb_release, fbgen_get_fix, fbgen_get_var,
        fbgen_set_var, fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display,
-       NULL /* fb_ioctl() */, NULL /* fb_mmap() */
+       NULL /* fb_ioctl() */, NULL /* fb_mmap() */, NULL /* fb_rasterimg */,
 };
 
 /***************************************************************************
@@ -363,17 +414,50 @@ inline static void pm2_WR(struct pm2fb_info* p, s32 off, u32 v) {
 
 inline static u32 pm2_RDAC_RD(struct pm2fb_info* p, s32 idx) {
 
-       pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+       int index = PM2R_RD_INDEXED_DATA;
+       switch (p->type) {
+       case PM2_TYPE_PERMEDIA2:
+               pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+               break;
+       case PM2_TYPE_PERMEDIA2V:
+               pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+               index = PM2VR_RD_INDEXED_DATA;
+               break;
+       }       
        DEFRW();
-       return pm2_RD(p, PM2R_RD_INDEXED_DATA);
+       return pm2_RD(p, index);
 }
 
 inline static void pm2_RDAC_WR(struct pm2fb_info* p, s32 idx,
                                                u32 v) {
 
-       pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
-       DEFW();
-       pm2_WR(p, PM2R_RD_INDEXED_DATA, v);
+       int index = PM2R_RD_INDEXED_DATA;
+       switch (p->type) {
+       case PM2_TYPE_PERMEDIA2:
+               pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+               break;
+       case PM2_TYPE_PERMEDIA2V:
+               pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+               index = PM2VR_RD_INDEXED_DATA;
+               break;
+       }       
+       DEFRW();
+       pm2_WR(p, index, v);
+}
+
+inline static u32 pm2v_RDAC_RD(struct pm2fb_info* p, s32 idx) {
+
+       pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+       DEFRW();
+       return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
+}
+
+inline static void pm2v_RDAC_WR(struct pm2fb_info* p, s32 idx,
+                                               u32 v) {
+
+       pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
+       DEFRW();
+       pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
 }
 
 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
@@ -435,8 +519,8 @@ static u32 from3264(u32 timing, int bpp, int is64) {
        return timing;
 }
 
-static void mnp(u32 clk, unsigned char* mm, unsigned char* nn,
-                                                       unsigned char* pp) {
+static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
+               unsigned char* pp) {
        unsigned char m;
        unsigned char n;
        unsigned char p;
@@ -463,6 +547,30 @@ static void mnp(u32 clk, unsigned char* mm, unsigned char* nn,
        }
 }
 
+static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
+               unsigned char* pp) {
+       unsigned char m;
+       unsigned char n;
+       unsigned char p;
+       u32 f;
+       s32 delta=1000;
+
+       *mm=*nn=*pp=0;
+       for (n=1; n; n++) {
+               for (m=1; m; m++) {
+                       for (p=0; p<2; p++) {
+                               f=PM2_REFERENCE_CLOCK*n/(m * (1<<(p+1)));
+                               if (clk>f-delta && clk<f+delta) {
+                                       delta=clk>f?clk-f:f-clk;
+                                       *mm=m;
+                                       *nn=n;
+                                       *pp=p;
+                               }
+                       }
+               }
+       }
+}
+
 static void wait_pm2(struct pm2fb_info* i) {
 
        WAIT_FIFO(i, 1);
@@ -474,12 +582,12 @@ static void wait_pm2(struct pm2fb_info* i) {
        } while (pm2_RD(i, PM2R_OUT_FIFO)!=PM2TAG(PM2R_SYNC));
 }
 
-static void set_memclock(struct pm2fb_info* info, u32 clk) {
+static void pm2_set_memclock(struct pm2fb_info* info, u32 clk) {
        int i;
        unsigned char m, n, p;
 
-       mnp(clk, &m, &n, &p);
-       WAIT_FIFO(info, 5);
+       pm2_mnp(clk, &m, &n, &p);
+       WAIT_FIFO(info, 10);
        pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 6);
        DEFW();
        pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_1, m);
@@ -493,23 +601,36 @@ static void set_memclock(struct pm2fb_info* info, u32 clk) {
                !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
 }
 
-static void set_pixclock(struct pm2fb_info* info, u32 clk) {
+static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) {
        int i;
        unsigned char m, n, p;
 
-       mnp(clk, &m, &n, &p);
-       WAIT_FIFO(info, 5);
-       pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
-       DEFW();
-       pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
-       pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n);
-       DEFW();
-       pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
-       DEFW();
-       pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
-       DEFR();
-       for (i=256; i &&
-               !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
+       switch (info->type) {
+       case PM2_TYPE_PERMEDIA2:
+               pm2_mnp(clk, &m, &n, &p);
+               WAIT_FIFO(info, 10);
+               pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
+               DEFW();
+               pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
+               pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n);
+               DEFW();
+               pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
+               DEFW();
+               pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
+               DEFR();
+               for (i=256; i &&
+                    !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
+               break;
+       case PM2_TYPE_PERMEDIA2V:
+               pm2v_mnp(clk/2, &m, &n, &p);
+               WAIT_FIFO(info, 8);
+               pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
+               pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m);
+               pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n);
+               pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p);
+               pm2_WR(info, PM2VR_RD_INDEX_HIGH, 0);
+               break;
+       }
 }
 
 static void clear_palette(struct pm2fb_info* p) {
@@ -543,7 +664,7 @@ static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
 
        WAIT_FIFO(i, 2);
 #ifdef __LITTLE_ENDIAN
-       pm2_WR(i, PM2R_APERTURE_ONE, 0);        /* FIXME */
+       pm2_WR(i, PM2R_APERTURE_ONE, 0);
        pm2_WR(i, PM2R_APERTURE_TWO, 0);
 #else
        switch (p->depth) {
@@ -567,32 +688,46 @@ static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
 static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
        u32 clrmode=0;
        u32 txtmap=0;
+       u32 pixsize=0;
+       u32 clrformat=0;
        u32 xres;
+       u32 video, tmp;
 
+       if (i->type == PM2_TYPE_PERMEDIA2V) {
+               WAIT_FIFO(i, 1);
+               pm2_WR(i, PM2VR_RD_INDEX_HIGH, 0);
+       }
        xres=(p->width+31)&~31;
        set_aperture(i, p);
        DEFRW();
-       WAIT_FIFO(i, 22);
+       WAIT_FIFO(i, 27);
        pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0:
                                                PM2F_COLOR_KEY_TEST_OFF);
        switch (p->depth) {
                case 8:
                        pm2_WR(i, PM2R_FB_READ_PIXEL, 0);
+                       clrformat=0x0e;
                        break;
                case 16:
                        pm2_WR(i, PM2R_FB_READ_PIXEL, 1);
                        clrmode=PM2F_RD_TRUECOLOR|0x06;
                        txtmap=PM2F_TEXTEL_SIZE_16;
+                       pixsize=1;
+                       clrformat=0x70;
                        break;
                case 32:
                        pm2_WR(i, PM2R_FB_READ_PIXEL, 2);
                        clrmode=PM2F_RD_TRUECOLOR|0x08;
                        txtmap=PM2F_TEXTEL_SIZE_32;
+                       pixsize=2;
+                       clrformat=0x20;
                        break;
                case 24:
                        pm2_WR(i, PM2R_FB_READ_PIXEL, 4);
                        clrmode=PM2F_RD_TRUECOLOR|0x09;
                        txtmap=PM2F_TEXTEL_SIZE_24;
+                       pixsize=4;
+                       clrformat=0x20;
                        break;
        }
        pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
@@ -613,10 +748,34 @@ static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
        pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride);
        DEFW();
        pm2_WR(i, PM2R_SCREEN_BASE, p->base);
-       pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
-                                               PM2F_RD_GUI_ACTIVE|clrmode);
-       pm2_WR(i, PM2R_VIDEO_CONTROL, p->video);
-       set_pixclock(i, p->pixclock);
+       /* HW cursor needs /VSYNC for recognizing vert retrace */
+       video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW);
+       video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
+       switch (i->type) {
+       case PM2_TYPE_PERMEDIA2:
+               tmp = PM2F_RD_PALETTE_WIDTH_8;
+               pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
+                                                  PM2F_RD_GUI_ACTIVE|clrmode);
+               if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
+                       tmp |= 4; /* invert hsync */
+               if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
+                       tmp |= 8; /* invert vsync */
+               pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
+               break;
+       case PM2_TYPE_PERMEDIA2V:
+               tmp = 0;
+               pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
+               pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
+               if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
+                       tmp |= 1; /* invert hsync */
+               if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
+                       tmp |= 4; /* invert vsync */
+               pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
+               pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
+               break;
+       }
+       pm2_WR(i, PM2R_VIDEO_CONTROL, video);
+       pm2_set_pixclock(i, p->pixclock);
 };
 
 /*
@@ -682,6 +841,8 @@ static void pm2fb_block_op(struct pm2fb_info* i, int copy,
 
 static void pm2fb_reset(struct pm2fb_info* p) {
 
+       if (p->type == PM2_TYPE_PERMEDIA2V)
+               pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
        pm2_WR(p, PM2R_RESET_STATUS, 0);
        DEFRW();
        while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
@@ -729,8 +890,16 @@ static void pm2fb_reset(struct pm2fb_info* p) {
        pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
        pm2_WR(p, PM2R_STATISTICS_MODE, 0);
        pm2_WR(p, PM2R_SCISSOR_MODE, 0);
-       pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
-       pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
+       switch (p->type) {
+       case PM2_TYPE_PERMEDIA2:
+               pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
+               pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
+               pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
+               break;
+       case PM2_TYPE_PERMEDIA2V:
+               pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
+               break;
+       }
        pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
        pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
        pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
@@ -738,7 +907,7 @@ static void pm2fb_reset(struct pm2fb_info* p) {
        pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
        clear_palette(p);
        if (p->memclock)
-               set_memclock(p, p->memclock);
+               pm2_set_memclock(p, p->memclock);
 }
 
 __initfunc(static int pm2fb_conf(struct pm2fb_info* p)) {
@@ -752,12 +921,16 @@ __initfunc(static int pm2fb_conf(struct pm2fb_info* p)) {
        DPRINTK("found board: %s\n", board_table[p->board].name);
        p->regions.p_fb=p->regions.fb_base;
        p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size);
-#ifdef __LITTLE_ENDIAN
+#ifndef PM2FB_BE_APERTURE
        p->regions.p_regs=p->regions.rg_base;
 #else
        p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
 #endif
        p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE);
+
+#ifdef PM2FB_HW_CURSOR
+       p->cursor = pm2_init_cursor(p);
+#endif
        return 1;
 }
 
@@ -805,10 +978,11 @@ static int cvppc_PCI_init(struct cvppc_par* p) {
        return 1;
 }
 
-static int cvppc_detect(struct pm2fb_info* p) {
+static int __init cvppc_detect(struct pm2fb_info* p) {
 
        if (!cvppc_PCI_init(&p->board_par.cvppc))
                return 0;
+       p->type = PM2_TYPE_PERMEDIA2;
        p->regions.fb_base=(unsigned char* )CVPPC_FB_APERTURE_ONE;
        p->regions.fb_size=CVPPC_FB_SIZE;
        p->regions.rg_base=(unsigned char* )CVPPC_REGS_REGION;
@@ -833,9 +1007,25 @@ static void cvppc_init(struct pm2fb_info* p) {
  * Generic PCI detection routines
  */
 #ifdef CONFIG_FB_PM2_PCI
-static int pm2pci_detect(struct pm2fb_info* p) {
+struct {
+       unsigned short vendor, device;
+       char *name;
+       pm2type_t type;
+} pm2pci_cards[] __initdata = {
+{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
+{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
+{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
+{ 0, 0 }
+};
+
+static int __init pm2pci_detect(struct pm2fb_info* p) {
        struct pm2pci_par* pci=&p->board_par.pci;
+       struct pci_dev* dev;
+       int i;
        unsigned char* m;
+#ifdef __sparc__
+       struct pcidev_cookie *pcp;
+#endif
 
        memset(pci, 0, sizeof(struct pm2pci_par));
        if (!pci_present()) {
@@ -843,9 +1033,16 @@ static int pm2pci_detect(struct pm2fb_info* p) {
                return 0;
        }
        DPRINTK("scanning PCI bus for known chipsets...\n");
-       if ((pci->dev=pci_find_device(PCI_VENDOR_ID_TI,
-                                       PCI_DEVICE_ID_TI_TVP4020, NULL))) {
-               DPRINTK("... found Texas Instruments TVP4020\n");
+
+       for (dev = pci_devices; !pci->dev && dev; dev = dev->next) {
+               for (i = 0; pm2pci_cards[i].vendor; i++)
+                       if (pm2pci_cards[i].vendor == dev->vendor &&
+                           pm2pci_cards[i].device == dev->device) {
+                               pci->dev = dev;
+                               p->type = pm2pci_cards[i].type;
+                               DPRINTK("... found %s\n", pm2pci_cards[i].name);
+                               break;
+                       }
        }
        if (!pci->dev) {
                DPRINTK("no PCI board found.\n");
@@ -861,6 +1058,41 @@ static int pm2pci_detect(struct pm2fb_info* p) {
                __pa(pci->dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK);
        p->regions.fb_base=(unsigned char* )
                __pa(pci->dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK);
+       pcp = pci->dev->sysdata;
+       /* If the user has not asked for a particular mode, lets guess */
+       if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) {
+               char timing[256], *q, *r;
+               unsigned long w, h;
+               int i;
+               prom_getstring(pcp->prom_node, "timing-numbers", timing, 256);
+               /* FIXME: Find out what the actual pixclock is and other values as well */
+               if (timing[0]) {
+                       w = simple_strtoul(timing, &q, 0);
+                       h = 0;
+                       if (q == timing) w = 0;
+                       if (w) {
+                               for (i = 0; i < 3; i++) {
+                                       for (r = q; *r && (*r < '0' || *r > '9'); r++);
+                                       simple_strtoul(r, &q, 0);
+                                       if (r == q) break;
+                               }
+                               if (i < 3) w = 0;
+                       }
+                       if (w) {
+                               for (r = q; *r && (*r < '0' || *r > '9'); r++);
+                               h = simple_strtoul(r, &q, 0);
+                               if (r == q) w = 0;
+                       }
+                       if (w == 640 && h == 480) w = 0;
+                       if (w) {
+                               for (i=0; user_mode[i].name[0] &&
+                                         (w != user_mode[i].par.width ||
+                                          h != user_mode[i].par.height); i++);
+                               if (user_mode[i].name[0])
+                                       memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
+                       }
+               }
+       }
 #else
        if (pm2fb_options.flags & OPTF_VIRTUAL) {
                p->regions.rg_base=(unsigned char* )
@@ -875,7 +1107,7 @@ static int pm2pci_detect(struct pm2fb_info* p) {
                        (pci->dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK);
        }
 #endif
-#ifdef __BIG_ENDIAN
+#ifdef PM2FB_BE_APERTURE
        p->regions.rg_base += PM2_REGS_SIZE;
 #endif
        if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) {
@@ -1042,7 +1274,7 @@ static void pm2fb_clear_margins8(struct vc_data* conp, struct display* p,
 static struct display_switch pm2_cfb8 = {
        fbcon_cfb8_setup, pm2fb_pp_bmove, pm2fb_clear8,
        fbcon_cfb8_putc, fbcon_cfb8_putcs, fbcon_cfb8_revc,
-       NULL /* cursor() */, NULL /* set_font() */,
+       pm2fb_cursor, pm2fb_set_font,
        pm2fb_clear_margins8,
        FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB8 */
@@ -1082,7 +1314,7 @@ static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p,
 static struct display_switch pm2_cfb16 = {
        fbcon_cfb16_setup, pm2fb_pp_bmove, pm2fb_clear16,
        fbcon_cfb16_putc, fbcon_cfb16_putcs, fbcon_cfb16_revc,
-       NULL /* cursor() */, NULL /* set_font() */,
+       pm2fb_cursor, pm2fb_set_font,
        pm2fb_clear_margins16,
        FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB16 */
@@ -1140,7 +1372,7 @@ static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p,
 static struct display_switch pm2_cfb24 = {
        fbcon_cfb24_setup, pm2fb_bmove, pm2fb_clear24,
        fbcon_cfb24_putc, fbcon_cfb24_putcs, fbcon_cfb24_revc,
-       NULL /* cursor() */, NULL /* set_font() */,
+       pm2fb_cursor, pm2fb_set_font,
        pm2fb_clear_margins24,
        FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB24 */
@@ -1178,7 +1410,7 @@ static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p,
 static struct display_switch pm2_cfb32 = {
        fbcon_cfb32_setup, pm2fb_bmove, pm2fb_clear32,
        fbcon_cfb32_putc, fbcon_cfb32_putcs, fbcon_cfb32_revc,
-       NULL /* cursor() */, NULL /* set_font() */,
+       pm2fb_cursor, pm2fb_set_font,
        pm2fb_clear_margins32,
        FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
 #endif /* FBCON_HAS_CFB32 */
@@ -1258,7 +1490,7 @@ static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
        p.height=var->yres_virtual;
        p.depth=(var->bits_per_pixel+7)&~7;
        p.depth=p.depth>32?32:p.depth;
-       data64=p.depth>8;
+       data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
        xres=(var->xres+31)&~31;
        if (p.width<xres+var->xoffset)
                p.width=xres+var->xoffset;
@@ -1417,14 +1649,12 @@ static int pm2fb_encode_var(struct fb_var_screeninfo* var,
 
 static void set_user_mode(struct pm2fb_info* i) {
 
-       memcpy(&i->current_par, &pm2fb_options.user_mode,
-                                               sizeof(i->current_par));
        if (pm2fb_options.flags & OPTF_YPAN) {
+               int h = i->current_par.height;
                i->current_par.height=i->regions.fb_size/
                        (i->current_par.width*i->current_par.depth/8);
                i->current_par.height=MIN(i->current_par.height,2047);
-               i->current_par.height=MAX(i->current_par.height,
-                                               pm2fb_options.user_mode.height);
+               i->current_par.height=MAX(i->current_par.height,h);
        }
 }
 
@@ -1456,6 +1686,12 @@ static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
        set_screen(i, p);
        i->current_par=*p;
        i->current_par_valid=1;
+#ifdef PM2FB_HW_CURSOR 
+       if (i->cursor) {
+               pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
+               pm2v_set_cursor_shape(i);
+       }
+#endif
 }
 
 static int pm2fb_getcolreg(unsigned regno,
@@ -1577,6 +1813,210 @@ static int pm2fb_release(struct fb_info* info, int user) {
        return 0;
 }
 
+#ifdef PM2FB_HW_CURSOR
+/***************************************************************************
+ * Hardware cursor support
+ ***************************************************************************/
+static u8 cursor_bits_lookup[16] = {
+       0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
+       0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
+};
+
+static u8 cursor_mask_lookup[16] = {
+       0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
+       0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa
+};
+
+static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue)
+{
+       struct pm2_cursor *c = fb->cursor;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               c->color[3*i] = red[i];
+               c->color[3*i+1] = green[i];
+               c->color[3*i+2] = blue[i];
+       }
+
+       WAIT_FIFO(fb, 14);
+       pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
+       for (i = 0; i < 6; i++)
+               pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PALETTE+i, c->color[i]);
+       pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
+}
+
+static void pm2v_set_cursor_shape(struct pm2fb_info *fb)
+{
+       struct pm2_cursor *c = fb->cursor;
+       u8 m, b;
+       int i, x, y;
+
+       WAIT_FIFO(fb, 1);
+       pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PATTERN >> 8);
+       for (y = 0, i = 0; y < c->size.y; y++) {
+               WAIT_FIFO(fb, 32);
+               for (x = 0; x < c->size.x >> 3; x++) {
+                       m = c->mask[x][y];
+                       b = c->bits[x][y];
+                       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i,
+                                    cursor_mask_lookup[m >> 4] |
+                                    cursor_bits_lookup[(b & m) >> 4]);
+                       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1,
+                                    cursor_mask_lookup[m & 0x0f] |
+                                    cursor_bits_lookup[(b & m) & 0x0f]);
+                       i+=2;
+               }
+               for ( ; x < 8; x++) {
+                       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
+                       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
+                       i+=2;
+               }
+       }
+       for (; y < 64; y++) {
+               WAIT_FIFO(fb, 32);
+               for (x = 0; x < 8; x++) {
+                       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
+                       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
+                       i+=2;
+               }
+       }
+       WAIT_FIFO(fb, 1);
+       pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
+}
+
+static void pm2v_set_cursor(struct pm2fb_info *fb, int on)
+{
+       struct pm2_cursor *c = fb->cursor;
+       int x = c->pos.x;
+
+       if (!on) x = 4000;
+       WAIT_FIFO(fb, 14);
+       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
+       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0x0f);
+       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_LOW, c->pos.y & 0xff);
+       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HIGH, (c->pos.y >> 8) & 0x0f);
+       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HOT, c->hot.x & 0x3f);
+       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HOT, c->hot.y & 0x3f);
+       pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_MODE, 0x11);
+}
+
+static void pm2_cursor_timer_handler(unsigned long dev_addr)
+{
+       struct pm2fb_info *fb = (struct pm2fb_info *)dev_addr;
+
+       if (!fb->cursor->enable)
+               goto out;
+
+       if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
+               fb->cursor->on ^= 1;
+               pm2v_set_cursor(fb, fb->cursor->on);
+               fb->cursor->vbl_cnt = fb->cursor->blink_rate;
+       }
+
+out:
+       fb->cursor->timer->expires = jiffies + (HZ / 50);
+       add_timer(fb->cursor->timer);
+}
+
+static void pm2fb_cursor(struct display *p, int mode, int x, int y)
+{
+       struct pm2fb_info *fb = (struct pm2fb_info *)p->fb_info;
+       struct pm2_cursor *c = fb->cursor;
+
+       if (!c) return;
+
+       x *= fontwidth(p);
+       y *= fontheight(p);
+       if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
+               return;
+
+       c->enable = 0;
+       if (c->on)
+               pm2v_set_cursor(fb, 0);
+       c->pos.x = x;
+       c->pos.y = y;
+
+       switch (mode) {
+       case CM_ERASE:
+               c->on = 0;
+               break;
+
+       case CM_DRAW:
+       case CM_MOVE:
+               if (c->on)
+                       pm2v_set_cursor(fb, 1);
+               else
+                       c->vbl_cnt = CURSOR_DRAW_DELAY;
+               c->enable = 1;
+               break;
+       }
+}
+
+static struct pm2_cursor * __init pm2_init_cursor(struct pm2fb_info *fb)
+{
+       struct pm2_cursor *cursor;
+
+       if (fb->type != PM2_TYPE_PERMEDIA2V)
+               return 0; /* FIXME: Support hw cursor everywhere */
+
+       cursor = kmalloc(sizeof(struct pm2_cursor), GFP_ATOMIC);
+       if (!cursor)
+               return 0;
+       memset(cursor, 0, sizeof(*cursor));
+
+       cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
+       if (!cursor->timer) {
+               kfree(cursor);
+               return 0;
+       }
+       memset(cursor->timer, 0, sizeof(*cursor->timer));
+
+       cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
+
+       if (curblink) {
+               init_timer(cursor->timer);
+               cursor->timer->expires = jiffies + (HZ / 50);
+               cursor->timer->data = (unsigned long)fb;
+               cursor->timer->function = pm2_cursor_timer_handler;
+               add_timer(cursor->timer);
+       }
+
+       return cursor;
+}
+
+static int pm2fb_set_font(struct display *d, int width, int height)
+{
+       struct pm2fb_info *fb = (struct pm2fb_info *)d->fb_info;
+       struct pm2_cursor *c = fb->cursor;
+       int i, j;
+
+       if (c) {
+               if (!width || !height) {
+                       width = 8;
+                       height = 16;
+               }
+
+               c->hot.x = 0;
+               c->hot.y = 0;
+               c->size.x = width;
+               c->size.y = height;
+
+               memset(c->bits, 0xff, sizeof(c->bits));
+               memset(c->mask, 0, sizeof(c->mask));
+
+               for (i = 0, j = width; j >= 0; j -= 8, i++) {
+                       c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
+                       c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
+               }
+
+               pm2v_set_cursor_color(fb, cursor_color_map, cursor_color_map, cursor_color_map);
+               pm2v_set_cursor_shape(fb);
+       }
+       return 1;
+}
+#endif /* PM2FB_HW_CURSOR */
+
 /***************************************************************************
  * Begin of public functions
  ***************************************************************************/
@@ -1594,6 +2034,7 @@ void pm2fb_cleanup(struct fb_info* info) {
 __initfunc(void pm2fb_init(void)) {
 
        memset(&fb_info, 0, sizeof(fb_info));
+       memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
        if (!pm2fb_conf(&fb_info))
                return;
        pm2fb_reset(&fb_info);
@@ -1624,23 +2065,25 @@ __initfunc(void pm2fb_init(void)) {
        MOD_INC_USE_COUNT;
 }
 
-__initfunc(void pm2fb_mode_setup(char* options)) {
+static void __init pm2fb_mode_setup(char* options) {
        int i;
 
        for (i=0; user_mode[i].name[0] &&
                strcmp(options, user_mode[i].name); i++);
-       if (user_mode[i].name[0])
+       if (user_mode[i].name[0]) {
                memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
                                        sizeof(pm2fb_options.user_mode));
+               pm2fb_options.flags |= OPTF_USER;
+       }
 }
 
-__initfunc(void pm2fb_font_setup(char* options)) {
+static void __init pm2fb_font_setup(char* options) {
 
        strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
        pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
 }
 
-__initfunc(void pm2fb_setup(char* options, int* ints)) {
+void __init pm2fb_setup(char* options, int* ints) {
        char* next;
 
        while (options) {
@@ -1656,6 +2099,8 @@ __initfunc(void pm2fb_setup(char* options, int* ints)) {
                        pm2fb_options.flags |= OPTF_OLD_MEM;
                else if (!strcmp(options, "virtual"))
                        pm2fb_options.flags |= OPTF_VIRTUAL;
+               else if (!strcmp(options, "noblink"))
+                       curblink = 0;
                options=next;
        }
 }
@@ -1665,9 +2110,14 @@ __initfunc(void pm2fb_setup(char* options, int* ints)) {
  ***************************************************************************/
 
 #ifdef MODULE
-int init_module(void) {
 
-       pm2fb_init();
+static char *mode = NULL;
+
+MODULE_PARM(mode, "s");
+
+int init_module(void) {
+       if (mode) pm2fb_mode_setup(mode);
+       pm2fb_init();
 }
 
 void cleanup_module(void) {
index f10ab7e93d2e5dd76bab58c9e1644654527a0bc5..b3ebc5ce7bd3ddc480180319bab034e39595a656 100644 (file)
 #define PM2R_FB_SOURCE_DELTA                           0x8d88
 #define PM2R_CONFIG                                    0x8d90
 
+/* Permedia2v */
+#define PM2VR_RD_INDEX_LOW                             0x4020
+#define PM2VR_RD_INDEX_HIGH                            0x4028
+#define PM2VR_RD_INDEXED_DATA                          0x4030
+
 /* Permedia2 RAMDAC indexed registers */
 #define PM2I_RD_CURSOR_CONTROL                         0x06
 #define PM2I_RD_COLOR_MODE                             0x18
 #define PM2I_RD_GREEN_KEY                              0x43
 #define PM2I_RD_BLUE_KEY                               0x44
 
+/* Permedia2v extensions */
+#define PM2VI_RD_MISC_CONTROL                          0x000
+#define PM2VI_RD_SYNC_CONTROL                          0x001
+#define PM2VI_RD_DAC_CONTROL                           0x002
+#define PM2VI_RD_PIXEL_SIZE                            0x003
+#define PM2VI_RD_COLOR_FORMAT                          0x004
+#define PM2VI_RD_CURSOR_MODE                           0x005
+#define PM2VI_RD_CURSOR_X_LOW                          0x007
+#define PM2VI_RD_CURSOR_X_HIGH                         0x008
+#define PM2VI_RD_CURSOR_Y_LOW                          0x009
+#define PM2VI_RD_CURSOR_Y_HIGH                         0x00A
+#define PM2VI_RD_CURSOR_X_HOT                          0x00B
+#define PM2VI_RD_CURSOR_Y_HOT                          0x00C
+#define PM2VI_RD_CLK0_PRESCALE                         0x201
+#define PM2VI_RD_CLK0_FEEDBACK                         0x202
+#define PM2VI_RD_CLK0_POSTSCALE                                0x203
+#define PM2VI_RD_CLK1_PRESCALE                         0x204
+#define PM2VI_RD_CLK1_FEEDBACK                         0x205
+#define PM2VI_RD_CLK1_POSTSCALE                                0x206
+#define PM2VI_RD_CURSOR_PALETTE                                0x303
+#define PM2VI_RD_CURSOR_PATTERN                                0x400
+
 /* Fields and flags */
 #define PM2F_RENDER_AREASTIPPLE                                (1L<<0)
 #define PM2F_RENDER_FASTFILL                           (1L<<3)
 #define PM2F_MEM_BANKS_3                               (2L<<29)
 #define PM2F_MEM_BANKS_4                               (3L<<29)
 
+typedef enum {
+       PM2_TYPE_PERMEDIA2,
+       PM2_TYPE_PERMEDIA2V
+} pm2type_t;
+
 #endif /* PM2FB_H */
 
 /*****************************************************************************
index c11cc4483598f26a95cec62a9fffcd4242cee62e..6373651ed69e84d181d964ee60fd0b06a69255db 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tcxfb.c,v 1.7 1999/01/26 10:55:03 jj Exp $
+/* $Id: tcxfb.c,v 1.7.2.1 1999/09/28 16:00:14 davem Exp $
  * tcxfb.c: TCX 24/8bit frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
index eaa873b60d0b2b3f3d2274e297752bddc23d296c..0dcf001fd974f9a994628022c1693aafa1764c1c 100644 (file)
@@ -526,29 +526,6 @@ struct dentry_operations nfs_dentry_operations = {
        NULL                    /* d_iput */
 };
 
-#ifdef NFS_PARANOIA
-/*
- * Display all dentries holding the specified inode.
- */
-static void show_dentry(struct list_head * dlist)
-{
-       struct list_head *tmp = dlist;
-
-       while ((tmp = tmp->next) != dlist) {
-               struct dentry * dentry = list_entry(tmp, struct dentry, d_alias);
-               const char * unhashed = "";
-
-               if (list_empty(&dentry->d_hash))
-                       unhashed = "(unhashed)";
-
-               printk("show_dentry: %s/%s, d_count=%d%s\n",
-                       dentry->d_parent->d_name.name,
-                       dentry->d_name.name, dentry->d_count,
-                       unhashed);
-       }
-}
-#endif
-
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
        struct inode *inode;
index 117587d8d74871447b8f2273ea4465cd6c6db8d4..3d264811579851472df51392bf32859c1ed3a135 100644 (file)
@@ -288,11 +288,15 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma)
                if (!dest_table)
                        return -ENOMEM;
 
-               if (!pte_present(*src_table))
-                       handle_mm_fault(tsk, src_vma, stmp, 1);
+               if (!pte_present(*src_table)) {
+                       if (handle_mm_fault(tsk, src_vma, stmp, 1) < 0)
+                               return -ENOMEM;
+               }
 
-               if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
-                       handle_mm_fault(tsk, src_vma, stmp, 1);
+               if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table)) {
+                       if (handle_mm_fault(tsk, src_vma, stmp, 1) < 0)
+                               return -ENOMEM;
+               }
 
                set_pte(src_table, pte_mkdirty(*src_table));
                set_pte(dest_table, *src_table);
index ea06839ea2dc73ff7eec22ac57290458d0f64b07..e0c4e12936c55b65b14e15010f0f32b98698fc5e 100644 (file)
@@ -7,6 +7,11 @@
  *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
  *  28/09/97 - Fixed smb_d_path [now smb_build_path()] to be non-recursive
  *             by Riccardo Facchetti
+ *  16/11/99 (tridge) 
+ *           - use level 260 for most conns, or level 1 for <NT1
+ *           - don't sleep every time with win95 on a FINDNEXT
+ *           - fixed loop_count bug
+ *           - got rid of resume_key
  */
 
 #include <linux/types.h>
@@ -1449,13 +1454,12 @@ entries_seen, i, fpos);
 
 /*
  * Interpret a long filename structure using the specified info level:
- *   level 1   -- Win NT, Win 95, OS/2
- *   level 259 -- File name and length only, Win NT, Win 95
+ *   level 1 for anything below NT1 protocol
+ *   level 260 for NT1 protocol
  *
  * We return a reference to the name string to avoid copying, and perform
- * any needed upper/lower casing in place.  Note!! Level 259 entries may
- * not have any space beyond the name, so don't try to write a null byte!
- *
+ * any needed upper/lower casing in place.  
+
  * Bugs Noted:
  * (1) Win NT 4.0 appends a null byte to names and counts it in the length!
  */
@@ -1474,30 +1478,24 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p,
        switch (level)
        {
        case 1:
-               len = *((unsigned char *) p + 26);
+               len = *((unsigned char *) p + 22);
                entry->len = len;
-               entry->name = p + 27;
-               result = p + 28 + len;
+               entry->name = p + 23;
+               result = p + 24 + len;
                break;
 
-       case 259: /* SMB_FIND_FILE_NAMES_INFO = 0x103 */
-               result = p + DVAL(p, 0);
-               /* DVAL(p, 4) should be resume key? Seems to be 0 .. */
-               len = DVAL(p, 8);
-               if (len > 255)
-                       len = 255;
-               entry->name = p + 12;
-               /*
-                * Kludge alert: Win NT 4.0 adds a trailing null byte and
-                * counts it in the name length, but Win 95 doesn't.  Hence
-                * we test for a trailing null and decrement the length ...
-                */
+       case 260: /* SMB_FIND_FILE_BOTH_DIRECTORY_INFO = 0x104 */
+               result = p + WVAL(p, 0);
+               len = DVAL(p, 60);
+               if (len > 255) len = 255;
+               /* NT4 null terminates */
+               entry->name = p + 94;
                if (len && entry->name[len-1] == '\0')
                        len--;
                entry->len = len;
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_decode_long_dirent: info 259 at %p, len=%d, name=%s\n",
-p, len, entry->name);
+printk("smb_decode_long_dirent: info 260 at %p, len=%d, name=%s\n",
+       p, entry->len, entry->name);
 #endif
                break;
 
@@ -1528,40 +1526,40 @@ p, len, entry->name);
  * is completely reproducible and can be toggled by the creation of a
  * single file. (E.g. echo hi >foo breaks, rm -f foo works.)
  */
+
+#define SMB_CLOSE_AFTER_FIRST (1<<0)
+#define SMB_CLOSE_IF_END (1<<1)
+#define SMB_REQUIRE_RESUME_KEY (1<<2)
+#define SMB_CONTINUE_BIT (1<<3)
+
 static int
 smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
                      void *cachep)
 {
-       char *p, *mask, *lastname, *param = server->temp_buf;
+       char *p, *mask, *param = server->temp_buf;
        __u16 command;
        int first, entries, entries_seen;
 
        /* Both NT and OS/2 accept info level 1 (but see note below). */
-       int info_level = 1;
+       int info_level = 260;
        const int max_matches = 512;
 
        unsigned char *resp_data = NULL;
        unsigned char *resp_param = NULL;
        int resp_data_len = 0;
        int resp_param_len = 0;
-       int ff_resume_key = 0; /* this isn't being used */
        int ff_searchcount = 0;
        int ff_eos = 0;
-       int ff_lastname = 0;
        int ff_dir_handle = 0;
        int loop_count = 0;
        int mask_len, i, result;
        static struct qstr star = { "*", 1, 0 };
 
        /*
-        * Check whether to change the info level.  There appears to be
-        * a bug in Win NT 4.0's handling of info level 1, whereby it
-        * truncates the directory scan for certain patterns of files.
-        * Hence we use level 259 for NT.
+        * use info level 1 for older servers that don't do 260
         */
-       if (server->opt.protocol >= SMB_PROTOCOL_NT1 &&
-           !(server->mnt->version & SMB_FIX_WIN95))
-               info_level = 259;
+       if (server->opt.protocol < SMB_PROTOCOL_NT1)
+               info_level = 1;
 
        smb_lock_server(server);
 
@@ -1586,7 +1584,7 @@ printk("smb_proc_readdir_long: starting fpos=%d, mask=%s\n", fpos, mask);
        while (ff_eos == 0)
        {
                loop_count += 1;
-               if (loop_count > 200)
+               if (loop_count > 10)
                {
                        printk(KERN_WARNING "smb_proc_readdir_long: "
                               "Looping in FIND_NEXT??\n");
@@ -1599,32 +1597,27 @@ printk("smb_proc_readdir_long: starting fpos=%d, mask=%s\n", fpos, mask);
                        command = TRANSACT2_FINDFIRST;
                        WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
                        WSET(param, 2, max_matches);    /* max count */
-                       WSET(param, 4, 4 + 2);          /* close on end +
-                                                          continue */
+                       WSET(param, 4, 
+                            SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); 
                        WSET(param, 6, info_level);
                        DSET(param, 8, 0);
                } else
                {
+                       /* we don't need the mask after the first bit */
+                       mask_len = 0;
+                       mask[0] = 0;
+
                        command = TRANSACT2_FINDNEXT;
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: handle=0x%X, resume=%d, lastname=%d, mask=%s\n",
-ff_dir_handle, ff_resume_key, ff_lastname, mask);
+printk("smb_proc_readdir_long: handle=0x%X, mask=%s\n",
+ff_dir_handle, mask);
 #endif
                        WSET(param, 0, ff_dir_handle);  /* search handle */
                        WSET(param, 2, max_matches);    /* max count */
                        WSET(param, 4, info_level);
-                       DSET(param, 6, ff_resume_key);  /* ff_resume_key */
-                       WSET(param, 10, 8 + 4 + 2);     /* resume required +
-                                                          close on end +
-                                                          continue */
-                       if (server->mnt->version & SMB_FIX_WIN95)
-                       {
-                               /* Windows 95 is not able to deliver answers
-                                * to FIND_NEXT fast enough, so sleep 0.2 sec
-                                */
-                               current->state = TASK_INTERRUPTIBLE;
-                               schedule_timeout(HZ/5);
-                       }
+                       DSET(param, 6, 0);              /* ff_resume_key */
+                       WSET(param, 10,
+                            SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); 
                }
 
                result = smb_trans2_request(server, command,
@@ -1647,6 +1640,16 @@ printk("smb_proc_readdir_long: error=%d, breaking\n", result);
                        entries = result;
                        break;
                }
+
+
+               if (server->rcls == ERRSRV && server->err == ERRerror) {
+                       /* a damn Win95 bug - sometimes it clags if you 
+                          ask it too fast */
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(HZ/5);
+                       continue;
+               }
+
                if (server->rcls != 0)
                { 
 #ifdef SMBFS_PARANOIA
@@ -1663,12 +1666,10 @@ mask, entries, server->rcls, server->err);
                        ff_dir_handle = WVAL(resp_param, 0);
                        ff_searchcount = WVAL(resp_param, 2);
                        ff_eos = WVAL(resp_param, 4);
-                       ff_lastname = WVAL(resp_param, 8);
                } else
                {
                        ff_searchcount = WVAL(resp_param, 0);
                        ff_eos = WVAL(resp_param, 2);
-                       ff_lastname = WVAL(resp_param, 6);
                }
 
                if (ff_searchcount == 0)
@@ -1676,38 +1677,6 @@ mask, entries, server->rcls, server->err);
                        break;
                }
 
-               /* we might need the lastname for continuations */
-               mask_len = 0;
-               if (ff_lastname > 0)
-               {
-                       lastname = resp_data + ff_lastname;
-                       switch (info_level)
-                       {
-                       case 259:
-                               if (ff_lastname < resp_data_len)
-                                       mask_len = resp_data_len - ff_lastname;
-                               break;
-                       case 1:
-                               /* Win NT 4.0 doesn't set the length byte */
-                               lastname++;
-                               if (ff_lastname + 2 < resp_data_len)
-                                       mask_len = strlen(lastname);
-                               break;
-                       }
-                       /*
-                        * Update the mask string for the next message.
-                        */
-                       if (mask_len > 255)
-                               mask_len = 255;
-                       if (mask_len)
-                               strncpy(mask, lastname, mask_len);
-                       ff_resume_key = 0;
-               }
-               mask[mask_len] = 0;
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: new mask, len=%d@%d, mask=%s\n",
-mask_len, ff_lastname, mask);
-#endif
                /* Now we are ready to parse smb directory entries. */
 
                /* point to the data bytes */
@@ -1719,8 +1688,6 @@ mask_len, ff_lastname, mask);
                        p = smb_decode_long_dirent(server, p, entry,
                                                        info_level);
 
-                       pr_debug("smb_readdir_long: got %s\n", entry->name);
-
                        /* ignore . and .. from the server */
                        if (entries_seen == 2 && entry->name[0] == '.')
                        {
@@ -1738,10 +1705,11 @@ mask_len, ff_lastname, mask);
                }
 
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_proc_readdir_long: received %d entries, eos=%d, resume=%d\n",
-ff_searchcount, ff_eos, ff_resume_key);
+printk("smb_proc_readdir_long: received %d entries, eos=%d\n",
+       ff_searchcount, ff_eos);
 #endif
                first = 0;
+               loop_count = 0;
        }
 
        smb_unlock_server(server);
index c45a7b4a78605c5ced028035b2d6f1714c43ea31..4c4110416c17d37c21a86f7a35997c017871ace6 100644 (file)
 #define ASIZ_task_sas_ss_sp    0x00000004
 #define AOFF_task_sas_ss_size  0x00000598
 #define ASIZ_task_sas_ss_size  0x00000004
+#define AOFF_task_parent_exec_id       0x0000059c
+#define ASIZ_task_parent_exec_id       0x00000004
+#define AOFF_task_self_exec_id 0x000005a0
+#define ASIZ_task_self_exec_id 0x00000004
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000004
 #define AOFF_mm_mmap_avl       0x00000004
 #define ASIZ_task_sas_ss_sp    0x00000004
 #define AOFF_task_sas_ss_size  0x00000694
 #define ASIZ_task_sas_ss_size  0x00000004
+#define AOFF_task_parent_exec_id       0x00000698
+#define ASIZ_task_parent_exec_id       0x00000004
+#define AOFF_task_self_exec_id 0x0000069c
+#define ASIZ_task_self_exec_id 0x00000004
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000004
 #define AOFF_mm_mmap_avl       0x00000004
index 174984e11e452e83c1b2cbaf9568528b73c69fd3..6065408818d3eb475f7770309fdeee9c4d01dddc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: shmparam.h,v 1.4 1998/09/28 07:15:01 jj Exp $ */
+/* $Id: shmparam.h,v 1.4.2.1 1999/09/29 18:00:44 davem Exp $ */
 #ifndef _ASMSPARC_SHMPARAM_H
 #define _ASMSPARC_SHMPARAM_H
 
 #define SHMMNI (1<<_SHM_ID_BITS)       /* max num of segs system wide */
 #define SHMALL                         /* max shm system wide (pages) */ \
        (1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
-#define        SHMLBA PAGE_SIZE                /* attach addr a multiple of this */
+
+extern int vac_cache_size;
+#define SHMLBA (vac_cache_size ? vac_cache_size : \
+               (sparc_cpu_model == sun4c ? (64 * 1024) : \
+                (sparc_cpu_model == sun4 ? (128 * 1024) : PAGE_SIZE)))
+
 #define SHMSEG SHMMNI                  /* max shared segs per process */
 
 #endif /* _ASMSPARC_SHMPARAM_H */
index 3301515c59207c1bf74e5b8a7ecba6651f409202..4bb5a543cc5bde0e66b942e46914f18e915724ed 100644 (file)
 #define ASIZ_task_sas_ss_sp    0x00000008
 #define AOFF_task_sas_ss_size  0x00000820
 #define ASIZ_task_sas_ss_size  0x00000008
+#define AOFF_task_parent_exec_id       0x00000828
+#define ASIZ_task_parent_exec_id       0x00000004
+#define AOFF_task_self_exec_id 0x0000082c
+#define ASIZ_task_self_exec_id 0x00000004
 #define ASIZ_task      0x00000830
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define ASIZ_task_sas_ss_sp    0x00000008
 #define AOFF_task_sas_ss_size  0x00000a10
 #define ASIZ_task_sas_ss_size  0x00000008
+#define AOFF_task_parent_exec_id       0x00000a18
+#define ASIZ_task_parent_exec_id       0x00000004
+#define AOFF_task_self_exec_id 0x00000a1c
+#define ASIZ_task_self_exec_id 0x00000004
 #define ASIZ_task      0x00000a20
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define ASIZ_task_sas_ss_sp    0x00000008
 #define AOFF_task_sas_ss_size  0x00000a18
 #define ASIZ_task_sas_ss_size  0x00000008
-#define ASIZ_task      0x00000a20
+#define AOFF_task_parent_exec_id       0x00000a20
+#define ASIZ_task_parent_exec_id       0x00000004
+#define AOFF_task_self_exec_id 0x00000a24
+#define ASIZ_task_self_exec_id 0x00000004
+#define ASIZ_task      0x00000a30
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define AOFF_mm_mmap_avl       0x00000008
index d29cb2a35901512f483526b3c7ce0e9b294c4025..31536fae9ae3ecd69a210ed5d21ceece7dc394de 100644 (file)
@@ -1,9 +1,10 @@
-/* $Id: mmu_context.h,v 1.35 1999/05/08 03:03:20 davem Exp $ */
+/* $Id: mmu_context.h,v 1.35.2.1 1999/09/29 20:22:02 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
 /* Derived heavily from Linus's Alpha/AXP ASN code... */
 
+#include <asm/spinlock.h>
 #include <asm/system.h>
 #include <asm/spitfire.h>
 #include <asm/spinlock.h>
@@ -12,6 +13,7 @@
 
 #ifndef __ASSEMBLY__
 
+extern spinlock_t ctx_alloc_lock;
 extern unsigned long tlb_context_cache;
 extern unsigned long mmu_context_bmap[];
 
@@ -35,11 +37,13 @@ extern void get_new_mmu_context(struct mm_struct *mm);
  * the final reference to the address space.
  */
 #define destroy_context(__mm)  do {                                            \
+       spin_lock(&ctx_alloc_lock);                                             \
        if ((__mm)->context != NO_CONTEXT &&                                    \
            atomic_read(&(__mm)->count) == 1) {                                 \
                if (!(((__mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))\
-                       clear_bit((__mm)->context & ~(CTX_VERSION_MASK),        \
-                                 mmu_context_bmap);                            \
+               {       unsigned long nr = (__mm)->context & ~CTX_VERSION_MASK; \
+                       mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63));         \
+               }                                                               \
                (__mm)->context = NO_CONTEXT;                                   \
                if(current->mm == (__mm)) {                                     \
                        current->tss.ctx = 0;                                   \
@@ -47,6 +51,7 @@ extern void get_new_mmu_context(struct mm_struct *mm);
                        __asm__ __volatile__("flush %g6");                      \
                }                                                               \
        }                                                                       \
+       spin_unlock(&ctx_alloc_lock);                                           \
 } while (0)
 
 /* This routine must called with interrupts off,
index 942d8e38216df875fc5ab3e307a34ef6087ab303..6c0a894dc667725226c62043079f259948cb875d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.10.2.1 1999/08/19 01:11:21 davem Exp $
+/* $Id: oplib.h,v 1.10.2.2 1999/10/24 17:29:38 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -223,6 +223,24 @@ extern long prom_dtlb_load(unsigned long index,
                           unsigned long tte_data,
                           unsigned long vaddr);
 
+/* Map/Unmap client program address ranges.  First the format of
+ * the mapping mode argument.
+ */
+#define PROM_MAP_WRITE 0x0001 /* Writable */
+#define PROM_MAP_READ  0x0002 /* Readable - sw */
+#define PROM_MAP_EXEC  0x0004 /* Executable - sw */
+#define PROM_MAP_LOCKED        0x0010 /* Locked, use i/dtlb load calls for this instead */
+#define PROM_MAP_CACHED        0x0020 /* Cacheable in both L1 and L2 caches */
+#define PROM_MAP_SE    0x0040 /* Side-Effects */
+#define PROM_MAP_GLOB  0x0080 /* Global */
+#define PROM_MAP_IE    0x0100 /* Invert-Endianness */
+#define PROM_MAP_DEFAULT (PROM_MAP_WRITE | PROM_MAP_READ | PROM_MAP_EXEC | PROM_MAP_CACHED)
+
+extern int prom_map(int mode, unsigned long size,
+                   unsigned long vaddr, unsigned long paddr);
+extern void prom_unmap(unsigned long size, unsigned long vaddr);
+
+
 /* PROM device tree traversal functions... */
 
 #ifdef PROMLIB_INTERNAL
index 6f6978fea426121fddb92a628e5df2e2aa420808..94c4b5b57bd3a86d6b4acf3a71ccca65957f79df 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.11.2.2 1999/09/22 11:37:47 jj Exp $ */
+/* $Id: ttable.h,v 1.11.2.3 1999/10/07 20:48:25 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
                
 /* Before touching these macros, you owe it to yourself to go and
  * see how arch/sparc64/kernel/winfixup.S works... -DaveM
+ *
+ * For the user cases we used to use the %asi register, but
+ * it turns out that the "wr xxx, %asi" costs ~30 cycles, so
+ * now we use immediate ASI loads and stores instead.  Kudos
+ * to Greg Onufer for pointing out this performance anomaly.
+ *
+ * Further note that we cannot use the g2, g4, g5, and g7 alternate
+ * globals in the spill routines, check out the save instruction in
+ * arch/sparc64/kernel/etrap.S to see what I mean about g2, and
+ * g4/g5 are the globals which are preserved by etrap processing
+ * for the caller of it.  The g7 register is the return pc for
+ * etrap.  Finally, g6 is the current thread register so we cannot
+ * us it in the spill handlers either.  Most of these rules do not
+ * apply to fill processing, only g6 is not usable.
  */
 
 /* Normal kernel spill */
        nop; nop; nop; nop; nop; nop; nop; nop;
 
 /* Normal 64bit spill */
-#define SPILL_1_GENERIC(xxx)                           \
-       wr      %g0, xxx, %asi;                         \
-       stxa    %l0, [%sp + STACK_BIAS + 0x00] %asi;    \
-       stxa    %l1, [%sp + STACK_BIAS + 0x08] %asi;    \
-       stxa    %l2, [%sp + STACK_BIAS + 0x10] %asi;    \
-       stxa    %l3, [%sp + STACK_BIAS + 0x18] %asi;    \
-       stxa    %l4, [%sp + STACK_BIAS + 0x20] %asi;    \
-       stxa    %l5, [%sp + STACK_BIAS + 0x28] %asi;    \
-       stxa    %l6, [%sp + STACK_BIAS + 0x30] %asi;    \
-       stxa    %l7, [%sp + STACK_BIAS + 0x38] %asi;    \
-       stxa    %i0, [%sp + STACK_BIAS + 0x40] %asi;    \
-       stxa    %i1, [%sp + STACK_BIAS + 0x48] %asi;    \
-       stxa    %i2, [%sp + STACK_BIAS + 0x50] %asi;    \
-       stxa    %i3, [%sp + STACK_BIAS + 0x58] %asi;    \
-       stxa    %i4, [%sp + STACK_BIAS + 0x60] %asi;    \
-       stxa    %i5, [%sp + STACK_BIAS + 0x68] %asi;    \
-       stxa    %i6, [%sp + STACK_BIAS + 0x70] %asi;    \
-       stxa    %i7, [%sp + STACK_BIAS + 0x78] %asi;    \
-       saved; retry; nop; nop; nop; nop; nop; nop;     \
-       nop; nop; nop; nop;                             \
+#define SPILL_1_GENERIC(ASI)                           \
+       add     %sp, STACK_BIAS + 0x00, %g1;            \
+       stxa    %l0, [%g1 + %g0] ASI;                   \
+       mov     0x08, %g3;                              \
+       stxa    %l1, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x10, %g1;                         \
+       stxa    %l2, [%g1 + %g0] ASI;                   \
+       stxa    %l3, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x10, %g1;                         \
+       stxa    %l4, [%g1 + %g0] ASI;                   \
+       stxa    %l5, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x10, %g1;                         \
+       stxa    %l6, [%g1 + %g0] ASI;                   \
+       stxa    %l7, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x10, %g1;                         \
+       stxa    %i0, [%g1 + %g0] ASI;                   \
+       stxa    %i1, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x10, %g1;                         \
+       stxa    %i2, [%g1 + %g0] ASI;                   \
+       stxa    %i3, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x10, %g1;                         \
+       stxa    %i4, [%g1 + %g0] ASI;                   \
+       stxa    %i5, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x10, %g1;                         \
+       stxa    %i6, [%g1 + %g0] ASI;                   \
+       stxa    %i7, [%g1 + %g3] ASI;                   \
+       saved;                                          \
+       retry; nop; nop;                                \
        b,a,pt  %xcc, spill_fixup_dax;                  \
        b,a,pt  %xcc, spill_fixup_mna;                  \
        b,a,pt  %xcc, spill_fixup;
 
 /* Normal 32bit spill */
-#define SPILL_2_GENERIC(xxx)                           \
-       wr      %g0, xxx, %asi;                         \
+#define SPILL_2_GENERIC(ASI)                           \
        srl     %sp, 0, %sp;                            \
-       stwa    %l0, [%sp + 0x00] %asi;                 \
-       stwa    %l1, [%sp + 0x04] %asi;                 \
-       stwa    %l2, [%sp + 0x08] %asi;                 \
-       stwa    %l3, [%sp + 0x0c] %asi;                 \
-       stwa    %l4, [%sp + 0x10] %asi;                 \
-       stwa    %l5, [%sp + 0x14] %asi;                 \
-       stwa    %l6, [%sp + 0x18] %asi;                 \
-       stwa    %l7, [%sp + 0x1c] %asi;                 \
-       stwa    %i0, [%sp + 0x20] %asi;                 \
-       stwa    %i1, [%sp + 0x24] %asi;                 \
-       stwa    %i2, [%sp + 0x28] %asi;                 \
-       stwa    %i3, [%sp + 0x2c] %asi;                 \
-       stwa    %i4, [%sp + 0x30] %asi;                 \
-       stwa    %i5, [%sp + 0x34] %asi;                 \
-       stwa    %i6, [%sp + 0x38] %asi;                 \
-       stwa    %i7, [%sp + 0x3c] %asi;                 \
-       saved; retry; nop; nop; nop; nop;               \
-       nop; nop; nop; nop; nop;                        \
+       stwa    %l0, [%sp + %g0] ASI;                   \
+       mov     0x04, %g3;                              \
+       stwa    %l1, [%sp + %g3] ASI;                   \
+       add     %sp, 0x08, %g1;                         \
+       stwa    %l2, [%g1 + %g0] ASI;                   \
+       stwa    %l3, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x08, %g1;                         \
+       stwa    %l4, [%g1 + %g0] ASI;                   \
+       stwa    %l5, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x08, %g1;                         \
+       stwa    %l6, [%g1 + %g0] ASI;                   \
+       stwa    %l7, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x08, %g1;                         \
+       stwa    %i0, [%g1 + %g0] ASI;                   \
+       stwa    %i1, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x08, %g1;                         \
+       stwa    %i2, [%g1 + %g0] ASI;                   \
+       stwa    %i3, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x08, %g1;                         \
+       stwa    %i4, [%g1 + %g0] ASI;                   \
+       stwa    %i5, [%g1 + %g3] ASI;                   \
+       add     %g1, 0x08, %g1;                         \
+       stwa    %i6, [%g1 + %g0] ASI;                   \
+       stwa    %i7, [%g1 + %g3] ASI;                   \
+       saved;                                          \
+        retry; nop; nop;                               \
        b,a,pt  %xcc, spill_fixup_dax;                  \
        b,a,pt  %xcc, spill_fixup_mna;                  \
        b,a,pt  %xcc, spill_fixup;
        nop; nop; nop; nop; nop; nop; nop; nop;
 
 /* Normal 64bit fill */
-#define FILL_1_GENERIC(xxx)                            \
-       wr      %g0, xxx, %asi;                         \
-       ldxa    [%sp + STACK_BIAS + 0x00] %asi, %l0;    \
-       ldxa    [%sp + STACK_BIAS + 0x08] %asi, %l1;    \
-       ldxa    [%sp + STACK_BIAS + 0x10] %asi, %l2;    \
-       ldxa    [%sp + STACK_BIAS + 0x18] %asi, %l3;    \
-       ldxa    [%sp + STACK_BIAS + 0x20] %asi, %l4;    \
-       ldxa    [%sp + STACK_BIAS + 0x28] %asi, %l5;    \
-       ldxa    [%sp + STACK_BIAS + 0x30] %asi, %l6;    \
-       ldxa    [%sp + STACK_BIAS + 0x38] %asi, %l7;    \
-       ldxa    [%sp + STACK_BIAS + 0x40] %asi, %i0;    \
-       ldxa    [%sp + STACK_BIAS + 0x48] %asi, %i1;    \
-       ldxa    [%sp + STACK_BIAS + 0x50] %asi, %i2;    \
-       ldxa    [%sp + STACK_BIAS + 0x58] %asi, %i3;    \
-       ldxa    [%sp + STACK_BIAS + 0x60] %asi, %i4;    \
-       ldxa    [%sp + STACK_BIAS + 0x68] %asi, %i5;    \
-       ldxa    [%sp + STACK_BIAS + 0x70] %asi, %i6;    \
-       ldxa    [%sp + STACK_BIAS + 0x78] %asi, %i7;    \
-       restored; retry; nop; nop; nop; nop; nop; nop;  \
-       nop; nop; nop; nop;                             \
+#define FILL_1_GENERIC(ASI)                            \
+       add     %sp, STACK_BIAS + 0x00, %g1;            \
+       ldxa    [%g1 + %g0] ASI, %l0;                   \
+       mov     0x08, %g2;                              \
+       mov     0x10, %g3;                              \
+       ldxa    [%g1 + %g2] ASI, %l1;                   \
+       mov     0x18, %g5;                              \
+       ldxa    [%g1 + %g3] ASI, %l2;                   \
+       ldxa    [%g1 + %g5] ASI, %l3;                   \
+       add     %g1, 0x20, %g1;                         \
+       ldxa    [%g1 + %g0] ASI, %l4;                   \
+       ldxa    [%g1 + %g2] ASI, %l5;                   \
+       ldxa    [%g1 + %g3] ASI, %l6;                   \
+       ldxa    [%g1 + %g5] ASI, %l7;                   \
+       add     %g1, 0x20, %g1;                         \
+       ldxa    [%g1 + %g0] ASI, %i0;                   \
+       ldxa    [%g1 + %g2] ASI, %i1;                   \
+       ldxa    [%g1 + %g3] ASI, %i2;                   \
+       ldxa    [%g1 + %g5] ASI, %i3;                   \
+       add     %g1, 0x20, %g1;                         \
+       ldxa    [%g1 + %g0] ASI, %i4;                   \
+       ldxa    [%g1 + %g2] ASI, %i5;                   \
+       ldxa    [%g1 + %g3] ASI, %i6;                   \
+       ldxa    [%g1 + %g5] ASI, %i7;                   \
+       restored;                                       \
+       retry; nop; nop; nop; nop;                      \
        b,a,pt  %xcc, fill_fixup_dax;                   \
        b,a,pt  %xcc, fill_fixup_mna;                   \
        b,a,pt  %xcc, fill_fixup;
 
 /* Normal 32bit fill */
-#define FILL_2_GENERIC(xxx)                            \
-       wr      %g0, xxx, %asi;                         \
+#define FILL_2_GENERIC(ASI)                            \
        srl     %sp, 0, %sp;                            \
-       lduwa   [%sp + 0x00] %asi, %l0;                 \
-       lduwa   [%sp + 0x04] %asi, %l1;                 \
-       lduwa   [%sp + 0x08] %asi, %l2;                 \
-       lduwa   [%sp + 0x0c] %asi, %l3;                 \
-       lduwa   [%sp + 0x10] %asi, %l4;                 \
-       lduwa   [%sp + 0x14] %asi, %l5;                 \
-       lduwa   [%sp + 0x18] %asi, %l6;                 \
-       lduwa   [%sp + 0x1c] %asi, %l7;                 \
-       lduwa   [%sp + 0x20] %asi, %i0;                 \
-       lduwa   [%sp + 0x24] %asi, %i1;                 \
-       lduwa   [%sp + 0x28] %asi, %i2;                 \
-       lduwa   [%sp + 0x2c] %asi, %i3;                 \
-       lduwa   [%sp + 0x30] %asi, %i4;                 \
-       lduwa   [%sp + 0x34] %asi, %i5;                 \
-       lduwa   [%sp + 0x38] %asi, %i6;                 \
-       lduwa   [%sp + 0x3c] %asi, %i7;                 \
-       restored; retry; nop; nop; nop; nop;            \
-       nop; nop; nop; nop; nop;                        \
+       lduwa   [%sp + %g0] ASI, %l0;                   \
+       mov     0x04, %g2;                              \
+       mov     0x08, %g3;                              \
+       lduwa   [%sp + %g2] ASI, %l1;                   \
+       mov     0x0c, %g5;                              \
+       lduwa   [%sp + %g3] ASI, %l2;                   \
+       lduwa   [%sp + %g5] ASI, %l3;                   \
+       add     %sp, 0x10, %g1;                         \
+       lduwa   [%g1 + %g0] ASI, %l4;                   \
+       lduwa   [%g1 + %g2] ASI, %l5;                   \
+       lduwa   [%g1 + %g3] ASI, %l6;                   \
+       lduwa   [%g1 + %g5] ASI, %l7;                   \
+       add     %g1, 0x10, %g1;                         \
+       lduwa   [%g1 + %g0] ASI, %i0;                   \
+       lduwa   [%g1 + %g2] ASI, %i1;                   \
+       lduwa   [%g1 + %g3] ASI, %i2;                   \
+       lduwa   [%g1 + %g5] ASI, %i3;                   \
+       add     %g1, 0x10, %g1;                         \
+       lduwa   [%g1 + %g0] ASI, %i4;                   \
+       lduwa   [%g1 + %g2] ASI, %i5;                   \
+       lduwa   [%g1 + %g3] ASI, %i6;                   \
+       lduwa   [%g1 + %g5] ASI, %i7;                   \
+       restored;                                       \
+       retry; nop; nop; nop; nop;                      \
        b,a,pt  %xcc, fill_fixup_dax;                   \
        b,a,pt  %xcc, fill_fixup_mna;                   \
        b,a,pt  %xcc, fill_fixup;
index aaf0a44365ff9481bbe1e13815b442fee93137c8..4170e030ee58548a692ab7d46a760f85ff8543f4 100644 (file)
@@ -26,6 +26,7 @@
 /* #define FBIOSWITCH_MONIBIT  0x460E */
 #define FBIOGET_CON2FBMAP      0x460F
 #define FBIOPUT_CON2FBMAP      0x4610
+#define FBIOBLANK              0x4611          /* arg: 0 or vesa level + 1 */
 
 #define FB_TYPE_PACKED_PIXELS          0       /* Packed Pixels        */
 #define FB_TYPE_PLANES                 1       /* Non interleaved planes */
index acb653d6cc13ca2433610d62e05f90b6fa0b1c93..a0a0b0fa70beb734e0f12e7344f7e6959cb1bed8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.76 1999/09/14 10:16:21 keil Exp $
+/* $Id: isdn.h,v 1.81 1999/10/27 21:21:18 detabc Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn.h,v $
+ * Revision 1.81  1999/10/27 21:21:18  detabc
+ * Added support for building logically-bind-group's per interface.
+ * usefull for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
+ * Revision 1.80  1999/10/26 21:09:29  armin
+ * New bufferlen for phonenumber only with kernel 2.3.x
+ *
+ * Revision 1.79  1999/10/16 17:52:38  keil
+ * Changing the MSN length need new data versions
+ *
+ * Revision 1.78  1999/10/08 18:59:33  armin
+ * Bugfix of too small MSN buffer and checking phone number
+ * in isdn_tty_getdial()
+ *
+ * Revision 1.77  1999/09/23 22:22:42  detabc
+ * added tcp-keepalive-detect with local response (ipv4 only)
+ * added host-only-interface support
+ * (source ipaddr == interface ipaddr) (ipv4 only)
+ * ok with kernel 2.3.18 and 2.2.12
+ *
  * Revision 1.76  1999/09/14 10:16:21  keil
  * change ABC include
  *
 #undef CONFIG_ISDN_WITH_ABC_CALLB
 #undef CONFIG_ISDN_WITH_ABC_UDP_CHECK
 #undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
+#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
 #undef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
-#undef CONFIG_ISDN_WITH_ABC_CALL_CHECK_SYNCRO
 #undef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
+#undef CONFIG_ISDN_WITH_ABC_IPV4_TCP_KEEPALIVE
+#undef CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
+#undef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
+#undef CONFIG_ISDN_WITH_ABC_ICALL_BIND
 
 
 /* New ioctl-codes */
 #define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing  */
 
 #define ISDN_MODEM_ANZREG    24        /* Number of Modem-Registers        */
-#define ISDN_MSNLEN          20
 #define ISDN_LMSNLEN         255 /* Length of tty's Listen-MSN string */
 #define ISDN_CMSGLEN        50  /* Length of CONNECT-Message to add for Modem */
 
+#define ISDN_MSNLEN          20
+#define NET_DV 0x05  /* Data version for isdn_net_ioctl_cfg   */
+#define TTY_DV 0x05  /* Data version for iprofd etc.          */
+
+#define INF_DV 0x01  /* Data version for /dev/isdninfo        */
+
 typedef struct {
   char drvid[25];
   unsigned long arg;
@@ -384,10 +418,6 @@ typedef struct {
   int  outgoing;
 } isdn_net_ioctl_phone;
 
-#define NET_DV 0x05  /* Data version for isdn_net_ioctl_cfg   */
-#define TTY_DV 0x05  /* Data version for iprofd etc.          */
-#define INF_DV 0x01  /* Data version for /dev/isdninfo        */
-
 typedef struct {
   char name[10];     /* Name of interface                     */
   char master[10];   /* Name of Master for Bundling           */
@@ -898,6 +928,7 @@ typedef struct isdn_devt {
 extern isdn_dev *dev;
 
 
+
 /* Utility-Macros */
 #define MIN(a,b) ((a<b)?a:b)
 #define MAX(a,b) ((a>b)?a:b)
index 6d63986033caa2c519b80c9af4003b3e0c991ff9..07e3b826df910b34e4345b51d8d97c3b20337099 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.31 1999/09/06 07:29:36 fritz Exp $
+/* $Id: isdnif.h,v 1.32 1999/10/11 22:03:00 keil Exp $
  *
  * Linux ISDN subsystem
  *
@@ -22,6 +22,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.32  1999/10/11 22:03:00  keil
+ * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
+ *
  * Revision 1.31  1999/09/06 07:29:36  fritz
  * Changed my mail-address.
  *
index bfc2b95c55ae5abadbb0076017de75d9d5e6d36a..40aa64ddb42da4c0b6483dbad18a086d3c952a23 100644 (file)
 #define PCI_DEVICE_ID_3DLABS_DELTA     0x0003
 #define PCI_DEVICE_ID_3DLABS_PERMEDIA  0x0004
 #define PCI_DEVICE_ID_3DLABS_MX                0x0006
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007
+#define PCI_DEVICE_ID_3DLABS_GAMMA     0x0008
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V        0x0009
 
 #define PCI_VENDOR_ID_AVANCE           0x4005
 #define PCI_DEVICE_ID_AVANCE_ALG2064   0x2064
index 032293ea354861648f8c87180c94b1259018bee0..d72dba85b4388f316c189dde93d02daaa7f45192 100644 (file)
@@ -124,8 +124,10 @@ struct rpc_rqst {
 struct rpc_xprt {
        struct rpc_xprt *       link;           /* list of all clients */
        struct rpc_xprt *       rx_pending;     /* receive pending list */
+       struct rpc_xprt *       tx_pending;     /* transmit pending list */
        
-       int                     rx_pending_flag;/* are we on the pending list ? */
+       int                     rx_pending_flag;/* are we on the rcv pending list ? */
+       int                     tx_pending_flag;/* are we on the xmit pending list ? */
 
        struct file *           file;           /* VFS layer */
        struct socket *         sock;           /* BSD socket layer */
index 753df742305b071d60113d7b0f3aef80a2647c86..e675d9b2aa2459041e8581b469098f47d97abd5f 100644 (file)
@@ -104,7 +104,8 @@ enum
        KERN_MSGMNB=36,         /* int: Maximum message queue size */
        KERN_MSGPOOL=37,         /* int: Maximum system message pool size */
        KERN_SYSRQ=38,          /* int: Sysreq enable */
-       KERN_SHMALL=41          /* int: maximum size of shared memory */
+       KERN_SHMALL=41,         /* int: maximum size of shared memory */
+       KERN_SPARC_STOP_A=44,   /* int: Sparc Stop-A enable */
 };
 
 
index f08a62ea87e751b1586293f0caf3626f8f9bd022..a771c9a632e7e2b44aade747d160b60f36b6fff9 100644 (file)
@@ -193,6 +193,7 @@ EXPORT_SYMBOL(vfs_unlink);
 EXPORT_SYMBOL(vfs_rename);
 EXPORT_SYMBOL(__pollwait);
 EXPORT_SYMBOL(ROOT_DEV);
+EXPORT_SYMBOL(inode_generation_count);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
index 51ee692b5d4019d6bdc84e73cf3fc6fbd2e659b6..46ec27a0ef01147b5c09507ee319dffbb8ddf839 100644 (file)
@@ -74,7 +74,12 @@ NORET_TYPE void panic(const char * fmt, ...)
                machine_restart(NULL);
        }
 #ifdef __sparc__
-       printk("Press L1-A to return to the boot prom\n");
+       {
+               extern int stop_a_enabled;
+               /* Make sure the user can actually press L1-A */
+               stop_a_enabled = 1;
+               printk("Press L1-A to return to the boot prom\n");
+       }
 #endif
 #ifdef __alpha__
        if (alpha_using_srm)
index 882e61311c42c7e4580c37102381b612119c36c8..bb3988849600057b567590f97dd32b2c7c7d9ab5 100644 (file)
@@ -53,6 +53,7 @@ extern int shmall_max;
 
 #ifdef __sparc__
 extern char reboot_command [];
+extern int stop_a_enabled;
 #endif
 #ifdef __powerpc__
 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
@@ -186,6 +187,8 @@ static ctl_table kern_table[] = {
 #ifdef __sparc__
        {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
         256, 0644, NULL, &proc_dostring, &sysctl_string },
+       {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
+        0644, NULL, &proc_dointvec},
 #endif
 #ifdef __powerpc__
        {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
index bce35d484cf1b550df1808f2c85684f9ecfba9bc..945f4a06b3e54f7de5f82d8cefeca5b6e756e4e9 100644 (file)
@@ -201,7 +201,7 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
         *      seems to set IFF_PROMISC.
         */
         
-       else if(dev->flags&(IFF_PROMISC/*|IFF_ALLMULTI*/))
+       else if(1 /*dev->flags&IFF_PROMISC*/)
        {
                if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
                        skb->pkt_type=PACKET_OTHERHOST;
index 1e5cf1b1142e0f4bd307218637ebea95b0af5d0c..79e738126407242e15d797b576b79cb23ba8ed87 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:    $Id: arp.c,v 1.77.2.1 1999/06/28 10:39:23 davem Exp $
+ * Version:    $Id: arp.c,v 1.77.2.4 1999/09/23 19:03:36 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
index 78c54be8e415fae0c3d1b1aea5303bd6ca52e5fa..6c1edfd7e68945fcfe2452456ec329a3d76248d7 100644 (file)
@@ -3,7 +3,7 @@
  *     
  *             Alan Cox, <alan@redhat.com>
  *
- *     Version: $Id: icmp.c,v 1.52.2.3 1999/09/22 16:33:02 davem Exp $
+ *     Version: $Id: icmp.c,v 1.52.2.4 1999/11/16 02:28:40 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
index 0614e22cda7dfa8ca6e596e796bf6081e0c334f7..fd8c0435dd8230d1fd3fae1817ba744006ad06f3 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The IP forwarding functionality.
  *             
- * Version:    $Id: ip_forward.c,v 1.43 1999/03/21 05:22:37 davem Exp $
+ * Version:    $Id: ip_forward.c,v 1.43.2.1 1999/11/16 06:33:43 davem Exp $
  *
  * Authors:    see ip.c
  *
index f95987d182f02842ec42b04a183ccc94ce196b8f..848cbfe8ba746c4c37cc9d410611b81e72b0260c 100644 (file)
@@ -2,7 +2,7 @@
  *     IP_MASQ_USER user space control module
  *
  *
- *     $Id: ip_masq_user.c,v 1.1.2.2 1999/08/13 18:26:33 davem Exp $
+ *     $Id: ip_masq_user.c,v 1.1.2.3 1999/11/16 06:33:51 davem Exp $
  */
 
 #include <linux/config.h>
index b308995b68c24524230f0c297c03adf9cebff924..2b114b3e549a8b236485d11e743881558183236c 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             ROUTE - implementation of the IP router.
  *
- * Version:    $Id: route.c,v 1.67.2.3 1999/08/08 08:43:12 davem Exp $
+ * Version:    $Id: route.c,v 1.67.2.4 1999/11/16 02:28:43 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
index dd7615e5a013eaaa56e621dfc5739bc912becd97..68b7e5e77859f379d2d15923b884e8e2d3b3e489 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.140.2.4 1999/08/09 03:13:12 davem Exp $
+ * Version:    $Id: tcp.c,v 1.140.2.5 1999/09/23 19:21:16 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
index a58382ef57d2f0113d4c856d7215d11b90f5ad3a..7f5cc4e7ebbc183b12f2acb2632672363f06ea00 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.164.2.7 1999/08/13 16:14:27 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.164.2.8 1999/09/23 19:21:23 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
index 55efebb5cb89f3dd4022a87ae49734c425118502..1864f09683f8df3ff4d3d6b398c3e9d9913f4e74 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.175.2.10 1999/08/13 16:14:35 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.175.2.13 1999/11/16 06:33:53 davem Exp $
  *
  *             IPv4 specific functions
  *
index ccb52088609eeca28490ff57492c4c43fdc30dc7..7529a441444f45f9283937813d3e0c683f7c8f79 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_timer.c,v 1.62.2.3 1999/06/20 20:14:30 davem Exp $
+ * Version:    $Id: tcp_timer.c,v 1.62.2.4 1999/09/23 19:21:39 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
index 54aef23dbe010746776a045c29305b4d3f4cbf43..9fc6a8e6d9232f71302638151448204579b1d963 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.104.2.9 1999/08/13 18:49:56 davem Exp $
+ *     $Id: tcp_ipv6.c,v 1.104.2.10 1999/09/23 19:21:46 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
index 8f20e82707a26e41dc53dfa706aea33ea4b35c35..dfa08241d48f545c21e3d27f6935ca572e1e6b43 100644 (file)
@@ -743,11 +743,29 @@ done:
        return result;
 }
 
+static __inline__ void tcp_output_record(struct rpc_xprt *xprt)
+{
+       if(xprt->snd_sent && xprt->snd_task)
+               dprintk("RPC: write space\n");
+       if(xprt->write_space == 0)
+       {
+               xprt->write_space = 1;
+               if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
+               {
+                       if(xprt->snd_sent)
+                               dprintk("RPC: Write wakeup snd_sent =%d\n",
+                                       xprt->snd_sent);
+                       rpc_wake_up_task(xprt->snd_task);                       
+               }
+       }
+}
+
 /*
  *     TCP task queue stuff
  */
  
-static struct rpc_xprt *rpc_xprt_pending = NULL;       /* Chain by rx_pending of rpc_xprt's */
+static struct rpc_xprt *rpc_rx_xprt_pending = NULL;    /* Chain by rx_pending of rpc_xprt's */
+static struct rpc_xprt *rpc_tx_xprt_pending = NULL;    /* Chain by tx_pending of rpc_xprt's */
 
 /*
  *     This is protected from tcp_data_ready and the stack as its run
@@ -765,11 +783,11 @@ void rpciod_tcp_dispatcher(void)
         *      Empty each pending socket
         */
         
-       while((xprt=rpc_xprt_pending)!=NULL)
+       while((xprt=rpc_rx_xprt_pending)!=NULL)
        {
                int safe_retry=0;
                
-               rpc_xprt_pending=xprt->rx_pending;
+               rpc_rx_xprt_pending=xprt->rx_pending;
                xprt->rx_pending_flag=0;
                
                dprintk("rpciod_tcp_dispatcher: Processing %p\n", xprt);
@@ -794,6 +812,13 @@ void rpciod_tcp_dispatcher(void)
                                        result);
                }
        }
+
+       while((xprt=rpc_tx_xprt_pending)!=NULL)
+       {
+               rpc_tx_xprt_pending = xprt->tx_pending;
+               xprt->tx_pending_flag = 0;
+               tcp_output_record(xprt);
+       }
 }
 
 
@@ -831,12 +856,12 @@ static void tcp_data_ready(struct sock *sk, int len)
        {
                int start_queue=0;
 
-               dprintk("RPC:     xprt queue %p\n", rpc_xprt_pending);
-               if(rpc_xprt_pending==NULL)
+               dprintk("RPC:     xprt queue %p\n", rpc_rx_xprt_pending);
+               if(rpc_rx_xprt_pending==NULL)
                        start_queue=1;
                xprt->rx_pending_flag=1;
-               xprt->rx_pending=rpc_xprt_pending;
-               rpc_xprt_pending=xprt;
+               xprt->rx_pending=rpc_rx_xprt_pending;
+               rpc_rx_xprt_pending=xprt;
                if (start_queue)
                  {
                    tcp_rpciod_queue();
@@ -878,18 +903,16 @@ tcp_write_space(struct sock *sk)
 
        if (!(xprt = xprt_from_sock(sk)))
                return;
-       if(xprt->snd_sent && xprt->snd_task)
-               dprintk("RPC: write space\n");
-       if(xprt->write_space == 0)
-       {
-               xprt->write_space = 1;
-               if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
-               {
-                       if(xprt->snd_sent)
-                               dprintk("RPC: Write wakeup snd_sent =%d\n",
-                                       xprt->snd_sent);
-                       rpc_wake_up_task(xprt->snd_task);                       
-               }
+       if (!xprt->tx_pending_flag) {
+               int start_queue = 0;
+
+               if (rpc_tx_xprt_pending == NULL)
+                       start_queue = 1;
+               xprt->tx_pending_flag = 1;
+               xprt->tx_pending = rpc_tx_xprt_pending;
+               rpc_tx_xprt_pending = xprt;
+               if (start_queue)
+                       tcp_rpciod_queue();
        }
 }