- 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
*************
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
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
**********************
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
==========
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
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
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
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
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.
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
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
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.
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
- 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
- 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
necessary. Those programs and some contributed utilities are available
at
- ftp.franken.de
+ ftp.isdn4linux.de
/pub/isdn4linux/isdn4k-utils-<VersionNumber>.tar.gz
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
--- /dev/null
+
+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
+
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
-$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.
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
------------------------
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.
- 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)
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.
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.
--- /dev/null
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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
----------------
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/)
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return 0;
}
if (pgd_bad(*pgdir)) {
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return 0;
}
if (pmd_bad(*pgmiddle)) {
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return 0;
}
page = pte_page(*pgtable);
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return;
}
if (pgd_bad(*pgdir)) {
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return;
}
if (pmd_bad(*pgmiddle)) {
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return;
}
page = pte_page(*pgtable);
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return;
}
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return 0;
}
if (pgd_bad(*pgdir)) {
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return 0;
}
if (pmd_bad(*pgmiddle)) {
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return 0;
}
page = pte_page(*pgtable);
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return;
}
if (pgd_bad(*pgdir)) {
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return;
}
if (pmd_bad(*pgmiddle)) {
if (fault > 0)
goto repeat;
if (fault < 0)
- force_sig(SIGKILL, current);
+ force_sig(SIGKILL, tsk);
return;
}
page = pte_page(*pgtable);
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 */
-/* $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)
.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)
#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
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
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
C_LABEL(vac_hwflush_patch1):
C_LABEL(vac_linesize_patch):
subcc %l7, 16, %l7
- bg 9b
+ bne 9b
C_LABEL(vac_hwflush_patch2):
sta %g0, [%l3 + %l7] ASI_FLUSHSEG
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
sun4c_fault_fromuser:
SAVE_ALL
+ nop
mov %l7, %o1 ! Decode the info from %l7
mov %l7, %o2
-/* $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)
*/
.ascii "HdrS"
.word LINUX_VERSION_CODE
- .half 0x0201 /* HdrS version */
+ .half 0x0203 /* HdrS version */
C_LABEL(root_flags):
.half 1
C_LABEL(root_dev):
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
-/* $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)
{
int ret = -EPERM;
- lock_kernel();
if (current->pid != 0)
goto out;
}
ret = 0;
out:
- unlock_kernel();
return ret;
}
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));
}
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));
}
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 */
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));
}
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));
}
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);
-/* $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)
initrd_start -= KERNBASE;
initrd_end -= KERNBASE;
break;
- }
+ default:
+ break;
+ };
}
}
#endif
-/* $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)
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 *);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memmove);
EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
EXPORT_SYMBOL_NOVERS(__lshrdi3);
EXPORT_SYMBOL_DOT(rem);
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();
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();
-/* $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
}
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 */
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);
-/* $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)
}
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.
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)
-# $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
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
--- /dev/null
+/* $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
-/* $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.
*
#include <asm/cprefix.h>
- .globl C_LABEL(__ashrdi3)
+ .text
+ .align 4
+ .globl C_LABEL(__ashrdi3)
C_LABEL(__ashrdi3):
tst %o2
be 3f
-# $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
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
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
-/* $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.
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));
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:
no_memory:
stats.failure++;
- oom(tsk);
+ force_sig(SIGKILL, tsk);
return 1;
bad_area:
-/* $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)
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;
/*
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;
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);
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);
}
}
}
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:
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;
{
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();
}
-/* $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)
#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/mxcc.h>
+#include <asm/mbus.h>
/* srmmu.c */
extern int viking_mxcc_present;
#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;
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;
}
-/* $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.
*
enum mbus_module srmmu_modtype;
+int vac_cache_size = 0;
+
__initfunc(static void should_not_happen(void))
{
prom_printf(shouldnothappen);
-/* $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)
#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.
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;
/* 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);
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
/* 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);
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);
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();
}
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();
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) {
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)
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)
__initfunc(static void init_hypersparc(void))
{
srmmu_name = "ROSS HyperSparc";
+ srmmu_modtype = HyperSparc;
init_vac_layout();
__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);
}
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!
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;
}
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);
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))
* 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";
-/* $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
#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);
}
{
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
: "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
{
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 {
}
}
-/* 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
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);
}
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);
sun4c_disable_vac();
if (ARCH_SUN4) {
- switch(idprom->id_machtype) {
+ switch (idprom->id_machtype) {
case (SM_SUN4|SM_4_110):
sun4c_vacinfo.type = NONE;
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.
*/
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);
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;
prom_printf("Unhandled number of segmaps: %d\n",
num_segmaps);
prom_halt();
- }
+ };
switch (num_contexts) {
case 8:
/* Default, nothing to do. */
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;
__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();
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.
*/
{
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);
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();
}
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];
{
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;
}
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);
}
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);
}
#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);
}
{
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;
}
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;
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;
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;
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);
{
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);
{
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)
{
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 {
free_user_entry(ctx, entry);
entry = next;
- } while(entry != head);
+ } while (entry != head);
sun4c_set_context(savectx);
}
restore_flags(flags);
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 {
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;
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)
{
#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;
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;
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);
}
/* 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. */
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));
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);
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);
{
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;
}
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 */
}
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--;
}
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--;
}
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();
}
{
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
begin += 512;
}
} else {
- while(begin < end) {
+ while (begin < end) {
__asm__ __volatile__("
ld [%0 + 0x00], %%g0
ld [%0 + 0x10], %%g0
{
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);
}
}
{
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
/* "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;
}
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;
/* 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);
/* "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;
}
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);
/* 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
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);
}
{
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 {
free_user_entry(new_ctx, entry);
entry = next;
- } while(entry != head);
+ } while (entry != head);
sun4c_set_context(savectx);
}
restore_flags(flags);
{
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;
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);
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);
}
}
{
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 {
free_user_entry(new_ctx, entry);
entry = next;
- } while(entry != head);
+ } while (entry != head);
sun4c_set_context(savectx);
}
restore_flags(flags);
{
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;
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);
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);
}
}
{
}
-
void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
int bus_type, int rdonly)
{
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);
}
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;
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. */
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);
}
{
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);
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;
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. */
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);
}
{
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);
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,
"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,
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;
}
* 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.
#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);
* 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);
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)));
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))
{
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--;
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;
}
{
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--;
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;
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);
}
} 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);
}
}
+/* 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));
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;
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);
--- /dev/null
+/* $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
-/* $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)
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
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
-# $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.
#
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
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
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
-/* $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)
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;
(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,
} 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];
+ }
}
}
} else {
dev->num_irqs = len / sizeof(irqs[0]);
for (i = 0; i < dev->num_irqs; i++) {
- ebus_intmap_match(dev->bus, ®s[0], &irqs[i]);
- dev->irqs[i] = psycho_irq_build(dev->bus->parent,
- dev->bus->self, irqs[i]);
+ if (ebus_intmap_match(dev->bus, ®s[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];
+ }
}
}
-/* $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)
.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
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
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
-/* $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)
.ascii "HdrS"
.word LINUX_VERSION_CODE
- .half 0x0202 /* HdrS version */
+ .half 0x0203 /* HdrS version */
root_flags:
.half 1
root_dev:
.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
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
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
set_worklist:
sllx %g1, 7, %g1
add %g5, %g1, %g5
- add %g5, 64, %g1
+ add %g5, 64, %g6
#endif
/* Kill PROM timer */
-/* $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)
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);
case TIOCSCTTY:
case TIOCGPTN:
case TIOCSPTLCK:
+ case TIOCGSERIAL:
+ case TIOCSSERIAL:
+ case TIOCSERGETLSR:
/* Big F */
case FBIOGTYPE:
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:
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;
(int)fd, (unsigned int)cmd, (unsigned int)arg);
} while(0);
error = -EINVAL;
- break;
+ goto out;
}
out:
+ fput(filp);
+out2:
unlock_kernel();
return error;
}
-/* $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)
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:
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);
{
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) {
/* 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
}
}
}
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");
pgd_t * pgdir;
pmd_t * pgmiddle;
pte_t * pgtable;
+ int fault;
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
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));
}
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));
}
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;
}
-/* $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)
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))
{
}
}
}
- 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.
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
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;
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) {
/* 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)
-/* $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)
#include <linux/personality.h>
#include <linux/stat.h>
#include <linux/timex.h>
+#include <linux/filter.h>
#include <asm/types.h>
#include <asm/ipc.h>
}
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),
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);
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;
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),
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);
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:
-/* $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)
*/
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)
{
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)
: "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
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
-/* $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
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
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
/* 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
#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
/* 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
-/* $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)
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
-/* $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.
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));
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:
no_memory:
stats.failure++;
- oom(tsk);
+ force_sig(SIGKILL, tsk);
return 1;
bad_area:
-/* $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)
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;
/*
}
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;
-/* $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)
/* 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;
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");
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();
}
}
}
}
+
+ /* 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
#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.
*
*/
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);
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;
}
/* 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
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();
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++)
-/* $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)
*
* 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
.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
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
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
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
cmp %g2, 63
ble,pt %icc, 1b
sll %g2, 3, %g3
- flush %g1
+ flush %g6
retry
.globl xcall_flush_cache_all
cmp %g3, %g2
bleu,pt %xcc, 1b
nop
- flush %g1
+ flush %g6
retry
#endif /* __SMP__ */
-# $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.
#
# 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
$(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
--- /dev/null
+/* $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
-/* $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.
*
#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>
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.
*/
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 */
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)
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. */
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. */
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.
*/
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),
-/* $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)
*/
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)
#if 1 /* DEBUGGING */
if (prom_entry_depth != 0)
panic("prom_get_lock");
-#endif
-#ifdef __SMP__
- smp_capture();
#endif
}
prom_entry_depth++;
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);
}
* 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 {
*/
(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;
}
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 */
}
handle_scancode(scancode, !(scancode & 0x80));
mark_bh(KEYBOARD_BH);
}
-
+ mdelay(1);
status = kbd_read_status();
if(!work--)
# 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
-/* $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()
*
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;
* 0 = Signature not found.
*/
static int
-isa_reset(unsigned short portbase)
+act2000_isa_reset(unsigned short portbase)
{
unsigned char reg;
int i;
}
int
-isa_detect(unsigned short portbase)
+act2000_isa_detect(unsigned short portbase)
{
int ret = 0;
unsigned long flags;
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;
/* 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) {
}
static void
-isa_select_irq(act2000_card * card)
+act2000_isa_select_irq(act2000_card * card)
{
unsigned char reg;
}
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);
}
* 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;
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;
}
} 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;
"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);
}
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);
* Release ressources, used by an adaptor.
*/
void
-isa_release(act2000_card * card)
+act2000_isa_release(act2000_card * card)
{
unsigned long flags;
}
static int
-isa_writeb(act2000_card * card, u_char data)
+act2000_isa_writeb(act2000_card * card, u_char data)
{
u_char timeout = 40;
}
static int
-isa_readb(act2000_card * card, u_char * data)
+act2000_isa_readb(act2000_card * card, u_char * data)
{
u_char timeout = 40;
}
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) {
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;
}
} 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);
}
}
}
}
void
-isa_send(act2000_card * card)
+act2000_isa_send(act2000_card * card)
{
unsigned long flags;
struct sk_buff *skb;
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 */
* Get firmware ID, check for 'ISDN' signature.
*/
static int
-isa_getid(act2000_card * card)
+act2000_isa_getid(act2000_card * card)
{
act2000_fwid fid;
while (1) {
if (count > 510)
return -EPROTO;
- if (isa_readb(card, p++))
+ if (act2000_isa_readb(card, p++))
break;
count++;
}
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;
}
* 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;
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));
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);
p += l;
}
kfree(buf);
- isa_delay(HZ / 2);
- return (isa_getid(card));
+ act2000_isa_delay(HZ / 2);
+ return (act2000_isa_getid(card));
}
-/* $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.
*
/* 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 */
-/* $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;
{
switch (card->bus) {
case ACT2000_BUS_ISA:
- isa_send(card);
+ act2000_isa_send(card);
break;
case ACT2000_BUS_PCMCIA:
case ACT2000_BUS_MCA:
{
switch (card->bus) {
case ACT2000_BUS_ISA:
- isa_receive(card);
+ act2000_isa_receive(card);
break;
case ACT2000_BUS_PCMCIA:
case ACT2000_BUS_MCA:
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;
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:
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:
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);
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 */
/*
- * $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
__u8 sendbuf[128+2048];
} avmcard_dmainfo;
+
typedef struct avmcard {
char name[32];
unsigned int port;
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 */
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];
/*
}
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,
/*
- * $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.
*
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.12 $";
/* ------------------------------------------------------------- */
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;
}
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);
}
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;
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;
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);
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;
}
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);
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);
}
}
- if (!b1_loaded(port)) {
+ if (!b1_loaded(card)) {
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
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);
}
__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;
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;
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);
/* ------------------------------------------------------------- */
-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);
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" : "",
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;
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;
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;
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) {
(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;
/*
- * $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.
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.5 $";
/* ------------------------------------------------------------- */
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);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
{
+ avmctrl_info *cinfo;
avmcard *card;
int retval;
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;
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;
}
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;
}
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;
}
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;
}
/* ------------------------------------------------------------- */
/*
- * $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
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.16 $";
+static char *revision = "$Revision: 1.18 $";
/* ------------------------------------------------------------- */
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;
}
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);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
ctrl->driverdata = 0;
+ kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
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;
}
/* ------------------------------------------------------------- */
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;
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;
}
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;
}
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
}
/*
- * $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.
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.5 $";
/* ------------------------------------------------------------- */
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;
}
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);
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;
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;
}
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;
}
/* ------------------------------------------------------------- */
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;
/*
- * $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>
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))
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 */
/*
- * $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>");
/* 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},
);
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++,
);
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:
/*
- * $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"
#include <linux/b1lli.h>
#endif
-static char *revision = "$Revision: 1.8 $";
+static char *revision = "$Revision: 1.10 $";
/* ------------------------------------------------------------- */
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;
}
/*
- * $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.
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.8 $";
/* ------------------------------------------------------------- */
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;
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);
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);
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;
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;
}
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;
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);
}
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);
}
}
- if (!b1_loaded(port)) {
+ if (!b1_loaded(card)) {
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
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);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
+ kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
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;
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;
}
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;
}
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);
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;
}
--- /dev/null
+/*
+ * $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, ®, 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, ®, 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, ¶m);
+ 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
-/* $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 {
#include <linux/delay.h>
#include <linux/ctype.h>
+#include <linux/isdn.h>
#include <linux/isdnif.h>
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 */
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 {
#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
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 */
#endif /* CONFIG_MCA */
extern ulong DebugVar;
+extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
#endif /* __KERNEL__ */
-/* $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
* 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;
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);
}
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)
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:
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);
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);
}
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
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);
}
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)
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);
}
__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;
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++];
}
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)) {
}
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;
}
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:
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;
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:
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);
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);
}
}
}
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 ********/
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)
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:
'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) &&
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;
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]);
}
}
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 */
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;
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)
}
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:
}
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);
}
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;
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;
/* 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);
}
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 */
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;
}
}
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;
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;
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);
}
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;
#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);
#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);
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;
}
/* 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) {
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) &&
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;
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:
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))
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;
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) {
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);
}
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();
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)
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)
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)
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;
}
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)
-/* $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) {
/* 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) {
}
}
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;
}
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;
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;
}
}
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))) {
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;
}
prram = 0;
break;
default:
- printk(KERN_WARNING "eicon_transmit: unsupported card-type!\n");
+ eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n");
return;
}
}
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;
}
}
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);
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 */
((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
chan->waitq = reqbuf->XBuffer.length;
chan->waitpq += reqbuf->XBuffer.length;
+ dlev = 128;
}
}
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);
}
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)
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;
}
prram = 0;
break;
default:
- printk(KERN_WARNING "eicon_irq: unsupported card-type!\n");
+ eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n");
return;
}
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;
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);
} 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);
}
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;
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);
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);
}
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;
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);
-/* $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.
*
* 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.
*
#define eicon_isa_h
#ifdef __KERNEL__
+#include <linux/config.h>
/* Factory defaults for ISA-Cards */
#define EICON_ISA_MEMBASE 0xd0000
-/* $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;
{
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;
}
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);
}
}
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);
}
}
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);
}
}
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))) {
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:
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;
}
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;
}
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;
}
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;
}
&(((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;
}
}
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;
}
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:
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;
}
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,
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;
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;
}
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) {
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
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;
}
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;
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;
}
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;
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;
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;
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;
}
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;
}
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);
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
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) {
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++;
};
{
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++)
{
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);
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);
/* 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;
};
-/* $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;
}
}
-static void
-channel_report(struct Channel *chanp)
-{
-}
-
static void
distr_debug(struct IsdnCardState *csta, int debugflags)
{
{
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;
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;
}
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;
-/* $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
*
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;
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));
}
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]);
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
}
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++) {
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++) {
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];
-/* $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
*
*
*
* $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
*
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);
debugl1(cs, "FIFO CRC error");
dev_kfree_skb(skb);
skb = NULL;
+#ifdef ERROR_STATISTIC
+ bcs->err_crc++;
+#endif
}
}
}
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);
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);
-/* $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
*
*
*
* $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
*
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)))
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 |
-/* $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},
};
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);
{
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 */
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);
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);
}
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 */
/*******************************************************************************/
/* 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 */
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;
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;
}
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,
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;
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)
goto Begin;
restore_flags(flags);
return;
-} /* receive_emsg */
+} /* receive_emsg */
/*********************/
/* Interrupt handler */
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)
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,
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();
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 {
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
+ int flags;
switch (pr) {
case (PH_DATA | REQUEST):
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);
{
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);
}
/******************************/
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))
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));
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;
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);
(((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);
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");
-/* $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
-/* $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
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;
struct teles0_hw {
unsigned int cfg_reg;
- unsigned int membase;
+ unsigned long membase;
+ unsigned long phymem;
};
struct avm_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 */
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;
};
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
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);
-/* $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
*
* 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
*
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) & (
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.
*/
/* 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;
-/* $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
*
* ../../../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)
*
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;
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))
-/* $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
*
*
*
* $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!)
*
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 {
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);
-/* $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);
-/* $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()
*
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)
#define ISURF_ISAR_OFFSET 0
#define ISURF_ISAC_OFFSET 0x100
-
+#define ISURF_IOMEM_SIZE 0x400
/* Interface functions */
static u_char
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",
} 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;
-/* $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
*
* 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
*
#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
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;
}
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;
}
# 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
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-----
-/* $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
*
* 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()
*
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)
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;
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 =
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;
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;
-/* $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),
* 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
#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
#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 */
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
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);
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);
}
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));
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);
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 {
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;
-/* $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
* 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();
}
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);
"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],
}
/* 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)) {
-/* $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
*
*
*
* $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
*
#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
} 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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
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);
/* 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);
-/* $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;
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]);
}
/* 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]) {
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;
}
}
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) {
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;
}
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 */
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);
-/* $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
*
-/* $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 */
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
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 );
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:
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);
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).
lp->netdev->dev.tbusy = 0;
mark_bh(NET_BH);
}
+#endif /* ISDN_NEW_TBUSY */
return 1;
}
break;
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);
* 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)
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;
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)))
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).
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 */
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]) {
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
/* 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 */
}
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
}
lp->first_skb = skb;
/* Initiate dialing */
+#ifndef ISDN_NEW_TBUSY
ndev->tbusy = 0;
+#endif
restore_flags(flags);
isdn_net_dial();
return 0;
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;
isdn_net_phone *n;
ulong flags;
char nr[32];
-
/* Search name in netdev-chain */
save_flags(flags);
cli();
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;
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;
restore_flags(flags);
return 0;
}
-
-/* $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>
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);
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;
/*
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);
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;
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;
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 */
/* 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);
{
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)) {
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)
}
/* 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));
}
}
-
int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
{
ipc->next = ipc_head;
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);
-/* $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()
*
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()
isdn_tty_modem_hup(modem_info * info, int local)
{
isdn_ctrl cmd;
- int usage;
if (!info)
return;
}
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;
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;
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];
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;
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';
}
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;
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;
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))
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;
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--;
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;
}
}
}
-/* $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).
*
* 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.
*
#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
}
/* isdn_v110_close frees private V.110 data structures */
-static void
+void
isdn_v110_close(isdn_v110_stream * v)
{
if (v == NULL)
-/* $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).
*
* 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).
*
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
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);
/* board */
volatile unsigned char* sh_mem; /* RDP address */
+ unsigned long ph_mem;
unsigned int irq;
unsigned int id;
unsigned int interrupt; /* set during interrupt
#define L2_ERROR 6
#endif
-
-
-
-
-
-
-
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
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
}
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;
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;
{
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:
}
if(tries)
return 0;
- printk("BigMAC: Cannot reset the QEC.\n");
+ printk(KERN_ERR "BigMAC: Cannot reset the QEC.\n");
return -1;
}
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);
}
}
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);
}
}
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");
}
}
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;
}
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;
}
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;
};
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;
};
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);
}
}
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);
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");
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;
}
} 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;
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);
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, ");
#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");
}
}
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__
}
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
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);
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;
}
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;
}
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;
}
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;
}
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],
/* 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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
/* 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. */
}
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
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
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;
/* 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;
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;
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;
}
*/
/* 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 {
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;
/* 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"));
/* 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"));
/* 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"));
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;
}
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"));
}
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 {
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;
}
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... */
}
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;
}
/* 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;
}
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)
/* 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)
/* 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;
}
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);
}
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((">"));
}
}
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
}
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((">"));
}
}
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
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;
}
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;
}
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;
}
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));
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();
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;
}
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;
}
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));
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");
}
}
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;
#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;
}
"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;
}
"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;
}
"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;
}
"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;
}
"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;
}
/* 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;
return -ENOMEM;
}
if(hme_version_printed++ == 0)
- printk(version);
+ printk(KERN_INFO "%s", version);
if (!qfe_slot) {
prom_name[0] = 0;
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");
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;
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;
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;
}
* 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);
latency_timer = 64;
else
latency_timer = ((min_gnt << 3) & 0xff);
+#endif
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer);
}
#ifdef __sparc_v9__
-/* $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
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);
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;
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;
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;
int csr0;
if (dev->interrupt)
- printk ("%s: again", dev->name);
+ printk (KERN_ERR "%s: again", dev->name);
dev->interrupt = 1;
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;
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;
}
/* 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;
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;
}
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);
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;
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
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);
}
/* 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;
}
}
if(tries)
return 0;
- printk("QuadEther: AIEEE cannot reset the QEC!\n");
+ printk(KERN_ERR "QuadEther: AIEEE cannot reset the QEC!\n");
return -1;
}
break;
}
if(!tries) {
- printk("QuadEther: AIEEE cannot reset the MACE!\n");
+ printk(KERN_ERR "QuadEther: AIEEE cannot reset the MACE!\n");
return -1;
}
break;
}
if(!tries) {
- printk("QuadEther: Cannot reset QE channel!\n");
+ printk(KERN_ERR "QuadEther: Cannot reset QE channel!\n");
return -1;
}
return 0;
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. */
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) {
}
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;
}
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++;
}
}
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;
}
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,
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;
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++) {
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;
"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;
}
"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;
}
"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;
}
*/
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],
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 */
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;
};
channel->input_count = 0;
if (channel->input_callback)
(*channel->input_callback)
- (channel->input_callback_arg, 1);
+ (channel->input_callback_arg, 1, 0);
}
}
}
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;
};
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));
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));
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);
#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>
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);
}
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");
dbri_cmdsend(dbri, cmd);
}
+#if 0
/* unlink_time_slot()
*
* I don't use this function, so it's basically untested.
dbri_cmdsend(dbri, cmd);
}
+#endif
/* xmit_fixed() / recv_fixed()
*
* 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;
buf, len);
restore_flags(flags);
- if (error <= 0)
+ if (error < 0)
error = -EINVAL;
break;
-/* $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)
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;
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 {
}
}
printk("pcimouse_init: no 8042 found\n");
- return -ENODEV;
+ goto do_enodev;
found:
pcimouse_iobase = child->base_address[0];
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,
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))
{
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 */
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) {
kbnode = prom_finddevice(prop);
}
if (!kbnode)
- return -ENODEV;
+ goto do_enodev;
len = prom_getproperty(node, "mouse", prop, sizeof(prop));
if (len > 0) {
msnode = prom_finddevice(prop);
}
if (!msnode)
- return -ENODEV;
+ goto do_enodev;
/*
* Find matching EBus nodes...
pnode = prom_getsibling(pnode);
pnode = prom_searchsiblings(pnode, "pci");
}
+do_enodev:
+ sunkbd_setinitfunc(memory_start, pcimouse_no_init);
return -ENODEV;
found:
-/* $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;
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.
__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, ' ');
printk("SAB82532 serial driver version %s\n", serial_version);
}
+extern int su_num_ports;
+
/*
* The serial driver boot-time initialization code!
*/
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;
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]);
}
__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) {
-/* $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.
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
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];
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];
return 0;
}
-#ifdef __sparc_v9__
-
static inline
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
* 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)
}
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;
}
sunkbd_inchar(ch, regs);
} else {
- sun_mouse_inbyte(ch);
+ sun_mouse_inbyte(ch, is_brk);
}
status = su_inb(info, UART_LSR);
{
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;
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
(status & UART_MSR_DCD))
hardpps();
#endif
- }
+ }
if (status & UART_MSR_DCTS)
icount->cts++;
wake_up_interruptible(&info->delta_msr_wait);
#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");
/*
* 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 {
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)
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 {
{
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);
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;
/*
* ---------------------------------------------------------------------
- * 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.
* ---------------------------------------------------------------------
*/
*/
__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, ' ');
}
/*
- * 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.
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 *)®0, sizeof(reg0)) == -1) {
prom_printf("su: no \"reg\" property\n");
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.
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 */
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
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!
*/
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;
}
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;
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();
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;
}
if (su_inb(info, UART_LSR) == 0xff)
return -1;
+ info->is_console = 1;
+
return 0;
}
NULL
};
+int su_console_registered = 0;
+
/*
* Register console.
*/
return 0;
sercons.index = 0;
register_console(&sercons);
+ su_console_registered = 1;
return 0;
}
+
/* Do not edit this file! It was automatically generated by */
/* loadkeys --mktable defkeymap.map > defkeymap.c */
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,
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,
};
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,
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,
};
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,
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,
};
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,
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,
};
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,
};
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,
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,
};
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
'\033', '[', 'P', 0,
};
+
char *funcbufptr = func_buf;
int funcbufsize = sizeof(func_buf);
int funcbufleft = 0; /* space left */
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
unsigned int tail;
union {
char stream [STREAM_SIZE];
- Firm_event ev [0];
+ Firm_event ev [EV_SIZE];
} queue;
};
}
/* 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". */
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
printk("DX2<%d>", mvalue);
#endif
sunmouse.delta_x += mvalue;
+ sunmouse.delta_x = CLIP(sunmouse.delta_x);
sunmouse.byte++;
return;
case 4:
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
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){
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);
} 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);
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))
-/* $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)
#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) */
-/* $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)
#include "sunserial.h"
int serial_console;
+int stop_a_enabled = 1;
__initfunc(int con_is_present(void))
{
* 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)
-/* $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)
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
-/* $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)
*/
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
goto next_char;
}
if(info->cons_mouse) {
- sun_mouse_inbyte(ch);
+ sun_mouse_inbyte(ch, 0);
do_queue_task = 0;
goto next_char;
}
* '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...
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, ' ');
*/
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;
*/
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;
"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);
}
* 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));
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 */
}
/*
#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
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;
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;
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);
}
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];
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;
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;
}
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)) {
}
/* 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;
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;
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);
int nqptis = 0, nqptis_in_use = 0;
int qpti_node;
int is_pti;
+ unsigned int cfreq;
tpnt->proc_dir = &proc_scsi_qlogicpti;
qptichain = 0;
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.
/* 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));
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));
#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");
{
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;
}
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);
}
}
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);
}
/*
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;
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;
}
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;
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];
#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... */
{"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...
/*****************************************************************************
*
- * 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)
#endif
/* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.10"
+#define DRIVER_VERSION "0.12"
#ifndef PCI_VENDOR_ESS
#define PCI_VENDOR_ESS 0x125D
#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
[TYPE_MAESTRO2E] = "ESS Maestro 2E"
};
+static int clock_freq[]={
+ [TYPE_MAESTRO] = (49152000L / 1024L),
+ [TYPE_MAESTRO2] = (50000000L / 1024L),
+ [TYPE_MAESTRO2E] = (50000000L / 1024L)
+};
/* --------------------------------------------------------------------- */
[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,
/* 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;
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;
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");
maestro_ac97_set(iobase, 0x0E, 0x801F);
return 0;
}
+#endif
/* this is very magic, and very slow.. */
static void
/* 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
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;
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)|
{
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)|
/* 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);
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);
/* 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 */
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! */
}
/* 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;
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)
{
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)
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);
}
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;
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) {
}
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;
start_dac(s);
}
return_free:
- if (splitbuf) kfree(splitbuf);
return ret;
}
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;
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;
db->mapped = 1;
return 0;
}
-#endif
static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
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) {
: (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);
(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:
NULL, /* readdir */
&ess_poll,
&ess_ioctl,
- NULL, /* XXX &ess_mmap, */
+ &ess_mmap,
&ess_open,
NULL, /* flush */
&ess_release,
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 */
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);
}
}
static int
-maestro_apm_suspend(void)
+maestro_suspend(void)
{
struct ess_card *card;
unsigned long flags;
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);
}
return 0;
}
static int
-maestro_apm_resume(void)
+maestro_resume(void)
{
struct ess_card *card;
unsigned long flags;
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;
}
-/* $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
} fbcon_cmap;
u8 blitter_may_be_busy;
#ifdef __sparc__
- u8 open;
u8 mmaped;
+ int open;
int vtconsole;
int consolecnt;
#endif
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++;
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--;
}
}
-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
*/
-/* $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)
#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__
-/* $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)
-/* $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)
-/* $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)
-/* $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)
/* 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;
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.
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;
}
static int PROC_CONSOLE(struct fb_info *info)
{
int fgc;
-
+
if (info->display_fg != NULL)
fgc = info->display_fg->vc_num;
else
/* 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;
+ }
}
}
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);
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 */
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;
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;
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
-/* $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)
/*
* 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
#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];
};
#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 */
u32 cmap32[16];
#endif
} cmap;
+ struct pm2_cursor *cursor;
} fb_info;
#ifdef CONFIG_FB_PM2_CVPPC
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:
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 */,
};
/***************************************************************************
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
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;
}
}
+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);
} 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);
!(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) {
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) {
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);
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);
};
/*
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);
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);
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)) {
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;
}
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;
* 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()) {
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");
__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* )
(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))) {
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 */
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 */
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 */
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 */
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;
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);
}
}
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,
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
***************************************************************************/
__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);
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) {
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;
}
}
***************************************************************************/
#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) {
#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 */
/*****************************************************************************
-/* $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)
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;
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);
* 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>
/*
* 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!
*/
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;
* 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);
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");
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,
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
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)
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 */
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] == '.')
{
}
#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);
#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
-/* $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 */
#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
-/* $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>
#ifndef __ASSEMBLY__
+extern spinlock_t ctx_alloc_lock;
extern unsigned long tlb_context_cache;
extern unsigned long mmu_context_bmap[];
* 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; \
__asm__ __volatile__("flush %g6"); \
} \
} \
+ spin_unlock(&ctx_alloc_lock); \
} while (0)
/* This routine must called with interrupts off,
-/* $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.
*
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
-/* $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;
/* #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 */
-/* $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;
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 */
extern isdn_dev *dev;
+
/* Utility-Macros */
#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)
-/* $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
*
* 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.
*
#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
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 */
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 */
};
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);
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)
#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;
#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),
* 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;
/* 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
*
*
* 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
*
* 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
*
* 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>
*
* 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>
*
* 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>
*
* 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>
*
* 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
*
*
* 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>
* 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
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
* 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);
result);
}
}
+
+ while((xprt=rpc_tx_xprt_pending)!=NULL)
+ {
+ rpc_tx_xprt_pending = xprt->tx_pending;
+ xprt->tx_pending_flag = 0;
+ tcp_output_record(xprt);
+ }
}
{
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();
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();
}
}