E: rubini@ipvvis.unipv.it
D: the gpm mouse server and kernel support for it
+N: Paul Russell
+E: Paul.Russell@rustcorp.com.au
+W: http://www.adelaide.net.au/~rustcorp
+D: Ruggedly handsome.
+D: Developed Generic IP Firewalling Chains with Michael Neuling.
+
N: Thomas Sailer
E: sailer@ife.ee.ethz.ch
E: HB9JNX@HB9W.CHE.EU (packet radio)
S: 10200 Prague 10, Hostivar
S: Czech Republic
+N: Andrew Veliath
+E: andrewtv@usa.net
+D: Turtle Beach MultiSound sound driver
+S: USA
+
N: Dirk Verworner
D: Co-author of german book ``Linux-Kernel-Programmierung''
D: Co-founder of Berlin Linux User Group
Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
needs.
-Last updated: May 12, 1998
+Last updated: May 31, 1998
Current Author: Chris Ricker (kaboom@gatech.edu).
Current Minimal Requirements
- Gnu C 2.7.2.3 ; gcc --version
- Binutils 2.8.1.0.23 ; ld -v
- Linux C Library 5.4.44 ; ls -l /lib/libc.so.*
-- Dynamic Linker (ld.so) 1.9.5 ; ldd --version
+- Dynamic Linker (ld.so) 1.9.9 ; ldd --version or ldd -v
- Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.*
- Procps 1.2.7 ; ps --version
-- Procinfo 13 ; procinfo -v
+- Procinfo 14 ; procinfo -v
- Mount 2.7l ; mount --version
- Net-tools 1.45 ; hostname -V
- Loadlin 1.6a
of /proc/net/dev changed; as a result, an older ifconfig will
incorrectly report errors.
+ As of 2.1.102, the firewalling code has been replaced with
+firewalling chains. See
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html for
+more information. Among other things, you'll now need to use ipchains
+instead of ipfwadm to configure your filters.
+
+ The IP firewalling code has been replaced: ipfwadm will no longer
+work. You need to obtain `ipchains', available from
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+which includes an ipfwadm wrapper.
+
Memory
======
RPM
===
- If you run Red Hat Linux or any other distribution that uses RPM, you
-need to upgrade RPM to version 2.2.7 or later.
+ If you run Red Hat Linux or any other distribution that uses RPM,
+you need to upgrade RPM to version 2.2.7 or later.
DOSEMU
======
Dynamic Linker
==============
-The 1.9.5 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.5.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.5.tar.gz
+The 1.9.9 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.9.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.9.tar.gz
Modules utilities
=================
Procinfo utilities
==================
-The 13 release:
-ftp://ftp.cistron.nl/pub/people/svm/procinfo-13.tar.gz
+The 14 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-14.tar.gz
RPM utilities
=============
The 2.2.7 release for Intel:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-2.2.7-1.i386.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.i386.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-2.2.7-1.i386.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.i386.rpm
The 2.2.7 release for Alpha:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/axp/rpm-2.2.7-1.axp.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/axp/rpm-devel-2.2.7-1.axp.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-2.2.7-1.axp.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/axp/rpm-devel-2.2.7-1.axp.rpm
The 2.2.7 release for SPARC:
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-2.2.7-1.sparc.rpm
-ftp://ftp.redhat.com/pub/redhat/redhat-4.0/updates/i386/rpm-devel-2.2.7-1.sparc.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-2.2.7-1.sparc.rpm
+ftp://ftp.redhat.com/pub/redhat/old-releases/redhat-4.0/updates/sparc/rpm-devel-2.2.7-1.sparc.rpm
DOSEMU
======
The 2.3.5 release:
ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.5.tar.gz
+IP Chains
+=========
+
+The 1.3.3 release:
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.gz
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.bz2
+
Other Info
==========
CONFIG_BLK_DEV_LOOP
Saying Y here will allow you to mount a file as a file system. This
is useful if you want to check an ISO9660 file system before burning
- the CD, or want to use floppy images without first writing them to
- floppy. This option also allows you to mount a filesystem with
- encryption. To use these features, you need a recent version of
- mount (available via FTP (user: anonymous) from
- ftp://ftp.win.tue.nl/pub/linux/util/). Note that this loop device
- has nothing to do with the loopback device used for network
- connections from the machine to itself. Most users will answer N
- here.
+ the CD, or if you want to use floppy images without first writing
+ them to floppy.
+
+ This option also allows you to mount a filesystem with encryption.
+ (Note that an alternative way to encrypt filesystems is provided by
+ the cfs package, which can be gotten via FTP (user: anonymous) from
+ ftp://ftp.replay.com/pub/crypto/disk).
+
+ To use the loop device, you need a recent version of mount
+ (available via FTP (user: anonymous) from
+ ftp://ftp.win.tue.nl/pub/linux/util/).
+
+ Note that this loop device has nothing to do with the loopback
+ device used for network connections from the machine to itself.
+
+ Most users will answer N here.
Network Block Device support
CONFIG_BLK_DEV_NBD
CONFIG_BLK_DEV_IDESCSI
This will provide SCSI host adapter emulation for IDE ATAPI devices,
and will allow you to use a SCSI device driver instead of a native
- ATAPI driver. This is useful if you have an ATAPI device for which
- no native driver has been written (for example, an ATAPI PD-CD or
- CDR drive); you can then use this emulation together with an
- appropriate SCSI device driver. If both this SCSI emulation and
- native ATAPI support are compiled into the kernel, the native
- support will be used. Normally, say N.
+ ATAPI driver.
+
+ This is useful if you have an ATAPI device for which no native
+ driver has been written (for example, an ATAPI PD-CD or CDR drive);
+ you can then use this emulation together with an appropriate SCSI
+ device driver. In order to do this, say Y here and to "SCSI support"
+ and "SCSI generic support", below.
+
+ Note that this option does NOT allow you to attach SCSI devices to a
+ box that doesn't have a SCSI host adapter installed.
+
+ If both this SCSI emulation and native ATAPI support are compiled
+ into the kernel, the native support will be used.
+
+ If unsure, say N.
CMD640 chipset bugfix/support
CONFIG_BLK_DEV_CMD640
CONFIG_BLK_DEV_NS87415
This driver adds detection and support for the NS87415 chip
(used in SPARC64, among others).
+
Please read the comments at the top of drivers/block/ns87415.c.
QDI QD6580 support
CONFIG_BLK_DEV_QD6580
This driver is enabled at runtime using the "ide0=qd6580" kernel
boot parameter. It permits faster I/O speeds to be set. See the
- Documentation/ide.txt and qd6580.c files for more info.
+ files Documentation/ide.txt and qd6580.c for more info.
UMC 8672 support
CONFIG_BLK_DEV_UMC8672
This driver is enabled at runtime using the "ide0=umc8672" kernel
boot parameter. It enables support for the secondary IDE interface
of the UMC-8672, and permits faster I/O speeds to be set as well.
- See the Documentation/ide.txt and umc8672.c files for more info.
+ See the files Documentation/ide.txt and umc8672.c for more info.
ALI M14xx support
CONFIG_BLK_DEV_ALI14XX
This driver is enabled at runtime using the "ide0=ali14xx" kernel
boot parameter. It enables support for the secondary IDE interface
of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
- I/O speeds to be set as well. See the Documentation/ide.txt and
- ali14xx.c files for more info.
+ I/O speeds to be set as well. See the files Documentation/ide.txt
+ and ali14xx.c for more info.
Apple Macintosh builtin IDE interface support (EXPERIMENTAL)
CONFIG_BLK_DEV_MAC_IDE
This is the IDE driver for the builtin IDE interface on some Apple
Macintosh models. It supports both the Quadra/Performa/LC 630 and
the PowerBook 190 IDE interface.
+
Say Y if you have such a Macintosh model and want to use IDE devices
(hard disks, CD-ROM drives, etc.) that are connected to the builtin
IDE interface.
XT hard disk support
CONFIG_BLK_DEV_XD
- Very old 8 bit hard disk controllers used in the IBM XT computer. To
- include a driver for these, say Y. If you want to compile the 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. The module will be called xd.o. It's
- pretty unlikely that you have one of these: say N.
+ Very old 8 bit hard disk controllers used in the IBM XT computer
+ will be supported if you say Y here.
+
+ If you want to compile the 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. The module will be
+ called xd.o.
+
+ It's pretty unlikely that you have one of these: say N.
Parallel port IDE device support
CONFIG_PARIDE
This option enables the high-level driver for ATAPI tape devices
connected through a parallel port. If you chose to build PARIDE
support into your kernel, you may answer Y here to build in the
- parallel port ATAPI disk driver, otherwise you should answer M
+ parallel port ATAPI tape driver, otherwise you should answer M
to build it as a loadable module. The module will be called pt.o.
You must also have at least one parallel port protocol driver in
your system. Among the devices supported by this driver is the
parallel port version of the HP 5GB drive.
+Parallel port generic ATAPI devices
+CONFIG_PARIDE_PG
+ This option enables a special high-level driver for generic ATAPI
+ devices connected through a parallel port. The driver allows user
+ programs, such as cdrecord, to send ATAPI commands directly to a
+ device. If you chose to build PARIDE support into your kernel, you
+ may answer Y here to build in the parallel port generic ATAPI driver,
+ otherwise you should answer M to build it as a loadable module.
+ The module will be called pg.o. You must also have at least one
+ parallel port protocol driver in your system. This driver
+ implements an API loosely related to the generic SCSI driver.
+ See /usr/include/linux/pg.h for details, or visit
+ http://www.torque.net/parport/cdr.html for more information and
+ the required patches to cdrecord.
+
ATEN EH-100 protocol
CONFIG_PARIDE_ATEN
This option enables support for the ATEN EH-100 parallel port IDE
adapter that is used in some portable hard drives. If you chose to
build PARIDE support into your kernel, you may answer Y here to
build in the protocol driver, otherwise you should answer M to
- build it as a loadable module. The module will be called ktti.o.
+ build it as a loadable module. The module will be called fit2.o.
You must also have a high-level driver for the type of device
that you want to support.
+FIT TD-3000 protocol
+CONFIG_PARIDE_FIT3
+ This option enables support for the TD-3000 parallel port IDE protocol
+ from Fidelity International Technology. This protocol is used in newer
+ models of their portable disk, CD-ROM and PD/CD devices. If you chose
+ to build PARIDE support into your kernel, you may answer Y here to
+ build in the protocol driver, otherwise you should answer M to
+ build it as a loadable module. The module will be called fit3.o.
+ You must also have a high-level driver for the type of device
+ that you want to support.
+
FreeCom power protocol
CONFIG_PARIDE_FRPW
This option enables support for the Freecom power parallel port IDE
want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say Y.
+IDE card support
+CONFIG_BLK_DEV_IDE_CARDS
+ On Acorn systems, say Y here if you wish to use an IDE interface
+ expansion card. If you do not or are unsure, say N.
+
+ICS IDE interface
+CONFIG_BLK_DEV_IDE_ICS
+ On Acorn systems, say Y here if you wish to use the ICS IDE
+ interface card. This is not required for ICS partition support. If
+ you are unsure, say.
+
+ADFS partition support
+CONFIG_BLK_DEV_PART
+ This allows Linux on Acorn systems to determine its partitions in
+ the 'non-ADFS' partition area of the hard disk - usually located
+ after the ADFS partition. You are probably using this system, so
+ you should say Y here.
+
IDE card support
CONFIG_BLK_DEV_IDE_CARDS
On Acorn systems, enable this if you wish to use an IDE interface
is talking to the firewall box -- makes the local network completely
invisible to the outside world and avoids the need to allocate
globally valid IP host addresses for the machines on the local net)
- and IP packet accounting (keeping track of what is using up all your
- network bandwidth) and IP transparent proxying (makes the computers
- on the local network think they're talking to a remote computer,
- while in reality the traffic is redirected by your Linux firewall to
- a local proxy server).
+ and IP transparent proxying (makes the computers on the local
+ network think they're talking to a remote computer, while in reality
+ the traffic is redirected by your Linux firewall to a local proxy
+ server).
Make sure to say N to "Fast switching" below if you intend to say Y
here.
about SYN cookies, check out
ftp://koobera.math.uic.edu/pub/docs/syncookies-archive.
+ If you are SYN flooded, the source address reported by the kernel is
+ likely to have been forged by the attacker; it is only reported as
+ an aid in tracing the packets to their actual source and should not
+ be taken as absolute truth.
+
If you say Y here, note that SYN cookies aren't enabled by default;
you can enable them by saying Y to "/proc filesystem support" and
"Sysctl support" below and executing the command
serial ports on the same board to share a single IRQ. To enable
support for this in the serial driver, say Y here.
-Autodetect IRQ on standard ports (unsafe)
+Auto detect IRQ on standard ports (unsafe)
CONFIG_SERIAL_DETECT_IRQ
- Enable this option if you want the kernel to try to guess which IRQ
- is configured during the boot sequence and you're too lazy to edit
- the boot scripts to use the setserial command. This option can be
- unsafe and should not be enabled on most machines. It is far
- better to dynamically request autoconfiguration during the boot-time
- scripts using the setserial command. You can change the IRQ and/or
- request automatic IRQ configuration at any time by using the
- "setserial" program. I wouldn't include this config option at all except
- people keep bellyaching about it. I guess they are really are too lazy
- to edit their boot scripts. :-) If unsure, say No.
+ Say Y here if you want the kernel to try to guess which IRQ
+ to use for your serial port.
+
+ This is considered unsafe; it is far better to configure the IRQ in
+ a boot script using the setserial command.
+
+ If unsure, say N.
Support special multiport boards
CONFIG_SERIAL_MULTIPORT
bus system, i.e. the way the CPU talks to the other stuff inside
your box. Other bus systems are ISA, EISA, Microchannel (MCA) or
VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available
- via FTP (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO,
- contains valuable information about which PCI hardware does work
- under Linux and which doesn't.
+ via FTP (user: anonymous) in
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, contains valuable
+ information about which PCI hardware does work under Linux and which
+ doesn't.
If some of your PCI devices don't work and you get a warning during
boot time ("man dmesg"), please follow the instructions at the top
PCI quirks
CONFIG_PCI_QUIRKS
If you have a broken BIOS, it may fail to set up the PCI bus in a
- correct or optimal fashion. If your BIOS is fine you can say N here
- for a very slightly smaller kernel. If unsure, say Y.
+ correct or optimal fashion. Saying Y here will correct that problem.
+ If your BIOS is fine you can say N here for a very slightly smaller
+ kernel. If unsure, say Y.
PCI bridge optimization (experimental)
CONFIG_PCI_OPTIMIZE
CONFIG_IP_ROUTE_TOS
The header of every IP packet carries a TOS (Type of Service) value
with which the packet requests a certain treatment, e.g. low latency
- (for interactive traffic), high throughput, or high
- reliability. Normally, these values are ignored, but if you say Y
- here, you will be able to specify different routes for packets with
- different TOS values.
+ (for interactive traffic), high throughput, or high reliability.
+ Normally, these values are ignored, but if you say Y here, you will
+ be able to specify different routes for packets with different TOS
+ values.
IP: verbose route monitoring
CONFIG_IP_ROUTE_VERBOSE
More powerful than the old IP firewalling but also provides similar
structure to original firewalling for experienced users. IP
accounting and packet logging are automatically included with firewall
- chains, so you don't need them them if you say Y here. See
+ chains. See
http://www.adelaide.net.au/~rustcorp for new ipfwadm (called ipchains).
If in doubt, say N here.
IP: firewall packet netlink device
CONFIG_IP_FIREWALL_NETLINK
- If you say Y here and then packets hit your Linux firewall and are
- blocked, the first 128 bytes of each such packet are passed on to
- optional user space monitoring software that can then look for
- attacks and take actions such as paging the administrator of the
- site. To use this, you need to create a character special file under
- /dev with major number 36 and minor number 3 using mknod ("man
- mknod"), and you need (to write) a program that reads from that
- device and takes appropriate action.
- With the current generic firewalling chains you can specify which
- packets go to this device, as well as how many bytes.
+ If you say Y here, then packets which hit your Linux firewall can
+ be copied to optional user space monitoring software that can then
+ respond accordingly: see the ipchains source distributions for an
+ example if this. To use this, you need to create a character
+ special file under /dev with major number 36 and minor number 3
+ using mknod ("man mknod"), and you need (to write) a program that
+ reads from that device and takes appropriate action.
IP: kernel level autoconfiguration
CONFIG_IP_PNP
Network), but can be distributed all over the Internet. If you want
to do that, say Y here and to "IP: multicast routing" below.
-IP: firewall packet logging
-CONFIG_IP_FIREWALL_VERBOSE
- This gives you information about what your firewall did with
- packets it received. The information is handled by the klogd daemon
- which is responsible for kernel messages ("man klogd").
-
IP: transparent proxying
CONFIG_IP_TRANSPARENT_PROXY
This enables your Linux firewall to transparently redirect any
Details on how to set things up are contained in the IP Masquerade
mini-HOWTO, available via FTP (user: anonymous) from
- ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini.
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini; there's also some
+ information on the WWW at
+ http://www.tor.shaw.wave.ca/~ambrose/kernel21.html.
If you say Y here, you should also say Y to "IP: always defragment",
below. If you say Y here, then the modules ip_masq_ftp.o (for ftp
IP: ipportfw masquerade support
CONFIG_IP_MASQUERADE_IPPORTFW
- ipportfw is an addition to IP Masquerading written by Steven Clarke
- to allow some forwarding of packets from outside to inside a
- firewall on given ports. Information and source for ipportfw is
- available from
+ Port Forwarding is an addition to IP Masquerading written by Steven
+ Clarke to allow some forwarding of packets from outside to inside a
+ firewall on given ports. This could be useful if, for example, you
+ want to run a web server behind the firewall or masquerading host
+ and this web server should be visible to the outside world. An
+ external client connects to port 80 of the firewall, the firewall
+ forwards requests to this port to the web server, the web server
+ handles the request and the results are sent through the firewall to
+ the original client. The client thinks that the firewall machine
+ itself is running the web server.
+
+ Information about it is available from
http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html (to
browse the WWW, you need to have access to a machine on the Internet
- that has a program like lynx or netscape).
+ that has a program like lynx or netscape). You will need the user
+ space program ipportfw which can be downloaded from
+ ftp://ftp.compsoc.net/users/steve/ipportfw/linux21/
The portfw code is still under development and so is currently
marked EXPERIMENTAL. If you want to try it, say Y.
Unix domain sockets
CONFIG_UNIX
This includes Unix domain sockets, the standard Unix mechanism for
- establishing and accessing network connections. Unless you are
- working on an embedded system or something, you definitely want to
- say Y here.
+ establishing and accessing network connections. Many commonly used
+ programs such as the X Window system and syslog use these sockets
+ even if your machine is not connected to any network. Unless you are
+ working on an embedded system or something similar, you therefore
+ definitely want to say Y here.
The socket support 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 unix.o. If you want to compile it
as a module, say M here and read Documentation/modules.txt. If you
try building this as a module and you are running kerneld, be sure
- to add 'alias net-pf-1 unix' to your /etc/conf.module file. If
- unsure, say Y. (NOTE: X Windows and syslog probably won't work
- if you say N to this or fail to configure it correctly)
+ to add 'alias net-pf-1 unix' to your /etc/conf.module file.
+
+ If unsure, say Y.
The IPv6 protocol
CONFIG_IPV6
some problems caused by the presence of two link-local addresses on
an interface.
+IPv6: routing messages via old netlink
+CONFIG_IPV6_NETLINK
+ You can say Y here to receive routing messages from the IPv6 code
+ through the old netlink interface. However, a better option is to
+ say Y to "Kernel/User network link driver" and to "Routing
+ messages" instead.
+
IPX networking
CONFIG_IPX
This is support for the Novell networking protocol, IPX, commonly
used for local networks of Windows machines. You need it if you want
to access Novell NetWare file or print servers using the Linux
Novell client ncpfs (available via FTP (user: anonymous) from
- sunsite.unc.edu:/pub/Linux/system/filesystems/) or from within the
- Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
- sunsite.unc.edu:/pub/Linux/docs/HOWTO). In order to do the former,
- you'll also have to say Y to "NCP filesystem support", below. To
- turn your Linux box into a fully featured NetWare file server and
+ ftp://sunsite.unc.edu/pub/Linux/system/filesystems/) or from within
+ the Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). In order to do the
+ former, you'll also have to say Y to "NCP filesystem support",
+ below.
+
+ IPX is similar in scope to IP, while SPX, which runs on top of IPX,
+ is similar to TCP. There is also experimental support for SPX in
+ Linux (see "SPX networking", below).
+
+ To turn your Linux box into a fully featured NetWare file server and
IPX router, say Y here and fetch either lwared from
- sunsite.unc.edu:/pub/Linux/system/network/daemons/ or mars_nwe from
- ftp.gwdg.de:/pub/linux/misc/ncpfs. For more information, read the
- IPX-HOWTO in sunsite.unc.edu:/pub/Linux/docs/howto. The IPX driver
- would enlarge your kernel by about 5 kB. This driver 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 ipx.o. If you want to compile it as a module, say M here
- and read Documentation/modules.txt. Unless you want to integrate
+ ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe from
+ ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information, read the
+ IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+ General information about how to connect Linux, Windows machines and
+ Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
+ browse the WWW, you need to have access to a machine on the Internet
+ that has a program like lynx or netscape).
+
+ The IPX driver would enlarge your kernel by about 5 kB. This driver
+ 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 ipx.o. If you want to compile it as a module, say M here
+ and read Documentation/modules.txt. Unless you want to integrate
your Linux box with a local Novell network, say N.
IPX: Full internal IPX network
Every IPX network has an address that identifies it. Sometimes it is
useful to give an IPX "network" address to your Linux box as well
(for example if your box is acting as a fileserver for different IPX
- networks: it will then be accessible form everywhere using the same
+ networks: it will then be accessible from everywhere using the same
address). The way this is done is to create a virtual internal
"network" inside your box and to assign an IPX address to this
network. Say Y here if you want to do this; read the IPX-HOWTO at
- sunsite.unc.edu:/pub/Linux/docs/howto for details.
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO for details.
+
The full internal IPX network enables you to allocate sockets on
different virtual nodes of the internal network. This is done by
evaluating the field sipx_node of the socket address given to the
'special' sockets to sockets listening on the primary network is
disabled. This might break existing applications, especially RIP/SAP
daemons. A RIP/SAP daemon that works well with the full internal net
- can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs. If you don't
+ can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. If you don't
know what you are doing, say N.
IPX: SPX networking (EXPERIMENTAL)
CONFIG_SPX
- The (SPP-derived) Sequenced Packet eXchange (SPX) protocol. Novell's
- networking protocol which monitors transmissions to guarantee
- successful delivery. It is safe to say Y/M here.
+ The Sequenced Packet eXchange protocol is a transport layer protocol
+ built on top of IPX. It is used in Novell NetWare systems for
+ client-server applications and is similar to TCP (which runs on top
+ of IP).
+
+ Note that Novell NetWare file sharing does not use SPX; it uses a
+ protocol called NCP, for which separate Linux support is available
+ ("NCP filesystem support" below for the client side, and the user
+ space programs lwared or mars_nwe for the server side).
+
+ Say Y here if you have use for SPX; read the IPX-HOWTO at
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO for details.
+
+ This driver 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 af_spx.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
Appletalk DDP
CONFIG_ATALK
want to join the conversation, say Y. You will need to use the
netatalk package so that your Linux box can act as a print and file
server for Macs as well as access Appletalk printers. Check out
- http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the
- WWW for details (to browse the WWW, you need to have access to a
- machine on the Internet that has a program like lynx or
- netscape). EtherTalk is the name used for Appletalk over Ethernet
- and the cheaper and slower LocalTalk is appletalk over a proprietary
- apple network using serial links. Ethertalk and Localtalk are fully
- supported by Linux. The NET-2-HOWTO, available via FTP (user: anonymous)
- in sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
- as well. This driver is also available as a module ( = code which
- can be inserted in and removed from the running kernel whenever you
- want). The module is called appletalk.o. If you want to compile
- it as a module, say M here and read Documentation/modules.txt. I
- hear that the GNU boycott of Apple is over, so even politically
- correct people are allowed to say Y here.
+ http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW
+ for details (to browse the WWW, you need to have access to a machine
+ on the Internet that has a program like lynx or netscape). EtherTalk
+ is the name used for Appletalk over Ethernet and the cheaper and
+ slower LocalTalk is appletalk over a proprietary apple network using
+ serial links. Ethertalk and Localtalk are fully supported by Linux.
+ The NET-2-HOWTO, available via FTP (user: anonymous) in
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO contains valuable
+ information as well.
+
+ General information about how to connect Linux, Windows machines and
+ Macs is on the WWW at http://www.eats.com/linux_mac_win.html
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module is called appletalk.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt. I hear that
+ the GNU boycott of Apple is over, so even politically correct people
+ are allowed to say Y here.
Appletalk-IP driver support
CONFIG_IPDDP
This allows IP networking for users who only have Appletalk
networking available. This feature is experimental. With this
driver, you can either encapsulate IP inside Appletalk (e.g. if your
- Linux box is stuck on an appletalk only network) or decapsulate
- (e.g. if you want your Linux box to act as a Internet gateway for a
+ Linux box is stuck on an Appletalk only network) or decapsulate
+ (e.g. if you want your Linux box to act as an Internet gateway for a
zoo of appletalk connected Macs). You decide which one of the two
you want in the following two questions; you can say Y to only one
of them. Please see Documentation/networking/ipddp.txt for more
- information. This driver is also available as a module ( = code
- which can be inserted in and removed from the running kernel
- whenever you want). The module is called ipddp.o. If you want to
- compile it as a module, say M here and read
- Documentation/modules.txt.
+ information.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module is called ipddp.o. If you want to compile it as a module,
+ say M here and read Documentation/modules.txt.
IP to Appletalk-IP Encapsulation support
CONFIG_IPDDP_ENCAP
say M here and read Documentation/modules.txt. This is recommended.
The module will be called baycom_par.o.
+BAYCOM epp driver for AX.25
+CONFIG_BAYCOM_EPP
+ This is a driver for Baycom style simple amateur radio modems that
+ connect to a parallel interface. The driver supports the epp
+ designs. To configure the driver, use the sethdlc utility available
+ in the standard ax25 utilities package. For information on the
+ modems, see http://www.baycom.de (to browse the WWW, you need to
+ have access to a machine on the Internet that has a program like
+ lynx or netscape) and Documentation/networking/baycom.txt.
+
+ 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 baycom_par.o.
+
BAYCOM ser12 full duplex driver for AX.25
CONFIG_BAYCOM_SER_FDX
This is one of two drivers for Baycom style simple amateur radio
BusLogic SCSI support
CONFIG_SCSI_BUSLOGIC
This is support for BusLogic MultiMaster and FlashPoint SCSI Host
- Adapters. Consult the SCSI-HOWTO, available via anonymous ftp from
+ Adapters. Consult the SCSI-HOWTO, available via anonymous FTP from
ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, and the files
README.BusLogic and README.FlashPoint in drivers/scsi for more
information. If this driver does not work correctly without
interface.
If all the boards of your system are genuine SYMBIOS boards or use
- BIOS and drivers from SYMBIOS, you would want to enable this option.
+ BIOS and drivers from SYMBIOS, you would want to say Y here.
The driver behaves correctly on my system with this option enabled.
(SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev
0x12). This option must be set to N if your system has at least one
DC-390/U/W/F).
However, if all your non Symbios compatible boards have NVRAM,
- setting option "detect and read serial NVRAMs"
+ saying Y to "detect and read serial NVRAMs"
(CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT) above allows the driver to
- distinguish Symbios compatible boards from other ones. So, you can
- answer Y if all non Symbios compatible boards have NVRAM.
+ distinguish Symbios compatible boards from other ones; you can then
+ also answer Y here.
If unsure, say N.
This driver supports all the EATA/DMA-compliant SCSI host adapters
and does not need any BIOS32 service. DPT ISA and all EISA i/o
addresses are probed looking for the "EATA" signature. If you said Y
- to "PCI bios support", the addresses of all the PCI SCSI controllers
+ to "PCI BIOS support", the addresses of all the PCI SCSI controllers
reported by BIOS32 are probed as well. You want to read
the start of drivers/scsi/eata.c and the SCSI-HOWTO, available via
FTP (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
This enables support for the Acorn SCSI card (aka30). If you have an
Acorn system with one of these, say Y. If unsure, say N.
+Acorn SCSI tagged queue support
+CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+ Say Y here to enable tagged queuing support on the Acorn SCSI card.
+
+ This is a feature of SCSI-2 which improves performance: the host
+ adapter can send several SCSI commands to a device's queue even if
+ previous commands haven't finished yet. Some SCSI devices don't
+ implement this properly, so the safe answer is N.
+
+Acorn SCSI Synchronous transfers support
+CONFIG_SCSI_ACORNSCSI_SYNC
+ Say Y here to enable synchronous transfer negotiation with all targets
+ on the Acorn SCSI card.
+
+ In general, this improves performance; however some SCSI devices
+ don't implement it properly, so the safe answer is N.
+
+Oak SCSI support
+CONFIG_SCSI_OAK1
+ This enables support for the Oak SCSI card. If you have an Acorn system
+ with one of these, say Y. If unsure, say N.
+
+Cumana SCSI I support
+CONFIG_SCSI_CUMANA_1
+ This enables support for the Cumana SCSI I card. If you have an Acorn
+ system with one of these, say Y. If unsure, say N.
+
+Cumana SCSI II support
+CONFIG_SCSI_CUMANA_2
+ This enables support for the Cumana SCSI II card. If you have an Acorn
+ system with one of these, say Y. If unsure, say N.
+
+EcoSCSI support
+CONFIG_SCSI_ECOSCSI
+ This enables support for the EcoSCSI card - a small card that sits in
+ the Econet socket. If you have an Acorn system with one of these,
+ say Y. If unsure, say N.
+
+EESOX SCSI support
+CONFIG_SCSI_EESOXSCSI
+ This enables support for the EESOX SCSI card. If you have an Acorn
+ system with one of these, say Y, otherwise say N.
+
+Powertec SCSI support
+CONFIG_SCSI_POWERTECSCSI
+ This enables support for the Powertec SCSI card on Acorn systems. If
+ you have one of these, say Y. If unsure, say N.
+
+AcornSCSI support
+CONFIG_SCSI_ACORNSCSI_3
+ This enables support for the Acorn SCSI card (aka30). If you have an
+ Acorn system with one of these, say Y. If unsure, say N.
+
Acorn SCSI tagged queue support
CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
Say Y here to enable tagged queuing support on the Acorn SCSI card.
AT&T WaveLAN & DEC RoamAbout DS support
CONFIG_WAVELAN
- The Lucent Wavelan (formerly NCR and AT&T ; or DEC RoamAbout DS) is
+ The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is
a Radio LAN (wireless Ethernet-like Local Area Network) using the
radio frequencies 900 MHz and 2.4 GHz.
This driver support the ISA version of the Wavelan card. A separate
- driver for the pcmcia hardware is available in David Hinds's pcmcia
- package. If you want to use an ISA Wavelan card under Linux, say Y
- and read the Ethernet-HOWTO, available via FTP (user: anonymous) in
+ driver for the pcmcia hardware is available in David Hinds's
+ pcmcia-cs package (see the file Documentation/Changes for location).
+
+ If you want to use an ISA Wavelan card under Linux, say Y and read
+ the Ethernet-HOWTO, available via FTP (user: anonymous) in
ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Some more specific
- information is contained in Documentation/networking/wavelan.txt.
+ information is contained in Documentation/networking/wavelan.txt and
+ in the source code drivers/net/wavelan.p.h.
+
You will also need the wireless tools package available from
ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/contrib/.
+ Please read the man pages contained therein.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
something at ftp://ftp.lmh.ox.ac.uk/users/weejock/linux/, but I haven't
written anything too useful yet...)
-AIMSlab RadioTrack card
+AIMSlab RadioTrack (aka RadioReveal) support
CONFIG_RADIO_RTRACK
- Choose Y here if you have one of these, and then fill in the port
- address below.
+ Choose Y here if you have one of these FM radio cards, and then fill
+ in the port address below.
+
+ In order to control your radio card under the X window system, you
+ may use the program X-Tuner, available on the WWW at
+ http://gatekeeper.dec.com/pub/X11/R6-contrib/applications/; to
+ browse the WWW, you need to have access to a machine on the Internet
+ that has a program like lynx or netscape.
+
+ 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. The module will be
+ called radio-aimslab.o.
RadioTrack i/o port
CONFIG_RADIO_RTRACK_PORT
Aztech/Packard Bell Radio
CONFIG_RADIO_AZTECH
- Choose Y here if you have one of these, and then fill in the port
- address below.
+ Choose Y here if you have one of these FM radio cards, and then fill
+ in the port address below.
+
+ 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. The module will be
+ called radio-aztech.o.
Aztech/Packard Bell radio card i/o port
CONFIG_RADIO_AZTECH_PORT
haven't changed the setting of jumper JP3 on the card. Removing the
jumper sets the card to 0x358.
+SF16FMI Radio
+CONFIG_RADIO_SF16FMI
+ Choose Y here if you have one of these FM radio cards, and then fill
+ in the port address below.
+
+ 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. The module will be
+ called radio-sf16fmi.o
+
+SF16FMI I/O port (0x284 or 0x384)
+CONFIG_RADIO_SF16FMI_PORT
+ Enter the I/O port of your SF16FMI radio card.
+
LAPB over Ethernet driver
CONFIG_LAPBETHER
This is a driver for a pseudo device (typically called /dev/lapb0)
The module will be called sdla.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
+Acorn Econet/AUN protocols (EXPERIMENTAL)
+CONFIG_ECONET
+ Econet is a fairly old and slow networking protocol mainly used by
+ Acorn computers to access file and print servers. It uses native
+ Econet network cards. AUN is an implementation of the higher level
+ parts of Econet that runs over ordinary Ethernet connections, on
+ top of the UDP packet protocol, which in turn runs on top of the
+ Internet protocol IP.
+
+ If you say Y here, you can choose with the next two options whether
+ to send Econet/AUN traffic over a UDP Ethernet connection or over
+ a native Econet network card.
+
+ This driver 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 econet.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
+AUN over UDP
+CONFIG_ECONET_AUNUDP
+ Say Y here if you want to send Econet/AUN traffic over a a UDP
+ connection (UDP is a packet based protocol that runs on top of the
+ Internet protocol IP) using an ordinary Ethernet network card.
+
+Native Econet
+CONFIG_ECONET_NATIVE
+ Say Y here if you have a native Econet network card installed in
+ your computer.
+
WAN Router
CONFIG_WAN_ROUTER
Wide Area Networks (WANs), such as X.25, frame relay and leased
called packet schedulers. You can attach different schedulers to
different network devices. If you want to stick to the default
scheduling algorithm, say N here. If you want to experiment with a
- couple of different algorithms, say Y.
+ couple of different algorithms, say Y. Currently, this is only
+ recommended for experts.
To administer these schedulers, you'll need the user-level utilities
from the package iproute2+tc at ftp://ftp.inr.ac.ru/ip-routing/
- The available schedulers are
- listed in the following questions; you can say Y to as many as you
- like. If unsure, say N now.
+ If you say Y here and to "/proc filesystem" below, you will be able
+ to read status information about priority schedulers from
+ the file /proc/net/psched.
+
+ The available schedulers are listed in the following questions; you
+ can say Y to as many as you like. If unsure, say N now.
CBQ packet scheduler
CONFIG_NET_SCH_CBQ
algorithm classifies the waiting packets into a tree-like hierarchy
of classes; the leaves of this tree are in turn scheduled by
separate algorithms (called "disciplines" in this context) which you
- can choose below from among the "auxiliary disciplines". See the top
- of net/sched/sch_cbq.c for references about the CBQ algorithm.
+ can choose below from among the various queueing algorithms. See the
+ top of net/sched/sch_cbq.c for references about the CBQ algorithm.
This code is also available as a module called sch_cbq.o ( = code
which can be inserted in and removed from the running kernel
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
-RED queueing discipline
+The simplest PRIO pseudo scheduler
+CONFIG_NET_SCH_PRIO
+ Say Y here if you want to use an n-band priority queue packet
+ "scheduler" for some of your network devices or as a leaf discipline
+ for the CBQ scheduling algorithm.
+
+ This code is also available as a module called sch_prio.o ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). If you want to compile it as a module, say M
+ here and read Documentation/modules.txt.
+
+RED queue
CONFIG_NET_SCH_RED
Say Y here if you want to use the Random Early Detection (RED)
packet scheduling algorithm for some of your network devices (see
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
-SFQ queueing discipline
+SFQ queue
CONFIG_NET_SCH_SFQ
Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
packet scheduling algorithm for some of your network devices or as a
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
-auxiliary TBF queue
+TEQL queue
+CONFIG_NET_SCH_TEQL
+ Say Y here if you want to use the True Link Equalizer (TLE) packet
+ scheduling algorithm for some of your network devices or as a leaf
+ discipline for the CBQ scheduling algorithm. This queueing
+ discipline allows the combination of several physical devices into
+ one virtual device. (see the top of net/sched/sch_teql.c for
+ details).
+
+ This code is also available as a module called sch_teql.o ( = code
+ which can be inserted in and removed from the running kernel
+ whenever you want). If you want to compile it as a module, say M
+ here and read Documentation/modules.txt.
+
+TBF queue
CONFIG_NET_SCH_TBF
Say Y here if you want to use the Simple Token Bucket Filter (TBF)
packet scheduling algorithm for some of your network devices or as a
whenever you want). If you want to compile it as a module, say M
here and read Documentation/modules.txt.
-auxiliary FIFO queue
-CONFIG_NET_SCH_PFIFO
- Say Y here if you want to use a simple FIFO (first in - first out)
- packet "scheduler" for some of your network devices or as a leaf
- discipline for the CBQ scheduling algorithm.
+QoS support
+CONFIG_NET_QOS
+ Say Y here if you want to include Quality Of Service scheduling
+ features, which means that you will be able to request certain
+ rate-of-flow limits for your net devices.
- This code is also available as a module called sch_fifo.o ( = code
- which can be inserted in and removed from the running kernel
- whenever you want). If you want to compile it as a module, say M
- here and read Documentation/modules.txt.
-
-auxiliary PRIO queue
-CONFIG_NET_SCH_PRIO
- Say Y here if you want to use an n-band priority queue packet
- "scheduler" for some of your network devices or as a leaf discipline
- for the CBQ scheduling algorithm.
-
- This code is also available as a module called sch_prio.o ( = code
- which can be inserted in and removed from the running kernel
- whenever you want). If you want to compile it as a module, say M
- here and read Documentation/modules.txt.
+ Note that the answer to this question won't directly affect the
+ kernel: saying N will just cause this configure script to skip all
+ the questions about QoS support.
+
+Rate estimator
+CONFIG_NET_ESTIMATOR
+ In order for Quality of Service scheduling to work, the current
+ rate-of-flow for a network device has to be estimated; if you say Y
+ here, the kernel will do just that.
+
+Packet classifier API
+CONFIG_NET_CLS
+ The CBQ scheduling algorithm requires that network packets which are
+ scheduled to be sent out over a network device be classified in some
+ way. If you say Y here, you will get a choice of several different
+ packet classifiers with the following questions.
+#
+# Routing tables based classifier
+# CONFIG_NET_CLS_ROUTE
+#
+# Firewall based classifier
+# CONFIG_NET_CLS_FW
+#
+# U32 classifier
+# CONFIG_NET_CLS_U32
+#
+# Special RSVP classifier
+# CONFIG_NET_CLS_RSVP
+#
+# Special RSVP classifier for IPv6
+# CONFIG_NET_CLS_RSVP6
+#
+# Ingres traffic policing
+# CONFIG_NET_CLS_POLICE
+###
+### Some expert please fill these in
+###
Network code profiler
CONFIG_NET_PROFILE
Ethernet (10 or 100Mbit)
CONFIG_NET_ETHERNET
Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
- type of Local Area Networks (LANs) in universities or
- companies. 10-base-2 or Thinnet (10 Mbps over coaxial cable, linking
- computers in a chain), 10-base-T (10 Mbps over twisted pair
+ type of Local Area Networks (LANs) in universities or companies.
+ 10-base-2 or Thinnet (10 Mbps over coaxial cable, linking computers
+ in a chain), 10-base-T or TwistedPair (10 Mbps over twisted pair
telephone cable, linking computers to a central hub) and
100-base-<whatever> (100 Mbps) are common types of Ethernet.
it as a module, say M here and read Documentation/modules.txt as
well as Documentation/networking/net-modules.txt.
+PCI NE2000 support
+CONFIG_NE2K_PCI
+ If you have a network (Ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available via FTP (user: anonymous) in
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+ This driver 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 ne2k-pci.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt as well as
+ Documentation/networking/net-modules.txt.
+
Racal-Interlan (Micom) NI cards
CONFIG_NET_VENDOR_RACAL
If you have a network (Ethernet) card belonging to this class, such
module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
+RealTek 8129/8139 (not 8019/8029!) support
+CONFIG_RTL8139
+ This is a driver for the Fast Ethernet PCI network cards based on
+ the RTL8129 and RTL8139 chips. If you have one of those, say Y and
+ read the Ethernet-HOWTO, available via FTP (user: anonymous) in
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+
+ 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 rtl8139.o.
+
+Packet Engines Yellowfin Gigabit-NIC support
+CONFIG_YELLOWFIN
+ Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
+ adapter. This adapter is used by the Beowulf Linux cluster project.
+ See http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html for
+ more information about this driver in particular and Beowulf in
+ general (to browse the WWW, you need to have access to a machine on
+ the Internet that has a program like lynx or netscape).
+
+ 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 yellowfin.o.
+
AMD LANCE and PCnet (AT1500 and NE2100) support
CONFIG_LANCE
If you have a network (Ethernet) card of this type, say Y and read
3c590 series (592/595/597) "Vortex" support
CONFIG_VORTEX
- If you have a 3Com "Vortex" or "Boomerang" series network (Ethernet)
- card (Fast EtherLink 3c590/3c592/3c595/3c597 or the EtherLink XL
- 3c900 or 3c905), say Y and read the Ethernet-HOWTO, available via
- FTP (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+ If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597)
+ or "Boomerang" series (EtherLink XL 3c900 or 3c905) network
+ (Ethernet) card, say Y and read the Ethernet-HOWTO, available via FTP
+ (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
More specific information is in Documentation/networking/vortex.txt
and in the comments at the beginning of drivers/net/3c59x.c.
Y here and read the Ethernet-HOWTO, available via FTP (user:
anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+ This driver 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 pcnet32.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt as well as
+ Documentation/networking/net-modules.txt.
+
Ansel Communications EISA 3200 support
CONFIG_AC3200
If you have a network (Ethernet) card of this type, say Y and read
If you want to plug a network card into the PCMCIA slot of your
laptop instead (PCMCIA is the standard for credit card size
- extension cards used by all modern laptops), look on the ftp site
+ extension cards used by all modern laptops), look on the FTP site
(user: anonymous) ftp://cb-iris.stanford.edu/pub/pcmcia and say N
here.
If you wish to compile a kernel for the EBSA-110, then you should
always answer Y to this.
+Acorn Ether1 card
+CONFIG_ARM_ETHER1
+ If you have an Acorn system with one of these (AKA25) network cards,
+ you should say Y to this option if you wish to use it with Linux.
+
+Acorn/ANT Ether3 card
+CONFIG_ARM_ETHER3
+ If you have an Acorn system with one of these network cards, you
+ should say Y to this option if you wish to use it with Linux.
+
+I Cubed EtherH card
+CONFIG_ARM_ETHERH
+ If you have an Acorn system with one of these network cards, you
+ should say Y to this option if you wish to use it with Linux.
+
+EBSA-110 ethernet interface
+CONFIG_AM79C961A
+ If you wish to compile a kernel for the EBSA-110, then you should
+ always answer Y to this.
+
Support CDROM drives that are not SCSI or IDE/ATAPI
CONFIG_CD_NO_IDESCSI
If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y
Second extended fs support
CONFIG_EXT2_FS
This is the de facto standard Linux filesystem (= method to organize
- files on a storage device) for hard disks. You want to say Y, unless
- you intend to use Linux exclusively from inside a DOS partition
- using the umsdos filesystem. The advantage of the latter is that you
- can get away without repartitioning your hard drive (which often
- implies backing everything up and restoring afterwards); the
- disadvantage is that Linux becomes susceptible to DOS viruses and
- that umsdos is somewhat slower than ext2fs. Even if you want to run
- Linux in this fashion, it might be a good idea to have ext2fs
- around: it enables you to read more floppy disks and facilitates the
- transition to a *real* Linux partition later. Another (rare) case
- which doesn't require ext2fs is a diskless Linux box which mounts
- all files over the network using NFS (in this case it's sufficient
- to say Y to "NFS filesystem support" below). Saying Y here will
- enlarge your kernel by about 41 kB.
+ files on a storage device) for hard disks.
+
+ You want to say Y here, unless you intend to use Linux exclusively
+ from inside a DOS partition using the umsdos filesystem. The
+ advantage of the latter is that you can get away without
+ repartitioning your hard drive (which often implies backing
+ everything up and restoring afterwards); the disadvantage is that
+ Linux becomes susceptible to DOS viruses and that umsdos is somewhat
+ slower than ext2fs. Even if you want to run Linux in this fashion,
+ it might be a good idea to have ext2fs around: it enables you to
+ read more floppy disks and facilitates the transition to a *real*
+ Linux partition later. Another (rare) case which doesn't require
+ ext2fs is a diskless Linux box which mounts all files over the
+ network using NFS (in this case it's sufficient to say Y to "NFS
+ filesystem support" below). Saying Y here will enlarge your kernel
+ by about 41 kB.
The Ext2fs-Undeletion mini-HOWTO, available via FTP (user:
anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini,
gives information about how to retrieve deleted files on ext2fs
filesystems.
- To change the behavior of ext2fs filesystems, you can use the
- tune2fs utility ("man tune2fs").
+ To change the behavior of ext2 filesystems, you can use the tune2fs
+ utility ("man tune2fs"). To modify attributes of files and
+ directories on ext2 filesystems, use chattr ("man chattr").
+
+ Ext2fs partitions can be read from within DOS using the ext2tool
+ package available via FTP (user: anonymous) from
+ ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2.
If you want to compile this filesystem as a module ( = code which
can be inserted in and removed from the running kernel whenever you
The automounter is a tool to automatically mount remote filesystems
on demand. This implementation is partially kernel-based to reduce
overhead in the already-mounted case; this is unlike the BSD
- automounter (amd), which is only in user space.
+ automounter (amd), which is a pure user space daemon.
To use the automounter you need the user-space tools from
ftp://ftp.kernel.org/pub/linux/daemons/autofs; you also want to say Y to
ADFS filesystem support (read only) (EXPERIMENTAL)
CONFIG_ADFS_FS
- The Acorn Disc Filing System is the standard filesystem of the RiscOS
- operating system which runs on Acorn's ARM based Risc PC systems and
- the Acorn Archimedes range of machines. These should be the first
- partition (ie, /dev/[hs]d?1) on each of your drives. If you say Y
+ The Acorn Disc Filing System is the standard filesystem of the
+ RiscOS operating system which runs on Acorn's ARM based Risc PC
+ systems and the Acorn Archimedes range of machines. If you say Y
here, Linux will be able to read from ADFS partitions on hard drives
and from ADFS-formatted floppy discs.
+ The ADFS partition should be the first partition (i.e.,
+ /dev/[hs]d?1) on each of your drives.
+
This code is also available as a module called adfs.o ( = code which
can be inserted in and removed from the running kernel whenever you
want). If you want to compile it as a module, say M here and read
CONFIG_DEVPTS_FS
If you say Y here, you'll get a virtual filesystem which can be
mounted on /dev/pts with "mount -t devpts". This, together with the
- pseudo terminal master multiplexer /dev/ptmx is used for pseudo
+ pseudo terminal master multiplexer /dev/ptmx, is used for pseudo
terminal support as described in the Open Group's Unix98 standard:
in order to acquire a pseudo terminal, a process opens /dev/ptmx;
the number of the pseudo terminal is then made available to the
or change their color depending on the virtual console you're on.
See Documentation/VGA-softcursor.txt for more information.
+Acorn's ADFS filesystem support (read only) (EXPERIMENTAL)
+CONFIG_ADFS_FS
+ The Advanced Disk File System is the filesystem used on floppy and
+ hard disks by Acorn Systems. Currently in development, as a read-
+ only driver for hard disks. These should be the first partition
+ (eg. /dev/[sh]d?1) on each of your drives. If unsure, say N.
+
Standard/generic serial support
CONFIG_SERIAL
This selects whether you want to include the driver for the standard
be lost when kerneld automatically unloads the driver. This
limitation may be lifted in the future.]
- BTW: If you have a mouseman serial mouse which is not recognized by
+ BTW1: If you have a mouseman serial mouse which is not recognized by
the X window system, try running gpm first.
+
+ BTW2: If you intend to connect a so-called Winmodem to your
+ machine's serial port, forget it. These modems require proprietary
+ drivers which are only available under Windows.
Most people will say Y or M here, so that they can use serial mice,
modems and similar devices connecting to the standard serial ports.
Specialix IO8+ card support
CONFIG_SPECIALIX
- This is a driver for the Specialix IO8+ multiport card, that give
+ This is a driver for the Specialix IO8+ multiport card which gives
you many serial ports. You would need something like this to
connect more than two modems to your Linux box, for instance in
order to become a BBS.
Specialix DTR/RTS pin is RTS
CONFIG_SPECIALIX_RTSCTS
- The Specialix card can only support either RTS or DTR. When you say
+ The Specialix card can only support either RTS or DTR. If you say
N here, the driver will use the pin as "DTR" when the tty is in
- software handshake mode. When you say Y here or hardware handshake
+ software handshake mode. If you say Y here or hardware handshake
is on, it will always be RTS. Read the file
Documentation/specialix.txt for more information.
MTRR control and configuration
CONFIG_MTRR
- On Intel Pentium Pro/Pentium II systems the Memory Type Range
+ On Intel Pentium Pro and Pentium II systems the Memory Type Range
Registers (MTRRs) may be used to control processor access to memory
ranges. This is most useful when you have a video (VGA) card on a
PCI or AGP bus. Enabling write-combining allows bus write transfers
your MTRRs. Typically the X server should use this. This should have
a reasonably generic interface so that similar control registers on
other processors can be easily supported.
- This option also fixes a problem with buggy SMP BIOSes which only
+
+ Saying Y here also fixes a problem with buggy SMP BIOSes which only
set the MTRRs for the boot CPU and not the secondary CPUs. This can
lead to all sorts of problems.
- Compiling this as a module is not available because the BIOS fix
- needs to be done early in the boot sequence, otherwise your machine
- could lock up.
+
+ In general you should compile this into the kernel, rather than as a
+ loadable module, because the BIOS fix needs to be done early in the
+ boot sequence. If you compile this as a module, the BIOS fix will be
+ delayed until when you load the module. You do this at your own risk.
+
See Documentation/mtrr.txt for more information.
Main CPU frequency, only for DEC alpha machine
3) passing the "floppy=nodma" option to the kernel
4) passing the "mem=4M" option to the kernel (thereby disabling
all but the first 4M of RAM)
- 5) reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
- 6) disabling the cache from your BIOS settings
- 7) installing a better fan
- 8) exchanging RAM chips
- 9) exchanging the motherboard.
+ 5) making sure that the CPU is not over clocked.
+ 6) reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
+ 7) disabling the cache from your BIOS settings
+ 8) installing a better fan
+ 9) exchanging RAM chips
+ 10) exchanging the motherboard.
Ignore USER SUSPEND
CONFIG_APM_IGNORE_USER_SUSPEND
The module will be called nvram.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
+Atomwide Serial Support
+CONFIG_ATOMWIDE_SERIAL
+ If you have an Atomwide Serial card for an Acorn system, say Y to
+ this option. The driver can handle 1, 2, or 3 port cards.
+ If unsure, say N
+
+The Serial Port Dual Serial Port
+CONFIG_DUALSP_SERIAL
+ If you have the Serial Port's dual serial card for an Acorn system,
+ say Y to this option. If unsure, say N
+
PC joystick support
CONFIG_JOYSTICK
If you have a PC compatible analog or digital joystick, you can say
I'm told that even without a sound card, you can make your computer
say more than an occasional beep, by programming the PC speaker.
Kernel patches and programs to do that are in the pcsndrv package on
- sunsite.unc.edu:/pub/Linux/kernel/patches/console/.
+ ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/ and in the
+ pcsp patch at ftp://dwmw2.robinson.cam.ac.uk/pub/kernel/ .
Support for Aztech Sound Galaxy (non-Pnp) cards
CONFIG_SOUND_SGALAXY
- This module initialises the older non Plug and Play sound galaxy cards
+ This module initializes the older non Plug and Play sound galaxy cards
from Aztech. It supports the Waverider Pro 32 - 3D and the Galaxy
Washington 16.
these cards may cause trouble (I don't currently know of any such
cards, however). If unsure, say Y.
-Loopback MIDI device support
-CONFIG_VMIDI
+#Loopback MIDI device support
+#CONFIG_SOUND_VMIDI
###
### somebody please fill this in.
###
-
+#
Gravis Ultrasound support
CONFIG_SOUND_GUS
Say Y here for any type of Gravis Ultrasound card, including
card based on the PSS chipset (AD1848 codec + ADSP-2115 DSP chip +
Echo ESC614 ASIC CHIP).
+#Enable PSS mixer (Beethoven ADSP-16 and other compatible)
+#CONFIG_PSS_MIXER
+###
+### Don't know what this is
+###
+#
Have DSPxxx.LD firmware file
CONFIG_PSS_HAVE_BOOT
If you want to emulate the Sound Blaster card and you have a DSPxxx.LD
Support for Crystal CS4232 based (PnP) cards
CONFIG_SOUND_CS4232
Say Y here if you have a card based on the Crystal CS4232 chip set,
- which use its own Plug and Play protocol. See Documentation/sound/CS4232
- for more information on configuring this card.
+ which uses its own Plug and Play protocol. See
+ Documentation/sound/CS4232 for more information on configuring this
+ card.
Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
CONFIG_SOUND_MAUI
CONFIG_MAUI_BOOT_FILE
Enter the full pathname of your OSWF.MOT file, starting from /.
+Support for Turtle Beach MultiSound Classic, Tahiti, Monterey
+CONFIG_SOUND_MSNDCLAS
+ Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
+ Monterey (not for the Pinnacle or Fiji). See
+ Documentation/sound/MultiSound for important information about this
+ driver.
+
+Full pathname of MSNDINIT.BIN firmware file
+CONFIG_MSNDCLAS_INIT_FILE
+ The MultiSound cards have two firmware files which are required for
+ operation, and are not currently included. These files can be
+ obtained from Turtle Beach.
+
+Full pathname of MSNDPERM.BIN firmware file
+CONFIG_MSNDCLAS_PERM_FILE
+ The MultiSound cards have two firmware files which are required for
+ operation, and are not currently included. These files can be
+ obtained from Turtle Beach.
+
+Support for Turtle Beach MultiSound Pinnacle, Fiji
+CONFIG_SOUND_MSNDPIN
+ Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
+ See Documentation/sound/MultiSound for important information about
+ this driver.
+
+Full pathname of PNDSPINI.BIN firmware file
+CONFIG_MSNDPIN_INIT_FILE
+ The MultiSound cards have two firmware files which are required for
+ operation, and are not currently included. These files can be
+ obtained from Turtle Beach.
+
+Full pathname of PNDSPERM.BIN firmware file
+CONFIG_MSNDPIN_PERM_FILE
+ The MultiSound cards have two firmware files which are required for
+ operation, and are not currently included. These files can be
+ obtained from Turtle Beach.
+
/dev/dsp and /dev/audio support
CONFIG_SOUND_AUDIO
Answering N disables /dev/dsp and /dev/audio, the A/D and D/A
affect the kernel; saying Y will simply cause this configure script
to present you with more options. If unsure, say Y.
-SB32/AWE support
-CONFIG_AWE32_SYNTH
- Say Y here if you have a SB32 or SB AWE soundcard. See
- drivers/sound/lowlevel/README.awe for more info.
-
ACI mixer (miroPCM12)
CONFIG_ACI_MIXER
Audio Command Interface (ACI) driver. ACI is a protocol used to
Macintosh support
CONFIG_MAC
- This option enables support for the Apple Macintosh series of computers
- (yes, there is experimental support now, at least for part of the series).
- Say N unless you're willing to code the remaining necessary support. ;)
+ This option enables support for the Apple Macintosh series of
+ computers (yes, there is experimental support now, at least for part
+ of the series).
+
+ Say N unless you're willing to code the remaining necessary support.
+ ;)
# CONFIG_APOLLO, etc. coming soon (?)
from the running kernel whenever you want). If you want to compile
it as a module, say M here and read Documentation/modules.txt.
+CPU Optimisation
+CONFIG_CPU_ARM2
+ This selects the processor type of your CPU. This is only used to
+ determine C compiler optimisation options, and can affect the
+ compatability of the kernel on other processors. If you specify
+ ARM6, the kernel should work on all 32-bit processors. If you
+ specify ARM2, ARM250 or ARM3, it should work on all 26-bit
+ processors. If you're not sure, set it to "None".
+
+ARM System type
+CONFIG_ARCH_ARC
+ This selects what ARM system you wish to build the kernel for. It
+ also selects to some extent the CPU type. If you are unsure what
+ to set this option to, please consult any information supplied with
+ your system.
+
+Build Tools Selection
+CONFIG_BINUTILS_NEW
+ Say Y here if you're using GCC 2.8.1/EGCS with a binutils version >= 2.8.1
+ to compile the kernel. Otherwise, say N.
+
+Compile kernel with frame pointer
+CONFIG_FRAME_POINTER
+ In order to give useful debugging/error results, say Y here, otherwise
+ say N.
+
+VIDC Sound
+CONFIG_VIDC_SOUND
+ Say 'Y' here for ARM systems with the VIDC video controller and 16-bit
+ Linear sound DACs. If unsure, say N.
+
#
# A couple of things I keep forgetting:
-# capitalize: DMA, Internet, Intel, IRQ, Linux, NetWare, NFS, PCI, SCSI
-# two words: hard drive, hard disk, sound card
-# other: it's safe to save; daemon
+# capitalize: Appletalk, Ethernet, DMA, FTP, Internet, Intel, IRQ,
+# Linux, NetWare, NFS, PCI, SCSI
+# two words: hard drive, hard disk, sound card
+# other: it's safe to save; daemon
#
# This is used by Emacs' spell checker ispell.el:
#
# LocalWords: buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext
# LocalWords: QLOGIC qlogic TMC seagate Trantor ultrastor FASST wd NETDEVICES
# LocalWords: unix BBS linux nullmodem CSLIP PLIP Kirch's LDP CSlip SL SCC IRQ
-# LocalWords: Turbo Laplink plip NCSA ReQuest IRQs EQL SMC AMD PCnet NE
+# LocalWords: Turbo Laplink plip NCSA port's ReQuest IRQs EQL SMC AMD PCnet NE
# LocalWords: COM ELPLUS Com EtherLinkIII VLB Arcnet arcnet Cabletron DEPCA DE
# LocalWords: depca EtherWorks EWRK ewrk SEEQ EtherExpressPro EEXPRESS NI xxx
# LocalWords: EtherExpress WaveLAN wavelan PCLAN HPLAN VG SK Ansel Xen de ZNET
# LocalWords: chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport
# LocalWords: Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
# LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
-# LocalWords: carleton Deskstation DECstation SUNFD JENSEN Noname SLiRP
+# LocalWords: carleton Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP
# LocalWords: pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd
# LocalWords: RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
# LocalWords: dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
# LocalWords: ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
# LocalWords: ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
# LocalWords: initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
-# LocalWords: FC DC dc PPA ppa RNFS FMV Fujitsu ARPD arpd loran layes
+# LocalWords: FC DC dc PPA IOMEGA's ppa RNFS FMV Fujitsu ARPD arpd loran layes
# LocalWords: FRAD indiana framerelay DLCI DCLIs Sangoma SDLA mrouted sync sec
# LocalWords: Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard
-# LocalWords: DIGI Xe Xeve digiboard UMISC touchscreens mtu HBAs MEX
+# LocalWords: DIGI Xe Xeve digiboard UMISC touchscreens mtu ethernets HBAs MEX
# LocalWords: Shifflett netcom js jshiffle WIC DECchip ELCP EtherPower dst RTC
# LocalWords: rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP
# LocalWords: Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo ufs
# LocalWords: Bernd informatik rwth aachen uae affs multihosting bytecode java
# LocalWords: applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab
# LocalWords: winsock RNIS caltech OSPF honour Honouring Mbit Localtalk DEFRAG
-# LocalWords: download Packetwin Baycom baycom interwork ascii JNT
+# LocalWords: localtalk download Packetwin Baycom baycom interwork ascii JNT
# LocalWords: Camtec proxying indyramp defragment defragmented UDP FAS FASXX
# LocalWords: FastSCSI SIO FDC qlogicfas QLogic qlogicisp setbaycom ife ee LJ
# LocalWords: ethz ch Travelmates ProAudioSpectrum ProAudio SoundMan SB SBPro
# LocalWords: smp HiSax SiemensChipSet Siemens AVM Elsa ITK hisax PCC MICROR
# LocalWords: Mircolink EURO DSS Spellcaster BRI sc spellcast Digiboards GPIO
# LocalWords: SYMBIOS COMPAT SDMS rev ASUS Tekram HX VX API ibmmcascsi ASY asy
-# LocalWords: loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's PnP
+# LocalWords: loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's Pnp
# LocalWords: AEDSP aedsp enskip tik Sysctl sysctl PARPORT parport pnp IDs EPP
# LocalWords: Autoprobe bart patrickr HDLS READBACK AB usr DAMA DS SparQ aten
# LocalWords: Symbios PCscsi tmscsim RoamAbout GHz Hinds' contrib mathematik
# LocalWords: mwave OLDCARD isdnloop linklevel loopctrl Eicon Diehl DIEHLDIVA
# LocalWords: ASUSCOM AsusCom TELEINT semiactiv Sedlbauer Sportster TA MIC ITH
# LocalWords: NETjet NetJet Niccy Neuhaus sparcs AOC AOCD AOCE Microlink SAA
-# LocalWords: teletext WinTV saa iproute tc
+# LocalWords: teletext WinTV saa iproute tc Quadra Performa PowerBook tor AUN
+# LocalWords: setserial compsoc steve Econet econet AUNUDP psched TEQL TLE CLS
+# LocalWords: teql FW Ingres TwistedPair MTRR MTRRs mtrr cfs crypto TD ktti KT
+# LocalWords: PHd ICS ipchains adelaide rustcorp syslog epp Cumana
+# LocalWords: AcornSCSI EcoSCSI EESOX EESOXSCSI Powertec POWERTECSCSI dec SF
+# LocalWords: RadioReveal gatekeeper aimslab aztech FMI sf fmi RTL rtl cesdis
+# LocalWords: Yellowfin gsfc nasa gov yellowfin pcnet Mylex LNE lne EtherH hs
+# LocalWords: EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson
+# LocalWords: SGALAXY Waverider DSPxxx TRXPRO AudioTrix OSWF MOT
+++ /dev/null
-Turtle Beach Multisound support is not yet integrated. If you'd like
-to test it or help out in finishing the module please see
-
- http://www.rpi.edu/~veliaa/pinlinux.html
check=strict Matches only filenames with the exact same case
cruft Try to handle badly formatted CDs.
map=off Do not map non-rockridge filenames to lowercase
- map=normal Map rockridge filenames to lowercase
+ map=normal Map non-rockridge filenames to lowecase
+ map=acorn As map=normal but also apply Acorn extensions if present
mode=xxx Sets the permissions on files to xxx
nojoliet Ignore Joliet extensions if they are present.
norock Ignore rockridge extensions if they are present.
Imation Superdisk LS-120
FreeCom Power CD
Hewlett-Packard 5GB tape drive
+ Hewlett-Packard 7100 and 7200 CD-RW drives
as well as most of the clone and no-name products on the market.
pcd ATAPI CD-ROM
pf ATAPI disk
pt ATAPI tape
+ pg ATAPI generic
-(Support for ATAPI CD-R and CD-RW drives is in the design phase.)
+(Currently, the pg driver is only used with CD-R drives).
The high-level drivers function according to the relevant standards.
The third component of PARIDE is a set of low-level protocol drivers
dstr DataStor EP-2000 (TW)
epat Shuttle EPAT (UK)
epia Shuttle EPIA (UK)
- fit2 FIT TD-2000
+ fit2 FIT TD-2000 (US)
+ fit3 FIT TD-3000 (US)
frpw Freecom Power (DE)
kbic KingByte KBIC-951A and KBIC-971A (TW)
ktti KT Technology PHd adapter (SG)
Avatar Shark pd epat
FreeCom CD-ROM pcd frpw
Hewlett-Packard 5GB Tape pt epat
+ Hewlett-Packard 7100/7200 pg epat
2.1 Configuring built-in drivers
for u in 0 1 2 3 ; do mkdev pf$u b 47 $u ; done
for u in 0 1 2 3 ; do mkdev pt$u c 96 $u ; done
for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done
+for u in 0 1 2 3 ; do mkdev pg$u c 97 $u ; done
#
# end of mkd
mkdosfs /dev/pf0
mount /dev/pf0 /mnt
+2.4 Using the pg driver
+
+The pg driver can be used in conjunction with the cdrecord program
+to create CD-ROMs. For more information, and the required patches
+to cdrecord, please visit http://www.torque.net/parport/cdr.html .
3. Troubleshooting
You might also find some useful information on the linux-parport
web pages (although they are not always up to date) at
- http://www.torque.net/linux-pp.html
+ http://www.torque.net/parport/
--- /dev/null
+ALS-007 based soundcards
+========================
+
+Support for soundcards based around the Avance Logic ALS-007 chip is
+included. The ALS-007 is a single chip PnP sound solution which is mostly
+hardware compatible with the Sound Blaster 16 card, with most differences
+occuring in the use of the mixer registers. For this reason the ALS-007
+code is integrated as part of the Sound Blaster 16 driver (adding only 800
+bytes to the SB16 driver).
+
+To use an ALS-007 soundcard under Linux, enable the following options in the
+sound configuration section of the kernel config:
+ - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
+ - FM synthesizer (YM3812/OPL-3) support
+Since the ALS-007 is a PnP card, the sound driver probably should be
+compiled as a module, with the isapnptools used to wake up the soundcard.
+Set the "I/O base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit -
+either 0, 1 or 3) to the values used in your particular installation (they
+should match the values used to configure the card using isapnp). The
+ALS-007 does NOT implement 16 bit DMA, so the "Sound Blaster 16 bit DMA"
+should be set to -1. If you wish to use the externel MPU-401 interface on
+the card, "MPU401 I/O base of SB16" and "SB MPU401 IRQ" should be set to
+the appropriate values for your installation. (Note that the ALS-007
+requires a separate IRQ for the MPU-401, so don't specify -1 here). (Note
+that the base port of the internal FM synth is fixed at 0x388 on the ALS007;
+in any case the FM synth location is not setable in the kernel config).
+
+The resulting sound driver will provide the following capabilities:
+ - 8 and 16 bit audio playback
+ - 8 and 16 bit audio recording
+ - Software selection of record source (line in, CD, FM, mic, master)
+ - Record and playback of midi data via the external MPU-401
+ - Playback of midi data using inbuilt FM synthesizer
+ - Control of the ALS-007 mixer via any OSS-compatible mixer programs.
+ Controls available are Master (L&R), Line in (L&R), CD (L&R),
+ DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono).
+
+Jonathan Woithe
+jwoithe@physics.adelaide.edu.au
+30 March 1998
be issued (of course with the suitable values for the parameters)
after PNP setup:
-insmod sound.o
+modprobe sound.o
insmod uart401.o
insmod sb.o io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
insmod awe_wave.o
rmmod sb
rmmod uart401
rmmod sound
+rmmod soundcore
-----
--- /dev/null
+Getting Firmware
+~~~~~~~~~~~~~~~~
+
+See the end of this document on how to obtain and create the necessary
+firmware files.
+
+
+Supported Features
+~~~~~~~~~~~~~~~~~~
+
+Currently digital audio and mixer functionality is supported. (memory
+mapped digital audio is not yet supported). MultiSound support is
+fully modularized, and can only be used as modules:
+
+msnd - MultiSound base (requires soundcore)
+msnd_classic - Base audio/mixer support for Classic, Monetery and
+ Tahiti cards
+msnd_pinnacle - Base audio/mixer support for Pinnacle and Fiji cards
+
+
+Important Notes - Read Before Using
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* The firmware files are not included (may change in future). You
+must obtain these images from Turtle Beach (they are included in the
+MultiSound Development Kits), and place them in /etc/sound for
+example, and give the full paths in the Linux configuration. Please
+note these files must be binary files, not assember.
+
+* You need the following information to use this driver: the card's
+I/O base (i.e. 0x250), the IRQ (i.e. 5), and the shared memory area
+(i.e. 0xd8000).
+
+* Probing is not currently implemented, and only the msnd_classic
+driver will actually program the card's IRQ and SMA locations; the
+msnd_pinnacle is primarily for use with the card in PnP mode, however
+it should work if you know what the card's resource values are (this
+will change in the future).
+
+* Note the Turtle Beach Pinnacle card contains a Kurzweil MA-1
+synthesizer with an MPU compatible interface, which should work with
+the mpu401 module. You must know the resource values of the MA-1.
+
+
+Examples
+~~~~~~~~
+
+* If you have a MultiSound Classic/Monterey/Tahiti:
+
+insmod soundcore
+insmod msnd
+insmod msnd_classic io=0x290 irq=7 mem=0xd0000
+
+* If you have a MultiSound Pinnacle:
+
+insmod soundcore
+insmod msnd
+insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000
+
+* To use the MPU-compatible Kurzweil synth on the Pinnacle, add the
+following:
+
+insmod sound
+insmod mpu401 io=0x330 irq=9
+
+
+msnd_classic, msnd_pinnacle Required Options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the following options are not given, the module will not load.
+Examine the kernel message log for informative error messages.
+WARNING--probing isn't supported so try to make sure you have the
+correct shared memory area, otherwise you may experience problems.
+
+io I/O base of DSP, e.g. io=0x210
+irq IRQ number, e.g. irq=5
+mem Shared memory area, e.g. mem=0xd8000
+
+
+msnd_classic, msnd_pinnacle Additional Options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+fifosize The digital audio FIFOs, in kilobytes. The default is
+ 64kB (two FIFOs are allocated, so this uses up 128kB).
+
+calibrate_signal Setting this to one calibrates the ADCs to the
+ signal, zero calibrates to the card (defaults
+ to zero).
+
+
+Creating and Obtaining Firmware
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ For the Classic/Tahiti/Monterey
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Download to /tmp and unzip the following file from Turtle Beach:
+
+ ftp://ftp.tbeach.com/pub/tbs/pinn/msndvkit.zip
+
+When unzipped, unzip the file named MsndFiles.zip. Then copy the
+following firmware files to /etc/sound (note the file renaming):
+
+ cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin
+ cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin
+
+When configuring the Linux kernel, specify /etc/sound/msndinit.bin and
+/etc/sound/msndperm.bin for the two firmware files.
+
+
+ For the Pinnacle/Fiji
+ ~~~~~~~~~~~~~~~~~~~~~
+
+Download to /tmp and unzip the following file from Turtle Beach (be
+sure to use the entire URL; some have had trouble navigating to the
+URL):
+
+ ftp://ftp.tbeach.com/oldpub/tbs/pinn/pnddk100.zip
+
+Put the following lines into a file named conv.l (between the start
+and end lines):
+
+-- conv.l start --
+%%
+[ \n\t,\r] ;
+\;.* ;
+DB ;
+[0-9A-Fa-f]+H { int n; sscanf(yytext, "%xH", &n); printf("%c", n); }
+-- conv.l end --
+
+Then, compile the conv program with GNU make with the following
+command:
+
+ make LEX=flex LOADLIBES=-lfl conv
+
+This should give you an executable named conv. Now, we create the
+binary firmware files by doing the following conversion (assuming the
+archive unpacked into a directory named PINNDDK):
+
+ ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin
+ ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin
+
+The conv (and conv.l) program is not needed after conversion and can
+be safely deleted. Then, when configuring the Linux kernel, specify
+/etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two
+firmware files.
--- /dev/null
+Turtle Beach Multisound support is not yet integrated. If you'd like
+to test it or help out in finishing the module please see
+
+ http://www.rpi.edu/~veliaa/pinlinux.html
to warm boot from DOS/Windows with the required firmware loaded under this
OS. IBM are being difficult about documenting how to load this firmware.
-Advance Logic ALS007
+Avance Logic ALS007
-This card isn't currently supported. I have patches to merge however that
-add limited support.
+This card is supported; see the separate file ALS007 for full details.
+
+Avance Logic ALS100
+
+This card is supported; setup should be as for a standard Sound Blaster 16.
+The driver will identify the audio device as a "Sound Blaster 16 (ALS-100)".
HIGH-SPEED SCC DRIVER FOR AX.25
P: Klaus Kudielka
-M: oe1kib@oe1xtu.ampr.org
+M: oe1kib@oe1kib.ampr.org
L: linux-hams@vger.rutgers.edu
S: Maintained
L: linux-kernel@vger.rutgers.edu
S: Maintained
+IP FIREWALL
+P: Paul Russell
+M: Paul.Russell@rustcorp.com.au
+W: http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+S: Maintained
+
IPX/SPX NETWORK LAYER
P: Jay Schulist
M: Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
L: linux-kernel@vger.rutgers.edu
S: Maintained
+MULTISOUND SOUND DRIVER
+P: Andrew Veliath
+M: andrewtv@usa.net
+S: Maintained
+
NCP FILESYSTEM:
P: Petr Vandrovec
M: vandrove@vc.cvut.cz
L: linux-kernel@vger.rutgers.edu ?
S: Supported
+SPX NETWORK LAYER
+P: Jay Schulist
+M: Jay.Schulist@spacs.k12.wi.us
+L: linux-net@vger.rutgers.edu
+S: Supported
+
STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
P: Greg Ungerer
M: support@stallion.oz.au
TOKEN-RING NETWORK DRIVER
P: Paul Norton
-M: pnorton@cts.com
+M: p.norton@computer.org
L: linux-net@vger.rutgers.edu
+L: linux-tr@emissary.aus-etc.com
S: Maintained
U14-34F SCSI DRIVER
L: linux-hams@vger.rutgers.edu
S: Maintained
+ARM PORT
+P: Russell King
+M: linux@arm.uk.linux.org
+L: linux-arm@vger.rutgers.edu
+L: arm-linux@tardis.ed.ac.uk
+W: http://www.arm.uk.linux.org/~rmk/armlinux.html
+S: Maintained
+
+ARM MFM AND FLOPPY DRIVERS
+P: Dave Gilbert
+M: linux@treblig.org
+S: Maintained
+
REST:
P: Linus Torvalds
S: Buried alive in diapers
PATCHLEVEL = 1
SUBLEVEL = 106
-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
+ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm*/arm/ -e s/sa110/arm/)
#
# For SMP kernels, set this. We don't want to have this in the config file
ON WHAT HARDWARE DOES IT RUN?
Linux was first developed for 386/486-based PCs. These days it also
- runs on DEC Alphas, SUN Sparcs, M68000 machines (like Atari and Amiga),
- MIPS, PowerPC, and others.
+ runs on ARMs, DEC Alphas, SUN Sparcs, M68000 machines (like Atari and
+ Amiga), MIPS and PowerPC, and others.
DOCUMENTATION:
error = verify_area(VERIFY_WRITE, name, 5 * 32);
if (error)
goto out;
+
+ down(&uts_sem);
copy_to_user(name + 0, system_utsname.sysname, 32);
copy_to_user(name + 32, system_utsname.nodename, 32);
copy_to_user(name + 64, system_utsname.release, 32);
copy_to_user(name + 96, system_utsname.version, 32);
copy_to_user(name + 128, system_utsname.machine, 32);
+ up(&uts_sem);
+
out:
unlock_kernel();
return error;
if (namelen > 32)
len = 32;
+ down(&uts_sem);
for (i = 0; i < len; ++i) {
- put_user(system_utsname.domainname[i], name + i);
+ __put_user(system_utsname.domainname[i], name + i);
if (system_utsname.domainname[i] == '\0')
break;
}
+ up(&uts_sem);
out:
unlock_kernel();
return error;
printk("sysinfo(%d)", command);
goto out;
}
+
+ down(&uts_sem);
res = sysinfo_table[offset];
len = strlen(res)+1;
if (len > count)
err = -EFAULT;
else
err = 0;
+ up(&uts_sem);
out:
unlock_kernel();
return err;
/* endless idle loop with no priority at all */
current->counter = -100;
for (;;) {
+ check_pgt_cache();
schedule();
}
ret = 0;
struct thread_struct * original_pcb_ptr;
+#ifndef __SMP__
+struct pgtable_cache_struct quicklists;
+#endif
+
+void __bad_pmd(pgd_t *pgd)
+{
+ printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+ pgd_set(pgd, BAD_PAGETABLE);
+}
+
+void __bad_pte(pmd_t *pmd)
+{
+ printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+ pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+ pmd_t *pmd;
+
+ pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+ if (pgd_none(*pgd)) {
+ if (pmd) {
+ clear_page((unsigned long)pmd);
+ pgd_set(pgd, pmd);
+ return pmd + offset;
+ }
+ pgd_set(pgd, BAD_PAGETABLE);
+ return NULL;
+ }
+ free_page((unsigned long)pmd);
+ if (pgd_bad(*pgd)) {
+ __bad_pmd(pgd);
+ return NULL;
+ }
+ return (pmd_t *) pgd_page(*pgd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (pte) {
+ clear_page((unsigned long)pte);
+ pmd_set(pmd, pte);
+ return pte + offset;
+ }
+ pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+ return NULL;
+ }
+ free_page((unsigned long)pte);
+ if (pmd_bad(*pmd)) {
+ __bad_pte(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
void show_mem(void)
{
int i,free = 0,total = 0,reserved = 0;
- int shared = 0;
+ int shared = 0, cached = 0;
printk("\nMem-info:\n");
show_free_areas();
total++;
if (PageReserved(mem_map+i))
reserved++;
+ else if (PageSwapCache(mem_map+i))
+ cached++;
else if (!atomic_read(&mem_map[i].count))
free++;
else
printk("%d free pages\n",free);
printk("%d reserved pages\n",reserved);
printk("%d pages shared\n",shared);
+ printk("%d pages swap cached\n",cached);
+ printk("%d pages in page table cache\n",pgtable_cache_size);
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
void free_initmem (void)
{
- extern char __init_begin, __init_end;
- unsigned long addr;
-
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
- free_page(addr);
- }
- printk ("Freeing unused kernel memory: %ldk freed\n",
+ extern char __init_begin, __init_end;
+ unsigned long addr;
+
+ addr = (unsigned long)(&__init_begin);
+ for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+ free_page(addr);
+ }
+ printk ("Freeing unused kernel memory: %ldk freed\n",
(&__init_end - &__init_begin) >> 10);
}
asmlinkage int sys_uname (struct old_utsname * name)
{
static int warned = 0;
-
+ int err;
+
if (warned == 0) {
warned ++;
printk (KERN_NOTICE "%s (%d): obsolete uname call\n",
current->comm, current->pid);
}
- if (name && !copy_to_user (name, &system_utsname, sizeof (*name)))
- return 0;
- return -EFAULT;
+ if(!name)
+ return -EFAULT;
+ down(&uts_sem);
+ err=copy_to_user (name, &system_utsname, sizeof (*name));
+ up(&uts_sem);
+ return err?-EFAULT:0;
}
asmlinkage int sys_olduname(struct oldold_utsname * name)
if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
return -EFAULT;
+ down(&uts_sem);
+
error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
error -= __put_user(0,name->version+__OLD_UTS_LEN);
error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
error -= __put_user(0,name->machine+__OLD_UTS_LEN);
+
+ up(&uts_sem);
+
error = error ? -EFAULT : 0;
return error;
out #0x60,al
call empty_8042
+! wait until a20 really *is* enabled; it can take a fair amount of
+! time on any
+
+ push ds
+ push es
+ xor ax,ax ! segment 0x0000
+ mov ds,ax
+ dec ax ! segment 0xffff (HMA)
+ mov es,ax
+a20_wait:
+ inc ax
+ mov [0x7c00],ax ! any unused memory location < 64K
+ seg es
+ cmp ax,[0x7c10] ! corresponding HMA address
+ je a20_wait ! loop until no longer aliased
+ pop es
+ pop ds
+
! make sure any possible coprocessor is properly reset..
xor ax,ax
* in 16-bit mode for the "real" operations.
*/
call setup_idt
- xorl %eax,%eax
-1: incl %eax # check that A20 really IS enabled
- movl %eax,0x000000 # loop forever if it isn't
- cmpl %eax,0x100000
- je 1b
/*
* Initialize eflags. Some BIOS's leave bits like NT set. This would
* confuse the debugger if this code is traced.
* the APM bios knowing only one CPU at a time will do
* so.
*/
- if (!start_idle)
+ if (!start_idle) {
+ check_pgt_cache();
start_idle = jiffies;
+ }
if (jiffies - start_idle > HARD_IDLE_TIMEOUT)
hard_idle();
else {
if(current_cpu_data.hlt_works_ok &&
!hlt_counter && !need_resched)
__asm("hlt");
+ check_pgt_cache();
/*
* tq_scheduler currently assumes we're running in a process
* context (ie that we hold the kernel lock..)
if ((fpvalid = current->used_math) != 0) {
if (boot_cpu_data.hard_math) {
- if (last_task_used_math == current) {
- __asm__("clts ; fsave %0; fwait": :"m" (*fpu));
- }
+ if (last_task_used_math == current) {
+ __asm__("clts ; fsave %0; fwait": :"m" (*fpu));
+ }
else
memcpy(fpu,¤t->tss.i387.hard,sizeof(*fpu));
} else {
{ X86_VENDOR_AMD, 5,
{ "K5/SSA5 (PR-75, PR-90, PR-100)", "K5 (PR-120, PR-133)",
"K5 (PR-166)", "K5 (PR-200)", NULL, NULL,
- "K6 (166 - 266)", "K6 (166 - 300)", "K6-3D (200 - 450)",
+ "K6 (166 - 266)", "K6 (166 - 300)", "K6-2 (200 - 450)",
"K6-3D-Plus (200 - 450)", NULL, NULL, NULL, NULL, NULL, NULL }},
{ X86_VENDOR_UMC, 4,
{ NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
{
char *p = buffer;
int sep_bug;
- static const char *x86_cap_flags[] = {
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
- "fcmov", "17", "18", "19", "20", "21", "22", "mmx",
- "osfxsr", "25", "26", "27", "28", "29", "30", "amd3d"
+ static char *x86_cap_flags[] = {
+ "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
+ "cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
+ "16", "17", "18", "19", "20", "21", "22", "mmx",
+ "24", "25", "26", "27", "28", "29", "30", "31"
};
struct cpuinfo_x86 *c = cpu_data;
int i, n;
} else
p += sprintf(p, "stepping\t: unknown\n");
+ /* Modify the capabilities according to chip type */
+ if (c->x86_mask) {
+ if (c->x86_vendor == X86_VENDOR_CYRIX) {
+ x86_cap_flags[24] = "cxmmx";
+ } else if (c->x86_vendor == X86_VENDOR_AMD) {
+ x86_cap_flags[16] = "fcmov";
+ x86_cap_flags[31] = "amd3d";
+ } else if (c->x86_vendor == X86_VENDOR_INTEL) {
+ x86_cap_flags[6] = "pae";
+ x86_cap_flags[9] = "apic";
+ x86_cap_flags[12] = "mtrr";
+ x86_cap_flags[14] = "mca";
+ x86_cap_flags[16] = "pat";
+ x86_cap_flags[17] = "pse";
+ x86_cap_flags[24] = "osfxsr";
+ }
+ }
+
sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
c->x86 == 0x06 &&
c->cpuid_level >= 0 &&
struct cpuinfo_x86 *c=&cpu_data[id];
*c = boot_cpu_data;
+ c->pte_quick = 0;
+ c->pgd_quick = 0;
+ c->pgtable_cache_sz = 0;
identify_cpu(c);
/*
* Mask B, Pentium, but not Pentium MMX
*/
asmlinkage int sys_uname(struct old_utsname * name)
{
- if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
- return 0;
- return -EFAULT;
+ int err;
+ if (!name)
+ return -EFAULT;
+ down(&uts_sem);
+ err=copy_to_user(name, &system_utsname, sizeof (*name));
+ up(&uts_sem);
+ return err?-EFAULT:0;
}
asmlinkage int sys_olduname(struct oldold_utsname * name)
if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
return -EFAULT;
+ down(&uts_sem);
+
error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
error |= __put_user(0,name->version+__OLD_UTS_LEN);
error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
error |= __put_user(0,name->machine+__OLD_UTS_LEN);
-
+
+ up(&uts_sem);
+
error = error ? -EFAULT : 0;
return error;
* Authors: Jorge Cwik, <jorge@laser.satlink.net>
* Arnt Gulbrandsen, <agulbra@nvg.unit.no>
* Tom May, <ftom@netcom.com>
+ * Pentium Pro/II routines:
+ * Alexander Kjeldaas <astor@guardian.no>
+ * Finn Arne Gangstad <finnag@guardian.no>
* Lots of code moved from tcp.c and ip.c; see those files
* for more names.
*
* computes a partial checksum, e.g. for TCP/UDP fragments
*/
+#if CPU!=686
+
unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) {
/*
* Experiments with ethernet and slip connections show that buff
return(sum);
}
+#else /* 686 */
+
+unsigned int csum_partial(const unsigned char * buf, int len, unsigned int sum) {
+ __asm__ ("
+ testl $2, %%esi
+ jnz 30f
+10:
+ movl %%ecx, %%edx
+ movl %%ecx, %%ebx
+ andl $0x7c, %%ebx
+ shrl $7, %%ecx
+ addl %%ebx,%%esi
+ shrl $2, %%ebx
+ negl %%ebx
+ lea 45f(%%ebx,%%ebx,2), %%ebx
+ testl %%esi, %%esi
+ jmp %%ebx
+
+ # Handle 2-byte-aligned regions
+20: addw (%%esi), %%ax
+ lea 2(%%esi), %%esi
+ adcl $0, %%eax
+ jmp 10b
+
+30: subl $2, %%ecx
+ ja 20b
+ je 32f
+ movzbl (%%esi),%%ebx # csumming 1 byte, 2-aligned
+ addl %%ebx, %%eax
+ adcl $0, %%eax
+ jmp 80f
+32:
+ addw (%%esi), %%ax # csumming 2 bytes, 2-aligned
+ adcl $0, %%eax
+ jmp 80f
+
+40:
+ addl -128(%%esi), %%eax
+ adcl -124(%%esi), %%eax
+ adcl -120(%%esi), %%eax
+ adcl -116(%%esi), %%eax
+ adcl -112(%%esi), %%eax
+ adcl -108(%%esi), %%eax
+ adcl -104(%%esi), %%eax
+ adcl -100(%%esi), %%eax
+ adcl -96(%%esi), %%eax
+ adcl -92(%%esi), %%eax
+ adcl -88(%%esi), %%eax
+ adcl -84(%%esi), %%eax
+ adcl -80(%%esi), %%eax
+ adcl -76(%%esi), %%eax
+ adcl -72(%%esi), %%eax
+ adcl -68(%%esi), %%eax
+ adcl -64(%%esi), %%eax
+ adcl -60(%%esi), %%eax
+ adcl -56(%%esi), %%eax
+ adcl -52(%%esi), %%eax
+ adcl -48(%%esi), %%eax
+ adcl -44(%%esi), %%eax
+ adcl -40(%%esi), %%eax
+ adcl -36(%%esi), %%eax
+ adcl -32(%%esi), %%eax
+ adcl -28(%%esi), %%eax
+ adcl -24(%%esi), %%eax
+ adcl -20(%%esi), %%eax
+ adcl -16(%%esi), %%eax
+ adcl -12(%%esi), %%eax
+ adcl -8(%%esi), %%eax
+ adcl -4(%%esi), %%eax
+45:
+ lea 128(%%esi), %%esi
+ adcl $0, %%eax
+ dec %%ecx
+ jge 40b
+ movl %%edx, %%ecx
+50: andl $3, %%ecx
+ jz 80f
+
+ # Handle the last 1-3 bytes without jumping
+ notl %%ecx # 1->2, 2->1, 3->0, higher bits are masked
+ movl $0xffffff,%%ebx # by the shll and shrl instructions
+ shll $3,%%ecx
+ shrl %%cl,%%ebx
+ andl -128(%%esi),%%ebx # esi is 4-aligned so should be ok
+ addl %%ebx,%%eax
+ adcl $0,%%eax
+80: "
+ : "=a"(sum)
+ : "0"(sum), "c"(len), "S"(buf)
+ : "bx", "cx", "dx", "si");
+ return(sum);
+}
+
+#endif
+
/*
* Copy from ds while checksumming, otherwise like csum_partial
*
" 9999: "#y"; \n \
.section __ex_table, \"a\"; \n \
.long 9999b, 6001f \n \
- .previous"
+ .previous\n"
#define DST(y...) \
" 9999: "#y"; \n \
.section __ex_table, \"a\"; \n \
.long 9999b, 6002f \n \
- .previous"
+ .previous\n"
+
+#if CPU!=686
unsigned int csum_partial_copy_generic (const char *src, char *dst,
int len, int sum, int *src_err_ptr, int *dst_err_ptr)
return(sum);
}
+#else /* CPU == 686 */
+
+#define ROUND1(x) \
+ SRC(movl x(%%esi), %%ebx ) \
+ "addl %%ebx, %%eax\n" \
+ DST(movl %%ebx, x(%%edi) )
+
+#define ROUND(x) \
+ SRC(movl x(%%esi), %%ebx ) \
+ "adcl %%ebx, %%eax\n" \
+ DST(movl %%ebx, x(%%edi) )
+
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+ int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+{
+ __asm__ __volatile__ ("
+ movl %%ecx, %%edx
+ movl %%ecx, %%ebx
+ shrl $6, %%ecx
+ andl $0x3c, %%ebx
+ negl %%ebx
+ subl %%ebx, %%esi
+ subl %%ebx, %%edi
+ lea 3f(%%ebx,%%ebx), %%ebx
+ testl %%esi, %%esi
+ jmp %%ebx
+1: addl $64,%%esi
+ addl $64,%%edi\n"
+ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
+ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
+ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
+ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
+"3: adcl $0,%%eax
+ dec %%ecx
+ jge 1b
+4: andl $3, %%edx
+ jz 7f
+ cmpl $2, %%edx
+ jb 5f
+ " SRC(movw (%%esi), %%dx )"
+ leal 2(%%esi), %%esi
+ " DST(movw %%dx, (%%edi) )"
+ leal 2(%%edi), %%edi
+ je 6f
+ shll $16,%%edx
+5:" SRC(movb (%%esi), %%dl )"
+ " DST(movb %%dl, (%%edi) )"
+6: addl %%edx, %%eax
+ adcl $0, %%eax
+7:
+.section .fixup, \"ax\"
+6000: movl %7, (%%ebx)
+# FIXME: do zeroing of rest of the buffer here.
+ jmp 7b
+6001: movl %1, %%ebx
+ jmp 6000b
+6002: movl %2, %%ebx
+ jmp 6000b
+.previous
+ "
+ : "=a"(sum), "=m"(src_err_ptr), "=m"(dst_err_ptr)
+ : "0"(sum), "c"(len), "S"(src), "D" (dst),
+ "i" (-EFAULT)
+ : "bx", "cx", "dx", "si", "di" );
+ return(sum);
+}
+
+#undef ROUND
+#undef ROUND1
+
+#endif
+
+
#undef SRC
#undef DST
#include <asm/pgtable.h>
#include <asm/dma.h>
-const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
-
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
+void __bad_pte_kernel(pmd_t *pmd)
+{
+ printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+ pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+}
+
+void __bad_pte(pmd_t *pmd)
+{
+ printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+ pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+}
+
+pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (pte) {
+ clear_page((unsigned long)pte);
+ pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte);
+ return pte + offset;
+ }
+ pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
+ return NULL;
+ }
+ free_page((unsigned long)pte);
+ if (pmd_bad(*pmd)) {
+ __bad_pte_kernel(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+ unsigned long pte;
+
+ pte = (unsigned long) __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (pte) {
+ clear_page(pte);
+ pmd_val(*pmd) = _PAGE_TABLE + __pa(pte);
+ return (pte_t *)(pte + offset);
+ }
+ pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+ return NULL;
+ }
+ free_page(pte);
+ if (pmd_bad(*pmd)) {
+ __bad_pte(pmd);
+ return NULL;
+ }
+ return (pte_t *) (pmd_page(*pmd) + offset);
+}
+
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
total++;
if (PageReserved(mem_map+i))
reserved++;
- if (PageSwapCache(mem_map+i))
+ else if (PageSwapCache(mem_map+i))
cached++;
else if (!atomic_read(&mem_map[i].count))
free++;
printk("%d reserved pages\n",reserved);
printk("%d pages shared\n",shared);
printk("%d pages swap cached\n",cached);
+ printk("%ld pages in page table cache\n",pgtable_cache_size);
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
SUBDIRS := $(SUBDIRS) arch/m68k/mac
endif
+ifdef CONFIG_HP300
+CORE_FILES := $(CORE_FILES) arch/m68k/hp300/hp300.o
+SUBDIRS := $(SUBDIRS) arch/m68k/hp300
+endif
+
ifdef CONFIG_APOLLO
CORE_FILES := $(CORE_FILES) arch/m68k/apollo/apollo.o
SUBDIRS := $(SUBDIRS) arch/m68k/apollo
SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x
endif
+ifdef CONFIG_BVME6000
+CORE_FILES := $(CORE_FILES) arch/m68k/bvme6000/bvme6000.o
+SUBDIRS := $(SUBDIRS) arch/m68k/bvme6000
+endif
+
ifdef CONFIG_M68040
CORE_FILES := $(CORE_FILES) arch/m68k/fpsp040/fpsp.o
SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
addql #8,%%sp
addql #4,%%sp
jbra "SYMBOL_NAME_STR(ret_from_interrupt)
- : : "i" (&kstat.irqs), "n" (PT_OFF_FORMATVEC)
+ : : "i" (&kstat.irqs[0]), "n" (PT_OFF_FORMATVEC)
);
}
#include <asm/atariints.h>
#include <asm/atarihw.h>
#include <asm/atarikb.h>
-#include <asm/atari_mouse.h>
#include <asm/atari_joystick.h>
#include <asm/irq.h>
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
};
-static u_short atashift_alt_map[NR_KEYS] = {
+static u_short atashift_alt_map[NR_KEYS] __initdata = {
0xf200, 0xf81b, 0xf821, 0xf840, 0xf823, 0xf824, 0xf825, 0xf85e,
0xf826, 0xf82a, 0xf828, 0xf829, 0xf85f, 0xf82b, 0xf808, 0xf809,
0xf851, 0xf857, 0xf845, 0xf852, 0xf854, 0xf859, 0xf855, 0xf849,
__initfunc(int atari_keyb_init(void))
{
/* setup key map */
- memcpy(plain_map, ataplain_map, sizeof(plain_map));
- memcpy(shift_map, atashift_map, sizeof(shift_map));
+ memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
+ memcpy(key_maps[1], atashift_map, sizeof(plain_map));
+ memcpy(key_maps[4], atactrl_map, sizeof(plain_map));
+ memcpy(key_maps[5], atashift_ctrl_map, sizeof(plain_map));
+ memcpy(key_maps[8], ataalt_map, sizeof(plain_map));
+ /* Atari doesn't have an altgr_map, so we can reuse its memory for
+ atashift_alt_map */
+ memcpy(key_maps[2], atashift_alt_map, sizeof(plain_map));
+ key_maps[9] = key_maps[2];
key_maps[2] = 0; /* ataaltgr_map */
- memcpy(ctrl_map, atactrl_map, sizeof(ctrl_map));
- memcpy(shift_ctrl_map, atashift_ctrl_map, sizeof(shift_ctrl_map));
- memcpy(alt_map, ataalt_map, sizeof(alt_map));
- key_maps[9] = atashift_alt_map;
- memcpy(ctrl_alt_map, atactrl_alt_map, sizeof(ctrl_alt_map));
+ memcpy(key_maps[12], atactrl_alt_map, sizeof(plain_map));
key_maps[13] = atashift_ctrl_alt_map;
keymap_count = 8;
return( 0 );
}
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void kbd_reset_setup(char *str, int *ints))
+{
+}
* License. See the file COPYING in the main directory of this archive
* for more details.
*
+ * 1998-05-31 ++andreas: atari_mksound rewritten to always use the envelope,
+ * no timer, atari_nosound removed.
+ *
*/
* stuff from the old atasound.c
*/
-
-static void atari_nosound (unsigned long ignored)
-{
- unsigned char tmp;
- unsigned long flags;
-
- /* turn off generator A in mixer control */
- save_flags(flags);
- cli();
- sound_ym.rd_data_reg_sel = 7;
- tmp = sound_ym.rd_data_reg_sel;
- sound_ym.wd_data = tmp | 0x39;
- restore_flags(flags);
-}
-
-
void atari_microwire_cmd (int cmd)
{
tt_microwire.mask = 0x7ff;
}
-#define PC_FREQ 1192180
+/* PSG base frequency */
#define PSG_FREQ 125000
+/* PSG envelope base frequency times 10 */
+#define PSG_ENV_FREQ_10 78125
-
-void atari_mksound (unsigned int count, unsigned int ticks)
+void atari_mksound (unsigned int hz, unsigned int ticks)
{
- static struct timer_list sound_timer = { NULL, NULL, 0, 0,
- atari_nosound };
- /*
- * Generates sound of some count for some number of clock ticks
- * [count = 1193180 / frequency]
- */
+ /* Generates sound of some frequency for some number of clock
+ ticks. */
unsigned long flags;
unsigned char tmp;
+ int period;
save_flags(flags);
cli();
- if (count == 750 && ticks == HZ/8) {
- /* Special case: These values are used by console.c to
- * generate the console bell. They are cached here and the
- * sound actually generated is somehow special: it uses the
- * generator B and an envelope. No timer is needed therefore
- * and the bell doesn't disturb an other ongoing sound.
- */
+ /* Convert from frequency value to PSG period value (base
+ frequency 125 kHz). */
+ period = PSG_FREQ / hz;
+
+ if (period > 0xfff) period = 0xfff;
- /* set envelope duration to 492 ms */
+ /* Disable generator A in mixer control. */
+ sound_ym.rd_data_reg_sel = 7;
+ tmp = sound_ym.rd_data_reg_sel;
+ tmp |= 011;
+ sound_ym.wd_data = tmp;
+ /* Set generator A frequency to hz. */
+ sound_ym.rd_data_reg_sel = 0;
+ sound_ym.wd_data = period & 0xff;
+ sound_ym.rd_data_reg_sel = 1;
+ sound_ym.wd_data = (period >> 8) & 0xf;
+ if (ticks) {
+ /* Set length of envelope (max 8 sec). */
+ int length = (ticks * PSG_ENV_FREQ_10) / HZ / 10;
+
+ if (length > 0xffff) length = 0xffff;
sound_ym.rd_data_reg_sel = 11;
- sound_ym.wd_data = 0;
+ sound_ym.wd_data = length & 0xff;
sound_ym.rd_data_reg_sel = 12;
- sound_ym.wd_data = 15;
- /* envelope form: max -> min single */
+ sound_ym.wd_data = length >> 8;
+ /* Envelope form: max -> min single. */
sound_ym.rd_data_reg_sel = 13;
- sound_ym.wd_data = 9;
- /* set generator B frequency to 2400 Hz */
- sound_ym.rd_data_reg_sel = 2;
- sound_ym.wd_data = 52;
- sound_ym.rd_data_reg_sel = 3;
sound_ym.wd_data = 0;
- /* set volume of generator B to envelope control */
- sound_ym.rd_data_reg_sel = 9;
+ /* Use envelope for generator A. */
+ sound_ym.rd_data_reg_sel = 8;
sound_ym.wd_data = 0x10;
- /* enable generator B in the mixer control */
- sound_ym.rd_data_reg_sel = 7;
- tmp = sound_ym.rd_data_reg_sel;
- sound_ym.wd_data = (tmp & ~0x02) | 0x38;
-
- restore_flags(flags);
- return;
- }
-
- del_timer( &sound_timer );
-
- if (!count) {
- atari_nosound( 0 );
- }
- else {
-
- /* convert from frequency value
- * to PSG period value (base frequency 125 kHz).
- */
- int period = PSG_FREQ / count;
-
- if (period > 0xfff) period = 0xfff;
-
- /* set generator A frequency to 0 */
- sound_ym.rd_data_reg_sel = 0;
- sound_ym.wd_data = period & 0xff;
- sound_ym.rd_data_reg_sel = 1;
- sound_ym.wd_data = (period >> 8) & 0xf;
- /* turn on generator A in mixer control (but not noise
- * generator!) */
- sound_ym.rd_data_reg_sel = 7;
- tmp = sound_ym.rd_data_reg_sel;
- sound_ym.wd_data = (tmp & ~0x01) | 0x38;
- /* set generator A level to maximum, no envelope */
+ } else {
+ /* Set generator A level to maximum, no envelope. */
sound_ym.rd_data_reg_sel = 8;
sound_ym.wd_data = 15;
-
- if (ticks) {
- sound_timer.expires = jiffies + ticks;
- add_timer( &sound_timer );
- }
}
+ /* Turn on generator A in mixer control. */
+ sound_ym.rd_data_reg_sel = 7;
+ tmp &= ~1;
+ sound_ym.wd_data = tmp;
restore_flags(flags);
}
#include <asm/atari_stram.h>
#include <asm/system.h>
#include <asm/machdep.h>
+#include <asm/hwtest.h>
u_long atari_mch_cookie;
u_long atari_mch_type = 0;
extern void (*kd_mksound)(unsigned int, unsigned int);
-/* This function tests for the presence of an address, specially a
- * hardware register address. It is called very early in the kernel
- * initialization process, when the VBR register isn't set up yet. On
- * an Atari, it still points to address 0, which is unmapped. So a bus
- * error would cause another bus error while fetching the exception
- * vector, and the CPU would do nothing at all. So we needed to set up
- * a temporary VBR and a vector table for the duration of the test.
+/* I've moved hwreg_present() and hwreg_present_bywrite() out into
+ * mm/hwtest.c, to avoid having multiple copies of the same routine
+ * in the kernel [I wanted them in hp300 and they were already used
+ * in the nubus code. NB: I don't have an Atari so this might (just
+ * conceivably) break something.
+ * I've preserved the #if 0 version of hwreg_present_bywrite() here
+ * for posterity.
+ * -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998
*/
-
-__initfunc(static int hwreg_present( volatile void *regp ))
-{
- int ret = 0;
- long save_sp, save_vbr;
- long tmp_vectors[3];
-
- __asm__ __volatile__
- ( "movec %/vbr,%2\n\t"
- "movel #Lberr1,%4@(8)\n\t"
- "movec %4,%/vbr\n\t"
- "movel %/sp,%1\n\t"
- "moveq #0,%0\n\t"
- "tstb %3@\n\t"
- "nop\n\t"
- "moveq #1,%0\n"
- "Lberr1:\n\t"
- "movel %1,%/sp\n\t"
- "movec %2,%/vbr"
- : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
- : "a" (regp), "a" (tmp_vectors)
- );
-
- return( ret );
-}
#if 0
__initfunc(static int
}
#endif
-/* Basically the same, but writes a value into a word register, protected
- * by a bus error handler */
-
-__initfunc(static int hwreg_write( volatile void *regp, unsigned short val ))
-{
- int ret;
- long save_sp, save_vbr;
- long tmp_vectors[3];
-
- __asm__ __volatile__
- ( "movec %/vbr,%2\n\t"
- "movel #Lberr2,%4@(8)\n\t"
- "movec %4,%/vbr\n\t"
- "movel %/sp,%1\n\t"
- "moveq #0,%0\n\t"
- "movew %5,%3@\n\t"
- "nop \n\t" /* If this nop isn't present, 'ret' may already be
- * loaded with 1 at the time the bus error
- * happens! */
- "moveq #1,%0\n"
- "Lberr2:\n\t"
- "movel %1,%/sp\n\t"
- "movec %2,%/vbr"
- : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
- : "a" (regp), "a" (tmp_vectors), "g" (val)
- );
-
- return( ret );
-}
/* ++roman: This is a more elaborate test for an SCC chip, since the plain
* Medusa board generates DTACK at the SCC's standard addresses, but a SCC
#include <asm/atarikb.h>
#include <asm/atari_joystick.h>
-#include <asm/atari_mouse.h>
#include <asm/uaccess.h>
#define MAJOR_NR JOYSTICK_MAJOR
return( -ENOMEM );
}
DPRINTK( "unswap: reading swap page %lu to %08lx\n", i, page );
- read_swap_page( entry, (char *)page );
+ rw_swap_page( READ, entry, (char *)page, 1 );
for_each_task(p) {
if (unswap_process( p->mm, entry, page, 0 )) {
#define RTC_READ(reg) \
({ unsigned char __val; \
- writeb(reg,&tt_rtc.regsel); \
+ (void) writeb(reg,&tt_rtc.regsel); \
__val = tt_rtc.data; \
__val; \
})
--- /dev/null
+#
+# Makefile for Linux arch/m68k/bvme6000 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := bvme6000.o
+O_OBJS := config.o bvmeints.o rtc.o
+#OX_OBJS = ksyms.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * arch/m68k/bvme6000/bvmeints.c
+ *
+ * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * based on amiints.c -- Amiga Linux interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+static void bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+static struct {
+ void (*handler)(int, void *, struct pt_regs *);
+ unsigned long flags;
+ void *dev_id;
+ const char *devname;
+ unsigned count;
+} irq_tab[256];
+
+/*
+ * void bvme6000_init_IRQ (void)
+ *
+ * Parameters: None
+ *
+ * Returns: Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the bvme6000 IRQ handling routines.
+ */
+
+void bvme6000_init_IRQ (void)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ irq_tab[i].handler = bvme6000_defhand;
+ irq_tab[i].flags = IRQ_FLG_STD;
+ irq_tab[i].dev_id = NULL;
+ irq_tab[i].devname = NULL;
+ irq_tab[i].count = 0;
+ }
+}
+
+int bvme6000_request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long flags, const char *devname, void *dev_id)
+{
+ if (irq > 255) {
+ printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+ return -ENXIO;
+ }
+#if 0
+ /* Nothing special about auto-vectored devices for the BVME6000,
+ * but treat it specially to avoid changes elsewhere.
+ */
+
+ if (irq >= VEC_INT1 && irq <= VEC_INT7)
+ return sys_request_irq(irq - VEC_SPUR, handler, flags,
+ devname, dev_id);
+#endif
+ if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
+ if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
+ printk("%s: IRQ %d from %s is not replaceable\n",
+ __FUNCTION__, irq, irq_tab[irq].devname);
+ return -EBUSY;
+ }
+ if (flags & IRQ_FLG_REPLACE) {
+ printk("%s: %s can't replace IRQ %d from %s\n",
+ __FUNCTION__, devname, irq, irq_tab[irq].devname);
+ return -EBUSY;
+ }
+ }
+ irq_tab[irq].handler = handler;
+ irq_tab[irq].flags = flags;
+ irq_tab[irq].dev_id = dev_id;
+ irq_tab[irq].devname = devname;
+ return 0;
+}
+
+void bvme6000_free_irq(unsigned int irq, void *dev_id)
+{
+ if (irq > 255) {
+ printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+ return;
+ }
+#if 0
+ if (irq >= VEC_INT1 && irq <= VEC_INT7) {
+ sys_free_irq(irq - VEC_SPUR, dev_id);
+ return;
+ }
+#endif
+ if (irq_tab[irq].dev_id != dev_id)
+ printk("%s: Removing probably wrong IRQ %d from %s\n",
+ __FUNCTION__, irq, irq_tab[irq].devname);
+
+ irq_tab[irq].handler = bvme6000_defhand;
+ irq_tab[irq].flags = IRQ_FLG_STD;
+ irq_tab[irq].dev_id = NULL;
+ irq_tab[irq].devname = NULL;
+}
+
+void bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
+{
+ if (vec > 255)
+ panic ("bvme6000_process_int: Illegal vector %ld", vec);
+ irq_tab[vec].count++;
+ irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+}
+
+int bvme6000_get_irq_list (char *buf)
+{
+ int i, len = 0;
+
+ for (i = 0; i < 256; i++) {
+ if (irq_tab[i].count)
+ len += sprintf (buf+len, "Vec 0x%02x: %8d %s\n",
+ i, irq_tab[i].count,
+ irq_tab[i].devname ? irq_tab[i].devname : "free");
+ }
+ return len;
+}
+
+
+static void bvme6000_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+ printk ("Unknown interrupt 0x%02x\n", irq);
+}
+
+void bvme6000_enable_irq (unsigned int irq)
+{
+}
+
+
+void bvme6000_disable_irq (unsigned int irq)
+{
+}
+
--- /dev/null
+/*
+ * arch/m68k/bvme6000/config.c
+ *
+ * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * Based on:
+ *
+ * linux/amiga/config.c
+ *
+ * Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/bvme6000hw.h>
+
+extern void bvme6000_process_int (int level, struct pt_regs *regs);
+extern void bvme6000_init_IRQ (void);
+extern void bvme6000_free_irq (unsigned int, void *);
+extern int bvme6000_get_irq_list (char *);
+extern void bvme6000_enable_irq (unsigned int);
+extern void bvme6000_disable_irq (unsigned int);
+static void bvme6000_get_model(char *model);
+static int bvme6000_get_hardware_list(char *buffer);
+extern int bvme6000_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void bvme6000_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int bvme6000_keyb_init(void);
+extern int bvme6000_kbdrate (struct kbd_repeat *);
+extern unsigned long bvme6000_gettimeoffset (void);
+extern void bvme6000_gettod (int *year, int *mon, int *day, int *hour,
+ int *min, int *sec);
+extern int bvme6000_hwclk (int, struct hwclk_time *);
+extern int bvme6000_set_clock_mmss (unsigned long);
+extern void bvme6000_check_partition (struct gendisk *hd, unsigned int dev);
+extern void bvme6000_mksound( unsigned int count, unsigned int ticks );
+extern void bvme6000_reset (void);
+extern void bvme6000_waitbut(void);
+void bvme6000_set_vectors (void);
+
+static unsigned char bcd2bin (unsigned char b);
+static unsigned char bin2bcd (unsigned char b);
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via bvme6000_process_int() */
+
+static void (*tick_handler)(int, void *, struct pt_regs *);
+
+int bvme6000_kbdrate (struct kbd_repeat *k)
+{
+ return 0;
+}
+
+void bvme6000_mksound( unsigned int count, unsigned int ticks )
+{
+}
+
+void bvme6000_reset()
+{
+ volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+
+ printk ("\r\n\nCalled bvme6000_reset\r\n"
+ "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r");
+ /* The string of returns is to delay the reset until the whole
+ * message is output. */
+ /* Enable the watchdog, via PIT port C bit 4 */
+
+ pit->pcddr |= 0x10; /* WDOG enable */
+
+ while(1)
+ ;
+}
+
+static void bvme6000_get_model(char *model)
+{
+ /* XXX Need to detect if BVME4000 or BVME6000 */
+ sprintf(model, "BVME6000");
+}
+
+
+/* No hardware options on BVME6000? */
+
+static int bvme6000_get_hardware_list(char *buffer)
+{
+ *buffer = '\0';
+ return 0;
+}
+
+
+__initfunc(void config_bvme6000(void))
+{
+ volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+
+#if 0
+ /* Call bvme6000_set_vectors() so ABORT will work, along with BVMBug
+ * debugger. Note trap_init() will splat the abort vector, but
+ * bvme6000_init_IRQ() will put it back again. Hopefully. */
+
+ bvme6000_set_vectors();
+#endif
+
+ mach_sched_init = bvme6000_sched_init;
+ mach_keyb_init = bvme6000_keyb_init;
+ mach_kbdrate = bvme6000_kbdrate;
+ mach_init_IRQ = bvme6000_init_IRQ;
+ mach_gettimeoffset = bvme6000_gettimeoffset;
+ mach_gettod = bvme6000_gettod;
+ mach_hwclk = bvme6000_hwclk;
+ mach_set_clock_mmss = bvme6000_set_clock_mmss;
+/* mach_mksound = bvme6000_mksound; */
+ mach_reset = bvme6000_reset;
+ mach_free_irq = bvme6000_free_irq;
+ mach_process_int = bvme6000_process_int;
+ mach_get_irq_list = bvme6000_get_irq_list;
+ mach_request_irq = bvme6000_request_irq;
+ enable_irq = bvme6000_enable_irq;
+ disable_irq = bvme6000_disable_irq;
+ mach_get_model = bvme6000_get_model;
+ mach_get_hardware_list = bvme6000_get_hardware_list;
+
+ printk ("Board is %sconfigured as a System Controller\n",
+ *config_reg_ptr & BVME_CONFIG_SW1 ? "" : "not ");
+
+ /* Now do the PIT configuration */
+
+ pit->pgcr = 0x00; /* Unidirectional 8 bit, no handshake for now */
+ pit->psrr = 0x18; /* PIACK and PIRQ fucntions enabled */
+ pit->pacr = 0x00; /* Sub Mode 00, H2 i/p, no DMA */
+ pit->padr = 0x00; /* Just to be tidy! */
+ pit->paddr = 0x00; /* All inputs for now (safest) */
+ pit->pbcr = 0x80; /* Sub Mode 1x, H4 i/p, no DMA */
+ pit->pbdr = 0xbc | (*config_reg_ptr & BVME_CONFIG_SW1 ? 0 : 0x40);
+ /* PRI, SYSCON?, Level3, SCC clks from xtal */
+ pit->pbddr = 0xf3; /* Mostly outputs */
+ pit->pcdr = 0x01; /* PA transceiver disabled */
+ pit->pcddr = 0x03; /* WDOG disable */
+}
+
+
+void bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+ unsigned long *new = (unsigned long *)vectors;
+ unsigned long *old = (unsigned long *)0xf8000000;;
+
+ /* Wait for button release */
+ while (*config_reg_ptr & BVME_ABORT_STATUS)
+ ;
+
+ *(new+4) = *(old+4); /* Illegal instruction */
+ *(new+9) = *(old+9); /* Trace */
+ *(new+47) = *(old+47); /* Trap #15 */
+ *(new+0x1f) = *(old+0x1f); /* ABORT switch */
+}
+
+
+static void bvme6000_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ unsigned char msr = rtc->msr & 0xc0;
+
+ rtc->msr = msr | 0x20; /* Ack the interrupt */
+
+ tick_handler(irq, dev_id, fp);
+}
+
+/*
+ * Set up the RTC timer 1 to mode 2, so T1 output toggles every 5ms
+ * (40000 x 125ns). It will interrupt every 10ms, when T1 goes low.
+ * So, when reading the elapsed time, you should read timer1,
+ * subtract it from 39999, and then add 40000 if T1 is high.
+ * That gives you the number of 125ns ticks in to the 10ms period,
+ * so divide by 8 to get the microsecond result.
+ */
+
+void bvme6000_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ unsigned char msr = rtc->msr & 0xc0;
+
+ rtc->msr = 0; /* Ensure timer registers accessible */
+
+ tick_handler = timer_routine;
+ if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0,
+ "timer", bvme6000_timer_int))
+ panic ("Couldn't register timer int");
+
+ rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */
+ rtc->t1msb = 39999 >> 8;
+ rtc->t1lsb = 39999 & 0xff;
+ rtc->irr_icr1 &= 0xef; /* Route timer 1 to INTR pin */
+ rtc->msr = 0x40; /* Access int.cntrl, etc */
+ rtc->pfr_icr0 = 0x80; /* Just timer 1 ints enabled */
+ rtc->irr_icr1 = 0;
+ rtc->t1cr_omr = 0x0a; /* INTR+T1 active lo, push-pull */
+ rtc->t0cr_rtmr &= 0xdf; /* Stop timers in standby */
+ rtc->msr = 0; /* Access timer 1 control */
+ rtc->t1cr_omr = 0x05; /* Mode 2, ext clk, GO */
+
+ rtc->msr = msr;
+
+ if (request_irq(BVME_IRQ_ABORT, bvme6000_abort_int, 0,
+ "abort", bvme6000_abort_int))
+ panic ("Couldn't register abort int");
+}
+
+
+/* This is always executed with interrupts disabled. */
+
+/*
+ * NOTE: Don't accept any readings within 5us of rollover, as
+ * the T1INT bit may be a little slow getting set. There is also
+ * a fault in the chip, meaning that reads may produce invalid
+ * results...
+ */
+
+unsigned long bvme6000_gettimeoffset (void)
+{
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
+ unsigned char msr = rtc->msr & 0xc0;
+ unsigned char t1int, t1op;
+ unsigned long v = 800000, ov;
+
+ rtc->msr = 0; /* Ensure timer registers accessible */
+
+ do {
+ ov = v;
+ t1int = rtc->msr & 0x20;
+ t1op = pit->pcdr & 0x04;
+ rtc->t1cr_omr |= 0x40; /* Latch timer1 */
+ v = rtc->t1msb << 8; /* Read timer1 */
+ v |= rtc->t1lsb; /* Read timer1 */
+ } while (t1int != (rtc->msr & 0x20) ||
+ t1op != (pit->pcdr & 0x04) ||
+ abs(ov-v) > 80 ||
+ v > 39960);
+
+ v = 39999 - v;
+ if (!t1op) /* If in second half cycle.. */
+ v += 40000;
+ v /= 8; /* Convert ticks to microseconds */
+ if (t1int)
+ v += 10000; /* Int pending, + 10ms */
+ rtc->msr = msr;
+
+ return v;
+}
+
+extern void bvme6000_gettod (int *year, int *mon, int *day, int *hour,
+ int *min, int *sec)
+{
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ unsigned char msr = rtc->msr & 0xc0;
+
+ rtc->msr = 0; /* Ensure clock accessible */
+
+ do { /* Loop until we get a reading with a stable seconds field */
+ *sec = bcd2bin (rtc->bcd_sec);
+ *min = bcd2bin (rtc->bcd_min);
+ *hour = bcd2bin (rtc->bcd_hr);
+ *day = bcd2bin (rtc->bcd_dom);
+ *mon = bcd2bin (rtc->bcd_mth);
+ *year = bcd2bin (rtc->bcd_year);
+ } while (bcd2bin (rtc->bcd_sec) != *sec);
+
+ rtc->msr = msr;
+}
+
+static unsigned char bcd2bin (unsigned char b)
+{
+ return ((b>>4)*10 + (b&15));
+}
+
+static unsigned char bin2bcd (unsigned char b)
+{
+ return (((b/10)*16) + (b%10));
+}
+
+
+/*
+ * Looks like op is non-zero for setting the clock, and zero for
+ * reading the clock.
+ *
+ * struct hwclk_time {
+ * unsigned sec; 0..59
+ * unsigned min; 0..59
+ * unsigned hour; 0..23
+ * unsigned day; 1..31
+ * unsigned mon; 0..11
+ * unsigned year; 00...
+ * int wday; 0..6, 0 is Sunday, -1 means unknown/don't set
+ * };
+ */
+
+int bvme6000_hwclk(int op, struct hwclk_time *t)
+{
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ unsigned char msr = rtc->msr & 0xc0;
+
+ rtc->msr = 0x40; /* Ensure clock and real-time-mode-register
+ * are accessible */
+ if (op)
+ { /* Write.... */
+ rtc->t0cr_rtmr = t->year%4;
+ rtc->bcd_tenms = 0;
+ rtc->bcd_sec = bin2bcd(t->sec);
+ rtc->bcd_min = bin2bcd(t->min);
+ rtc->bcd_hr = bin2bcd(t->hour);
+ rtc->bcd_dom = bin2bcd(t->day);
+ rtc->bcd_mth = bin2bcd(t->mon + 1);
+ rtc->bcd_year = bin2bcd(t->year%100);
+ if (t->wday >= 0)
+ rtc->bcd_dow = bin2bcd(t->wday+1);
+ rtc->t0cr_rtmr = t->year%4 | 0x08;
+ }
+ else
+ { /* Read.... */
+ do {
+ t->sec = bcd2bin(rtc->bcd_sec);
+ t->min = bcd2bin(rtc->bcd_min);
+ t->hour = bcd2bin(rtc->bcd_hr);
+ t->day = bcd2bin(rtc->bcd_dom);
+ t->mon = bcd2bin(rtc->bcd_mth)-1;
+ t->year = bcd2bin(rtc->bcd_year);
+ if (t->year < 70)
+ t->year += 100;
+ t->wday = bcd2bin(rtc->bcd_dow)-1;
+ } while (t->sec != bcd2bin(rtc->bcd_sec));
+ }
+
+ rtc->msr = msr;
+
+ return 0;
+}
+
+/*
+ * Set the minutes and seconds from seconds value 'nowtime'. Fail if
+ * clock is out by > 30 minutes. Logic lifted from atari code.
+ * Algorithm is to wait for the 10ms register to change, and then to
+ * wait a short while, and then set it.
+ */
+
+int bvme6000_set_clock_mmss (unsigned long nowtime)
+{
+ int retval = 0;
+ short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+ unsigned char rtc_minutes, rtc_tenms;
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ unsigned char msr = rtc->msr & 0xc0;
+ unsigned long flags;
+ volatile int i;
+
+ rtc->msr = 0; /* Ensure clock accessible */
+ rtc_minutes = bcd2bin (rtc->bcd_min);
+
+ if ((rtc_minutes < real_minutes
+ ? real_minutes - rtc_minutes
+ : rtc_minutes - real_minutes) < 30)
+ {
+ save_flags(flags);
+ cli();
+ rtc_tenms = rtc->bcd_tenms;
+ while (rtc_tenms == rtc->bcd_tenms)
+ ;
+ for (i = 0; i < 1000; i++)
+ ;
+ rtc->bcd_min = bin2bcd(real_minutes);
+ rtc->bcd_sec = bin2bcd(real_seconds);
+ restore_flags(flags);
+ }
+ else
+ retval = -1;
+
+ rtc->msr = msr;
+
+ return retval;
+}
+
+
+int bvme6000_keyb_init (void)
+{
+ return 0;
+}
+
+/*------------------- Serial console stuff ------------------------*/
+
+static void bvme_scc_write(struct console *co, const char *str, unsigned cnt);
+
+
+void bvme6000_init_console_port (struct console *co, int cflag)
+{
+ co->write = bvme_scc_write;
+}
+
+
+static void scc_delay (void)
+{
+ int n;
+ char i;
+
+ for (n = 0; n < 20; n++)
+ i = *(volatile char *)0;
+}
+
+static void scc_write (char ch)
+{
+ volatile char *p = (volatile char *)BVME_SCC_A_ADDR;
+
+ do {
+ scc_delay();
+ }
+ while (!(*p & 4));
+ scc_delay();
+ *p = 8;
+ scc_delay();
+ *p = ch;
+}
+
+
+static void bvme_scc_write (struct console *co, const char *str, unsigned count)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ while (count--)
+ {
+ if (*str == '\n')
+ scc_write ('\r');
+ scc_write (*str++);
+ }
+ restore_flags(flags);
+}
+
--- /dev/null
+/*
+ * Real Time Clock interface for Linux on the BVME6000
+ *
+ * Based on the PC driver by Paul Gortmaker.
+ */
+
+#define RTC_VERSION "1.00"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
+#include <asm/bvme6000hw.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/setup.h>
+
+/*
+ * We sponge a minor off of the misc major. No need slurping
+ * up another valuable major dev number for this. If you add
+ * an ioctl, make sure you don't conflict with SPARC's RTC
+ * ioctls.
+ */
+
+#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char rtc_status = 0;
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
+ unsigned char msr;
+ unsigned long flags;
+ struct rtc_time wtime;
+
+ switch (cmd) {
+ case RTC_RD_TIME: /* Read the time/date from RTC */
+ {
+ save_flags(flags);
+ cli();
+ /* Ensure clock and real-time-mode-register are accessible */
+ msr = rtc->msr & 0xc0;
+ rtc->msr = 0x40;
+ do {
+ wtime.tm_sec = BCD2BIN(rtc->bcd_sec);
+ wtime.tm_min = BCD2BIN(rtc->bcd_min);
+ wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
+ wtime.tm_mday = BCD2BIN(rtc->bcd_dom);
+ wtime.tm_mon = BCD2BIN(rtc->bcd_mth)-1;
+ wtime.tm_year = BCD2BIN(rtc->bcd_year);
+ if (wtime.tm_year < 70)
+ wtime.tm_year += 100;
+ wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+ } while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec));
+ rtc->msr = msr;
+ restore_flags(flags);
+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
+ -EFAULT : 0;
+ }
+ case RTC_SET_TIME: /* Set the RTC */
+ {
+ unsigned char leap_yr;
+ struct rtc_time rtc_tm;
+
+ if (!suser())
+ return -EACCES;
+
+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+
+ leap_yr = ((!(rtc_tm.tm_year % 4) && (rtc_tm.tm_year % 100)) || !(rtc_tm.tm_year % 400));
+
+ if ((rtc_tm.tm_mon > 12) || (rtc_tm.tm_mday == 0))
+ return -EINVAL;
+
+ if (rtc_tm.tm_mday > (days_in_mo[rtc_tm.tm_mon] + ((rtc_tm.tm_mon == 2) && leap_yr)))
+ return -EINVAL;
+
+ if ((rtc_tm.tm_hour >= 24) || (rtc_tm.tm_min >= 60) || (rtc_tm.tm_sec >= 60))
+ return -EINVAL;
+
+ save_flags(flags);
+ cli();
+ /* Ensure clock and real-time-mode-register are accessible */
+ msr = rtc->msr & 0xc0;
+ rtc->msr = 0x40;
+
+ rtc->t0cr_rtmr = rtc_tm.tm_year%4;
+ rtc->bcd_tenms = 0;
+ rtc->bcd_sec = BIN2BCD(rtc_tm.tm_sec);
+ rtc->bcd_min = BIN2BCD(rtc_tm.tm_min);
+ rtc->bcd_hr = BIN2BCD(rtc_tm.tm_hour);
+ rtc->bcd_dom = BIN2BCD(rtc_tm.tm_mday);
+ rtc->bcd_mth = BIN2BCD(rtc_tm.tm_mon + 1);
+ rtc->bcd_year = BIN2BCD(rtc_tm.tm_year%100);
+ if (rtc_tm.tm_wday >= 0)
+ rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+ rtc->t0cr_rtmr = rtc_tm.tm_year%4 | 0x08;
+
+ rtc->msr = msr;
+ restore_flags(flags);
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * We enforce only one user at a time here with the open/close.
+ * Also clear the previous interrupt data on an open, and clean
+ * up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ if(rtc_status)
+ return -EBUSY;
+
+ rtc_status = 1;
+ return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+ rtc_status = 0;
+ return 0;
+}
+
+/*
+ * The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+ NULL,
+ NULL,
+ NULL, /* No write */
+ NULL, /* No readdir */
+ NULL,
+ rtc_ioctl,
+ NULL, /* No mmap */
+ rtc_open,
+ rtc_release
+};
+
+static struct miscdevice rtc_dev=
+{
+ RTC_MINOR,
+ "rtc",
+ &rtc_fops
+};
+
+__initfunc(int rtc_DP8570A_init(void))
+{
+ if (!MACH_IS_BVME6000)
+ return -ENODEV;
+
+ printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
+ misc_register(&rtc_dev);
+ return 0;
+}
+
endmenu
mainmenu_option next_comment
-comment 'Platform-dependent setup'
+comment 'Platform dependent setup'
bool 'Amiga support' CONFIG_AMIGA
bool 'Atari support' CONFIG_ATARI
fi
fi
bool 'Macintosh support' CONFIG_MAC
+if [ "$CONFIG_MAC" = "y" ]; then
+ define_bool CONFIG_NUBUS y
+fi
bool 'Apollo support' CONFIG_APOLLO
bool 'VME (Motorola and BVM) support' CONFIG_VME
if [ "$CONFIG_VME" = "y" ]; then
bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
-# bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
+ bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
+fi
+bool 'HP9000/300 support' CONFIG_HP300
+if [ "$CONFIG_HP300" = "y" ]; then
+ bool 'DIO bus support' CONFIG_DIO
fi
-
if [ "$CONFIG_PCI" = "y" ]; then
bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
fi
bool 'Advanced processor options' CONFIG_ADVANCED_CPU
if [ "$CONFIG_ADVANCED_CPU" = "y" ]; then
bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
+ bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
fi
endmenu
if [ "$CONFIG_AMIGA" = "y" ]; then
bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
-# bool 'Amiga GSP (TMS340x0) support' CONFIG_AMIGA_GSP
-# if [ "$CONFIG_AMIGA_GSP" = "y" ]; then
-# bool 'DMI Resolver support' CONFIG_GSP_RESOLVER
-# bool 'A2410 support' CONFIG_GSP_A2410
-# fi
fi
if [ "$CONFIG_ATARI" = "y" ]; then
bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
fi
if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
-fi
-endmenu
-
-#
-# Block device driver configuration
-#
-mainmenu_option next_comment
-comment 'Floppy, IDE, and other block devices'
-
-if [ "$CONFIG_AMIGA" = "y" ]; then
- tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
-fi
-if [ "$CONFIG_ATARI" = "y" ]; then
- tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
-fi
-if [ "$CONFIG_MAC" = "y" ]; then
- tristate 'Macintosh IWM floppy support' CONFIG_MAC_FLOPPY
-fi
-#Normal floppy disk support' CONFIG_BLK_DEV_FD
-
-tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
-if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
- dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
- dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
- dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
- dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
- dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
- if [ "$CONFIG_AMIGA" = "y" ]; then
- bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA
- bool ' Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
- fi
- fi
- if [ "$CONFIG_ATARI" = "y" ]; then
- bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
- fi
-fi
-if [ "$CONFIG_AMIGA" = "y" ]; then
- tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
-fi
-if [ "$CONFIG_ATARI" = "y" ]; then
- tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
- if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
- comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
- bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
- dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI
+else
+ if [ "$CONFIG_HP300" = "y" ]; then
+# We have a dedicated heartbeat LED. :-)
+ define_bool CONFIG_HEARTBEAT y
fi
fi
-
-comment 'Additional Block Devices'
-
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
-bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
-if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
- tristate ' Linear (append) mode' CONFIG_MD_LINEAR
- tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED
-fi
-if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
- bool ' Boot support (linear, striped)' CONFIG_MD_BOOT
-fi
-tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
-if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
- bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
-fi
+bool '/proc/hardware support' CONFIG_PROC_HARDWARE
endmenu
+source drivers/block/Config.in
+
if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
fi
bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
bool 'A4091 SCSI support' CONFIG_A4091_SCSI
bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
- bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
+# bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
# bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
fi
+ if [ "$CONFIG_MAC" = "y" ]; then
+ bool ' Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
+ fi
fi
if [ "$CONFIG_ATARI" = "y" ]; then
dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
- bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
- if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
- bool 'Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
+ if [ "$CONFIG_ATARI_SCSI" != "n" ]; then
+ bool ' Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+ bool ' Reset SCSI-devices at boottime' CONFIG_ATARI_SCSI_RESET_BOOT
+ if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
+ bool ' Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
+ fi
fi
fi
if [ "$CONFIG_MAC" = "y" ]; then
bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
+ bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
+fi
+
endmenu
fi
if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
bool 'MVME16x Ethernet support' CONFIG_APRICOT
fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
+ bool 'BVME6000 Ethernet support' CONFIG_APRICOT
+fi
fi
endmenu
tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
fi
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+if [ "$CONFIG_MAC" = "y" ]; then
+ bool 'Mac SCC serial support' CONFIG_MAC_SCC
+fi
+if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
+ tristate 'HP DCA serial support' CONFIG_HPDCA
+fi
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
+ "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" ]; then
if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
- "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
- "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
+ "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
+ "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
+ "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
+ "$CONFIG_HPDCA" = "y" ]; then
bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
fi
fi
-if [ "$CONFIG_MAC" = "y" ]; then
- bool 'Mac SCC serial support' CONFIG_MAC_SCC
-fi
if [ "$CONFIG_VME" = "y" ]; then
define_bool CONFIG_SERIAL_CONSOLE y
- bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
- bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+ if [ "$CONFIG_MVME16x" = "y" ]; then
+ bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
+ bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+ fi
+ if [ "$CONFIG_BVME6000" = "y" ]; then
+ bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC
+ fi
fi
if [ "$CONFIG_APOLLO" = "y" ]; then
bool 'Support for DN serial port (dummy)' CONFIG_SERIAL
bool ' Software Watchdog' CONFIG_SOFT_WATCHDOG
fi
bool 'Support for user misc device modules' CONFIG_UMISC
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o "$CONFIG_MAC" = "y" ]; then
define_bool CONFIG_ABSTRACT_CONSOLE y
fi
if [ "$CONFIG_ATARI" = "y" ]; then
# CONFIG_AMIGA_GSP is not set
# CONFIG_GSP_RESOLVER is not set
# CONFIG_GSP_A2410 is not set
+# CONFIG_HEARTBEAT is not set
+CONFIG_PROC_HARDWARE=y
#
# Block device driver configuration
# CONFIG_A4091_SCSI is not set
# CONFIG_WARPENGINE_SCSI is not set
CONFIG_ATARI_SCSI=y
+# CONFIG_ATARI_SCSI_TOSHIBA_DELAY is not set
+# CONFIG_ATARI_SCSI_RESET_BOOT is not set
#
# Network device support
--- /dev/null
+#
+# Makefile for Linux arch/m68k/hp300 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := hp300.o
+O_OBJS := ksyms.o config.o ints.o time.o reboot.o hil.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+HP300 notes
+-----------
+
+The Linux/HP web page is at <http://www.tazenda.demon.co.uk/phil/linux-hp/>
+
+Currently only 9000/340 machines have been tested. Any amount of RAM should
+work now but I've only tried 16MB and 12MB.
+
+The serial console is probably broken at the moment but the Topcat/HIL keyboard
+combination seems to work for me. Your mileage may vary.
+
+The LANCE driver works after a fashion but only if you reset the chip before
+every packet. This doesn't make for very speedy operation.
+
--- /dev/null
+/*
+ * linux/arch/m68k/hp300/config.c
+ *
+ * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ * This file contains the HP300-specific initialisation code. It gets
+ * called by setup.c.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <asm/machdep.h>
+#include <asm/blinken.h>
+#include <asm/io.h> /* readb() and writeb() */
+#include <asm/hwtest.h> /* hwreg_present() */
+
+#include "ints.h"
+#include "time.h"
+
+extern void hp300_reset(void);
+extern void hp300_hil_init(void);
+
+#ifdef CONFIG_HEARTBEAT
+static void hp300_pulse(int x)
+{
+ if (x)
+ blinken_leds(0xfe);
+ else
+ blinken_leds(0xff);
+}
+#endif
+
+static int hp300_kbdrate(struct kbd_repeat *k)
+{
+ return 0;
+}
+
+static void hp300_kbd_leds(unsigned int leds)
+{
+}
+
+__initfunc(void config_hp300(void))
+{
+ mach_sched_init = hp300_sched_init;
+ mach_keyb_init = hp300_hil_init;
+ mach_kbdrate = hp300_kbdrate;
+ mach_kbd_leds = hp300_kbd_leds;
+ mach_init_IRQ = hp300_init_IRQ;
+ mach_request_irq = hp300_request_irq;
+ mach_free_irq = hp300_free_irq;
+#if 0
+ mach_get_model = hp300_get_model;
+ mach_get_irq_list = hp300_get_irq_list;
+#endif
+ mach_gettimeoffset = hp300_gettimeoffset;
+#if 0
+ mach_gettod = hp300_gettod;
+#endif
+ mach_reset = hp300_reset;
+#ifdef CONFIG_HEARTBEAT
+ mach_heartbeat = hp300_pulse;
+#endif
+#ifdef CONFIG_FB
+ conswitchp = &fb_con;
+#endif
+ mach_max_dma_address = 0xffffffff;
+}
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void kbd_reset_setup(char *str, int *ints))
+{
+}
--- /dev/null
+/*
+ * linux/arch/m68k/hp300/hil.c
+ *
+ * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ * HP300 Human Interface Loop driver. This handles the keyboard and mouse.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/keyboard.h>
+#include <linux/kbd_ll.h>
+#include <asm/io.h>
+#include <asm/hwtest.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#define HILBASE 0xf0428000
+#define HIL_DATA 0x1
+#define HIL_CMD 0x3
+
+#define HIL_BUSY 0x02
+#define HIL_DATA_RDY 0x01
+
+#define hil_busy() (readb(HILBASE + HIL_CMD) & HIL_BUSY)
+#define hil_data_available() (readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
+#define hil_status() (readb(HILBASE + HIL_CMD))
+#define hil_command(x) do { writeb((x), HILBASE + HIL_CMD); } while (0)
+#define hil_read_data() (readb(HILBASE + HIL_DATA))
+#define hil_write_data(x) do { writeb((x), HILBASE + HIL_DATA); } while (0)
+
+#define HIL_SETARD 0xA0 /* set auto-repeat delay */
+#define HIL_SETARR 0xA2 /* set auto-repeat rate */
+#define HIL_SETTONE 0xA3 /* set tone generator */
+#define HIL_CNMT 0xB2 /* clear nmi */
+#define HIL_INTON 0x5C /* Turn on interrupts. */
+#define HIL_INTOFF 0x5D /* Turn off interrupts. */
+#define HIL_TRIGGER 0xC5 /* trigger command */
+#define HIL_STARTCMD 0xE0 /* start loop command */
+#define HIL_TIMEOUT 0xFE /* timeout */
+#define HIL_READTIME 0x13 /* Read real time register */
+
+#define HIL_READBUSY 0x02 /* internal "busy" register */
+#define HIL_READKBDLANG 0x12 /* read keyboard language code */
+#define HIL_READKBDSADR 0xF9
+#define HIL_WRITEKBDSADR 0xE9
+#define HIL_READLPSTAT 0xFA
+#define HIL_WRITELPSTAT 0xEA
+#define HIL_READLPCTRL 0xFB
+#define HIL_WRITELPCTRL 0xEB
+
+#define HIL_IRQ 1
+
+static u_short hp_plain_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf01b, 0xf20e, 0xf700, 0xf700, 0xf700, 0xf702, 0xf036,
+ 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+ 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+ 0xfb62, 0xfb76, 0xf063, 0xfb78, 0xfb7a, 0xf702, 0xfb61, 0xfb73,
+ 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+ 0xfb68, 0xfb67, 0xfb66, 0xfb64, 0xfb73, 0xfb61, 0xfb63, 0xfb76,
+ 0xfb75, 0xfb79, 0xfb74, 0xfb72, 0xfb65, 0xfb77, 0xfb71, 0xf200,
+ 0xf037, 0xf036, 0xf035, 0xf034, 0xf033, 0xf032, 0xf031, 0xf104,
+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+ 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+ 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf038, 0xf039, 0xf030, 0xf200, 0xf200, 0xf008, 0xf200, 0xf200,
+ 0xfb69, 0xfb6f, 0xfb70, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+ 0xfb6a, 0xfb6b, 0xfb6c, 0xf305, 0xf306, 0xf00d, 0xf302, 0xf303,
+ 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xfb6e, 0xf020, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short hp_shift_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf01b, 0xf20e, 0xf700, 0xf700, 0xf700, 0xf002, 0xf036,
+ 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+ 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+ 0xfb62, 0xfb76, 0xf063, 0xfb78, 0xfb7a, 0xf702, 0xfb61, 0xfb73,
+ 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+ 0xfb68, 0xfb67, 0xfb66, 0xfb64, 0xfb73, 0xfb61, 0xfb63, 0xfb76,
+ 0xfb75, 0xfb79, 0xfb74, 0xfb72, 0xfb65, 0xfb77, 0xfb71, 0xf200,
+ 0xf037, 0xf036, 0xf035, 0xf034, 0xf033, 0xf032, 0xf031, 0xf104,
+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+ 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+ 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf038, 0xf039, 0xf030, 0xf200, 0xf200, 0xf008, 0xf200, 0xf200,
+ 0xfb69, 0xfb6f, 0xfb70, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+ 0xfb6a, 0xfb6b, 0xfb6c, 0xf305, 0xf306, 0xf00d, 0xf302, 0xf303,
+ 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xfb6e, 0xf020, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+static u_short hp_ctrl_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+ 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+ 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+ 0xf00f, 0xf010, 0xf003, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
+ 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+ 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
+ 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200,
+ 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+ 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+ 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+ 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+ 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+struct {
+ unsigned char s, c;
+ int valid;
+} hil_last;
+
+#define hil_getlast(s,c) do { s = hil_last.s; c = hil_last.c; hil_last.valid = 0; } while (0)
+
+struct {
+ unsigned char data[16];
+ unsigned int ptr;
+} poll;
+
+unsigned char curdev = 0;
+
+static void poll_finished(void)
+{
+ switch (poll.data[0])
+ {
+ case 0x40:
+ {
+ unsigned char scode = (poll.data[1] >> 1) | ((poll.data[1] & 1)?0x80:0);
+#if 0
+ if (scode & 0x80)
+ printk("[%02x]", scode & 0x7f);
+#endif
+ handle_scancode(scode);
+ }
+ break;
+ }
+ curdev = 0;
+}
+
+static inline void handle_status(unsigned char s, unsigned char c)
+{
+ if (c & 0x8) {
+ /* End of block */
+ if (c & 0x10)
+ poll_finished();
+ } else {
+ if (c & 0x10) {
+ if (curdev)
+ poll_finished(); /* just in case */
+ curdev = c & 7;
+ poll.ptr = 0;
+ }
+ }
+}
+
+static inline void handle_data(unsigned char s, unsigned char c)
+{
+ if (curdev)
+ poll.data[poll.ptr++] = c;
+}
+
+/*
+ * Handle HIL interrupts.
+ */
+
+static void hil_interrupt(int irq, void *handle, struct pt_regs *regs)
+{
+ unsigned char s, c;
+ s = hil_status(); c = hil_read_data();
+ switch (s >> 4)
+ {
+ case 0x5:
+ handle_status(s, c);
+ break;
+ case 0x6:
+ handle_data(s, c);
+ break;
+ case 0x4:
+ hil_last.s = s;
+ hil_last.c = c;
+ mb();
+ hil_last.valid = 1;
+ break;
+ }
+}
+
+/*
+ * Send a command to the HIL
+ */
+
+static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
+{
+ unsigned long flags;
+ save_flags(flags); cli();
+ while (hil_busy());
+ hil_command(cmd);
+ while (len--) {
+ while (hil_busy());
+ hil_write_data(*(data++));
+ }
+ restore_flags(flags);
+}
+
+/*
+ * Initialise HIL.
+ */
+
+__initfunc(void hp300_hil_init(void))
+{
+ unsigned char s, c, kbid;
+ unsigned int n = 0;
+
+ memcpy(key_maps[0], hp_plain_map, sizeof(plain_map));
+ memcpy(key_maps[1], hp_shift_map, sizeof(plain_map));
+ memcpy(key_maps[4], hp_ctrl_map, sizeof(plain_map));
+
+ if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
+ return; /* maybe this can happen */
+
+ request_irq(HIL_IRQ, hil_interrupt, 0, "HIL", NULL);
+
+ /* Turn on interrupts */
+ hil_do(HIL_INTON, NULL, 0);
+
+ /* Look for keyboards */
+ hil_do(HIL_READKBDSADR, NULL, 0);
+ while (!hil_last.valid) {
+ if (n++ > 1000) {
+ printk("HIL: timed out, assuming no keyboard present.\n");
+ return;
+ }
+ mb();
+ }
+ hil_getlast(s, c);
+ if (c == 0) {
+ printk("HIL: no keyboard present.\n");
+ return;
+ }
+ for (kbid = 0; (kbid < 8) && ((c & (1<<kbid)) == 0); kbid++);
+ printk("HIL: keyboard found at id %d\n", kbid);
+ /* set it to raw mode */
+ c = 0;
+ hil_do(HIL_WRITEKBDSADR, &c, 1);
+}
--- /dev/null
+/*
+ * linux/arch/m68k/hp300/ints.c
+ *
+ * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ * This file contains the HP300-specific interrupt handling. There
+ * isn't much here -- we only use the autovector interrupts and at the
+ * moment everything difficult is handled by the generic code.
+ */
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include "ints.h"
+
+static void hp300_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
+{
+ extern void hp300_reset(void);
+ printk("RESET pressed - self destruct sequence initiated.\n");
+ hp300_reset();
+}
+
+int hp300_request_irq(unsigned int irq,
+ void (*handler) (int, void *, struct pt_regs *),
+ unsigned long flags, const char *devname, void *dev_id)
+{
+ return sys_request_irq(irq, handler, flags, devname, dev_id);
+}
+
+void hp300_free_irq(unsigned int irq, void *dev_id)
+{
+ sys_free_irq(irq, dev_id);
+}
+
+__initfunc(void hp300_init_IRQ(void))
+{
+ /* IPL6 - NMI (keyboard reset) */
+ sys_request_irq(7, hp300_nmi_handler, IRQ_FLG_STD, "NMI", hp300_nmi_handler);
+}
--- /dev/null
+extern void hp300_init_IRQ(void);
+extern void (*hp300_handlers[8])(int, void *, struct pt_regs *);
+extern void hp300_free_irq(unsigned int irq, void *dev_id);
+extern int hp300_request_irq(unsigned int irq,
+ void (*handler) (int, void *, struct pt_regs *),
+ unsigned long flags, const char *devname, void *dev_id);
--- /dev/null
+/*
+ * linux/arch/m68k/hp300/ksyms.c
+ *
+ * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ * This file contains the HP300-specific kernel symbols. None yet. :-)
+ */
+
+#include <linux/module.h>
--- /dev/null
+/*
+ * linux/arch/m68k/hp300/reboot.S
+ *
+ * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ * Do the dirty work of rebooting the machine. Basically we need to undo all the
+ * good stuff that head.S did when we started up. The caches and MMU must be
+ * disabled and then we jump back to the PROM. This is a bit gruesome but we put
+ * a brave face on it.
+ */
+
+/* XXX Doesn't work yet. Not sure why and can't be bothered to fix it at the moment. */
+
+ .globl hp300_reset
+hp300_reset:
+ .chip 68030
+ oriw #0x0700,%sr /* cli() */
+ movel hp300_phys_ram_base, %d1
+ movel #0, %d0
+ movec %d0, %vbr /* reset vector table */
+ lea zero, %a0
+ lea 1f, %a1
+ add %d1, %a0
+ add %d1, %a1
+ pmove %tc, %a0@
+ bclr #7, %a0@
+ pmove %a0@, %tc /* goodbye MMU */
+ jmp %a1@
+1: movel #0x808, %d0
+ movec %d0, %cacr /* cache off */
+ moveb #0, 0x1ffff
+ movel #0x1a4, %a0
+ jmp %a0@
+
+zero: .quad 0
--- /dev/null
+/*
+ * linux/arch/m68k/hp300/time.c
+ *
+ * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
+ *
+ * This file contains the HP300-specific time handling code.
+ */
+
+#include <linux/config.h>
+#include <asm/ptrace.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include "ints.h"
+
+/* Clock hardware definitions */
+
+#define CLOCKBASE 0xf05f8000
+
+#define CLKCR1 0x1
+#define CLKCR2 0x3
+#define CLKCR3 CLKCR1
+#define CLKSR CLKCR2
+#define CLKMSB1 0x5
+#define CLKMSB2 0x9
+#define CLKMSB3 0xD
+
+unsigned long hp300_gettimeoffset (void)
+{
+ return 0L;
+}
+
+static void hp300_tick(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long tmp;
+ void (*vector)(int, void *, struct pt_regs *) = dev_id;
+ readb(CLOCKBASE + CLKSR);
+ asm volatile ("movpw %1@(5),%0" : "=r" (tmp) : "a" (CLOCKBASE));
+ vector(irq, NULL, regs);
+}
+
+__initfunc(void hp300_sched_init(void (*vector)(int, void *, struct pt_regs *)))
+{
+ unsigned int intval = (10000 / 4) - 1;
+
+ writeb(0x1, CLOCKBASE + CLKCR2); /* select CR1 */
+ writeb(0x1, CLOCKBASE + CLKCR1); /* reset */
+
+ asm volatile(" movpw %0,%1@(5)" : : "d" (intval), "a" (CLOCKBASE));
+
+ sys_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector);
+
+ writeb(0x1, CLOCKBASE + CLKCR2); /* select CR1 */
+ writeb(0x40, CLOCKBASE + CLKCR1); /* enable irq */
+}
+
--- /dev/null
+extern void hp300_sched_init(void (*vector)(int, void *, struct pt_regs *));
+extern unsigned long hp300_gettimeoffset (void);
+
+
* been removed in this version.
*/
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#define GB (1024*MB)
#define MAJOR_REV 0
-#define MINOR_REV 0
+#define MINOR_REV 1
/*
* Base addresses of the PCI memory and I/O areas on the Hades.
#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2)
-__initfunc(static void layout_dev(struct pci_dev *dev))
+__initfunc(static void layout_dev(struct pci_dev *dev, unsigned long pci_mem_base,
+ unsigned long pci_io_base))
{
struct pci_bus *bus;
unsigned short cmd;
unsigned int base, mask, size, reg;
unsigned int alignto;
+ int i;
/*
* Skip video cards for the time being.
bus = dev->bus;
pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
- for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4)
+ for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++)
{
/*
* Figure out how much space and of what type this
if (!base)
{
/* this base-address register is unused */
+ dev->base_address[i] = 0;
continue;
}
io_base = base + size;
pcibios_write_config_dword(bus->number, dev->devfn,
reg, base | 0x1);
+ dev->base_address[i] = (pci_io_base + base) | 1;
DBG_DEVS(("layout_dev: IO address: %lX\n", base));
}
else
mem_base = base + size;
pcibios_write_config_dword(bus->number, dev->devfn,
reg, base);
+ dev->base_address[i] = pci_mem_base + base;
}
}
bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
}
-__initfunc(static void layout_bus(struct pci_bus *bus))
+__initfunc(static void layout_bus(struct pci_bus *bus, unsigned long pci_mem_base,
+ unsigned long pci_io_base))
{
struct pci_dev *dev;
for (dev = bus->devices; dev; dev = dev->sibling)
{
if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
- layout_dev(dev);
+ layout_dev(dev, pci_mem_base, pci_io_base);
}
}
return 0;
}
-__initfunc(unsigned long pcibios_init(unsigned long mem_start,
- unsigned long mem_end))
+__initfunc(void pcibios_init(void))
{
printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
printk("...NOT modifying existing PCI configuration\n");
#endif
- return mem_start;
+ pci_mem_base = 0x80000000;
+ pci_io_base = 0xB0000000;
}
/*
}
}
-__initfunc(unsigned long pcibios_fixup(unsigned long mem_start,
- unsigned long mem_end))
+__initfunc(void pcibios_fixup(void))
{
#if PCI_MODIFY
+ unsigned long orig_mem_base, orig_io_base;
+
+ orig_mem_base = pci_mem_base;
+ orig_io_base = pci_io_base;
+ pci_mem_base = 0;
+ pci_io_base = 0;
+
/*
* Scan the tree, allocating PCI memory and I/O space.
*/
- layout_bus(&pci_root);
-#endif
+ layout_bus(&pci_root, orig_mem_base, orig_io_base);
- pci_mem_base = 0x80000000;
- pci_io_base = 0xB0000000;
+ pci_mem_base = orig_mem_base;
+ pci_io_base = orig_io_base;
+#endif
/*
* Now is the time to do all those dirty little deeds...
*/
hades_fixup();
+}
- return mem_start;
+__initfunc(char *pcibios_setup(char *str))
+{
+ return str;
}
#endif /* CONFIG_PCI */
.long SYMBOL_NAME(sys_pread) /* 180 */
.long SYMBOL_NAME(sys_pwrite)
.long SYMBOL_NAME(sys_lchown);
+ .long SYMBOL_NAME(sys_getcwd)
+ .long SYMBOL_NAME(sys_capget)
+ .long SYMBOL_NAME(sys_capset) /* 185 */
.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
.long SYMBOL_NAME(sys_ni_syscall)
.endr
** 95/11/18 Richard Hirst: Added MVME166 support
** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
** Magnum- and FX-alternate ram
+** 98/04/25 Phil Blundell: added HP300 support
**
** This file is subject to the terms and conditions of the GNU General Public
** License. See the file README.legal in the main directory of this archive
#include <asm/pgtable.h>
.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
-.globl SYMBOL_NAME(availmem), SYMBOL_NAME(mvme_bdid_ptr)
+.globl SYMBOL_NAME(availmem)
.globl SYMBOL_NAME(m68k_pgtable_cachemode)
.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
+#if defined(CONFIG_MVME16x)
+.globl SYMBOL_NAME(mvme_bdid_ptr)
+#endif
+
+/*
+ * Added m68k_supervisor_cachemode for 68060 boards where some drivers
+ * need writethrough caching for supervisor accesses. Drivers known to
+ * be effected are 53c7xx.c and apricot.c (when used on VME boards).
+ * Richard Hirst.
+ */
+
+#ifdef CONFIG_060_WRITETHROUGH
+.globl SYMBOL_NAME(m68k_supervisor_cachemode)
+#endif
+
D6B_0460 = 16 /* indicates 680[46]0 in d6 */
D6B_060 = 17 /* indicates 68060 in d6 */
D6F_040 = 1<<D6B_0460
#define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
#define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
+#define is_not_bvme6000(lab) moveq &MACH_BVME6000,%d7; cmpl %d4,%d7; jne lab
+#define is_not_hp300(lab) moveq &MACH_HP300,%d7 ; cmpl %d4,%d7; jne lab
#define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
#define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
#define is_060(lab) btst &D6B_060,%d6; jne lab
#define is_not_060(lab) btst &D6B_060,%d6; jeq lab
+/* On the HP300 we use the on-board LEDs for debug output before
+ the console is running. Writing a 1 bit turns the corresponding LED
+ _off_ - on the 340 bit 7 is towards the back panel of the machine. */
+#ifdef CONFIG_HP300
+#define leds(x) is_not_hp300(42f) ; moveb #(x),%d7 ; jbsr Lset_leds; 42:
+#else
+#define leds(x)
+#endif
+
.text
ENTRY(_stext)
/*
.long MACH_AMIGA, AMIGA_BOOTI_VERSION
.long MACH_ATARI, ATARI_BOOTI_VERSION
.long MACH_MVME16x, MVME16x_BOOTI_VERSION
+ .long MACH_BVME6000, BVME6000_BOOTI_VERSION
.long 0
1: jra SYMBOL_NAME(_start)
movew %d6,%d0
movel %d0,%a0@ /* save cache mode for page tables */
+ /*
+ * If this is a 68060 board using drivers with cache coherency
+ * problems, then supervisor memory accesses need to be write-through
+ * also; otherwise, we want copyback.
+ */
+
+#if defined(CONFIG_060_WRITETHROUGH)
+ is_not_060(Lset_norm)
+ jra 1f
+Lset_norm:
+ move.w #_PAGE_CACHE040,%d0
+1:
+ lea %pc@(SYMBOL_NAME(m68k_supervisor_cachemode)),%a0
+ movel %d0,%a0@
+#endif
+
/*
* raise interrupt level
*/
movel %a3,%a0
movel %d5,%a1
- addw #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+#if defined(CONFIG_060_WRITETHROUGH)
+ addw #_PAGE_GLOBAL040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+ addl m68k_supervisor_cachemode,%a1
+#else
+ addw #_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT+_PAGE_ACCESSED,%a1
+#endif
movew #(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1
movel #PAGESIZE,%d2
1: movel %a1,%a0@+
* of %a2 are forgotten.
*/
Lnot040:
+
+ leds(0x4)
+
/*
* Do any machine specific page table initializations.
*/
Lnotatari:
#endif
+#ifdef CONFIG_HP300
+ is_not_hp300(Lnothp300)
+
+/* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx)
+ by mapping 32MB from 0xf0xxxxxx -> 0x00xxxxxx) using an 030 early
+ termination page descriptor. The ROM mapping is needed because the LEDs
+ are mapped there too. */
+
+ movel #_PAGE_NOCACHE030+_PAGE_PRESENT+_PAGE_ACCESSED,%d0
+ movel %d0,%a5@(0x78<<2)
+
+Lnothp300:
+
+#endif
+
#if defined(CONFIG_MVME16x)
is_not_mvme16x(Lnot16x)
Lnot16x:
#endif
+#if defined(CONFIG_BVME6000)
+ is_not_bvme6000(Lnotbvm)
+
+ /*
+ * On BVME6000 we have already created kernel page tables for
+ * 4MB of RAM at address 0, so now need to do a transparent
+ * mapping of the top of memory space. Make it 0.5GByte for now.
+ */
+
+ movel #0xe01f0000,%d2 /* logical address base */
+ orw #0xa040,%d2 /* add in magic bits */
+ .long 0x4e7b2005 /* movec d2,ittr1 */
+ .long 0x4e7b2007 /* movec d2,dttr1 */
+ .long 0x4e7b2004 /* movec d2,ittr0 */
+ .long 0x4e7b2006 /* movec d2,dttr0 */
+
+Lnotbvm:
+#endif
+
/*
* Setup a transparent mapping of the physical memory we are executing in.
*
*/
Lmapphys:
putc('J')
+ leds(0x8)
#ifdef CONFIG_AMIGA
is_not_amiga(Lmapphysnotamiga)
#endif
+#if defined(CONFIG_HP300)
+ is_not_hp300(Lmapphysnothp300)
+
+/*
+ * Physical RAM is at 0xff000000. We want to map the kernel at 0x00000000.
+ * In order to avoid disaster when we enable the MMU we need to make a
+ * transparent mapping of the RAM we're executing out of as well.
+ */
+ /*
+ * save physaddr of phys mem in register a3
+ */
+
+ .chip 68030
+ lea %pc@(Lmmu),%a3
+ movel %d5,%d0
+ andl #0xff000000,%d0 /* logical address base */
+ orw #TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
+ movel %d0,%a3@
+ pmove %a3@,%tt0
+ /* no limit, 4byte descriptors */
+ movel #0x80000002,%a3@
+ movel %a5,%a3@(4)
+ pmove %a3@,%srp
+ pmove %a3@,%crp
+ pflusha
+ /*
+ * enable,super root enable,4096 byte pages,7 bit root index,
+ * 7 bit pointer index, 6 bit page table index.
+ */
+ movel #0x82c07760,%a3@
+ pmove %a3@,%tc /* enable the MMU */
+ jmp 1f
+1:
+ .chip 68k
+
+ /*
+ * Fix up the custom register to point to the new location of the LEDs.
+ */
+ lea %pc@(Lcustom),%a1
+ movel #0xf0000000,%a1@
+
+ /*
+ * Energise the FPU and caches.
+ */
+ orl #0x64, 0xf05f400c
+
+Lmapphysnothp300:
+
+#endif
+
+#if defined(CONFIG_BVME6000)
+ is_not_bvme6000(Lmapphysnotbvm)
+ /*
+ * save physaddr of phys mem in register a3
+ */
+ moveq #'L',%d7
+ jbsr Lserial_putc
+
+ .word 0xf4d8 /* CINVA I/D */
+ .word 0xf518 /* pflusha */
+ .long 0x4e7bd807 /* movec a5,srp */
+ .long 0x4e7bd806 /* movec a5,urp */
+ movel #(TC_ENABLE+TC_PAGE4K),%d0
+ /*
+ * this value is also ok for the 68060, we don`t use the cache
+ * mode/protection defaults
+ */
+ .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */
+ jra LdoneMMUenable /* branch to continuation of startup */
+
+Lmapphysnotbvm:
+
+#endif
+
LdoneMMUenable:
/*
*/
putc('M')
+ leds(0x10)
/*
* d5 contains physaddr of kernel start
/* jump to the kernel start */
putr()
+ leds(0x55)
subl %a6,%a6 /* clear a6 for gdb */
jbsr SYMBOL_NAME(start_kernel)
#endif
#endif
+#if defined (CONFIG_BVME6000)
+BVME_SCC_CTRL_A = 0xffb0000b
+BVME_SCC_DATA_A = 0xffb0000f
+#endif
+
/*
* Serial port output support.
*/
9:
rts
+#ifdef CONFIG_HP300
+/* Set LEDs to %d7 */
+ .even
+Lset_leds:
+ moveml %a0/%a1,%sp@-
+ movel %pc@(Lcustom),%a1
+ moveb %d7,%a1@(0x1ffff)
+ moveml %sp@+,%a0/%a1
+ rts
+#endif
+
/*
* Output character in d7 on serial port.
* d7 thrashed.
jne 2f
moveb %d7,%sp@-
.long 0x4e4f0020
+ jra 9f
+2:
+#endif
+#ifdef CONFIG_BVME6000
+ cmpil #MACH_BVME6000,%d4
+ jne 2f
+1: btst #2,BVME_SCC_CTRL_A
+ jeq 1b
+ moveb %d7,BVME_SCC_DATA_A
+ jra 9f
2:
#endif
#ifdef CONFIG_AMIGA
.long 0
SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
.long 0
+#ifdef CONFIG_060_WRITETHROUGH
+SYMBOL_NAME_LABEL(m68k_supervisor_cachemode)
+ .long 0
+#endif
+#if defined(CONFIG_MVME16x)
SYMBOL_NAME_LABEL(mvme_bdid_ptr)
.long 0
+#endif
#include <linux/errno.h>
#include <linux/init.h>
+#include <asm/setup.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/traps.h>
asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
{
- if (vec >= VEC_INT1 && vec <= VEC_INT7) {
+ if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
vec -= VEC_SPUR;
kstat.irqs[0][vec]++;
irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
-
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
goto out;
child->flags |= PF_PTRACED;
if (child->p_pptr != current) {
+ unsigned long flags;
+
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
}
send_sig(SIGSTOP, child, 1);
ret = 0;
}
case PTRACE_DETACH: { /* detach a process that was attached. */
+ unsigned long flags;
long tmp;
ret = -EIO;
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
child->exit_code = data;
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
/* make sure the single step bit is not set. */
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
put_reg(child, PT_SR, tmp);
extern void config_sun3(void);
extern void config_apollo(void);
extern void config_mvme16x(void);
+extern void config_bmve6000(void);
+extern void config_hp300(void);
#define MASK_256K 0xfffc0000
case MACH_MVME16x:
config_mvme16x();
break;
+#endif
+#ifdef CONFIG_BVME6000
+ case MACH_BVME6000:
+ config_bvme6000();
+ break;
+#endif
+#ifdef CONFIG_HP300
+ case MACH_HP300:
+ config_hp300();
+ break;
#endif
default:
panic ("No configuration setup");
do_exit(SIGSEGV);
}
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+ switch (regs->d0) {
+ case -ERESTARTNOHAND:
+ if (!has_handler)
+ goto do_restart;
+ regs->d0 = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+ regs->d0 = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ do_restart:
+ regs->d0 = regs->orig_d0;
+ regs->pc -= 2;
+ break;
+ }
+}
+
/*
* OK, we're invoking a handler
*/
sigset_t *oldset, struct pt_regs *regs)
{
/* are we from a system call? */
- if (regs->orig_d0 >= 0) {
+ if (regs->orig_d0 >= 0)
/* If so, check system call restarting.. */
- switch (regs->d0) {
- case -ERESTARTNOHAND:
- regs->d0 = -EINTR;
- break;
-
- case -ERESTARTSYS:
- if (!(ka->sa.sa_flags & SA_RESTART)) {
- regs->d0 = -EINTR;
- break;
- }
- /* fallthrough */
- case -ERESTARTNOINTR:
- regs->d0 = regs->orig_d0;
- regs->pc -= 2;
- }
- }
+ handle_restart(regs, ka, 1);
/* set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
/* Did we come from a system call? */
if (regs->orig_d0 >= 0) {
- /* Restart the system call */
- if (regs->d0 == -ERESTARTNOHAND ||
- regs->d0 == -ERESTARTSYS ||
- regs->d0 == -ERESTARTNOINTR) {
- regs->d0 = regs->orig_d0;
- regs->pc -= 2;
- }
+ /* Restart the system call the same way as
+ if the process were not traced. */
+ struct k_sigaction *ka =
+ ¤t->sig->action[signr-1];
+ int has_handler =
+ (ka->sa.sa_handler != SIG_IGN &&
+ ka->sa.sa_handler != SIG_DFL);
+ handle_restart(regs, ka, has_handler);
}
notify_parent(current, SIGCHLD);
schedule();
}
/* Did we come from a system call? */
- if (regs->orig_d0 >= 0) {
+ if (regs->orig_d0 >= 0)
/* Restart the system call - no handlers present */
- if (regs->d0 == -ERESTARTNOHAND ||
- regs->d0 == -ERESTARTSYS ||
- regs->d0 == -ERESTARTNOINTR) {
- regs->d0 = regs->orig_d0;
- regs->pc -= 2;
- }
- }
+ handle_restart(regs, NULL, 0);
/* If we are about to discard some frame stuff we must copy
over the remaining frame. */
if (!(a.flags & MAP_ANONYMOUS)) {
error = -EBADF;
- if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd]))
+ file = fget(a.fd);
+ if (!file)
goto out;
}
a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+ if (file)
+ fput(file);
out:
unlock_kernel();
return error;
EXTRA_CFLAGS := -Wa,-m68020
O_TARGET := mac.o
-O_OBJS := config.o ksyms.o bootparse.o macints.o via6522.o \
+O_OBJS := config.o bootparse.o macints.o via6522.o \
mackeyb.o adb-bus.o macboing.o debug.o
+OX_OBJS := mac_ksyms.o
include $(TOPDIR)/Rules.make
static int status = ST_IDLE|TREQ;
static int last_status;
+
+static int driver_running = 0;
+
/*static int adb_delay;*/
int in_keybinit = 1;
static void adb_hw_setup_IIsi(void);
/*
- * Misc. defines for testing
+ * debug level 10 required for ADB logging (should be && debug_adb, ideally)
*/
extern int console_loglevel;
+/*
+ * Misc. defines for testing - should go to header :-(
+ */
+
#define ADBDEBUG_STATUS (1)
#define ADBDEBUG_STATE (2)
#define ADBDEBUG_READ (4)
#define ADBDEBUG_IISI (8192)
-#define DEBUG_ADB
+/*#define DEBUG_ADB*/
#ifdef DEBUG_ADB
#define ADBDEBUG (ADBDEBUG_INPUT | ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST)
void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
{
int x, adbdir;
+ unsigned long flags;
struct adb_request *req;
last_status = status;
+ /* prevent races due to SCSI enabling ints */
+ save_flags(flags);
+ cli();
+
+ if (driver_running) {
+ restore_flags(flags);
+ return;
+ }
+
+ driver_running = 1;
+
#ifdef USE_ORIG
status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
#else
adb_state, status, last_status, adbdir);
#endif
-
switch (adb_state)
{
case idle:
printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
#endif
}
+ /* reset mutex and interrupts */
+ driver_running = 0;
+ restore_flags(flags);
}
/*
#include "via6522.h"
-/* old bootinfo stuff */
+/* Mac bootinfo struct */
struct mac_booter_data mac_bi_data = {0,};
int mac_bisize = sizeof mac_bi_data;
-struct compat_bootinfo compat_boot_info ={0,};
-int compat_bisize = sizeof compat_boot_info;
-
-int compat_bi = 0;
-
-/* New bootinfo stuff */
+/* New m68k bootinfo stuff and videobase */
extern int m68k_num_memory;
extern struct mem_info m68k_memory[NUM_MEMINFO];
void *mac_env; /* Loaded by the boot asm */
-/* The locgial video addr. determined by head.S - testing */
+/* The logical video addr. determined by head.S - testing */
extern unsigned long mac_videobase;
/* The phys. video addr. - might be bogus on some machines */
extern void mac_debug_init(void);
#ifdef CONFIG_MAGIC_SYSRQ
+
+/* XXX FIXME: Atari scancodes still */
static char mac_sysrq_xlate[128] =
- "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
- "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
- "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
- "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
+ "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
"\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
"\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
- "\000\000\000()/*789456123" /* 0x60 - 0x6f */
+ "\000\000\000()/*789456123" /* 0x60 - 0x6f */
"0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */
#endif
extern void (*kd_mksound)(unsigned int, unsigned int);
-void mac_get_model(char *str)
-{
- strcpy(str,"Macintosh");
-}
+static void mac_get_model(char *str);
void mac_bang(int irq, void *vector, struct pt_regs *p)
{
extern int console_loglevel;
+/*
+ * This function translates the boot timeval into a proper date, to initialize
+ * the system time.
+ * Known problem: off by one after Feb. 27 on leap years
+ */
+
void mac_gettod (int *yearp, int *monp, int *dayp,
int *hourp, int *minp, int *secp)
{
unsigned long time;
int leap, oldleap, isleap;
- int mon_days[14] = { -1, 31, 27, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
+ int mon_days[14] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */
-#if 0
- printk("mac_gettod: boottime 0x%lx gmtbias %ld \n",
- mac_bi_data.boottime, mac_bi_data.gmtbias);
-#endif
-
*minp = time / 60;
*secp = time - (*minp * 60);
time = *minp; /* minutes now */
/* for leap day calculation */
*yearp = (time / 365) + 1970; /* approx. year */
- /* leap year calculation - there's an easier way, I bet */
+ /* leap year calculation - there's an easier way, I bet. And it's broken :-( */
/* calculate leap days up to previous year */
oldleap = (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400;
/* calculate leap days incl. this year */
time = *dayp;
if (isleap) /* add leap day ?? */
- mon_days[2] = 28;
+ mon_days[2] += 1;
/* count the months */
for (*monp = 1; time > mon_days[*monp]; (*monp)++)
*dayp = time;
-#if 1
- printk("mac_gettod: %d-%d-%d %d:%d.%d GMT (GMT offset %d)\n",
- *yearp, *monp, *dayp, *hourp, *minp, *secp,
- (signed long) mac_bi_data.gmtbias);
-#endif
-
return;
}
;
}
+extern struct consw fb_con;
+extern struct fb_info *mac_fb_init(long *);
extern void mac_video_setup(char *, int *);
-void mac_debug_init (void)
-{
- ;
-}
-
void (*mac_handlers[8])(int, void *, struct pt_regs *)=
{
mac_default_handler,
mac_bi_data.id = *data;
break;
case BI_MAC_VADDR:
+ /* save booter supplied videobase; use the one mapped in head.S! */
mac_orig_videoaddr = *data;
mac_bi_data.videoaddr = mac_videobase;
break;
printk("ERROR: no Mac, but config_mac() called!! \n");
}
- mac_debugging_penguin(5);
-
mac_debug_init();
mach_sched_init = mac_sched_init;
mach_mksound = mac_mksound;
#endif
mach_reset = mac_reset;
-#ifdef CONFIG_MAC_FLOPPY
- mach_floppy_setup = mac_floppy_setup;
-#endif
conswitchp = &fb_con;
mach_max_dma_address = 0xffffffff;
#if 0
nubus_sweep_video();
- mac_debugging_penguin(6);
}
/*
- * Macintosh Table
+ * Macintosh Table: hardcoded model configuration data.
+ *
+ * Much of this was defined by Alan, based on who knows what docs.
+ * I've added a lot more, and some of that was pure guesswork based
+ * on hardware pages present on the Mac web site. Possibly wildly
+ * inaccurate, so look here if a new Mac model won't run. Example: if
+ * a Mac crashes immediately after the VIA1 registers have been dumped
+ * to the screen, it probably died attempting to read DirB on a RBV.
+ * Meaning it should have MAC_VIA_IIci here :-)
*/
struct mac_model *macintosh_config;
*
* The IIfx apparently has different ADB hardware, and stuff
* so zany nobody knows how to drive it.
+ * Even so, with Marten's help we'll try to deal with it :-)
*/
{ MAC_MODEL_IICI, "IIci", MAC_ADB_II, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_IIFX, "IIfx", MAC_ADB_NONE, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_IIFX, "IIfx", MAC_ADB_II, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_IISI, "IIsi", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_IIVI, "IIvi", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_IIVX, "IIvx", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
* Some Mac LC machines. Basically the same as the IIci, ADB like IIsi
*/
+ { MAC_MODEL_LC, "LC", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_LCII, "LC II", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_LCIII,"LC III", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
* place to confuse us. The 840 seems to have a scsi location of its own
*/
- { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
/* The Q700 does have a NS Sonic */
- { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
/* Does the 840 have ethernet ??? documents seem to indicate its not quite a
Quadra in this respect ? */
- { MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
/* These might have IOP problems */
- { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
- { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS},
+ { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS},
/*
* Performa - more LC type machines
*/
- { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
#if 0 /* other sources seem to suggest the P630/Q630/LC630 is more like LCIII */
- { MAC_MODEL_P630, "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_P630, "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS},
#endif
/*
* Centris - just guessing again; maybe like Quadra
{ MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
/* The PB150 has IDE, and IIci style VIA */
- { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
/*
*/
{ MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
- { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
+ { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{ MAC_MODEL_PB280, "PowerBook Duo 280", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS},
{
printk("\nUnknown macintosh model %d, probably unsupported.\n",
model);
- mac_debugging_long(1, (long) 0x55555555);
- mac_debugging_long(1, (long) model);
model = MAC_MODEL_Q800;
printk("Defaulting to: Quadra800, model id %d\n", model);
printk("Please report this case to linux-mac68k@wave.lm.com\n");
/*
* Report booter data:
*/
- printk (" Penguin (bootinfo version %d) data:\n", 2-compat_bi);
+ printk (" Penguin bootinfo data:\n");
printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %d x %d\n",
mac_bi_data.videoaddr, mac_bi_data.videorow,
mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF,
printk("Apple Macintosh %s\n", macintosh_config->name);
}
+static void mac_get_model(char *str)
+{
+ strcpy(str,"Macintosh ");
+ strcat(str, macintosh_config->name);
+}
+
/*
* Local variables:
* c-indent-level: 4
extern unsigned long mac_videodepth;
extern unsigned long mac_rowbytes;
+#define DEBUG_SCREEN
+#define DEBUG_SERIAL
+
/*
* These two auxiliary debug functions should go away ASAP. Only usage:
* before the console output is up (after head.S come some other crucial
* The 'pos' argument now simply means 'linefeed after print' ...
*/
+#ifdef DEBUG_SCREEN
static int peng=0, line=0;
+#endif
void mac_debugging_short(int pos, short num)
{
+#ifdef DEBUG_SCREEN
unsigned char *pengoffset;
unsigned char *pptr;
int i;
+#endif
+
+#ifdef DEBUG_SERIAL
+ printk("debug: %d !\n", num);
+#endif
+#ifdef DEBUG_SCREEN
if (!MACH_IS_MAC) {
/* printk("debug: %d !\n", num); */
return;
}
/* calculate current offset */
- pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+ pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
+80*peng;
pptr=pengoffset;
line++;
peng = 0;
}
+#endif
}
void mac_debugging_long(int pos, long addr)
{
+#ifdef DEBUG_SCREEN
unsigned char *pengoffset;
unsigned char *pptr;
int i;
+#endif
+#ifdef DEBUG_SERIAL
+ printk("debug: #%ld !\n", addr);
+#endif
+
+#ifdef DEBUG_SCREEN
if (!MACH_IS_MAC) {
/* printk("debug: #%ld !\n", addr); */
return;
}
- pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+ pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
+80*peng;
pptr=pengoffset;
line++;
peng = 0;
}
+#endif
}
/*
#include "that_penguin.h"
};
+#ifdef DEBUG_SCREEN
/*
* B/W version of penguin, unfinished - any takers??
*/
static char bw_penguin[]={
#include "bw_penguin.h"
};
+#endif
void mac_debugging_penguin(int peng)
{
+#ifdef DEBUG_SCREEN
unsigned char *pengoffset;
unsigned char *pptr;
unsigned char *bwpdptr=bw_penguin;
int i;
+#endif
+#ifdef DEBUG_SERIAL
+ printk("Penguin: #%d !\n", peng);
+#endif
+
+#ifdef DEBUG_SCREEN
if (!MACH_IS_MAC)
return;
bwpdptr+=4;
pptr+=mac_rowbytes;
}
+#endif
}
+#ifdef DEBUG_SCREEN
/*
* B/W version of flaming Mac, unfinished (see above).
*/
static char bw_kaboom_map[]={
#include "bw_mac.h"
};
+#endif
+#ifdef DEBUG_SCREEN
static void mac_boom_boom(void)
{
static unsigned char *boomoffset=NULL;
unsigned char *bwpdptr=bw_kaboom_map;
int i;
+#ifdef DEBUG_SERIAL
+ printk("BOOM !\n");
+#endif
+
+ if (!MACH_IS_MAC)
+ return;
+
if(!boomoffset)
if (mac_videodepth == 1) {
boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes);
pptr+=mac_rowbytes;
}
}
+#endif
void mac_boom(int booms)
{
+#ifdef DEBUG_SCREEN
int i;
+#endif
if (!MACH_IS_MAC)
return;
+#ifdef DEBUG_SCREEN
for(i=0;i<booms;i++)
mac_boom_boom();
while(1);
+#endif
}
-#if 0
+#ifdef DEBUG_SERIAL
/*
* TODO: serial debug code
*/
+#define SCC_BAS (0x50F04000)
+struct SCC
+ {
+ u_char cha_b_ctrl;
+ u_char char_dummy1;
+ u_char cha_a_ctrl;
+ u_char char_dummy2;
+ u_char cha_b_data;
+ u_char char_dummy3;
+ u_char cha_a_data;
+ };
+# define scc ((*(volatile struct SCC*)SCC_BAS))
+
/* Flag that serial port is already initialized and used */
int mac_SCC_init_done = 0;
/* Can be set somewhere, if a SCC master reset has already be done and should
static int scc_port;
-static inline void mac_scc_out (char c)
+/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
+
+#define US 1
+
+static inline void mac_sccb_out (char c)
{
+ int i;
do {
- MFPDELAY();
+ for( i = US; i > 0; --i )
+ barrier();
} while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
- MFPDELAY();
+ for( i = US; i > 0; --i )
+ barrier();
scc.cha_b_data = c;
}
-void mac_scc_console_write (struct console *co, const char *str,
+static inline void mac_scca_out (char c)
+{
+ int i;
+ do {
+ for( i = US; i > 0; --i )
+ barrier();
+ } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
+ for( i = US; i > 0; --i )
+ barrier();
+ scc.cha_a_data = c;
+}
+
+void mac_sccb_console_write (struct console *co, const char *str,
unsigned int count)
{
while (count--) {
if (*str == '\n')
- mac_scc_out( '\r' );
- mac_scc_out( *str++ );
+ mac_sccb_out( '\r' );
+ mac_sccb_out( *str++ );
+ }
+}
+
+void mac_scca_console_write (struct console *co, const char *str,
+ unsigned int count)
+{
+ while (count--) {
+ if (*str == '\n')
+ mac_scca_out( '\r' );
+ mac_scca_out( *str++ );
}
}
#ifdef CONFIG_SERIAL_CONSOLE
-int mac_scc_console_wait_key(struct console *co)
+int mac_sccb_console_wait_key(struct console *co)
{
+ int i;
do {
- MFPDELAY();
+ for( i = US; i > 0; --i )
+ barrier();
} while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
- MFPDELAY();
+ for( i = US; i > 0; --i )
+ barrier();
return( scc.cha_b_data );
}
+
+int mac_scca_console_wait_key(struct console *co)
+{
+ int i;
+ do {
+ for( i = US; i > 0; --i )
+ barrier();
+ } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */
+ for( i = US; i > 0; --i )
+ barrier();
+ return( scc.cha_a_data );
+}
#endif
/* The following two functions do a quick'n'dirty initialization of the MFP or
* SCC serial ports. They're used by the debugging interface, kgdb, and the
* serial console code. */
-#define SCC_WRITE(reg,val) \
+#define SCCB_WRITE(reg,val) \
do { \
+ int i; \
scc.cha_b_ctrl = (reg); \
- MFPDELAY(); \
+ for( i = US; i > 0; --i ) \
+ barrier(); \
scc.cha_b_ctrl = (val); \
- MFPDELAY(); \
+ for( i = US; i > 0; --i ) \
+ barrier(); \
+ } while(0)
+
+#define SCCA_WRITE(reg,val) \
+ do { \
+ int i; \
+ scc.cha_a_ctrl = (reg); \
+ for( i = US; i > 0; --i ) \
+ barrier(); \
+ scc.cha_a_ctrl = (val); \
+ for( i = US; i > 0; --i ) \
+ barrier(); \
} while(0)
/* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a
* delay of ~ 60us. */
+/* Mac: loops_per_sec min. 1900000 ^= .5 us; MFPDELAY was 0.6 us*/
#define LONG_DELAY() \
do { \
int i; \
- for( i = 100; i > 0; --i ) \
- MFPDELAY(); \
+ for( i = 60*US; i > 0; --i ) \
+ barrier(); \
} while(0)
#ifndef CONFIG_SERIAL_CONSOLE
reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
-
- (void)scc.cha_b_ctrl; /* reset reg pointer */
- SCC_WRITE( 9, 0xc0 ); /* reset */
- LONG_DELAY(); /* extra delay after WR9 access */
- SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
- 0x04 /* 1 stopbit */ |
- clkmode );
- SCC_WRITE( 3, reg3 );
- SCC_WRITE( 5, reg5 );
- SCC_WRITE( 9, 0 ); /* no interrupts */
- LONG_DELAY(); /* extra delay after WR9 access */
- SCC_WRITE( 10, 0 ); /* NRZ mode */
- SCC_WRITE( 11, clksrc ); /* main clock source */
- SCC_WRITE( 12, div ); /* BRG value */
- SCC_WRITE( 13, 0 ); /* BRG high byte */
- SCC_WRITE( 14, brgsrc_table[baud] );
- SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
- SCC_WRITE( 3, reg3 | 1 );
- SCC_WRITE( 5, reg5 | 8 );
-
+
+#if 0
+ if (port) {
+#endif
+ (void)scc.cha_b_ctrl; /* reset reg pointer */
+ SCCB_WRITE( 9, 0xc0 ); /* reset */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+ 0x04 /* 1 stopbit */ |
+ clkmode );
+ SCCB_WRITE( 3, reg3 );
+ SCCB_WRITE( 5, reg5 );
+ SCCB_WRITE( 9, 0 ); /* no interrupts */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCCB_WRITE( 10, 0 ); /* NRZ mode */
+ SCCB_WRITE( 11, clksrc ); /* main clock source */
+ SCCB_WRITE( 12, div ); /* BRG value */
+ SCCB_WRITE( 13, 0 ); /* BRG high byte */
+ SCCB_WRITE( 14, brgsrc_table[baud] );
+ SCCB_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+ SCCB_WRITE( 3, reg3 | 1 );
+ SCCB_WRITE( 5, reg5 | 8 );
+#if 0
+ } else {
+#endif
+ (void)scc.cha_a_ctrl; /* reset reg pointer */
+ SCCA_WRITE( 9, 0xc0 ); /* reset */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+ 0x04 /* 1 stopbit */ |
+ clkmode );
+ SCCA_WRITE( 3, reg3 );
+ SCCA_WRITE( 5, reg5 );
+ SCCA_WRITE( 9, 0 ); /* no interrupts */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCCA_WRITE( 10, 0 ); /* NRZ mode */
+ SCCA_WRITE( 11, clksrc ); /* main clock source */
+ SCCA_WRITE( 12, div ); /* BRG value */
+ SCCA_WRITE( 13, 0 ); /* BRG high byte */
+ SCCA_WRITE( 14, brgsrc_table[baud] );
+ SCCA_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+ SCCA_WRITE( 3, reg3 | 1 );
+ SCCA_WRITE( 5, reg5 | 8 );
+#if 0
+ }
+#endif
mac_SCC_reset_done = 1;
mac_SCC_init_done = 1;
}
-
+#endif /* DEBUG_SERIAL */
__initfunc(void mac_debug_init(void))
{
/* the m68k_debug_device is used by the GDB stub, do nothing here */
return;
#endif
+#ifdef DEBUG_SERIAL
if (!strcmp( m68k_debug_device, "ser" )) {
strcpy( m68k_debug_device, "ser1" );
}
if (!strcmp( m68k_debug_device, "ser1" )) {
/* ST-MFP Modem1 serial port */
mac_init_scc_port( B9600|CS8, 0 );
- mac_console_driver.write = mac_scc_console_write;
+ mac_console_driver.write = mac_scca_console_write;
}
else if (!strcmp( m68k_debug_device, "ser2" )) {
/* SCC Modem2 serial port */
mac_init_scc_port( B9600|CS8, 1 );
- mac_console_driver.write = mac_scc_console_write;
+ mac_console_driver.write = mac_sccb_console_write;
}
if (mac_console_driver.write)
register_console(&mac_console_driver);
-}
#endif
+}
/*
* Local variables:
+++ /dev/null
-#include <linux/module.h>
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-/* Hook for mouse driver */
-extern void (*mac_mouse_interrupt_hook) (char *);
-
-EXPORT_SYMBOL(mac_mouse_interrupt_hook);
--- /dev/null
+#include <linux/module.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+/* Hook for mouse driver */
+extern void (*mac_mouse_interrupt_hook) (char *);
+
+EXPORT_SYMBOL(mac_mouse_interrupt_hook);
*
* 7 - Debug output
*
+ * AV Macs only, handled by PSC:
+ *
+ * 3 - MACE ethernet IRQ (DMA complete on level 4)
+ *
+ * 5 - DSP ??
+ *
* Using the autovector irq numbers for Linux/m68k hardware interrupts without
* the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt
* handling in kernel versions 2.0.x, so the following strategy is used:
* should be sufficient to use the same numbers (everything > 7 is assumed
* to be machspec, according to Jes!).
*
+ * TODO:
+ * - integrate Nubus interrupts in request/free_irq
+ *
+ * -
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h> /* for intr_count */
+#include <linux/delay.h>
#include <asm/system.h>
#include <asm/irq.h>
static struct irqhandler via1_handler[8];
static struct irqhandler via2_handler[8];
static struct irqhandler rbv_handler[8];
+static struct irqhandler psc3_handler[8];
static struct irqhandler scc_handler[8];
+static struct irqhandler psc5_handler[8];
+static struct irqhandler psc6_handler[8];
static struct irqhandler nubus_handler[8];
static struct irqhandler *handler_table[8];
static struct irqparam via1_param[8];
static struct irqparam via2_param[8];
static struct irqparam rbv_param[8];
+static struct irqparam psc3_param[8];
static struct irqparam scc_param[8];
+static struct irqparam psc5_param[8];
+static struct irqparam psc6_param[8];
static struct irqparam nubus_param[8];
static struct irqparam *param_table[8];
/*
* This array holds the pointers to the various VIA or other interrupt
- * controllers
+ * controllers, indexed by interrupt level
*/
static volatile unsigned char *via_table[8];
-#ifdef VIABASE_WEIRDNESS
/*
- * VIA2 / RBV default base address
+ * Arrays with irq statistics
*/
+static unsigned long via1_irqs[8];
+static unsigned long via2_irqs[8];
+static unsigned long rbv_irqs[8];
+static unsigned long psc3_irqs[8];
+static unsigned long scc_irqs[8];
+static unsigned long psc5_irqs[8];
+static unsigned long psc6_irqs[8];
+static unsigned long nubus_irqs[8];
-volatile unsigned char *via2_regp = ((volatile unsigned char *)VIA2_BAS);
-volatile unsigned char *rbv_regp = ((volatile unsigned char *)VIA2_BAS_IIci);
-#endif
+static unsigned long *mac_irqs[8];
+
+/*
+ * VIA2 / RBV register base pointers
+ */
+
+volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS;
+volatile unsigned char *rbv_regp=(volatile unsigned char *)VIA2_BAS_IIci;
+volatile unsigned char *oss_regp=(volatile unsigned char *)OSS_BAS;
+volatile unsigned char *psc_regp=(volatile unsigned char *)PSC_BAS;
/*
* Flags to control via2 / rbv behaviour
*/
static int via2_is_rbv = 0;
+static int via2_is_oss = 0;
static int rbv_clear = 0;
+/* fake VIA2 to OSS bit mapping */
+static int oss_map[8] = {2, 7, 0, 1, 3, 4, 5};
+
+void oss_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void oss_do_nubus(int irq, void *dev_id, struct pt_regs *regs);
+
+/* PSC ints */
+void psc_irq(int irq, void *dev_id, struct pt_regs *regs);
+
/*
* console_loglevel determines NMI handler function
*/
#ifdef DEBUG_MACINTS
printk("Mac interrupt stuff initializing ...\n");
#endif
+
+ via2_regp = (unsigned char *)VIA2_BAS;
+ rbv_regp = (unsigned char *)VIA2_BAS_IIci;
+
/* initialize the hardwired (primary, autovector) IRQs */
/* level 1 IRQ: VIA1, always present */
/* via2 or rbv?? */
if (macintosh_config->via_type == MAC_VIA_IIci) {
- /* VIA2 is part of the RBV: different base, other offsets */
- via2_is_rbv = 1;
- /* LC III weirdness: IFR seems to behave like VIA2 */
- /* FIXME: maybe also for LC II ?? */
- if (macintosh_config->ident == MAC_MODEL_LCIII) {
- rbv_clear = 0x0;
+ /*
+ * A word of caution: the definitions here only affect interrupt
+ * handling, see via6522.c for yet another file to change
+ * base addresses and RBV flags
+ */
+
+ /* yes, this is messy - the IIfx deserves a class of his own */
+ if (macintosh_config->ident == MAC_MODEL_IIFX) {
+ /* no real VIA2, the OSS seems _very_different */
+ via2_is_oss = 1;
+ /* IIfx has OSS, at a different base address than RBV */
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ rbv_regp = (unsigned char *) OSS_BAS;
+ sys_request_irq(2, oss_irq, IRQ_FLG_LOCK, "oss", oss_irq);
} else {
- rbv_clear = 0x80;
+ /* VIA2 is part of the RBV: different base, other offsets */
+ via2_is_rbv = 1;
+
+ /* LC III weirdness: IFR seems to behave like VIA2 */
+ /* FIXME: maybe also for LC II ?? */
+ if (macintosh_config->ident == MAC_MODEL_LCIII) {
+ rbv_clear = 0x0;
+ } else {
+ rbv_clear = 0x80;
+ }
+ /* level 2 IRQ: RBV/OSS; we only care about RBV for now */
+ sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
}
- /* level 2 IRQ: RBV/OSS; we only care about RBV for now */
- sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
} else
/* level 2 IRQ: VIA2 */
sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq);
* Currently, one interrupt per channel is used, solely
* to pass the correct async_info as parameter!
*/
-#if 0 /* doesn't seem to work yet */
+#if 0 /* want to install debug/SCC shutup routine until SCC init */
sys_request_irq(4, mac_SCC_handler, IRQ_FLG_STD, "INT4", mac_SCC_handler);
#else
sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler);
via_table[0] = via1_regp;
handler_table[0] = &via1_handler[0];
param_table[0] = &via1_param[0];
+ mac_irqs[0] = &via1_irqs[0];
if (via2_is_rbv) {
via_table[1] = rbv_regp;
handler_table[1] = &rbv_handler[0];
param_table[1] = &rbv_param[0];
+ mac_irqs[1] = &rbv_irqs[0];
} else {
via_table[1] = via2_regp;
handler_table[1] = &via2_handler[0];
param_table[1] = &via2_param[0];
+ mac_irqs[1] = &via2_irqs[0];
}
via_table[2] = NULL;
via_table[3] = NULL;
handler_table[2] = &rbv_handler[0];
- handler_table[3] = &nubus_handler[0];
+ handler_table[3] = &scc_handler[0];
+ handler_table[4] = NULL;
+ handler_table[5] = NULL;
+ handler_table[6] = NULL;
+ handler_table[7] = &nubus_handler[0];
param_table[2] = &rbv_param[0];
- param_table[3] = &nubus_param[0];
+ param_table[3] = &scc_param[0];
+ param_table[7] = &nubus_param[0];
+
+ mac_irqs[2] = &rbv_irqs[0];
+ mac_irqs[3] = &scc_irqs[0];
+ mac_irqs[7] = &nubus_irqs[0];
+
+ /*
+ * AV Macs: shutup the PSC ints
+ */
+ if (macintosh_config->ident == MAC_MODEL_C660
+ || macintosh_config->ident == MAC_MODEL_Q840) {
+ psc_init();
+
+ handler_table[2] = &psc3_handler[0];
+ /* handler_table[3] = &psc4_handler[0]; */
+ handler_table[4] = &psc5_handler[0];
+ handler_table[5] = &psc6_handler[0];
+
+ param_table[2] = &psc3_param[0];
+ /* param_table[3] = &psc4_param[0]; */
+ param_table[4] = &psc5_param[0];
+ param_table[5] = &psc6_param[0];
+
+ mac_irqs[2] = &psc3_irqs[0];
+ /* mac_irqs[3] = &psc4_irqs[0]; */
+ mac_irqs[4] = &psc5_irqs[0];
+ mac_irqs[5] = &psc6_irqs[0];
+
+ sys_request_irq(3, psc_irq, IRQ_FLG_STD, "PSC3", psc_irq);
+ sys_request_irq(4, psc_irq, IRQ_FLG_STD, "PSC4", psc_irq);
+ sys_request_irq(5, psc_irq, IRQ_FLG_STD, "PSC5", psc_irq);
+ sys_request_irq(6, psc_irq, IRQ_FLG_STD, "PSC6", psc_irq);
+ }
#ifdef DEBUG_MACINTS
printk("Mac interrupt init done!\n");
* We have no machine specific interrupts on a macintoy
* Yet, we need to register/unregister interrupts ... :-)
* Currently unimplemented: Test for valid irq number, chained irqs,
- * Nubus interrupts.
+ * Nubus interrupts (use nubus_request_irq!).
*/
int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
return -EINVAL;
}
- /* figure out if SCC pseudo-irq */
- if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+ /* figure out if SCC pseudo-irq (redundant ??) */
+ if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
/* set specific SCC handler */
scc_handler[irqidx].handler = handler;
scc_handler[irqidx].dev_id = dev_id;
return 0;
}
+ /* add similar hack for Nubus pseudo-irq here - hide nubus_request_irq */
+
via = (volatile unsigned char *) via_table[srcidx];
if (!via)
return -EINVAL;
via_param[irqidx].flags = flags;
via_param[irqidx].devname = devname;
- /* and turn it on ... */
+ /* and turn it on ... careful, that's VIA only ... */
if (srcidx == SRC_VIA2 && via2_is_rbv)
via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+ else if (srcidx == SRC_VIA2 && via2_is_oss)
+ via_write(oss_regp, oss_map[irqidx]+8, 2);
else
via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
if (irq == IRQ_IDX(IRQ_MAC_SCSI)) {
/*
* Set vPCR for SCSI interrupts. (what about RBV here?)
+ * 980429 MS: RBV is ok, OSS seems to be differentt
*/
- via_write(via, vPCR, 0x66);
+ if (!via2_is_oss)
+ /* CB2 (IRQ) indep. interrupt input, positive edge */
+ /* CA2 (DRQ) indep. interrupt input, positive edge */
+ via_write(via, vPCR, 0x66);
+#if 0
+ else
+ /* CB2 (IRQ) indep. interrupt input, negative edge */
+ /* CA2 (DRQ) indep. interrupt input, negative edge */
+ via_write(via, vPCR, 0x22);
+#endif
}
return 0;
cli();
/* figure out if SCC pseudo-irq */
- if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+ if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
/* clear specific SCC handler */
scc_handler[irqidx].handler = mac_default_handler;
scc_handler[irqidx].dev_id = NULL;
/* and turn it off */
if (srcidx == SRC_VIA2 && via2_is_rbv)
via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+ else if (srcidx == SRC_VIA2 && via2_is_oss)
+ via_write(oss_regp, oss_map[irqidx]+8, 0);
else
via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
void mac_enable_irq (unsigned int irq)
{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
irq_flags[srcidx].disabled &= ~(1<<irqidx);
/*
void mac_disable_irq (unsigned int irq)
{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
irq_flags[srcidx].disabled |= (1<<irqidx);
}
void mac_turnon_irq( unsigned int irq )
{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
volatile unsigned char *via;
via = (volatile unsigned char *) via_table[srcidx];
if (srcidx == SRC_VIA2 && via2_is_rbv)
via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+ else if (srcidx == SRC_VIA2 && via2_is_oss)
+ via_write(oss_regp, oss_map[irqidx]+8, 2);
+ else if (srcidx >= SRC_VIA2)
+ via_write(via, (0x104 + 0x10*srcidx),
+ via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx)));
else
via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
void mac_turnoff_irq( unsigned int irq )
{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
volatile unsigned char *via;
via = (volatile unsigned char *) via_table[srcidx];
if (srcidx == SRC_VIA2 && via2_is_rbv)
via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+ else if (srcidx == SRC_VIA2 && via2_is_oss)
+ via_write(oss_regp, oss_map[irqidx]+8, 0);
+ else if (srcidx >= SRC_VIA2)
+ via_write(via, (0x104 + 0x10*srcidx),
+ via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx)));
else
via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
}
void mac_clear_pending_irq( unsigned int irq )
{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
irq_flags[srcidx].pending &= ~(1<<irqidx);
}
int mac_irq_pending( unsigned int irq )
{
- int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
- int irqidx = (irq & IRQ_IDX_MASK);
+ int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+ int irqidx = (irq & IRQ_IDX_MASK);
return (irq_flags[srcidx].pending & (1<<irqidx));
}
int mac_get_irq_list (char *buf)
{
- return 0;
+ int i, len = 0;
+ int srcidx, irqidx;
+
+ for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) {
+ srcidx = ((i & IRQ_SRC_MASK)>>3) - 1;
+ irqidx = (i & IRQ_IDX_MASK);
+
+ /*
+ * Not present: skip
+ */
+
+ if (mac_irqs[srcidx] == NULL)
+ continue;
+
+ /*
+ * never used by VIAs, unused by others so far, counts
+ * the magic 'nothing pending' cases ...
+ */
+ if (irqidx == 7 && mac_irqs[srcidx][irqidx]) {
+ len += sprintf(buf+len, "Level %01d: %10u (spurious) \n",
+ srcidx,
+ mac_irqs[srcidx][irqidx]);
+ continue;
+ }
+
+ /*
+ * Nothing registered for this IPL: skip
+ */
+
+ if (handler_table[srcidx] == NULL)
+ continue;
+
+ /*
+ * No handler installed: skip
+ */
+
+ if (handler_table[srcidx][irqidx].handler == mac_default_handler ||
+ handler_table[srcidx][irqidx].handler == nubus_wtf)
+ continue;
+
+
+ if (i < VIA2_SOURCE_BASE)
+ len += sprintf(buf+len, "via1 %01d: %10u ",
+ irqidx,
+ mac_irqs[srcidx][irqidx]);
+ else if (i < RBV_SOURCE_BASE)
+ len += sprintf(buf+len, "via2 %01d: %10u ",
+ irqidx,
+ mac_irqs[srcidx][irqidx]);
+ else if (i < MAC_SCC_SOURCE_BASE)
+ len += sprintf(buf+len, "rbv %01d: %10u ",
+ irqidx,
+ mac_irqs[srcidx][irqidx]);
+ else if (i < NUBUS_SOURCE_BASE)
+ len += sprintf(buf+len, "scc %01d: %10u ",
+ irqidx,
+ mac_irqs[srcidx][irqidx]);
+ else /* Nubus */
+ len += sprintf(buf+len, "nubus %01d: %10u ",
+ irqidx,
+ mac_irqs[srcidx][irqidx]);
+
+ len += sprintf(buf+len, "%s\n",
+ param_table[srcidx][irqidx].devname);
+
+ }
+ if (num_spurious)
+ len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
+ return len;
}
void via_scsi_clear(void)
if (via2_is_rbv) {
via_write(rbv_regp, rIFR, (1<<3)|(1<<0)|0x80);
deep_magic = via_read(rbv_regp, rBufB);
+ } else if (via2_is_oss) {
+ /* nothing */
+ /* via_write(oss_regp, 9, 0) */;
} else
deep_magic = via_read(via2_regp, vBufB);
mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) );
}
}
+void scsi_mac_debug(void);
+void scsi_mac_polled(void);
+
void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
{
+ int i;
/*
* generate debug output on NMI switch if 'debug' kernel option given
* (only works with Penguin!)
*/
+#if 0
+ scsi_mac_debug();
+ printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
+#endif
+ for (i=0; i<100; i++)
+ udelay(1000);
+ scsi_mac_polled();
+
if ( console_loglevel >= 8 ) {
#if 0
show_state();
int ct = 0;
struct irqhandler *via_handler = handler_table[*viaidx];
struct irqparam *via_param = param_table[*viaidx];
+ unsigned long *via_irqs = mac_irqs[*viaidx];
/* to be changed, possibly: for each non'masked', enabled IRQ, read
* flag bit, ack and call handler ...
if(events==0)
{
- printk("via%d_irq: nothing pending!\n", *viaidx + 1);
+#ifdef DEBUG_VIA
+ /* should go away; mostly missing timer ticks and ADB events */
+ printk("via%d_irq: nothing pending, flags %x mask %x!\n",
+ *viaidx + 1, via_read(via, vIFR), via_read(via,vIER));
+#endif
+ via_irqs[7]++;
return;
}
/* call corresponding handlers */
if (events&(1<<i)) {
if (irq_flags[*viaidx].disabled & (1<<i)) {
+ if (!irq_flags[*viaidx].pending&(1<<i))
+ via_irqs[i]++;
/* irq disabled -> mark pending */
irq_flags[*viaidx].pending |= (1<<i);
} else {
+ via_irqs[i]++;
/* irq enabled -> call handler */
(via_handler[i].handler)(irq, via, regs);
}
ct++;
if(events && ct>8)
{
+#ifdef DEBUG_VIA
printk("via%d: stuck events %x\n", (*viaidx)+1, events);
+#endif
break;
}
}
struct irqhandler *via_handler = handler_table[srcidx];
struct irqparam *via_param = param_table[srcidx];
+ /* shouldn't we disable interrupts here ?? */
+
+
+ /*
+ * Shouldnt happen
+ */
+
+ if(events==0)
+ {
+#ifdef DEBUG_VIA
+ printk("rbv_irq: nothing pending, flags %x mask %x!\n",
+ via_read(via, rIFR), via_read(via,rIER));
+#endif
+ rbv_irqs[7]++;
+ return;
+ }
+
#ifdef DEBUG_VIA
/*
* limited verbosity for RBV interrupts (add more if needed)
* If ack for masked IRQ required: keep 'pending' info separate.
*/
- /* shouldn't we disable interrupts here ?? */
-
-
- /*
- * Shouldnt happen
- */
-
- if(events==0)
- {
- printk("rbv_irq: nothing pending!\n");
- return;
- }
-
do {
/*
* Clear the pending flag
int irq = (srcidx+1)* 8 + i;
/* call corresponding handlers */
if (events&(1<<i)) {
- if (irq_flags[srcidx].disabled & (1<<i))
+ if (irq_flags[srcidx].disabled & (1<<i)) {
+ if (!irq_flags[srcidx].pending&(1<<i))
+ rbv_irqs[i]++;
/* irq disabled -> mark pending */
irq_flags[srcidx].pending |= (1<<i);
- else
+ } else {
+ rbv_irqs[i]++;
/* irq enabled -> call handler */
(via_handler[i].handler)(irq, via, regs);
+ }
}
/* and call handlers for pending irqs - first ?? */
if ( (irq_flags[srcidx].pending & (1<<i))
irq_flags[srcidx].pending &= ~(1<<i);
}
}
-
+
/*
* And done ... check for more punishment!
*/
#endif
}
+/*
+ * Nubus / SCSI interrupts; OSS style
+ * The OSS is even more different than the RBV. OSS appears to stand for
+ * Obscenely Screwed Silicon ...
+ *
+ * Latest NetBSD sources suggest the OSS should behave like a RBV, but
+ * that's probably true for the 0x203 offset (Nubus/ADB-SWIM IOP) at best
+ */
+
+void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int srcidx = IRQ_IDX(irq) - 1; /* MUST be 1 !! */
+ volatile unsigned char *via = oss_regp;
+ unsigned char events=(via_read(via, oIFR))&0x03;
+ unsigned char nub_ev=(via_read(via, nIFR))&0x4F;
+ unsigned char adb_ev;
+ int i;
+ int ct = 0;
+ struct irqhandler *via_handler = handler_table[srcidx];
+ struct irqparam *via_param = param_table[srcidx];
+
+ /* shouldn't we disable interrupts here ?? */
+
+ adb_ev = nub_ev & 0x40;
+ nub_ev &= 0x3F;
+
+ /*
+ * Shouldnt happen
+ */
+
+ if (events==0 && adb_ev==0 && nub_ev==0)
+ {
+ printk("oss_irq: nothing pending, flags %x %x!\n",
+ via_read(via, oIFR), via_read(via, nIFR));
+ rbv_irqs[7]++;
+ return;
+ }
+
+#ifdef DEBUG_VIA
+ /*
+ * limited verbosity for RBV interrupts (add more if needed)
+ */
+ if ( events != 1<<3 ) /* SCSI IRQ */
+ printk("oss_irq: irq %d events %x %x %x !\n", irq, srcidx+1,
+ events, adb_ev, nub_ev);
+#endif
+
+ /*
+ * OSS priorities: call ADB handler first if registered, other events,
+ * then Nubus
+ * ADB: yet to be implemented!
+ */
+
+ /*
+ * ADB: try to shutup the IOP
+ */
+ if (adb_ev) {
+ printk("Hands off ! Don't press this button ever again !!!\n");
+ via_write(via, 6, 0);
+ }
+
+ do {
+ /*
+ * Clear the pending flags
+ * How exactly is that supposed to work ??
+ */
+
+ /*
+ * Now see what bits are raised
+ */
+
+ for(i=0;i<7;i++)
+ {
+ /* HACK HACK: map to bit number in OSS register */
+ int irqidx = oss_map[i];
+ /* determine machspec. irq no. */
+ int irq = (srcidx+1)* 8 + i;
+ /* call corresponding handlers */
+ if ( (events&(1<<irqidx)) && /* bit set*/
+ (via_read(via, irqidx+8)&0x7) ) { /* irq enabled */
+ if (irq_flags[srcidx].disabled & (1<<i)) {
+ if (!irq_flags[srcidx].pending&(1<<i))
+ rbv_irqs[i]++;
+ /* irq disabled -> mark pending */
+ irq_flags[srcidx].pending |= (1<<i);
+ } else {
+ rbv_irqs[i]++;
+ /* irq enabled -> call handler */
+ (via_handler[i].handler)(irq, via, regs);
+ }
+ }
+ /* and call handlers for pending irqs - first ?? */
+ if ( (irq_flags[srcidx].pending & (1<<i))
+ && !(irq_flags[srcidx].disabled & (1<<i)) ) {
+ /* call handler for re-enabled irq */
+ (via_handler[i].handler)(irq, via, regs);
+ /* and clear pending flag :-) */
+ irq_flags[srcidx].pending &= ~(1<<i);
+ }
+ }
+
+ /*
+ * And done ... check for more punishment!
+ */
+
+ events=(via_read(via, oIFR)/*&via_read(via,rIER)*/)&0x03;
+ ct++;
+ if(events && ct>8)
+ {
+ printk("oss: stuck events %x\n",events);
+ for(i=0;i<7;i++)
+ {
+ if(events&(1<<i))
+ {
+ printk("oss - bashing source %d\n",
+ i);
+ /* that should disable it */
+ via_write(via, 8+i, 0);
+ }
+ }
+ break;
+ }
+ }
+ while(events);
+#if 0
+ scsi_mac_polled();
+#endif
+
+ if (nub_ev)
+ oss_do_nubus(irq, via, regs);
+
+}
+
+/*
+ * Unexpected slot interrupt
+ */
+
void nubus_wtf(int slot, void *via, struct pt_regs *regs)
{
-#ifdef DEBUG_VIA
+#ifdef DEBUG_VIA_NUBUS
printk("Unexpected interrupt on nubus slot %d\n",slot);
#endif
}
+/*
+ * SCC master interrupt handler; sole purpose: pass the registered
+ * async struct to the SCC handler proper.
+ */
+
void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int i;
-
- for (i = 0; i < 8; i++)
+ /* 1+2: compatibility with PSC ! */
+ for (i = 1; i < 3; i++) /* currently only these two used */
if (scc_handler[i].handler != mac_default_handler)
(scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
}
+/*
+ * PSC interrupt handler
+ */
+
+void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int srcidx = IRQ_IDX(irq) - 1;
+ volatile unsigned char *via = psc_regp;
+ unsigned int pIFR = 0x100 + 0x10*srcidx;
+ unsigned int pIER = 0x104 + 0x10*srcidx;
+ unsigned char events=(via_read(via, pIFR)&via_read(via,pIER))&0xF;
+ int i;
+ int ct = 0;
+ struct irqhandler *via_handler = handler_table[srcidx];
+ struct irqparam *via_param = param_table[srcidx];
+
+ /* shouldn't we disable interrupts here ?? */
+
+
+ /*
+ * Shouldnt happen
+ */
+
+ if(events==0)
+ {
+#ifdef DEBUG_VIA
+ printk("rbv_irq: nothing pending, flags %x mask %x!\n",
+ via_read(via, pIFR), via_read(via,pIER));
+#endif
+ mac_irqs[srcidx][7]++;
+ return;
+ }
+
+#ifdef DEBUG_VIA
+ /*
+ * limited verbosity for RBV interrupts (add more if needed)
+ */
+ if ( srcidx == 1 && events != 1<<3 && events != 1<<1 ) /* SCSI IRQ */
+ printk("psc_irq: irq %d events %x !\n", irq, srcidx+1, events);
+#endif
+
+ /* to be changed, possibly: for each non'masked', enabled IRQ, read
+ * flag bit, ack and call handler ...
+ * Currently: all pending irqs ack'ed en bloc.
+ * If ack for masked IRQ required: keep 'pending' info separate.
+ */
+
+ do {
+ /*
+ * Clear the pending flag
+ */
+
+ /* via_write(via, pIFR, events); */
+
+ /*
+ * Now see what bits are raised
+ */
+
+ for(i=0;i<7;i++)
+ {
+ /* determine machspec. irq no. */
+ int irq = (srcidx+1)* 8 + i;
+ /* call corresponding handlers */
+ if (events&(1<<i)) {
+ if (irq_flags[srcidx].disabled & (1<<i)) {
+ if (!irq_flags[srcidx].pending&(1<<i))
+ mac_irqs[srcidx][i]++;
+ /* irq disabled -> mark pending */
+ irq_flags[srcidx].pending |= (1<<i);
+ } else {
+ mac_irqs[srcidx][i]++;
+ /* irq enabled -> call handler */
+ (via_handler[i].handler)(irq, via, regs);
+ }
+ }
+ /* and call handlers for pending irqs - first ?? */
+ if ( (irq_flags[srcidx].pending & (1<<i))
+ && !(irq_flags[srcidx].disabled & (1<<i)) ) {
+ /* call handler for re-enabled irq */
+ (via_handler[i].handler)(irq, via, regs);
+ /* and clear pending flag :-) */
+ irq_flags[srcidx].pending &= ~(1<<i);
+ }
+ }
+
+ /*
+ * And done ... check for more punishment!
+ */
+
+ events=(via_read(via,pIFR)&via_read(via,pIER))&0x7F;
+ ct++;
+ if(events && ct>8)
+ {
+ printk("psc: stuck events %x\n",events);
+ for(i=0;i<7;i++)
+ {
+ if(events&(1<<i))
+ {
+ printk("psc - bashing source %d\n",
+ i);
+ via_write(via, pIER, 1<<i);
+ /* via_write(via, pIFR, (1<<i)); */
+ }
+ }
+ break;
+ }
+ }
+ while(events);
+}
+
+
/*
* Nubus handling
* Caution: slot numbers are currently 'hardcoded' to the range 9-15!
nubus_handler[slot].handler=handler;
nubus_handler[slot].dev_id =dev_id;
nubus_param[slot].flags = IRQ_FLG_LOCK;
- nubus_param[slot].devname = "nubus";
+ nubus_param[slot].devname = "nubus slot";
/*
* if no nubus int. was active previously: register the main nubus irq
* handler now!
*/
- if (!nubus_active)
- request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK,
- "nubus dispatch", via_do_nubus);
+ if (!nubus_active && !via2_is_oss) {
+ request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK,
+ "nubus dispatch", via_do_nubus);
+ }
nubus_active|=1<<slot;
/* printk("program slot %d\n",slot);*/
via_read(via2, vDirA)|(1<<slot));
via_write(via2, vBufA, 0);
#endif
- if (!via2_is_rbv) {
+ if (via2_is_oss)
+ via_write(oss_regp, slot, 2);
+ else if (!via2_is_rbv) {
/* Make sure the bit is an input */
via_write(via2_regp, vDirA,
via_read(via2_regp, vDirA)&~(1<<slot));
if (via2_is_rbv)
via_write(rbv_regp, rBufA, 1<<slot);
+ else if (via2_is_oss)
+ via_write(oss_regp, slot, 0);
else {
via_write(via2_regp, vDirA,
via_read(via2_regp, vDirA)|(1<<slot));
return 0;
}
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+/*
+ * IDE interrupt hook
+ */
+extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
+#endif
+
+/*
+ * Nubus dispatch handler - VIA/RBV style
+ */
static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
{
unsigned char map;
else
via_write(via2_regp, vIFR, 0x82);
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+ /* IDE hack */
+ if (mac_ide_intr_hook)
+ /* 'slot' is lacking the machspec bit in 2.0 */
+ /* need to pass proper dev_id = hwgroup here */
+ mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+#endif
+
while(1)
{
if (via2_is_rbv)
else
map = ~via_read(via2_regp, vBufA);
-#ifdef DEBUG_VIA
- printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+ if( (map = (map&nubus_active)) ==0 ) {
+#ifdef DEBUG_NUBUS_INT
+ printk("nubus_irq: nothing pending, map %x mask %x\n",
+ map, nubus_active);
#endif
- if( (map = (map&nubus_active)) ==0 )
+ nubus_irqs[7]++;
break;
+ }
+#ifdef DEBUG_NUBUS_INT
+ printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#endif
if(ct++>2)
{
+#ifdef DEBUG_NUBUS_INT
printk("nubus stuck events - %d/%d\n", map, nubus_active);
+#endif
return;
}
{
if(map&(1<<i))
{
+ nubus_irqs[i]++;
(nubus_handler[i].handler)(i+9, nubus_handler[i].dev_id, regs);
}
}
/* And done */
}
+
+/*
+ * Nubus dispatch handler - OSS style
+ */
+static void oss_do_nubus(int slot, void *via, struct pt_regs *regs)
+{
+ unsigned char map;
+ int i;
+ int ct=0;
+
+/* printk("nubus interrupt\n");*/
+
+#if 0
+ /* lock the nubus interrupt */
+ if (via2_is_rbv)
+ via_write(rbv_regp, rIFR, 0x82);
+ else
+ via_write(via2_regp, vIFR, 0x82);
+#endif
+
+ /* IDE hack for Quadra: uses Nubus interrupt without any slot bit set */
+ if (mac_ide_intr_hook)
+ mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+
+ while(1)
+ {
+ /* pending events */
+ map=(via_read(via, nIFR))&0x3F;
+
+#ifdef DEBUG_VIA_NUBUS
+ printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#endif
+ if( (map = (map&nubus_active)) ==0 ) {
+ if (!mac_ide_intr_hook)
+ printk("nubus_irq: nothing pending, map %x mask %x\n",
+ map, nubus_active);
+ nubus_irqs[7]++;
+ break;
+ }
+
+ if(ct++>2)
+ {
+#if 0
+ printk("nubus stuck events - %d/%d\n", map, nubus_active);
+#endif
+ return;
+ }
+
+ for(i=0;i<7;i++)
+ {
+ if(map&(1<<i))
+ {
+ nubus_irqs[i]++;
+ /* call handler */
+ (nubus_handler[i].handler)((i+9), nubus_handler[i].dev_id, regs);
+ /* clear interrupt ?? */
+#if 0
+ via_write(oss_regp, i, 0);
+#endif
+ }
+ }
+ /* clear it */
+#if 0
+ via_write(oss_regp, nIFR, map);
+#endif
+ }
+
+ /* And done */
+}
volatile int ct;
/* setup key map */
- memcpy (plain_map, mac_plain_map, sizeof(plain_map));
- memcpy(shift_map, mac_shift_map, sizeof(shift_map));
- memcpy(altgr_map, mac_altgr_map, sizeof(altgr_map));
- memcpy(ctrl_map, mac_ctrl_map, sizeof(ctrl_map));
- memcpy(shift_ctrl_map, mac_shift_ctrl_map, sizeof(shift_ctrl_map));
- memcpy(alt_map, mac_alt_map, sizeof(alt_map));
- memcpy(ctrl_alt_map, mac_ctrl_alt_map, sizeof(ctrl_alt_map));
+ memcpy(key_maps[0], mac_plain_map, sizeof(plain_map));
+ memcpy(key_maps[1], mac_shift_map, sizeof(plain_map));
+ memcpy(key_maps[2], mac_altgr_map, sizeof(plain_map));
+ memcpy(key_maps[4], mac_ctrl_map, sizeof(plain_map));
+ memcpy(key_maps[5], mac_shift_ctrl_map, sizeof(plain_map));
+ memcpy(key_maps[8], mac_alt_map, sizeof(plain_map));
+ memcpy(key_maps[12], mac_ctrl_alt_map, sizeof(plain_map));
/* initialize mouse interrupt hook */
mac_mouse_interrupt_hook = NULL;
--- /dev/null
+/*
+ * Apple Peripheral System Controller (PSC)
+ *
+ * The PSC is used on the AV Macs to control IO functions not handled
+ * by the VIAs (Ethernet, DSP, SCC).
+ */
+
+#define PSCBASE 0x50F31000
+
+#define pIFR3 0x130
+#define pIFR4 0x140
+#define pIFR5 0x150
+#define pIFR6 0x160
+
+#define pIER3 0x134
+#define pIER4 0x144
+#define pIER5 0x154
+#define pIER6 0x164
-
/*
* 6522 Versatile Interface Adapter (VIA)
*
* via them as are assorted bits and bobs - eg rtc, adb.
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
#include "via6522.h"
+#include "psc.h"
volatile unsigned char *via1=(unsigned char *)VIABASE;
volatile unsigned char *via2=(unsigned char *)VIABASE2;
+volatile unsigned char *psc=(unsigned char *)PSCBASE;
unsigned char via1_clock, via1_datab;
static int rbv=0;
+static int oss=0;
+
+extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
/*
- * Debugging the VBL ints
+ * hardware reset vector
*/
-
-extern int console_loglevel;
+static void (*rom_reset)(void);
/*
- * VIA1 - hardwired vectors
+ * Timer defs.
*/
-
-#if 0 /* gone to macints.[ch] */
-extern void via_wtf(int slot, void *via, struct pt_regs *regs);
-static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs);
-
-extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
-
-static struct via_irq_tab via1_func_tab=
-{
- {
- via_wtf, /* One second interrupt */
- via_wtf, /* Vblank */
- via_wtf, /* ADB data ready */
- via_wtf, /* ADB data */
- via_wtf, /* ADB clock */
- via_wtf,
- via_wtf, /* Slot 6 is replaced by the timer */
- via_wtf
- }
-};
-
-static struct via_irq_tab via2_func_tab=
-{
- {
- via_wtf,
- via_do_nubus,
- via_wtf,
- via_wtf,
- via_wtf,
- via_wtf,
- via_wtf,
- via_wtf
- }
-};
-
-static struct via_irq_tab nubus_func_tab=
-{
- {
- via_wtf,
- via_wtf,
- via_wtf,
- via_wtf,
- via_wtf,
- via_wtf,
- via_wtf,
- via_wtf
- }
-};
-#endif
-
-extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
-
#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */
#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
{
unsigned char c;
-/* mac_debugging_penguin(6);*/
-
switch(macintosh_config->via_type)
{
/*
via1=(void *)0x50F00000;
via2=(void *)0x50F26000;
rbv=1;
+ if (macintosh_config->ident == MAC_MODEL_IIFX) {
+ via2=(void *)0x50F1A000;
+ oss=1;
+ }
break;
/*
* Quadra and early MacIIs agree on the VIA locations
via_write(via2,vT2CH,0);
via_write(via2,vIER, 0x7F);
}
- else
+ else if (oss==0)
{
/*
* Init the RBV chip a bit
request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
-/* mac_debugging_penguin(7);*/
-
/*
* SE/30: disable video int.
* XXX: testing for SE/30 VBL
*/
- if (macintosh_config->ident == MAC_MODEL_SE30
- && console_loglevel != 10) {
+ if (macintosh_config->ident == MAC_MODEL_SE30) {
c = via_read(via1, vBufB);
via_write(via1, vBufB, c|(0x40));
c = via_read(via1, vDirB);
via_write(via1, vDirB, c|(0x40));
}
- /*
- * XXX: use positive edge
- */
-
- if (console_loglevel == 10) {
- c = via_read(via1, vPCR);
- via_write(via1, vPCR, c|(0x1));
- }
-
#if 0 /* gone to mac_init_IRQ */
/*
* Set vPCR for SCSI interrupts.
}
-#if 0 /* moved to macints.c */
-
-static void via_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
- struct pt_regs *regs)
-{
- unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
- int i;
- int ct=0;
-
- /*
- * Shouldnt happen
- */
-
- if(events==0)
- {
- printk("via_irq: nothing pending!\n");
- return;
- }
-
- do {
- /*
- * Clear the pending flag
- */
-
- /* HACK HACK - FIXME !!! - just testing some keyboard ideas */
-
- /* events&=~(1<<4); */
- via_write(via, vIFR, events);
-
- /*
- * Now see what bits are raised
- */
-
- for(i=0;i<7;i++)
- {
- if(events&(1<<i))
- (irqtab->vector[i])(i, via, regs);
- }
-
- /*
- * And done..
- */
- events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
- ct++;
- if(events && ct>8)
- {
- printk("via: stuck events %x\n",events);
- break;
- }
- }
- while(events);
-
- scsi_mac_polled();
-}
-
-/*
- *
- * The RBV is different. RBV appears to stand for randomly broken
- * VIA.
- */
-
-static void rbv_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
- struct pt_regs *regs)
-{
- unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
- int i;
- int ct=0;
-
- /*
- * Shouldnt happen
- */
-
- if(events==0)
- {
- printk("rbv_irq: nothing pending!\n");
- return;
- }
-
- do {
- /*
- * Clear the pending flag
- */
-
- /* HACK HACK - FIXME !!! - just testing some keyboard ideas */
-
- /* events&=~(1<<4); */
- via_write(via, rIFR, events);
-
- /*
- * Now see what bits are raised
- */
-
- for(i=0;i<7;i++)
- {
- if(events&(1<<i))
- (irqtab->vector[i])(i, via, regs);
- }
-
- /*
- * And done..
- */
- events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
- ct++;
- if(events && ct>8)
- {
- printk("rbv: stuck events %x\n",events);
- for(i=0;i<7;i++)
- {
- if(events&(1<<i))
- {
- printk("rbv - bashing source %d\n",
- i);
- via_write(via, rIER, i);
- via_write(via, rIFR, i);
- }
- }
- break;
- }
- }
- while(events);
-}
-
-/*
- * System interrupts
- */
-
-void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- via_irq(via1, &via1_func_tab, regs);
-}
-
-/*
- * Nubus interrupts
- */
-
-void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-/* printk("via2 interrupt\n");*/
- if(rbv)
- rbv_irq(via2, &via2_func_tab, regs);
- else
- via_irq(via2, &via2_func_tab, regs);
-}
-
/*
- * Unexpected via interrupt
+ * PSC (AV Macs; level 3-6): initialize interrupt enable registers
*/
-
-void via_wtf(int slot, volatile void *via, struct pt_regs *regs)
-{
- printk("Unexpected event %d on via %p\n",slot,via);
-}
-void nubus_wtf(int slot, volatile void *via, struct pt_regs *regs)
+void psc_init(void)
{
- printk("Unexpected interrupt on nubus slot %d\n",slot);
+ via_write(psc, pIER3, 0x01);
+ via_write(psc, pIER4, 0x09);
+ via_write(psc, pIER4, 0x86);
+ via_write(psc, pIER5, 0x03);
+ via_write(psc, pIER6, 0x07);
}
-#endif
-
/*
* The power switch - yes its software!
*/
-void mac_reset(void)
+void mac_poweroff(void)
{
+#if 0
+ /*
+ * Powerdown, for the Macs that support it
+ */
if(rbv) {
via_write(via2, rBufB, via_read(via2, rBufB)&~0x04);
} else {
/* Send a value of 0 on that line */
via_write(via2,vBufB,via_read(via2,vBufB)&~0x04);
}
+#endif
+ /* We should never make it this far... */
+ /* XXX - delay do we need to spin here ? */
+ while(1); /* Just in case .. */
+}
+
+/*
+ * Not all Macs support software power down; for the rest, just
+ * try the ROM reset vector ...
+ */
+void mac_reset(void)
+{
+ unsigned long flags;
+ unsigned long *reset_hook;
+
+ save_flags(flags);
+ cli();
+
+#if 0 /* need ROMBASE in booter */
+#if 0 /* works on some */
+ rom_reset = (boot_info.bi_mac.rombase + 0xa);
+#else /* testing, doesn't work on SE/30 either */
+ reset_hook = (unsigned long *) (boot_info.bi_mac.rombase + 0x4);
+ printk("ROM reset hook: %p\n", *reset_hook);
+ rom_reset = *reset_hook;
+#endif
+ rom_reset();
+#endif
+ restore_flags(flags);
+
/* We never make it this far... */
+ printk(" reboot failed, reboot manually!\n");
/* XXX - delay do we need to spin here ? */
while(1); /* Just in case .. */
}
via_write(via1, vBufA, via_read(via1, vBufA)|0x20);
}
-#if 0 /* moved to macints.c */
-
-
-/*
- * Set up the SCSI
- */
-
-void via_scsi_disable(void)
-{
- if (rbv)
- via_write(via2, rIER, (1<<3)|(1<<0));
- else
- via_write(via2, vIER, (1<<3)|(1<<0));
-}
-
-void via_scsi_enable(void)
-{
- if (rbv)
- via_write(via2, rIER, (1<<3)|(1<<0)|0x80);
- else
- via_write(via2, vIER, (1<<3)|(1<<0)|0x80);
-}
-
-void via_scsi_clear(void)
-{
- if (rbv)
- via_write(via2, rIFR, (1<<3)|(1<<0)|0x80);
- volatile unsigned char deep_magic=via_read(via2, vBufB);
- via_scsi_enable();
-}
-
-void via_setup_scsi(void (*handler)(int,volatile void *,struct pt_regs *))
-{
- via2_func_tab.vector[0]=handler; /* SCSI DRQ */
- via2_func_tab.vector[3]=handler; /* SCSI IRQ */
- via_write(via2, vPCR, 0x66); /* Edge direction! */
- via_scsi_enable();
-}
-
-/*
- * Nubus handling
- */
-
-static int nubus_active=0;
-
-int nubus_request_irq(int slot, void (*handler)(int,void *,struct pt_regs *))
-{
- slot-=9;
-/* printk("Nubus request irq for slot %d\n",slot);*/
- if(nubus_func_tab.vector[slot]==nubus_wtf)
- return -EBUSY;
- nubus_func_tab.vector[slot]=handler;
- nubus_active|=1<<slot;
-/* printk("program slot %d\n",slot);*/
-/* printk("via2=%p\n",via2);*/
-#if 0
- via_write(via2, vDirA,
- via_read(via2, vDirA)|(1<<slot));
- via_write(via2, vBufA, 0);
-#endif
- if (!rbv) {
- /* Make sure the bit is an input */
- via_write(via2, vDirA,
- via_read(via2, vDirA)&~(1<<slot));
- }
-/* printk("nubus irq on\n");*/
- return 0;
-}
-
-int nubus_free_irq(int slot)
-{
- slot-=9;
- nubus_active&=~(1<<slot);
- nubus_func_tab.vector[slot]=nubus_wtf;
- if (rbv) {
- via_write(via2, rBufA, 1<<slot);
- } else {
- via_write(via2, vDirA,
- via_read(via2, vDirA)|(1<<slot));
- via_write(via2, vBufA, 1<<slot);
- via_write(via2, vDirA,
- via_read(via2, vDirA)&~(1<<slot));
- }
- return 0;
-}
-
-static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs)
-{
- unsigned char map;
- int i;
- int ct=0;
-
-/* printk("nubus interrupt\n");*/
-
- if (rbv) {
- via_write(via2, rIFR, 0x82); /* lock the nubus interrupt */
- } else {
- via_write(via2, vIFR, 0x82); /* lock the nubus interrupt */
-
- while(1)
- {
- if(rbv)
- map=~via_read(via2, rBufA);
- else
- map=~via_read(via2, vBufA);
- if((map=(map&nubus_active))==0)
- break;
- if(ct++>2)
- {
- printk("nubus stuck events - %d/%d\n", map, nubus_active);
- return;
- }
- for(i=0;i<7;i++)
- {
- if(map&(1<<i))
- {
- (nubus_func_tab.vector[i])(i+9, via, regs);
- }
- }
- if (rbv)
- via_write(via2, rIFR, 0x02); /* clear it */
- else
- via_write(via2, vIFR, 0x02); /* clear it */
- }
-
- /* And done */
-}
-#endif
-
void nubus_init_via(void)
{
if (rbv) {
- via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
- via_write(via2, rIER, 0x82); /* Interrupts on */
+ if (oss==0) {
+ via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
+ via_write(via2, rIER, 0x82); /* Interrupts on */
+ }
} else {
/* Assert the nubus active */
via_write(via2, vDirB, via_read(via2, vDirB)|0x02);
/* via_write(via2, vDirA, 0xFF); */
via_write(via2, vIER, 0x82); /* Interrupts on */
}
- printk("BTW boot via1 acr=%X datab=%X pcr=%X\n",
- (int)via1_clock, (int)via1_datab, (int)via_read(via1, vPCR));
-}
+ printk("nubus_init_via: via1 acr=%X datab=%X pcr=%X\n",
+ (int)via_read(via1, vACR), (int)via_read(via1, vBufB),
+ (int)via_read(via1, vPCR));
+
+ if (rbv==0)
+ printk("nubus_init_via: via2 acr=%X datab=%X pcr=%X\n",
+ (int)via_read(via2, vACR), (int)via_read(via2, vBufB),
+ (int)via_read(via2, vPCR));
+}
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := mm.o
-O_OBJS := init.o fault.o memory.o kmap.o extable.o
+O_OBJS := init.o fault.o memory.o kmap.o extable.o hwtest.o
include $(TOPDIR)/Rules.make
vma = find_vma(mm, address);
if (!vma)
goto bad_area;
+ if (vma->vm_flags & VM_IO)
+ goto bad_area;
if (vma->vm_start <= address)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
--- /dev/null
+/* Tests for presence or absence of hardware registers.
+ * This code was originally in atari/config.c, but I noticed
+ * that it was also in drivers/nubus/nubus.c and I wanted to
+ * use it in hp300/config.c, so it seemed sensible to pull it
+ * out into its own file.
+ *
+ * The test is for use when trying to read a hardware register
+ * that isn't present would cause a bus error. We set up a
+ * temporary handler so that this doesn't kill the kernel.
+ *
+ * There is a test-by-reading and a test-by-writing; I present
+ * them here complete with the comments from the original atari
+ * config.c...
+ * -- PMM <pmaydell@chiark.greenend.org.uk>, 05/1998
+ */
+
+/* This function tests for the presence of an address, specially a
+ * hardware register address. It is called very early in the kernel
+ * initialization process, when the VBR register isn't set up yet. On
+ * an Atari, it still points to address 0, which is unmapped. So a bus
+ * error would cause another bus error while fetching the exception
+ * vector, and the CPU would do nothing at all. So we needed to set up
+ * a temporary VBR and a vector table for the duration of the test.
+ */
+
+int hwreg_present( volatile void *regp )
+{
+ int ret = 0;
+ long save_sp, save_vbr;
+ long tmp_vectors[3];
+
+ __asm__ __volatile__
+ ( "movec %/vbr,%2\n\t"
+ "movel #Lberr1,%4@(8)\n\t"
+ "movec %4,%/vbr\n\t"
+ "movel %/sp,%1\n\t"
+ "moveq #0,%0\n\t"
+ "tstb %3@\n\t"
+ "nop\n\t"
+ "moveq #1,%0\n"
+ "Lberr1:\n\t"
+ "movel %1,%/sp\n\t"
+ "movec %2,%/vbr"
+ : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+ : "a" (regp), "a" (tmp_vectors)
+ );
+
+ return( ret );
+}
+
+/* Basically the same, but writes a value into a word register, protected
+ * by a bus error handler. Returns 1 if successful, 0 otherwise.
+ */
+
+int hwreg_write( volatile void *regp, unsigned short val )
+{
+ int ret;
+ long save_sp, save_vbr;
+ long tmp_vectors[3];
+
+ __asm__ __volatile__
+ ( "movec %/vbr,%2\n\t"
+ "movel #Lberr2,%4@(8)\n\t"
+ "movec %4,%/vbr\n\t"
+ "movel %/sp,%1\n\t"
+ "moveq #0,%0\n\t"
+ "movew %5,%3@\n\t"
+ "nop \n\t" /* If this nop isn't present, 'ret' may already be
+ * loaded with 1 at the time the bus error
+ * happens! */
+ "moveq #1,%0\n"
+ "Lberr2:\n\t"
+ "movel %1,%/sp\n\t"
+ "movec %2,%/vbr"
+ : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
+ : "a" (regp), "a" (tmp_vectors), "g" (val)
+ );
+
+ return( ret );
+}
+
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void init_kpointer_table(void);
extern void show_net_buffers(void);
-extern const char PgtabStr_bad_pmd[];
-
-struct pgtable_cache_struct quicklists;
-
-void __bad_pte(pmd_t *pmd)
-{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- pmd_set(pmd, BAD_PAGETABLE);
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
- pte_t *pte;
-
- pte = (pte_t *) __get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (pte) {
- memset(pte, 0, PAGE_SIZE)
- flush_page_to_ram((unsigned long)pte);
- flush_tlb_kernel_page((unsigned long)pte);
- nocache_page((unsigned long)pte);
- pmd_set(pmd, pte);
- return pte + offset;
- }
- pmd_set(pmd, BAD_PAGETABLE);
- return NULL;
- }
- free_page((unsigned long)pte);
- if (pmd_bad(*pmd)) {
- __bad_pte(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + offset;
-}
/*
* BAD_PAGE is the page that is used for page faults when linux
total++;
if (PageReserved(mem_map+i))
reserved++;
- else if (PageSwapCache(mem_map+i))
+ if (PageSwapCache(mem_map+i))
cached++;
else if (!atomic_read(&mem_map[i].count))
free++;
printk("%d pages nonshared\n",nonshared);
printk("%d pages shared\n",shared);
printk("%d pages swap cached\n",cached);
- printk("%d pages in page table cache\n",pgtable_cache_size);
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
*/
for (i = 0; i < 64; i++) {
pte_val(ktablep[i]) = physaddr | _PAGE_PRESENT
- | _PAGE_CACHE040 | _PAGE_GLOBAL040
+ | m68k_supervisor_cachemode | _PAGE_GLOBAL040
| _PAGE_ACCESSED;
physaddr += PAGE_SIZE;
}
* Copyright (C) 1995 Hamish Macdonald
*/
+#include <linux/config.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/traps.h>
+#ifdef CONFIG_AMIGA
#include <asm/amigahw.h>
+#endif
/* Strings for `extern inline' functions in <asm/pgtable.h>. If put
directly into these functions, they are output for every file that
*
*/
+#ifdef CONFIG_AMIGA
/*
* if on an amiga and address is in first 16M, move it
* to the ZTWO_VADDR range
*/
if (MACH_IS_AMIGA && paddr < 16*1024*1024)
return ZTWO_VADDR(paddr);
+#endif
return paddr;
}
static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp)
{
- panic ("Unknown interrupt 0x%02x", irq);
+ printk ("Unknown interrupt 0x%02x\n", irq);
}
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := mvme16x.o
-O_OBJS := config.o 16xints.o
+O_OBJS := config.o 16xints.o rtc.o
#OX_OBJS = ksyms.o
include $(TOPDIR)/Rules.make
#include <asm/machdep.h>
#include <asm/mvme16xhw.h>
-typedef struct {
- unsigned char
- ctrl,
- bcd_sec,
- bcd_min,
- bcd_hr,
- bcd_dow,
- bcd_dom,
- bcd_mth,
- bcd_year;
-} MK48T08;
-
-#define RTC_WRITE 0x80
-#define RTC_READ 0x40
-#define RTC_STOP 0x20
-
int atari_SCC_reset_done = 1; /* So SCC doesn't get reset */
u_long atari_mch_cookie = 0;
-MK48T08 * volatile rtc = (MK48T08 *)0xfffc1ff8;
+static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
extern void mvme16x_process_int (int level, struct pt_regs *regs);
extern void mvme16x_init_IRQ (void);
}
+#define pcc2chip ((volatile u_char *)0xfff42000)
+#define PccSCCMICR 0x1d
+#define PccSCCTICR 0x1e
+#define PccSCCRICR 0x1f
+
__initfunc(void config_mvme16x(void))
{
p_bdid p = (p_bdid)mvme_bdid_ptr;
rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : "");
}
else
+ {
mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401;
+
+ /* Dont allow any interrupts from the CD2401 until the interrupt */
+ /* handlers are installed */
+
+ pcc2chip[PccSCCMICR] = 0x10;
+ pcc2chip[PccSCCTICR] = 0x10;
+ pcc2chip[PccSCCRICR] = 0x10;
+ }
+}
+
+static void mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+ p_bdid p = (p_bdid)mvme_bdid_ptr;
+ unsigned long *new = (unsigned long *)vectors;
+ unsigned long *old = (unsigned long *)0xffe00000;
+ volatile unsigned char uc, *ucp;
+
+ if (p->brdno == 0x0162 || p->brdno == 0x172)
+ {
+ ucp = (volatile unsigned char *)0xfff42043;
+ uc = *ucp | 8;
+ *ucp = uc;
+ }
+ else
+ {
+ *(volatile unsigned long *)0xfff40074 = 0x40000000;
+ }
+ *(new+4) = *(old+4); /* Illegal instruction */
+ *(new+9) = *(old+9); /* Trace */
+ *(new+47) = *(old+47); /* Trap #15 */
+
+ if (p->brdno == 0x0162 || p->brdno == 0x172)
+ *(new+0x5e) = *(old+0x5e); /* ABORT switch */
+ else
+ *(new+0x6e) = *(old+0x6e); /* ABORT switch */
}
static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
void mvme16x_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
{
+ p_bdid p = (p_bdid)mvme_bdid_ptr;
+ int irq;
+
tick_handler = timer_routine;
/* Using PCCchip2 or MC2 chip tick timer 1 */
*(volatile unsigned long *)0xfff42008 = 0;
*(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */
*(volatile unsigned char *)0xfff42017 |= 3;
*(volatile unsigned char *)0xfff4201b = 0x16;
- if (request_irq(IRQ_MVME16x_TIMER, mvme16x_timer_int, 0,
+ if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0,
"timer", mvme16x_timer_int))
panic ("Couldn't register timer int");
+
+ if (p->brdno == 0x0162 || p->brdno == 0x172)
+ irq = MVME162_IRQ_ABORT;
+ else
+ irq = MVME167_IRQ_ABORT;
+ if (request_irq(irq, mvme16x_abort_int, 0,
+ "abort", mvme16x_abort_int))
+ panic ("Couldn't register abort int");
}
return 0;
}
-/*
- * console_map_init(), here to avoid having to modify drivers/block/genhd.c
- */
-
-void console_map_init(void)
-{
-}
-
-/*
- * fbmem_init(), here to avoid having to modify drivers/char/mem.c
- */
-
-void fbmem_init(void)
-{
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-unsigned long con_init(unsigned long kmem_start)
-{
- return (kmem_start);
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-int vcs_init(void)
-{
- return (0);
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-int kbd_init(void)
-{
- return (0);
-}
-
-/* Avoid mods to init/main.c */
-
-void no_scroll(char *str, int *ints)
-{
-}
-
-/* Avoid mods to kernel/panic.c */
-
-void do_unblank_screen(void)
-{
-}
-
int mvme16x_keyb_init (void)
{
return 0;
}
-void mvme16x_set_vectors (void)
-{
- p_bdid p = (p_bdid)mvme_bdid_ptr;
- unsigned long *new = (unsigned long *)vectors;
- unsigned long *old = (unsigned long *)0xffe00000;;
-
- *(new+4) = *(old+4); /* Illegal instruction */
- *(new+9) = *(old+9); /* Trace */
- *(new+47) = *(old+47); /* Trap #15 */
-
- if (p->brdno == 0x0162 || p->brdno == 0x172)
- *(new+0x5e) = *(old+0x5e); /* ABORT switch */
- else
- *(new+0x6e) = *(old+0x6e); /* ABORT switch */
-}
-
/*------------------- Serial console stuff ------------------------*/
extern void mvme167_serial_console_setup(int cflag);
static void scc_write (char ch)
{
- volatile char *p = (volatile char *)SCC_A_ADDR;
+ volatile char *p = (volatile char *)MVME_SCC_A_ADDR;
do {
scc_delay();
--- /dev/null
+/*
+ * Real Time Clock interface for Linux on the MVME16x
+ *
+ * Based on the PC driver by Paul Gortmaker.
+ */
+
+#define RTC_VERSION "1.00"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
+#include <asm/mvme16xhw.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/setup.h>
+
+/*
+ * We sponge a minor off of the misc major. No need slurping
+ * up another valuable major dev number for this. If you add
+ * an ioctl, make sure you don't conflict with SPARC's RTC
+ * ioctls.
+ */
+
+#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char rtc_status = 0;
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ volatile MK48T08ptr_t rtc = (MK48T08ptr_t)MVME_RTC_BASE;
+ unsigned long flags;
+ struct rtc_time wtime;
+
+ switch (cmd) {
+ case RTC_RD_TIME: /* Read the time/date from RTC */
+ {
+ save_flags(flags);
+ cli();
+ /* Ensure clock and real-time-mode-register are accessible */
+ rtc->ctrl = RTC_READ;
+ wtime.tm_sec = BCD2BIN(rtc->bcd_sec);
+ wtime.tm_min = BCD2BIN(rtc->bcd_min);
+ wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
+ wtime.tm_mday = BCD2BIN(rtc->bcd_dom);
+ wtime.tm_mon = BCD2BIN(rtc->bcd_mth)-1;
+ wtime.tm_year = BCD2BIN(rtc->bcd_year);
+ if (wtime.tm_year < 70)
+ wtime.tm_year += 100;
+ wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+ rtc->ctrl = 0;
+ restore_flags(flags);
+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
+ -EFAULT : 0;
+ }
+ case RTC_SET_TIME: /* Set the RTC */
+ {
+ unsigned char leap_yr;
+ struct rtc_time rtc_tm;
+
+ if (!suser())
+ return -EACCES;
+
+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+
+ leap_yr = ((!(rtc_tm.tm_year % 4) && (rtc_tm.tm_year % 100)) || !(rtc_tm.tm_year % 400));
+
+ if ((rtc_tm.tm_mon > 12) || (rtc_tm.tm_mday == 0))
+ return -EINVAL;
+
+ if (rtc_tm.tm_mday > (days_in_mo[rtc_tm.tm_mon] + ((rtc_tm.tm_mon == 2) && leap_yr)))
+ return -EINVAL;
+
+ if ((rtc_tm.tm_hour >= 24) || (rtc_tm.tm_min >= 60) || (rtc_tm.tm_sec >= 60))
+ return -EINVAL;
+
+ save_flags(flags);
+ cli();
+ rtc->ctrl = RTC_WRITE;
+
+ rtc->bcd_sec = BIN2BCD(rtc_tm.tm_sec);
+ rtc->bcd_min = BIN2BCD(rtc_tm.tm_min);
+ rtc->bcd_hr = BIN2BCD(rtc_tm.tm_hour);
+ rtc->bcd_dom = BIN2BCD(rtc_tm.tm_mday);
+ rtc->bcd_mth = BIN2BCD(rtc_tm.tm_mon + 1);
+ rtc->bcd_year = BIN2BCD(rtc_tm.tm_year%100);
+ if (rtc_tm.tm_wday >= 0)
+ rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+
+ rtc->ctrl = 0;
+ restore_flags(flags);
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * We enforce only one user at a time here with the open/close.
+ * Also clear the previous interrupt data on an open, and clean
+ * up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ if(rtc_status)
+ return -EBUSY;
+
+ rtc_status = 1;
+ return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+ rtc_status = 0;
+ return 0;
+}
+
+/*
+ * The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+ NULL,
+ NULL,
+ NULL, /* No write */
+ NULL, /* No readdir */
+ NULL,
+ rtc_ioctl,
+ NULL, /* No mmap */
+ rtc_open,
+ rtc_release
+};
+
+static struct miscdevice rtc_dev=
+{
+ RTC_MINOR,
+ "rtc",
+ &rtc_fops
+};
+
+__initfunc(int rtc_MK48T08_init(void))
+{
+ if (!MACH_IS_MVME16x)
+ return -ENODEV;
+
+ printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
+ misc_register(&rtc_dev);
+ return 0;
+}
+
asmlinkage int sys_getdomainname(char *name, int len)
{
- int nlen = strlen(system_utsname.domainname);
+ int nlen;
+ int err = -EFAULT;
+
+ down(&uts_sem);
+
+ nlen = strlen(system_utsname.domainname);
if (nlen < len)
len = nlen;
if(len > __NEW_UTS_LEN)
- return -EFAULT;
+ goto done
if(copy_to_user(name, system_utsname.domainname, len))
- return -EFAULT;
- return 0;
+ goto done;
+ err=0;
+done:
+ up(&uts_sem);
+ return err;
}
case IDE4_MAJOR:
case IDE5_MAJOR:
case ACSI_MAJOR:
+ case MFM_ACORN_MAJOR:
/*
* The scsi disk and cdrom drivers completely remove the request
* from the queue when they start processing an entry. For this
#ifdef CONFIG_BLK_DEV_XD
xd_init();
#endif
+#ifdef CONFIG_BLK_DEV_MFM
+ mfm_init();
+#endif
#ifdef CONFIG_PARIDE
{ extern void paride_init(void); paride_init(); };
#endif
dep_tristate ' Parallel port ATAPI CD-ROMs' CONFIG_PARIDE_PCD $CONFIG_PARIDE
dep_tristate ' Parallel port ATAPI disks' CONFIG_PARIDE_PF $CONFIG_PARIDE
dep_tristate ' Parallel port ATAPI tapes' CONFIG_PARIDE_PT $CONFIG_PARIDE
+dep_tristate ' Parallel port generic ATAPI devices' CONFIG_PARIDE_PG $CONFIG_PARIDE
comment 'Parallel IDE protocol modules'
dep_tristate ' ATEN EH-100 protocol' CONFIG_PARIDE_ATEN $CONFIG_PARIDE
dep_tristate ' MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE
dep_tristate ' DataStor Commuter protocol' CONFIG_PARIDE_COMM $CONFIG_PARIDE
dep_tristate ' DataStor EP-2000 protocol' CONFIG_PARIDE_DSTR $CONFIG_PARIDE
dep_tristate ' FIT TD-2000 protocol' CONFIG_PARIDE_FIT2 $CONFIG_PARIDE
+dep_tristate ' FIT TD-3000 protocol' CONFIG_PARIDE_FIT3 $CONFIG_PARIDE
dep_tristate ' Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
dep_tristate ' Shuttle EPIA protocol' CONFIG_PARIDE_EPIA $CONFIG_PARIDE
dep_tristate ' FreeCom power protocol' CONFIG_PARIDE_FRPW $CONFIG_PARIDE
endif
endif
+ifeq ($(CONFIG_PARIDE_PG),y)
+ LX_OBJS += pg.o
+else
+ ifeq ($(CONFIG_PARIDE_PG),m)
+ MX_OBJS += pg.o
+ endif
+endif
+
ifeq ($(CONFIG_PARIDE_ATEN),y)
LX_OBJS += aten.o
else
endif
endif
+ifeq ($(CONFIG_PARIDE_FIT3),y)
+ LX_OBJS += fit3.o
+else
+ ifeq ($(CONFIG_PARIDE_FIT3),m)
+ MX_OBJS += fit3.o
+ endif
+endif
+
ifeq ($(CONFIG_PARIDE_FRPW),y)
LX_OBJS += frpw.o
else
--- /dev/null
+/*
+ fit3.c (c) 1998 Grant R. Guenther <grant@torque.net>
+ Under the terms of the GNU public license.
+
+ fit3.c is a low-level protocol driver for newer models
+ of the Fidelity International Technology parallel port adapter.
+ This adapter is used in their TransDisk 3000 portable
+ hard-drives, as well as CD-ROM, PD-CD and other devices.
+
+ The TD-2000 and certain older devices use a different protocol.
+ Try the fit2 protocol module with them.
+
+ NB: The FIT adapters do not appear to support the control
+ registers. So, we map ALT_STATUS to STATUS and NO-OP writes
+ to the device control register - this means that IDE reset
+ will not work on these devices.
+
+*/
+
+#define FIT3_VERSION "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define j44(a,b) (((a>>3)&0x0f)|((b<<1)&0xf0))
+
+#define w7(byte) {out_p(7,byte);}
+#define r7() (in_p(7) & 0xff)
+
+/* cont = 0 - access the IDE register file
+ cont = 1 - access the IDE command set
+
+*/
+
+static void fit3_write_regr( PIA *pi, int cont, int regr, int val)
+
+{ if (cont == 1) return;
+
+ switch (pi->mode) {
+
+ case 0:
+ case 1: w2(0xc); w0(regr); w2(0x8); w2(0xc);
+ w0(val); w2(0xd);
+ w0(0); w2(0xc);
+ break;
+
+ case 2: w2(0xc); w0(regr); w2(0x8); w2(0xc);
+ w4(val); w4(0);
+ w2(0xc);
+ break;
+
+ }
+}
+
+static int fit3_read_regr( PIA *pi, int cont, int regr )
+
+{ int a, b;
+
+ if (cont) {
+ if (regr != 6) return 0xff;
+ regr = 7;
+ }
+
+ switch (pi->mode) {
+
+ case 0: w2(0xc); w0(regr + 0x10); w2(0x8); w2(0xc);
+ w2(0xd); a = r1();
+ w2(0xf); b = r1();
+ w2(0xc);
+ return j44(a,b);
+
+ case 1: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc);
+ w2(0xec); w2(0xee); w2(0xef); a = r0();
+ w2(0xc);
+ return a;
+
+ case 2: w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc);
+ w2(0xec);
+ a = r4(); b = r4();
+ w2(0xc);
+ return a;
+
+ }
+ return -1;
+
+}
+
+static void fit3_read_block( PIA *pi, char * buf, int count )
+
+{ int k, a, b, c, d;
+
+ switch (pi->mode) {
+
+ case 0: w2(0xc); w0(0x10); w2(0x8); w2(0xc);
+ for (k=0;k<count/2;k++) {
+ w2(0xd); a = r1();
+ w2(0xf); b = r1();
+ w2(0xc); c = r1();
+ w2(0xe); d = r1();
+ buf[2*k ] = j44(a,b);
+ buf[2*k+1] = j44(c,d);
+ }
+ w2(0xc);
+ break;
+
+ case 1: w2(0xc); w0(0x90); w2(0x8); w2(0xc);
+ w2(0xec); w2(0xee);
+ for (k=0;k<count/2;k++) {
+ w2(0xef); a = r0();
+ w2(0xee); b = r0();
+ buf[2*k ] = a;
+ buf[2*k+1] = b;
+ }
+ w2(0xec);
+ w2(0xc);
+ break;
+
+ case 2: w2(0xc); w0(0x90); w2(0x8); w2(0xc);
+ w2(0xec);
+ for (k=0;k<count;k++) buf[k] = r4();
+ w2(0xc);
+ break;
+
+ }
+}
+
+static void fit3_write_block( PIA *pi, char * buf, int count )
+
+{ int k;
+
+ switch (pi->mode) {
+
+ case 0:
+ case 1: w2(0xc); w0(0); w2(0x8); w2(0xc);
+ for (k=0;k<count/2;k++) {
+ w0(buf[2*k ]); w2(0xd);
+ w0(buf[2*k+1]); w2(0xc);
+ }
+ break;
+
+ case 2: w2(0xc); w0(0); w2(0x8); w2(0xc);
+ for (k=0;k<count;k++) w4(buf[k]);
+ w2(0xc);
+ break;
+ }
+}
+
+static void fit3_connect ( PIA *pi )
+
+{ pi->saved_r0 = r0();
+ pi->saved_r2 = r2();
+ w2(0xc); w0(0); w2(0xa);
+ if (pi->mode == 2) {
+ w2(0xc); w0(0x9); w2(0x8); w2(0xc);
+ }
+}
+
+static void fit3_disconnect ( PIA *pi )
+
+{ w2(0xc); w0(0xa); w2(0x8); w2(0xc);
+ w0(pi->saved_r0);
+ w2(pi->saved_r2);
+}
+
+static void fit3_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{ char *mode_string[3] = {"4-bit","8-bit","EPP"};
+
+ printk("%s: fit3 %s, FIT 3000 adapter at 0x%x, "
+ "mode %d (%s), delay %d\n",
+ pi->device,FIT3_VERSION,pi->port,
+ pi->mode,mode_string[pi->mode],pi->delay);
+
+}
+
+static void fit3_init_proto(PIA *pi)
+
+{ MOD_INC_USE_COUNT;
+}
+
+static void fit3_release_proto(PIA *pi)
+
+{ MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol fit3 = {"fit3",0,3,2,1,1,
+ fit3_write_regr,
+ fit3_read_regr,
+ fit3_write_block,
+ fit3_read_block,
+ fit3_connect,
+ fit3_disconnect,
+ 0,
+ 0,
+ 0,
+ fit3_log_adapter,
+ fit3_init_proto,
+ fit3_release_proto
+ };
+
+
+#ifdef MODULE
+
+int init_module(void)
+
+{ return pi_register( &fit3 ) - 1;
+}
+
+void cleanup_module(void)
+
+{ pi_unregister( &fit3 );
+}
+
+#endif
+
+/* end of fit3.c */
#
# mkd -- a script to create the device special files for the PARIDE subsystem
#
+# block devices: pd (45), pcd (46), pf (47)
+# character devices: pt (96), pg (97)
+#
function mkdev {
mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
}
for u in 0 1 2 3 ; do mkdev pf$u b 47 $u ; done
for u in 0 1 2 3 ; do mkdev pt$u c 96 $u ; done
for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done
+for u in 0 1 2 3 ; do mkdev pg$u c 97 $u ; done
#
# end of mkd
+
pi_register(&fit2);
};
#endif
+#ifdef CONFIG_PARIDE_FIT3
+ { extern struct pi_protocol fit3;
+ pi_register(&fit3);
+ };
+#endif
#ifdef CONFIG_PARIDE_KBIC
{ extern struct pi_protocol k951;
extern struct pi_protocol k971;
#define PI_PCD 1 /* ATAPI CDrom */
#define PI_PF 2 /* ATAPI disk */
#define PI_PT 3 /* ATAPI tape */
+#define PI_PG 4 /* ATAPI generic */
/* The paride module contains no state, instead the drivers allocate
a pi_adapter data structure and pass it to paride in every operation.
--- /dev/null
+/*
+ pg.c (c) 1998 Grant R. Guenther <grant@torque.net>
+ Under the terms of the GNU public license.
+
+ The pg driver provides a simple character device interface for
+ sending ATAPI commands to a device. With the exception of the
+ ATAPI reset operation, all operations are performed by a pair
+ of read and write operations to the appropriate /dev/pgN device.
+ A write operation delivers a command and any outbound data in
+ a single buffer. Normally, the write will succeed unless the
+ device is offline or malfunctioning, or there is already another
+ command pending. If the write succeeds, it should be followed
+ immediately by a read operation, to obtain any returned data and
+ status information. A read will fail if there is no operation
+ in progress.
+
+ As a special case, the device can be reset with a write operation,
+ and in this case, no following read is expected, or permitted.
+
+ There are no ioctl() operations. Any single operation
+ may transfer at most PG_MAX_DATA bytes. Note that the driver must
+ copy the data through an internal buffer. In keeping with all
+ current ATAPI devices, command packets are assumed to be exactly
+ 12 bytes in length.
+
+ To permit future changes to this interface, the headers in the
+ read and write buffers contain a single character "magic" flag.
+ Currently this flag must be the character "P".
+
+ By default, the driver will autoprobe for a single parallel
+ port ATAPI device, but if their individual parameters are
+ specified, the driver can handle up to 4 devices.
+
+ To use this device, you must have the following device
+ special files defined:
+
+ /dev/pg0 b 97 0
+ /dev/pg1 b 97 1
+ /dev/pg2 b 97 2
+ /dev/pg3 b 97 3
+
+ (You'll need to change the 97 to something else if you use
+ the 'major' parameter to install the driver on a different
+ major number.)
+
+ The behaviour of the pg driver can be altered by setting
+ some parameters from the insmod command line. The following
+ parameters are adjustable:
+
+ drive0 These four arguments can be arrays of
+ drive1 1-6 integers as follows:
+ drive2
+ drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
+
+ Where,
+
+ <prt> is the base of the parallel port address for
+ the corresponding drive. (required)
+
+ <pro> is the protocol number for the adapter that
+ supports this drive. These numbers are
+ logged by 'paride' when the protocol modules
+ are initialised. (0 if not given)
+
+ <uni> for those adapters that support chained
+ devices, this is the unit selector for the
+ chain of devices on the given port. It should
+ be zero for devices that don't support chaining.
+ (0 if not given)
+
+ <mod> this can be -1 to choose the best mode, or one
+ of the mode numbers supported by the adapter.
+ (-1 if not given)
+
+ <slv> ATAPI devices can be jumpered to master or slave.
+ Set this to 0 to choose the master drive, 1 to
+ choose the slave, -1 (the default) to choose the
+ first drive found.
+
+ <dly> some parallel ports require the driver to
+ go more slowly. -1 sets a default value that
+ should work with the chosen protocol. Otherwise,
+ set this to a small integer, the larger it is
+ the slower the port i/o. In some cases, setting
+ this to zero will speed up the device. (default -1)
+
+ major You may use this parameter to overide the
+ default major number (97) that this driver
+ will use. Be sure to change the device
+ name as well.
+
+ name This parameter is a character string that
+ contains the name the kernel will use for this
+ device (in /proc output, for instance).
+ (default "pg").
+
+ verbose This parameter controls the amount of logging
+ that is done by the driver. Set it to 0 for
+ quiet operation, to 1 to enable progress
+ messages while the driver probes for devices,
+ or to 2 for full debug logging. (default 0)
+
+ If this driver is built into the kernel, you can use
+ the following command line parameters, with the same values
+ as the corresponding module parameters listed above:
+
+ pg.drive0
+ pg.drive1
+ pg.drive2
+ pg.drive3
+
+ In addition, you can use the parameter pg.disable to disable
+ the driver entirely.
+
+*/
+
+#define PG_VERSION "1.0"
+#define PG_MAJOR 97
+#define PG_NAME "pg"
+#define PG_UNITS 4
+
+/* Here are things one can override from the insmod command.
+ Most are autoprobed by paride unless set here. Verbose is 0
+ by default.
+
+*/
+
+static int verbose = 0;
+static int major = PG_MAJOR;
+static char *name = PG_NAME;
+static int disable = 0;
+
+static int drive0[6] = {0,0,0,-1,-1,-1};
+static int drive1[6] = {0,0,0,-1,-1,-1};
+static int drive2[6] = {0,0,0,-1,-1,-1};
+static int drive3[6] = {0,0,0,-1,-1,-1};
+
+static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3};
+static int pg_drive_count;
+
+#define D_PRT 0
+#define D_PRO 1
+#define D_UNI 2
+#define D_MOD 3
+#define D_SLV 4
+#define D_DLY 5
+
+#define DU (*drives[unit])
+
+/* end of parameters */
+
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/mtio.h>
+#include <linux/pg.h>
+
+#include <asm/uaccess.h>
+
+#ifndef MODULE
+
+#include "setup.h"
+
+static STT pg_stt[5] = {{"drive0",6,drive0},
+ {"drive1",6,drive1},
+ {"drive2",6,drive2},
+ {"drive3",6,drive3},
+ {"disable",1,&disable}};
+
+void pg_setup( char *str, int *ints)
+
+{ generic_setup(pg_stt,5,str);
+}
+
+#endif
+
+MODULE_PARM(verbose,"i");
+MODULE_PARM(major,"i");
+MODULE_PARM(name,"s");
+MODULE_PARM(drive0,"1-6i");
+MODULE_PARM(drive1,"1-6i");
+MODULE_PARM(drive2,"1-6i");
+MODULE_PARM(drive3,"1-6i");
+
+#include "paride.h"
+
+#define PG_SPIN_DEL 50 /* spin delay in micro-seconds */
+#define PG_SPIN 200
+#define PG_TMO HZ
+
+#define STAT_ERR 0x01
+#define STAT_INDEX 0x02
+#define STAT_ECC 0x04
+#define STAT_DRQ 0x08
+#define STAT_SEEK 0x10
+#define STAT_WRERR 0x20
+#define STAT_READY 0x40
+#define STAT_BUSY 0x80
+
+#define ATAPI_IDENTIFY 0x12
+
+int pg_init(void);
+#ifdef MODULE
+void cleanup_module( void );
+#endif
+
+static int pg_open(struct inode *inode, struct file *file);
+static int pg_release (struct inode *inode, struct file *file);
+static ssize_t pg_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos);
+static ssize_t pg_write(struct file * filp, const char * buf,
+ size_t count, loff_t *ppos);
+static int pg_detect(void);
+
+static int pg_identify (int unit, int log);
+
+#define PG_NAMELEN 8
+
+struct pg_unit {
+ struct pi_adapter pia; /* interface to paride layer */
+ struct pi_adapter *pi;
+ int busy; /* write done, read expected */
+ int start; /* jiffies at command start */
+ int dlen; /* transfer size requested */
+ int timeout; /* timeout requested */
+ int status; /* last sense key */
+ int drive; /* drive */
+ int access; /* count of active opens ... */
+ int present; /* device present ? */
+ char *bufptr;
+ char name[PG_NAMELEN]; /* pg0, pg1, ... */
+ };
+
+struct pg_unit pg[PG_UNITS];
+
+/* 'unit' must be defined in all functions - either as a local or a param */
+
+#define PG pg[unit]
+#define PI PG.pi
+
+static char pg_scratch[512]; /* scratch block buffer */
+
+/* kernel glue structures */
+
+static struct file_operations pg_fops = {
+ NULL, /* lseek - default */
+ pg_read, /* read */
+ pg_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ pg_open, /* open */
+ pg_release, /* release */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* media change ? */
+ NULL /* revalidate new media */
+};
+
+void pg_init_units( void )
+
+{ int unit, j;
+
+ pg_drive_count = 0;
+ for (unit=0;unit<PG_UNITS;unit++) {
+ PG.pi = & PG.pia;
+ PG.access = 0;
+ PG.busy = 0;
+ PG.present = 0;
+ PG.bufptr = NULL;
+ PG.drive = DU[D_SLV];
+ j = 0;
+ while ((j < PG_NAMELEN-2) && (PG.name[j]=name[j])) j++;
+ PG.name[j++] = '0' + unit;
+ PG.name[j] = 0;
+ if (DU[D_PRT]) pg_drive_count++;
+ }
+}
+
+int pg_init (void) /* preliminary initialisation */
+
+{ int unit;
+
+ if (disable) return -1;
+
+ pg_init_units();
+
+ if (pg_detect()) return -1;
+
+ if (register_chrdev(major,name,&pg_fops)) {
+ printk("pg_init: unable to get major number %d\n",
+ major);
+ for (unit=0;unit<PG_UNITS;unit++)
+ if (PG.present) pi_release(PI);
+ return -1;
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+
+/* Glue for modules ... */
+
+void cleanup_module(void);
+
+int init_module(void)
+
+{ int err;
+ long flags;
+
+ save_flags(flags);
+ cli();
+
+ err = pg_init();
+
+ restore_flags(flags);
+ return err;
+}
+
+void cleanup_module(void)
+
+{ long flags;
+ int unit;
+
+ save_flags(flags);
+ cli();
+
+ unregister_chrdev(major,name);
+
+ for (unit=0;unit<PG_UNITS;unit++)
+ if (PG.present) pi_release(PI);
+
+ restore_flags(flags);
+}
+
+#endif
+
+#define WR(c,r,v) pi_write_regr(PI,c,r,v)
+#define RR(c,r) (pi_read_regr(PI,c,r))
+
+#define DRIVE (0xa0+0x10*PG.drive)
+
+static void pg_sleep( int cs )
+
+{ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + cs;
+ schedule();
+}
+
+static int pg_wait( int unit, int go, int stop, int tmo, char * msg )
+
+{ int j, r, e, s, p;
+
+ PG.status = 0;
+
+ j = 0;
+ while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(jiffies<tmo)) {
+ if (j++ < PG_SPIN) udelay(PG_SPIN_DEL);
+ else pg_sleep(1);
+ }
+
+ if ((r&(STAT_ERR&stop))||(jiffies>=tmo)) {
+ s = RR(0,7);
+ e = RR(0,1);
+ p = RR(0,2);
+ if (verbose > 1)
+ printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n",
+ PG.name,msg,s,e,p,(jiffies>=tmo)?" timeout":"");
+
+
+ if (jiffies>=tmo) e |= 0x100;
+ PG.status = (e >> 4) & 0xff;
+ return -1;
+ }
+ return 0;
+}
+
+static int pg_command( int unit, char * cmd, int dlen, int tmo )
+
+{ int k;
+
+ pi_connect(PI);
+
+ WR(0,6,DRIVE);
+
+ if (pg_wait(unit,STAT_BUSY|STAT_DRQ,0,tmo,"before command")) {
+ pi_disconnect(PI);
+ return -1;
+ }
+
+ WR(0,4,dlen % 256);
+ WR(0,5,dlen / 256);
+ WR(0,7,0xa0); /* ATAPI packet command */
+
+ if (pg_wait(unit,STAT_BUSY,STAT_DRQ,tmo,"command DRQ")) {
+ pi_disconnect(PI);
+ return -1;
+ }
+
+ if (RR(0,2) != 1) {
+ printk("%s: command phase error\n",PG.name);
+ pi_disconnect(PI);
+ return -1;
+ }
+
+ pi_write_block(PI,cmd,12);
+
+ if (verbose > 1) {
+ printk("%s: Command sent, dlen=%d packet= ", PG.name,dlen);
+ for (k=0;k<12;k++) printk("%02x ",cmd[k]&0xff);
+ printk("\n");
+ }
+ return 0;
+}
+
+static int pg_completion( int unit, char * buf, int tmo)
+
+{ int r, s, d, n, p;
+
+ r = pg_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR,
+ tmo,"completion");
+
+ PG.dlen = 0;
+
+ if (RR(0,7)&STAT_DRQ) {
+ d = (RR(0,4)+256*RR(0,5));
+ n = ((d+3)&0xfffc);
+ p = RR(0,2)&3;
+ if (p == 0) pi_write_block(PI,buf,n);
+ if (p == 2) pi_read_block(PI,buf,n);
+ if (verbose > 1) printk("%s: %s %d bytes\n",PG.name,
+ p?"Read":"Write",n);
+ PG.dlen = (1-p)*d;
+ }
+
+ s = pg_wait(unit,STAT_BUSY,STAT_READY|STAT_ERR,tmo,"data done");
+
+ pi_disconnect(PI);
+
+ return (r?r:s);
+}
+
+static int pg_reset( int unit )
+
+{ int i, k, flg;
+ int expect[5] = {1,1,1,0x14,0xeb};
+
+ pi_connect(PI);
+ WR(0,6,DRIVE);
+ WR(0,7,8);
+
+ pg_sleep(2);
+
+ k = 0;
+ while ((k++ < PG_TMO) && (RR(1,6)&STAT_BUSY))
+ pg_sleep(1);
+
+ flg = 1;
+ for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
+
+ if (verbose) {
+ printk("%s: Reset (%d) signature = ",PG.name,k);
+ for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
+ if (!flg) printk(" (incorrect)");
+ printk("\n");
+ }
+
+ pi_disconnect(PI);
+ return flg-1;
+}
+
+static void xs( char *buf, char *targ, int offs, int len )
+
+{ int j,k,l;
+
+ j=0; l=0;
+ for (k=0;k<len;k++)
+ if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
+ l=targ[j++]=buf[k+offs];
+ if (l==0x20) j--; targ[j]=0;
+}
+
+static int pg_identify( int unit, int log )
+
+{ int s;
+ char *ms[2] = {"master","slave"};
+ char mf[10], id[18];
+ char id_cmd[12] = { ATAPI_IDENTIFY,0,0,0,36,0,0,0,0,0,0,0};
+ char buf[36];
+
+ s = pg_command(unit,id_cmd,36,jiffies+PG_TMO);
+ if (s) return -1;
+ s = pg_completion(unit,buf,jiffies+PG_TMO);
+ if (s) return -1;
+
+ if (log) {
+ xs(buf,mf,8,8);
+ xs(buf,id,16,16);
+ printk("%s: %s %s, %s\n",PG.name,mf,id,ms[PG.drive]);
+ }
+
+ return 0;
+}
+
+static int pg_probe( int unit )
+
+/* returns 0, with id set if drive is detected
+ -1, if drive detection failed
+*/
+
+{ if (PG.drive == -1) {
+ for (PG.drive=0;PG.drive<=1;PG.drive++)
+ if (!pg_reset(unit)) return pg_identify(unit,1);
+ } else {
+ if (!pg_reset(unit)) return pg_identify(unit,1);
+ }
+ return -1;
+}
+
+static int pg_detect( void )
+
+{ int k, unit;
+
+ printk("%s: %s version %s, major %d\n",
+ name,name,PG_VERSION,major);
+
+ k = 0;
+ if (pg_drive_count == 0) {
+ unit = 0;
+ if (pi_init(PI,1,-1,-1,-1,-1,-1,pg_scratch,
+ PI_PG,verbose,PG.name)) {
+ if (!pg_probe(unit)) {
+ PG.present = 1;
+ k++;
+ } else pi_release(PI);
+ }
+
+ } else for (unit=0;unit<PG_UNITS;unit++) if (DU[D_PRT])
+ if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
+ DU[D_PRO],DU[D_DLY],pg_scratch,PI_PG,verbose,
+ PG.name)) {
+ if (!pg_probe(unit)) {
+ PG.present = 1;
+ k++;
+ } else pi_release(PI);
+ }
+
+ if (k) return 0;
+
+ printk("%s: No ATAPI device detected\n",name);
+ return -1;
+}
+
+#define DEVICE_NR(dev) (MINOR(dev) % 128)
+
+static int pg_open (struct inode *inode, struct file *file)
+
+{ int unit = DEVICE_NR(inode->i_rdev);
+
+ if ((unit >= PG_UNITS) || (!PG.present)) return -ENODEV;
+
+ PG.access++;
+
+ if (PG.access > 1) {
+ PG.access--;
+ return -EBUSY;
+ }
+
+ MOD_INC_USE_COUNT;
+
+ if (PG.busy) {
+ pg_reset(unit);
+ PG.busy = 0;
+ }
+
+ pg_identify(unit,(verbose>1));
+
+
+ PG.bufptr = kmalloc(PG_MAX_DATA,GFP_KERNEL);
+ if (PG.bufptr == NULL) {
+ PG.access--;
+ MOD_DEC_USE_COUNT;
+ printk("%s: buffer allocation failed\n",PG.name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int pg_release (struct inode *inode, struct file *file)
+{
+ int unit = DEVICE_NR(inode->i_rdev);
+
+ if ((unit >= PG_UNITS) || (PG.access <= 0))
+ return -EINVAL;
+
+ PG.access--;
+
+ kfree(PG.bufptr);
+ PG.bufptr = NULL;
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+
+}
+
+static ssize_t pg_write(struct file * filp, const char * buf,
+ size_t count, loff_t *ppos)
+
+{ struct inode *ino = filp->f_dentry->d_inode;
+ int unit = DEVICE_NR(ino->i_rdev);
+ struct pg_write_hdr hdr;
+ int hs = sizeof(hdr);
+
+ if (PG.busy) return -EBUSY;
+ if (count < hs) return -EINVAL;
+
+ copy_from_user((char *)&hdr,buf,hs);
+
+ if (hdr.magic != PG_MAGIC) return -EINVAL;
+ if (hdr.dlen > PG_MAX_DATA) return -EINVAL;
+ if ((count - hs) > PG_MAX_DATA) return -EINVAL;
+
+ if (hdr.func == PG_RESET) {
+ if (count != hs) return -EINVAL;
+ if (pg_reset(unit)) return -EIO;
+ return count;
+ }
+
+ if (hdr.func != PG_COMMAND) return -EINVAL;
+
+ PG.start = jiffies;
+ PG.timeout = hdr.timeout*HZ + HZ/2 + jiffies;
+
+ if (pg_command(unit,hdr.packet,hdr.dlen,jiffies+PG_TMO)) {
+ if (PG.status & 0x10) return -ETIME;
+ return -EIO;
+ }
+
+ PG.busy = 1;
+
+ copy_from_user(PG.bufptr,buf+hs,count-hs);
+
+ return count;
+}
+
+static ssize_t pg_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
+
+{ struct inode *ino = filp->f_dentry->d_inode;
+ int unit = DEVICE_NR(ino->i_rdev);
+ struct pg_read_hdr hdr;
+ int hs = sizeof(hdr);
+ int copy;
+
+ if (!PG.busy) return -EINVAL;
+ if (count < hs) return -EINVAL;
+
+ PG.busy = 0;
+
+ if (pg_completion(unit,PG.bufptr,PG.timeout))
+ if (PG.status & 0x10) return -ETIME;
+
+ hdr.magic = PG_MAGIC;
+ hdr.dlen = PG.dlen;
+ copy = 0;
+
+ if (hdr.dlen < 0) {
+ hdr.dlen = -1 * hdr.dlen;
+ copy = hdr.dlen;
+ if (copy > (count - hs)) copy = count - hs;
+ }
+
+ hdr.duration = (jiffies - PG.start + HZ/2) / HZ;
+ hdr.scsi = PG.status & 0x0f;
+
+ copy_to_user(buf,(char *)&hdr,hs);
+ if (copy > 0) copy_to_user(buf+hs,PG.bufptr,copy);
+
+ return copy+hs;
+}
+
+/* end of pg.c */
+
static int ps_timer_active = 0;
static int ps_tq_active = 0;
-spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED;
+static spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED;
static struct timer_list ps_timer = {0,0,0,0,ps_timer_int};
static struct tq_struct ps_tq = {0,0,ps_tq_int,NULL};
--- /dev/null
+/*
+ * Macintosh ADB Mouse driver for Linux
+ *
+ * 27 Oct 1997 Michael Schmitz
+ * logitech fixes by anthony tong
+ *
+ * Apple mouse protocol according to:
+ *
+ * Device code shamelessly stolen from:
+ */
+/*
+ * Atari Mouse Driver for Linux
+ * by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Compatibility with busmouse
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
+ *
+ * 1996/02/11 Andreas Schwab
+ * Module support
+ * Allow multiple open's
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+
+#include <asm/adb_mouse.h>
+#include <asm/segment.h>
+#include <asm/processor.h>
+
+static struct mouse_status mouse;
+static int adb_mouse_x_threshold = 2, adb_mouse_y_threshold = 2;
+static int adb_mouse_buttons = 0;
+
+extern void (*adb_mouse_interrupt_hook) (char *, int);
+
+extern int console_loglevel;
+
+/*
+ * XXX: need to figure out what ADB mouse packets mean ...
+ * This is the stuff stolen from the Atari driver ...
+ */
+static void adb_mouse_interrupt(char *buf, int nb)
+{
+ static int buttons = 7;
+
+ /*
+ Handler 1 -- 100cpi original Apple mouse protocol.
+ Handler 2 -- 200cpi original Apple mouse protocol.
+
+ For Apple's standard one-button mouse protocol the data array will
+ contain the following values:
+
+ BITS COMMENTS
+ data[0] = 0000 0000 ADB packet identifer.
+ data[1] = ???? ???? (?)
+ data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+ data[3] = bxxx xxxx First button and x-axis motion.
+ data[4] = byyy yyyy Second button and y-axis motion.
+
+ NOTE: data[0] is confirmed by the parent function and need not be
+ checked here.
+ */
+
+ /*
+ Handler 4 -- Apple Extended mouse protocol.
+
+ For Apple's 3-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = 0000 0000 ADB packet identifer.
+ data[1] = 0100 0000 Extended protocol register.
+ Bits 6-7 are the device id, which should be 1.
+ Bits 4-5 are resolution which is in "units/inch".
+ The Logitech MouseMan returns these bits clear but it has
+ 200/300cpi resolution.
+ Bits 0-3 are unique vendor id.
+ data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+ Bits 2-3 should be 8 + 4.
+ Bits 4-7 should be 3 for a mouse device.
+ data[3] = bxxx xxxx Left button and x-axis motion.
+ data[4] = byyy yyyy Second button and y-axis motion.
+ data[5] = byyy bxxx Third button and fourth button.
+ Y is additiona. high bits of y-axis motion.
+ X is additional high bits of x-axis motion.
+
+ NOTE: data[0] and data[2] are confirmed by the parent function and
+ need not be checked here.
+ */
+
+ /*
+ * 'buttons' here means 'button down' states!
+ * Button 1 (left) : bit 2, busmouse button 3
+ * Button 2 (right) : bit 0, busmouse button 1
+ * Button 3 (middle): bit 1, busmouse button 2
+ */
+
+ /* x/y and buttons swapped */
+
+ if (nb > 0) { /* real packet : use buttons? */
+ if (console_loglevel >= 8)
+ printk("adb_mouse: real data; ");
+ /* button 1 (left, bit 2) : always significant ! */
+ buttons = (buttons&3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
+ /* button 2 (middle) */
+ buttons = (buttons&5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
+ /* button 3 (right) present?
+ * on a logitech mouseman, the right and mid buttons sometimes behave
+ * strangely until they both have been pressed after booting. */
+ /* data valid only if extended mouse format ! (buf[3] = 0 else) */
+ if ( nb == 6 )
+ buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
+ } else { /* fake packet : use 2+3 */
+ if (console_loglevel >= 8)
+ printk("adb_mouse: fake data; ");
+ /* we only see state changes here, but the fake driver takes care
+ * to preserve state... button 1 state must stay unchanged! */
+ buttons = (buttons&4) | ((buf[2] & 0x80 ? 1 : 0) |
+ (buf[3] & 0x80 ? 2 : 0));
+ }
+
+ add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
+ mouse.buttons = buttons & 7;
+ mouse.dx += ((buf[2]&0x7f) < 64 ? (buf[2]&0x7f) : (buf[2]&0x7f)-128 );
+ mouse.dy -= ((buf[1]&0x7f) < 64 ? (buf[1]&0x7f) : (buf[1]&0x7f)-128 );
+
+ if (console_loglevel >= 8)
+ printk(" %X %X %X buttons %x dx %d dy %d \n",
+ buf[1], buf[2], buf[3], mouse.buttons, mouse.dx, mouse.dy);
+
+ mouse.ready = 1;
+ wake_up_interruptible(&mouse.wait);
+ if (mouse.fasyncptr)
+ kill_fasync(mouse.fasyncptr, SIGIO);
+
+}
+
+static int fasync_mouse(struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+static int release_mouse(struct inode *inode, struct file *file)
+{
+ fasync_mouse(file, 0);
+ if (--mouse.active)
+ return 0;
+
+ adb_mouse_interrupt_hook = NULL;
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int open_mouse(struct inode *inode, struct file *file)
+{
+ if (mouse.active++)
+ return 0;
+
+ mouse.ready = 0;
+
+ mouse.dx = mouse.dy = 0;
+ adb_mouse_buttons = 0;
+ MOD_INC_USE_COUNT;
+ adb_mouse_interrupt_hook = adb_mouse_interrupt;
+ return 0;
+}
+
+static ssize_t write_mouse(struct file *file, const char *buffer,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static ssize_t read_mouse(struct file *file, char *buffer, size_t count,
+ loff_t *ppos)
+{
+ int dx, dy, buttons;
+
+ if (count < 3)
+ return -EINVAL;
+ if (!mouse.ready)
+ return -EAGAIN;
+ dx = mouse.dx;
+ dy = mouse.dy;
+ buttons = mouse.buttons;
+ if (dx > 127)
+ dx = 127;
+ else if (dx < -128)
+ dx = -128;
+ if (dy > 127)
+ dy = 127;
+ else if (dy < -128)
+ dy = -128;
+ mouse.dx -= dx;
+ mouse.dy -= dy;
+ if (mouse.dx == 0 && mouse.dy == 0)
+ mouse.ready = 0;
+ if (put_user(buttons | 0x80, buffer++) ||
+ put_user((char) dx, buffer++) ||
+ put_user((char) dy, buffer++))
+ return -EFAULT;
+ if (count > 3)
+ if (clear_user(buffer, count - 3))
+ return -EFAULT;
+ return count;
+}
+
+static unsigned int mouse_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &mouse.wait, wait);
+ if (mouse.ready)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+struct file_operations adb_mouse_fops = {
+ NULL, /* mouse_seek */
+ read_mouse,
+ write_mouse,
+ NULL, /* mouse_readdir */
+ mouse_poll,
+ NULL, /* mouse_ioctl */
+ NULL, /* mouse_mmap */
+ open_mouse,
+ release_mouse,
+ NULL,
+ fasync_mouse,
+};
+
+#define ADB_MOUSE_MINOR 10
+
+static struct miscdevice adb_mouse = {
+ ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
+};
+
+__initfunc(int adb_mouse_init(void))
+{
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.wait = NULL;
+
+ if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+ return -ENODEV;
+ printk(KERN_INFO "Macintosh ADB mouse installed.\n");
+ misc_register(&adb_mouse);
+ return 0;
+}
+
+
+#define MIN_THRESHOLD 1
+#define MAX_THRESHOLD 20 /* more seems not reasonable... */
+
+__initfunc(void adb_mouse_setup(char *str, int *ints))
+{
+ if (ints[0] < 1) {
+ printk( "adb_mouse_setup: no arguments!\n" );
+ return;
+ }
+ else if (ints[0] > 2) {
+ printk( "adb_mouse_setup: too many arguments\n" );
+ }
+
+ if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
+ printk( "adb_mouse_setup: bad threshold value (ignored)\n" );
+ else {
+ adb_mouse_x_threshold = ints[1];
+ adb_mouse_y_threshold = ints[1];
+ if (ints[0] > 1) {
+ if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
+ printk("adb_mouse_setup: bad threshold value (ignored)\n" );
+ else
+ adb_mouse_y_threshold = ints[2];
+ }
+ }
+
+}
+
+#ifdef MODULE
+#include <asm/setup.h>
+
+int init_module(void)
+{
+ return adb_mouse_init();
+}
+
+void cleanup_module(void)
+{
+ misc_deregister(&adb_mouse);
+}
+#endif
}
btv->win.sheight=v.height;
btv->win.swidth=v.width;
-+ btv->win.bpp=((v.depth+1)&0x18)/8;
+ btv->win.bpp=((v.depth+1)&0x38)/8;
btv->win.depth=v.depth;
btv->win.bpl=v.bytesperline;
"DEC DC21030", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL,
"Matrox Millennium", PCI_BASE_ADDRESS_1},
+ { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2,
+ "Matrox Millennium II", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1},
{ PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128,
"Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
static void insert_char(int currcons, unsigned int nr)
{
- unsigned int i = x;
- unsigned short * p, * q = (unsigned short *) pos;
+ unsigned short *p, *q = (unsigned short *) pos;
- while (i++ <= video_num_columns - nr) {
+ p = q + video_num_columns - nr - x;
+ while (--p >= q)
scr_writew(scr_readw(p), p + nr);
- p++;
- }
+
memsetw(q, video_erase_char, nr*2);
need_wrap = 0;
}
#include <linux/lp_intern.h>
static int minor = -1;
+MODULE_PARM(minor,"i");
static void lp_int_out(int, int);
static int lp_int_busy(int);
--- /dev/null
+/*
+ * mac_SCC.c: m68k version of
+ *
+ * macserial.c: Serial port driver for Power Macintoshes.
+ * Extended for the 68K mac by Alan Cox.
+ * Rewritten to m68k serial design by Michael Schmitz
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ * Design note for the m68k rewrite:
+ * The structure of the m68k serial code requires separation of the low-level
+ * functions that talk directly to the hardware from the Linux serial driver
+ * code interfacing to the tty layer. The reason for this separation is simply
+ * the fact that the m68k serial hardware is, unlike the i386, based on a
+ * variety of chips, and the rs_* serial routines need to be shared.
+ *
+ * I've tried to make consistent use of the async_struct info populated in the
+ * midlevel code, and introduced an async_private struct to hold the Macintosh
+ * SCC internals (this was added to the async_struct for the PowerMac driver).
+ * Exception: the console and kgdb hooks still use the zs_soft[] data, and this
+ * is still filled in by the probe_sccs() routine, which provides some data
+ * for mac_SCC_init as well. Interrupts are registered in mac_SCC_init, so
+ * the console/kgdb stuff probably won't work before proper serial init, and
+ * I have to rely on keeping info and zs_soft consistent at least for the
+ * console/kgdb port.
+ *
+ * Update (16-11-97): The SCC interrupt handling was suffering from the problem
+ * that the autovector SCC interrupt was registered only once, hence only one
+ * async_struct was passed to the interrupt function and only interrupts from
+ * the corresponding channel could be handled (yes, major design flaw).
+ * The autovector interrupt is now registered by the main interrupt initfunc,
+ * and uses a handler that will call the registered SCC specific interrupts in
+ * turn. The SCC init has to register these as machspec interrupts now, as is
+ * done for the VIA interrupts elsewhere.
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/macints.h>
+#ifndef CONFIG_MAC
+#include <asm/prom.h>
+#endif
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+
+#include "mac_SCC.h"
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL 2 /* Max number of ZS chips supported */
+#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
+
+#ifdef CONFIG_MAC
+/*
+ * All the Macintosh 68K boxes that have an MMU also have hardware
+ * recovery delays.
+ */
+#define RECOVERY_DELAY
+#else
+/* On PowerMacs, the hardware takes care of the SCC recovery time,
+ but we need the eieio to make sure that the accesses occur
+ in the order we want. */
+#define RECOVERY_DELAY eieio()
+#endif
+
+struct mac_zschannel *zs_kgdbchan;
+struct mac_zschannel zs_channels[NUM_CHANNELS];
+
+struct m68k_async_struct zs_soft[NUM_CHANNELS];
+struct m68k_async_private zs_soft_private[NUM_CHANNELS];
+int zs_channels_found;
+struct m68k_async_struct *zs_chain; /* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chanout = 0;
+static int zs_cons_chanin = 0;
+struct m68k_async_struct *zs_consinfo = 0;
+struct mac_zschannel *zs_conschan;
+
+static unsigned char kgdb_regs[16] = {
+ 0, 0, 0, /* write 0, 1, 2 */
+ (Rx8 | RxENABLE), /* write 3 */
+ (X16CLK | SB1 | PAR_EVEN), /* write 4 */
+ (Tx8 | TxENAB), /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ (NV), /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 1, 0, /* 38400 baud divisor, write 12 + 13 */
+ (BRENABL), /* write 14 */
+ (DCDIE) /* write 15 */
+};
+
+#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+/***************************** Prototypes *****************************/
+
+static void SCC_init_port( struct m68k_async_struct *info, int type, int channel );
+#if 0
+#ifdef MODULE
+static void SCC_deinit_port( struct m68k_async_struct *info, int channel );
+#endif
+#endif
+
+/* FIXME !!! Currently, only autovector interrupt used! */
+#if 0
+static void SCC_rx_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_spcond_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_tx_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_stat_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_ri_int (int irq, void *data, struct pt_regs *fp);
+#endif
+
+static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct
+ *tty, struct file *file );
+static void SCC_init( struct m68k_async_struct *info );
+static void SCC_deinit( struct m68k_async_struct *info, int leave_dtr );
+static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag );
+static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base,
+ int divisor );
+static void SCC_change_speed( struct m68k_async_struct *info );
+#if 0
+static int SCC_clocksrc( unsigned baud_base, unsigned channel );
+#endif
+static void SCC_throttle( struct m68k_async_struct *info, int status );
+static void SCC_set_break( struct m68k_async_struct *info, int break_flag );
+static void SCC_get_serial_info( struct m68k_async_struct *info, struct
+ serial_struct *retinfo );
+static unsigned int SCC_get_modem_info( struct m68k_async_struct *info );
+static int SCC_set_modem_info( struct m68k_async_struct *info, int new_dtr, int
+ new_rts );
+static int SCC_ioctl( struct tty_struct *tty, struct file *file, struct
+ m68k_async_struct *info, unsigned int cmd, unsigned long arg );
+static void SCC_stop_receive (struct m68k_async_struct *info);
+static int SCC_trans_empty (struct m68k_async_struct *info);
+
+/************************* End of Prototypes **************************/
+
+
+static SERIALSWITCH SCC_switch = {
+ SCC_init, SCC_deinit, SCC_enab_tx_int,
+ SCC_check_custom_divisor, SCC_change_speed,
+ SCC_throttle, SCC_set_break,
+ SCC_get_serial_info, SCC_get_modem_info,
+ SCC_set_modem_info, SCC_ioctl, SCC_stop_receive, SCC_trans_empty,
+ SCC_check_open
+};
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 0 };
+
+/*
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct mac_zschannel *channel,
+ unsigned char reg)
+{
+ unsigned char retval;
+
+ if (reg != 0) {
+ *channel->control = reg;
+ RECOVERY_DELAY;
+ }
+ retval = *channel->control;
+ RECOVERY_DELAY;
+ return retval;
+}
+
+static inline void write_zsreg(struct mac_zschannel *channel,
+ unsigned char reg, unsigned char value)
+{
+ if (reg != 0) {
+ *channel->control = reg;
+ RECOVERY_DELAY;
+ }
+ *channel->control = value;
+ RECOVERY_DELAY;
+ return;
+}
+
+static inline unsigned char read_zsdata(struct mac_zschannel *channel)
+{
+ unsigned char retval;
+
+ retval = *channel->data;
+ RECOVERY_DELAY;
+ return retval;
+}
+
+static inline void write_zsdata(struct mac_zschannel *channel,
+ unsigned char value)
+{
+ *channel->data = value;
+ RECOVERY_DELAY;
+ return;
+}
+
+static inline void load_zsregs(struct mac_zschannel *channel,
+ unsigned char *regs)
+{
+ ZS_CLEARERR(channel);
+ ZS_CLEARFIFO(channel);
+ /* Load 'em up */
+ write_zsreg(channel, R4, regs[R4]);
+ write_zsreg(channel, R10, regs[R10]);
+ write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+ write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+ write_zsreg(channel, R1, regs[R1]);
+ write_zsreg(channel, R9, regs[R9]);
+ write_zsreg(channel, R11, regs[R11]);
+ write_zsreg(channel, R12, regs[R12]);
+ write_zsreg(channel, R13, regs[R13]);
+ write_zsreg(channel, R14, regs[R14]);
+ write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R3, regs[R3]);
+ write_zsreg(channel, R5, regs[R5]);
+ return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct m68k_async_struct *ss, int set)
+{
+ if (set)
+ ss->private->curregs[5] |= (RTS | DTR);
+ else
+ ss->private->curregs[5] &= ~(RTS | DTR);
+ write_zsreg(ss->private->zs_channel, 5, ss->private->curregs[5]);
+ return;
+}
+
+static inline void kgdb_chaninit(struct m68k_async_struct *ss, int intson, int bps)
+{
+ int brg;
+
+ if (intson) {
+ kgdb_regs[R1] = INT_ALL_Rx;
+ kgdb_regs[R9] |= MIE;
+ } else {
+ kgdb_regs[R1] = 0;
+ kgdb_regs[R9] &= ~MIE;
+ }
+ brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+ kgdb_regs[R12] = brg;
+ kgdb_regs[R13] = brg >> 8;
+ load_zsregs(ss->private->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct m68k_async_struct *ss)
+{
+ struct mac_zschannel *channel = ss->private->zs_channel;
+ int brg;
+
+ /* The baud rate is split up between two 8-bit registers in
+ * what is termed 'BRG time constant' format in my docs for
+ * the chip, it is a function of the clk rate the chip is
+ * receiving which happens to be constant.
+ */
+ brg = (read_zsreg(channel, 13) << 8);
+ brg |= read_zsreg(channel, 12);
+ return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->private->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void SCC_recv_clear(struct mac_zschannel *zsc)
+{
+ write_zsreg(zsc, 0, ERR_RES);
+ write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+extern void breakpoint(void); /* For the KGDB frame character */
+
+static /*_INLINE_*/ void receive_chars(struct m68k_async_struct *info,
+ struct pt_regs *regs)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned char ch, stat, flag;
+
+ while ((read_zsreg(info->private->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+ stat = read_zsreg(info->private->zs_channel, R1);
+ ch = read_zsdata(info->private->zs_channel);
+
+#ifdef SCC_DEBUG
+ printk("mac_SCC: receive_chars stat=%X char=%X \n", stat, ch);
+#endif
+
+#if 0 /* KGDB not yet supported */
+ /* Look for kgdb 'stop' character, consult the gdb documentation
+ * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+ * to see how all this works.
+ */
+ if ((info->kgdb_channel) && (ch =='\003')) {
+ breakpoint();
+ continue;
+ }
+#endif
+
+ if (!tty)
+ continue;
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ tty_flip_buffer_push(tty);
+
+ if (stat & Rx_OVR) {
+ flag = TTY_OVERRUN;
+ /* reset the error indication */
+ write_zsreg(info->private->zs_channel, 0, ERR_RES);
+ } else if (stat & FRM_ERR) {
+ /* this error is not sticky */
+ flag = TTY_FRAME;
+ } else if (stat & PAR_ERR) {
+ flag = TTY_PARITY;
+ /* reset the error indication */
+ write_zsreg(info->private->zs_channel, 0, ERR_RES);
+ } else
+ flag = 0;
+
+ if (tty->flip.buf_num
+ && tty->flip.count >= TTY_FLIPBUF_SIZE) {
+#ifdef SCC_DEBUG_OVERRUN
+ printk("mac_SCC: flip buffer overrun!\n");
+#endif
+ return;
+ }
+
+ if (!tty->flip.buf_num
+ && tty->flip.count >= 2*TTY_FLIPBUF_SIZE) {
+ printk("mac_SCC: double flip buffer overrun!\n");
+ return;
+ }
+
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = flag;
+ *tty->flip.char_buf_ptr++ = ch;
+ info->icount.rx++;
+ tty_flip_buffer_push(tty);
+ }
+#if 0
+clear_and_exit:
+ SCC_recv_clear(info->private->zs_channel);
+#endif
+}
+
+/* that's SCC_enable_tx_int, basically */
+
+static void transmit_chars(struct m68k_async_struct *info)
+{
+ if ((read_zsreg(info->private->zs_channel, 0) & Tx_BUF_EMP) == 0)
+ return;
+ info->private->tx_active = 0;
+
+ if (info->x_char) {
+ /* Send next char */
+ write_zsdata(info->private->zs_channel, info->x_char);
+ info->x_char = 0;
+ info->private->tx_active = 1;
+ return;
+ }
+
+ if ((info->xmit_cnt <= 0) || info->tty->stopped
+ || info->private->tx_stopped) {
+ write_zsreg(info->private->zs_channel, 0, RES_Tx_P);
+ return;
+ }
+
+ /* Send char */
+ write_zsdata(info->private->zs_channel, info->xmit_buf[info->xmit_tail++]);
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->icount.tx++;
+ info->xmit_cnt--;
+ info->private->tx_active = 1;
+
+ if (info->xmit_cnt < WAKEUP_CHARS)
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static /*_INLINE_*/ void status_handle(struct m68k_async_struct *info)
+{
+ unsigned char status;
+
+ /* Get status from Read Register 0 */
+ status = read_zsreg(info->private->zs_channel, 0);
+
+ /* Check for DCD transitions */
+ if (((status ^ info->private->read_reg_zero) & DCD) != 0
+ && info->tty && C_CLOCAL(info->tty)) {
+ if (status & DCD) {
+ wake_up_interruptible(&info->open_wait);
+ } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+ if (info->tty)
+ tty_hangup(info->tty);
+ }
+ }
+
+ /* Check for CTS transitions */
+ if (info->tty && C_CRTSCTS(info->tty)) {
+ /*
+ * For some reason, on the Power Macintosh,
+ * it seems that the CTS bit is 1 when CTS is
+ * *negated* and 0 when it is asserted.
+ * The DCD bit doesn't seem to be inverted
+ * like this.
+ */
+ if ((status & CTS) == 0) {
+ if (info->private->tx_stopped) {
+ info->private->tx_stopped = 0;
+ if (!info->private->tx_active)
+ transmit_chars(info);
+ }
+ } else {
+ info->private->tx_stopped = 1;
+ }
+ }
+
+ /* Clear status condition... */
+ write_zsreg(info->private->zs_channel, 0, RES_EXT_INT);
+ info->private->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void mac_SCC_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct m68k_async_struct *info = (struct m68k_async_struct *) dev_id;
+ unsigned char zs_intreg;
+ int shift;
+
+ /* NOTE: The read register 3, which holds the irq status,
+ * does so for both channels on each chip. Although
+ * the status value itself must be read from the A
+ * channel and is only valid when read from channel A.
+ * Yes... broken hardware...
+ */
+#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+#ifdef SCC_DEBUG
+ printk("mac_SCC: interrupt; port: %lx channel: %lx \n",
+ info->port, info->private->zs_channel);
+#endif
+
+ if (info->private->zs_chan_a == info->private->zs_channel)
+ shift = 3; /* Channel A */
+ else
+ shift = 0; /* Channel B */
+
+ for (;;) {
+ zs_intreg = read_zsreg(info->private->zs_chan_a, 3);
+#ifdef SCC_DEBUG
+ printk("mac_SCC: status %x shift %d shifted %x \n",
+ zs_intreg, shift, zs_intreg >> shift);
+#endif
+ zs_intreg = zs_intreg >> shift;
+ if ((zs_intreg & CHAN_IRQMASK) == 0)
+ break;
+
+ if (zs_intreg & CHBRxIP)
+ receive_chars(info, regs);
+ if (zs_intreg & CHBTxIP)
+ transmit_chars(info);
+ if (zs_intreg & CHBEXT)
+ status_handle(info);
+ }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+
+static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag )
+{
+ unsigned long flags;
+
+ if (enab_flag) {
+#if 0
+ save_flags(flags); cli();
+ if (info->private->curregs[5] & TxENAB) {
+ info->private->curregs[5] &= ~TxENAB;
+ info->private->pendregs[5] &= ~TxENAB;
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ }
+ restore_flags(flags);
+#endif
+ /* FIXME: should call transmit_chars here ??? */
+ transmit_chars(info);
+ } else {
+ save_flags(flags); cli();
+#if 0
+ if ( info->xmit_cnt && info->xmit_buf &&
+ !(info->private->curregs[5] & TxENAB)) {
+ info->private->curregs[5] |= TxENAB;
+ info->private->pendregs[5] = info->private->curregs[5];
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ }
+#else
+ if ( info->xmit_cnt && info->xmit_buf &&
+ !info->private->tx_active) {
+ transmit_chars(info);
+ }
+#endif
+ restore_flags(flags);
+ }
+
+}
+
+#if 0
+/*
+ * leftover from original driver ...
+ */
+static int SCC_startup(struct m68k_async_struct * info)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+ /*
+ * Clear the receive FIFO.
+ */
+ ZS_CLEARFIFO(info->private->zs_channel);
+ info->xmit_fifo_size = 1;
+
+ /*
+ * Clear the interrupt registers.
+ */
+ write_zsreg(info->private->zs_channel, 0, ERR_RES);
+ write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
+
+ /*
+ * Turn on RTS and DTR.
+ */
+ zs_rtsdtr(info, 1);
+
+ /*
+ * Finally, enable sequencing and interrupts
+ */
+ info->private->curregs[1] = (info->private->curregs[1] & ~0x18)
+ | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+ info->private->pendregs[1] = info->private->curregs[1];
+ info->private->curregs[3] |= (RxENABLE | Rx8);
+ info->private->pendregs[3] = info->private->curregs[3];
+ info->private->curregs[5] |= (TxENAB | Tx8);
+ info->private->pendregs[5] = info->private->curregs[5];
+ info->private->curregs[9] |= (NV | MIE);
+ info->private->pendregs[9] = info->private->curregs[9];
+ write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+ write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
+
+ /*
+ * Set the speed of the serial port
+ */
+ SCC_change_speed(info);
+
+ /* Save the current value of RR0 */
+ info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
+
+ restore_flags(flags);
+ return 0;
+}
+#endif
+
+/* FIXME: are these required ?? */
+static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty,
+ struct file *file )
+{
+ /* check on the basis of info->whatever ?? */
+ if (info->private->kgdb_channel || info->private->is_cons)
+ return -EBUSY;
+ return( 0 );
+}
+
+static void SCC_init( struct m68k_async_struct *info )
+{
+ /* FIXME: init currently done in probe_sccs() */
+
+ /* BUT: startup part needs to be done here! */
+
+#ifdef SCC_DEBUG
+ printk("mac_SCC: init, info %lx, info->port %lx \n", info, info->port);
+#endif
+ /*
+ * Clear the receive FIFO.
+ */
+ ZS_CLEARFIFO(info->private->zs_channel);
+ info->xmit_fifo_size = 1;
+
+ /*
+ * Clear the interrupt registers.
+ */
+ write_zsreg(info->private->zs_channel, 0, ERR_RES);
+ write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
+
+ /*
+ * Turn on RTS and DTR.
+ */
+ zs_rtsdtr(info, 1);
+
+ /*
+ * Finally, enable sequencing and interrupts
+ */
+ info->private->curregs[1] = (info->private->curregs[1] & ~0x18)
+ | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+ info->private->pendregs[1] = info->private->curregs[1];
+ info->private->curregs[3] |= (RxENABLE | Rx8);
+ info->private->pendregs[3] = info->private->curregs[3];
+ info->private->curregs[5] |= (TxENAB | Tx8);
+ info->private->pendregs[5] = info->private->curregs[5];
+ info->private->curregs[9] |= (NV | MIE);
+ info->private->pendregs[9] = info->private->curregs[9];
+ write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+ write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
+
+ /*
+ * Set the speed of the serial port - done in startup() !!
+ */
+#if 0
+ SCC_change_speed(info);
+#endif
+
+ /* Save the current value of RR0 */
+ info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
+
+}
+
+static void SCC_init_port( struct m68k_async_struct *info, int type, int channel )
+{
+ static int got_autovector = 0;
+
+#ifdef SCC_DEBUG
+ printk("mac_SCC: init_port, info %x \n", info);
+#endif
+ info->sw = &SCC_switch;
+ info->private = &zs_soft_private[channel];
+ info->private->zs_channel = &zs_channels[channel];
+ info->irq = IRQ4;
+ info->private->clk_divisor = 16;
+ info->private->zs_baud = get_zsbaud(info);
+ info->port = (int) info->private->zs_channel->control;
+
+ /*
+ * MSch: Extended interrupt scheme:
+ * The generic m68k interrupt code can't use multiple handlers for
+ * the same interrupt source (no chained interrupts).
+ * We have to plug in a 'master' interrupt handler instead, calling
+ * mac_SCC_interrupt with the proper arguments ...
+ */
+
+ if (!got_autovector) {
+ if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info))
+ panic("macserial: can't get irq %d", IRQ4);
+#ifdef SCC_DEBUG
+ printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n",
+ IRQ4, channel, info);
+#endif
+ got_autovector = 1;
+ }
+
+ if (info->private->zs_chan_a == info->private->zs_channel) {
+ /* Channel A */
+ if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info))
+ panic("mac_SCC: can't get irq %d", IRQ_SCCA);
+#ifdef SCC_DEBUG
+ printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n",
+ IRQ_SCCA, channel, info);
+#endif
+ } else {
+ /* Channel B */
+ if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info))
+ panic("mac_SCC: can't get irq %d", IRQ_SCCB);
+#ifdef SCC_DEBUG
+ printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n",
+ IRQ_SCCB, channel, info);
+#endif
+ }
+
+ /* If console serial line, then enable interrupts. */
+ if (info->private->is_cons) {
+ printk("mac_SCC: console line %lx; enabling interrupt!\n", info);
+ write_zsreg(info->private->zs_channel, R1,
+ (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+ write_zsreg(info->private->zs_channel, R9, (NV | MIE));
+ write_zsreg(info->private->zs_channel, R10, (NRZ));
+ write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE));
+ write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB));
+ }
+ /* If this is the kgdb line, enable interrupts because we
+ * now want to receive the 'control-c' character from the
+ * client attached to us asynchronously.
+ */
+ if (info->private->kgdb_channel) {
+ printk("mac_SCC: kgdb line %lx; enabling interrupt!\n", info);
+ kgdb_chaninit(info, 1, info->private->zs_baud);
+ }
+ /* Report settings (in m68kserial.c) */
+#ifndef CONFIG_MAC
+ printk("ttyS%d at 0x%08x (irq = %d)", info->line,
+ info->port, info->irq);
+ printk(" is a Z8530 SCC\n");
+#endif
+
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void SCC_deinit(struct m68k_async_struct * info, int leave_dtr)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ info->private->pendregs[1] = info->private->curregs[1] = 0;
+ write_zsreg(info->private->zs_channel, 1, 0); /* no interrupts */
+
+ info->private->curregs[3] &= ~RxENABLE;
+ info->private->pendregs[3] = info->private->curregs[3];
+ write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+
+ info->private->curregs[5] &= ~TxENAB;
+
+ if (!leave_dtr)
+ info->private->curregs[5] &= ~(DTR | RTS);
+ else
+ info->private->curregs[5] &= ~(RTS);
+
+ info->private->pendregs[5] = info->private->curregs[5];
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+
+ restore_flags(flags);
+}
+
+/* FIXME !!! */
+static int SCC_check_custom_divisor( struct m68k_async_struct *info,
+ int baud_base, int divisor )
+{
+ return 0;
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void SCC_change_speed(struct m68k_async_struct *info)
+{
+ unsigned short port;
+ unsigned cflag;
+ int i;
+ int brg;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+ cflag = info->tty->termios->c_cflag;
+ if (!(port = info->port))
+ return;
+ i = cflag & CBAUD;
+
+ if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) {
+ /* speed == 0 -> drop DTR */
+ save_flags(flags);
+ cli();
+ info->private->curregs[5] &= ~(DTR | RTS);
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+ restore_flags(flags);
+ return;
+ }
+
+
+ if (i & CBAUDEX) {
+ /* XXX CBAUDEX is not obeyed.
+ * It is impossible at a 32bits PPC. XXX??
+ * But we have to report this to user ... someday.
+ */
+ i = B9600;
+ }
+
+ save_flags(flags); cli();
+ info->private->zs_baud = baud_table[i];
+ info->private->clk_divisor = 16;
+
+ info->private->curregs[4] = X16CLK;
+ info->private->curregs[11] = TCBR | RCBR;
+ brg = BPS_TO_BRG(info->private->zs_baud,
+ ZS_CLOCK/info->private->clk_divisor);
+ info->private->curregs[12] = (brg & 255);
+ info->private->curregs[13] = ((brg >> 8) & 255);
+ info->private->curregs[14] = BRENABL;
+
+ /* byte size and parity */
+ info->private->curregs[3] &= ~RxNBITS_MASK;
+ info->private->curregs[5] &= ~TxNBITS_MASK;
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->private->curregs[3] |= Rx5;
+ info->private->curregs[5] |= Tx5;
+ break;
+ case CS6:
+ info->private->curregs[3] |= Rx6;
+ info->private->curregs[5] |= Tx6;
+ break;
+ case CS7:
+ info->private->curregs[3] |= Rx7;
+ info->private->curregs[5] |= Tx7;
+ break;
+ case CS8:
+ default: /* defaults to 8 bits */
+ info->private->curregs[3] |= Rx8;
+ info->private->curregs[5] |= Tx8;
+ break;
+ }
+ info->private->pendregs[3] = info->private->curregs[3];
+ info->private->pendregs[5] = info->private->curregs[5];
+
+ info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+ if (cflag & CSTOPB) {
+ info->private->curregs[4] |= SB2;
+ } else {
+ info->private->curregs[4] |= SB1;
+ }
+ if (cflag & PARENB) {
+ info->private->curregs[4] |= PAR_ENA;
+ }
+ if (!(cflag & PARODD)) {
+ info->private->curregs[4] |= PAR_EVEN;
+ }
+ info->private->pendregs[4] = info->private->curregs[4];
+
+ info->private->curregs[15] &= ~(DCDIE | CTSIE);
+ if (!(cflag & CLOCAL)) {
+ info->private->curregs[15] |= DCDIE;
+ }
+ if (cflag & CRTSCTS) {
+ info->private->curregs[15] |= CTSIE;
+ if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0)
+ info->private->tx_stopped = 1;
+ } else
+ info->private->tx_stopped = 0;
+ info->private->pendregs[15] = info->private->curregs[15];
+
+ /* Load up the new values */
+ load_zsregs(info->private->zs_channel, info->private->curregs);
+
+ restore_flags(flags);
+}
+
+/* This is for console output over ttya/ttyb */
+static void SCC_put_char(char ch)
+{
+ struct mac_zschannel *chan = zs_conschan;
+ int loops = 0;
+ unsigned long flags;
+
+ if(!chan)
+ return;
+
+ save_flags(flags); cli();
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) {
+ loops++;
+ udelay(5);
+ }
+ write_zsdata(chan, ch);
+ restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(chan, kgdb_char);
+}
+
+char getDebugChar(void)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+
+ while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+ udelay(5);
+ return read_zsdata(chan);
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void SCC_fair_output(void)
+{
+ int left; /* Output no more than that */
+ unsigned long flags;
+ struct m68k_async_struct *info = zs_consinfo;
+ char c;
+
+ if (info == 0) return;
+ if (info->xmit_buf == 0) return;
+
+ save_flags(flags); cli();
+ left = info->xmit_cnt;
+ while (left != 0) {
+ c = info->xmit_buf[info->xmit_tail];
+ info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ restore_flags(flags);
+
+ SCC_put_char(c);
+
+ save_flags(flags); cli();
+ left = MIN(info->xmit_cnt, left-1);
+ }
+
+ restore_flags(flags);
+ return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+ char c;
+
+ while ((c = *(p++)) != 0) {
+ if (c == '\n')
+ SCC_put_char('\r');
+ SCC_put_char(c);
+ }
+
+ /* Comment this if you want to have a strict interrupt-driven output */
+ SCC_fair_output();
+}
+
+/* FIXME: check with SCC_enab_tx_int!! */
+#if 0
+static void rs_flush_chars(struct tty_struct *tty)
+{
+ struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || info->private->tx_stopped ||
+ !info->xmit_buf)
+ return;
+
+ /* Enable transmitter */
+ save_flags(flags); cli();
+ transmit_chars(info);
+ restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write"))
+ return 0;
+
+ if (!tty || !info->xmit_buf)
+ return 0;
+
+ save_flags(flags);
+ while (1) {
+ cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ if (from_user) {
+ down(&tmp_buf_sem);
+ memcpy_fromfs(tmp_buf, buf, c);
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ up(&tmp_buf_sem);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+ && !info->tx_active)
+ transmit_chars(info);
+ restore_flags(flags);
+ return total;
+}
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void SCC_throttle(struct m68k_async_struct *info, int status)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (status) {
+ /*
+ * Here we want to turn off the RTS line. On Macintoshes,
+ * we only get the DTR line, which goes to both DTR and
+ * RTS on the modem. RTS doesn't go out to the serial
+ * port socket. So you should make sure your modem is
+ * set to ignore DTR if you're using CRTSCTS.
+ */
+ info->private->curregs[5] &= ~(DTR | RTS);
+ info->private->pendregs[5] &= ~(DTR | RTS);
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ } else {
+ /* Assert RTS and DTR lines */
+ info->private->curregs[5] |= DTR | RTS;
+ info->private->pendregs[5] |= DTR | RTS;
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ }
+
+ restore_flags(flags);
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static void SCC_get_serial_info(struct m68k_async_struct * info,
+ struct serial_struct * retinfo)
+{
+ struct serial_struct tmp;
+
+ retinfo->baud_base = info->baud_base;
+ retinfo->custom_divisor = info->custom_divisor;
+}
+
+/* FIXME: set_serial_info needs check_custom_divisor !!! */
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int SCC_get_lsr_info(struct m68k_async_struct * info, unsigned int *value)
+{
+ unsigned char status;
+
+ cli();
+ status = read_zsreg(info->private->zs_channel, 0);
+ sti();
+ return status;
+}
+
+static unsigned int SCC_get_modem_info(struct m68k_async_struct *info)
+{
+ unsigned char control, status;
+ unsigned int result;
+
+ cli();
+ control = info->private->curregs[5];
+ status = read_zsreg(info->private->zs_channel, 0);
+ sti();
+ result = ((control & RTS) ? TIOCM_RTS: 0)
+ | ((control & DTR) ? TIOCM_DTR: 0)
+ | ((status & DCD) ? TIOCM_CAR: 0)
+ | ((status & CTS) ? 0: TIOCM_CTS);
+ return result;
+}
+
+/* FIXME: zs_setdtr was used in rs_open ... */
+
+static int SCC_set_modem_info(struct m68k_async_struct *info,
+ int new_dtr, int new_rts)
+{
+ int error;
+ unsigned int arg, bits;
+
+ bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0);
+ info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits;
+ info->private->pendregs[5] = info->private->curregs[5];
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+ sti();
+ return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void SCC_set_break(struct m68k_async_struct * info, int break_flag)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (break_flag) {
+ info->private->curregs[5] |= SND_BRK;
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ } else {
+ info->private->curregs[5] &= ~SND_BRK;
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ }
+
+ restore_flags(flags);
+}
+
+/* FIXME: these have to be enabled in rs_ioctl !! */
+
+static int SCC_ioctl(struct tty_struct *tty, struct file * file,
+ struct m68k_async_struct * info, unsigned int cmd,
+ unsigned long arg)
+{
+ int error;
+ int retval;
+
+ switch (cmd) {
+ case TIOCSERGETLSR: /* Get line status register */
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int));
+ if (error)
+ return error;
+ else
+ return SCC_get_lsr_info(info, (unsigned int *) arg);
+
+ case TIOCSERGSTRUCT:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct m68k_async_struct));
+ if (error)
+ return error;
+ copy_to_user((struct m68k_async_struct *) arg,
+ info, sizeof(struct m68k_async_struct));
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void SCC_stop_receive (struct m68k_async_struct *info)
+{
+ /* disable Rx */
+ info->private->curregs[3] &= ~RxENABLE;
+ info->private->pendregs[3] = info->private->curregs[3];
+ write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+ /* disable Rx interrupts */
+ info->private->curregs[1] &= ~(0x18); /* disable any rx ints */
+ info->private->pendregs[1] = info->private->curregs[1];
+ write_zsreg(info->private->zs_channel, 1, info->private->curregs[1]);
+ ZS_CLEARFIFO(info->private->zs_channel);
+}
+
+static int SCC_trans_empty (struct m68k_async_struct *info)
+{
+ return (read_zsreg(info->private->zs_channel, 1) & ALL_SNT) != 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+#ifdef CONFIG_MAC
+
+/*
+ * Mac: use boot_info data; assume 2 channels
+ */
+
+static void probe_sccs(void)
+{
+ int n;
+
+#define ZS_CONTROL 0x50F04000
+#define ZS_DATA (ZS_CONTROL+4)
+#define ZS_IRQ 5
+#define ZS_MOVE -2
+#define ZS_DATA_MOVE 4
+#define ZS_CH_A_FIRST 2
+
+ /* last-ditch fixup for NetBSD booter case */
+ if (mac_bi_data.sccbase == 0)
+ mac_bi_data.sccbase = ZS_CONTROL;
+
+ /* testing: fix up broken 24 bit addresses (ClassicII) */
+ if ((mac_bi_data.sccbase & 0x00FFFFFF) == mac_bi_data.sccbase)
+ mac_bi_data.sccbase |= 0x50000000;
+
+ for(n=0;n<2;n++)
+ {
+#if 0
+ zs_channels[n].control = (volatile unsigned char *)
+ ZS_CONTROL+ZS_MOVE*n;
+ zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n;
+#else
+ zs_channels[n].control = (volatile unsigned char *)
+ (mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n;
+ zs_channels[n].data = (volatile unsigned char *)
+ (mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n;
+#endif
+ zs_soft[n].private = &zs_soft_private[n];
+ zs_soft[n].private->zs_channel = &zs_channels[n];
+ zs_soft[n].irq = IRQ4;
+#if 0
+ if (request_irq(ch->intrs[0], rs_interrupt, 0,
+ "SCC", &zs_soft[n]))
+ panic("macserial: can't get irq %d",
+ ch->intrs[0]);
+#endif
+ if (n & 1)
+ zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
+ else
+ zs_soft[n].private->zs_chan_a = &zs_channels[n];
+ }
+
+ zs_channels_found=2;
+}
+
+#else
+
+/*
+ * PowerMAC - query the PROM
+ */
+
+static void show_serial_version(void)
+{
+ printk("PowerMac Z8530 serial driver version 1.00\n");
+}
+
+/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
+static void
+probe_sccs()
+{
+ struct device_node *dev, *ch;
+ struct m68k_async_struct **pp;
+ int n;
+
+ n = 0;
+ pp = &zs_chain;
+ for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+ if (n >= NUM_CHANNELS) {
+ printk("Sorry, can't use %s: no more channels\n",
+ dev->full_name);
+ continue;
+ }
+ for (ch = dev->child; ch != 0; ch = ch->sibling) {
+ if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+ printk("Can't use %s: %d addrs %d intrs\n",
+ ch->full_name, ch->n_addrs, ch->n_intrs);
+ continue;
+ }
+ zs_channels[n].control = (volatile unsigned char *)
+ ch->addrs[0].address;
+ zs_channels[n].data = zs_channels[n].control
+ + ch->addrs[0].size / 2;
+ zs_soft[n].private = &zs_soft_private[n];
+ zs_soft[n].private->zs_channel = &zs_channels[n];
+ zs_soft[n].irq = ch->intrs[0];
+ if (request_irq(ch->intrs[0], mac_SCC_interrupt, 0,
+ "SCC", &zs_soft[n]))
+ panic("macserial: can't get irq %d",
+ ch->intrs[0]);
+ /* XXX this assumes the prom puts chan A before B */
+ if (n & 1)
+ zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
+ else
+ zs_soft[n].private->zs_chan_a = &zs_channels[n];
+
+ *pp = &zs_soft[n];
+ pp = &zs_soft[n].private->zs_next;
+ ++n;
+ }
+ }
+ *pp = 0;
+ zs_channels_found = n;
+}
+
+#endif
+
+extern void register_console(void (*proc)(const char *));
+
+static inline void
+rs_cons_check(struct m68k_async_struct *ss, int channel)
+{
+ int i, o, io;
+ static consout_registered = 0;
+ static msg_printed = 0;
+
+ i = o = io = 0;
+
+ /* Is this one of the serial console lines? */
+ if ((zs_cons_chanout != channel) &&
+ (zs_cons_chanin != channel))
+ return;
+ zs_conschan = ss->private->zs_channel;
+ zs_consinfo = ss;
+
+ /* Register the console output putchar, if necessary */
+ if (zs_cons_chanout == channel) {
+ o = 1;
+ /* double whee.. */
+ if (!consout_registered) {
+ register_console(zs_console_print);
+ consout_registered = 1;
+ }
+ }
+
+ if (zs_cons_chanin == channel) {
+ i = 1;
+ }
+ if (o && i)
+ io = 1;
+ if (ss->private->zs_baud != 9600)
+ panic("Console baud rate weirdness");
+
+ /* Set flag variable for this port so that it cannot be
+ * opened for other uses by accident.
+ */
+ ss->private->is_cons = 1;
+
+ if (io) {
+ if(!msg_printed) {
+ printk("zs%d: console I/O\n", ((channel>>1)&1));
+ msg_printed = 1;
+ }
+ } else {
+ printk("zs%d: console %s\n", ((channel>>1)&1),
+ (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
+ }
+
+ /* FIXME : register interrupt here??? */
+}
+
+volatile int test_done;
+
+/* rs_init inits the driver */
+int mac_SCC_init(void)
+{
+ int channel, line, nr = 0, i;
+ unsigned long flags;
+ struct serial_struct req;
+ struct m68k_async_struct *info;
+
+ printk("Mac68K Z8530 serial driver version 1.01\n");
+
+ /* SCC present at all? */
+ if (MACH_IS_ATARI || MACH_IS_AMIGA
+#if 0
+ || !(MACHW_PRESENT(SCC) || MACHW_PRESENT(ST_ESCC))
+#endif
+ )
+ return( -ENODEV );
+
+ if (zs_chain == 0)
+ probe_sccs();
+
+ save_flags(flags);
+ cli();
+
+ /*
+ * FIXME: init of rs_table entry and register_serial now done,
+ * but possible clash of zs_soft[channel] and rs_table[channel]!!
+ * zs_soft initialized in probe_sccs(), some settings copied to
+ * info = &rs_table[channel], which is used by the mid-level code.
+ * The info->private part is shared among both!
+ */
+
+ for (channel = 0; channel < zs_channels_found; ++channel) {
+ req.line = channel;
+ req.type = SER_SCC_MAC;
+ req.port = zs_soft[channel].private->zs_channel->control;
+
+ if ((line = register_serial( &req )) >= 0) {
+ SCC_init_port( &rs_table[line], req.type, line );
+ ++nr;
+ }
+ else
+ printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line );
+ }
+
+ restore_flags(flags);
+
+ return( nr > 0 ? 0 : -ENODEV );
+}
+
+/* Hooks for running a serial console. con_init() calls this if the
+ * console is being run over one of the serial ports.
+ * 'channel' is decoded as 0=modem 1=printer, 'chip' is ignored.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+ if (zs_chain == 0)
+ probe_sccs();
+ zs_soft[channel].private->clk_divisor = 16;
+ zs_soft[channel].private->zs_baud = get_zsbaud(&zs_soft[channel]);
+ rs_cons_check(&zs_soft[channel], channel);
+ if (out)
+ zs_cons_chanout = channel;
+ else
+ zs_cons_chanin = channel;
+
+ /* FIXME : register interrupt here??? */
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1
+ * for /dev/ttyS1 which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+ if (zs_chain == 0)
+ probe_sccs();
+ zs_kgdbchan = zs_soft[tty_num].private->zs_channel;
+ zs_soft[tty_num].private->clk_divisor = 16;
+ zs_soft[tty_num].private->zs_baud = get_zsbaud(&zs_soft[tty_num]);
+ zs_soft[tty_num].private->kgdb_channel = 1; /* This runs kgdb */
+ zs_soft[tty_num ^ 1].private->kgdb_channel = 0; /* This does not */
+ /* Turn on transmitter/receiver at 8-bits/char */
+ kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+ ZS_CLEARERR(zs_kgdbchan);
+ ZS_CLEARFIFO(zs_kgdbchan);
+
+ /* FIXME : register interrupt here??? */
+}
+
--- /dev/null
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _MAC_SCC_H
+#define _MAC_SCC_H
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output. 65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF 0
+#define ZILOG_CLOSING_WAIT_NONE 65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
+ on the callout port */
+#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK 0x0030
+#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
+ * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+/* MSch: gone to <asm/serial.h> */
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP 0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define FLAG 0x7e
+
+/* Write Register 0 */
+#define R0 0 /* Register selects */
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define NULLCODE 0 /* Null Code */
+#define POINT_HIGH 0x8 /* Select upper half of registers */
+#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
+#define SEND_ABORT 0x18 /* HDLC Abort */
+#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
+#define RES_Tx_P 0x28 /* Reset TxINT Pending */
+#define ERR_RES 0x30 /* Error Reset */
+#define RES_H_IUS 0x38 /* Reset highest IUS */
+
+#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
+#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
+#define RES_EOM_L 0xC0 /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
+#define TxINT_ENAB 0x2 /* Tx Int Enable */
+#define PAR_SPEC 0x4 /* Parity is special condition */
+
+#define RxINT_DISAB 0 /* Rx Int Disable */
+#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
+#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
+#define INT_ERR_Rx 0x18 /* Int on error only */
+
+#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
+#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define RxENABLE 0x1 /* Rx Enable */
+#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
+#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
+#define ENT_HM 0x10 /* Enter Hunt Mode */
+#define AUTO_ENAB 0x20 /* Auto Enables */
+#define Rx5 0x0 /* Rx 5 Bits/Character */
+#define Rx7 0x40 /* Rx 7 Bits/Character */
+#define Rx6 0x80 /* Rx 6 Bits/Character */
+#define Rx8 0xc0 /* Rx 8 Bits/Character */
+#define RxNBITS_MASK 0xc0
+
+/* Write Register 4 */
+
+#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_EVEN 0x2 /* Parity Even/Odd* */
+
+#define SYNC_ENAB 0 /* Sync Modes Enable */
+#define SB1 0x4 /* 1 stop bit/char */
+#define SB15 0x8 /* 1.5 stop bits/char */
+#define SB2 0xc /* 2 stop bits/char */
+#define SB_MASK 0xc
+
+#define MONSYNC 0 /* 8 Bit Sync character */
+#define BISYNC 0x10 /* 16 bit sync character */
+#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC 0x30 /* External Sync Mode */
+
+#define X1CLK 0x0 /* x1 clock mode */
+#define X16CLK 0x40 /* x16 clock mode */
+#define X32CLK 0x80 /* x32 clock mode */
+#define X64CLK 0xC0 /* x64 clock mode */
+#define XCLK_MASK 0xC0
+
+/* Write Register 5 */
+
+#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
+#define RTS 0x2 /* RTS */
+#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
+#define TxENAB 0x8 /* Tx Enable */
+#define SND_BRK 0x10 /* Send Break */
+#define Tx5 0x0 /* Tx 5 bits (or less)/character */
+#define Tx7 0x20 /* Tx 7 bits/character */
+#define Tx6 0x40 /* Tx 6 bits/character */
+#define Tx8 0x60 /* Tx 8 bits/character */
+#define TxNBITS_MASK 0x60
+#define DTR 0x80 /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define VIS 1 /* Vector Includes Status */
+#define NV 2 /* No Vector */
+#define DLC 4 /* Disable Lower Chain */
+#define MIE 8 /* Master Interrupt Enable */
+#define STATHI 0x10 /* Status high */
+#define NORESET 0 /* No reset on write to R9 */
+#define CHRB 0x40 /* Reset channel B */
+#define CHRA 0x80 /* Reset channel A */
+#define FHWRES 0xc0 /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define BIT6 1 /* 6 bit/8bit sync */
+#define LOOPMODE 2 /* SDLC Loop mode */
+#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE 8 /* Mark/flag on idle */
+#define GAOP 0x10 /* Go active on poll */
+#define NRZ 0 /* NRZ mode */
+#define NRZI 0x20 /* NRZI mode */
+#define FM1 0x40 /* FM1 (transition = 1) */
+#define FM0 0x60 /* FM0 (transition = 0) */
+#define CRCPS 0x80 /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define TRxCXT 0 /* TRxC = Xtal output */
+#define TRxCTC 1 /* TRxC = Transmit clock */
+#define TRxCBR 2 /* TRxC = BR Generator Output */
+#define TRxCDP 3 /* TRxC = DPLL output */
+#define TRxCOI 4 /* TRxC O/I */
+#define TCRTxCP 0 /* Transmit clock = RTxC pin */
+#define TCTRxCP 8 /* Transmit clock = TRxC pin */
+#define TCBR 0x10 /* Transmit clock = BR Generator output */
+#define TCDPLL 0x18 /* Transmit clock = DPLL output */
+#define RCRTxCP 0 /* Receive clock = RTxC pin */
+#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
+#define RCBR 0x40 /* Receive clock = BR Generator output */
+#define RCDPLL 0x60 /* Receive clock = DPLL output */
+#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define BRENABL 1 /* Baud rate generator enable */
+#define BRSRC 2 /* Baud rate generator source */
+#define DTRREQ 4 /* DTR/Request function */
+#define AUTOECHO 8 /* Auto Echo */
+#define LOOPBAK 0x10 /* Local loopback */
+#define SEARCH 0x20 /* Enter search mode */
+#define RMC 0x40 /* Reset missing clock */
+#define DISDPLL 0x60 /* Disable DPLL */
+#define SSBR 0x80 /* Set DPLL source = BR generator */
+#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
+#define SFMM 0xc0 /* Set FM mode */
+#define SNRZI 0xe0 /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define ZCIE 2 /* Zero count IE */
+#define DCDIE 8 /* DCD IE */
+#define SYNCIE 0x10 /* Sync/hunt IE */
+#define CTSIE 0x20 /* CTS IE */
+#define TxUIE 0x40 /* Tx Underrun/EOM IE */
+#define BRKIE 0x80 /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define Rx_CH_AV 0x1 /* Rx Character Available */
+#define ZCOUNT 0x2 /* Zero count */
+#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
+#define DCD 0x8 /* DCD */
+#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define CTS 0x20 /* CTS */
+#define TxEOM 0x40 /* Tx underrun */
+#define BRK_ABRT 0x80 /* Break/Abort */
+
+/* Read Register 1 */
+#define ALL_SNT 0x1 /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3 0x8 /* 0/3 */
+#define RES4 0x4 /* 0/4 */
+#define RES5 0xc /* 0/5 */
+#define RES6 0x2 /* 0/6 */
+#define RES7 0xa /* 0/7 */
+#define RES8 0x6 /* 0/8 */
+#define RES18 0xe /* 1/8 */
+#define RES28 0x0 /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR 0x10 /* Parity error */
+#define Rx_OVR 0x20 /* Rx Overrun Error */
+#define FRM_ERR 0x40 /* CRC/Framing Error */
+#define END_FR 0x80 /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
+#define CHBTxIP 0x2 /* Channel B Tx IP */
+#define CHBRxIP 0x4 /* Channel B Rx IP */
+#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
+#define CHATxIP 0x10 /* Channel A Tx IP */
+#define CHARxIP 0x20 /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10 (misc status bits) */
+#define ONLOOP 2 /* On loop */
+#define LOOPSEND 0x10 /* Loop sending */
+#define CLK2MIS 0x40 /* Two clocks missing */
+#define CLK1MIS 0x80 /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
+ garbage = read_zsdata(channel); \
+ garbage = read_zsdata(channel); \
+ garbage = read_zsdata(channel); \
+ } while(0)
+
+#endif /* !(_MAC_SCC_H) */
#include <asm/pgtable.h>
#ifdef CONFIG_SOUND
+void soundcore_init(void);
+#ifdef CONFIG_SOUND_OSS
void soundcard_init(void);
#endif
+#ifdef CONFIG_DMASOUND
+void dmasound_init(void);
+#endif
+#endif
#ifdef CONFIG_ISDN
int isdn_init(void);
#endif
#ifdef CONFIG_SOUND_OSS
soundcard_init();
#endif
+#ifdef CONFIG_DMASOUND
+ dmasound_init();
+#endif
#endif
#ifdef CONFIG_JOYSTICK
/*
extern int amiga_mouse_init(void);
extern int atari_mouse_init(void);
extern int sun_mouse_init(void);
+extern int adb_mouse_init(void);
extern void watchdog_init(void);
extern void wdt_init(void);
extern void acq_init(void);
#ifdef CONFIG_SUN_MOUSE
sun_mouse_init();
#endif
+#ifdef CONFIG_MACMOUSE
+ adb_mouse_init();
+#endif
#ifdef CONFIG_PC110_PAD
pc110pad_init();
#endif
#ifdef CONFIG_H8
h8_init();
#endif
-#ifdef CONFIG_RTC
+#if defined(CONFIG_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
rtc_init();
#endif
#ifdef CONFIG_ATARI_DSP56K
*
* They're only built if CONFIG_ATARI is defined, because Atari drivers use
* them. For other configurations (PC), the rest of the kernel can't rely on
- * them being present (this driver couldn't be configured at all, or as a
+ * them being present (this driver may not be configured at all, or as a
* module), so they access config information themselves.
*/
return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
}
-static ssize_t nvram_read( struct file * file,
- char * buf, size_t count, loff_t *ppos )
+static ssize_t nvram_read(struct file * file,
+ char * buf, size_t count, loff_t *ppos )
{
unsigned long flags;
unsigned i = *ppos;
char *tmp = buf;
+
+ if (i != *ppos)
+ return -EINVAL;
save_flags(flags);
cli();
return( tmp - buf );
}
-static ssize_t nvram_write( struct file * file, const char * buf, size_t count, loff_t *ppos )
+static ssize_t nvram_write(struct file * file,
+ const char * buf, size_t count, loff_t *ppos )
{
unsigned long flags;
unsigned i = *ppos;
const char *tmp = buf;
char c;
+
+ if (i != *ppos)
+ return -EINVAL;
save_flags(flags);
cli();
if (!CHECK_DRIVER_INIT())
return( -ENXIO );
- printk( "Non-volatile memory driver v%s\n", NVRAM_VERSION );
+ printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION );
misc_register( &nvram_dev );
#ifdef CONFIG_PROC_FS
if ((proc_nvram = create_proc_entry( "nvram", 0, 0 )))
#define fieldsize(a) (sizeof(a)/sizeof(*a))
static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
- off_t *begin, off_t offset, int size )
+ off_t *begin, off_t offset, int size )
{
int checksum = nvram_check_checksum();
int i;
/* the following entries are defined only for the Falcon */
if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
- return;
+ return 1;
PRINT_PROC( "OS language : " );
if (nvram[6] < fieldsize(languages))
| KBD_MODE_DISABLE_MOUSE
| KBD_MODE_KCC);
+ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
+ if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+ /*
+ * If the controller does not support conversion,
+ * Set the keyboard to scan-code set 1.
+ */
+ kbd_write(KBD_DATA_REG, 0xF0);
+ kbd_wait_for_input();
+ kbd_write(KBD_DATA_REG, 0x01);
+ kbd_wait_for_input();
+ }
+
+
kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
if (kbd_wait_for_input() != KBD_REPLY_ACK)
return "Enable keyboard: no ACK";
/* radiotrack (radioreveal) driver for Linux radio support
* (c) 1997 M. Kirkwood
* Coverted to new API by Alan Cox <Alan.Cox@linux.org>
+ * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
* TODO: Allow for more than one of these foolish entities :-)
*
/* local things */
-static void sleep_delay(int n)
+static void sleep_delay(long n)
{
/* Sleep nicely for 'n' uS */
int d=n/1000000/HZ;
schedule();
}
}
-
-/* Clock out data to the chip. This looks suspiciously like i2c as usual */
-
-static void outbits(int bits, int data, int port)
-{
- while(bits--)
- {
- if(data & 1)
- {
- outw(5, port);
- outw(5, port);
- outw(7, port);
- outw(7, port);
- }
- else
- {
- outw(1, port);
- outw(1, port);
- outw(3, port);
- outw(3, port);
- }
- data>>=1;
- }
-}
-static void rt_decvol(int port)
+static void rt_decvol(void)
{
- outb(0x48, port);
+ outb(0x58, io); /* volume down + sigstr + on */
sleep_delay(100000);
- outb(0xc8, port);
+ outb(0xd8, io); /* volume steady + sigstr + on */
}
-static void rt_incvol(int port)
+static void rt_incvol(void)
{
- outb(0x88, port);
+ outb(0x98, io); /* volume up + sigstr + on */
sleep_delay(100000);
- outb(0xc8, port);
+ outb(0xd8, io); /* volume steady + sigstr + on */
}
-static void rt_mute(int port)
+static void rt_mute(void)
{
- outb(0, port);
- outb(0xc0, port);
-}
-
-static void rt_unmute(int port)
-{
- outb(0, port);
- outb(0xc8, port);
+ outb(0x48, io); /* volume down but still "on" */
+ sleep_delay(2000000); /* make sure it's totally down */
+ outb(0xc0, io); /* volume steady, off */
}
static int rt_setvol(struct rt_device *dev, int vol)
{
int i;
- if(vol == dev->curvol)
+
+ if(vol == dev->curvol) /* no change needed */
return 0;
- if(vol == 0)
- rt_mute(dev->port);
+ if(vol == 0) { /* volume = 0 means mute the card */
+ rt_mute();
+ dev->curvol = 0;
+ return 0;
+ }
if(vol > dev->curvol)
- for(i = dev->curvol; i < vol; i++)
- rt_incvol(dev->port);
+ for(i = dev->curvol; i < vol; i++)
+ rt_incvol();
else
- for(i = dev->curvol; i > vol; i--)
- rt_decvol(dev->port);
+ for(i = dev->curvol; i > vol; i--)
+ rt_decvol();
- if(dev->curvol == 0)
- rt_unmute(dev->port);
+ dev->curvol = vol;
return 0;
}
-static int rt_setfreq(struct rt_device *dev, unsigned long frequency)
+/* the 128+64 on these outb's is to keep the volume stable while tuning
+ * without them, the volume _will_ creep up with each frequency change
+ * and bit 4 (+16) is to keep the signal strength meter enabled
+ */
+
+void send_0_byte(int port, struct rt_device *dev)
+{
+ if (dev->curvol == 0) {
+ outb_p(128+64+16+ 1, port); /* wr-enable + data low */
+ outb_p(128+64+16+2+1, port); /* clock */
+ }
+ else {
+ outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */
+ outb_p(128+64+16+8+2+1, port); /* clock */
+ }
+ sleep_delay(1000);
+}
+
+void send_1_byte(int port, struct rt_device *dev)
+{
+ if (dev->curvol == 0) {
+ outb_p(128+64+16+4 +1, port); /* wr-enable+data high */
+ outb_p(128+64+16+4+2+1, port); /* clock */
+ }
+ else {
+ outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */
+ outb_p(128+64+16+8+4+2+1, port); /* clock */
+ }
+
+ sleep_delay(1000);
+}
+
+static int rt_setfreq(struct rt_device *dev, unsigned long freq)
{
- int myport = dev->port;
-#define RTRACK_ENCODE(x) (((((x)*2)/5)-(40*88))+0xf6c)
- outbits(16, RTRACK_ENCODE(frequency), myport);
- outbits(8, 0xa0, myport);
-/* XXX - get rid of this once setvol is implemented properly - XXX */
-/* these insist on turning the thing on. not sure I approve... */
- udelay(1000);
- outb(0, myport);
- outb(0xc8, myport);
+ int i;
+
+ /* adapted from radio-aztech.c */
+
+ freq = (freq / 16.0) * 100; /* massage the data a little */
+ freq += 1070; /* IF = 10.7 MHz */
+ freq /= 5; /* ref = 25 kHz */
+
+ send_0_byte (io, dev); /* 0: LSB of frequency */
+
+ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
+ if (freq & (1 << i))
+ send_1_byte (io, dev);
+ else
+ send_0_byte (io, dev);
+
+ send_0_byte (io, dev); /* 14: test bit - always 0 */
+ send_0_byte (io, dev); /* 15: test bit - always 0 */
+
+ send_0_byte (io, dev); /* 16: band data 0 - always 0 */
+ send_0_byte (io, dev); /* 17: band data 1 - always 0 */
+ send_0_byte (io, dev); /* 18: band data 2 - always 0 */
+ send_0_byte (io, dev); /* 19: time base - always 0 */
+
+ send_0_byte (io, dev); /* 20: spacing (0 = 25 kHz) */
+ send_1_byte (io, dev); /* 21: spacing (1 = 25 kHz) */
+ send_0_byte (io, dev); /* 22: spacing (0 = 25 kHz) */
+ send_1_byte (io, dev); /* 23: AM/FM (FM = 1, always) */
+
+ if (dev->curvol == 0)
+ outb (0xd0, io); /* volume steady + sigstr */
+ else
+ outb (0xd8, io); /* volume steady + sigstr + on */
return 0;
}
int rt_getsigstr(struct rt_device *dev)
{
- int res;
- int myport = dev->port;
-
- outb(0xf8, myport);
- sleep_delay(200000);
- res = (int)inb(myport);
- sleep_delay(10000);
- outb(0xe8, myport);
- if(res == 0xfd)
- return 1;
- else
+ if (inb(io) & 2) /* bit set = no signal present */
return 0;
+ return 1; /* signal present */
}
static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_audio v;
memset(&v,0, sizeof(v));
v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
- v.volume=rt->curvol;
+ v.volume=rt->curvol * 6554;
strcpy(v.name, "Radio");
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
return -EFAULT;
if(v.audio)
return -EINVAL;
- rt->curvol=v.volume;
- if(v.flags&VIDEO_AUDIO_MUTE)
- rt_mute(rt->port);
+ if(v.flags&VIDEO_AUDIO_MUTE) {
+ rt_mute();
+ rt->curvol=0;
+ }
else
- rt_setvol(rt,rt->curvol/6554);
+ rt_setvol(rt,v.volume/6554);
+
return 0;
}
default:
request_region(io, 2, "rtrack");
printk(KERN_INFO "AIMSlab Radiotrack/radioreveal card driver.\n");
/* mute card - prevents noisy bootups */
- rt_mute(io);
+ rt_mute();
+ rtrack_unit.curvol = 0;
return 0;
}
do_gettimeofday(&tv);
add_entropy_words(r, tv.tv_sec, tv.tv_usec);
+ /*
+ * This doesnt lock system.utsname. Howeve we are generating
+ * entropy so a race with a name set here is fine.
+ */
p = (__u32 *)&system_utsname;
for (i = sizeof(system_utsname) / sizeof(words); i; i--) {
memcpy(words, p, sizeof(words));
static int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(struct file * filp, int on);
+#ifdef CONFIG_8xx
+extern long console_8xx_init(void);
+extern int rs_8xx_init(void);
+#endif /* CONFIG_8xx */
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#ifdef CONFIG_SERIAL
rs_init();
#endif
+#ifdef CONFIG_MAC_SERIAL
+ macserial_init();
+#endif
#ifdef CONFIG_ROCKETPORT
rp_init();
#endif
#ifdef CONFIG_SPECIALIX
specialix_init();
#endif
+#ifdef CONFIG_8xx
+ rs_8xx_init();
+#endif /* CONFIG_8xx */
pty_init();
#ifdef CONFIG_VT
vcs_init();
--- /dev/null
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+#
+# NB: cribbed from the drivers/sbus/Makefile -- PMM
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_OBJS := dio.o
+L_TARGET := dio.a
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/* Code to support devices on the DIO (and eventually DIO-II) bus
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * This code has basically these routines at the moment:
+ * int dio_find(u_int deviceid)
+ * Search the list of DIO devices and return the select code
+ * of the next unconfigured device found that matches the given device ID.
+ * Note that the deviceid parameter should be the encoded ID.
+ * This means that framebuffers should pass it as
+ * DIO_ENCODE_ID(DIO_ID_FBUFFER,DIO_ID2_TOPCAT)
+ * (or whatever); everybody else just uses DIO_ID_FOOBAR.
+ * void *dio_scodetoviraddr(int scode)
+ * Return the virtual address corresponding to the given select code.
+ * NB: DIO-II devices will have to be mapped in in this routine!
+ * int dio_scodetoipl(int scode)
+ * Every DIO card has a fixed interrupt priority level. This function
+ * returns it, whatever it is.
+ * const char *dio_scodetoname(int scode)
+ * Return a character string describing this board [might be "" if
+ * not CONFIG_DIO_CONSTANTS]
+ * void dio_config_board(int scode) mark board as configured in the list
+ * void dio_unconfig_board(int scode) mark board as no longer configured
+ *
+ * This file is based on the way the Amiga port handles Zorro II cards,
+ * although we aren't so complicated...
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/dio.h>
+#include <linux/malloc.h> /* kmalloc() */
+#include <linux/init.h>
+#include <asm/hwtest.h> /* hwreg_present() */
+#include <asm/io.h> /* readb() */
+/* not a real config option yet! */
+#define CONFIG_DIO_CONSTANTS
+
+#ifdef CONFIG_DIO_CONSTANTS
+/* We associate each numeric ID with an appropriate descriptive string
+ * using a constant array of these structs.
+ * FIXME: we should be able to arrange to throw away most of the strings
+ * using the initdata stuff. Then we wouldn't need to worry about
+ * carrying them around...
+ * I think we do this by copying them into newly kmalloc()ed memory and
+ * marking the names[] array as .initdata ?
+ */
+struct dioname
+{
+ int id;
+ const char *name;
+};
+
+/* useful macro */
+#define DIONAME(x) { DIO_ID_##x, DIO_DESC_##x }
+#define DIOFBNAME(x) { DIO_ENCODE_ID( DIO_ID_FBUFFER, DIO_ID2_##x), DIO_DESC2_##x }
+
+static struct dioname names[] =
+{
+ DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM),
+ DIONAME(DCM), DIONAME(DCMREM),
+ DIONAME(LAN),
+ DIONAME(FHPIB), DIONAME(NHPIB), DIONAME(IHPIB),
+ DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3),
+ DIONAME(FBUFFER),
+ DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM),
+ DIONAME(MISC0), DIONAME(MISC1), DIONAME(MISC2), DIONAME(MISC3),
+ DIONAME(MISC4), DIONAME(MISC5), DIONAME(MISC6), DIONAME(MISC7),
+ DIONAME(MISC8), DIONAME(MISC9), DIONAME(MISC10), DIONAME(MISC11),
+ DIONAME(MISC12), DIONAME(MISC13),
+ DIOFBNAME(GATORBOX), DIOFBNAME(TOPCAT), DIOFBNAME(RENAISSANCE),
+ DIOFBNAME(LRCATSEYE), DIOFBNAME(HRCCATSEYE), DIOFBNAME(HRMCATSEYE),
+ DIOFBNAME(DAVINCI), DIOFBNAME(XXXCATSEYE), DIOFBNAME(HYPERION),
+ DIOFBNAME(XGENESIS), DIOFBNAME(TIGER), DIOFBNAME(YGENESIS)
+};
+
+#undef DIONAME
+#undef DIOFBNAME
+
+#define NUMNAMES (sizeof(names) / sizeof(struct dioname))
+
+static const char *unknowndioname
+ = "unknown DIO board -- please email <pmaydell@chiark.greenend.org.uk>!";
+
+static const char *dio_getname(int id)
+{
+ /* return pointer to a constant string describing the board with given ID */
+ unsigned int i;
+ for (i = 0; i < NUMNAMES; i++)
+ if (names[i].id == id)
+ return names[i].name;
+
+ return unknowndioname;
+}
+
+#else
+
+static char dio_no_name[] = { 0 };
+#define dio_getname(_id) (dio_no_name)
+
+#endif /* CONFIG_DIO_CONSTANTS */
+
+/* We represent all the DIO boards in the system with a linked list of these structs. */
+struct dioboard
+{
+ struct dioboard *next; /* link to next struct in list */
+ int ipl; /* IPL of this board */
+ int configured; /* has this board been configured? */
+ int scode; /* select code of this board */
+ int id; /* encoded ID */
+ const char *name;
+};
+
+static struct dioboard *blist = NULL;
+
+__initfunc(static int dio_find_slow(int deviceid))
+{
+ /* Called to find a DIO device before the full bus scan has run. Basically
+ only used by the console driver. */
+ int scode;
+ for (scode = 0; scode < DIO_SCMAX; scode++)
+ {
+ void *va;
+
+ if (DIO_SCINHOLE(scode))
+ continue;
+
+ va = dio_scodetoviraddr(scode);
+ if (!va || !hwreg_present(va + DIO_IDOFF))
+ continue; /* no board present at that select code */
+
+ if (DIO_ID(va) == deviceid)
+ return scode;
+ }
+ return 0;
+}
+
+int dio_find(int deviceid)
+{
+ if (blist)
+ {
+ /* fast way */
+ struct dioboard *b;
+ for (b = blist; b; b = b->next)
+ if (b->id == deviceid && b->configured == 0)
+ return b->scode;
+ return 0;
+ }
+ return dio_find_slow(deviceid);
+}
+
+/* This is the function that scans the DIO space and works out what
+ * hardware is actually present.
+ */
+__initfunc(void dio_init(void))
+{
+ int scode;
+ struct dioboard *b, *bprev = NULL;
+
+ printk("Scanning for DIO devices...\n");
+
+ for (scode = 0; scode < DIO_SCMAX; ++scode)
+ {
+ u_char prid, secid = 0; /* primary, secondary ID bytes */
+ u_char *va;
+
+ if (DIO_SCINHOLE(scode))
+ continue;
+
+ va = dio_scodetoviraddr(scode);
+ if (!va || !hwreg_present(va + DIO_IDOFF))
+ continue; /* no board present at that select code */
+
+ /* Found a board, allocate it an entry in the list */
+ b = kmalloc(sizeof(struct dioboard), GFP_KERNEL);
+
+ /* read the ID byte(s) and encode if necessary. Note workaround
+ * for broken internal HPIB devices...
+ */
+ if (!DIO_ISIHPIB(scode))
+ prid = DIO_ID(va);
+ else
+ prid = DIO_ID_IHPIB;
+
+ if (DIO_NEEDSSECID(prid))
+ {
+ secid = DIO_SECID(va);
+ b->id = DIO_ENCODE_ID(prid, secid);
+ }
+ else
+ b->id = prid;
+
+ b->configured = 0;
+ b->scode = scode;
+ b->ipl = DIO_IPL(va);
+ b->name = dio_getname(b->id);
+ printk("select code %3d: ID %02X", scode, prid);
+ if (DIO_NEEDSSECID(b->id))
+ printk(":%02X", secid);
+ printk(" %s\n", b->name);
+
+ b->next = NULL;
+
+ if (bprev)
+ bprev->next = b;
+ else
+ blist = b;
+ bprev = b;
+ }
+}
+
+/* Bear in mind that this is called in the very early stages of initialisation
+ * in order to get the virtual address of the serial port for the console...
+ */
+void *dio_scodetoviraddr(int scode)
+{
+ if (scode > DIOII_SCBASE)
+ {
+ printk("dio_scodetoviraddr: don't support DIO-II yet!\n");
+ return 0;
+ }
+ else if (scode > DIO_SCMAX || scode < 0)
+ return 0;
+ else if (DIO_SCINHOLE(scode))
+ return 0;
+ else if (scode == DIO_IHPIBSCODE) /* this should really be #ifdef CONFIG_IHPIB */
+ return (void*)DIO_IHPIBADDR; /* or something similar... */
+
+ return (void*)(DIO_VIRADDRBASE + DIO_BASE + scode * 0x10000);
+}
+
+int dio_scodetoipl(int scode)
+{
+ struct dioboard *b;
+ for (b = blist; b; b = b->next)
+ if (b->scode == scode)
+ break;
+
+ if (!b)
+ {
+ printk("dio_scodetoipl: bad select code %d\n", scode);
+ return 0;
+ }
+ else
+ return b->ipl;
+}
+
+const char *dio_scodetoname(int scode)
+{
+ struct dioboard *b;
+ for (b = blist; b; b = b->next)
+ if (b->scode == scode)
+ break;
+
+ if (!b)
+ {
+ printk("dio_scodetoname: bad select code %d\n", scode);
+ return NULL;
+ }
+ else
+ return b->name;
+}
+
+void dio_config_board(int scode)
+{
+ struct dioboard *b;
+ for (b = blist; b; b = b->next)
+ if (b->scode == scode)
+ break;
+
+ if (!b)
+ printk("dio_config_board: bad select code %d\n", scode);
+ else if (b->configured)
+ printk("dio_config_board: board at select code %d already configured\n", scode);
+ else
+ b->configured = 1;
+}
+
+void dio_unconfig_board(int scode)
+{
+ struct dioboard *b;
+ for (b = blist; b; b = b->next)
+ if (b->scode == scode)
+ break;
+
+ if (!b)
+ printk("dio_unconfig_board: bad select code %d\n", scode);
+ else if (!b->configured)
+ printk("dio_unconfig_board: board at select code %d not configured\n",
+ scode);
+ else
+ b->configured = 0;
+}
arc_release_resources,
arc_claim_resources,
+ NULL, /* epp_write_data */
+ NULL, /* epp_read_data */
+ NULL, /* epp_write_addr */
+ NULL, /* epp_read_addr */
+ NULL, /* epp_check_timeout */
+
NULL, /* epp_write_block */
NULL, /* epp_read_block */
#define DATA 0x00
#define STATUS 0x01
#define CONTROL 0x02
-#define EPPREG 0x04
+#define EPPADDR 0x03
+#define EPPDATA 0x04
#define CFIFO 0x400
#define DFIFO 0x400
void
parport_ax_write_epp(struct parport *p, unsigned char d)
{
- outb(d, p->base + EPPREG);
+ outb(d, p->base + EPPDATA);
}
unsigned char
parport_ax_read_epp(struct parport *p)
{
- return inb(p->base + EPPREG);
+ return inb(p->base + EPPDATA);
+}
+
+void
+parport_ax_write_epp_addr(struct parport *p, unsigned char d)
+{
+ outb(d, p->base + EPPADDR);
+}
+
+unsigned char
+parport_ax_read_epp_addr(struct parport *p)
+{
+ return inb(p->base + EPPADDR);
+}
+
+int
+parport_ax_check_epp_timeout(struct parport *p)
+{
+ if (!(inb(p->base+STATUS) & 1))
+ return 0;
+ parport_ax_epp_clear_timeout(p);
+ return 1;
}
unsigned char
parport_ax_release_resources,
parport_ax_claim_resources,
+ parport_ax_write_epp,
+ parport_ax_read_epp,
+ parport_ax_write_epp_addr,
+ parport_ax_read_epp_addr,
+ parport_ax_check_epp_timeout,
+
parport_ax_epp_write_block,
parport_ax_epp_read_block,
if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops)))
return 0;
- /* Safe away pointer to our EBus DMA */
+ /* Save away pointer to our EBus DMA */
p->private_data = (void *)dev->base_address[2];
p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p);
*
* In addition, there are some optional registers:
*
- * base+3 EPP command
- * base+4 EPP
+ * base+3 EPP address
+ * base+4 EPP data
* base+0x400 ECP config A
* base+0x401 ECP config B
* base+0x402 ECP control
void parport_pc_write_epp(struct parport *p, unsigned char d)
{
- outb(d, p->base+EPPREG);
+ outb(d, p->base+EPPDATA);
}
unsigned char parport_pc_read_epp(struct parport *p)
{
- return inb(p->base+EPPREG);
+ return inb(p->base+EPPDATA);
+}
+
+void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+{
+ outb(d, p->base+EPPADDR);
+}
+
+unsigned char parport_pc_read_epp_addr(struct parport *p)
+{
+ return inb(p->base+EPPADDR);
+}
+
+int parport_pc_check_epp_timeout(struct parport *p)
+{
+ if (!(inb(p->base+STATUS) & 1))
+ return 0;
+ parport_pc_epp_clear_timeout(p);
+ return 1;
}
unsigned char parport_pc_read_configb(struct parport *p)
{
size_t got = 0;
for (; got < length; got++) {
- *((char*)buf)++ = inb (p->base+EPPREG);
+ *((char*)buf)++ = inb (p->base+EPPDATA);
if (inb (p->base+STATUS) & 0x01)
break;
}
{
size_t written = 0;
for (; written < length; written++) {
- outb (*((char*)buf)++, p->base+EPPREG);
+ outb (*((char*)buf)++, p->base+EPPDATA);
if (inb (p->base+STATUS) & 0x01)
break;
}
parport_pc_release_resources,
parport_pc_claim_resources,
+ parport_pc_write_epp,
+ parport_pc_read_epp,
+ parport_pc_write_epp_addr,
+ parport_pc_read_epp_addr,
+ parport_pc_check_epp_timeout,
+
parport_pc_epp_write_block,
parport_pc_epp_read_block,
/*
* Clear TIMEOUT BIT in EPP MODE
*/
-static int epp_clear_timeout(struct parport *pb)
+int parport_pc_epp_clear_timeout(struct parport *pb)
{
unsigned char r;
*/
static int parport_SPP_supported(struct parport *pb)
{
+ /*
+ * first clear an eventually pending EPP timeout
+ * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
+ * that does not even respond to SPP cycles if an EPP
+ * timeout is pending
+ */
+ parport_pc_epp_clear_timeout(pb);
+
/* Do a simple read-write test to make sure the port exists. */
parport_pc_write_control(pb, 0xc);
parport_pc_write_data(pb, 0xaa);
static int parport_EPP_supported(struct parport *pb)
{
/* If EPP timeout bit clear then EPP available */
- if (!epp_clear_timeout(pb))
+ if (!parport_pc_epp_clear_timeout(pb))
return 0; /* No way to clear timeout */
parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
- epp_clear_timeout(pb);
+ parport_pc_epp_clear_timeout(pb);
parport_pc_read_epp(pb);
udelay(30); /* Wait for possible EPP timeout */
if (parport_pc_read_status(pb) & 0x01) {
- epp_clear_timeout(pb);
+ parport_pc_epp_clear_timeout(pb);
return PARPORT_MODE_PCEPP;
}
int ok = 0;
unsigned char octr = parport_pc_read_control(pb);
- epp_clear_timeout(pb);
+ parport_pc_epp_clear_timeout(pb);
parport_pc_write_control(pb, octr | 0x20); /* try to tri-state the buffer */
if (pb->modes & PARPORT_MODE_PCECR)
parport_pc_frob_econtrol (pb, 0x10, 0x10);
- epp_clear_timeout(pb);
+ parport_pc_epp_clear_timeout(pb);
parport_pc_frob_control (pb, 0x20, 0x20);
parport_pc_frob_control (pb, 0x10, 0x10);
- epp_clear_timeout(pb);
+ parport_pc_epp_clear_timeout(pb);
/* Device isn't expecting an EPP read
* and generates an IRQ.
(pb->modes & PARPORT_MODE_PCECPEPP))
pb->irq = irq_probe_EPP(pb);
- epp_clear_timeout(pb);
+ parport_pc_epp_clear_timeout(pb);
if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCEPP))
pb->irq = irq_probe_EPP(pb);
- epp_clear_timeout(pb);
+ parport_pc_epp_clear_timeout(pb);
if (pb->irq == PARPORT_IRQ_NONE)
pb->irq = irq_probe_SPP(pb);
--- /dev/null
+/*
+ * 7990.c -- LANCE ethernet IC generic routines.
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE
+ * (Local Area Network Controller for Ethernet) chip.
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ * NB: this was made easy by the fact that Jes Sorensen had cleaned up
+ * most of a2025 and sunlance with the aim of merging them, so the
+ * common code was pretty obvious.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/pgtable.h>
+#include <linux/errno.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "7990.h"
+
+/* Lossage Factor Nine, Mr Sulu. */
+#define WRITERAP(x) (lp->writerap(lp,x))
+#define WRITERDP(x) (lp->writerdp(lp,x))
+#define READRDP() (lp->readrdp(lp))
+/* These used to be ll->rap = x, ll->rdp = x, and (ll->rdp). Sigh.
+ * If you want to switch them back then
+ * #define DECLARE_LL volatile struct lance_regs *ll = lp->ll
+ */
+#define DECLARE_LL /* nothing to declare */
+
+/* debugging output macros, various flavours */
+/* #define TEST_HITS */
+#ifdef UNDEF
+#define PRINT_RINGS() \
+do { \
+ int t; \
+ for (t=0; t < RX_RING_SIZE; t++) { \
+ printk("R%d: @(%02X %04X) len %04X, mblen %04X, bits %02X\n",\
+ t, ib->brx_ring[t].rmd1_hadr, ib->brx_ring[t].rmd0,\
+ ib->brx_ring[t].length,\
+ ib->brx_ring[t].mblength, ib->brx_ring[t].rmd1_bits);\
+ }\
+ for (t=0; t < TX_RING_SIZE; t++) { \
+ printk("T%d: @(%02X %04X) len %04X, misc %04X, bits %02X\n",\
+ t, ib->btx_ring[t].tmd1_hadr, ib->btx_ring[t].tmd0,\
+ ib->btx_ring[t].length,\
+ ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits);\
+ }\
+} while (0)
+#else
+#define PRINT_RINGS()
+#endif
+
+/* Load the CSR registers. The LANCE has to be STOPped when we do this! */
+static void load_csrs (struct lance_private *lp)
+{
+ volatile struct lance_init_block *aib = lp->lance_init_block;
+ int leptr;
+ DECLARE_LL;
+
+ leptr = LANCE_ADDR (aib);
+
+ WRITERAP(LE_CSR1); /* load address of init block */
+ WRITERDP(leptr & 0xFFFF);
+ WRITERAP(LE_CSR2);
+ WRITERDP(leptr >> 16);
+ WRITERAP(LE_CSR3);
+ WRITERDP(lp->busmaster_regval); /* set byteswap/ALEctrl/byte ctrl */
+
+ /* Point back to csr0 */
+ WRITERAP(LE_CSR0);
+}
+
+/* #define to 0 or 1 appropriately */
+#define DEBUG_IRING 0
+/* Set up the Lance Rx and Tx rings and the init block */
+/* Sets dev->tbusy */
+static void lance_init_ring (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
+ int leptr;
+ int i;
+
+ aib = lp->lance_init_block;
+
+ /* Lock out other processes while setting up hardware */
+ dev->tbusy = 1;
+ lp->rx_new = lp->tx_new = 0;
+ lp->rx_old = lp->tx_old = 0;
+
+ ib->mode = LE_MO_PROM; /* normal, enable Tx & Rx */
+
+ /* Copy the ethernet address to the lance init block
+ * Notice that we do a byteswap if we're big endian.
+ * [I think this is the right criterion; at least, sunlance,
+ * a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
+ * However, the datasheet says that the BSWAP bit doesn't affect
+ * the init block, so surely it should be low byte first for
+ * everybody? Um.]
+ * We could define the ib->physaddr as three 16bit values and
+ * use (addr[1] << 8) | addr[0] & co, but this is more efficient.
+ */
+#ifdef __BIG_ENDIAN
+ ib->phys_addr [0] = dev->dev_addr [1];
+ ib->phys_addr [1] = dev->dev_addr [0];
+ ib->phys_addr [2] = dev->dev_addr [3];
+ ib->phys_addr [3] = dev->dev_addr [2];
+ ib->phys_addr [4] = dev->dev_addr [5];
+ ib->phys_addr [5] = dev->dev_addr [4];
+#else
+ for (i=0; i<6; i++)
+ ib->phys_addr[i] = dev->dev_addr[i];
+#endif
+
+ if (DEBUG_IRING)
+ printk ("TX rings:\n");
+
+ /* Setup the Tx ring entries */
+ for (i = 0; i < (1<<lp->lance_log_tx_bufs); i++) {
+ leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
+ ib->btx_ring [i].tmd0 = leptr;
+ ib->btx_ring [i].tmd1_hadr = leptr >> 16;
+ ib->btx_ring [i].tmd1_bits = 0;
+ ib->btx_ring [i].length = 0xf000; /* The ones required by tmd2 */
+ ib->btx_ring [i].misc = 0;
+ if (DEBUG_IRING)
+ printk ("%d: 0x%8.8x\n", i, leptr);
+ }
+
+ /* Setup the Rx ring entries */
+ if (DEBUG_IRING)
+ printk ("RX rings:\n");
+ for (i = 0; i < (1<<lp->lance_log_rx_bufs); i++) {
+ leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
+
+ ib->brx_ring [i].rmd0 = leptr;
+ ib->brx_ring [i].rmd1_hadr = leptr >> 16;
+ ib->brx_ring [i].rmd1_bits = LE_R1_OWN;
+ /* 0xf000 == bits that must be one (reserved, presumably) */
+ ib->brx_ring [i].length = -RX_BUFF_SIZE | 0xf000;
+ ib->brx_ring [i].mblength = 0;
+ if (DEBUG_IRING)
+ printk ("%d: 0x%8.8x\n", i, leptr);
+ }
+
+ /* Setup the initialization block */
+
+ /* Setup rx descriptor pointer */
+ leptr = LANCE_ADDR(&aib->brx_ring);
+ ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
+ ib->rx_ptr = leptr;
+ if (DEBUG_IRING)
+ printk ("RX ptr: %8.8x\n", leptr);
+
+ /* Setup tx descriptor pointer */
+ leptr = LANCE_ADDR(&aib->btx_ring);
+ ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
+ ib->tx_ptr = leptr;
+ if (DEBUG_IRING)
+ printk ("TX ptr: %8.8x\n", leptr);
+
+ /* Clear the multicast filter */
+ ib->filter [0] = 0;
+ ib->filter [1] = 0;
+ PRINT_RINGS();
+}
+
+/* LANCE must be STOPped before we do this, too... */
+static int init_restart_lance (struct lance_private *lp)
+{
+ int i;
+ DECLARE_LL;
+
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_INIT);
+
+ /* Need a hook here for sunlance ledma stuff */
+
+ /* Wait for the lance to complete initialization */
+ for (i = 0; (i < 100) && !(READRDP() & (LE_C0_ERR | LE_C0_IDON)); i++)
+ barrier();
+ if ((i == 100) || (READRDP() & LE_C0_ERR)) {
+ printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP());
+ return -1;
+ }
+
+ /* Clear IDON by writing a "1", enable interrupts and start lance */
+ WRITERDP(LE_C0_IDON);
+ WRITERDP(LE_C0_INEA | LE_C0_STRT);
+
+ return 0;
+}
+
+static int lance_reset (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ int status;
+ DECLARE_LL;
+
+ /* Stop the lance */
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+
+ load_csrs (lp);
+ lance_init_ring (dev);
+ dev->trans_start = jiffies;
+ dev->interrupt = 0;
+ dev->start = 1;
+ dev->tbusy = 0;
+ status = init_restart_lance (lp);
+#ifdef DEBUG_DRIVER
+ printk ("Lance restart=%d\n", status);
+#endif
+ return status;
+}
+
+static int lance_rx (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ volatile struct lance_rx_desc *rd;
+ unsigned char bits;
+ int len = 0; /* XXX shut up gcc warnings */
+ struct sk_buff *skb = 0; /* XXX shut up gcc warnings */
+#ifdef TEST_HITS
+ int i;
+#endif
+ DECLARE_LL;
+
+#ifdef TEST_HITS
+ printk ("[");
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (i == lp->rx_new)
+ printk ("%s",
+ ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "_" : "X");
+ else
+ printk ("%s",
+ ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "." : "1");
+ }
+ printk ("]");
+#endif
+
+ WRITERDP(LE_C0_RINT | LE_C0_INEA); /* ack Rx int, reenable ints */
+ for (rd = &ib->brx_ring [lp->rx_new]; /* For each Rx ring we own... */
+ !((bits = rd->rmd1_bits) & LE_R1_OWN);
+ rd = &ib->brx_ring [lp->rx_new]) {
+
+ /* We got an incomplete frame? */
+ if ((bits & LE_R1_POK) != LE_R1_POK) {
+ lp->stats.rx_over_errors++;
+ lp->stats.rx_errors++;
+ continue;
+ } else if (bits & LE_R1_ERR) {
+ /* Count only the end frame as a rx error,
+ * not the beginning
+ */
+ if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ } else {
+ len = (rd->mblength & 0xfff) - 4;
+ skb = dev_alloc_skb (len+2);
+
+ if (skb == 0) {
+ printk ("%s: Memory squeeze, deferring packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ rd->mblength = 0;
+ rd->rmd1_bits = LE_R1_OWN;
+ lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+ return 0;
+ }
+
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align */
+ skb_put (skb, len); /* make room */
+ eth_copy_and_sum(skb,
+ (unsigned char *)&(ib->rx_buf [lp->rx_new][0]),
+ len, 0);
+ skb->protocol = eth_type_trans (skb, dev);
+ netif_rx (skb);
+ lp->stats.rx_packets++;
+ }
+
+ /* Return the packet to the pool */
+ rd->mblength = 0;
+ rd->rmd1_bits = LE_R1_OWN;
+ lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
+ }
+ return 0;
+}
+
+static int lance_tx (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ volatile struct lance_tx_desc *td;
+ int i, j;
+ int status;
+ DECLARE_LL;
+
+ /* csr0 is 2f3 */
+ WRITERDP(LE_C0_TINT | LE_C0_INEA);
+ /* csr0 is 73 */
+
+ j = lp->tx_old;
+ for (i = j; i != lp->tx_new; i = j) {
+ td = &ib->btx_ring [i];
+
+ /* If we hit a packet not owned by us, stop */
+ if (td->tmd1_bits & LE_T1_OWN)
+ break;
+
+ if (td->tmd1_bits & LE_T1_ERR) {
+ status = td->misc;
+
+ lp->stats.tx_errors++;
+ if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+
+ if (status & LE_T3_CLOS) {
+ lp->stats.tx_carrier_errors++;
+ if (lp->auto_select) {
+ lp->tpe = 1 - lp->tpe;
+ printk("%s: Carrier Lost, trying %s\n",
+ dev->name, lp->tpe?"TPE":"AUI");
+ /* Stop the lance */
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+ lance_init_ring (dev);
+ load_csrs (lp);
+ init_restart_lance (lp);
+ return 0;
+ }
+ }
+
+ /* buffer errors and underflows turn off the transmitter */
+ /* Restart the adapter */
+ if (status & (LE_T3_BUF|LE_T3_UFL)) {
+ lp->stats.tx_fifo_errors++;
+
+ printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
+ dev->name);
+ /* Stop the lance */
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+ lance_init_ring (dev);
+ load_csrs (lp);
+ init_restart_lance (lp);
+ return 0;
+ }
+ } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
+ /*
+ * So we don't count the packet more than once.
+ */
+ td->tmd1_bits &= ~(LE_T1_POK);
+
+ /* One collision before packet was sent. */
+ if (td->tmd1_bits & LE_T1_EONE)
+ lp->stats.collisions++;
+
+ /* More than one collision, be optimistic. */
+ if (td->tmd1_bits & LE_T1_EMORE)
+ lp->stats.collisions += 2;
+
+ lp->stats.tx_packets++;
+ }
+
+ j = (j + 1) & lp->tx_ring_mod_mask;
+ }
+ lp->tx_old = j;
+ WRITERDP(LE_C0_TINT | LE_C0_INEA);
+ return 0;
+}
+
+static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *)dev_id;
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ int csr0;
+ DECLARE_LL;
+
+ WRITERAP(LE_CSR0); /* LANCE Controller Status */
+ csr0 = READRDP();
+
+ PRINT_RINGS();
+
+ if (!(csr0 & LE_C0_INTR)) /* Check if any interrupt has */
+ return; /* been generated by the Lance. */
+
+ if (dev->interrupt)
+ printk ("%s: again", dev->name);
+
+ dev->interrupt = 1;
+
+ /* Acknowledge all the interrupt sources ASAP */
+ WRITERDP(csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
+
+ if ((csr0 & LE_C0_ERR)) {
+ /* Clear the error condition */
+ WRITERDP(LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
+ }
+
+ if (csr0 & LE_C0_RINT)
+ lance_rx (dev);
+
+ if (csr0 & LE_C0_TINT)
+ lance_tx (dev);
+
+ /* Log misc errors. */
+ if (csr0 & LE_C0_BABL)
+ lp->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & LE_C0_MISS)
+ lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & LE_C0_MERR) {
+ printk("%s: Bus master arbitration failure, status %4.4x.\n",
+ dev->name, csr0);
+ /* Restart the chip. */
+ WRITERDP(LE_C0_STRT);
+ }
+
+ if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) {
+ dev->tbusy = 0;
+ mark_bh (NET_BH);
+ }
+
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
+
+ dev->interrupt = 0;
+}
+
+int lance_open (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ DECLARE_LL;
+
+ /* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
+ if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
+ return -EAGAIN;
+
+ return lance_reset(dev);
+}
+
+int lance_close (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ DECLARE_LL;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ /* Stop the LANCE */
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+
+ free_irq(lp->irq, dev);
+
+ return 0;
+}
+
+int lance_start_xmit (struct sk_buff *skb, struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ int entry, skblen, len;
+ int status = 0;
+ static int outs;
+ DECLARE_LL;
+
+ lance_reset(dev);
+
+ /* Transmitter timeout, serious problems */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+
+ if (tickssofar < 100) {
+ status = -1;
+ } else {
+ printk ("%s: transmit timed out, status %04x, resetting\n",
+ dev->name, READRDP());
+ lance_reset (dev);
+ }
+ return status;
+ }
+
+ /* Block a timer-based transmit from overlapping. */
+ if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
+ printk ("Transmitter access conflict.\n");
+ return -1;
+ }
+
+ skblen = skb->len;
+
+ if (!TX_BUFFS_AVAIL)
+ return -1;
+
+#ifdef DEBUG_DRIVER
+ /* dump the packet */
+ {
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ if ((i % 16) == 0)
+ printk ("\n");
+ printk ("%2.2x ", skb->data [i]);
+ }
+ }
+#endif
+ len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+ entry = lp->tx_new & lp->tx_ring_mod_mask;
+ ib->btx_ring [entry].length = (-len) | 0xf000;
+ ib->btx_ring [entry].misc = 0;
+
+ memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
+
+ /* Now, give the packet to the lance */
+ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
+ lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
+
+ outs++;
+ /* Kick the lance: transmit now */
+ WRITERDP(LE_C0_INEA | LE_C0_TDMD);
+ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+
+ if (TX_BUFFS_AVAIL)
+ dev->tbusy = 0;
+
+ return status;
+}
+
+struct net_device_stats *lance_get_stats (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+
+ return &lp->stats;
+}
+
+/* taken from the depca driver via a2065.c */
+static void lance_load_multicast (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ volatile u16 *mcast_table = (u16 *)&ib->filter;
+ struct dev_mc_list *dmi=dev->mc_list;
+ char *addrs;
+ int i, j, bit, byte;
+ u32 crc, poly = CRC_POLYNOMIAL_LE;
+
+ /* set all multicast bits */
+ if (dev->flags & IFF_ALLMULTI){
+ ib->filter [0] = 0xffffffff;
+ ib->filter [1] = 0xffffffff;
+ return;
+ }
+ /* clear the multicast filter */
+ ib->filter [0] = 0;
+ ib->filter [1] = 0;
+
+ /* Add addresses */
+ for (i = 0; i < dev->mc_count; i++){
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+
+ /* multicast address? */
+ if (!(*addrs & 1))
+ continue;
+
+ crc = 0xffffffff;
+ for (byte = 0; byte < 6; byte++)
+ for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
+ {
+ int test;
+
+ test = ((bit ^ crc) & 0x01);
+ crc >>= 1;
+
+ if (test)
+ {
+ crc = crc ^ poly;
+ }
+ }
+
+ crc = crc >> 26;
+ mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+ }
+ return;
+}
+
+
+void lance_set_multicast (struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib = lp->init_block;
+ DECLARE_LL;
+
+ while (dev->tbusy)
+ schedule();
+ set_bit (0, (void *) &dev->tbusy);
+
+ while (lp->tx_old != lp->tx_new)
+ schedule();
+
+ WRITERAP(LE_CSR0);
+ WRITERDP(LE_C0_STOP);
+ lance_init_ring (dev);
+
+ if (dev->flags & IFF_PROMISC) {
+ ib->mode |= LE_MO_PROM;
+ } else {
+ ib->mode &= ~LE_MO_PROM;
+ lance_load_multicast (dev);
+ }
+ load_csrs (lp);
+ init_restart_lance (lp);
+ dev->tbusy = 0;
+}
+
--- /dev/null
+/*
+ * 7990.h -- LANCE ethernet IC generic routines.
+ * This is an attempt to separate out the bits of various ethernet
+ * drivers that are common because they all use the AMD 7990 LANCE
+ * (Local Area Network Controller for Ethernet) chip.
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ *
+ * Most of this stuff was obtained by looking at other LANCE drivers,
+ * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
+ */
+
+#ifndef _7990_H
+#define _7990_H
+
+/* The lance only has two register locations. We communicate mostly via memory. */
+struct lance_regs
+{
+ unsigned short rdp; /* Register Data Port */
+ unsigned short rap; /* Register Address Port */
+};
+
+/* Transmit/receive ring definitions.
+ * We allow the specific drivers to override these defaults if they want to.
+ * NB: according to lance.c, increasing the number of buffers is a waste
+ * of space and reduces the chance that an upper layer will be able to
+ * reorder queued Tx packets based on priority. [Clearly there is a minimum
+ * limit too: too small and we drop rx packets and can't tx at full speed.]
+ * 4+4 seems to be the usual setting; the atarilance driver uses 3 and 5.
+ */
+
+/* Blast! This won't work. The problem is that we can't specify a default
+ * setting because that would cause the lance_init_block struct to be
+ * too long (and overflow the RAM on shared-memory cards like the HP LANCE.
+ */
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+#endif
+
+#define TX_RING_SIZE (1<<LANCE_LOG_TX_BUFFERS)
+#define RX_RING_SIZE (1<<LANCE_LOG_RX_BUFFERS)
+#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
+#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
+#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
+#define PKT_BUFF_SIZE (1544)
+#define RX_BUFF_SIZE PKT_BUFF_SIZE
+#define TX_BUFF_SIZE PKT_BUFF_SIZE
+
+/* Each receive buffer is described by a receive message descriptor (RMD) */
+struct lance_rx_desc {
+ volatile unsigned short rmd0; /* low address of packet */
+ volatile unsigned char rmd1_bits; /* descriptor bits */
+ volatile unsigned char rmd1_hadr; /* high address of packet */
+ volatile short length; /* This length is 2s complement (negative)!
+ * Buffer length
+ */
+ volatile unsigned short mblength; /* Actual number of bytes received */
+};
+
+/* Ditto for TMD: */
+struct lance_tx_desc {
+ volatile unsigned short tmd0; /* low address of packet */
+ volatile unsigned char tmd1_bits; /* descriptor bits */
+ volatile unsigned char tmd1_hadr; /* high address of packet */
+ volatile short length; /* Length is 2s complement (negative)! */
+ volatile unsigned short misc;
+};
+
+/* There are three memory structures accessed by the LANCE:
+ * the initialization block, the receive and transmit descriptor rings,
+ * and the data buffers themselves. In fact we might as well put the
+ * init block,the Tx and Rx rings and the buffers together in memory:
+ */
+struct lance_init_block {
+ volatile unsigned short mode; /* Pre-set mode (reg. 15) */
+ volatile unsigned char phys_addr[6]; /* Physical ethernet address */
+ volatile unsigned filter[2]; /* Multicast filter (64 bits) */
+
+ /* Receive and transmit ring base, along with extra bits. */
+ volatile unsigned short rx_ptr; /* receive descriptor addr */
+ volatile unsigned short rx_len; /* receive len and high addr */
+ volatile unsigned short tx_ptr; /* transmit descriptor addr */
+ volatile unsigned short tx_len; /* transmit len and high addr */
+
+ /* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
+ * This will be true if this whole struct is 8-byte aligned.
+ */
+ volatile struct lance_tx_desc btx_ring[TX_RING_SIZE];
+ volatile struct lance_rx_desc brx_ring[RX_RING_SIZE];
+
+ volatile char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
+ volatile char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
+ /* we use this just to make the struct big enough that we can move its startaddr
+ * in order to force alignment to an eight byte boundary.
+ */
+};
+
+/* This is where we keep all the stuff the driver needs to know about.
+ * I'm definitely unhappy about the mechanism for allowing specific
+ * drivers to add things...
+ */
+struct lance_private
+{
+ char *name;
+ volatile struct lance_regs *ll;
+ volatile struct lance_init_block *init_block; /* CPU address of RAM */
+ volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
+
+ int rx_new, tx_new;
+ int rx_old, tx_old;
+
+ int lance_log_rx_bufs, lance_log_tx_bufs;
+ int rx_ring_mod_mask, tx_ring_mod_mask;
+
+ struct net_device_stats stats;
+ int tpe; /* TPE is selected */
+ int auto_select; /* cable-selection is by carrier */
+ unsigned short busmaster_regval;
+
+ unsigned int irq; /* IRQ to register */
+
+ /* This is because the HP LANCE is disgusting and you have to check
+ * a DIO-specific register every time you read/write the LANCE regs :-<
+ * [could we get away with making these some sort of macro?]
+ */
+ void (*writerap)(void *, unsigned short);
+ void (*writerdp)(void *, unsigned short);
+ unsigned short (*readrdp)(struct lance_private *);
+};
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+/*
+ * Am7990 Control and Status Registers
+ */
+#define LE_CSR0 0x0000 /* LANCE Controller Status */
+#define LE_CSR1 0x0001 /* IADR[15:0] (bit0==0 ie word aligned) */
+#define LE_CSR2 0x0002 /* IADR[23:16] (high bits reserved) */
+#define LE_CSR3 0x0003 /* Misc */
+
+/*
+ * Bit definitions for CSR0 (LANCE Controller Status)
+ */
+#define LE_C0_ERR 0x8000 /* Error = BABL | CERR | MISS | MERR */
+#define LE_C0_BABL 0x4000 /* Babble: Transmitted too many bits */
+#define LE_C0_CERR 0x2000 /* No Heartbeat (10BASE-T) */
+#define LE_C0_MISS 0x1000 /* Missed Frame (no rx buffer to put it in) */
+#define LE_C0_MERR 0x0800 /* Memory Error */
+#define LE_C0_RINT 0x0400 /* Receive Interrupt */
+#define LE_C0_TINT 0x0200 /* Transmit Interrupt */
+#define LE_C0_IDON 0x0100 /* Initialization Done */
+#define LE_C0_INTR 0x0080 /* Interrupt Flag
+ = BABL | MISS | MERR | RINT | TINT | IDON */
+#define LE_C0_INEA 0x0040 /* Interrupt Enable */
+#define LE_C0_RXON 0x0020 /* Receive On */
+#define LE_C0_TXON 0x0010 /* Transmit On */
+#define LE_C0_TDMD 0x0008 /* Transmit Demand */
+#define LE_C0_STOP 0x0004 /* Stop */
+#define LE_C0_STRT 0x0002 /* Start */
+#define LE_C0_INIT 0x0001 /* Initialize */
+
+
+/*
+ * Bit definitions for CSR3
+ */
+#define LE_C3_BSWP 0x0004 /* Byte Swap
+ (on for big endian byte order) */
+#define LE_C3_ACON 0x0002 /* ALE Control
+ (on for active low ALE) */
+#define LE_C3_BCON 0x0001 /* Byte Control */
+
+
+/*
+ * Mode Flags
+ */
+#define LE_MO_PROM 0x8000 /* Promiscuous Mode */
+/* these next ones 0x4000 -- 0x0080 are not available on the LANCE 7990,
+ * but they are in NetBSD's am7990.h, presumably for backwards-compatible chips
+ */
+#define LE_MO_DRCVBC 0x4000 /* disable receive broadcast */
+#define LE_MO_DRCVPA 0x2000 /* disable physical address detection */
+#define LE_MO_DLNKTST 0x1000 /* disable link status */
+#define LE_MO_DAPC 0x0800 /* disable automatic polarity correction */
+#define LE_MO_MENDECL 0x0400 /* MENDEC loopback mode */
+#define LE_MO_LRTTSEL 0x0200 /* lower RX threshold / TX mode selection */
+#define LE_MO_PSEL1 0x0100 /* port selection bit1 */
+#define LE_MO_PSEL0 0x0080 /* port selection bit0 */
+/* and this one is from the C-LANCE data sheet... */
+#define LE_MO_EMBA 0x0080 /* Enable Modified Backoff Algorithm
+ (C-LANCE, not original LANCE) */
+#define LE_MO_INTL 0x0040 /* Internal Loopback */
+#define LE_MO_DRTY 0x0020 /* Disable Retry */
+#define LE_MO_FCOLL 0x0010 /* Force Collision */
+#define LE_MO_DXMTFCS 0x0008 /* Disable Transmit CRC */
+#define LE_MO_LOOP 0x0004 /* Loopback Enable */
+#define LE_MO_DTX 0x0002 /* Disable Transmitter */
+#define LE_MO_DRX 0x0001 /* Disable Receiver */
+
+
+/*
+ * Receive Flags
+ */
+#define LE_R1_OWN 0x80 /* LANCE owns the descriptor */
+#define LE_R1_ERR 0x40 /* Error */
+#define LE_R1_FRA 0x20 /* Framing Error */
+#define LE_R1_OFL 0x10 /* Overflow Error */
+#define LE_R1_CRC 0x08 /* CRC Error */
+#define LE_R1_BUF 0x04 /* Buffer Error */
+#define LE_R1_SOP 0x02 /* Start of Packet */
+#define LE_R1_EOP 0x01 /* End of Packet */
+#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
+
+
+/*
+ * Transmit Flags
+ */
+#define LE_T1_OWN 0x80 /* LANCE owns the descriptor */
+#define LE_T1_ERR 0x40 /* Error */
+#define LE_T1_RES 0x20 /* Reserved, LANCE writes this with a zero */
+#define LE_T1_EMORE 0x10 /* More than one retry needed */
+#define LE_T1_EONE 0x08 /* One retry needed */
+#define LE_T1_EDEF 0x04 /* Deferred */
+#define LE_T1_SOP 0x02 /* Start of Packet */
+#define LE_T1_EOP 0x01 /* End of Packet */
+#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
+
+/*
+ * Error Flags
+ */
+#define LE_T3_BUF 0x8000 /* Buffer Error */
+#define LE_T3_UFL 0x4000 /* Underflow Error */
+#define LE_T3_LCOL 0x1000 /* Late Collision */
+#define LE_T3_CLOS 0x0800 /* Loss of Carrier */
+#define LE_T3_RTY 0x0400 /* Retry Error */
+#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry */
+
+/* Miscellaneous useful macros */
+
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+ lp->tx_old+lp->tx_ring_mod_mask-lp->tx_new:\
+ lp->tx_old - lp->tx_new-1)
+
+/* The LANCE only uses 24 bit addresses. This does the obvious thing. */
+#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
+
+/* Now the prototypes we export */
+extern int lance_open(struct device *dev);
+extern int lance_close (struct device *dev);
+extern int lance_start_xmit (struct sk_buff *skb, struct device *dev);
+extern struct net_device_stats *lance_get_stats (struct device *dev);
+extern void lance_set_multicast (struct device *dev);
+
+#endif /* ndef _7990_H */
}
dev->interrupt = 1;
- sti();
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
#
bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
+ if [ "$CONFIG_ARM" = "y" ]; then
+ if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
+ tristate 'AM79C961A support' CONFIG_ARM_AM79C961A
+ else
+ source drivers/acorn/net/Config.in
+ fi
+ fi
if [ "$CONFIG_PMAC" = "y" ]; then
bool 'MACE (Power Mac Ethernet) support' CONFIG_MACE
fi
M_OBJS :=
MOD_LIST_NAME := NET_MODULES
-# Need these to keep track of whether the 8390, PPP and SLHC modules should
-# really go in the kernel or a module.
+# Need these to keep track of whether the 7990 (LANCE), 8390, PPP and SLHC
+# modules should really go in the kernel or a module.
CONFIG_8390_BUILTIN :=
CONFIG_8390_MODULE :=
CONFIG_SLHC_BUILTIN :=
CONFIG_SLHC_MODULE :=
CONFIG_PPPDEF_BUILTIN :=
CONFIG_PPPDEF_MODULE :=
+CONFIG_7990_BUILTIN :=
+CONFIG_7990_MODULE :=
ifeq ($(CONFIG_ISDN),y)
ifeq ($(CONFIG_ISDN_PPP),y)
endif
endif
+ifeq ($(CONFIG_ETHERH),y)
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_ETHERH),m)
+ CONFIG_8390_MODULE = y
+ endif
+endif
ifeq ($(CONFIG_WD80x3),y)
L_OBJS += wd.o
endif
endif
+ifeq ($(CONFIG_HPLANCE),y)
+L_OBJS += hplance.o
+CONFIG_7990_BUILTIN = y
+else
+ ifeq ($(CONFIG_HPLANCE),m)
+ CONFIG_7990_MODULE = y
+ M_OBJS += hplance.o
+ endif
+endif
+# If we need generic LANCE support, either in the kernel or as a module,
+# build it in the appropriate way.
+ifdef CONFIG_7990_BUILTIN
+L_OBJS += 7990.o
+else
+ ifdef CONFIG_7990_MODULE
+ M_OBJS += 7990.o
+ endif
+endif
ifeq ($(CONFIG_EQUALIZER),y)
L_OBJS += eql.o
extern int a2065_probe(struct device *);
extern int ariadne_probe(struct device *);
extern int hydra_probe(struct device *);
+extern int bionet_probe(struct device *);
+extern int pamsnet_probe(struct device *);
extern int tlan_probe(struct device *);
extern int mace_probe(struct device *);
extern int cs89x0_probe(struct device *dev);
extern int ethertap_probe(struct device *dev);
+extern int acorn_ethif_probe(struct device *dev);
+extern int am79c961_probe(struct device *dev);
extern int epic100_probe(struct device *dev);
extern int rtl8139_probe(struct device *dev);
+extern int hplance_probe(struct device *dev);
/* Gigabit Ethernet adapters */
extern int yellowfin_probe(struct device *dev);
#ifdef CONFIG_HYDRA /* Hydra Systems Amiganet Ethernet board */
&& hydra_probe(dev)
#endif
+#ifdef CONFIG_ATARI_BIONET /* Atari Bionet Ethernet board */
+ && bionet_probe(dev)
+#endif
+#ifdef CONFIG_ATARI_PAMSNET /* Atari PAMsNet Ethernet board */
+ && pamsnet_probe(dev)
+#endif
+#ifdef CONFIG_HPLANCE /* HP300 internal Ethernet */
+ && hplance_probe(dev)
+#endif
#ifdef CONFIG_SUNLANCE
&& sparc_lance_probe(dev)
#endif
#endif
#ifdef CONFIG_MIPS_JAZZ_SONIC
&& sonic_probe(dev)
-#endif
+#endif
#ifdef CONFIG_ARCH_ACORN
&& acorn_ethif_probe(dev)
#endif
# define ETH0_IRQ 0
#endif
-#ifndef __sparc__
+#if !defined(__sparc__) && !defined(CONFIG_ARCH_ACORN)
#define ETH_NOPROBE_ADDR 0xffe0
#else
#define ETH_NOPROBE_ADDR 0
* and Torsten Narjes <narjes@ifk-mp.uni-kiel.de>
*
* Little adaptions for integration into pl7 by Roman Hodek
+ *
+ * Some changes in bionet_poll_rx by Karl-Heinz Lohner
*
What is it ?
------------
dma_wd.dma_mode_status = 0x9a;
dma_wd.dma_mode_status = 0x19a;
dma_wd.dma_mode_status = 0x9a;
- dma_wd.fdc_acces_seccount = 0x05; /* sector count */
+ dma_wd.fdc_acces_seccount = 0x04; /* sector count (was 5) */
dma_wd.dma_lo = (unsigned char)paddr;
paddr >>= 8;
dma_wd.dma_md = (unsigned char)paddr;
paddr >>= 8;
dma_wd.dma_hi = (unsigned char)paddr;
- dma_wd.fdc_acces_seccount = 0xaa; /* sector count */
+ dma_wd.fdc_acces_seccount = 0x4; /* sector count */
restore_flags(flags);
c = sendcmd(0,0x100,NODE_ADR | C_WRITE); /* CMD: WRITE */
buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
}
+ if (bionet_debug >1) {
+ u_char *data = nic_packet->buffer, *p;
+ int i;
+
+ printk( "%s: TX pkt type 0x%4x from ", dev->name,
+ ((u_short *)data)[6]);
+
+ for( p = &data[6], i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" );
+ printk(" to ");
+
+ for( p = data, i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+
+ printk( "%s: ", dev->name );
+ printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+ " %02x%02x%02x%02x len %d\n",
+ data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+ data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+ data[28], data[29], data[30], data[31], data[32], data[33],
+ length );
+ }
dma_cache_maintenance(buf, length, 1);
stat = hardware_send_packet(buf, length);
while(boguscount--) {
status = get_frame((unsigned long)phys_nic_packet, 0);
- if( status != 1 ) break;
+ if( status == 0 ) break;
/* Good packet... */
pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo;
lp->poll_time = bionet_min_poll_time; /* fast poll */
- if( pkt_len >= 60 && pkt_len <= 1514 ) {
-
+ if( pkt_len >= 60 && pkt_len <= 1520 ) {
+ /* ^^^^ war 1514 KHL */
/* Malloc up new buffer.
*/
- struct sk_buff *skb = alloc_skb(pkt_len, GFP_ATOMIC);
+ struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 );
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n",
dev->name);
lp->stats.rx_dropped++;
break;
}
- skb->len = pkt_len;
+
skb->dev = dev;
+ skb_reserve( skb, 2 ); /* 16 Byte align */
+ skb_put( skb, pkt_len ); /* make room */
/* 'skb->data' points to the start of sk_buff data area.
*/
memcpy(skb->data, nic_packet->buffer, pkt_len);
+ skb->protocol = eth_type_trans( skb, dev );
netif_rx(skb);
lp->stats.rx_packets++;
lp->stats.rx_bytes+=pkt_len;
- }
- }
/* If any worth-while packets have been received, dev_rint()
has done a mark_bh(INET_BH) for us and will work on them
when we get to the bottom-half routine.
*/
+ if (bionet_debug >1) {
+ u_char *data = nic_packet->buffer, *p;
+ int i;
+
+ printk( "%s: RX pkt type 0x%4x from ", dev->name,
+ ((u_short *)data)[6]);
+
+
+ for( p = &data[6], i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" );
+ printk(" to ");
+ for( p = data, i = 0; i < 6; i++ )
+ printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+
+ printk( "%s: ", dev->name );
+ printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+ " %02x%02x%02x%02x len %d\n",
+ data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+ data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+ data[28], data[29], data[30], data[31], data[32], data[33],
+ pkt_len );
+ }
+ }
+ else {
+ printk(" Packet has wrong length: %04d bytes\n", pkt_len);
+ lp->stats.rx_errors++;
+ }
+ }
stdma_release();
ENABLE_IRQ();
return;
/*
- * $Id: dmascc.c,v 1.2.1.3 1997/12/19 13:40:15 oe1kib Exp $
+ * $Id: dmascc.c,v 1.2.1.4 1998/06/10 02:24:11 kudielka Exp $
*
* Driver for high-speed SCC boards (those with DMA support)
* Copyright (C) 1997 Klaus Kudielka
--- /dev/null
+/* hplance.c : the Linux/hp300/lance ethernet driver
+ *
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ * Uses the generic 7990.c LANCE code.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* Used for the temporal inet entries and routing */
+#include <linux/socket.h>
+#include <linux/route.h>
+
+#include <linux/dio.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "hplance.h"
+
+/* We have 16834 bytes of RAM for the init block and buffers. This places
+ * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
+ * buffers and 2 Tx buffers.
+ */
+#define LANCE_LOG_TX_BUFFERS 1
+#define LANCE_LOG_RX_BUFFERS 3
+
+#include "7990.h" /* use generic LANCE code */
+
+/* Our private data structure */
+struct hplance_private {
+ struct lance_private lance;
+ unsigned int scode;
+ void *base;
+};
+
+/* function prototypes... This is easy because all the grot is in the
+ * generic LANCE support. All we have to support is probing for boards,
+ * plus board-specific init, open and close actions.
+ * Oh, and we need to tell the generic code how to read and write LANCE registers...
+ */
+int hplance_probe(struct device *dev);
+static int hplance_init(struct device *dev, int scode);
+static int hplance_open(struct device *dev);
+static int hplance_close(struct device *dev);
+static void hplance_writerap(struct hplance_private *lp, unsigned short value);
+static void hplance_writerdp(struct hplance_private *lp, unsigned short value);
+static unsigned short hplance_readrdp(struct hplance_private *lp);
+
+#ifdef MODULE
+static struct hplance_private *root_hplance_dev = NULL;
+#endif
+
+/* Find all the HP Lance boards and initialise them... */
+__initfunc(int hplance_probe(struct device *dev))
+{
+ int cards = 0, called = 0;
+
+ if (!MACH_IS_HP300 || called)
+ return(ENODEV);
+ called++;
+
+ /* Isn't DIO nice? */
+ for(;;)
+ {
+ int v, scode = dio_find(DIO_ID_LAN);
+
+ if (!scode)
+ break;
+
+ if(cards)
+ dev = NULL; /* don't trash previous device, make a new one */
+ cards++;
+
+ v = hplance_init(dev, scode);
+ if (v) /* error, abort immediately */
+ return v;
+ }
+ /* OK, return success, or ENODEV if we didn't find any cards */
+ if (!cards)
+ return ENODEV;
+ return 0;
+}
+
+/* Initialise a single lance board at the given select code */
+__initfunc (static int hplance_init(struct device *dev, int scode))
+{
+ /* const char *name = dio_scodetoname(scode); */
+ static const char name[] = "HP LANCE";
+ void *va = dio_scodetoviraddr(scode);
+ struct hplance_private *lp;
+ int i;
+
+ if (dev == NULL)
+ dev = init_etherdev(0, sizeof(struct hplance_private));
+ else
+ {
+ dev->priv = kmalloc(sizeof(struct hplance_private), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct hplance_private));
+ }
+ printk("%s: HP LANCE; select code %d, addr", dev->name, scode);
+
+ /* reset the board */
+ writeb(0xff,va+DIO_IDOFF);
+ udelay(100); /* ariba! ariba! udelay! udelay! */
+
+ /* Fill the dev fields */
+ dev->base_addr = (unsigned long)va;
+ dev->open = &hplance_open;
+ dev->stop = &hplance_close;
+ dev->hard_start_xmit = &lance_start_xmit;
+ dev->get_stats = &lance_get_stats;
+ dev->set_multicast_list = &lance_set_multicast;
+ dev->dma = 0;
+
+ for (i=0; i<6; i++)
+ {
+ /* The NVRAM holds our ethernet address, one nibble per byte,
+ * at bytes NVRAMOFF+1,3,5,7,9...
+ */
+ dev->dev_addr[i] = ((readb(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
+ | (readb(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
+ printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
+ }
+
+ lp = (struct hplance_private *)dev->priv;
+ lp->lance.name = (char*)name; /* discards const, shut up gcc */
+ lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF);
+ lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
+ lp->lance.lance_init_block = 0; /* LANCE addr of same RAM */
+ lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */
+ lp->lance.irq = dio_scodetoipl(scode);
+ lp->lance.writerap = hplance_writerap;
+ lp->lance.writerdp = hplance_writerdp;
+ lp->lance.readrdp = hplance_readrdp;
+ lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
+ lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
+ lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
+ lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
+ lp->scode = scode;
+ lp->base = va;
+ ether_setup(dev);
+ printk(", irq %d\n", lp->lance.irq);
+
+#ifdef MODULE
+ dev->ifindex = dev_new_index();
+ lp->next_module = root_hplance_dev;
+ root_hplance_dev = lp;
+#endif /* MODULE */
+
+ dio_config_board(scode); /* tell bus scanning code this one's taken */
+ return 0;
+}
+
+/* This is disgusting. We have to check the DIO status register for ack every
+ * time we read or write the LANCE registers.
+ */
+static void hplance_writerap(struct hplance_private *lp, unsigned short value)
+{
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+ do {
+ lp->lance.ll->rap = value;
+ } while ((hpregs->status & LE_ACK) == 0);
+}
+
+static void hplance_writerdp(struct hplance_private *lp, unsigned short value)
+{
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+ do {
+ lp->lance.ll->rdp = value;
+ } while ((hpregs->status & LE_ACK) == 0);
+}
+
+static unsigned short hplance_readrdp(struct hplance_private *lp)
+{
+ unsigned short val;
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+ do {
+ val = lp->lance.ll->rdp;
+ } while ((hpregs->status & LE_ACK) == 0);
+ return val;
+}
+
+static int hplance_open(struct device *dev)
+{
+ int status;
+ struct hplance_private *lp = (struct hplance_private *)dev->priv;
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+
+ status = lance_open(dev); /* call generic lance open code */
+ if (status)
+ return status;
+ /* enable interrupts at board level. */
+ writeb(LE_IE, &(hpregs->status));
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int hplance_close(struct device *dev)
+{
+ struct hplance_private *lp = (struct hplance_private *)dev->priv;
+ struct hplance_reg *hpregs = (struct hplance_reg *)lp->base;
+ writeb(0,&(hpregs->status)); /* disable interrupts at boardlevel */
+ lance_close(dev);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ root_lance_dev = NULL;
+ return hplance_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+ /* Walk the chain of devices, unregistering them */
+ struct hplance_private *lp;
+ while (root_hplance_dev) {
+ lp = root_hplance_dev->next_module;
+ dio_unconfig_board(lp->scode);
+ unregister_netdev(root_lance_dev->dev);
+ kfree(root_lance_dev->dev);
+ root_lance_dev = lp;
+ }
+}
+
+#endif /* MODULE */
--- /dev/null
+/* Random defines and structures for the HP Lance driver.
+ * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+ * Based on the Sun Lance driver and the NetBSD HP Lance driver
+ */
+
+/* Registers */
+struct hplance_reg
+{
+ u_char pad0;
+ volatile u_char id; /* DIO register: ID byte */
+ u_char pad1;
+ volatile u_char status; /* DIO register: interrupt enable */
+};
+
+/* Control and status bits for the hplance->status register */
+#define LE_IE 0x80 /* interrupt enable */
+#define LE_IR 0x40 /* interrupt requested */
+#define LE_LOCK 0x08 /* lock status register */
+#define LE_ACK 0x04 /* ack of lock */
+#define LE_JAB 0x02 /* loss of tx clock (???) */
+/* We can also extract the IPL from the status register with the standard
+ * DIO_IPL(hplance) macro, or using dio_scodetoipl()
+ */
+
+/* These are the offsets for the DIO regs (hplance_reg), lance_ioreg,
+ * memory and NVRAM:
+ */
+#define HPLANCE_IDOFF 0 /* board baseaddr, struct hplance_reg */
+#define HPLANCE_REGOFF 0x4000 /* struct lance_regs */
+#define HPLANCE_MEMOFF 0x8000 /* struct lance_init_block */
+#define HPLANCE_NVRAMOFF 0xC008 /* etheraddress as one *nibble* per byte */
#include <linux/if_ether.h> /* For the statistics structure. */
#include <linux/if_arp.h> /* For ARPHRD_ETHER */
-#define LOOPBACK_MTU (PAGE_SIZE*7/8)
+#define LOOPBACK_MTU (PAGE_SIZE - 172)
/*
* The higher levels take care of making this non-reentrant (it's
*
* Machine hang caused by NULLing a live wait queue fix. <Alan.Cox@linux.org>
*
- * ==FILEVERSION 980607==
+ * ==FILEVERSION 980608==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the number above to the
CHECK_PPP_MAGIC(ppp); \
if (!ppp->inuse) { \
printk (ppp_warning, __LINE__); \
+ return; \
} \
} while (0)
{
struct ppp *ppp = tty2ppp (tty);
__u8 c;
- int error;
ssize_t len, ret;
#define GETC(c) \
*/
if (!ppp)
return -EIO;
-
- /* if (ppp->magic != PPP_MAGIC)
- return -EIO; */
-
CHECK_PPP (-ENXIO);
/*
* Before we attempt to write the frame to the user, ensure that the
* user has access to the pages for the total buffer length.
*/
- error = verify_area (VERIFY_WRITE, buf, nr);
- if (error != 0)
- return (error);
+ if (verify_area (VERIFY_WRITE, buf, nr))
+ return -EFAULT;
+
+/*
+ * Increment the module use count so that the module can't get unloaded
+ * while we're sleeping below. The problem is that ppp_tty_close() can
+ * get called (as a result of a hangup from the tty) while we're sleeping.
+ */
+ MOD_INC_USE_COUNT;
/*
* Acquire the read lock.
*/
for (;;) {
+ ret = 0;
ppp = tty2ppp (tty);
if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
|| tty != ppp->tty)
- return 0;
+ goto done;
if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
-#if 0
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: sleeping(ubuf)\n");
-#endif
current->timeout = 0;
current->state = TASK_INTERRUPTIBLE;
- schedule ();
+ schedule();
+ ret = -EINTR;
if (signal_pending(current))
- return -EINTR;
+ goto done;
continue;
}
*/
/* no data */
clear_bit (0, &ppp->ubuf->locked);
+ ret = -EAGAIN;
if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ goto done;
current->timeout = 0;
-#if 0
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: sleeping(read_wait)\n");
-#endif
interruptible_sleep_on (&ppp->read_wait);
+ ret = -EINTR;
if (signal_pending(current))
- return -EINTR;
+ goto done;
}
/*
"ppp: read of %lu bytes too small for %ld "
"frame\n", (unsigned long) nr, (long) len + 2);
ppp->stats.ppp_ierrors++;
- error = -EOVERFLOW;
+ ret = -EOVERFLOW;
goto out;
}
* Fake the insertion of the ADDRESS and CONTROL information because these
* were not saved in the buffer.
*/
- error = put_user((u_char) PPP_ALLSTATIONS, buf);
- if (error)
+ ret = -EFAULT;
+ if (put_user((u_char) PPP_ALLSTATIONS, buf)
+ || put_user((u_char) PPP_UI, buf+1))
goto out;
- ++buf;
- error = put_user((u_char) PPP_UI, buf);
- if (error)
- goto out;
- ++buf;
+ buf += 2;
/*
* Copy the received data from the buffer to the caller's area.
*/
- ret = len + 2; /* Account for ADDRESS and CONTROL bytes */
+ nr = len + 2; /* Account for ADDRESS and CONTROL bytes */
while (len-- > 0) {
GETC (c);
- error = put_user(c, buf);
- if (error)
+ if (put_user(c, buf))
goto out;
++buf;
}
-
- clear_bit (0, &ppp->ubuf->locked);
- return ret;
+ ret = nr;
out:
- ppp->ubuf->tail += len;
- ppp->ubuf->tail &= ppp->ubuf->size;
- clear_bit (0, &ppp->ubuf->locked);
- return error;
+ if (len > 0)
+ ppp->ubuf->tail = (ppp->ubuf->tail + len) & ppp->ubuf->size;
+ clear_bit(0, &ppp->ubuf->locked);
+
+done:
+ MOD_DEC_USE_COUNT;
+ return ret;
#undef GETC
}
error = -EFAULT;
if (copy_from_user(new_data, data, count))
goto out_free;
+
+/*
+ * Increment the module use count so that the module can't get unloaded
+ * while we're sleeping below. The problem is that ppp_tty_close() can
+ * get called (as a result of a hangup from the tty) while we're sleeping.
+ */
+ MOD_INC_USE_COUNT;
+
/*
* Lock this PPP unit so we will be the only writer,
* sleeping if necessary.
current->state = TASK_RUNNING;
remove_wait_queue(&ppp->write_wait, &wait);
if (error)
- goto out_free;
+ goto out_free_dec;
/*
* Change the LQR frame
}
error = count;
+out_free_dec:
+ MOD_DEC_USE_COUNT;
out_free:
kfree (new_data);
out:
dev->name);
CHECK_PPP (-ENXIO);
+ MOD_INC_USE_COUNT;
return 0;
}
{
struct ppp *ppp = dev2ppp (dev);
+ MOD_DEC_USE_COUNT;
if (ppp2tty (ppp) == NULL) {
return -ENXIO;
}
ppp_last->next = ppp;
ppp_last = ppp;
ppp->next = 0;
+ ppp->read_wait = NULL;
+ ppp->write_wait = NULL;
dev = ppp2dev(ppp);
dev->next = NULL;
/*
- * Wavelan ISA driver
+ * WaveLAN ISA driver
*
* Jean II - HPLB '96
*
* Reorganisation and extension of the driver.
- * Original copyrigth follow (see also end of this file).
+ * Original copyright follows (also see the end of this file).
* See wavelan.p.h for details.
*/
/************************* MISC SUBROUTINES **************************/
/*
* Subroutines which won't fit in one of the following category
- * (wavelan modem or i82586)
+ * (WaveLAN modem or i82586)
*/
/*------------------------------------------------------------------*/
#undef SC
return((char *) NULL);
-} /* wv_structuct_check */
+} /* wv_struct_check */
#endif /* STRUCT_CHECK */
/********************* HOST ADAPTER SUBROUTINES *********************/
/*
- * Usefull subroutines to manage the wavelan ISA interface
+ * Useful subroutines to manage the WaveLAN ISA interface
*
- * One major difference with the Pcmcia hardware (exept the port mapping)
+ * One major difference with the PCMCIA hardware (except the port mapping)
* is that we have to keep the state of the Host Control Register
* because of the interrupt enable & bus size flags.
*/
/*------------------------------------------------------------------*/
/*
- * Set the i/o transfer over the ISA bus to 8 bits mode
+ * Set the I/O transfer over the ISA bus to 8-bit mode
*/
static inline void
wv_16_off(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Set the i/o transfer over the ISA bus to 8 bits mode
+ * Set the I/O transfer over the ISA bus to 8-bit mode
*/
static inline void
wv_16_on(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Disable interrupts on the wavelan hardware
+ * Disable interrupts on the WaveLAN hardware.
*/
static inline void
wv_ints_off(device * dev)
/*------------------------------------------------------------------*/
/*
- * Enable interrupts on the wavelan hardware
+ * Enable interrupts on the WaveLAN hardware.
*/
static inline void
wv_ints_on(device * dev)
/******************* MODEM MANAGEMENT SUBROUTINES *******************/
/*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the WaveLAN
*/
/*------------------------------------------------------------------*/
/*------------------------------------------------------------------*/
/*
- * Write the Paramter Storage Area to the WaveLAN card's memory
+ * Write the Parameter Storage Area to the WaveLAN card's memory.
*/
static void
psa_write(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
* Calculate the PSA CRC (not tested yet)
- * As the Wavelan drivers don't use the CRC, I won't use it either...
- * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
+ * As the WaveLAN drivers don't use the CRC, I won't use it either.
+ * Thanks to Nico Valster <NVALSTER@wcnd.nl.lucent.com> for the code
* NOTE: By specifying a length including the CRC position the
- * returned value should be zero. (i.e. a correct checksum in the PSA)
+ * returned value should be zero. (i.e. a correct checksum in the PSA).
*/
static u_short
psa_crc(u_short * psa, /* The PSA */
/*------------------------------------------------------------------*/
/*
* Routine to write bytes to the Modem Management Controller.
- * We start by the end because it is the way it should be !
+ * We start at the end because it is the way it should be!
*/
static inline void
mmc_write(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Read 1 byte from the MMC.
- * Optimised version for 1 byte, avoid using memory...
+ * Read a byte from the MMC.
+ * Optimised version for 1 byte, avoid using memory.
*/
static inline u_char
mmc_in(u_long ioaddr,
* The implementation is complicated by a lack of address lines,
* which prevents decoding of the low-order bit.
* (code has just been moved in the above function)
- * We start by the end because it is the way it should be !
+ * We start at the end because it is the way it should be!
*/
static inline void
mmc_read(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Get the type of encryption available...
+ * Get the type of encryption available.
*/
static inline int
mmc_encr(u_long ioaddr) /* i/o port of the card */
/*------------------------------------------------------------------*/
/*
- * Wait for the frequency EEprom to complete a command...
- * I hope this one will be optimally inlined...
+ * Wait for the frequency EEPROM to complete a command.
+ * I hope this one will be optimally inlined.
*/
static inline void
fee_wait(u_long ioaddr, /* i/o port of the card */
/*------------------------------------------------------------------*/
/*
- * Read bytes from the Frequency EEprom (frequency select cards).
+ * Read bytes from the Frequency EEPROM (frequency select cards).
*/
static void
fee_read(u_long ioaddr, /* i/o port of the card */
/* Write the read command */
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
- /* Wait until EEprom is ready (should be quick !) */
+ /* Wait until EEPROM is ready (should be quick). */
fee_wait(ioaddr, 10, 100);
- /* Read the value */
+ /* Read the value. */
*--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
}
}
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */
/*------------------------------------------------------------------*/
/*
- * Write bytes from the Frequency EEprom (frequency select cards).
- * This is a bit complicated, because the frequency eeprom has to
+ * Write bytes from the Frequency EEPROM (frequency select cards).
+ * This is a bit complicated, because the frequency EEPROM has to
* be unprotected and the write enabled.
* Jean II
*/
u_short * b, /* data buffer */
int n) /* number of registers */
{
- b += n; /* Position at the end of the area */
+ b += n; /* Position at the end of the area. */
#ifdef EEPROM_IS_PROTECTED /* disabled */
#ifdef DOESNT_SEEM_TO_WORK /* disabled */
fee_wait(ioaddr, 10, 100);
- /* Read the protected register */
+ /* Read the protected register. */
printk("Protected 2 : %02X-%02X\n",
mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
#endif /* DOESNT_SEEM_TO_WORK */
- /* Enable protected register */
+ /* Enable protected register. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
fee_wait(ioaddr, 10, 100);
- /* Unprotect area */
+ /* Unprotect area. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
#ifdef DOESNT_SEEM_TO_WORK /* disabled */
fee_wait(ioaddr, 10, 100);
#endif /* EEPROM_IS_PROTECTED */
- /* Write enable */
+ /* Write enable. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
fee_wait(ioaddr, 10, 100);
- /* Write the EEprom address */
+ /* Write the EEPROM address. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
/* Loop on all buffer */
while(n-- > 0)
{
- /* Write the value */
+ /* Write the value. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
- /* Write the write command */
+ /* Write the write command. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
- /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */
+ /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
mdelay(10);
fee_wait(ioaddr, 10, 100);
}
- /* Write disable */
+ /* Write disable. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
fee_wait(ioaddr, 10, 100);
#ifdef EEPROM_IS_PROTECTED /* disabled */
- /* Reprotect EEprom */
+ /* Reprotect EEPROM. */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
/************************ I82586 SUBROUTINES *************************/
/*
- * Usefull subroutines to manage the Ethernet controler
+ * Useful subroutines to manage the Ethernet controller
*/
/*------------------------------------------------------------------*/
/*
* Read bytes from the on-board RAM.
- * Why inlining this function make it fail ???
+ * Why does inlining this function make it fail?
*/
static /*inline*/ void
obram_read(u_long ioaddr,
/*------------------------------------------------------------------*/
/*
- * Acknowledge the reading of the status issued by the i82586
+ * Acknowledge the reading of the status issued by the i82586.
*/
static void
wv_ack(device * dev)
/*------------------------------------------------------------------*/
/*
* Set channel attention bit and busy wait until command has
- * completed, then acknowledge the command completion.
+ * completed, then acknowledge completion of the command.
*/
static inline int
wv_synchronous_cmd(device * dev,
/*------------------------------------------------------------------*/
/*
* Configuration commands completion interrupt.
- * Check if done, and if ok...
+ * Check if done, and if OK.
*/
static inline int
wv_config_complete(device * dev,
mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
+ sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
- /* Read the status of the last command (set mc list) */
+ /* Read the status of the last command (set mc list). */
obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status));
/* If not completed -> exit */
printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n",
dev->name, str, status);
- /* Check config command */
+ /* Check config command. */
cfg_addr = ias_addr - sizeof(ac_cfg_t);
obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status));
if(status & AC_SFLD_OK != 0)
printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
*/
- /* Was it the last one ? */
+ /* Was it the last one? */
if(lp->tx_n_in_use <= 0)
lp->tx_first_in_use = I82586NULL;
else
/*------------------------------------------------------------------*/
/*
- * Reconfigure the i82586, or at least ask for it...
- * Because wv_82586_config use a transmission buffer, we must do it
+ * Reconfigure the i82586, or at least ask for it.
+ * Because wv_82586_config uses a transmission buffer, we must do it
* when we are sure that there is one left, so we do it now
* or in wavelan_packet_xmit() (I can't find any better place,
- * wavelan_interrupt is not an option...), so you may experience
- * some delay sometime...
+ * wavelan_interrupt is not an option), so you may experience
+ * delays sometimes.
*/
static inline void
wv_82586_reconfig(device * dev)
/********************* DEBUG & INFO SUBROUTINES *********************/
/*
- * This routines are used in the code to show debug informations.
- * Most of the time, it dump the content of hardware structures...
+ * This routine is used in the code to show information for debugging.
+ * Most of the time, it dumps the contents of hardware structures.
*/
#ifdef DEBUG_PSA_SHOW
static void
wv_psa_show(psa_t * p)
{
- printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
p->psa_io_base_addr_2,
/*------------------------------------------------------------------*/
/*
* Print the formatted status of the Modem Management Controller.
- * This function need to be completed...
+ * This function needs to be completed.
*/
static void
wv_mmc_show(device * dev)
mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m));
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
/* Don't forget to update statistics */
lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
#endif /* WIRELESS_EXT */
- printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
#ifdef DEBUG_SHOW_UNUSED
printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
m.mmr_unused0[0],
m.mmr_unused0[6],
m.mmr_unused0[7]);
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
+ printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
m.mmr_des_avail, m.mmr_des_status);
#ifdef DEBUG_SHOW_UNUSED
printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
#ifdef DEBUG_I82586_SHOW
/*------------------------------------------------------------------*/
/*
- * Print the last block of the i82586 memory
+ * Print the last block of the i82586 memory.
*/
static void
wv_scb_show(u_long ioaddr)
obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
- printk(KERN_DEBUG "##### wavelan system control block: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
printk(KERN_DEBUG "status: ");
printk("stat 0x%x[%s%s%s%s] ",
{
/* net_local *lp = (net_local *) dev->priv; */
- printk(KERN_DEBUG "##### wavelan i82586 receiver unit status: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
printk(KERN_DEBUG "ru:");
/*
* Not implemented yet...
/*------------------------------------------------------------------*/
/*
- * Display info about one control block of the i82586 memory
+ * Display info about one control block of the i82586 memory.
*/
static void
wv_cu_show_one(device * dev,
/*------------------------------------------------------------------*/
/*
- * Print status of the command unit of the i82586
+ * Print status of the command unit of the i82586.
*/
static void
wv_cu_show(device * dev)
unsigned int i;
u_short p;
- printk(KERN_DEBUG "##### wavelan i82586 command unit status: #####\n");
+ printk(KERN_DEBUG "##### WaveLAN i82586 command unit status: #####\n");
printk(KERN_DEBUG);
for(i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++)
/*------------------------------------------------------------------*/
/*
- * This is the information which is displayed by the driver at startup
- * There is a lot of flag to configure it at your will...
+ * This is the information which is displayed by the driver at startup.
+ * There are lots of flags for configuring it to your liking.
*/
static inline void
wv_init_info(device * dev)
printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
printk(", IRQ %d", dev->irq);
- /* Print current network id */
+ /* Print current network ID. */
if(psa.psa_nwid_select)
printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
else
{
unsigned short freq;
- /* Ask the EEprom to read the frequency from the first area */
+ /* Ask the EEPROM to read the frequency from the first area */
fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
&freq, 1);
/* Print frequency */
printk(", 2.00, %ld", (freq >> 6) + 2400L);
- /* Hack !!! */
+ /* Hack! */
if(freq & 0x20)
printk(".5");
}
printk("MCIA");
break;
default:
- printk("???");
+ printk("?");
}
printk(", ");
switch (psa.psa_subband)
printk("2430.5");
break;
default:
- printk("???");
+ printk("?");
}
}
/********************* IOCTL, STATS & RECONFIG *********************/
/*
- * We found here routines that are called by Linux on differents
+ * We found here routines that are called by Linux on different
* occasions after the configuration and not for transmitting data
* These may be called when the user use ifconfig, /proc/net/dev
* or wireless extensions
/*------------------------------------------------------------------*/
/*
- * Get the current ethernet statistics. This may be called with the
+ * Get the current Ethernet statistics. This may be called with the
* card open or closed.
* Used when the user read /proc/net/dev
*/
dev->name, dev->flags, dev->mc_count);
#endif
- /* If we ask for promiscuous mode,
- * or all multicast addresses (we don't have that !)
- * or too much multicast addresses for the hardware filter */
+ /* Are we asking for promiscuous mode,
+ * or all multicast addresses (we don't have that!)
+ * or too many multicast addresses for the hardware filter? */
if((dev->flags & IFF_PROMISC) ||
(dev->flags & IFF_ALLMULTI) ||
(dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES))
wv_82586_reconfig(dev);
- /* Tell the kernel that we are doing a really bad job... */
+ /* Tell the kernel that we are doing a really bad job. */
dev->flags |= IFF_PROMISC;
}
}
else
- /* If there is some multicast addresses to send */
+ /* Are there multicast addresses to send? */
if(dev->mc_list != (struct dev_mc_list *) NULL)
{
/*
/*------------------------------------------------------------------*/
/*
- * This function doesn't exist...
+ * This function doesn't exist.
*/
static int
wavelan_set_mac_address(device * dev,
{
struct sockaddr * mac = addr;
- /* Copy the address */
+ /* Copy the address. */
memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
- /* Reconfig the beast */
+ /* Reconfigure the beast. */
wv_82586_reconfig(dev);
return 0;
}
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
/*------------------------------------------------------------------*/
/*
#endif
/* Setting by frequency */
- /* Theoritically, you may set any frequency between
+ /* Theoretically, you may set any frequency between
* the two limits with a 0.5 MHz precision. In practice,
* I don't want you to have trouble with local
- * regulations... */
+ * regulations. */
if((frequency->e == 1) &&
(frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
{
}
/* Setting by channel (same as wfreqsel) */
- /* Warning : each channel is 22MHz wide, so some of the channels
- * will interfere... */
+ /* Warning: each channel is 22 MHz wide, so some of the channels
+ * will interfere. */
if((frequency->e == 0) &&
(frequency->m >= 0) && (frequency->m < BAND_NUM))
{
- /* frequency in 1/4 of MHz (as read in the offset register) */
+ /* frequency in units of 250 kHz (as read in the offset register) */
short bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, 0xD0, 0xF0, 0xF8, 0x150 };
- /* Get frequency offset */
+ /* Get frequency offset. */
freq = bands[frequency->m] >> 1;
}
- /* Verify if the frequency is allowed */
+ /* Verify that the frequency is allowed. */
if(freq != 0L)
{
u_short table[10]; /* Authorized frequency table */
- /* Read the frequency table */
+ /* Read the frequency table. */
fee_read(ioaddr, 0x71 /* frequency table */,
table, 10);
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "Frequency table :");
+ printk(KERN_DEBUG "Frequency table: ");
for(i = 0; i < 10; i++)
{
printk(" %04X",
printk("\n");
#endif
- /* Look in the table if the frequency is allowed */
+ /* Look in the table to see whether the frequency is allowed. */
if(!(table[9 - ((freq - 24) / 16)] &
(1 << ((freq - 24) % 16))))
return -EINVAL; /* not allowed */
else
return -EINVAL;
- /* If we get a usable frequency */
+ /* if we get a usable frequency */
if(freq != 0L)
{
unsigned short area[16];
unsigned short area_verify[16];
unsigned short dac_verify[2];
/* Corresponding gain (in the power adjust value table)
- * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8
+ * see AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
* & WCIN062D.DOC, page 6.2.9 */
unsigned short power_limit[] = { 40, 80, 120, 160, 0 };
int power_band = 0; /* Selected band */
(power_limit[++power_band] != 0))
;
- /* Read the first area */
+ /* Read the first area. */
fee_read(ioaddr, 0x00,
area, 16);
- /* Read the DAC */
+ /* Read the DAC. */
fee_read(ioaddr, 0x60,
dac, 2);
- /* Read the new power adjust value */
+ /* Read the new power adjust value. */
fee_read(ioaddr, 0x6B - (power_band >> 1),
&power_adjust, 1);
if(power_band & 0x1)
power_adjust &= 0xFF;
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+ printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
for(i = 0; i < 16; i++)
{
printk(" %04X",
}
printk("\n");
- printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+ printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
dac[0], dac[1]);
#endif
- /* Frequency offset (for info only...) */
+ /* Frequency offset (for info only) */
area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
/* Receiver Principle main divider coefficient */
area[13] = (freq >> 1) + 2400L;
area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
- /* Others part of the area are flags, bit streams or unused... */
+ /* Other parts of the area are flags, bit streams or unused. */
- /* Set the value in the DAC */
+ /* Set the value in the DAC. */
dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
- /* Write the first area */
+ /* Write the first area. */
fee_write(ioaddr, 0x00,
area, 16);
- /* Write the DAC */
+ /* Write the DAC. */
fee_write(ioaddr, 0x60,
dac, 2);
- /* We now should verify here that the EEprom writting was ok */
+ /* We now should verify here that the writing of the EEPROM was OK. */
- /* ReRead the first area */
+ /* Reread the first area. */
fee_read(ioaddr, 0x00,
area_verify, 16);
- /* ReRead the DAC */
+ /* Reread the DAC. */
fee_read(ioaddr, 0x60,
dac_verify, 2);
- /* Compare */
+ /* Compare. */
if(memcmp(area, area_verify, 16 * 2) ||
memcmp(dac, dac_verify, 2 * 2))
{
#ifdef DEBUG_IOCTL_ERROR
- printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
+ printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
#endif
return -EOPNOTSUPP;
}
/* We must download the frequency parameters to the
- * synthetisers (from the EEprom - area 1)
- * Note : as the EEprom is auto decremented, we set the end
+ * synthesizers (from the EEPROM - area 1)
+ * Note: as the EEPROM is automatically decremented, we set the end
* if the area... */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
fee_wait(ioaddr, 100, 100);
/* We must now download the power adjust value (gain) to
- * the synthetisers (from the EEprom - area 7 - DAC) */
+ * the synthesizers (from the EEPROM - area 7 - DAC) */
mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
fee_wait(ioaddr, 100, 100);
#ifdef DEBUG_IOCTL_INFO
- /* Verification of what we have done... */
+ /* Verification of what we have done */
- printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+ printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
for(i = 0; i < 16; i++)
{
printk(" %04X",
}
printk("\n");
- printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+ printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
dac_verify[0], dac_verify[1]);
#endif
fee_read(ioaddr, 0x71 /* frequency table */,
table, 10);
- /* Look all frequencies */
+ /* Check all frequencies */
i = 0;
for(freq = 0; freq < 150; freq++)
/* Look in the table if the frequency is allowed */
list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
list[i++].e = 1;
- /* Check number */
+ /* Check number. */
if(i >= max)
return(i);
}
#ifdef WIRELESS_SPY
/*------------------------------------------------------------------*/
/*
- * Gather wireless spy statistics : for each packet, compare the source
- * address with out list, and if match, get the stats...
- * Sorry, but this function really need wireless extensions...
+ * Gather wireless spy statistics: for each packet, compare the source
+ * address with our list, and if they match, get the statistics.
+ * Sorry, but this function really needs the wireless extensions.
*/
static inline void
wl_spy_gather(device * dev,
net_local * lp = (net_local *) dev->priv;
int i;
- /* Look all addresses */
+ /* Check all addresses. */
for(i = 0; i < lp->spy_number; i++)
/* If match */
if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
#ifdef HISTOGRAM
/*------------------------------------------------------------------*/
/*
- * This function calculate an histogram on the signal level.
+ * This function calculates a histogram of the signal level.
* As the noise is quite constant, it's like doing it on the SNR.
* We have defined a set of interval (lp->his_range), and each time
* the level goes in that interval, we increment the count (lp->his_sum).
- * With this histogram you may detect if one wavelan is really weak,
- * or you may also calculate the mean and standard deviation of the level...
+ * With this histogram you may detect if one WaveLAN is really weak,
+ * or you may also calculate the mean and standard deviation of the level.
*/
static inline void
wl_his_gather(device * dev,
u_char level = stats[0] & MMR_SIGNAL_LVL;
int i;
- /* Find the correct interval */
+ /* Find the correct interval. */
i = 0;
while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
;
- /* Increment interval counter */
+ /* Increment interval counter. */
(lp->his_sum[i])++;
}
#endif /* HISTOGRAM */
/*------------------------------------------------------------------*/
/*
- * Perform ioctl : config & info stuff
+ * Perform ioctl: configuration and information
* This is here that are treated the wireless extensions (iwconfig)
*/
static int
-wavelan_ioctl(struct device * dev, /* Device on wich the ioctl apply */
- struct ifreq * rq, /* Data passed */
- int cmd) /* Ioctl number */
+wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */
+ struct ifreq * rq, /* data passed */
+ int cmd) /* ioctl number */
{
u_long ioaddr = dev->base_addr;
net_local * lp = (net_local *)dev->priv; /* lp is not unused */
break;
case SIOCSIWNWID:
- /* Set NWID in wavelan */
+ /* Set NWID in WaveLAN. */
if(wrq->u.nwid.on)
{
/* Set NWID in psa */
}
else
{
- /* Disable nwid in the psa */
+ /* Disable NWID in the psa. */
psa.psa_nwid_select = 0x00;
psa_write(ioaddr, lp->hacr,
(char *)&psa.psa_nwid_select - (char *)&psa,
(unsigned char *)&psa.psa_nwid_select, 1);
- /* Disable nwid in the mmc (no filtering) */
+ /* Disable NWID in the mmc (no filtering). */
mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
}
break;
case SIOCGIWNWID:
- /* Read the NWID */
+ /* Read the NWID. */
psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3);
wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
break;
case SIOCSIWFREQ:
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
break;
case SIOCGIWFREQ:
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody ??? - especially old cards...) */
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
+ * Does it work for everybody, especially old cards? */
if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
unsigned short freq;
- /* Ask the EEprom to read the frequency from the first area */
+ /* Ask the EEPROM to read the frequency from the first area */
fee_read(ioaddr, 0x00 /* 1st area - frequency... */,
&freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
break;
case SIOCSIWSENS:
- /* Set the level threshold */
+ /* Set the level threshold. */
if(!suser())
return -EPERM;
psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
break;
case SIOCGIWSENS:
- /* Read the level threshold */
+ /* Read the level threshold. */
psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
break;
case SIOCSIWENCODE:
- /* Set encryption key */
+ /* Set encryption key. */
if(!mmc_encr(ioaddr))
{
ret = -EOPNOTSUPP;
}
if(wrq->u.encoding.method)
- { /* enable encryption */
+ { /* Enable encryption. */
int i;
long long key = wrq->u.encoding.code;
(unsigned char *) &psa.psa_encryption_key, 8);
}
else
- { /* disable encryption */
+ { /* Disable encryption. */
psa.psa_encryption_select = 0;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select - (char *) &psa,
break;
case SIOCGIWENCODE:
- /* Read the encryption key */
+ /* Read the encryption key. */
if(!mmc_encr(ioaddr))
{
ret = -EOPNOTSUPP;
break;
}
- /* only super-user can see encryption key */
+ /* Only super-user can see encryption key. */
if(!suser())
{
ret = -EPERM;
break;
case SIOCGIWRANGE:
- /* Basic checking... */
+ /* basic checking */
if(wrq->u.data.pointer != (caddr_t) 0)
{
struct iw_range range;
- /* Verify the user buffer */
+ /* Verify the user buffer. */
ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
sizeof(struct iw_range));
if(ret)
break;
- /* Set the length (useless : its constant...) */
+ /* Set the length (useless: it's constant). */
wrq->u.data.length = sizeof(struct iw_range);
- /* Set information in the range struct */
+ /* Set information in the range struct. */
range.throughput = 1.6 * 1024 * 1024; /* don't argue on this ! */
range.min_nwid = 0x0000;
range.max_nwid = 0xFFFF;
- /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
range.max_qual.level = MMR_SIGNAL_LVL;
range.max_qual.noise = MMR_SILENCE_LVL;
- /* Copy structure to the user buffer */
+ /* Copy structure to the user buffer. */
copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range));
}
break;
case SIOCGIWPRIV:
- /* Basic checking... */
+ /* Basic checking */
if(wrq->u.data.pointer != (caddr_t) 0)
{
struct iw_priv_args priv[] =
if(ret)
break;
- /* Set the number of ioctl available */
+ /* Set the number of available ioctls. */
wrq->u.data.length = 4;
- /* Copy structure to the user buffer */
+ /* Copy structure to the user buffer. */
copy_to_user(wrq->u.data.pointer, (u_char *) priv,
sizeof(priv));
}
case SIOCSIWSPY:
/* Set the spy list */
- /* Check the number of addresses */
+ /* Check the number of addresses. */
if(wrq->u.data.length > IW_MAX_SPY)
{
ret = -E2BIG;
}
lp->spy_number = wrq->u.data.length;
- /* If there is some addresses to copy */
+ /* Are there are addresses to copy? */
if(lp->spy_number > 0)
{
struct sockaddr address[IW_MAX_SPY];
int i;
- /* Verify where the user has set his addresses */
+ /* Verify where the user has set his addresses. */
ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
sizeof(struct sockaddr) * lp->spy_number);
if(ret)
break;
- /* Copy addresses to the driver */
+ /* Copy addresses to the driver. */
copy_from_user(address, wrq->u.data.pointer,
sizeof(struct sockaddr) * lp->spy_number);
- /* Copy addresses to the lp structure */
+ /* Copy addresses to the lp structure. */
for(i = 0; i < lp->spy_number; i++)
{
memcpy(lp->spy_address[i], address[i].sa_data,
WAVELAN_ADDR_SIZE);
}
- /* Reset structure... */
+ /* Reset structure. */
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO
- printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+ printk(KERN_DEBUG "SetSpy - Set of new addresses is: \n");
for(i = 0; i < wrq->u.data.length; i++)
printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
lp->spy_address[i][0],
break;
case SIOCGIWSPY:
- /* Get the spy list and spy stats */
+ /* Get the spy list and spy stats. */
/* Set the number of addresses */
wrq->u.data.length = lp->spy_number;
- /* If the user want to have the addresses back... */
+ /* Does the user want to have the addresses back? */
if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
{
struct sockaddr address[IW_MAX_SPY];
int i;
- /* Verify the user buffer */
+ /* Verify the user buffer. */
ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
(sizeof(iw_qual) + sizeof(struct sockaddr))
* IW_MAX_SPY);
if(ret)
break;
- /* Copy addresses from the lp structure */
+ /* Copy addresses from the lp structure. */
for(i = 0; i < lp->spy_number; i++)
{
memcpy(address[i].sa_data, lp->spy_address[i],
address[i].sa_family = AF_UNIX;
}
- /* Copy addresses to the user buffer */
+ /* Copy addresses to the user buffer. */
copy_to_user(wrq->u.data.pointer, address,
sizeof(struct sockaddr) * lp->spy_number);
- /* Copy stats to the user buffer (just after) */
+ /* Copy stats to the user buffer (just after). */
copy_to_user(wrq->u.data.pointer +
(sizeof(struct sockaddr) * lp->spy_number),
lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
- /* Reset updated flags */
+ /* Reset updated flags. */
for(i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0;
} /* if(pointer != NULL) */
if(!suser())
return -EPERM;
- /* Check the number of intervals */
+ /* Check the number of intervals. */
if(wrq->u.data.length > 16)
{
ret = -E2BIG;
}
lp->his_number = wrq->u.data.length;
- /* If there is some addresses to copy */
+ /* Are there addresses to copy? */
if(lp->his_number > 0)
{
- /* Verify where the user has set his addresses */
+ /* Verify where the user has set his addresses. */
ret = verify_area(VERIFY_READ, wrq->u.data.pointer,
sizeof(char) * lp->his_number);
if(ret)
copy_from_user(lp->his_range, wrq->u.data.pointer,
sizeof(char) * lp->his_number);
- /* Reset structure... */
+ /* Reset structure. */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
}
break;
case SIOCGIPHISTO:
- /* Set the number of intervals */
+ /* Set the number of intervals. */
wrq->u.data.length = lp->his_number;
/* Give back the distribution statistics */
if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
{
- /* Verify the user buffer */
+ /* Verify the user buffer. */
ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
sizeof(long) * 16);
if(ret)
break;
- /* Copy data to the user buffer */
+ /* Copy data to the user buffer. */
copy_to_user(wrq->u.data.pointer, lp->his_sum,
sizeof(long) * lp->his_number);
} /* if(pointer != NULL) */
ret = -EOPNOTSUPP;
}
- /* ReEnable interrupts & restore flags */
+ /* Enable interrupts and restore flags. */
wv_splx(x);
#ifdef DEBUG_IOCTL_TRACE
/*------------------------------------------------------------------*/
/*
- * Get wireless statistics
- * Called by /proc/net/wireless...
+ * Get wireless statistics.
+ * Called by /proc/net/wireless
*/
static iw_stats *
wavelan_get_wireless_stats(device * dev)
printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
#endif
- /* Disable interrupts & save flags */
+ /* Disable interrupts and save flags. */
x = wv_splhi();
if(lp == (net_local *) NULL)
return (iw_stats *) NULL;
wstats = &lp->wstats;
- /* Get data from the mmc */
+ /* Get data from the mmc. */
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
- /* Copy data to wireless stuff */
+ /* Copy data to wireless stuff. */
wstats->status = m.mmr_dce_status;
wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
wstats->discard.code = 0L;
wstats->discard.misc = 0L;
- /* ReEnable interrupts & restore flags */
+ /* Enable interrupts and restore flags. */
wv_splx(x);
#ifdef DEBUG_IOCTL_TRACE
/************************* PACKET RECEPTION *************************/
/*
- * This part deal with receiving the packets.
- * The interrupt handler get an interrupt when a packet has been
- * successfully received and called this part...
+ * This part deals with receiving the packets.
+ * The interrupt handler gets an interrupt when a packet has been
+ * successfully received and calls this part.
*/
/*------------------------------------------------------------------*/
/*
- * This routine does the actual copy of data (including the ethernet
+ * This routine does the actual copying of data (including the Ethernet
* header structure) from the WaveLAN card to an sk_buff chain that
- * will be passed up to the network interface layer. NOTE: We
+ * will be passed up to the network interface layer. NOTE: we
* currently don't handle trailer protocols (neither does the rest of
* the network interface), so if that is needed, it will (at least in
* part) be added here. The contents of the receive ring buffer are
* copied to a message chain that is then passed to the kernel.
*
- * Note: if any errors occur, the packet is "dropped on the floor"
+ * Note: if any errors occur, the packet is "dropped on the floor".
* (called by wv_packet_rcv())
*/
static inline void
skb->dev = dev;
- /* Copy the packet to the buffer */
+ /* Copy the packet to the buffer. */
obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
skb->protocol=eth_type_trans(skb, dev);
wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
#endif /* DEBUG_RX_INFO */
- /* Statistics gathering & stuff associated.
+ /* Statistics-gathering and associated stuff.
* It seem a bit messy with all the define, but it's really simple... */
#if defined(WIRELESS_SPY) || defined(HISTOGRAM)
if(
#endif /* HISTOGRAM */
0)
{
- u_char stats[3]; /* Signal level, Noise level, Signal quality */
+ u_char stats[3]; /* signal level, noise level, signal quality */
- /* read signal level, silence level and signal quality bytes */
- /* Note : in the Pcmcia hardware, these are part of the frame. It seem
+ /* Read signal level, silence level and signal quality bytes. */
+ /* Note: in the PCMCIA hardware, these are part of the frame. It seems
* that for the ISA hardware, it's nowhere to be found in the frame,
- * so I'm oblige to do this (it has side effect on /proc/net/wireless)
- * Any idea ? */
+ * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
+ * Any ideas? */
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
/*
- * Hand the packet to the Network Module
+ * Hand the packet to the network module.
*/
netif_rx(skb);
- /* Keep stats up to date */
+ /* Keep statistics up to date */
lp->stats.rx_packets++;
lp->stats.rx_bytes += skb->len;
printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
#endif
- /* Loop on each received packet */
+ /* Loop on each received packet. */
for(;;)
{
fd_t fd;
obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd));
- /* If the current frame is not complete, we have reach the end... */
+ /* If the current frame is not complete, we have reached the end. */
if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
- break; /* This is how we exit the loop */
+ break; /* This is how we exit the loop. */
nreaped++;
- /* Check if frame correctly received */
+ /* Check whether frame was correctly received. */
if((fd.fd_status & (FD_STATUS_B | FD_STATUS_OK)) !=
(FD_STATUS_B | FD_STATUS_OK))
{
#endif
}
- /* Check is there was problems in the frame processing */
+ /* Were there problems in processing the frame? Let's check. */
if((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 |
FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11))
!= 0)
}
}
- /* Check if frame contain a pointer to the data */
+ /* Does the frame contain a pointer to the data? Let's check. */
if(fd.fd_rbd_offset == I82586NULL)
#ifdef DEBUG_RX_ERROR
printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name);
/*********************** PACKET TRANSMISSION ***********************/
/*
- * This part deal with sending packet through the wavelan
+ * This part deals with sending packets through the WaveLAN.
*
*/
* locations on the WaveLAN card and starts the card off on
* the transmit.
*
- * The principle :
- * Each block contains a transmit command, a nop command,
+ * The principle:
+ * Each block contains a transmit command, a NOP command,
* a transmit block descriptor and a buffer.
* The CU reads the transmit block which points to the tbd,
* reads the tbd and the content of the buffer.
* When it has finished with it, it goes to the next command
- * which in our case is the nop. The nop points on itself,
+ * which in our case is the NOP. The NOP points on itself,
* so the CU stops here.
* When we add the next block, we modify the previous nop
* to make it point on the new tx command.
printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
#endif
- /* Check if we need some padding */
+ /* Do we need some padding? */
if(clen < ETH_ZLEN)
clen = ETH_ZLEN;
x = wv_splhi();
- /* Calculate addresses of next block and previous block */
+ /* Calculate addresses of next block and previous block. */
txblock = lp->tx_first_free;
txpred = txblock - TXBLOCKZ;
if(txpred < OFFSET_CU)
lp->tx_n_in_use++;
- /* Calculate addresses of the differents part of the block */
+ /* Calculate addresses of the different parts of the block. */
tx_addr = txblock;
nop_addr = tx_addr + sizeof(tx);
tbd_addr = nop_addr + sizeof(nop);
buf_addr = tbd_addr + sizeof(tbd);
/*
- * Transmit command.
+ * Transmit command
*/
tx.tx_h.ac_status = 0;
obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
sizeof(tx.tx_h.ac_status));
/*
- * NOP command.
+ * NOP command
*/
nop.nop_h.ac_status = 0;
obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
sizeof(nop.nop_h.ac_link));
/*
- * Transmit buffer descriptor.
+ * Transmit buffer descriptor
*/
tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
tbd.tbd_next_bd_offset = I82586NULL;
obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd));
/*
- * Data.
+ * Data
*/
obram_write(ioaddr, buf_addr, buf, clen);
(unsigned char *) &nop.nop_h.ac_link,
sizeof(nop.nop_h.ac_link));
- /* Keep stats up to date */
+ /* Keep stats up to date. */
lp->stats.tx_bytes += length;
/* If watchdog not already active, activate it... */
if(lp->watchdog.prev == (timer_list *) NULL)
{
- /* set timer to expire in WATCHDOG_JIFFIES */
+ /* Set timer to expire in WATCHDOG_JIFFIES. */
lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
add_timer(&lp->watchdog);
}
* This routine is called when we want to send a packet (NET3 callback)
* In this routine, we check if the hardware is ready to accept
* the packet. We also prevent reentrance. Then, we call the function
- * to send the packet...
+ * to send the packet.
*/
static int
wavelan_packet_xmit(struct sk_buff * skb,
#endif
/* This flag indicate that the hardware can't perform a transmission.
- * Theoritically, NET3 check it before sending a packet to the driver,
- * but in fact it never do that and pool continuously.
- * As the watchdog will abort too long transmissions, we are quite safe...
+ * Theoretically, NET3 checks it before sending a packet to the driver,
+ * but in fact it never does that and pools continuously.
+ * As the watchdog will abort overly long transmissions, we are quite safe.
*/
if(dev->tbusy)
return 1;
#endif
else
{
- /* If somebody has asked to reconfigure the controler, we can do it now */
+ /* If somebody has asked to reconfigure the controller,
+ * we can do it now.
+ */
if(lp->reconfig_82586)
{
wv_82586_config(dev);
return 0;
}
-/********************** HARDWARE CONFIGURATION **********************/
+/*********************** HARDWARE CONFIGURATION ***********************/
/*
- * This part do the real job of starting and configuring the hardware.
+ * This part does the real job of starting and configuring the hardware.
*/
-/*------------------------------------------------------------------*/
+/*--------------------------------------------------------------------*/
/*
* Routine to initialize the Modem Management Controller.
* (called by wv_hw_reset())
printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
#endif
- /* Read the parameter storage area */
+ /* Read the parameter storage area. */
psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
#ifdef USE_PSA_CONFIG
/* Is the PSA is not configured */
if(!configured)
{
- /* User will be able to configure NWID after (with iwconfig) */
+ /* User will be able to configure NWID later (with iwconfig). */
psa.psa_nwid[0] = 0;
psa.psa_nwid[1] = 0;
- /* As NWID is not set : no NWID checking */
+ /* no NWID checking since NWID is not set */
psa.psa_nwid_select = 0;
/* Disable encryption */
#endif
}
- /* Zero the mmc structure */
+ /* Zero the mmc structure. */
memset(&m, 0x00, sizeof(m));
- /* Copy PSA info to the mmc */
+ /* Copy PSA info to the mmc. */
m.mmw_netw_id_l = psa.psa_nwid[1];
m.mmw_netw_id_h = psa.psa_nwid[0];
m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
- /* Missing : encryption stuff... */
+ /* Encryption stuff is missing. */
/*
* Set default modem control parameters.
m.mmw_decay_prm = 0;
m.mmw_decay_updat_prm = 0;
- /* Write all info to mmc */
+ /* Write all info to MMC. */
mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
- /* The following code start the modem of the 2.00 frequency
+ /* The following code starts the modem of the 2.00 frequency
* selectable cards at power on. It's not strictly needed for the
- * following boots...
+ * following boots.
* The original patch was by Joe Finney for the PCMCIA driver, but
- * I've cleaned it a bit and add documentation.
+ * I've cleaned it up a bit and added documentation.
* Thanks to Loeke Brederveld from Lucent for the info.
*/
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
- * (does it work for everybody ??? - especially old cards...) */
- /* Note : WFREQSEL verify that it is able to read from EEprom
- * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
- * is 0xA (Xilinx version) or 0xB (Ariadne version).
- * My test is more crude but do work... */
+ * Does it work for everybody, especially old cards? */
+ /* Note: WFREQSEL verifies that it is able to read a sensible
+ * frequency from from EEPROM (address 0x00) and that
+ * MMR_FEE_STATUS_ID is 0xA (Xilinx version) or 0xB (Ariadne version).
+ * My test is more crude but does work. */
if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
/* We must download the frequency parameters to the
- * synthetisers (from the EEprom - area 1)
- * Note : as the EEprom is auto decremented, we set the end
+ * synthesizers (from the EEPROM - area 1)
+ * Note: as the EEPROM is automatically decremented, we set the end
* if the area... */
m.mmw_fee_addr = 0x0F;
m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
(unsigned char *)&m.mmw_fee_ctrl, 2);
- /* Wait until the download is finished */
+ /* Wait until the download is finished. */
fee_wait(ioaddr, 100, 100);
#ifdef DEBUG_CONFIG_INFO
- /* The frequency was in the last word downloaded... */
+ /* The frequency was in the last word downloaded. */
mmc_read(ioaddr, (char *)&m.mmw_fee_data_l - (char *)&m,
(unsigned char *)&m.mmw_fee_data_l, 2);
- /* Print some info for the user */
- printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n",
+ /* Print some info for the user. */
+ printk(KERN_DEBUG "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n",
dev->name,
((m.mmw_fee_data_h << 4) |
(m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
#endif
/* We must now download the power adjust value (gain) to
- * the synthetisers (from the EEprom - area 7 - DAC) */
+ * the synthesizers (from the EEPROM - area 7 - DAC). */
m.mmw_fee_addr = 0x61;
m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
(unsigned char *)&m.mmw_fee_ctrl, 2);
- /* Wait until the download is finished */
+ /* Wait until the download is finished. */
} /* if 2.00 card */
#ifdef DEBUG_CONFIG_TRACE
* Start the command unit executing the NOP
* self-loop of the first transmit block.
*
- * Here, we create the list of send buffer used to transmit packets
+ * Here we create the list of send buffers used to transmit packets
* between the PC and the command unit. For each buffer, we create a
* buffer descriptor (pointing on the buffer), a transmit command
- * (pointing to the buffer descriptor) and a nop command.
- * The transmit command is linked to the nop, and the nop to itself.
- * When we will have finish to execute the transmit command, we will
- * then loop on the nop. By releasing the nop link to a new command,
+ * (pointing to the buffer descriptor) and a NOP command.
+ * The transmit command is linked to the NOP, and the NOP to itself.
+ * When we will have finished executing the transmit command, we will
+ * then loop on the NOP. By releasing the NOP link to a new command,
* we may send another buffer.
*
* (called by wv_hw_reset())
/*------------------------------------------------------------------*/
/*
- * This routine does a standard config of the WaveLAN controler (i82586).
+ * This routine does a standard configuration of the WaveLAN
+ * controller (i82586).
*
- * It initialise the scp, iscp and scb structure
- * The two first are only pointer to the next.
+ * It initialises the scp, iscp and scb structure
+ * The first two are just pointers to the next.
* The last one is used for basic configuration and for basic
- * communication (interrupt status)
+ * communication (interrupt status).
*
* (called by wv_hw_reset())
*/
iscp.iscp_offset = OFFSET_SCB;
obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
- /* Our first command is to reset the i82586 */
+ /* Our first command is to reset the i82586. */
memset(&scb, 0x00, sizeof(scb));
scb.scb_command = SCB_CMD_RESET;
scb.scb_cbl_offset = OFFSET_CU;
set_chan_attn(ioaddr, lp->hacr);
- /* Wait for command to finish */
+ /* Wait for command to finish. */
for(i = 1000; i > 0; i--)
{
obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, sizeof(iscp));
return -1;
}
- /* Check command completion */
+ /* Check command completion. */
for(i = 15; i > 0; i--)
{
obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, sizeof(scb));
wv_ack(dev);
- /* Set the action command header */
+ /* Set the action command header. */
memset(&cb, 0x00, sizeof(cb));
cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
cb.ac_link = OFFSET_CU;
/*------------------------------------------------------------------*/
/*
- * This routine does a standard config of the WaveLAN controler (i82586).
+ * This routine does a standard configuration of the WaveLAN
+ * controller (i82586).
*
* This routine is a violent hack. We use the first free transmit block
* to make our configuration. In the buffer area, we create the three
- * configure command (linked). We make the previous nop point to the
- * beggining of the buffer instead of the tx command. After, we go as
- * usual to the nop command...
- * Note that only the last command (mc_set) will generate an interrupt...
+ * configuration commands (linked). We make the previous NOP point to
+ * the beginning of the buffer instead of the tx command. After, we go
+ * as usual to the NOP command.
+ * Note that only the last command (mc_set) will generate an interrupt.
*
* (called by wv_hw_reset(), wv_82586_reconfig())
*/
x = wv_splhi();
- /* Calculate addresses of next block and previous block */
+ /* Calculate addresses of next block and previous block. */
txblock = lp->tx_first_free;
txpred = txblock - TXBLOCKZ;
if(txpred < OFFSET_CU)
lp->tx_n_in_use++;
- /* Calculate addresses of the differents part of the block */
+ /* Calculate addresses of the different parts of the block. */
tx_addr = txblock;
nop_addr = tx_addr + sizeof(tx);
tbd_addr = nop_addr + sizeof(nop);
- cfg_addr = tbd_addr + sizeof(tbd_t); /* beggining of the buffer */
+ cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */
ias_addr = cfg_addr + sizeof(cfg);
mcs_addr = ias_addr + sizeof(ias);
/*
- * Transmit command.
+ * Transmit command
*/
tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */
obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
sizeof(tx.tx_h.ac_status));
/*
- * NOP command.
+ * NOP command
*/
nop.nop_h.ac_status = 0;
obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
(unsigned char *) &nop.nop_h.ac_link,
sizeof(nop.nop_h.ac_link));
- /* Create a configure action */
+ /* Create a configure action. */
memset(&cfg, 0x00, sizeof(cfg));
#if 0
/*
- * The default board configuration.
+ * The default board configuration
*/
cfg.fifolim_bytecnt = 0x080c;
cfg.addrlen_mode = 0x2600;
cfg.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
cfg.slot_time = 0xf00c; /* slottime=12 */
- cfg.hardware = 0x0008; /* tx even w/o CD */
+ cfg.hardware = 0x0008; /* tx even without CD */
cfg.min_frame_len = 0x0040;
#endif /* 0 */
/*
- * For Linux we invert AC_CFG_ALOC(..) so as to conform
+ * For Linux we invert AC_CFG_ALOC() so as to conform
* to the way that net packets reach us from above.
* (See also ac_tx_t.)
*/
cfg.cfg_h.ac_link = ias_addr;
obram_write(ioaddr, cfg_addr, (unsigned char *)&cfg, sizeof(cfg));
- /* Setup the MAC address */
+ /* Set up the MAC address */
memset(&ias, 0x00, sizeof(ias));
ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
ias.ias_h.ac_link = mcs_addr;
memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr));
obram_write(ioaddr, ias_addr, (unsigned char *)&ias, sizeof(ias));
- /* Initialize adapter's ethernet multicast addresses */
+ /* Initialize adapter's Ethernet multicast addresses */
memset(&mcs, 0x00, sizeof(mcs));
mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
mcs.mcs_h.ac_link = nop_addr;
mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
obram_write(ioaddr, mcs_addr, (unsigned char *)&mcs, sizeof(mcs));
- /* If any address to set */
+ /* Any address to set? */
if(lp->mc_count)
{
for(dmi=dev->mc_list; dmi; dmi=dmi->next)
/*------------------------------------------------------------------*/
/*
- * This routine stop gracefully the WaveLAN controler (i82586).
- * (called by wavelan_close())
+ * This routine, called by wavelan_close(), gracefully stops the
+ * WaveLAN controller (i82586).
*/
static inline void
wv_82586_stop(device * dev)
printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
#endif
- /* Suspend both command unit and receive unit */
+ /* Suspend both command unit and receive unit. */
scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS);
obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
(unsigned char *)&scb_cmd, sizeof(scb_cmd));
/*------------------------------------------------------------------*/
/*
- * Totally reset the wavelan and restart it.
+ * Totally reset the WaveLAN and restart it.
* Performs the following actions:
* 1. A power reset (reset DMA)
* 2. Initialize the radio modem (using wv_mmc_init)
(unsigned int)dev);
#endif
- /* If watchdog was activated, kill it ! */
+ /* If watchdog was activated, kill it! */
if(lp->watchdog.prev != (timer_list *) NULL)
del_timer(&lp->watchdog);
- /* Increase the number of resets done */
+ /* Increase the number of resets done. */
lp->nresets++;
wv_hacr_reset(ioaddr);
(wv_82586_start(dev) < 0))
return -1;
- /* Enable the card to send interrupts */
+ /* Enable the card to send interrupts. */
wv_ints_on(dev);
/* Start card functions */
(wv_cu_start(dev) < 0))
return -1;
- /* Finish configuration */
+ /* Finish configuration. */
wv_82586_config(dev);
#ifdef DEBUG_CONFIG_TRACE
/*------------------------------------------------------------------*/
/*
- * Check if there is a wavelan at the specific base address.
- * As a side effect, it read the MAC address.
+ * Check if there is a WaveLAN at the specific base address.
+ * As a side effect, this reads the MAC address.
* (called in wavelan_probe() and init_module())
*/
static int
{
int i; /* Loop counter */
- /* Check if the base address if available */
+ /* Check if the base address if available. */
if(check_region(ioaddr, sizeof(ha_t)))
- return EADDRINUSE; /* ioaddr already used... */
+ return EADDRINUSE; /* ioaddr already used */
/* Reset host interface */
wv_hacr_reset(ioaddr);
- /* Read the MAC address from the parameter storage area */
+ /* Read the MAC address from the parameter storage area. */
psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
mac, 6);
/*
- * Check the first three octets of the addr for the manufacturer's code.
- * Note: If you can't find your wavelan card, you've got a
- * non-NCR/AT&T/Lucent ISA cards, see wavelan.p.h for detail on
- * how to configure your card...
+ * Check the first three octets of the address for the manufacturer's code.
+ * Note: if this can't find your WaveLAN card, you've got a
+ * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on
+ * how to configure your card.
*/
for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
if((mac[0] == MAC_ADDRESSES[i][0]) &&
return 0;
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_WARNING "Wavelan (0x%3X) : Your MAC address might be : %02X:%02X:%02X...\n",
+ printk(KERN_WARNING "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
ioaddr, mac[0], mac[1], mac[2]);
#endif
return ENODEV;
lp = (net_local *) dev->priv;
ioaddr = dev->base_addr;
- /* Prevent reentrance. What should we do here ? */
+ /* Prevent reentrance. What should we do here? */
#ifdef DEBUG_INTERRUPT_ERROR
if(dev->interrupt)
printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
return;
}
- /* Read interrupt data */
+ /* Read interrupt data. */
obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
(unsigned char *) &status, sizeof(status));
wv_receive(dev);
}
- /* Check the state of the command unit */
+ /* Check the state of the command unit. */
if(((status & SCB_ST_CNA) == SCB_ST_CNA) ||
(((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start))
{
wv_hw_reset(dev);
}
- /* Check the state of the command unit */
+ /* Check the state of the command unit. */
if(((status & SCB_ST_RNR) == SCB_ST_RNR) ||
(((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start))
{
/*------------------------------------------------------------------*/
/*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel. If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, we set a timer in the
+ * kernel. If the transmission completes, this timer is disabled. If
+ * the timer expires, we try to unlock the hardware.
*
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the previous version of the ISA driver. I make it this
+ * Note: this watchdog doesn't work on the same principle as the
+ * watchdog in the previous version of the ISA driver. I made it this
* way because the overhead of add_timer() and del_timer() is nothing
- * and that it avoid calling the watchdog, saving some CPU...
+ * and because it avoids calling the watchdog, saving some CPU.
*/
static void
wavelan_watchdog(u_long a)
wv_hw_reset(dev);
}
else
- /* Re-set watchodog for next transmission */
+ /* Reset watchdog for next transmission. */
if(lp->tx_n_in_use > 0)
{
/* set timer to expire in WATCHDOG_JIFFIES */
/********************* CONFIGURATION CALLBACKS *********************/
/*
- * Here are the functions called by the linux networking (NET3) for
- * initialization, configuration and deinstallations of the Wavelan
- * ISA Hardware.
+ * Here are the functions called by the Linux networking code (NET3)
+ * for initialization, configuration and deinstallations of the
+ * WaveLAN ISA hardware.
*/
/*------------------------------------------------------------------*/
/*
* Configure and start up the WaveLAN PCMCIA adaptor.
- * Called by NET3 when it "open" the device.
+ * Called by NET3 when it "opens" the device.
*/
static int
wavelan_open(device * dev)
if(dev->irq == 0)
{
#ifdef DEBUG_CONFIG_ERRORS
- printk(KERN_WARNING "%s: wavelan_open(): no irq\n", dev->name);
+ printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name);
#endif
return -ENXIO;
}
if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
{
#ifdef DEBUG_CONFIG_ERRORS
- printk(KERN_WARNING "%s: wavelan_open(): invalid irq\n", dev->name);
+ printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name);
#endif
return -EAGAIN;
}
/*------------------------------------------------------------------*/
/*
- * Shutdown the WaveLAN ISA card.
- * Called by NET3 when it "close" the device.
+ * Shut down the WaveLAN ISA card.
+ * Called by NET3 when it "closes" the device.
*/
static int
wavelan_close(device * dev)
(unsigned int) dev);
#endif
- /* Not do the job twice... */
+ /* Don't do the job twice. */
if(dev->start == 0)
return 0;
dev->tbusy = 1;
dev->start = 0;
- /* If watchdog was activated, kill it ! */
+ /* If watchdog was activated, kill it! */
if(lp->watchdog.prev != (timer_list *) NULL)
del_timer(&lp->watchdog);
/*------------------------------------------------------------------*/
/*
- * Probe an i/o address, and if the wavelan is there configure the
+ * Probe an I/O address, and if the WaveLAN is there configure the
* device structure
- * (called by wavelan_probe() & via init_module())
+ * (called by wavelan_probe() and via init_module()).
*/
__initfunc(static int
wavelan_config(device * dev))
(unsigned int)dev, ioaddr);
#endif
- /* Check irq arg on command line */
+ /* Check IRQ argument on command line. */
if(dev->irq != 0)
{
irq_mask = wv_irq_to_psa(dev->irq);
if(irq_mask == 0)
{
#ifdef DEBUG_CONFIG_ERROR
- printk(KERN_WARNING "%s: wavelan_config(): invalid irq %d -- ignored.\n",
+ printk(KERN_WARNING "%s: wavelan_config(): invalid IRQ %d ignored.\n",
dev->name, dev->irq);
#endif
dev->irq = 0;
else
{
#ifdef DEBUG_CONFIG_INFO
- printk(KERN_DEBUG "%s: wavelan_config(): changing irq to %d\n",
+ printk(KERN_DEBUG "%s: wavelan_config(): changing IRQ to %d\n",
dev->name, dev->irq);
#endif
psa_write(ioaddr, HACR_DEFAULT,
memset(dev->priv, 0x00, sizeof(net_local));
lp = (net_local *)dev->priv;
- /* Back link to the device structure */
+ /* Back link to the device structure. */
lp->dev = dev;
- /* Add the device at the beggining of the linked list */
+ /* Add the device at the beginning of the linked list. */
lp->next = wavelan_list;
wavelan_list = lp;
/*
* Fill in the fields of the device structure
- * with ethernet-generic values.
+ * with generic Ethernet values.
*/
ether_setup(dev);
dev->set_multicast_list = &wavelan_set_multicast_list;
dev->set_mac_address = &wavelan_set_mac_address;
-#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
+#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
dev->do_ioctl = wavelan_ioctl;
dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif
dev->mtu = WAVELAN_MTU;
- /* Display nice info */
+ /* Display nice information. */
wv_init_info(dev);
#ifdef DEBUG_CALLBACK_TRACE
/*------------------------------------------------------------------*/
/*
- * Check for a network adaptor of this type.
- * Return '0' iff one exists.
- * (There seem to be different interpretations of
+ * Check for a network adaptor of this type. Return '0' iff one
+ * exists. There seem to be different interpretations of
* the initial value of dev->base_addr.
- * We follow the example in drivers/net/ne.c.)
+ * We follow the example in drivers/net/ne.c.
* (called in "Space.c")
*/
__initfunc(int
wavelan_probe(device * dev))
{
short base_addr;
- mac_addr mac; /* Mac address (check wavelan existence) */
+ mac_addr mac; /* MAC address (check existence of WaveLAN) */
int i;
int r;
}
#endif /* STRUCT_CHECK */
- /* Check the value of the command line parameter for base address */
+ /* Check the value of the command line parameter for base address. */
base_addr = dev->base_addr;
/* Don't probe at all. */
/* Check a single specified location. */
if(base_addr > 0x100)
{
- /* Check if the is something at this base address */
+ /* Check if there is something at this base address */
if((r = wv_check_ioaddr(base_addr, mac)) == 0)
{
- memcpy(dev->dev_addr, mac, 6); /* Copy mac address */
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
r = wavelan_config(dev);
}
return r;
}
- /* Scan all possible address of the wavelan hardware */
+ /* Scan all possible addresses of the WaveLAN hardware. */
for(i = 0; i < NELS(iobase); i++)
{
- /* Check if the is something at this base address */
+ /* Check whether there is something at this base address. */
if(wv_check_ioaddr(iobase[i], mac) == 0)
{
- dev->base_addr = iobase[i]; /* Copy base address */
- memcpy(dev->dev_addr, mac, 6); /* Copy mac address */
+ dev->base_addr = iobase[i]; /* Copy base address. */
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
if(wavelan_config(dev) == 0)
{
#ifdef DEBUG_CALLBACK_TRACE
}
}
- /* We may have touch base_addr : another driver may not like it... */
+ /* We may have touched base_addr. Another driver may not like it. */
dev->base_addr = base_addr;
#ifdef DEBUG_CONFIG_INFO
/****************************** MODULE ******************************/
/*
- * Module entry point : insertion & removal
+ * Module entry point: insertion and removal
*/
#ifdef MODULE
/*------------------------------------------------------------------*/
/*
- * Insertion of the module...
- * I'm now quite proud of the multi-device support...
+ * Insertion of the module
+ * I'm now quite proud of the multi-device support.
*/
int
init_module(void)
{
- mac_addr mac; /* Mac address (check wavelan existence) */
+ mac_addr mac; /* MAC address (check WaveLAN existence) */
int ret = 0;
int i;
if(io[0] == 0)
{
#ifdef DEBUG_CONFIG_ERRORS
- printk(KERN_WARNING "wavelan init_module(): doing device probing (bad !)\n");
+ printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n");
printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n");
#endif
- /* Copy the basic set of address to be probed */
+ /* Copy the basic set of address to be probed. */
for(i = 0; i < NELS(iobase); i++)
io[i] = iobase[i];
}
- /* Loop on all possible base addresses */
+ /* Loop on all possible base addresses. */
i = -1;
while((io[++i] != 0) && (i < NELS(io)))
{
- /* Check if the is something at this base address */
+ /* Check if there is something at this base address. */
if(wv_check_ioaddr(io[i], mac) == 0)
{
device * dev;
- /* Create device and set basics args */
+ /* Create device and set basic arguments. */
dev = kmalloc(sizeof(struct device), GFP_KERNEL);
memset(dev, 0x00, sizeof(struct device));
dev->name = name[i];
dev->base_addr = io[i];
dev->irq = irq[i];
dev->init = &wavelan_config;
- memcpy(dev->dev_addr, mac, 6); /* Copy mac address */
+ memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */
- /* Try to create the device */
+ /* Try to create the device. */
if(register_netdev(dev) != 0)
{
- /* DeAllocate everything */
- /* Note : if dev->priv is mallocated, there is no way to fail */
+ /* Deallocate everything. */
+ /* Note: if dev->priv is mallocated, there is no way to fail. */
kfree_s(dev, sizeof(struct device));
ret = -EIO;
}
- } /* If there is something at the address */
- } /* Loop on all addresses */
+ } /* if there is something at the address */
+ } /* Loop on all addresses. */
#ifdef DEBUG_CONFIG_ERRORS
if(wavelan_list == (net_local *) NULL)
- printk(KERN_WARNING "wavelan init_module(): No device found\n");
+ printk(KERN_WARNING "WaveLAN init_module(): no device found\n");
#endif
#ifdef DEBUG_MODULE_TRACE
printk(KERN_DEBUG "-> cleanup_module()\n");
#endif
- /* Loop on all devices and release them */
+ /* Loop on all devices and release them. */
while(wavelan_list != (net_local *) NULL)
{
device * dev = wavelan_list->dev;
dev->name, (unsigned int) dev);
#endif
- /* Release the ioport-region. */
+ /* Release the ioport region. */
release_region(dev->base_addr, sizeof(ha_t));
- /* Remove definitely the device */
+ /* Definitely remove the device. */
unregister_netdev(dev);
- /* Unlink the device */
+ /* Unlink the device. */
wavelan_list = wavelan_list->next;
- /* Free pieces */
+ /* Free pieces. */
kfree_s(dev->priv, sizeof(struct net_local));
kfree_s(dev, sizeof(struct device));
}
fi
dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI
fi
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+ source drivers/acorn/scsi/Config.in
+fi
endmenu
esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
- /* Reload the configuration registers */
- eregs->esp_cfact = esp->cfact;
- eregs->esp_stp = 0;
- eregs->esp_soff = 0;
- eregs->esp_timeo = esp->neg_defp;
-
/* This is the only point at which it is reliable to read
* the ID-code for a fast ESP chip variant.
*/
}
#endif
if(family_code == 0x02)
- esp->erev = fas236;
+ if ((version & 7) == 2)
+ esp->erev = fas216;
+ else
+ esp->erev = fas236;
else if(family_code == 0x0a)
esp->erev = fashme; /* Version is usually '5'. */
else
printk("esp%d: FAST chip is %s (family=%d, version=%d)\n",
esp->esp_id,
(esp->erev == fas236) ? "fas236" :
- ((esp->erev == fas100a) ? "fas100a" :
- "fasHME"), family_code, (version & 7));
+ ((esp->erev == fas216) ? "fas216" :
+ (((esp->erev == fas100a) ? "fas100a" :
+ "fasHME"))), family_code, (version & 7));
esp->min_period = ((4 * esp->ccycle) / 1000);
} else {
esp->min_period = ((5 * esp->ccycle) / 1000);
}
+
+ /* Reload the configuration registers */
+ eregs->esp_cfact = esp->cfact;
+ eregs->esp_stp = 0;
+ eregs->esp_soff = 0;
+ eregs->esp_timeo = esp->neg_defp;
esp->max_period = (esp->max_period + 3)>>2;
esp->min_period = (esp->min_period + 3)>>2;
case fashme:
esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
/* fallthrough... */
+ case fas216:
case fas236:
/* Fast 236 or HME */
eregs->esp_cfg2 = esp->config2;
esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
esp->sync_defp = SYNC_DEFP_SLOW;
+ printk("SCSI ID %d Clock %d MHz CCF=%d Time-Out %d ",
+ esp->scsi_id, (esp->cfreq / 1000000),
+ esp->ccf, (int) esp->neg_defp);
/* Fill in ehost data */
esp->ehost->base = (unsigned char *) eregs;
esp_bootup_reset(esp, eregs);
esps_in_use++;
-
- printk("SCSI ID %d Clock %d MHz CCF=%d Time-Out %d ",
- esp->scsi_id, (esp->cfreq / 1000000),
- esp->ccf, (int) esp->neg_defp);
}
/* The info function will return whatever useful
esp = (struct NCR_ESP *) host->hostdata;
switch(esp->erev) {
case esp100:
- return "Sparc ESP100 (NCR53C90)";
+ return "ESP100 (NCR53C90)";
case esp100a:
- return "Sparc ESP100A (NCR53C90A)";
+ return "ESP100A (NCR53C90A)";
case esp236:
- return "Sparc ESP236";
+ return "ESP236";
+ case fas216:
+ return "ESP216-FAST";
case fas236:
- return "Sparc ESP236-FAST";
+ return "ESP236-FAST";
case fashme:
- return "Sparc ESP366-HME";
+ return "ESP366-HME";
case fas100a:
- return "Sparc ESP100A-FAST";
+ return "ESP100A-FAST";
default:
panic("Bogon ESP revision");
};
case esp236:
copy_info(&info, "ESP236\n");
break;
+ case fas216:
+ copy_info(&info, "FAS216\n");
+ break;
case fas236:
copy_info(&info, "FAS236\n");
break;
SCpnt->SCp.buffer =
(struct scatterlist *) SCpnt->request_buffer;
SCpnt->SCp.buffers_residual = 0;
-#ifdef CONFIG_SCSI_SUNESP
- /* Sneaky. */
- SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
- SCpnt->SCp.this_residual,
- ((struct linux_sbus_device*) (esp->edev))->my_bus);
- /* XXX The casts are extremely gross, but with 64-bit kernel
- * XXX and 32-bit SBUS what am I to do? -DaveM
- */
- SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in);
-#else
- SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
- (char *) VTOP((unsigned long) SCpnt->request_buffer);
-#endif
-
+ if (esp->dma_mmu_get_scsi_one)
+ esp->dma_mmu_get_scsi_one (esp, SCpnt);
+ else
+ SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
+ (char *) virt_to_phys(SCpnt->request_buffer);
} else {
ESPQUEUE(("use_sg "));
#ifdef DEBUG_ESP_SG
SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
-#ifdef CONFIG_SCSI_SUNESP
- mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
- SCpnt->SCp.buffers_residual,
- ((struct linux_sbus_device *) (esp->edev))->my_bus);
- /* XXX Again these casts are sick... -DaveM */
- SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address);
-#else
- SCpnt->SCp.ptr =
- (char *) VTOP((unsigned long) SCpnt->SCp.buffer->address);
-#endif
+ if (esp->dma_mmu_get_scsi_sgl)
+ esp->dma_mmu_get_scsi_sgl (esp, SCpnt);
+ else
+ SCpnt->SCp.ptr =
+ (char *) virt_to_phys(SCpnt->SCp.buffer->address);
}
SCpnt->SCp.Status = CHECK_CONDITION;
SCpnt->SCp.Message = 0xff;
/* Free dvma entry. */
if(!done_SC->use_sg) {
-#ifdef CONFIG_SCSI_SUNESP
- /* Sneaky. */
- mmu_release_scsi_one(done_SC->SCp.have_data_in,
- done_SC->request_bufflen,
- ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+ if (esp->dma_mmu_release_scsi_one)
+ esp->dma_mmu_release_scsi_one (esp, done_SC);
} else {
#ifdef DEBUG_ESP_SG
printk("esp%d: unmapping sg ", esp->esp_id);
#endif
-#ifdef CONFIG_SCSI_SUNESP
- mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
- done_SC->use_sg - 1,
- ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+ if (esp->dma_mmu_release_scsi_sgl)
+ esp->dma_mmu_release_scsi_sgl (esp, done_SC);
#ifdef DEBUG_ESP_SG
printk("done.\n");
#endif
return do_work_bus;
}
-static inline void advance_sg(Scsi_Cmnd *sp)
+static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
++sp->SCp.buffer;
--sp->SCp.buffers_residual;
sp->SCp.this_residual = sp->SCp.buffer->length;
-#ifdef CONFIG_SCSI_SUNESP
- sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
-#else
- sp->SCp.ptr = (char *)VTOP((unsigned long) sp->SCp.buffer->address);
-#endif
+ if (esp->dma_advance_sg)
+ esp->dma_advance_sg (sp);
+ else
+ sp->SCp.ptr = (char *)virt_to_phys(sp->SCp.buffer->address);
}
/* Please note that the way I've coded these routines is that I _always_
* figure this out.
*/
if(SCptr->use_sg && !SCptr->SCp.this_residual)
- advance_sg(SCptr);
+ advance_sg(esp, SCptr);
if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
ESPDATA(("to more data\n"));
return esp_do_data(esp, eregs);
tmp = esp->ccycle / 1000;
regval = (((period << 2) + tmp - 1) / tmp);
if(regval && ((esp->erev == fas100a ||
+ esp->erev == fas216 ||
esp->erev == fas236 ||
esp->erev == fashme))) {
if(period >= 50)
SDptr->sync_min_period = (regval & 0x1f);
SDptr->sync_max_offset = (offset | esp->radelay);
- if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+ if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
if((esp->erev == fas100a) || (esp->erev == fashme))
bit = ESP_CONFIG3_FAST;
else
SDptr->sync_min_period = 0;
eregs->esp_soff = 0;
eregs->esp_stp = 0;
- if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+ if((esp->erev == fas100a || esp->erev == fas216 || esp->erev == fas236 || esp->erev == fashme)) {
if((esp->erev == fas100a) || (esp->erev == fashme))
bit = ESP_CONFIG3_FAST;
else
if(esp->current_SC) {
Scsi_Cmnd *SCptr = esp->current_SC;
-#ifdef CONFIG_SCSI_SUNESP
- if(!SCptr->use_sg)
- mmu_release_scsi_one(SCptr->SCp.have_data_in,
- SCptr->request_bufflen,
- ((struct linux_sbus_device *) (esp->edev))->my_bus);
- else
- mmu_release_scsi_sgl((struct mmu_sglist *)
- SCptr->buffer,
- SCptr->use_sg - 1,
- ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+ if(!SCptr->use_sg) {
+ if (esp->dma_mmu_release_scsi_one)
+ esp->dma_mmu_release_scsi_one (esp, SCptr);
+ } else {
+ if (esp->dma_mmu_release_scsi_sgl)
+ esp->dma_mmu_release_scsi_sgl (esp, SCptr);
+ }
SCptr->result = (DID_RESET << 16);
SCptr->scsi_done(SCptr);
if(esp->disconnected_SC) {
Scsi_Cmnd *SCptr;
while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
- if(!SCptr->use_sg)
-#ifdef CONFIG_SCSI_SUNESP
- mmu_release_scsi_one(SCptr->SCp.have_data_in,
- SCptr->request_bufflen,
- ((struct linux_sbus_device *) (esp->edev))->my_bus);
- else
- mmu_release_scsi_sgl((struct mmu_sglist *)
- SCptr->buffer,
- SCptr->use_sg - 1,
- ((struct linux_sbus_device *) (esp->edev))->my_bus);
-#endif
+ if(!SCptr->use_sg) {
+ if (esp->dma_mmu_release_scsi_one)
+ esp->dma_mmu_release_scsi_one (esp, SCptr);
+ } else {
+ if (esp->dma_mmu_release_scsi_sgl)
+ esp->dma_mmu_release_scsi_sgl (esp, SCptr);
+ }
SCptr->result = (DID_RESET << 16);
SCptr->scsi_done(SCptr);
repeat:
again = 0;
for_each_esp(esp) {
+#ifndef __mips__
if(((esp)->irq & 0xf) == irq) {
+#endif
if(esp->dma_irq_p(esp)) {
again = 1;
esp->dma_ints_on(esp);
}
+#ifndef __mips__
}
+#endif
}
if(again)
goto repeat;
(printk ("Internal ESP driver error in file %s, line %d\n", \
__FILE__, __LINE__))
+/*
+ * padding for register structure
+ */
+#ifdef CONFIG_JAZZ_ESP
+#define EREGS_PAD(n)
+#else
+#define EREGS_PAD(n) unchar n[3];
+#endif
+
/* The ESP SCSI controllers have their register sets in three
* "classes":
*
struct ESP_regs {
/* Access Description Offset */
volatile unchar esp_tclow; /* rw Low bits of the transfer count 0x00 */
- unchar tlpad1[3];
+ EREGS_PAD(tlpad1);
volatile unchar esp_tcmed; /* rw Mid bits of the transfer count 0x04 */
- unchar fdpad[3];
+ EREGS_PAD(fdpad);
volatile unchar esp_fdata; /* rw FIFO data bits 0x08 */
- unchar cbpad[3];
+ EREGS_PAD(cbpad);
volatile unchar esp_cmd; /* rw SCSI command bits 0x0c */
- unchar stpad[3];
+ EREGS_PAD(stpad);
volatile unchar esp_status; /* ro ESP status register 0x10 */
#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */
- unchar irqpd[3];
+ EREGS_PAD(irqpd);
volatile unchar esp_intrpt; /* ro Kind of interrupt 0x14 */
#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */
- unchar sspad[3];
+ EREGS_PAD(sspad);
volatile unchar esp_sstep; /* ro Sequence step register 0x18 */
#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */
- unchar ffpad[3];
+ EREGS_PAD(ffpad);
volatile unchar esp_fflags; /* ro Bits of current FIFO info 0x1c */
#define esp_soff esp_fflags /* wo Sync offset 0x1c */
- unchar cf1pd[3];
+ EREGS_PAD(cf1pd);
volatile unchar esp_cfg1; /* rw First configuration register 0x20 */
- unchar cfpad[3];
+ EREGS_PAD(cfpad);
volatile unchar esp_cfact; /* wo Clock conversion factor 0x24 */
#define esp_status2 esp_cfact /* ro HME status2 register 0x24 */
- unchar ctpad[3];
+ EREGS_PAD(ctpad);
volatile unchar esp_ctest; /* wo Chip test register 0x28 */
- unchar cf2pd[3];
+ EREGS_PAD(cf2pd);
volatile unchar esp_cfg2; /* rw Second configuration register 0x2c */
- unchar cf3pd[3];
+ EREGS_PAD(cf3pd);
/* The following is only found on the 53C9X series SCSI chips */
volatile unchar esp_cfg3; /* rw Third configuration register 0x30 */
- unchar thpd[7];
-
+ EREGS_PAD(holep);
+ volatile unchar esp_hole; /* hole in register map 0x34 */
+ EREGS_PAD(thpd);
/* The following is found on all chips except the NCR53C90 (ESP100) */
volatile unchar esp_tchi; /* rw High bits of transfer count 0x38 */
#define esp_uid esp_tchi /* ro Unique ID code 0x38 */
#define fas_rlo esp_tchi /* rw HME extended counter 0x38 */
- unchar fgpad[3];
+ EREGS_PAD(fgpad);
volatile unchar esp_fgrnd; /* rw Data base for fifo 0x3c */
#define fas_rhi esp_fgrnd /* rw HME extended counter 0x3c */
};
fas100a = 0x04,
fast = 0x05,
fashme = 0x06,
- espunknown = 0x07
+ fas216 = 0x07,
+ espunknown = 0x08
};
/* We get one of these for each ESP probed. */
void (*dma_led_on)(struct NCR_ESP *);
void (*dma_poll)(struct NCR_ESP *, unsigned char *);
void (*dma_reset)(struct NCR_ESP *);
+
+ /* Optional virtual DMA functions */
+ void (*dma_mmu_get_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_mmu_get_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_mmu_release_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_mmu_release_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+ void (*dma_advance_sg)(Scsi_Cmnd *);
};
/* Bitfield meanings for the above registers. */
esp->eregs = eregs;
/* Set the command buffer */
+ esp->esp_command = (volatile unsigned char*) cmd_buffer;
esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout);
-#define SCSI_BLZ1230 { \
-/* struct SHT *next */ NULL, \
-/* long *usage_count */ NULL, \
-/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \
-/* const char *name */ "Blizzard1230 SCSI IV", \
-/* int detect(struct SHT *) */ blz1230_esp_detect, \
-/* int release(struct Scsi_Host *) */ NULL, \
-/* const char *info(struct Scsi_Host *) */ esp_info, \
-/* int command(Scsi_Cmnd *) */ esp_command, \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \
-/* int abort(Scsi_Cmnd *) */ esp_abort, \
-/* int reset(Scsi_Cmnd *) */ esp_reset, \
-/* int slave_attach(int, int) */ NULL, \
-/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \
-/* int can_queue */ 7, \
-/* int this_id */ 7, \
-/* short unsigned int sg_tablesize */ SG_ALL, \
-/* short cmd_per_lun */ 1, \
-/* unsigned char present */ 0, \
-/* unsigned unchecked_isa_dma:1 */ 0, \
-/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, }
+#define SCSI_BLZ1230 { proc_dir: &proc_scsi_esp, \
+ name: "Blizzard1230 SCSI IV", \
+ detect: blz1230_esp_detect, \
+ release: NULL, \
+ queuecommand: esp_queue, \
+ abort: esp_abort, \
+ reset: esp_reset, \
+ can_queue: 7, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif /* BLZ1230_H */
esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
/* Set the command buffer */
+ esp->esp_command = (volatile unsigned char*) cmd_buffer;
esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout);
-#define SCSI_BLZ2060 { \
-/* struct SHT *next */ NULL, \
-/* long *usage_count */ NULL, \
-/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \
-/* const char *name */ "Blizzard2060 SCSI", \
-/* int detect(struct SHT *) */ blz2060_esp_detect, \
-/* int release(struct Scsi_Host *) */ NULL, \
-/* const char *info(struct Scsi_Host *) */ esp_info, \
-/* int command(Scsi_Cmnd *) */ esp_command, \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \
-/* int abort(Scsi_Cmnd *) */ esp_abort, \
-/* int reset(Scsi_Cmnd *) */ esp_reset, \
-/* int slave_attach(int, int) */ NULL, \
-/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \
-/* int can_queue */ 7, \
-/* int this_id */ 7, \
-/* short unsigned int sg_tablesize */ SG_ALL, \
-/* short cmd_per_lun */ 1, \
-/* unsigned char present */ 0, \
-/* unsigned unchecked_isa_dma:1 */ 0, \
-/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, }
+#define SCSI_BLZ2060 { proc_dir: &proc_scsi_esp, \
+ name: "Blizzard2060 SCSI", \
+ detect: blz2060_esp_detect, \
+ release: NULL, \
+ queuecommand: esp_queue, \
+ abort: esp_abort, \
+ reset: esp_reset, \
+ can_queue: 7, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif /* BLZ2060_H */
esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
/* Set the command buffer */
+ esp->esp_command = (volatile unsigned char*) cmd_buffer;
esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
int hostno, int inout);
-#define SCSI_CYBERSTORM { \
-/* struct SHT *next */ NULL, \
-/* long *usage_count */ NULL, \
-/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \
-/* const char *name */ "CyberStorm SCSI", \
-/* int detect(struct SHT *) */ cyber_esp_detect, \
-/* int release(struct Scsi_Host *) */ NULL, \
-/* const char *info(struct Scsi_Host *) */ esp_info, \
-/* int command(Scsi_Cmnd *) */ esp_command, \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \
-/* int abort(Scsi_Cmnd *) */ esp_abort, \
-/* int reset(Scsi_Cmnd *) */ esp_reset, \
-/* int slave_attach(int, int) */ NULL, \
-/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \
-/* int can_queue */ 7, \
-/* int this_id */ 7, \
-/* short unsigned int sg_tablesize */ SG_ALL, \
-/* short cmd_per_lun */ 1, \
-/* unsigned char present */ 0, \
-/* unsigned unchecked_isa_dma:1 */ 0, \
-/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, }
+#define SCSI_CYBERSTORM { proc_dir: &proc_scsi_esp, \
+ name: "CyberStorm SCSI", \
+ detect: cyber_esp_detect, \
+ release: NULL, \
+ queuecommand: esp_queue, \
+ abort: esp_abort, \
+ reset: esp_reset, \
+ can_queue: 7, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif /* CYBER_ESP_H */
esp->eregs = eregs;
/* Set the command buffer */
+ esp->esp_command = (volatile unsigned char*) cmd_buffer;
esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout);
-#define SCSI_CYBERSTORMII { \
-/* struct SHT *next */ NULL, \
-/* long *usage_count */ NULL, \
-/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \
-/* const char *name */ "CyberStorm Mk II SCSI", \
-/* int detect(struct SHT *) */ cyberII_esp_detect, \
-/* int release(struct Scsi_Host *) */ NULL, \
-/* const char *info(struct Scsi_Host *) */ esp_info, \
-/* int command(Scsi_Cmnd *) */ esp_command, \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \
-/* int abort(Scsi_Cmnd *) */ esp_abort, \
-/* int reset(Scsi_Cmnd *) */ esp_reset, \
-/* int slave_attach(int, int) */ NULL, \
-/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \
-/* int can_queue */ 7, \
-/* int this_id */ 7, \
-/* short unsigned int sg_tablesize */ SG_ALL, \
-/* short cmd_per_lun */ 1, \
-/* unsigned char present */ 0, \
-/* unsigned unchecked_isa_dma:1 */ 0, \
-/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, }
+#define SCSI_CYBERSTORMII { proc_dir: &proc_scsi_esp, \
+ name: "CyberStorm Mk II SCSI", \
+ detect: cyberII_esp_detect, \
+ release: NULL, \
+ queuecommand: esp_queue, \
+ abort: esp_abort, \
+ reset: esp_reset, \
+ can_queue: 7, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif /* CYBERII_ESP_H */
* This driver is based on the CyberStorm driver, hence the occasional
* reference to CyberStorm.
*
- * Betatesting & crucial adjustments by Patrik Rak
- * (prak3264@ss1000.ms.mff.cuni.cz)
+ * Betatesting & crucial adjustments by
+ * Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
*
*/
#include <asm/pgtable.h>
+/* Such day has just come... */
+#if 0
/* Let this defined unless you really need to enable DMA IRQ one day */
#define NODMAIRQ
+#endif
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
static void dma_ints_off(struct NCR_ESP *esp);
static void dma_ints_on(struct NCR_ESP *esp);
static int dma_irq_p(struct NCR_ESP *esp);
+static void dma_irq_exit(struct NCR_ESP *esp);
static void dma_led_off(struct NCR_ESP *esp);
static void dma_led_on(struct NCR_ESP *esp);
static int dma_ports_p(struct NCR_ESP *esp);
esp->dma_drain = 0;
esp->dma_invalidate = 0;
esp->dma_irq_entry = 0;
- esp->dma_irq_exit = 0;
+ esp->dma_irq_exit = &dma_irq_exit;
esp->dma_led_on = &dma_led_on;
esp->dma_led_off = &dma_led_off;
esp->dma_poll = 0;
esp->edev = (void *) address;
/* Set the command buffer */
+ esp->esp_command = (volatile unsigned char*) cmd_buffer;
esp->esp_command_dvma = VTOP((unsigned long) cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
enable_irq(esp->irq);
}
+static void dma_irq_exit(struct NCR_ESP *esp)
+{
+ struct fastlane_dma_registers *dregs =
+ (struct fastlane_dma_registers *) (esp->dregs);
+
+ dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
+ nop();
+ dregs->ctrl_reg = ctrl_data;
+}
+
static int dma_irq_p(struct NCR_ESP *esp)
{
struct fastlane_dma_registers *dregs =
(struct fastlane_dma_registers *) (esp->dregs);
-#if 0
unsigned char dma_status;
- int r = 0;
dma_status = dregs->cond_reg;
if(dma_status & FASTLANE_DMA_IACT)
return 0; /* not our IRQ */
- /* Return 1 if ESP requested IRQ */
- if(
+ /* Return non-zero if ESP requested IRQ */
+ return (
#ifndef NODMAIRQ
(dma_status & FASTLANE_DMA_CREQ) &&
#endif
(!(dma_status & FASTLANE_DMA_MINT)) &&
- ((((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR))
- r = 1;
-
- dregs->ctrl_reg = (ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI) );
- dregs->ctrl_reg = ctrl_data;
-
- return r;
-#else
- int r;
- r = (((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR;
- dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
- dregs->ctrl_reg = ctrl_data;
- return r;
-#endif
+ ((((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR));
}
static void dma_led_off(struct NCR_ESP *esp)
extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout);
-#define SCSI_FASTLANE { \
-/* struct SHT *next */ NULL, \
-/* long *usage_count */ NULL, \
-/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \
-/* const char *name */ "Fastlane SCSI", \
-/* int detect(struct SHT *) */ fastlane_esp_detect, \
-/* int release(struct Scsi_Host *) */ NULL, \
-/* const char *info(struct Scsi_Host *) */ esp_info, \
-/* int command(Scsi_Cmnd *) */ esp_command, \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \
-/* int abort(Scsi_Cmnd *) */ esp_abort, \
-/* int reset(Scsi_Cmnd *) */ esp_reset, \
-/* int slave_attach(int, int) */ NULL, \
-/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \
-/* int can_queue */ 7, \
-/* int this_id */ 7, \
-/* short unsigned int sg_tablesize */ SG_ALL, \
-/* short cmd_per_lun */ 1, \
-/* unsigned char present */ 0, \
-/* unsigned unchecked_isa_dma:1 */ 0, \
-/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, }
+#define SCSI_FASTLANE { proc_dir: &proc_scsi_esp, \
+ name: "Fastlane SCSI", \
+ detect: fastlane_esp_detect, \
+ release: NULL, \
+ queuecommand: esp_queue, \
+ abort: esp_abort, \
+ reset: esp_reset, \
+ can_queue: 7, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif /* FASTLANE_H */
#include "scsi_debug.h"
#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_3
+#include "../acorn/scsi/acornscsi.h"
+#endif
+
+#ifdef CONFIG_SCSI_CUMANA_1
+#include "../acorn/scsi/cumana_1.h"
+#endif
+
+#ifdef CONFIG_SCSI_CUMANA_2
+#include "../acorn/scsi/cumana_2.h"
+#endif
+
+#ifdef CONFIG_SCSI_ECOSCSI
+#include "../acorn/scsi/ecoscsi.h"
+#endif
+
+#ifdef CONFIG_SCSI_OAK1
+#include "../acorn/scsi/oak.h"
+#endif
+
+#ifdef CONFIG_SCSI_POWERTECSCSI
+#include "../acorn/scsi/powertec.h"
+#endif
/*
static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $";
#ifdef CONFIG_SCSI_PLUTO
PLUTO,
#endif
+#ifdef CONFIG_ARCH_ACORN
+#ifdef CONFIG_SCSI_ACORNSCSI_3
+ ACORNSCSI_3,
+#endif
+#ifdef CONFIG_SCSI_CUMANA_1
+ CUMANA_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_CUMANA_2
+ CUMANA_FAS216,
+#endif
+#ifdef CONFIG_SCSI_ECOSCSI
+ ECOSCSI_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_OAK1
+ OAK_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_POWERTECSCSI
+ POWERTECSCSI,
+#endif
+#endif
#ifdef CONFIG_SCSI_DEBUG
SCSI_DEBUG,
#endif
static int scsi_reset (Scsi_Cmnd *, unsigned int);
extern void scsi_old_done (Scsi_Cmnd *SCpnt);
-static int update_timeout (Scsi_Cmnd *, int);
+int update_timeout (Scsi_Cmnd *, int);
extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
extern void internal_cmnd (Scsi_Cmnd * SCpnt);
* set the timer, we want to take this value into account.
*/
-static int update_timeout(Scsi_Cmnd * SCset, int timeout)
+int update_timeout(Scsi_Cmnd * SCset, int timeout)
{
int rtn;
if (!buf || !cmdList) /* bad input ? */
return(NULL);
- if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), 1)) == 0)
+ if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0)
return(NULL); /* out of memory */
- if ((handle->cmdPos = (char**) kmalloc(sizeof(int), cmdNum)) == 0) {
+ if ((handle->cmdPos = (char**) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) {
kfree(handle);
return(NULL); /* out of memory */
}
printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
if (retries++ < 10) {
/* sleep 2 sec and try again */
+ /*
+ * The spinlock is silly - we should really lock more of this
+ * function, but the minimal locking required to not lock up
+ * is around this - scsi_sleep() assumes we hold the spinlock.
+ */
+ spin_lock_irqsave(&io_request_lock, flags);
scsi_sleep(2*HZ);
+ spin_unlock_irqrestore(&io_request_lock, flags);
goto retry;
} else {
/* 20 secs are enouth? */
string ' Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE
fi
fi
+
+ if [ "$CONFIG_SOUND" = "m" ]; then
+ dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
+ if [ "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
+ string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE
+ string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE
+ fi
+ dep_tristate 'Support for Turtle Beach MultiSound Pinnacle, Fiji' CONFIG_SOUND_MSNDPIN $CONFIG_SOUND
+ if [ "$CONFIG_SOUND_MSNDPIN" = "m" ]; then
+ string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE
+ string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE
+ fi
+ fi
dep_tristate 'Support for Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
if [ "$CONFIG_SOUND_SGALAXY" = "y" ]; then
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \
- opl3.o sb_card.o sequencer_syms.o sound_core.o \
- sound_firmware.o sound_syms.o uart401.o
+ msnd.o opl3.o sb_card.o sequencer_syms.o \
+ sound_core.o sound_firmware.o sound_syms.o \
+ uart401.o
obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o
obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o
obj-$(CONFIG_SOUND_MPU401) += mpu401.o
+obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
+obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o uart401.o
/*
OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k
+Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
(c) 1995 by Michael Schlueter & Michael Marte
#include <linux/mm.h>
#include <linux/malloc.h>
+#ifdef __mc68000__
#include <asm/setup.h>
+#endif
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#endif /* CONFIG_PMAC_PBOOK */
+#include "awacs_defs.h"
+#include <linux/nvram.h>
+#include <linux/vt_kern.h>
+#endif /* CONFIG_PMAC */
#include "dmasound.h"
#include <linux/soundcard.h>
+#define HAS_8BIT_TABLES
#ifdef MODULE
static int chrdev_registered = 0;
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+/*
+ * Interrupt numbers and addresses, obtained from the device tree.
+ */
+static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
+static volatile struct awacs_regs *awacs;
+static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
+static int awacs_rate_index;
+
+/*
+ * Space for the DBDMA command blocks.
+ */
+static void *awacs_tx_cmd_space;
+static volatile struct dbdma_cmd *awacs_tx_cmds;
+
+/*
+ * Cached values of AWACS registers (we can't read them).
+ */
+int awacs_reg[5];
+
+#define HAS_16BIT_TABLES
+#undef HAS_8BIT_TABLES
+
+/*
+ * Stuff for outputting a beep. The values range from -327 to +327
+ * so we can multiply by an amplitude in the range 0..100 to get a
+ * signed short value to put in the output buffer.
+ */
+static short beep_wform[256] = {
+ 0, 40, 79, 117, 153, 187, 218, 245,
+ 269, 288, 304, 316, 323, 327, 327, 324,
+ 318, 310, 299, 288, 275, 262, 249, 236,
+ 224, 213, 204, 196, 190, 186, 183, 182,
+ 182, 183, 186, 189, 192, 196, 200, 203,
+ 206, 208, 209, 209, 209, 207, 204, 201,
+ 197, 193, 188, 183, 179, 174, 170, 166,
+ 163, 161, 160, 159, 159, 160, 161, 162,
+ 164, 166, 168, 169, 171, 171, 171, 170,
+ 169, 167, 163, 159, 155, 150, 144, 139,
+ 133, 128, 122, 117, 113, 110, 107, 105,
+ 103, 103, 103, 103, 104, 104, 105, 105,
+ 105, 103, 101, 97, 92, 86, 78, 68,
+ 58, 45, 32, 18, 3, -11, -26, -41,
+ -55, -68, -79, -88, -95, -100, -102, -102,
+ -99, -93, -85, -75, -62, -48, -33, -16,
+ 0, 16, 33, 48, 62, 75, 85, 93,
+ 99, 102, 102, 100, 95, 88, 79, 68,
+ 55, 41, 26, 11, -3, -18, -32, -45,
+ -58, -68, -78, -86, -92, -97, -101, -103,
+ -105, -105, -105, -104, -104, -103, -103, -103,
+ -103, -105, -107, -110, -113, -117, -122, -128,
+ -133, -139, -144, -150, -155, -159, -163, -167,
+ -169, -170, -171, -171, -171, -169, -168, -166,
+ -164, -162, -161, -160, -159, -159, -160, -161,
+ -163, -166, -170, -174, -179, -183, -188, -193,
+ -197, -201, -204, -207, -209, -209, -209, -208,
+ -206, -203, -200, -196, -192, -189, -186, -183,
+ -182, -182, -183, -186, -190, -196, -204, -213,
+ -224, -236, -249, -262, -275, -288, -299, -310,
+ -318, -324, -327, -327, -323, -316, -304, -288,
+ -269, -245, -218, -187, -153, -117, -79, -40,
+};
+
+#define BEEP_SPEED 2 /* 22050 Hz sample rate */
+#define BEEP_BUFLEN 512
+#define BEEP_VOLUME 15 /* 0 - 100 */
+
+static int beep_volume = BEEP_VOLUME;
+static int beep_playing = 0;
+static short *beep_buf;
+static volatile struct dbdma_cmd *beep_dbdma_cmd;
+static void (*orig_mksound)(unsigned int, unsigned int);
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Stuff for restoring after a sleep.
+ */
+static int awacs_sleep_notify(struct notifier_block *, unsigned long, void *);
+struct notifier_block awacs_sleep_notifier = {
+ awacs_sleep_notify
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+#endif /* CONFIG_PMAC */
/*** Some declarations *******************************************************/
#define DMASND_TT 1
#define DMASND_FALCON 2
#define DMASND_AMIGA 3
+#define DMASND_AWACS 4
#define MAX_CATCH_RADIUS 10
#define MIN_BUFFERS 4
#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
#define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
- if (error) return error; \
- } while (0)
+ do { int error = get_user(ret, (int *)(arg)); \
+ if (error) return error; \
+ } while (0)
#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
/*** Some low level helpers **************************************************/
-
+#ifdef HAS_8BIT_TABLES
/* 8 bit mu-law */
static char ulaw2dma8[] = {
- -126, -122, -118, -114, -110, -106, -102, -98,
- -94, -90, -86, -82, -78, -74, -70, -66,
- -63, -61, -59, -57, -55, -53, -51, -49,
- -47, -45, -43, -41, -39, -37, -35, -33,
- -31, -30, -29, -28, -27, -26, -25, -24,
- -23, -22, -21, -20, -19, -18, -17, -16,
- -16, -15, -15, -14, -14, -13, -13, -12,
- -12, -11, -11, -10, -10, -9, -9, -8,
- -8, -8, -7, -7, -7, -7, -6, -6,
- -6, -6, -5, -5, -5, -5, -4, -4,
- -4, -4, -4, -4, -3, -3, -3, -3,
- -3, -3, -3, -3, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 0,
- 125, 121, 117, 113, 109, 105, 101, 97,
- 93, 89, 85, 81, 77, 73, 69, 65,
- 62, 60, 58, 56, 54, 52, 50, 48,
- 46, 44, 42, 40, 38, 36, 34, 32,
- 30, 29, 28, 27, 26, 25, 24, 23,
- 22, 21, 20, 19, 18, 17, 16, 15,
- 15, 14, 14, 13, 13, 12, 12, 11,
- 11, 10, 10, 9, 9, 8, 8, 7,
- 7, 7, 6, 6, 6, 6, 5, 5,
- 5, 5, 4, 4, 4, 4, 3, 3,
- 3, 3, 3, 3, 2, 2, 2, 2,
- 2, 2, 2, 2, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
+ -126, -122, -118, -114, -110, -106, -102, -98,
+ -94, -90, -86, -82, -78, -74, -70, -66,
+ -63, -61, -59, -57, -55, -53, -51, -49,
+ -47, -45, -43, -41, -39, -37, -35, -33,
+ -31, -30, -29, -28, -27, -26, -25, -24,
+ -23, -22, -21, -20, -19, -18, -17, -16,
+ -16, -15, -15, -14, -14, -13, -13, -12,
+ -12, -11, -11, -10, -10, -9, -9, -8,
+ -8, -8, -7, -7, -7, -7, -6, -6,
+ -6, -6, -5, -5, -5, -5, -4, -4,
+ -4, -4, -4, -4, -3, -3, -3, -3,
+ -3, -3, -3, -3, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 0,
+ 125, 121, 117, 113, 109, 105, 101, 97,
+ 93, 89, 85, 81, 77, 73, 69, 65,
+ 62, 60, 58, 56, 54, 52, 50, 48,
+ 46, 44, 42, 40, 38, 36, 34, 32,
+ 30, 29, 28, 27, 26, 25, 24, 23,
+ 22, 21, 20, 19, 18, 17, 16, 15,
+ 15, 14, 14, 13, 13, 12, 12, 11,
+ 11, 10, 10, 9, 9, 8, 8, 7,
+ 7, 7, 6, 6, 6, 6, 5, 5,
+ 5, 5, 4, 4, 4, 4, 3, 3,
+ 3, 3, 3, 3, 2, 2, 2, 2,
+ 2, 2, 2, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
};
/* 8 bit A-law */
static char alaw2dma8[] = {
- -22, -21, -24, -23, -18, -17, -20, -19,
- -30, -29, -32, -31, -26, -25, -28, -27,
- -11, -11, -12, -12, -9, -9, -10, -10,
- -15, -15, -16, -16, -13, -13, -14, -14,
- -86, -82, -94, -90, -70, -66, -78, -74,
- -118, -114, -126, -122, -102, -98, -110, -106,
- -43, -41, -47, -45, -35, -33, -39, -37,
- -59, -57, -63, -61, -51, -49, -55, -53,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -6, -6, -6, -6, -5, -5, -5, -5,
- -8, -8, -8, -8, -7, -7, -7, -7,
- -3, -3, -3, -3, -3, -3, -3, -3,
- -4, -4, -4, -4, -4, -4, -4, -4,
- 21, 20, 23, 22, 17, 16, 19, 18,
- 29, 28, 31, 30, 25, 24, 27, 26,
- 10, 10, 11, 11, 8, 8, 9, 9,
- 14, 14, 15, 15, 12, 12, 13, 13,
- 86, 82, 94, 90, 70, 66, 78, 74,
- 118, 114, 126, 122, 102, 98, 110, 106,
- 43, 41, 47, 45, 35, 33, 39, 37,
- 59, 57, 63, 61, 51, 49, 55, 53,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 5, 5, 5, 5, 4, 4, 4, 4,
- 7, 7, 7, 7, 6, 6, 6, 6,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3
+ -22, -21, -24, -23, -18, -17, -20, -19,
+ -30, -29, -32, -31, -26, -25, -28, -27,
+ -11, -11, -12, -12, -9, -9, -10, -10,
+ -15, -15, -16, -16, -13, -13, -14, -14,
+ -86, -82, -94, -90, -70, -66, -78, -74,
+ -118, -114, -126, -122, -102, -98, -110, -106,
+ -43, -41, -47, -45, -35, -33, -39, -37,
+ -59, -57, -63, -61, -51, -49, -55, -53,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -6, -6, -6, -6, -5, -5, -5, -5,
+ -8, -8, -8, -8, -7, -7, -7, -7,
+ -3, -3, -3, -3, -3, -3, -3, -3,
+ -4, -4, -4, -4, -4, -4, -4, -4,
+ 21, 20, 23, 22, 17, 16, 19, 18,
+ 29, 28, 31, 30, 25, 24, 27, 26,
+ 10, 10, 11, 11, 8, 8, 9, 9,
+ 14, 14, 15, 15, 12, 12, 13, 13,
+ 86, 82, 94, 90, 70, 66, 78, 74,
+ 118, 114, 126, 122, 102, 98, 110, 106,
+ 43, 41, 47, 45, 35, 33, 39, 37,
+ 59, 57, 63, 61, 51, 49, 55, 53,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 4, 4, 4, 4,
+ 7, 7, 7, 7, 6, 6, 6, 6,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3
};
-
+#endif /* HAS_8BIT_TABLES */
#ifdef HAS_16BIT_TABLES
/* 16 bit mu-law */
-static char ulaw2dma16[] = {
- -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
- -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
- -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
- -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
- -876, -844, -812, -780, -748, -716, -684, -652,
- -620, -588, -556, -524, -492, -460, -428, -396,
- -372, -356, -340, -324, -308, -292, -276, -260,
- -244, -228, -212, -196, -180, -164, -148, -132,
- -120, -112, -104, -96, -88, -80, -72, -64,
- -56, -48, -40, -32, -24, -16, -8, 0,
- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
- 876, 844, 812, 780, 748, 716, 684, 652,
- 620, 588, 556, 524, 492, 460, 428, 396,
- 372, 356, 340, 324, 308, 292, 276, 260,
- 244, 228, 212, 196, 180, 164, 148, 132,
- 120, 112, 104, 96, 88, 80, 72, 64,
- 56, 48, 40, 32, 24, 16, 8, 0,
+static short ulaw2dma16[] = {
+ -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
+ -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
+ -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
+ -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
+ -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+ -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+ -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+ -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+ -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+ -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
+ -876, -844, -812, -780, -748, -716, -684, -652,
+ -620, -588, -556, -524, -492, -460, -428, -396,
+ -372, -356, -340, -324, -308, -292, -276, -260,
+ -244, -228, -212, -196, -180, -164, -148, -132,
+ -120, -112, -104, -96, -88, -80, -72, -64,
+ -56, -48, -40, -32, -24, -16, -8, 0,
+ 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+ 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+ 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+ 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
+ 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
+ 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
+ 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
+ 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
+ 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
+ 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
+ 876, 844, 812, 780, 748, 716, 684, 652,
+ 620, 588, 556, 524, 492, 460, 428, 396,
+ 372, 356, 340, 324, 308, 292, 276, 260,
+ 244, 228, 212, 196, 180, 164, 148, 132,
+ 120, 112, 104, 96, 88, 80, 72, 64,
+ 56, 48, 40, 32, 24, 16, 8, 0,
};
/* 16 bit A-law */
-static char alaw2dma16[] = {
- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
- -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
- -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
- -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
- -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
- -344, -328, -376, -360, -280, -264, -312, -296,
- -472, -456, -504, -488, -408, -392, -440, -424,
- -88, -72, -120, -104, -24, -8, -56, -40,
- -216, -200, -248, -232, -152, -136, -184, -168,
- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
- -688, -656, -752, -720, -560, -528, -624, -592,
- -944, -912, -1008, -976, -816, -784, -880, -848,
- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
- 344, 328, 376, 360, 280, 264, 312, 296,
- 472, 456, 504, 488, 408, 392, 440, 424,
- 88, 72, 120, 104, 24, 8, 56, 40,
- 216, 200, 248, 232, 152, 136, 184, 168,
- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
- 688, 656, 752, 720, 560, 528, 624, 592,
- 944, 912, 1008, 976, 816, 784, 880, 848,
+static short alaw2dma16[] = {
+ -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
+ -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+ -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
+ -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
+ -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+ -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+ -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
+ -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+ -344, -328, -376, -360, -280, -264, -312, -296,
+ -472, -456, -504, -488, -408, -392, -440, -424,
+ -88, -72, -120, -104, -24, -8, -56, -40,
+ -216, -200, -248, -232, -152, -136, -184, -168,
+ -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+ -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
+ -688, -656, -752, -720, -560, -528, -624, -592,
+ -944, -912, -1008, -976, -816, -784, -880, -848,
+ 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
+ 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
+ 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
+ 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
+ 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+ 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+ 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
+ 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+ 344, 328, 376, 360, 280, 264, 312, 296,
+ 472, 456, 504, 488, 408, 392, 440, 424,
+ 88, 72, 120, 104, 24, 8, 56, 40,
+ 216, 200, 248, 232, 152, 136, 184, 168,
+ 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
+ 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
+ 688, 656, 752, 720, 560, 528, 624, 592,
+ 944, 912, 1008, 976, 816, 784, 880, 848,
};
#endif /* HAS_16BIT_TABLES */
/* 14 bit mu-law (LSB) */
static char alaw2dma14l[] = {
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 49, 17, 49, 17, 49, 17, 49, 17,
- 49, 17, 49, 17, 49, 17, 49, 17,
- 41, 57, 9, 25, 41, 57, 9, 25,
- 41, 57, 9, 25, 41, 57, 9, 25,
- 37, 45, 53, 61, 5, 13, 21, 29,
- 37, 45, 53, 61, 5, 13, 21, 29,
- 35, 39, 43, 47, 51, 55, 59, 63,
- 3, 7, 11, 15, 19, 23, 27, 31,
- 34, 36, 38, 40, 42, 44, 46, 48,
- 50, 52, 54, 56, 58, 60, 62, 0,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 15, 47, 15, 47, 15, 47, 15, 47,
- 15, 47, 15, 47, 15, 47, 15, 47,
- 23, 7, 55, 39, 23, 7, 55, 39,
- 23, 7, 55, 39, 23, 7, 55, 39,
- 27, 19, 11, 3, 59, 51, 43, 35,
- 27, 19, 11, 3, 59, 51, 43, 35,
- 29, 25, 21, 17, 13, 9, 5, 1,
- 61, 57, 53, 49, 45, 41, 37, 33,
- 30, 28, 26, 24, 22, 20, 18, 16,
- 14, 12, 10, 8, 6, 4, 2, 0
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 49, 17, 49, 17, 49, 17, 49, 17,
+ 49, 17, 49, 17, 49, 17, 49, 17,
+ 41, 57, 9, 25, 41, 57, 9, 25,
+ 41, 57, 9, 25, 41, 57, 9, 25,
+ 37, 45, 53, 61, 5, 13, 21, 29,
+ 37, 45, 53, 61, 5, 13, 21, 29,
+ 35, 39, 43, 47, 51, 55, 59, 63,
+ 3, 7, 11, 15, 19, 23, 27, 31,
+ 34, 36, 38, 40, 42, 44, 46, 48,
+ 50, 52, 54, 56, 58, 60, 62, 0,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 15, 47, 15, 47, 15, 47, 15, 47,
+ 15, 47, 15, 47, 15, 47, 15, 47,
+ 23, 7, 55, 39, 23, 7, 55, 39,
+ 23, 7, 55, 39, 23, 7, 55, 39,
+ 27, 19, 11, 3, 59, 51, 43, 35,
+ 27, 19, 11, 3, 59, 51, 43, 35,
+ 29, 25, 21, 17, 13, 9, 5, 1,
+ 61, 57, 53, 49, 45, 41, 37, 33,
+ 30, 28, 26, 24, 22, 20, 18, 16,
+ 14, 12, 10, 8, 6, 4, 2, 0
};
/* 14 bit A-law (LSB) */
static char alaw2dma14l[] = {
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 16, 48, 16, 48, 16, 48, 16, 48,
- 16, 48, 16, 48, 16, 48, 16, 48,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 42, 46, 34, 38, 58, 62, 50, 54,
- 10, 14, 2, 6, 26, 30, 18, 22,
- 42, 46, 34, 38, 58, 62, 50, 54,
- 10, 14, 2, 6, 26, 30, 18, 22,
- 40, 56, 8, 24, 40, 56, 8, 24,
- 40, 56, 8, 24, 40, 56, 8, 24,
- 20, 28, 4, 12, 52, 60, 36, 44,
- 20, 28, 4, 12, 52, 60, 36, 44,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 48, 16, 48, 16, 48, 16, 48, 16,
- 48, 16, 48, 16, 48, 16, 48, 16,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 22, 18, 30, 26, 6, 2, 14, 10,
- 54, 50, 62, 58, 38, 34, 46, 42,
- 22, 18, 30, 26, 6, 2, 14, 10,
- 54, 50, 62, 58, 38, 34, 46, 42,
- 24, 8, 56, 40, 24, 8, 56, 40,
- 24, 8, 56, 40, 24, 8, 56, 40,
- 44, 36, 60, 52, 12, 4, 28, 20,
- 44, 36, 60, 52, 12, 4, 28, 20
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 16, 48, 16, 48, 16, 48, 16, 48,
+ 16, 48, 16, 48, 16, 48, 16, 48,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 42, 46, 34, 38, 58, 62, 50, 54,
+ 10, 14, 2, 6, 26, 30, 18, 22,
+ 42, 46, 34, 38, 58, 62, 50, 54,
+ 10, 14, 2, 6, 26, 30, 18, 22,
+ 40, 56, 8, 24, 40, 56, 8, 24,
+ 40, 56, 8, 24, 40, 56, 8, 24,
+ 20, 28, 4, 12, 52, 60, 36, 44,
+ 20, 28, 4, 12, 52, 60, 36, 44,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 48, 16, 48, 16, 48, 16, 48, 16,
+ 48, 16, 48, 16, 48, 16, 48, 16,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 22, 18, 30, 26, 6, 2, 14, 10,
+ 54, 50, 62, 58, 38, 34, 46, 42,
+ 22, 18, 30, 26, 6, 2, 14, 10,
+ 54, 50, 62, 58, 38, 34, 46, 42,
+ 24, 8, 56, 40, 24, 8, 56, 40,
+ 24, 8, 56, 40, 24, 8, 56, 40,
+ 44, 36, 60, 52, 12, 4, 28, 20,
+ 44, 36, 60, 52, 12, 4, 28, 20
};
#endif /* HAS_14BIT_TABLES */
u_char frame[], long *frameUsed, long frameLeft);
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+static long pmac_ct_law(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_s8(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_u8(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_s16(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ct_u16(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_law(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_s8(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_u8(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_s16(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+static long pmac_ctx_u16(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft);
+#endif /* CONFIG_PMAC */
/*** Machine definitions *****************************************************/
typedef struct {
- int type;
- void *(*dma_alloc)(unsigned int, int);
- void (*dma_free)(void *, unsigned int);
- int (*irqinit)(void);
+ int type;
+ void *(*dma_alloc)(unsigned int, int);
+ void (*dma_free)(void *, unsigned int);
+ int (*irqinit)(void);
#ifdef MODULE
- void (*irqcleanup)(void);
+ void (*irqcleanup)(void);
#endif /* MODULE */
- void (*init)(void);
- void (*silence)(void);
- int (*setFormat)(int);
- int (*setVolume)(int);
- int (*setBass)(int);
- int (*setTreble)(int);
- int (*setGain)(int);
- void (*play)(void);
+ void (*init)(void);
+ void (*silence)(void);
+ int (*setFormat)(int);
+ int (*setVolume)(int);
+ int (*setBass)(int);
+ int (*setTreble)(int);
+ int (*setGain)(int);
+ void (*play)(void);
} MACHINE;
typedef struct {
- int format; /* AFMT_* */
- int stereo; /* 0 = mono, 1 = stereo */
- int size; /* 8/16 bit*/
- int speed; /* speed */
+ int format; /* AFMT_* */
+ int stereo; /* 0 = mono, 1 = stereo */
+ int size; /* 8/16 bit*/
+ int speed; /* speed */
} SETTINGS;
typedef struct {
- long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long);
- long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long);
- long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long);
- long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long);
- long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long);
- long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long);
- long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long);
- long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long);
+ long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long);
+ long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long);
+ long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long);
+ long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long);
+ long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long);
+ long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long);
+ long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long);
+ long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long);
} TRANS;
struct sound_settings {
- MACHINE mach; /* machine dependent things */
- SETTINGS hard; /* hardware settings */
- SETTINGS soft; /* software settings */
- SETTINGS dsp; /* /dev/dsp default settings */
- TRANS *trans; /* supported translations */
- int volume_left; /* volume (range is machine dependent) */
- int volume_right;
- int bass; /* tone (range is machine dependent) */
- int treble;
- int gain;
- int minDev; /* minor device number currently open */
-#ifdef CONFIG_ATARI
- int bal; /* balance factor for expanding (not volume!) */
- u_long data; /* data for expanding */
+ MACHINE mach; /* machine dependent things */
+ SETTINGS hard; /* hardware settings */
+ SETTINGS soft; /* software settings */
+ SETTINGS dsp; /* /dev/dsp default settings */
+ TRANS *trans; /* supported translations */
+ int volume_left; /* volume (range is machine dependent) */
+ int volume_right;
+ int bass; /* tone (range is machine dependent) */
+ int treble;
+ int gain;
+ int minDev; /* minor device number currently open */
+#if defined(CONFIG_ATARI) || defined(CONFIG_PMAC)
+ int bal; /* balance factor for expanding (not volume!) */
+ u_long data; /* data for expanding */
#endif /* CONFIG_ATARI */
};
static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+static void *PMacAlloc(unsigned int size, int flags);
+static void PMacFree(void *ptr, unsigned int size);
+static int PMacIrqInit(void);
+#ifdef MODULE
+static void PMacIrqCleanup(void);
+#endif /* MODULE */
+static void PMacSilence(void);
+static void PMacInit(void);
+static void PMacPlay(void);
+static int PMacSetFormat(int format);
+static int PMacSetVolume(int volume);
+static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
+static void awacs_write(int val);
+static int awacs_get_volume(int reg, int lshift);
+static int awacs_volume_setter(int volume, int n, int mute, int lshift);
+static void awacs_mksound(unsigned int hz, unsigned int ticks);
+static void awacs_nosound(unsigned long xx);
+#endif /* CONFIG_PMAC */
/*** Mid level stuff *********************************************************/
#ifdef CONFIG_ATARI
static int sound_set_bass(int bass);
#endif /* CONFIG_ATARI */
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
static int sound_set_treble(int treble);
+#endif /* CONFIG_ATARI || CONFIG_AMIGA */
static long sound_copy_translate(const u_char *userPtr,
unsigned long userCount,
u_char frame[], long *frameUsed,
*/
struct sound_queue {
- int max_count, block_size;
- char **buffers;
-
- /* it shouldn't be necessary to declare any of these volatile */
- int front, rear, count;
- int rear_size;
- /*
- * The use of the playing field depends on the hardware
- *
- * Atari: The number of frames that are loaded/playing
- *
- * Amiga: Bit 0 is set: a frame is loaded
- * Bit 1 is set: a frame is playing
- */
- int playing;
- struct wait_queue *write_queue, *open_queue, *sync_queue;
- int open_mode;
- int busy, syncing;
+ int max_count, block_size;
+ char **buffers;
+ int max_active;
+
+ /* it shouldn't be necessary to declare any of these volatile */
+ int front, rear, count;
+ int rear_size;
+ /*
+ * The use of the playing field depends on the hardware
+ *
+ * Atari, PMac: The number of frames that are loaded/playing
+ *
+ * Amiga: Bit 0 is set: a frame is loaded
+ * Bit 1 is set: a frame is playing
+ */
+ int playing;
+ struct wait_queue *write_queue, *open_queue, *sync_queue;
+ int open_mode;
+ int busy, syncing;
#ifdef CONFIG_ATARI
- int ignore_int; /* ++TeSche: used for Falcon */
+ int ignore_int; /* ++TeSche: used for Falcon */
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
- int block_size_half, block_size_quarter;
+ int block_size_half, block_size_quarter;
#endif /* CONFIG_AMIGA */
};
static void sq_reset(void);
static int sq_sync(void);
static int sq_release(void);
+static void init_settings(void);
/*
*/
struct sound_state {
- int busy;
- char buf[512];
- int len, ptr;
+ int busy;
+ char buf[512];
+ int len, ptr;
};
static struct sound_state state;
loff_t *ppos);
static inline int ioctl_return(int *addr, int value)
{
- if (value < 0)
- return(value);
+ if (value < 0)
+ return(value);
- return put_user(value, addr);
+ return put_user(value, addr)? -EFAULT: 0;
}
static int unknown_minor_dev(char *fname, int dev);
static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
static long ata_ct_law(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- long count, used;
- u_char *p = &frame[*frameUsed];
+ char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+ long count, used;
+ u_char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft);
- if (sound.soft.stereo)
- count &= ~1;
- used = count;
- while (count > 0) {
- u_char data;
- get_user(data, userPtr++);
- *p++ = table[data];
- count--;
- }
- *frameUsed += used;
- return(used);
+ count = min(userCount, frameLeft);
+ if (sound.soft.stereo)
+ count &= ~1;
+ used = count;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *p++ = table[data];
+ count--;
+ }
+ *frameUsed += used;
+ return(used);
}
static long ata_ct_s8(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- void *p = &frame[*frameUsed];
+ long count, used;
+ void *p = &frame[*frameUsed];
- count = min(userCount, frameLeft);
- if (sound.soft.stereo)
- count &= ~1;
- used = count;
- copy_from_user(p, userPtr, count);
- *frameUsed += used;
- return(used);
+ count = min(userCount, frameLeft);
+ if (sound.soft.stereo)
+ count &= ~1;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ *frameUsed += used;
+ return(used);
}
static long ata_ct_u8(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
-
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft);
- used = count;
- while (count > 0) {
- u_char data;
- get_user(data, userPtr++);
- *p++ = data ^ 0x80;
- count--;
- }
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- get_user(data, ((u_short *)userPtr)++);
- *p++ = data ^ 0x8080;
- count--;
+ long count, used;
+
+ if (!sound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ count = min(userCount, frameLeft);
+ used = count;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *p++ = data ^ 0x80;
+ count--;
+ }
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *p++ = data ^ 0x8080;
+ count--;
+ }
}
- }
- *frameUsed += used;
- return(used);
+ *frameUsed += used;
+ return(used);
}
static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- u_long data;
-
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- void *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft) & ~3;
- used = count;
- copy_from_user(p, userPtr, count);
- *frameUsed += used;
- }
- return(used);
+ long count, used;
+ u_long data;
+
+ if (!sound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ void *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft) & ~3;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ *frameUsed += used;
+ }
+ return(used);
}
static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- u_long data;
-
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data ^= 0x8000;
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count*4;
- while (count > 0) {
- get_user(data, ((u_int *)userPtr)++);
- *p++ = data ^ 0x80008000;
- count--;
+ long count, used;
+ u_long data;
+
+ if (!sound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count*4;
+ while (count > 0) {
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ *p++ = data ^ 0x80008000;
+ count--;
+ }
+ *frameUsed += used;
}
- *frameUsed += used;
- }
- return(used);
+ return(used);
}
static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- u_long data;
-
- count = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data);
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count*4;
- while (count > 0) {
- get_user(data, ((u_int *)userPtr)++);
- data = le2be16dbl(data);
- *p++ = data;
- count--;
+ long count, used;
+ u_long data;
+
+ count = frameLeft;
+ if (!sound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count*4;
+ while (count > 0) {
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data);
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used;
}
- *frameUsed += used;
- }
- return(used);
+ return(used);
}
static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- u_long data;
-
- count = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data) ^ 0x8000;
- *p++ = data;
- *p++ = data;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count;
- while (count > 0) {
- get_user(data, ((u_int *)userPtr)++);
- data = le2be16dbl(data) ^ 0x80008000;
- *p++ = data;
- count--;
+ long count, used;
+ u_long data;
+
+ count = frameLeft;
+ if (!sound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ *p++ = data;
+ *p++ = data;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count;
+ while (count > 0) {
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data) ^ 0x80008000;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used;
}
- *frameUsed += used;
- }
- return(used);
+ return(used);
}
static long ata_ctx_law(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- /* this should help gcc to stuff everything into registers */
- u_long data = sound.data;
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- long used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (!userCount)
- break;
- get_user(c, userPtr++);
- data = table[c];
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- while (frameLeft >= 2) {
- u_char c;
- if (bal < 0) {
- if (userCount < 2)
- break;
- get_user(c, userPtr++);
- data = table[c] << 8;
- get_user(c, userPtr++);
- data |= table[c];
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- }
- sound.bal = bal;
- sound.data = data;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
+ char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+ /* this should help gcc to stuff everything into registers */
+ u_long data = sound.data;
+ long bal = sound.bal;
+ long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ long used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!sound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c];
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ while (frameLeft >= 2) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c] << 8;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data |= table[c];
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ }
+ sound.bal = bal;
+ sound.data = data;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return(used);
}
static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- /* this should help gcc to stuff everything into registers */
- u_long data = sound.data;
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- long used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- while (frameLeft) {
- if (bal < 0) {
- if (!userCount)
- break;
- get_user(data, userPtr++);
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- while (frameLeft >= 2) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- get_user(data, ((u_short *)userPtr)++);
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- }
- sound.bal = bal;
- sound.data = data;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
+ /* this should help gcc to stuff everything into registers */
+ u_long data = sound.data;
+ long bal = sound.bal;
+ long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ long used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!sound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ while (frameLeft) {
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ while (frameLeft >= 2) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ }
+ sound.bal = bal;
+ sound.data = data;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return(used);
}
static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- /* this should help gcc to stuff everything into registers */
- u_long data = sound.data;
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- long used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- while (frameLeft) {
- if (bal < 0) {
- if (!userCount)
- break;
- get_user(data, userPtr++);
- data ^= 0x80;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- while (frameLeft >= 2) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- get_user(data, ((u_short *)userPtr)++);
- data ^= 0x8080;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- }
- sound.bal = bal;
- sound.data = data;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
+ /* this should help gcc to stuff everything into registers */
+ u_long data = sound.data;
+ long bal = sound.bal;
+ long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ long used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!sound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ while (frameLeft) {
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ data ^= 0x80;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ while (frameLeft >= 2) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8080;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ }
+ sound.bal = bal;
+ sound.data = data;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return(used);
}
static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- /* this should help gcc to stuff everything into registers */
- u_long data = sound.data;
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- long used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- get_user(data, ((u_short *)userPtr)++);
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- get_user(data, ((u_int *)userPtr)++);
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- }
- sound.bal = bal;
- sound.data = data;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
+ /* this should help gcc to stuff everything into registers */
+ u_long data = sound.data;
+ long bal = sound.bal;
+ long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ long used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!sound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ }
+ sound.bal = bal;
+ sound.data = data;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return(used);
}
static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- /* this should help gcc to stuff everything into registers */
- u_long data = sound.data;
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- long used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- get_user(data, ((u_short *)userPtr)++);
- data ^= 0x8000;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- get_user(data, ((u_int *)userPtr)++);
- data ^= 0x80008000;
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- }
- sound.bal = bal;
- sound.data = data;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
+ /* this should help gcc to stuff everything into registers */
+ u_long data = sound.data;
+ long bal = sound.bal;
+ long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ long used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!sound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x80008000;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ }
+ sound.bal = bal;
+ sound.data = data;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return(used);
}
static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- /* this should help gcc to stuff everything into registers */
- u_long data = sound.data;
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- long used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data);
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- get_user(data, ((u_int *)userPtr)++);
- data = le2be16dbl(data);
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- }
- sound.bal = bal;
- sound.data = data;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
+ /* this should help gcc to stuff everything into registers */
+ u_long data = sound.data;
+ long bal = sound.bal;
+ long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ long used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!sound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data);
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ }
+ sound.bal = bal;
+ sound.data = data;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return(used);
}
static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- /* this should help gcc to stuff everything into registers */
- u_long data = sound.data;
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- long used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data) ^ 0x8000;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- get_user(data, ((u_int *)userPtr)++);
- data = le2be16dbl(data) ^ 0x80008000;
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- }
- sound.bal = bal;
- sound.data = data;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
+ /* this should help gcc to stuff everything into registers */
+ u_long data = sound.data;
+ long bal = sound.bal;
+ long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ long used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!sound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data) ^ 0x80008000;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ }
+ sound.bal = bal;
+ sound.data = data;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return(used);
}
#endif /* CONFIG_ATARI */
static long ami_ct_law(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- long count, used;
-
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- while (count > 0) {
- u_char data;
- get_user(data, userPtr++);
- *p++ = table[data];
- count--;
- }
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- u_char data;
- get_user(data, userPtr++);
- *left++ = table[data];
- get_user(data, userPtr++);
- *right++ = table[data];
- count--;
+ char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+ long count, used;
+
+ if (!sound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ count = min(userCount, frameLeft) & ~1;
+ used = count;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *p++ = table[data];
+ count--;
+ }
+ } else {
+ u_char *left = &frame[*frameUsed>>1];
+ u_char *right = left+sq.block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *left++ = table[data];
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *right++ = table[data];
+ count--;
+ }
}
- }
- *frameUsed += used;
- return(used);
+ *frameUsed += used;
+ return(used);
}
static long ami_ct_s8(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
-
- if (!sound.soft.stereo) {
- void *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- copy_from_user(p, userPtr, count);
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- get_user(*left++, userPtr++);
- get_user(*right++, userPtr++);
- count--;
+ long count, used;
+
+ if (!sound.soft.stereo) {
+ void *p = &frame[*frameUsed];
+ count = min(userCount, frameLeft) & ~1;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ } else {
+ u_char *left = &frame[*frameUsed>>1];
+ u_char *right = left+sq.block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(*left++, userPtr++)
+ || get_user(*right++, userPtr++))
+ return -EFAULT;
+ count--;
+ }
}
- }
- *frameUsed += used;
- return(used);
+ *frameUsed += used;
+ return(used);
}
static long ami_ct_u8(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
-
- if (!sound.soft.stereo) {
- char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- while (count > 0) {
- u_char data;
- get_user(data, userPtr++);
- *p++ = data ^ 0x80;
- count--;
- }
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- u_char data;
- get_user(data, userPtr++);
- *left++ = data ^ 0x80;
- get_user(data, userPtr++);
- *right++ = data ^ 0x80;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
+ long count, used;
+
+ if (!sound.soft.stereo) {
+ char *p = &frame[*frameUsed];
+ count = min(userCount, frameLeft) & ~1;
+ used = count;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *p++ = data ^ 0x80;
+ count--;
+ }
+ } else {
+ u_char *left = &frame[*frameUsed>>1];
+ u_char *right = left+sq.block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *left++ = data ^ 0x80;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *right++ = data ^ 0x80;
+ count--;
+ }
+ }
+ *frameUsed += used;
+ return(used);
}
static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- u_long data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- get_user(data, ((u_short *)userPtr)++);
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
+ long count, used;
+ u_long data;
+
+ if (!sound.soft.stereo) {
+ u_char *high = &frame[*frameUsed>>1];
+ u_char *low = high+sq.block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *high++ = data>>8;
+ *low++ = (data>>2) & 0x3f;
+ count--;
+ }
+ } else {
+ u_char *lefth = &frame[*frameUsed>>2];
+ u_char *leftl = lefth+sq.block_size_quarter;
+ u_char *righth = lefth+sq.block_size_half;
+ u_char *rightl = righth+sq.block_size_quarter;
+ count = min(userCount, frameLeft)>>2 & ~1;
+ used = count*4;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *lefth++ = data>>8;
+ *leftl++ = (data>>2) & 0x3f;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *righth++ = data>>8;
+ *rightl++ = (data>>2) & 0x3f;
+ count--;
+ }
+ }
+ *frameUsed += used;
+ return(used);
}
static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- u_long data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data ^= 0x8000;
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data ^= 0x8000;
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- get_user(data, ((u_short *)userPtr)++);
- data ^= 0x8000;
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
+ long count, used;
+ u_long data;
+
+ if (!sound.soft.stereo) {
+ u_char *high = &frame[*frameUsed>>1];
+ u_char *low = high+sq.block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ *high++ = data>>8;
+ *low++ = (data>>2) & 0x3f;
+ count--;
+ }
+ } else {
+ u_char *lefth = &frame[*frameUsed>>2];
+ u_char *leftl = lefth+sq.block_size_quarter;
+ u_char *righth = lefth+sq.block_size_half;
+ u_char *rightl = righth+sq.block_size_quarter;
+ count = min(userCount, frameLeft)>>2 & ~1;
+ used = count*4;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ *lefth++ = data>>8;
+ *leftl++ = (data>>2) & 0x3f;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ *righth++ = data>>8;
+ *rightl++ = (data>>2) & 0x3f;
+ count--;
+ }
}
- }
- *frameUsed += used;
- return(used);
+ *frameUsed += used;
+ return(used);
}
static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- u_long data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data);
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data);
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data);
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
+ long count, used;
+ u_long data;
+
+ if (!sound.soft.stereo) {
+ u_char *high = &frame[*frameUsed>>1];
+ u_char *low = high+sq.block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ *high++ = data>>8;
+ *low++ = (data>>2) & 0x3f;
+ count--;
+ }
+ } else {
+ u_char *lefth = &frame[*frameUsed>>2];
+ u_char *leftl = lefth+sq.block_size_quarter;
+ u_char *righth = lefth+sq.block_size_half;
+ u_char *rightl = righth+sq.block_size_quarter;
+ count = min(userCount, frameLeft)>>2 & ~1;
+ used = count*4;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ *lefth++ = data>>8;
+ *leftl++ = (data>>2) & 0x3f;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ *righth++ = data>>8;
+ *rightl++ = (data>>2) & 0x3f;
+ count--;
+ }
}
- }
- *frameUsed += used;
- return(used);
+ *frameUsed += used;
+ return(used);
}
static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount,
u_char frame[], long *frameUsed, long frameLeft)
{
- long count, used;
- u_long data;
+ long count, used;
+ u_long data;
+
+ if (!sound.soft.stereo) {
+ u_char *high = &frame[*frameUsed>>1];
+ u_char *low = high+sq.block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ *high++ = data>>8;
+ *low++ = (data>>2) & 0x3f;
+ count--;
+ }
+ } else {
+ u_char *lefth = &frame[*frameUsed>>2];
+ u_char *leftl = lefth+sq.block_size_quarter;
+ u_char *righth = lefth+sq.block_size_half;
+ u_char *rightl = righth+sq.block_size_quarter;
+ count = min(userCount, frameLeft)>>2 & ~1;
+ used = count*4;
+ while (count > 0) {
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ *lefth++ = data>>8;
+ *leftl++ = (data>>2) & 0x3f;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ *righth++ = data>>8;
+ *rightl++ = (data>>2) & 0x3f;
+ count--;
+ }
+ }
+ *frameUsed += used;
+ return(used);
+}
+#endif /* CONFIG_AMIGA */
+
+#ifdef CONFIG_PMAC
+static long pmac_ct_law(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
+ long count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = sound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data];
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data];
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
+
+static long pmac_ct_s8(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ long count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = sound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data) ^ 0x8000;
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data << 8;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data << 8;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static long pmac_ct_u8(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ long count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = sound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
while (count > 0) {
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data) ^ 0x8000;
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- get_user(data, ((u_short *)userPtr)++);
- data = le2be16(data) ^ 0x8000;
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = (data ^ 0x80) << 8;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = (data ^ 0x80) << 8;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static long pmac_ct_s16(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ long count, used;
+ int stereo = sound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ if (!stereo) {
+ short *up = (short *) userPtr;
+ while (count > 0) {
+ short data;
+ if (get_user(data, up++))
+ return -EFAULT;
+ *fp++ = data;
+ *fp++ = data;
+ count--;
+ }
+ } else {
+ if (copy_from_user(fp, userPtr, count * 4))
+ return -EFAULT;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+static long pmac_ct_u16(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ long count, used;
+ int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ int stereo = sound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+ short *up = (short *) userPtr;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ int data;
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ *fp++ = data;
+ if (stereo) {
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ }
+ *fp++ = data;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+
+static long pmac_ctx_law(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ unsigned short *table = (unsigned short *)
+ (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
+ unsigned int data = sound.data;
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ int bal = sound.bal;
+ int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ int utotal, ftotal;
+ int stereo = sound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c];
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + table[c];
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ sound.bal = bal;
+ sound.data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_s8(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = sound.data;
+ int bal = sound.bal;
+ int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ int stereo = sound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = c << 8;
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + (c << 8);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ sound.bal = bal;
+ sound.data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_u8(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = sound.data;
+ int bal = sound.bal;
+ int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ int stereo = sound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (c ^ 0x80) << 8;
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + ((c ^ 0x80) << 8);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ sound.bal = bal;
+ sound.data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static long pmac_ctx_s16(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = sound.data;
+ unsigned short *up = (unsigned short *) userPtr;
+ int bal = sound.bal;
+ int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ int stereo = sound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ unsigned short c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(data, up++))
+ return -EFAULT;
+ if (stereo) {
+ if (get_user(c, up++))
+ return -EFAULT;
+ data = (data << 16) + c;
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ sound.bal = bal;
+ sound.data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 4: utotal * 2;
+}
+
+
+static long pmac_ctx_u16(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = sound.data;
+ unsigned short *up = (unsigned short *) userPtr;
+ int bal = sound.bal;
+ int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ int stereo = sound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ unsigned short c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ if (stereo) {
+ if (get_user(c, up++))
+ return -EFAULT;
+ data = (data << 16) + (c ^ mask);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ sound.bal = bal;
+ sound.data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 4: utotal * 2;
}
-#endif /* CONFIG_AMIGA */
+
+#endif /* CONFIG_PMAC */
#ifdef CONFIG_ATARI
static TRANS transTTNormal = {
- ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
+ ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
};
static TRANS transTTExpanding = {
- ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
+ ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
};
static TRANS transFalconNormal = {
- ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be,
- ata_ct_s16le, ata_ct_u16le
+ ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8,
+ ata_ct_s16be, ata_ct_u16be, ata_ct_s16le, ata_ct_u16le
};
static TRANS transFalconExpanding = {
- ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be,
- ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
+ ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8,
+ ata_ctx_s16be, ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
};
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
static TRANS transAmiga = {
- ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be,
- ami_ct_s16le, ami_ct_u16le
+ ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8,
+ ami_ct_s16be, ami_ct_u16be, ami_ct_s16le, ami_ct_u16le
};
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+static TRANS transAwacsNormal = {
+ pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8,
+ pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16
+};
+
+static TRANS transAwacsExpand = {
+ pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
+ pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
+};
+#endif /* CONFIG_PMAC */
/*** Low level stuff *********************************************************/
static void *AtaAlloc(unsigned int size, int flags)
{
- return( atari_stram_alloc( size, NULL, "dmasound" ));
+ return( atari_stram_alloc( size, NULL, "dmasound" ));
}
static void AtaFree(void *obj, unsigned int size)
{
- atari_stram_free( obj );
+ atari_stram_free( obj );
}
static int AtaIrqInit(void)
{
- /* Set up timer A. Timer A
- will receive a signal upon end of playing from the sound
- hardware. Furthermore Timer A is able to count events
- and will cause an interrupt after a programmed number
- of events. So all we need to keep the music playing is
- to provide the sound hardware with new data upon
- an interrupt from timer A. */
- mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
- mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
- mfp.tim_ct_a = 8; /* Turn on event counting. */
- /* Register interrupt handler. */
- request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
- "DMA sound", ata_sq_interrupt);
- mfp.int_en_a |= 0x20; /* Turn interrupt on. */
- mfp.int_mk_a |= 0x20;
- return(1);
+ /* Set up timer A. Timer A
+ will receive a signal upon end of playing from the sound
+ hardware. Furthermore Timer A is able to count events
+ and will cause an interrupt after a programmed number
+ of events. So all we need to keep the music playing is
+ to provide the sound hardware with new data upon
+ an interrupt from timer A. */
+ mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
+ mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
+ mfp.tim_ct_a = 8; /* Turn on event counting. */
+ /* Register interrupt handler. */
+ request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
+ "DMA sound", ata_sq_interrupt);
+ mfp.int_en_a |= 0x20; /* Turn interrupt on. */
+ mfp.int_mk_a |= 0x20;
+ return(1);
}
#ifdef MODULE
static void AtaIrqCleanUp(void)
{
- mfp.tim_ct_a = 0; /* stop timer */
- mfp.int_en_a &= ~0x20; /* turn interrupt off */
- free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
+ mfp.tim_ct_a = 0; /* stop timer */
+ mfp.int_en_a &= ~0x20; /* turn interrupt off */
+ free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
}
#endif /* MODULE */
static int AtaSetBass(int bass)
{
- sound.bass = TONE_VOXWARE_TO_DB(bass);
- atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
- return(TONE_DB_TO_VOXWARE(sound.bass));
+ sound.bass = TONE_VOXWARE_TO_DB(bass);
+ atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
+ return(TONE_DB_TO_VOXWARE(sound.bass));
}
static int AtaSetTreble(int treble)
{
- sound.treble = TONE_VOXWARE_TO_DB(treble);
- atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
- return(TONE_DB_TO_VOXWARE(sound.treble));
+ sound.treble = TONE_VOXWARE_TO_DB(treble);
+ atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
+ return(TONE_DB_TO_VOXWARE(sound.treble));
}
static void TTSilence(void)
{
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
}
static void TTInit(void)
{
- int mode, i, idx;
- const int freq[4] = {50066, 25033, 12517, 6258};
+ int mode, i, idx;
+ const int freq[4] = {50066, 25033, 12517, 6258};
- /* search a frequency that fits into the allowed error range */
+ /* search a frequency that fits into the allowed error range */
- idx = -1;
- for (i = 0; i < arraysize(freq); i++)
- /* this isn't as much useful for a TT than for a Falcon, but
- * then it doesn't hurt very much to implement it for a TT too.
- */
- if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
- idx = i;
- if (idx > -1) {
- sound.soft.speed = freq[idx];
- sound.trans = &transTTNormal;
- } else
- sound.trans = &transTTExpanding;
-
- TTSilence();
- sound.hard = sound.soft;
-
- if (sound.hard.speed > 50066) {
- /* we would need to squeeze the sound, but we won't do that */
- sound.hard.speed = 50066;
- mode = DMASND_MODE_50KHZ;
- sound.trans = &transTTNormal;
- } else if (sound.hard.speed > 25033) {
- sound.hard.speed = 50066;
- mode = DMASND_MODE_50KHZ;
- } else if (sound.hard.speed > 12517) {
- sound.hard.speed = 25033;
- mode = DMASND_MODE_25KHZ;
- } else if (sound.hard.speed > 6258) {
- sound.hard.speed = 12517;
- mode = DMASND_MODE_12KHZ;
- } else {
- sound.hard.speed = 6258;
- mode = DMASND_MODE_6KHZ;
- }
-
- tt_dmasnd.mode = (sound.hard.stereo ?
- DMASND_MODE_STEREO : DMASND_MODE_MONO) |
- DMASND_MODE_8BIT | mode;
-
- sound.bal = -sound.soft.speed;
+ idx = -1;
+ for (i = 0; i < arraysize(freq); i++)
+ /* this isn't as much useful for a TT than for a Falcon, but
+ * then it doesn't hurt very much to implement it for a TT too.
+ */
+ if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+ idx = i;
+ if (idx > -1) {
+ sound.soft.speed = freq[idx];
+ sound.trans = &transTTNormal;
+ } else
+ sound.trans = &transTTExpanding;
+
+ TTSilence();
+ sound.hard = sound.soft;
+
+ if (sound.hard.speed > 50066) {
+ /* we would need to squeeze the sound, but we won't do that */
+ sound.hard.speed = 50066;
+ mode = DMASND_MODE_50KHZ;
+ sound.trans = &transTTNormal;
+ } else if (sound.hard.speed > 25033) {
+ sound.hard.speed = 50066;
+ mode = DMASND_MODE_50KHZ;
+ } else if (sound.hard.speed > 12517) {
+ sound.hard.speed = 25033;
+ mode = DMASND_MODE_25KHZ;
+ } else if (sound.hard.speed > 6258) {
+ sound.hard.speed = 12517;
+ mode = DMASND_MODE_12KHZ;
+ } else {
+ sound.hard.speed = 6258;
+ mode = DMASND_MODE_6KHZ;
+ }
+
+ tt_dmasnd.mode = (sound.hard.stereo ?
+ DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+ DMASND_MODE_8BIT | mode;
+
+ sound.bal = -sound.soft.speed;
}
static int TTSetFormat(int format)
{
- /* TT sound DMA supports only 8bit modes */
+ /* TT sound DMA supports only 8bit modes */
- switch (format) {
+ switch (format) {
case AFMT_QUERY:
- return(sound.soft.format);
+ return(sound.soft.format);
case AFMT_MU_LAW:
case AFMT_A_LAW:
case AFMT_S8:
case AFMT_U8:
- break;
+ break;
default:
- format = AFMT_S8;
- }
+ format = AFMT_S8;
+ }
- sound.soft.format = format;
- sound.soft.size = 8;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = 8;
- }
- TTInit();
+ sound.soft.format = format;
+ sound.soft.size = 8;
+ if (sound.minDev == SND_DEV_DSP) {
+ sound.dsp.format = format;
+ sound.dsp.size = 8;
+ }
+ TTInit();
- return(format);
+ return(format);
}
static int TTSetVolume(int volume)
{
- sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
- atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
- sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
- atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
- return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
- (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
+ sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
+ atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
+ sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
+ atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
+ return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+ (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
}
static int TTSetGain(int gain)
{
- sound.gain = GAIN_VOXWARE_TO_DB(gain);
- atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
- return GAIN_DB_TO_VOXWARE(sound.gain);
+ sound.gain = GAIN_VOXWARE_TO_DB(gain);
+ atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
+ return GAIN_DB_TO_VOXWARE(sound.gain);
}
static void FalconSilence(void)
{
- /* stop playback, set sample rate 50kHz for PSG sound */
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
- tt_dmasnd.int_div = 0; /* STE compatible divider */
- tt_dmasnd.int_ctrl = 0x0;
- tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
- tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
- tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
- tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
+ /* stop playback, set sample rate 50kHz for PSG sound */
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
+ tt_dmasnd.int_div = 0; /* STE compatible divider */
+ tt_dmasnd.int_ctrl = 0x0;
+ tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
+ tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
+ tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
+ tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
}
static void FalconInit(void)
{
- int divider, i, idx;
- const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
+ int divider, i, idx;
+ const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
- /* search a frequency that fits into the allowed error range */
+ /* search a frequency that fits into the allowed error range */
- idx = -1;
- for (i = 0; i < arraysize(freq); i++)
- /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
- * be playable without expanding, but that now a kernel runtime
- * option
- */
- if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
- idx = i;
- if (idx > -1) {
- sound.soft.speed = freq[idx];
- sound.trans = &transFalconNormal;
- } else
- sound.trans = &transFalconExpanding;
-
- FalconSilence();
- sound.hard = sound.soft;
-
- if (sound.hard.size == 16) {
- /* the Falcon can play 16bit samples only in stereo */
- sound.hard.stereo = 1;
- }
-
- if (sound.hard.speed > 49170) {
- /* we would need to squeeze the sound, but we won't do that */
- sound.hard.speed = 49170;
- divider = 1;
- sound.trans = &transFalconNormal;
- } else if (sound.hard.speed > 32780) {
- sound.hard.speed = 49170;
- divider = 1;
- } else if (sound.hard.speed > 24585) {
- sound.hard.speed = 32780;
- divider = 2;
- } else if (sound.hard.speed > 19668) {
- sound.hard.speed = 24585;
- divider = 3;
- } else if (sound.hard.speed > 16390) {
- sound.hard.speed = 19668;
- divider = 4;
- } else if (sound.hard.speed > 12292) {
- sound.hard.speed = 16390;
- divider = 5;
- } else if (sound.hard.speed > 9834) {
- sound.hard.speed = 12292;
- divider = 7;
- } else if (sound.hard.speed > 8195) {
- sound.hard.speed = 9834;
- divider = 9;
- } else {
- sound.hard.speed = 8195;
- divider = 11;
- }
- tt_dmasnd.int_div = divider;
-
- /* Setup Falcon sound DMA for playback */
- tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
- tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
- tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
- tt_dmasnd.cbar_dst = 0x0000;
- tt_dmasnd.rec_track_select = 0;
- tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
- tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
-
- tt_dmasnd.mode = (sound.hard.stereo ?
- DMASND_MODE_STEREO : DMASND_MODE_MONO) |
- ((sound.hard.size == 8) ?
- DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
- DMASND_MODE_6KHZ;
-
- sound.bal = -sound.soft.speed;
-}
+ idx = -1;
+ for (i = 0; i < arraysize(freq); i++)
+ /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+ * be playable without expanding, but that now a kernel runtime
+ * option
+ */
+ if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+ idx = i;
+ if (idx > -1) {
+ sound.soft.speed = freq[idx];
+ sound.trans = &transFalconNormal;
+ } else
+ sound.trans = &transFalconExpanding;
+
+ FalconSilence();
+ sound.hard = sound.soft;
+
+ if (sound.hard.size == 16) {
+ /* the Falcon can play 16bit samples only in stereo */
+ sound.hard.stereo = 1;
+ }
+
+ if (sound.hard.speed > 49170) {
+ /* we would need to squeeze the sound, but we won't do that */
+ sound.hard.speed = 49170;
+ divider = 1;
+ sound.trans = &transFalconNormal;
+ } else if (sound.hard.speed > 32780) {
+ sound.hard.speed = 49170;
+ divider = 1;
+ } else if (sound.hard.speed > 24585) {
+ sound.hard.speed = 32780;
+ divider = 2;
+ } else if (sound.hard.speed > 19668) {
+ sound.hard.speed = 24585;
+ divider = 3;
+ } else if (sound.hard.speed > 16390) {
+ sound.hard.speed = 19668;
+ divider = 4;
+ } else if (sound.hard.speed > 12292) {
+ sound.hard.speed = 16390;
+ divider = 5;
+ } else if (sound.hard.speed > 9834) {
+ sound.hard.speed = 12292;
+ divider = 7;
+ } else if (sound.hard.speed > 8195) {
+ sound.hard.speed = 9834;
+ divider = 9;
+ } else {
+ sound.hard.speed = 8195;
+ divider = 11;
+ }
+ tt_dmasnd.int_div = divider;
+
+ /* Setup Falcon sound DMA for playback */
+ tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+ tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+ tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+ tt_dmasnd.cbar_dst = 0x0000;
+ tt_dmasnd.rec_track_select = 0;
+ tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+ tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+ tt_dmasnd.mode = (sound.hard.stereo ?
+ DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+ ((sound.hard.size == 8) ?
+ DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+ DMASND_MODE_6KHZ;
+
+ sound.bal = -sound.soft.speed;
+}
static int FalconSetFormat(int format)
{
- int size;
- /* Falcon sound DMA supports 8bit and 16bit modes */
+ int size;
+ /* Falcon sound DMA supports 8bit and 16bit modes */
- switch (format) {
+ switch (format) {
case AFMT_QUERY:
- return(sound.soft.format);
+ return(sound.soft.format);
case AFMT_MU_LAW:
case AFMT_A_LAW:
case AFMT_U8:
case AFMT_S8:
- size = 8;
- break;
+ size = 8;
+ break;
case AFMT_S16_BE:
case AFMT_U16_BE:
case AFMT_S16_LE:
case AFMT_U16_LE:
- size = 16;
- break;
+ size = 16;
+ break;
default: /* :-) */
- size = 8;
- format = AFMT_S8;
- }
+ size = 8;
+ format = AFMT_S8;
+ }
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = sound.soft.size;
- }
+ sound.soft.format = format;
+ sound.soft.size = size;
+ if (sound.minDev == SND_DEV_DSP) {
+ sound.dsp.format = format;
+ sound.dsp.size = sound.soft.size;
+ }
- FalconInit();
+ FalconInit();
- return(format);
+ return(format);
}
static int FalconSetVolume(int volume)
{
- sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
- sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
- tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
- return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
- VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
+ sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
+ sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
+ tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
+ return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+ VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
}
static void ata_sq_play_next_frame(int index)
{
- char *start, *end;
+ char *start, *end;
- /* used by AtaPlay() if all doubts whether there really is something
- * to be played are already wiped out.
- */
- start = sq_block_address(sq.front);
- end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
- /* end might not be a legal virtual address. */
- DMASNDSetEnd(VTOP(end - 1) + 1);
- DMASNDSetBase(VTOP(start));
+ /* used by AtaPlay() if all doubts whether there really is something
+ * to be played are already wiped out.
+ */
+ start = sq_block_address(sq.front);
+ end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
+ /* end might not be a legal virtual address. */
+ DMASNDSetEnd(VTOP(end - 1) + 1);
+ DMASNDSetBase(VTOP(start));
/* Since only an even number of samples per frame can
- be played, we might lose one byte here. (TO DO) */
- sq.front = (sq.front+1) % sq.max_count;
- sq.playing++;
- tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+ be played, we might lose one byte here. (TO DO) */
+ sq.front = (sq.front+1) % sq.max_count;
+ sq.playing++;
+ tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
}
static void AtaPlay(void)
{
- /* ++TeSche: Note that sq.playing is no longer just a flag but holds
- * the number of frames the DMA is currently programmed for instead,
- * may be 0, 1 (currently being played) or 2 (pre-programmed).
- *
- * Changes done to sq.count and sq.playing are a bit more subtle again
- * so now I must admit I also prefer disabling the irq here rather
- * than considering all possible situations. But the point is that
- * disabling the irq doesn't have any bad influence on this version of
- * the driver as we benefit from having pre-programmed the DMA
- * wherever possible: There's no need to reload the DMA at the exact
- * time of an interrupt but only at some time while the pre-programmed
- * frame is playing!
- */
- atari_disable_irq(IRQ_MFP_TIMA);
-
- if (sq.playing == 2 || /* DMA is 'full' */
- sq.count <= 0) { /* nothing to do */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
-
- if (sq.playing == 0) {
- /* looks like there's nothing 'in' the DMA yet, so try
- * to put two frames into it (at least one is available).
+ /* ++TeSche: Note that sq.playing is no longer just a flag but holds
+ * the number of frames the DMA is currently programmed for instead,
+ * may be 0, 1 (currently being played) or 2 (pre-programmed).
+ *
+ * Changes done to sq.count and sq.playing are a bit more subtle again
+ * so now I must admit I also prefer disabling the irq here rather
+ * than considering all possible situations. But the point is that
+ * disabling the irq doesn't have any bad influence on this version of
+ * the driver as we benefit from having pre-programmed the DMA
+ * wherever possible: There's no need to reload the DMA at the exact
+ * time of an interrupt but only at some time while the pre-programmed
+ * frame is playing!
*/
- if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- ata_sq_play_next_frame(1);
- if (sq.count == 1) {
- /* no more frames */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, there were two frames, but the second
- * one is not yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- ata_sq_play_next_frame(2);
- } else {
- /* there's already a frame being played so we may only stuff
- * one new into the DMA, but even if this may be the last
- * frame existing the previous one is still on sq.count.
- */
- if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
+ atari_disable_irq(IRQ_MFP_TIMA);
+
+ if (sq.playing == 2 || /* DMA is 'full' */
+ sq.count <= 0) { /* nothing to do */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
}
- ata_sq_play_next_frame(2);
- }
- atari_enable_irq(IRQ_MFP_TIMA);
+
+ if (sq.playing == 0) {
+ /* looks like there's nothing 'in' the DMA yet, so try
+ * to put two frames into it (at least one is available).
+ */
+ if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ ata_sq_play_next_frame(1);
+ if (sq.count == 1) {
+ /* no more frames */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+ /* hmmm, there were two frames, but the second
+ * one is not yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ ata_sq_play_next_frame(2);
+ } else {
+ /* there's already a frame being played so we may only stuff
+ * one new into the DMA, but even if this may be the last
+ * frame existing the previous one is still on sq.count.
+ */
+ if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ ata_sq_play_next_frame(2);
+ }
+ atari_enable_irq(IRQ_MFP_TIMA);
}
static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
#if 0
- /* ++TeSche: if you should want to test this... */
- static int cnt = 0;
- if (sq.playing == 2)
- if (++cnt == 10) {
- /* simulate losing an interrupt */
- cnt = 0;
- return;
- }
+ /* ++TeSche: if you should want to test this... */
+ static int cnt = 0;
+ if (sq.playing == 2)
+ if (++cnt == 10) {
+ /* simulate losing an interrupt */
+ cnt = 0;
+ return;
+ }
#endif
- if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
- /* ++TeSche: Falcon only: ignore first irq because it comes
- * immediately after starting a frame. after that, irqs come
- * (almost) like on the TT.
- */
- sq.ignore_int = 0;
- return;
- }
+ if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
+ /* ++TeSche: Falcon only: ignore first irq because it comes
+ * immediately after starting a frame. after that, irqs come
+ * (almost) like on the TT.
+ */
+ sq.ignore_int = 0;
+ return;
+ }
- if (!sq.playing) {
- /* playing was interrupted and sq_reset() has already cleared
- * the sq variables, so better don't do anything here.
+ if (!sq.playing) {
+ /* playing was interrupted and sq_reset() has already cleared
+ * the sq variables, so better don't do anything here.
+ */
+ WAKE_UP(sq.sync_queue);
+ return;
+ }
+
+ /* Probably ;) one frame is finished. Well, in fact it may be that a
+ * pre-programmed one is also finished because there has been a long
+ * delay in interrupt delivery and we've completely lost one, but
+ * there's no way to detect such a situation. In such a case the last
+ * frame will be played more than once and the situation will recover
+ * as soon as the irq gets through.
*/
- WAKE_UP(sq.sync_queue);
- return;
- }
-
- /* Probably ;) one frame is finished. Well, in fact it may be that a
- * pre-programmed one is also finished because there has been a long
- * delay in interrupt delivery and we've completely lost one, but
- * there's no way to detect such a situation. In such a case the last
- * frame will be played more than once and the situation will recover
- * as soon as the irq gets through.
- */
- sq.count--;
- sq.playing--;
-
- if (!sq.playing) {
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- sq.ignore_int = 1;
- }
+ sq.count--;
+ sq.playing--;
+
+ if (!sq.playing) {
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ sq.ignore_int = 1;
+ }
- WAKE_UP(sq.write_queue);
+ WAKE_UP(sq.write_queue);
/* At least one block of the queue is free now
- so wake up a writing process blocked because
- of a full queue. */
-
- if ((sq.playing != 1) || (sq.count != 1))
- /* We must be a bit carefully here: sq.count indicates the
- * number of buffers used and not the number of frames to
- * be played. If sq.count==1 and sq.playing==1 that means
- * the only remaining frame was already programmed earlier
- * (and is currently running) so we mustn't call AtaPlay()
- * here, otherwise we'll play one frame too much.
- */
- AtaPlay();
+ so wake up a writing process blocked because
+ of a full queue. */
+
+ if ((sq.playing != 1) || (sq.count != 1))
+ /* We must be a bit carefully here: sq.count indicates the
+ * number of buffers used and not the number of frames to
+ * be played. If sq.count==1 and sq.playing==1 that means
+ * the only remaining frame was already programmed earlier
+ * (and is currently running) so we mustn't call AtaPlay()
+ * here, otherwise we'll play one frame too much.
+ */
+ AtaPlay();
- if (!sq.playing) WAKE_UP(sq.sync_queue);
+ if (!sq.playing) WAKE_UP(sq.sync_queue);
/* We are not playing after AtaPlay(), so there
- is nothing to play any more. Wake up a process
- waiting for audio output to drain. */
+ is nothing to play any more. Wake up a process
+ waiting for audio output to drain. */
}
#endif /* CONFIG_ATARI */
static void *AmiAlloc(unsigned int size, int flags)
{
- return(amiga_chip_alloc((long)size));
+ return(amiga_chip_alloc((long)size));
}
static void AmiFree(void *obj, unsigned int size)
{
- amiga_chip_free (obj);
+ amiga_chip_free (obj);
}
static int AmiIrqInit(void)
{
- /* turn off DMA for audio channels */
- custom.dmacon = AMI_AUDIO_OFF;
+ /* turn off DMA for audio channels */
+ custom.dmacon = AMI_AUDIO_OFF;
- /* Register interrupt handler. */
- if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
- "DMA sound", ami_sq_interrupt))
- return(0);
- return(1);
+ /* Register interrupt handler. */
+ if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
+ "DMA sound", ami_sq_interrupt))
+ return(0);
+ return(1);
}
#ifdef MODULE
static void AmiIrqCleanUp(void)
{
- /* turn off DMA for audio channels */
- custom.dmacon = AMI_AUDIO_OFF;
- /* release the interrupt */
- free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
+ /* turn off DMA for audio channels */
+ custom.dmacon = AMI_AUDIO_OFF;
+ /* release the interrupt */
+ free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
}
#endif /* MODULE */
static void AmiSilence(void)
{
- /* turn off DMA for audio channels */
- custom.dmacon = AMI_AUDIO_OFF;
+ /* turn off DMA for audio channels */
+ custom.dmacon = AMI_AUDIO_OFF;
}
static void AmiInit(void)
{
- int period, i;
-
- AmiSilence();
-
- if (sound.soft.speed)
- period = amiga_colorclock/sound.soft.speed-1;
- else
- period = amiga_audio_min_period;
- sound.hard = sound.soft;
- sound.trans = &transAmiga;
-
- if (period < amiga_audio_min_period) {
- /* we would need to squeeze the sound, but we won't do that */
- period = amiga_audio_min_period;
- } else if (period > 65535) {
- period = 65535;
- }
- sound.hard.speed = amiga_colorclock/(period+1);
+ int period, i;
+
+ AmiSilence();
+
+ if (sound.soft.speed)
+ period = amiga_colorclock/sound.soft.speed-1;
+ else
+ period = amiga_audio_min_period;
+ sound.hard = sound.soft;
+ sound.trans = &transAmiga;
+
+ if (period < amiga_audio_min_period) {
+ /* we would need to squeeze the sound, but we won't do that */
+ period = amiga_audio_min_period;
+ } else if (period > 65535) {
+ period = 65535;
+ }
+ sound.hard.speed = amiga_colorclock/(period+1);
- for (i = 0; i < 4; i++)
- custom.aud[i].audper = period;
- amiga_audio_period = period;
+ for (i = 0; i < 4; i++)
+ custom.aud[i].audper = period;
+ amiga_audio_period = period;
- AmiSetTreble(50); /* recommended for newer amiga models */
+ AmiSetTreble(50); /* recommended for newer amiga models */
}
static int AmiSetFormat(int format)
{
- int size;
+ int size;
- /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+ /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
- switch (format) {
+ switch (format) {
case AFMT_QUERY:
- return(sound.soft.format);
+ return(sound.soft.format);
case AFMT_MU_LAW:
case AFMT_A_LAW:
case AFMT_U8:
case AFMT_S8:
- size = 8;
- break;
+ size = 8;
+ break;
case AFMT_S16_BE:
case AFMT_U16_BE:
case AFMT_S16_LE:
case AFMT_U16_LE:
- size = 16;
- break;
+ size = 16;
+ break;
default: /* :-) */
- size = 8;
- format = AFMT_S8;
- }
+ size = 8;
+ format = AFMT_S8;
+ }
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = sound.soft.size;
- }
- AmiInit();
+ sound.soft.format = format;
+ sound.soft.size = size;
+ if (sound.minDev == SND_DEV_DSP) {
+ sound.dsp.format = format;
+ sound.dsp.size = sound.soft.size;
+ }
+ AmiInit();
- return(format);
+ return(format);
}
static int AmiSetVolume(int volume)
{
- sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
- custom.aud[0].audvol = sound.volume_left;
- sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
- custom.aud[1].audvol = sound.volume_right;
- return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
- (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+ sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
+ custom.aud[0].audvol = sound.volume_left;
+ sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
+ custom.aud[1].audvol = sound.volume_right;
+ return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+ (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
}
static int AmiSetTreble(int treble)
{
- sound.treble = treble;
- if (treble < 50)
- ciaa.pra &= ~0x02;
- else
- ciaa.pra |= 0x02;
- return(treble);
+ sound.treble = treble;
+ if (treble < 50)
+ ciaa.pra &= ~0x02;
+ else
+ ciaa.pra |= 0x02;
+ return(treble);
}
static void ami_sq_play_next_frame(int index)
{
- u_char *start, *ch0, *ch1, *ch2, *ch3;
- u_long size;
-
- /* used by AmiPlay() if all doubts whether there really is something
- * to be played are already wiped out.
- */
- start = sq_block_address(sq.front);
- size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
-
- if (sound.hard.stereo) {
- ch0 = start;
- ch1 = start+sq.block_size_half;
- size >>= 1;
- } else {
- ch0 = start;
- ch1 = start;
- }
- if (sound.hard.size == 8) {
- custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
- custom.aud[0].audlen = size;
- custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
- custom.aud[1].audlen = size;
- custom.dmacon = AMI_AUDIO_8;
- } else {
- size >>= 1;
- custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
- custom.aud[0].audlen = size;
- custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
- custom.aud[1].audlen = size;
- if (sound.volume_left == 64 && sound.volume_right == 64) {
- /* We can play pseudo 14-bit only with the maximum volume */
- ch3 = ch0+sq.block_size_quarter;
- ch2 = ch1+sq.block_size_quarter;
- custom.aud[2].audvol = 1; /* we are being affected by the beeps */
- custom.aud[3].audvol = 1; /* restoring volume here helps a bit */
- custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
- custom.aud[2].audlen = size;
- custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
- custom.aud[3].audlen = size;
- custom.dmacon = AMI_AUDIO_14;
- } else
- custom.dmacon = AMI_AUDIO_8;
- }
- sq.front = (sq.front+1) % sq.max_count;
- sq.playing |= AMI_PLAY_LOADED;
+ u_char *start, *ch0, *ch1, *ch2, *ch3;
+ u_long size;
+
+ /* used by AmiPlay() if all doubts whether there really is something
+ * to be played are already wiped out.
+ */
+ start = sq_block_address(sq.front);
+ size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
+
+ if (sound.hard.stereo) {
+ ch0 = start;
+ ch1 = start+sq.block_size_half;
+ size >>= 1;
+ } else {
+ ch0 = start;
+ ch1 = start;
+ }
+ if (sound.hard.size == 8) {
+ custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+ custom.aud[0].audlen = size;
+ custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+ custom.aud[1].audlen = size;
+ custom.dmacon = AMI_AUDIO_8;
+ } else {
+ size >>= 1;
+ custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+ custom.aud[0].audlen = size;
+ custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+ custom.aud[1].audlen = size;
+ if (sound.volume_left == 64 && sound.volume_right == 64) {
+ /* We can play pseudo 14-bit only with the maximum volume */
+ ch3 = ch0+sq.block_size_quarter;
+ ch2 = ch1+sq.block_size_quarter;
+ custom.aud[2].audvol = 1; /* we are being affected by the beeps */
+ custom.aud[3].audvol = 1; /* restoring volume here helps a bit */
+ custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
+ custom.aud[2].audlen = size;
+ custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
+ custom.aud[3].audlen = size;
+ custom.dmacon = AMI_AUDIO_14;
+ } else
+ custom.dmacon = AMI_AUDIO_8;
+ }
+ sq.front = (sq.front+1) % sq.max_count;
+ sq.playing |= AMI_PLAY_LOADED;
}
static void AmiPlay(void)
{
- int minframes = 1;
+ int minframes = 1;
- custom.intena = IF_AUD0;
+ custom.intena = IF_AUD0;
- if (sq.playing & AMI_PLAY_LOADED) {
- /* There's already a frame loaded */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
+ if (sq.playing & AMI_PLAY_LOADED) {
+ /* There's already a frame loaded */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
- if (sq.playing & AMI_PLAY_PLAYING)
- /* Increase threshold: frame 1 is already being played */
- minframes = 2;
+ if (sq.playing & AMI_PLAY_PLAYING)
+ /* Increase threshold: frame 1 is already being played */
+ minframes = 2;
- if (sq.count < minframes) {
- /* Nothing to do */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
+ if (sq.count < minframes) {
+ /* Nothing to do */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
- if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
+ if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
- ami_sq_play_next_frame(minframes);
+ ami_sq_play_next_frame(minframes);
- custom.intena = IF_SETCLR | IF_AUD0;
+ custom.intena = IF_SETCLR | IF_AUD0;
}
static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
- int minframes = 1;
+ int minframes = 1;
- if (!sq.playing) {
- /* Playing was interrupted and sq_reset() has already cleared
- * the sq variables, so better don't do anything here.
- */
- WAKE_UP(sq.sync_queue);
- return;
- }
+ if (!sq.playing) {
+ /* Playing was interrupted and sq_reset() has already cleared
+ * the sq variables, so better don't do anything here.
+ */
+ WAKE_UP(sq.sync_queue);
+ return;
+ }
- if (sq.playing & AMI_PLAY_PLAYING) {
- /* We've just finished a frame */
- sq.count--;
- WAKE_UP(sq.write_queue);
- }
+ if (sq.playing & AMI_PLAY_PLAYING) {
+ /* We've just finished a frame */
+ sq.count--;
+ WAKE_UP(sq.write_queue);
+ }
- if (sq.playing & AMI_PLAY_LOADED)
- /* Increase threshold: frame 1 is already being played */
- minframes = 2;
+ if (sq.playing & AMI_PLAY_LOADED)
+ /* Increase threshold: frame 1 is already being played */
+ minframes = 2;
- /* Shift the flags */
- sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
+ /* Shift the flags */
+ sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
- if (!sq.playing)
- /* No frame is playing, disable audio DMA */
- custom.dmacon = AMI_AUDIO_OFF;
+ if (!sq.playing)
+ /* No frame is playing, disable audio DMA */
+ custom.dmacon = AMI_AUDIO_OFF;
- if (sq.count >= minframes)
- /* Try to play the next frame */
- AmiPlay();
+ if (sq.count >= minframes)
+ /* Try to play the next frame */
+ AmiPlay();
- if (!sq.playing)
- /* Nothing to play anymore.
- Wake up a process waiting for audio output to drain. */
- WAKE_UP(sq.sync_queue);
+ if (!sq.playing)
+ /* Nothing to play anymore.
+ Wake up a process waiting for audio output to drain. */
+ WAKE_UP(sq.sync_queue);
}
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+
+/*
+ * PCI PowerMac, with AWACS and DBDMA.
+ */
+
+static void *PMacAlloc(unsigned int size, int flags)
+{
+ return kmalloc(size, flags);
+}
+
+static void PMacFree(void *ptr, unsigned int size)
+{
+ kfree(ptr);
+}
+
+static int PMacIrqInit(void)
+{
+ if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
+ || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0))
+ return 0;
+ return 1;
+}
+
+#ifdef MODULE
+static void PMacIrqCleanup(void)
+{
+ /* turn off output dma */
+ out_le32(&awacs_txdma->control, RUN<<16);
+ /* disable interrupts from awacs interface */
+ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+ free_irq(awacs_irq, pmac_awacs_intr);
+ free_irq(awacs_tx_irq, pmac_awacs_tx_intr);
+ kfree(awacs_tx_cmd_space);
+ if (beep_buf)
+ kfree(beep_buf);
+ kd_mksound = orig_mksound;
+}
+#endif /* MODULE */
+
+static void PMacSilence(void)
+{
+ /* turn off output dma */
+ out_le32(&awacs_txdma->control, RUN<<16);
+}
+
+static int awacs_freqs[8] = {
+ 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
+};
+
+static void PMacInit(void)
+{
+ int i, tolerance;
+
+ switch (sound.soft.format) {
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ sound.hard.format = AFMT_S16_LE;
+ break;
+ default:
+ sound.hard.format = AFMT_S16_BE;
+ break;
+ }
+ sound.hard.stereo = 1;
+ sound.hard.size = 16;
+
+ /*
+ * If we have a sample rate which is within catchRadius percent
+ * of the requested value, we don't have to expand the samples.
+ * Otherwise choose the next higher rate.
+ */
+ i = 8;
+ do {
+ tolerance = catchRadius * awacs_freqs[--i] / 100;
+ } while (sound.soft.speed > awacs_freqs[i] + tolerance && i > 0);
+ if (sound.soft.speed >= awacs_freqs[i] - tolerance)
+ sound.trans = &transAwacsNormal;
+ else
+ sound.trans = &transAwacsExpand;
+ sound.hard.speed = awacs_freqs[i];
+ awacs_rate_index = i;
+
+ PMacSilence();
+ out_le32(&awacs->control, MASK_IEPC | MASK_IEE | (i << 8) | 0x11);
+ awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+
+ sound.bal = -sound.soft.speed;
+}
+
+static int PMacSetFormat(int format)
+{
+ int size;
+
+ switch (format) {
+ case AFMT_QUERY:
+ return sound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_U8:
+ case AFMT_S8:
+ size = 8;
+ break;
+ case AFMT_S16_BE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ size = 16;
+ break;
+ default: /* :-) */
+ printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
+ format);
+ size = 8;
+ format = AFMT_U8;
+ }
+
+ sound.soft.format = format;
+ sound.soft.size = size;
+ if (sound.minDev == SND_DEV_DSP) {
+ sound.dsp.format = format;
+ sound.dsp.size = size;
+ }
+
+ PMacInit();
+
+ return format;
+}
+
+#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99))
+#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15))
+
+static int awacs_get_volume(int reg, int lshift)
+{
+ int volume;
+
+ volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
+ volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
+ return volume;
+}
+
+static int awacs_volume_setter(int volume, int n, int mute, int lshift)
+{
+ int r1, rn;
+
+ if (mute && volume == 0) {
+ r1 = awacs_reg[1] | mute;
+ } else {
+ r1 = awacs_reg[1] & ~mute;
+ rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
+ rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
+ rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
+ awacs_reg[n] = rn;
+ awacs_write((n << 12) | rn);
+ volume = awacs_get_volume(rn, lshift);
+ }
+ if (r1 != awacs_reg[1]) {
+ awacs_reg[1] = r1;
+ awacs_write(r1 | MASK_ADDR1);
+ }
+ return volume;
+}
+
+static int PMacSetVolume(int volume)
+{
+ return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
+}
+
+static void PMacPlay(void)
+{
+ volatile struct dbdma_cmd *cp;
+ int i, count;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (beep_playing) {
+ /* sound takes precedence over beeps */
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ || (awacs_rate_index << 8));
+ out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+ beep_playing = 0;
+ }
+ i = sq.front + sq.playing;
+ if (i >= sq.max_count)
+ i -= sq.max_count;
+ while (sq.playing < 2 && sq.playing < sq.count) {
+ count = (sq.count == sq.playing + 1)? sq.rear_size: sq.block_size;
+ if (count < sq.block_size && !sq.syncing)
+ /* last block not yet filled, and we're not syncing. */
+ break;
+ cp = &awacs_tx_cmds[i];
+ st_le16(&cp->req_count, count);
+ st_le16(&cp->xfer_status, 0);
+ if (++i >= sq.max_count)
+ i = 0;
+ out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
+ out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+ if (sq.playing == 0)
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
+ out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+ ++sq.playing;
+ }
+ restore_flags(flags);
+}
+
+static void
+pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ int i = sq.front;
+ int stat;
+ volatile struct dbdma_cmd *cp;
+
+ while (sq.playing > 0) {
+ cp = &awacs_tx_cmds[i];
+ stat = ld_le16(&cp->xfer_status);
+ if ((stat & ACTIVE) == 0)
+ break; /* this frame is still going */
+ --sq.count;
+ --sq.playing;
+ if (++i >= sq.max_count)
+ i = 0;
+ }
+ if (i != sq.front)
+ WAKE_UP(sq.write_queue);
+ sq.front = i;
+
+ PMacPlay();
+
+ if (!sq.playing)
+ WAKE_UP(sq.sync_queue);
+}
+
+static void
+pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ int ctrl = in_le32(&awacs->control);
+
+ if (ctrl & MASK_PORTCHG) {
+ /* do something when headphone is plugged/unplugged? */
+ }
+ if (ctrl & MASK_CNTLERR) {
+ printk(KERN_ERR "AWACS: error, status = %x\n",
+ in_le32(&awacs->codec_stat));
+ }
+ /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
+ out_le32(&awacs->control, ctrl);
+}
+
+static void
+awacs_write(int val)
+{
+ while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+ ; /* XXX should have timeout */
+ out_le32(&awacs->codec_ctrl, val);
+}
+
+static void awacs_nosound(unsigned long xx)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (beep_playing) {
+ st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+ beep_playing = 0;
+ }
+ restore_flags(flags);
+}
+
+static struct timer_list beep_timer = {
+ NULL, NULL, 0, 0, awacs_nosound
+};
+
+static void awacs_mksound(unsigned int hz, unsigned int ticks)
+{
+ unsigned long flags;
+ int srate = awacs_freqs[BEEP_SPEED];
+ int period, ncycles, nsamples;
+ int i, j, f;
+ short *p;
+ static int beep_hz_cache;
+ static int beep_nsamples_cache;
+ static int beep_volume_cache;
+
+ if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
+#if 1
+ /* this is a hack for broken X server code */
+ hz = 750;
+ ticks = 12;
+#else
+ /* cancel beep currently playing */
+ awacs_nosound(0);
+ return;
+#endif
+ }
+ save_flags(flags); cli();
+ del_timer(&beep_timer);
+ if (ticks) {
+ beep_timer.expires = jiffies + ticks;
+ add_timer(&beep_timer);
+ }
+ if (beep_playing || sq.playing || beep_buf == NULL) {
+ restore_flags(flags);
+ return; /* too hard, sorry :-( */
+ }
+ beep_playing = 1;
+ st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
+ restore_flags(flags);
+
+ if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
+ nsamples = beep_nsamples_cache;
+ } else {
+ period = srate * 256 / hz; /* fixed point */
+ ncycles = BEEP_BUFLEN * 256 / period;
+ nsamples = (period * ncycles) >> 8;
+ f = ncycles * 65536 / nsamples;
+ j = 0;
+ p = beep_buf;
+ for (i = 0; i < nsamples; ++i, p += 2) {
+ p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
+ j = (j + f) & 0xffff;
+ }
+ beep_hz_cache = hz;
+ beep_volume_cache = beep_volume;
+ beep_nsamples_cache = nsamples;
+ }
+
+ st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
+ st_le16(&beep_dbdma_cmd->xfer_status, 0);
+ st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
+ st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
+
+ save_flags(flags); cli();
+ if (beep_playing) { /* i.e. haven't been terminated already */
+ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ | (BEEP_SPEED << 8));
+ out_le32(&awacs->byteswap, 0);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+ out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+ }
+ restore_flags(flags);
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save state when going to sleep, restore it afterwards.
+ */
+static int awacs_sleep_notify(struct notifier_block *this,
+ unsigned long code, void *x)
+{
+ switch (code) {
+ case PBOOK_SLEEP:
+ /* XXX we should stop any dma in progress when going to sleep
+ and restart it when we wake. */
+ PMacSilence();
+ break;
+ case PBOOK_WAKE:
+ out_le32(&awacs->control, MASK_IEPC | MASK_IEE |
+ (awacs_rate_index << 8) | 0x11);
+ awacs_write(awacs_reg[0] | MASK_ADDR0);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ awacs_write(awacs_reg[2] | MASK_ADDR2);
+ awacs_write(awacs_reg[4] | MASK_ADDR4);
+ out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+ }
+ return NOTIFY_DONE;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+#endif /* CONFIG_PMAC */
/*** Machine definitions *****************************************************/
#ifdef CONFIG_ATARI
static MACHINE machTT = {
- DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
+ DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
#ifdef MODULE
- AtaIrqCleanUp,
+ AtaIrqCleanUp,
#endif /* MODULE */
- TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble,
- TTSetGain,
- AtaPlay
+ TTInit, TTSilence, TTSetFormat, TTSetVolume,
+ AtaSetBass, AtaSetTreble, TTSetGain,
+ AtaPlay
};
static MACHINE machFalcon = {
- DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
+ DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
#ifdef MODULE
- AtaIrqCleanUp,
+ AtaIrqCleanUp,
#endif /* MODULE */
- FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass,
- AtaSetTreble, NULL, AtaPlay
+ FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume,
+ AtaSetBass, AtaSetTreble, NULL,
+ AtaPlay
};
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
static MACHINE machAmiga = {
- DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
+ DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
+#ifdef MODULE
+ AmiIrqCleanUp,
+#endif /* MODULE */
+ AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume,
+ NULL, AmiSetTreble, NULL,
+ AmiPlay
+};
+#endif /* CONFIG_AMIGA */
+
+#ifdef CONFIG_PMAC
+static MACHINE machPMac = {
+ DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit,
#ifdef MODULE
- AmiIrqCleanUp,
+ PMacIrqCleanup,
#endif /* MODULE */
- AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble,
- NULL,
- AmiPlay
+ PMacInit, PMacSilence, PMacSetFormat, PMacSetVolume,
+ NULL, NULL, NULL, /* bass, treble, gain */
+ PMacPlay
};
#endif /* CONFIG_AMIGA */
static void sound_silence(void)
{
- /* update hardware settings one more */
- (*sound.mach.init)();
+ /* update hardware settings one more */
+ (*sound.mach.init)();
- (*sound.mach.silence)();
+ (*sound.mach.silence)();
}
static void sound_init(void)
{
- (*sound.mach.init)();
+ (*sound.mach.init)();
}
static int sound_set_format(int format)
{
- return(*sound.mach.setFormat)(format);
+ return(*sound.mach.setFormat)(format);
}
static int sound_set_speed(int speed)
{
- if (speed < 0)
- return(sound.soft.speed);
+ if (speed < 0)
+ return(sound.soft.speed);
- sound.soft.speed = speed;
- (*sound.mach.init)();
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.speed = sound.soft.speed;
+ sound.soft.speed = speed;
+ (*sound.mach.init)();
+ if (sound.minDev == SND_DEV_DSP)
+ sound.dsp.speed = sound.soft.speed;
- return(sound.soft.speed);
+ return(sound.soft.speed);
}
static int sound_set_stereo(int stereo)
{
- if (stereo < 0)
- return(sound.soft.stereo);
+ if (stereo < 0)
+ return(sound.soft.stereo);
- stereo = !!stereo; /* should be 0 or 1 now */
+ stereo = !!stereo; /* should be 0 or 1 now */
- sound.soft.stereo = stereo;
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.stereo = stereo;
- (*sound.mach.init)();
+ sound.soft.stereo = stereo;
+ if (sound.minDev == SND_DEV_DSP)
+ sound.dsp.stereo = stereo;
+ (*sound.mach.init)();
- return(stereo);
+ return(stereo);
}
static int sound_set_volume(int volume)
{
- return(*sound.mach.setVolume)(volume);
+ return(*sound.mach.setVolume)(volume);
}
#ifdef CONFIG_ATARI
static int sound_set_bass(int bass)
{
- return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
+ return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
}
static int sound_set_gain(int gain)
{
- return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
+ return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
}
#endif /* CONFIG_ATARI */
-
+#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
static int sound_set_treble(int treble)
{
- return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
+ return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
}
+#endif /* CONFIG_ATARI || CONFIG_AMIGA */
static long sound_copy_translate(const u_char *userPtr,
u_char frame[], long *frameUsed,
long frameLeft)
{
- long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL;
+ long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL;
- switch (sound.soft.format) {
+ switch (sound.soft.format) {
case AFMT_MU_LAW:
- ct_func = sound.trans->ct_ulaw;
- break;
+ ct_func = sound.trans->ct_ulaw;
+ break;
case AFMT_A_LAW:
- ct_func = sound.trans->ct_alaw;
- break;
+ ct_func = sound.trans->ct_alaw;
+ break;
case AFMT_S8:
- ct_func = sound.trans->ct_s8;
- break;
+ ct_func = sound.trans->ct_s8;
+ break;
case AFMT_U8:
- ct_func = sound.trans->ct_u8;
- break;
+ ct_func = sound.trans->ct_u8;
+ break;
case AFMT_S16_BE:
- ct_func = sound.trans->ct_s16be;
- break;
+ ct_func = sound.trans->ct_s16be;
+ break;
case AFMT_U16_BE:
- ct_func = sound.trans->ct_u16be;
- break;
+ ct_func = sound.trans->ct_u16be;
+ break;
case AFMT_S16_LE:
- ct_func = sound.trans->ct_s16le;
- break;
+ ct_func = sound.trans->ct_s16le;
+ break;
case AFMT_U16_LE:
- ct_func = sound.trans->ct_u16le;
- break;
- }
- if (ct_func)
- return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
- else
- return(0);
+ ct_func = sound.trans->ct_u16le;
+ break;
+ }
+ if (ct_func)
+ return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
+ else
+ return(0);
}
static void mixer_init(void)
{
- mixer.busy = 0;
- sound.treble = 0;
- sound.bass = 0;
- switch (sound.mach.type) {
+ mixer.busy = 0;
+ sound.treble = 0;
+ sound.bass = 0;
+ switch (sound.mach.type) {
#ifdef CONFIG_ATARI
case DMASND_TT:
- atari_microwire_cmd(MW_LM1992_VOLUME(0));
- sound.volume_left = 0;
- atari_microwire_cmd(MW_LM1992_BALLEFT(0));
- sound.volume_right = 0;
- atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
- atari_microwire_cmd(MW_LM1992_TREBLE(0));
- atari_microwire_cmd(MW_LM1992_BASS(0));
- break;
+ atari_microwire_cmd(MW_LM1992_VOLUME(0));
+ sound.volume_left = 0;
+ atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+ sound.volume_right = 0;
+ atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+ atari_microwire_cmd(MW_LM1992_TREBLE(0));
+ atari_microwire_cmd(MW_LM1992_BASS(0));
+ break;
case DMASND_FALCON:
- sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
- sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
- break;
+ sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+ sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+ break;
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
case DMASND_AMIGA:
- sound.volume_left = 64;
- sound.volume_right = 64;
- custom.aud[0].audvol = sound.volume_left;
- custom.aud[3].audvol = 1; /* For pseudo 14bit */
- custom.aud[1].audvol = sound.volume_right;
- custom.aud[2].audvol = 1; /* For pseudo 14bit */
- sound.treble = 50;
- break;
+ sound.volume_left = 64;
+ sound.volume_right = 64;
+ custom.aud[0].audvol = sound.volume_left;
+ custom.aud[3].audvol = 1; /* For pseudo 14bit */
+ custom.aud[1].audvol = sound.volume_right;
+ custom.aud[2].audvol = 1; /* For pseudo 14bit */
+ sound.treble = 50;
+ break;
#endif /* CONFIG_AMIGA */
- }
+ }
}
static int mixer_open(int open_mode)
{
- if (mixer.busy)
- return(-EBUSY);
- mixer.busy = 1;
- return(0);
+ mixer.busy = 1;
+ return(0);
}
static int mixer_release(void)
{
- mixer.busy = 0;
- return(0);
+ mixer.busy = 0;
+ return(0);
}
static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg)
{
- int data;
- switch (sound.mach.type) {
+ int data;
+ switch (sound.mach.type) {
#ifdef CONFIG_ATARI
case DMASND_FALCON:
- switch (cmd) {
+ switch (cmd) {
case SOUND_MIXER_READ_DEVMASK:
- return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+ return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
case SOUND_MIXER_READ_RECMASK:
- return(IOCTL_OUT(arg, SOUND_MASK_MIC));
+ return(IOCTL_OUT(arg, SOUND_MASK_MIC));
case SOUND_MIXER_READ_STEREODEVS:
- return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
+ return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
case SOUND_MIXER_READ_CAPS:
- return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
+ return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
case SOUND_MIXER_READ_VOLUME:
- return(IOCTL_OUT(arg,
- VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
- VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
+ return(IOCTL_OUT(arg,
+ VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
+ VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- tt_dmasnd.input_gain =
- RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
- RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
- /* fall thru, return set value */
+ IOCTL_IN(arg, data);
+ tt_dmasnd.input_gain =
+ RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
+ RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
+ /* fall thru, return set value */
case SOUND_MIXER_READ_MIC:
- return(IOCTL_OUT(arg,
- RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
- RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
+ return(IOCTL_OUT(arg,
+ RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
+ RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
case SOUND_MIXER_READ_SPEAKER:
- {
- int porta;
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = sound_ym.rd_data_reg_sel;
- sti();
- return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
- }
+ {
+ int porta;
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ porta = sound_ym.rd_data_reg_sel;
+ sti();
+ return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+ }
case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_volume(data)));
- case SOUND_MIXER_WRITE_SPEAKER:
- {
- int porta;
IOCTL_IN(arg, data);
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = (sound_ym.rd_data_reg_sel & ~0x40) |
- (data < 50 ? 0x40 : 0);
- sound_ym.wd_data = porta;
- sti();
- return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
- }
- }
- break;
+ return(IOCTL_OUT(arg, sound_set_volume(data)));
+ case SOUND_MIXER_WRITE_SPEAKER:
+ {
+ int porta;
+ IOCTL_IN(arg, data);
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+ (data < 50 ? 0x40 : 0);
+ sound_ym.wd_data = porta;
+ sti();
+ return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+ }
+ }
+ break;
case DMASND_TT:
- switch (cmd) {
+ switch (cmd) {
case SOUND_MIXER_READ_DEVMASK:
- return(IOCTL_OUT(arg,
- SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
- (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)));
+ return(IOCTL_OUT(arg,
+ SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
+ (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)));
case SOUND_MIXER_READ_RECMASK:
- return(IOCTL_OUT(arg, 0));
+ return(IOCTL_OUT(arg, 0));
case SOUND_MIXER_READ_STEREODEVS:
- return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+ return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
case SOUND_MIXER_READ_VOLUME:
- return(IOCTL_OUT(arg,
- VOLUME_DB_TO_VOXWARE(sound.volume_left) |
- (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
+ return(IOCTL_OUT(arg,
+ VOLUME_DB_TO_VOXWARE(sound.volume_left) |
+ (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
case SOUND_MIXER_READ_BASS:
- return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
+ return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
case SOUND_MIXER_READ_TREBLE:
- return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
+ return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
case SOUND_MIXER_READ_OGAIN:
- return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain)));
+ return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain)));
case SOUND_MIXER_READ_SPEAKER:
- {
- int porta;
- if (MACH_IS_TT) {
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = sound_ym.rd_data_reg_sel;
- sti();
- return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
- } else
- return(-EINVAL);
- }
+ {
+ int porta;
+ if (MACH_IS_TT) {
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ porta = sound_ym.rd_data_reg_sel;
+ sti();
+ return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+ } else
+ return(-EINVAL);
+ }
case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_volume(data)));
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_volume(data)));
case SOUND_MIXER_WRITE_BASS:
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_bass(data)));
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_bass(data)));
case SOUND_MIXER_WRITE_TREBLE:
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_treble(data)));
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_treble(data)));
case SOUND_MIXER_WRITE_OGAIN:
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_gain(data)));
- case SOUND_MIXER_WRITE_SPEAKER:
- if (MACH_IS_TT) {
- int porta;
IOCTL_IN(arg, data);
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = (sound_ym.rd_data_reg_sel & ~0x40) |
- (data < 50 ? 0x40 : 0);
- sound_ym.wd_data = porta;
- sti();
- return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
- } else
- return(-EINVAL);
- }
- break;
+ return(IOCTL_OUT(arg, sound_set_gain(data)));
+ case SOUND_MIXER_WRITE_SPEAKER:
+ if (MACH_IS_TT) {
+ int porta;
+ IOCTL_IN(arg, data);
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+ (data < 50 ? 0x40 : 0);
+ sound_ym.wd_data = porta;
+ sti();
+ return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+ } else
+ return(-EINVAL);
+ }
+ break;
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
case DMASND_AMIGA:
- switch (cmd) {
+ switch (cmd) {
case SOUND_MIXER_READ_DEVMASK:
- return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
+ return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
case SOUND_MIXER_READ_RECMASK:
- return(IOCTL_OUT(arg, 0));
+ return(IOCTL_OUT(arg, 0));
case SOUND_MIXER_READ_STEREODEVS:
- return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+ return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
case SOUND_MIXER_READ_VOLUME:
- return(IOCTL_OUT(arg,
- VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
- VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+ return(IOCTL_OUT(arg,
+ VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
+ VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_volume(data)));
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_volume(data)));
case SOUND_MIXER_READ_TREBLE:
- return(IOCTL_OUT(arg, sound.treble));
+ return(IOCTL_OUT(arg, sound.treble));
case SOUND_MIXER_WRITE_TREBLE:
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_treble(data)));
- }
- break;
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_treble(data)));
+ }
+ break;
#endif /* CONFIG_AMIGA */
- }
- return(-EINVAL);
+#ifdef CONFIG_PMAC
+ case DMASND_AWACS:
+ switch (cmd) {
+ case SOUND_MIXER_READ_DEVMASK:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+ | SOUND_MASK_LINE | SOUND_MASK_MIC
+ | SOUND_MASK_CD | SOUND_MASK_RECLEV
+ | SOUND_MASK_ALTPCM;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECMASK:
+ data = SOUND_MASK_LINE | SOUND_MASK_MIC
+ | SOUND_MASK_CD;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECSRC:
+ data = 0;
+ if (awacs_reg[0] & MASK_MUX_AUDIN)
+ data |= SOUND_MASK_LINE;
+ if (awacs_reg[0] & MASK_MUX_MIC)
+ data |= SOUND_MASK_MIC;
+ if (awacs_reg[0] & MASK_MUX_CD)
+ data |= SOUND_MASK_CD;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECSRC:
+ IOCTL_IN(arg, data);
+ data &= (SOUND_MASK_LINE
+ | SOUND_MASK_MIC | SOUND_MASK_CD);
+ awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+ | MASK_MUX_AUDIN);
+ if (data & SOUND_MASK_LINE)
+ awacs_reg[0] |= MASK_MUX_AUDIN;
+ if (data & SOUND_MASK_MIC)
+ awacs_reg[0] |= MASK_MUX_MIC;
+ if (data & SOUND_MASK_CD)
+ awacs_reg[0] |= MASK_MUX_CD;
+ awacs_write(awacs_reg[0] | MASK_ADDR0);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_STEREODEVS:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+ | SOUND_MASK_RECLEV;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_CAPS:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_READ_VOLUME:
+ data = (awacs_reg[1] & MASK_AMUTE)? 0:
+ awacs_get_volume(awacs_reg[2], 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_volume(data));
+ case SOUND_MIXER_READ_SPEAKER:
+ data = (awacs_reg[1] & MASK_CMUTE)? 0:
+ awacs_get_volume(awacs_reg[4], 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_SPEAKER:
+ IOCTL_IN(arg, data);
+ data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
+ IOCTL_IN(arg, data);
+ beep_volume = data & 0xff;
+ /* fall through */
+ case SOUND_MIXER_READ_ALTPCM:
+ return IOCTL_OUT(arg, beep_volume);
+ case SOUND_MIXER_WRITE_LINE:
+ IOCTL_IN(arg, data);
+ awacs_reg[0] &= ~MASK_MUX_AUDIN;
+ if ((data & 0xff) >= 50)
+ awacs_reg[0] |= MASK_MUX_AUDIN;
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_LINE:
+ data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_MIC:
+ IOCTL_IN(arg, data);
+ data &= 0xff;
+ awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
+ if (data >= 25) {
+ awacs_reg[0] |= MASK_MUX_MIC;
+ if (data >= 75)
+ awacs_reg[0] |= MASK_GAINLINE;
+ }
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_MIC:
+ data = (awacs_reg[0] & MASK_MUX_MIC)?
+ (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_CD:
+ IOCTL_IN(arg, data);
+ awacs_reg[0] &= ~MASK_MUX_CD;
+ if ((data & 0xff) >= 50)
+ awacs_reg[0] |= MASK_MUX_CD;
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_CD:
+ data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECLEV:
+ IOCTL_IN(arg, data);
+ data = awacs_volume_setter(data, 0, 0, 4);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECLEV:
+ data = awacs_get_volume(awacs_reg[0], 4);
+ return IOCTL_OUT(arg, data);
+ }
+ break;
+#endif
+ }
+
+ return(-EINVAL);
}
static void sq_init(int numBufs, int bufSize, char **buffers)
{
- sq.max_count = numBufs;
- sq.block_size = bufSize;
- sq.buffers = buffers;
-
- sq.front = sq.count = 0;
- sq.rear = -1;
- sq.write_queue = sq.open_queue = sq.sync_queue = 0;
- sq.busy = 0;
- sq.syncing = 0;
+#ifdef CONFIG_PMAC
+ int i;
+ volatile struct dbdma_cmd *cp;
+#endif /* CONFIG_PMAC */
+
+ sq.max_count = numBufs;
+ sq.max_active = numBufs;
+ sq.block_size = bufSize;
+ sq.buffers = buffers;
+
+ sq.front = sq.count = 0;
+ sq.rear = -1;
+ sq.write_queue = sq.open_queue = sq.sync_queue = 0;
+ sq.busy = 0;
+ sq.syncing = 0;
- sq.playing = 0;
+ sq.playing = 0;
#ifdef CONFIG_ATARI
- sq.ignore_int = 0;
+ sq.ignore_int = 0;
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
- sq.block_size_half = sq.block_size>>1;
- sq.block_size_quarter = sq.block_size_half>>1;
+ sq.block_size_half = sq.block_size>>1;
+ sq.block_size_quarter = sq.block_size_half>>1;
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+ cp = awacs_tx_cmds;
+ memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
+ for (i = 0; i < numBufs; ++i, ++cp) {
+ st_le32(&cp->phy_addr, virt_to_bus(buffers[i]));
+ }
+ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+ st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
+#endif /* CONFIG_PMAC */
+}
- sound_silence();
-
- /* whatever you like as startup mode for /dev/dsp,
- * (/dev/audio hasn't got a startup mode). note that
- * once changed a new open() will *not* restore these!
- */
- sound.dsp.format = AFMT_S8;
- sound.dsp.stereo = 0;
- sound.dsp.size = 8;
+static void
+init_settings(void)
+{
+ /* whatever you like as startup mode for /dev/dsp,
+ * (/dev/audio hasn't got a startup mode). note that
+ * once changed a new open() will *not* restore these!
+ */
+ sound.dsp.format = AFMT_U8;
+ sound.dsp.stereo = 0;
+ sound.dsp.size = 8;
- /* set minimum rate possible without expanding */
- switch (sound.mach.type) {
+ /* set minimum rate possible without expanding */
+ switch (sound.mach.type) {
#ifdef CONFIG_ATARI
case DMASND_TT:
- sound.dsp.speed = 6258;
- break;
+ sound.dsp.speed = 6258;
+ break;
case DMASND_FALCON:
- sound.dsp.speed = 8195;
- break;
+ sound.dsp.speed = 8195;
+ break;
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
case DMASND_AMIGA:
- sound.dsp.speed = 8000;
- break;
+ sound.dsp.speed = 8000;
+ break;
#endif /* CONFIG_AMIGA */
- }
+#ifdef CONFIG_PMAC
+ case DMASND_AWACS:
+ sound.dsp.speed = 8000;
+ break;
+#endif /* CONFIG_PMAC */
+ }
+
+ /* before the first open to /dev/dsp this wouldn't be set */
+ sound.soft = sound.dsp;
+ sound.hard = sound.dsp;
- /* before the first open to /dev/dsp this wouldn't be set */
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
+ sound_silence();
}
static void sq_play(void)
{
- (*sound.mach.play)();
+ (*sound.mach.play)();
}
static long sq_write(const char *src, unsigned long uLeft)
{
- long uWritten = 0;
- u_char *dest;
- long uUsed, bUsed, bLeft;
+ long uWritten = 0;
+ u_char *dest;
+ long uUsed, bUsed, bLeft;
- /* ++TeSche: Is something like this necessary?
- * Hey, that's an honest question! Or does any other part of the
- * filesystem already checks this situation? I really don't know.
- */
- if (uLeft == 0)
- return(0);
+ /* ++TeSche: Is something like this necessary?
+ * Hey, that's an honest question! Or does any other part of the
+ * filesystem already checks this situation? I really don't know.
+ */
+ if (uLeft == 0)
+ return(0);
- /* The interrupt doesn't start to play the last, incomplete frame.
- * Thus we can append to it without disabling the interrupts! (Note
- * also that sq.rear isn't affected by the interrupt.)
- */
-
- if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
- dest = sq_block_address(sq.rear);
- bUsed = sq.rear_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- sq.rear_size = bUsed;
- }
-
- do {
- while (sq.count == sq.max_count) {
- sq_play();
- if (NON_BLOCKING(sq.open_mode))
- return(uWritten > 0 ? uWritten : -EAGAIN);
- SLEEP(sq.write_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- return(uWritten > 0 ? uWritten : -EINTR);
- }
-
- /* Here, we can avoid disabling the interrupt by first
- * copying and translating the data, and then updating
- * the sq variables. Until this is done, the interrupt
- * won't see the new frame and we can work on it
- * undisturbed.
+ /* The interrupt doesn't start to play the last, incomplete frame.
+ * Thus we can append to it without disabling the interrupts! (Note
+ * also that sq.rear isn't affected by the interrupt.)
*/
- dest = sq_block_address((sq.rear+1) % sq.max_count);
- bUsed = 0;
- bLeft = sq.block_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- if (bUsed) {
- sq.rear = (sq.rear+1) % sq.max_count;
- sq.rear_size = bUsed;
- sq.count++;
+ if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
+ dest = sq_block_address(sq.rear);
+ bUsed = sq.rear_size;
+ uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+ if (uUsed <= 0)
+ return uUsed;
+ src += uUsed;
+ uWritten += uUsed;
+ uLeft -= uUsed;
+ sq.rear_size = bUsed;
}
- } while (bUsed); /* uUsed may have been 0 */
- sq_play();
+ do {
+ while (sq.count == sq.max_active) {
+ sq_play();
+ if (NON_BLOCKING(sq.open_mode))
+ return(uWritten > 0 ? uWritten : -EAGAIN);
+ SLEEP(sq.write_queue, ONE_SECOND);
+ if (SIGNAL_RECEIVED)
+ return(uWritten > 0 ? uWritten : -EINTR);
+ }
+
+ /* Here, we can avoid disabling the interrupt by first
+ * copying and translating the data, and then updating
+ * the sq variables. Until this is done, the interrupt
+ * won't see the new frame and we can work on it
+ * undisturbed.
+ */
+
+ dest = sq_block_address((sq.rear+1) % sq.max_count);
+ bUsed = 0;
+ bLeft = sq.block_size;
+ uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
+ if (uUsed <= 0)
+ break;
+ src += uUsed;
+ uWritten += uUsed;
+ uLeft -= uUsed;
+ if (bUsed) {
+ sq.rear = (sq.rear+1) % sq.max_count;
+ sq.rear_size = bUsed;
+ sq.count++;
+ }
+ } while (bUsed); /* uUsed may have been 0 */
- return(uWritten);
+ sq_play();
+
+ return(uUsed < 0? uUsed: uWritten);
}
static int sq_open(int open_mode)
{
- if (sq.busy) {
- if (NON_BLOCKING(open_mode))
- return(-EBUSY);
- while (sq.busy) {
- SLEEP(sq.open_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- return(-EINTR);
- }
- }
- sq.open_mode = open_mode;
- sq.busy = 1;
+ if (sq.busy) {
+ if (NON_BLOCKING(open_mode))
+ return(-EBUSY);
+ while (sq.busy) {
+ SLEEP(sq.open_queue, ONE_SECOND);
+ if (SIGNAL_RECEIVED)
+ return(-EINTR);
+ }
+ }
+ sq_init(numBufs, bufSize << 10, sound_buffers);
+ sq.open_mode = open_mode;
+ sq.busy = 1;
#ifdef CONFIG_ATARI
- sq.ignore_int = 1;
+ sq.ignore_int = 1;
#endif /* CONFIG_ATARI */
- return(0);
+ return(0);
}
static void sq_reset(void)
{
- sound_silence();
- sq.playing = 0;
- sq.count = 0;
- sq.front = (sq.rear+1) % sq.max_count;
+ sound_silence();
+ sq.playing = 0;
+ sq.count = 0;
+ sq.front = (sq.rear+1) % sq.max_count;
}
static int sq_sync(void)
{
- int rc = 0;
-
- sq.syncing = 1;
- sq_play(); /* there may be an incomplete frame waiting */
-
- while (sq.playing) {
- SLEEP(sq.sync_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED) {
- /* While waiting for audio output to drain, an interrupt occurred.
- Stop audio output immediately and clear the queue. */
- sq_reset();
- rc = -EINTR;
- break;
+ int rc = 0;
+
+ sq.syncing = 1;
+ sq_play(); /* there may be an incomplete frame waiting */
+
+ while (sq.playing) {
+ SLEEP(sq.sync_queue, ONE_SECOND);
+ if (SIGNAL_RECEIVED) {
+ /* While waiting for audio output to drain, an
+ * interrupt occurred. Stop audio output immediately
+ * and clear the queue. */
+ sq_reset();
+ rc = -EINTR;
+ break;
+ }
}
- }
- sq.syncing = 0;
- return(rc);
+ sq.syncing = 0;
+ return(rc);
}
static int sq_release(void)
{
- int rc = 0;
- if (sq.busy) {
- rc = sq_sync();
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- /* Wake up a process waiting for the queue being released.
- Note: There may be several processes waiting for a call to open()
- returning. */
- }
- return(rc);
+ int rc = 0;
+ if (sq.busy) {
+ rc = sq_sync();
+ sq.busy = 0;
+ WAKE_UP(sq.open_queue);
+ /* Wake up a process waiting for the queue being released.
+ * Note: There may be several processes waiting for a call
+ * to open() returning. */
+ }
+ return(rc);
}
static void state_init(void)
{
- state.busy = 0;
+ state.busy = 0;
}
static int state_open(int open_mode)
{
- char *buffer = state.buf, *mach = "";
- int len = 0;
+ char *buffer = state.buf, *mach = "";
+ int len = 0;
- if (state.busy)
- return(-EBUSY);
+ if (state.busy)
+ return(-EBUSY);
- state.ptr = 0;
- state.busy = 1;
+ state.ptr = 0;
+ state.busy = 1;
- switch (sound.mach.type) {
+ switch (sound.mach.type) {
#ifdef CONFIG_ATARI
case DMASND_TT:
case DMASND_FALCON:
- mach = "Atari ";
- break;
+ mach = "Atari ";
+ break;
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
case DMASND_AMIGA:
- mach = "Amiga ";
- break;
+ mach = "Amiga ";
+ break;
#endif /* CONFIG_AMIGA */
- }
- len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
+#ifdef CONFIG_PMAC
+ case DMASND_AWACS:
+ mach = "PowerMac ";
+ break;
+#endif /* CONFIG_PMAC */
+ }
+ len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
- len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
- switch (sound.soft.format) {
+ len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
+ switch (sound.soft.format) {
case AFMT_MU_LAW:
- len += sprintf(buffer+len, " (mu-law)");
- break;
+ len += sprintf(buffer+len, " (mu-law)");
+ break;
case AFMT_A_LAW:
- len += sprintf(buffer+len, " (A-law)");
- break;
+ len += sprintf(buffer+len, " (A-law)");
+ break;
case AFMT_U8:
- len += sprintf(buffer+len, " (unsigned 8 bit)");
- break;
+ len += sprintf(buffer+len, " (unsigned 8 bit)");
+ break;
case AFMT_S8:
- len += sprintf(buffer+len, " (signed 8 bit)");
- break;
+ len += sprintf(buffer+len, " (signed 8 bit)");
+ break;
case AFMT_S16_BE:
- len += sprintf(buffer+len, " (signed 16 bit big)");
- break;
+ len += sprintf(buffer+len, " (signed 16 bit big)");
+ break;
case AFMT_U16_BE:
- len += sprintf(buffer+len, " (unsigned 16 bit big)");
- break;
+ len += sprintf(buffer+len, " (unsigned 16 bit big)");
+ break;
case AFMT_S16_LE:
- len += sprintf(buffer+len, " (signed 16 bit little)");
- break;
+ len += sprintf(buffer+len, " (signed 16 bit little)");
+ break;
case AFMT_U16_LE:
- len += sprintf(buffer+len, " (unsigned 16 bit little)");
- break;
- }
- len += sprintf(buffer+len, "\n");
- len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
- sound.soft.speed, sound.hard.speed);
- len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
- sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
- switch (sound.mach.type) {
+ len += sprintf(buffer+len, " (unsigned 16 bit little)");
+ break;
+ }
+ len += sprintf(buffer+len, "\n");
+ len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+ sound.soft.speed, sound.hard.speed);
+ len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+ sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
+ switch (sound.mach.type) {
#ifdef CONFIG_ATARI
case DMASND_TT:
- len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
- sound.volume_right);
- len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
- sound.bass);
- len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
- sound.treble);
- break;
+ len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+ sound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+ sound.volume_right);
+ len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+ sound.bass);
+ len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+ sound.treble);
+ break;
case DMASND_FALCON:
- len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
- sound.volume_right);
- break;
+ len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+ sound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+ sound.volume_right);
+ break;
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
case DMASND_AMIGA:
- len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
- sound.volume_right);
- break;
+ len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
+ sound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
+ sound.volume_right);
+ break;
#endif /* CONFIG_AMIGA */
- }
- len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n",
- sq.block_size, sq.max_count);
- len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
- sq.rear_size);
- len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
- sq.playing, sq.syncing);
- state.len = len;
- return(0);
+ }
+ len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
+ " sq.max_active = %d\n",
+ sq.block_size, sq.max_count, sq.max_active);
+ len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
+ sq.rear_size);
+ len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
+ sq.playing, sq.syncing);
+ state.len = len;
+ return(0);
}
static int state_release(void)
{
- state.busy = 0;
- return(0);
+ state.busy = 0;
+ return(0);
}
static long state_read(char *dest, unsigned long count)
{
- int n = state.len-state.ptr;
- if (n > count)
- n = count;
- if (n <= 0)
- return(0);
- copy_to_user(dest, &state.buf[state.ptr], n);
- state.ptr += n;
- return(n);
+ int n = state.len-state.ptr;
+ if (n > count)
+ n = count;
+ if (n <= 0)
+ return(0);
+ if (copy_to_user(dest, &state.buf[state.ptr], n))
+ return -EFAULT;
+ state.ptr += n;
+ return(n);
}
static int sound_open(struct inode *inode, struct file *file)
{
- int dev = MINOR(inode->i_rdev) & 0x0f;
- int rc = 0;
+ int dev = MINOR(inode->i_rdev) & 0x0f;
+ int rc = 0;
- switch (dev) {
+ switch (dev) {
case SND_DEV_STATUS:
- rc = state_open(file->f_flags);
- break;
+ rc = state_open(file->f_flags);
+ break;
case SND_DEV_CTL:
- rc = mixer_open(file->f_flags);
- break;
+ rc = mixer_open(file->f_flags);
+ break;
case SND_DEV_DSP:
case SND_DEV_AUDIO:
- rc = sq_open(file->f_flags);
- if (rc == 0) {
- sound.minDev = dev;
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_init();
- if (dev == SND_DEV_AUDIO) {
- sound_set_speed(8000);
- sound_set_stereo(0);
- sound_set_format(AFMT_MU_LAW);
- }
- }
- break;
+ rc = sq_open(file->f_flags);
+ if (rc == 0) {
+ sound.minDev = dev;
+ sound.soft = sound.dsp;
+ sound.hard = sound.dsp;
+ sound_init();
+ if (dev == SND_DEV_AUDIO) {
+ sound_set_speed(8000);
+ sound_set_stereo(0);
+ sound_set_format(AFMT_MU_LAW);
+ }
+ }
+ break;
default:
- rc = -ENXIO;
- }
+ rc = -ENXIO;
+ }
#ifdef MODULE
- if (rc >= 0)
- MOD_INC_USE_COUNT;
+ if (rc >= 0)
+ MOD_INC_USE_COUNT;
#endif
- return(rc);
+ return(rc);
}
static int sound_fsync(struct file *filp, struct dentry *dentry)
{
- int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f;
+ int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f;
- switch (dev) {
+ switch (dev) {
case SND_DEV_STATUS:
case SND_DEV_CTL:
- return(0);
+ return(0);
case SND_DEV_DSP:
case SND_DEV_AUDIO:
- return(sq_sync());
+ return(sq_sync());
default:
- return(unknown_minor_dev("sound_fsync", dev));
- }
+ return(unknown_minor_dev("sound_fsync", dev));
+ }
}
static int sound_release(struct inode *inode, struct file *file)
{
- int dev = MINOR(inode->i_rdev);
+ int dev = MINOR(inode->i_rdev);
- switch (dev & 0x0f) {
+ switch (dev & 0x0f) {
case SND_DEV_STATUS:
- state_release();
- break;
+ state_release();
+ break;
case SND_DEV_CTL:
- mixer_release();
- break;
+ mixer_release();
+ break;
case SND_DEV_DSP:
case SND_DEV_AUDIO:
- sq_release();
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_silence();
- break;
+ sq_release();
+ sound.soft = sound.dsp;
+ sound.hard = sound.dsp;
+ sound_silence();
+ break;
default:
- return unknown_minor_dev("sound_release", dev);
- }
+ return unknown_minor_dev("sound_release", dev);
+ }
#ifdef MODULE
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
#endif
- return 0;
+ return 0;
}
static long long sound_lseek(struct file *file, long long offset, int orig)
{
- return -ESPIPE;
+ return -ESPIPE;
}
static ssize_t sound_read(struct file *file, char *buf, size_t count,
loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
- int dev = MINOR(inode->i_rdev);
+ struct inode *inode = file->f_dentry->d_inode;
+ int dev = MINOR(inode->i_rdev);
- switch (dev & 0x0f) {
+ switch (dev & 0x0f) {
case SND_DEV_STATUS:
- return(state_read(buf, count));
+ return(state_read(buf, count));
case SND_DEV_CTL:
case SND_DEV_DSP:
case SND_DEV_AUDIO:
- return(-EPERM);
+ return(-EPERM);
default:
- return(unknown_minor_dev("sound_read", dev));
- }
+ return(unknown_minor_dev("sound_read", dev));
+ }
}
static ssize_t sound_write(struct file *file, const char *buf, size_t count,
loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
- int dev = MINOR(inode->i_rdev);
+ struct inode *inode = file->f_dentry->d_inode;
+ int dev = MINOR(inode->i_rdev);
- switch (dev & 0x0f) {
+ switch (dev & 0x0f) {
case SND_DEV_STATUS:
case SND_DEV_CTL:
- return(-EPERM);
+ return(-EPERM);
case SND_DEV_DSP:
case SND_DEV_AUDIO:
- return(sq_write(buf, count));
+ return(sq_write(buf, count));
default:
- return(unknown_minor_dev("sound_write", dev));
- }
+ return(unknown_minor_dev("sound_write", dev));
+ }
}
static int unknown_minor_dev(char *fname, int dev)
{
- /* printk("%s: Unknown minor device %d\n", fname, dev); */
- return(-ENXIO);
+ /* printk("%s: Unknown minor device %d\n", fname, dev); */
+ return(-ENXIO);
}
static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg)
{
- int dev = MINOR(inode->i_rdev);
- u_long fmt;
- int data;
+ int dev = MINOR(inode->i_rdev);
+ u_long fmt;
+ int data;
+ int size, nbufs;
- switch (dev & 0x0f) {
+ switch (dev & 0x0f) {
case SND_DEV_STATUS:
- return(-EPERM);
+ return(-EPERM);
case SND_DEV_CTL:
- return(mixer_ioctl(inode, file, cmd, arg));
+ return(mixer_ioctl(inode, file, cmd, arg));
case SND_DEV_AUDIO:
case SND_DEV_DSP:
- switch (cmd) {
+ switch (cmd) {
case SNDCTL_DSP_RESET:
- sq_reset();
- return(0);
+ sq_reset();
+ return(0);
case SNDCTL_DSP_POST:
case SNDCTL_DSP_SYNC:
- return(sound_fsync(file, file->f_dentry));
+ return(sound_fsync(file, file->f_dentry));
- /* ++TeSche: before changing any of these it's probably wise to
- * wait until sound playing has settled down
- */
+ /* ++TeSche: before changing any of these it's
+ * probably wise to wait until sound playing has
+ * settled down. */
case SNDCTL_DSP_SPEED:
- sound_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_speed(data)));
+ sound_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_speed(data)));
case SNDCTL_DSP_STEREO:
- sound_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_stereo(data)));
+ sound_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_stereo(data)));
case SOUND_PCM_WRITE_CHANNELS:
- sound_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1));
+ sound_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1));
case SNDCTL_DSP_SETFMT:
- sound_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return(IOCTL_OUT(arg, sound_set_format(data)));
+ sound_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_format(data)));
case SNDCTL_DSP_GETFMTS:
- fmt = 0;
- if (sound.trans) {
- if (sound.trans->ct_ulaw)
- fmt |= AFMT_MU_LAW;
- if (sound.trans->ct_alaw)
- fmt |= AFMT_A_LAW;
- if (sound.trans->ct_s8)
- fmt |= AFMT_S8;
- if (sound.trans->ct_u8)
- fmt |= AFMT_U8;
- if (sound.trans->ct_s16be)
- fmt |= AFMT_S16_BE;
- if (sound.trans->ct_u16be)
- fmt |= AFMT_U16_BE;
- if (sound.trans->ct_s16le)
- fmt |= AFMT_S16_LE;
- if (sound.trans->ct_u16le)
- fmt |= AFMT_U16_LE;
- }
- return(IOCTL_OUT(arg, fmt));
+ fmt = 0;
+ if (sound.trans) {
+ if (sound.trans->ct_ulaw)
+ fmt |= AFMT_MU_LAW;
+ if (sound.trans->ct_alaw)
+ fmt |= AFMT_A_LAW;
+ if (sound.trans->ct_s8)
+ fmt |= AFMT_S8;
+ if (sound.trans->ct_u8)
+ fmt |= AFMT_U8;
+ if (sound.trans->ct_s16be)
+ fmt |= AFMT_S16_BE;
+ if (sound.trans->ct_u16be)
+ fmt |= AFMT_U16_BE;
+ if (sound.trans->ct_s16le)
+ fmt |= AFMT_S16_LE;
+ if (sound.trans->ct_u16le)
+ fmt |= AFMT_U16_LE;
+ }
+ return(IOCTL_OUT(arg, fmt));
case SNDCTL_DSP_GETBLKSIZE:
- return(IOCTL_OUT(arg, 10240));
+ size = sq.block_size
+ * sound.soft.size * (sound.soft.stereo + 1)
+ / (sound.hard.size * (sound.hard.stereo + 1));
+ return(IOCTL_OUT(arg, size));
case SNDCTL_DSP_SUBDIVIDE:
+ break;
case SNDCTL_DSP_SETFRAGMENT:
- break;
+ if (sq.count || sq.playing || sq.syncing)
+ return -EINVAL;
+ IOCTL_IN(arg, size);
+ nbufs = size >> 16;
+ if (nbufs < 2 || nbufs > numBufs)
+ nbufs = numBufs;
+ size &= 0xffff;
+ if (size >= 8 && size <= 30) {
+ size = 1 << size;
+ size *= sound.hard.size * (sound.hard.stereo + 1);
+ size /= sound.soft.size * (sound.soft.stereo + 1);
+ if (size > (bufSize << 10))
+ size = bufSize << 10;
+ } else
+ size = bufSize << 10;
+ sq_init(numBufs, size, sound_buffers);
+ sq.max_active = nbufs;
+ break;
default:
- return(mixer_ioctl(inode, file, cmd, arg));
- }
- break;
+ return(mixer_ioctl(inode, file, cmd, arg));
+ }
+ break;
default:
- return(unknown_minor_dev("sound_ioctl", dev));
- }
- return(-EINVAL);
+ return(unknown_minor_dev("sound_ioctl", dev));
+ }
+ return(-EINVAL);
}
static struct file_operations sound_fops =
{
- sound_lseek,
- sound_read,
- sound_write,
- NULL,
- NULL, /* select */
- sound_ioctl,
- NULL,
- sound_open,
- sound_release,
- sound_fsync
+ sound_lseek,
+ sound_read,
+ sound_write,
+ NULL,
+ NULL, /* select */
+ sound_ioctl,
+ NULL,
+ sound_open,
+ sound_release,
+ sound_fsync
};
void soundcard_init(void)
{
- int has_sound = 0;
- int i;
+ int has_sound = 0;
+ int i;
- switch (m68k_machtype) {
+#ifdef __mc68000__
+ switch (m68k_machtype) {
#ifdef CONFIG_ATARI
case MACH_ATARI:
- if (ATARIHW_PRESENT(PCM_8BIT)) {
- if (ATARIHW_PRESENT(CODEC))
- sound.mach = machFalcon;
- else if (ATARIHW_PRESENT(MICROWIRE))
- sound.mach = machTT;
- else
- break;
- if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
- has_sound = 1;
- else
- printk("DMA sound driver: Timer A interrupt already in use\n");
- }
- break;
+ if (ATARIHW_PRESENT(PCM_8BIT)) {
+ if (ATARIHW_PRESENT(CODEC))
+ sound.mach = machFalcon;
+ else if (ATARIHW_PRESENT(MICROWIRE))
+ sound.mach = machTT;
+ else
+ break;
+ if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+ has_sound = 1;
+ else
+ printk("DMA sound driver: Timer A interrupt already in use\n");
+ }
+ break;
#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
case MACH_AMIGA:
- if (AMIGAHW_PRESENT(AMI_AUDIO)) {
- sound.mach = machAmiga;
- has_sound = 1;
- }
- break;
+ if (AMIGAHW_PRESENT(AMI_AUDIO)) {
+ sound.mach = machAmiga;
+ has_sound = 1;
+ }
+ break;
#endif /* CONFIG_AMIGA */
- }
- if (!has_sound)
- return;
+ }
+#endif /* __mc68000__ */
- /* Set up sound queue, /dev/audio and /dev/dsp. */
- sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_buffers) {
-out_of_memory:
- printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
- return;
- }
- for (i = 0; i < numBufs; i++) {
- sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
- if (!sound_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- goto out_of_memory;
- }
- }
+#ifdef CONFIG_PMAC
+ struct device_node *np;
+
+ np = find_devices("awacs");
+ if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
+ int vol;
+ sound.mach = machPMac;
+ has_sound = 1;
+ awacs = (volatile struct awacs_regs *)
+ ioremap(np->addrs[0].address, 0x80);
+ awacs_txdma = (volatile struct dbdma_regs *)
+ ioremap(np->addrs[1].address, 0x100);
+ awacs_rxdma = (volatile struct dbdma_regs *)
+ ioremap(np->addrs[2].address, 0x100);
+ awacs_irq = np->intrs[0].line;
+ awacs_tx_irq = np->intrs[1].line;
+ awacs_rx_irq = np->intrs[2].line;
+ awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd),
+ GFP_KERNEL);
+ if (awacs_tx_cmd_space == NULL)
+ goto out_of_memory;
+ awacs_tx_cmds = (volatile struct dbdma_cmd *)
+ DBDMA_ALIGN(awacs_tx_cmd_space);
+ awacs_reg[0] = MASK_MUX_CD;
+ awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
+ /* get default volume from nvram */
+ vol = (~nvram_read_byte(0x1308) & 7) << 1;
+ awacs_reg[2] = vol + (vol << 6);
+ awacs_reg[4] = vol + (vol << 6);
+ awacs_write(awacs_reg[0] + MASK_ADDR0);
+ awacs_write(awacs_reg[1] + MASK_ADDR1);
+ awacs_write(awacs_reg[2] + MASK_ADDR2);
+ awacs_write(awacs_reg[4] + MASK_ADDR4);
+
+ /* Initialize beep stuff */
+ beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1);
+ orig_mksound = kd_mksound;
+ kd_mksound = awacs_mksound;
+ beep_buf = (short *) kmalloc(BEEP_BUFLEN * 2, GFP_KERNEL);
+ if (beep_buf == NULL)
+ printk(KERN_WARNING "dmasound: no memory for "
+ "beep buffer\n");
+#ifdef CONFIG_PMAC_PBOOK
+ notifier_chain_register(&sleep_notifier_list,
+ &awacs_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+ }
+#endif /* CONFIG_PMAC */
+
+ if (!has_sound)
+ return;
+
+ /* Set up sound queue, /dev/audio and /dev/dsp. */
+ sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
+ if (!sound_buffers) {
+ out_of_memory:
+ printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
+ return;
+ }
+ for (i = 0; i < numBufs; i++) {
+ sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
+ if (!sound_buffers[i]) {
+ while (i--)
+ sound.mach.dma_free (sound_buffers[i], bufSize << 10);
+ kfree (sound_buffers);
+ sound_buffers = 0;
+ goto out_of_memory;
+ }
+ }
#ifndef MODULE
- /* Register driver with the VFS. */
- register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+ /* Register driver with the VFS. */
+ register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
#endif
- sq_init(numBufs, bufSize << 10, sound_buffers);
+ sq_init(numBufs, bufSize << 10, sound_buffers);
- /* Set up /dev/sndstat. */
- state_init();
+ /* Set default settings. */
+ init_settings();
- /* Set up /dev/mixer. */
- mixer_init();
+ /* Set up /dev/sndstat. */
+ state_init();
- if (!sound.mach.irqinit()) {
- printk("DMA sound driver: Interrupt initialization failed\n");
- return;
- }
+ /* Set up /dev/mixer. */
+ mixer_init();
+
+ if (!sound.mach.irqinit()) {
+ printk("DMA sound driver: Interrupt initialization failed\n");
+ return;
+ }
#ifdef MODULE
- irq_installed = 1;
+ irq_installed = 1;
#endif
- printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
- bufSize);
+ printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
+ bufSize);
- return;
+ return;
}
void sound_setup(char *str, int *ints)
{
- /* ++Martin: stub, could possibly be merged with soundcard.c et al later */
+ /* ++Martin: stub, could possibly be merged with soundcard.c et al later */
}
void dmasound_setup(char *str, int *ints)
{
- /* check the bootstrap parameter for "dmasound=" */
+ /* check the bootstrap parameter for "dmasound=" */
- switch (ints[0]) {
+ switch (ints[0]) {
case 3:
- if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
- printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
- else
- catchRadius = ints[3];
- /* fall through */
+ if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+ printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+ else
+ catchRadius = ints[3];
+ /* fall through */
case 2:
- if (ints[1] < MIN_BUFFERS)
- printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
- else
- numBufs = ints[1];
- if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
- printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
- else
- bufSize = ints[2];
- break;
+ if (ints[1] < MIN_BUFFERS)
+ printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
+ else
+ numBufs = ints[1];
+ if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+ printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
+ else
+ bufSize = ints[2];
+ break;
case 0:
- break;
+ break;
default:
- printk("dmasound_setup: illegal number of arguments\n");
- }
+ printk("dmasound_setup: illegal number of arguments\n");
+ }
}
int init_module(void)
{
- int err, i = 0;
- int ints[MAXARGS+1];
+ int err, i = 0;
+ int ints[MAXARGS+1];
- while (i < MAXARGS && dmasound[i])
- ints[i + 1] = dmasound[i++];
- ints[0] = i;
+ while (i < MAXARGS && dmasound[i])
+ ints[i + 1] = dmasound[i++];
+ ints[0] = i;
- if (i)
- dmasound_setup("dmasound=", ints);
+ if (i)
+ dmasound_setup("dmasound=", ints);
- err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
- if (err) {
- printk("dmasound: driver already loaded/included in kernel\n");
- return err;
- }
- chrdev_registered = 1;
- soundcard_init();
+ err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+ if (err) {
+ printk("dmasound: driver already loaded/included in kernel\n");
+ return err;
+ }
+ chrdev_registered = 1;
+ soundcard_init();
- return 0;
+ return 0;
}
void cleanup_module(void)
{
- int i;
+ int i;
- if (MOD_IN_USE)
- return;
+ if (MOD_IN_USE)
+ return;
- if (chrdev_registered)
- unregister_chrdev(SOUND_MAJOR, "sound");
+ if (chrdev_registered)
+ unregister_chrdev(SOUND_MAJOR, "sound");
- if (irq_installed) {
- sound_silence();
- sound.mach.irqcleanup();
- }
-
- if (sound_buffers) {
- for (i = 0; i < numBufs; i++)
- sound.mach.dma_free(sound_buffers[i], bufSize << 10);
- kfree(sound_buffers);
- }
+ if (irq_installed) {
+ sound_silence();
+ sound.mach.irqcleanup();
+ }
+
+ if (sound_buffers) {
+ for (i = 0; i < numBufs; i++)
+ sound.mach.dma_free(sound_buffers[i], bufSize << 10);
+ kfree(sound_buffers);
+ }
}
#endif /* MODULE */
if ((gus_mem_size > 0) & !gus_no_wave_dma)
{
- if ((dev = sound_alloc_audiodev()) != -1)
+ hw_config->slots[4] = -1;
+ if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
+ "Ultrasound",
+ &gus_audio_driver,
+ sizeof(struct audio_driver),
+ NEEDS_RESTART |
+ ((!iw_mode && dma2 != dma && dma2 != -1) ?
+ DMA_DUPLEX : 0),
+ AFMT_U8 | AFMT_S16_LE,
+ NULL, dma, dma2)) < 0)
{
- hw_config->slots[4] = dev;
- if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
- "Ultrasound",
- &gus_audio_driver,
- sizeof(struct audio_driver),
- NEEDS_RESTART |
- ((!iw_mode && dma2 != dma && dma2 != -1) ?
- DMA_DUPLEX : 0),
- AFMT_U8 | AFMT_S16_LE,
- NULL,
- dma,
- dma2)) < 0)
- {
- return;
- }
+ return;
+ }
- audio_devs[gus_devnum]->min_fragment = 9; /* 512k */
- audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */
- audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */
- audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
- } else
- printk(KERN_WARNING "GUS: Too many audio devices available\n");
+ audio_devs[gus_devnum]->min_fragment = 9; /* 512k */
+ audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */
+ audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */
+ audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
}
/*
--- /dev/null
+/*********************************************************************
+ *
+ * msnd.c - Driver Base
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+#include "msnd.h"
+
+#define LOGNAME "msnd"
+
+#define MSND_MAX_DEVS 4
+
+static multisound_dev_t *devs[MSND_MAX_DEVS];
+static int num_devs;
+
+int msnd_register(multisound_dev_t *dev)
+{
+ int i;
+
+ for (i = 0; i < MSND_MAX_DEVS; ++i)
+ if (devs[i] == NULL)
+ break;
+
+ if (i == MSND_MAX_DEVS)
+ return -ENOMEM;
+
+ devs[i] = dev;
+ ++num_devs;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+void msnd_unregister(multisound_dev_t *dev)
+{
+ int i;
+
+ for (i = 0; i < MSND_MAX_DEVS; ++i)
+ if (devs[i] == dev)
+ break;
+
+ if (i == MSND_MAX_DEVS) {
+ printk(KERN_WARNING LOGNAME ": Unregistering unknown device\n");
+ return;
+ }
+
+ devs[i] = NULL;
+ --num_devs;
+
+ MOD_DEC_USE_COUNT;
+}
+
+int msnd_get_num_devs(void)
+{
+ return num_devs;
+}
+
+multisound_dev_t *msnd_get_dev(int j)
+{
+ int i;
+
+ for (i = 0; i < MSND_MAX_DEVS && j; ++i)
+ if (devs[i] != NULL)
+ --j;
+
+ if (i == MSND_MAX_DEVS || j != 0)
+ return NULL;
+
+ return devs[i];
+}
+
+void msnd_fifo_init(msnd_fifo *f)
+{
+ f->data = NULL;
+}
+
+void msnd_fifo_free(msnd_fifo *f)
+{
+ if (f->data) {
+ vfree(f->data);
+ f->data = NULL;
+ }
+}
+
+int msnd_fifo_alloc(msnd_fifo *f, size_t n)
+{
+ msnd_fifo_free(f);
+ f->data = (char *)vmalloc(n);
+ f->n = n;
+ f->tail = 0;
+ f->head = 0;
+ f->len = 0;
+
+ if (!f->data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void msnd_fifo_make_empty(msnd_fifo *f)
+{
+ f->len = f->tail = f->head = 0;
+}
+
+int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user)
+{
+ int count = 0;
+
+ if (f->len == f->n)
+ return 0;
+
+ while ((count < len) && (f->len != f->n)) {
+
+ int nwritten;
+
+ if (f->head <= f->tail) {
+ nwritten = len - count;
+ if (nwritten > f->n - f->tail)
+ nwritten = f->n - f->tail;
+ }
+ else {
+ nwritten = f->head - f->tail;
+ if (nwritten > len - count)
+ nwritten = len - count;
+ }
+
+ if (user) {
+ if (copy_from_user(f->data + f->tail, buf, nwritten))
+ return -EFAULT;
+ } else
+ memcpy(f->data + f->tail, buf, nwritten);
+
+ count += nwritten;
+ buf += nwritten;
+ f->len += nwritten;
+ f->tail += nwritten;
+ f->tail %= f->n;
+ }
+
+ return count;
+}
+
+int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
+{
+ int count = 0;
+
+ if (f->len == 0)
+ return f->len;
+
+ while ((count < len) && (f->len > 0)) {
+
+ int nread;
+
+ if (f->tail <= f->head) {
+ nread = len - count;
+ if (nread > f->n - f->head)
+ nread = f->n - f->head;
+ }
+ else {
+ nread = f->tail - f->head;
+ if (nread > len - count)
+ nread = len - count;
+ }
+
+ if (user) {
+ if (copy_to_user(buf, f->data + f->head, nread))
+ return -EFAULT;
+ } else
+ memcpy(buf, f->data + f->head, nread);
+
+ count += nread;
+ buf += nread;
+ f->len -= nread;
+ f->head += nread;
+ f->head %= f->n;
+ }
+
+ return count;
+}
+
+int msnd_wait_TXDE(multisound_dev_t *dev)
+{
+ register unsigned int io = dev->io;
+ register int timeout = 5000;
+
+ while(timeout-- > 0)
+ if (inb(io + HP_ISR) & HPISR_TXDE)
+ return 0;
+
+ return -EIO;
+}
+
+int msnd_wait_HC0(multisound_dev_t *dev)
+{
+ register unsigned int io = dev->io;
+ register int timeout = 25000;
+
+ while(timeout-- > 0)
+ if (!(inb(io + HP_CVR) & HPCVR_HC))
+ return 0;
+
+ return -EIO;
+}
+
+int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (msnd_wait_HC0(dev) == 0) {
+
+ outb(cmd, dev->io + HP_CVR);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ printk(KERN_WARNING LOGNAME ": Send DSP command timeout\n");
+
+ return -EIO;
+}
+
+int msnd_send_word(multisound_dev_t *dev, unsigned char high,
+ unsigned char mid, unsigned char low)
+{
+ register unsigned int io = dev->io;
+
+ if (msnd_wait_TXDE(dev) == 0) {
+
+ outb(high, io + HP_TXH);
+ outb(mid, io + HP_TXM);
+ outb(low, io + HP_TXL);
+ return 0;
+ }
+
+ printk(KERN_WARNING LOGNAME ": Send host word timeout\n");
+
+ return -EIO;
+}
+
+int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
+{
+ int i;
+
+ if (len % 3 != 0) {
+
+ printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i += 3)
+ if (msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0)
+ return -EIO;
+
+ inb(dev->io + HP_RXL);
+ inb(dev->io + HP_CVR);
+
+ return 0;
+}
+
+int msnd_enable_irq(multisound_dev_t *dev)
+{
+ printk(KERN_INFO LOGNAME ": enable_irq: count %d\n", dev->irq_ref);
+
+ if (dev->irq_ref++ != 0)
+ return 0;
+
+ printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
+
+ if (msnd_wait_TXDE(dev) == 0) {
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
+
+ if (dev->type == msndClassic)
+ outb(dev->irqid, dev->io + HP_IRQM);
+
+ outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
+ outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return 0;
+ }
+
+ return -EIO;
+}
+
+int msnd_disable_irq(multisound_dev_t *dev)
+{
+ unsigned long flags;
+
+ printk(KERN_DEBUG LOGNAME ": disable_irq: count %d\n", dev->irq_ref);
+
+ if (--dev->irq_ref > 0)
+ return 0;
+
+ if (dev->irq_ref < 0)
+ dev->irq_ref = 0;
+
+ printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+ outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+
+ if (dev->type == msndClassic)
+ outb(HPIRQ_NONE, dev->io + HP_IRQM);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(msnd_register);
+EXPORT_SYMBOL(msnd_unregister);
+EXPORT_SYMBOL(msnd_get_num_devs);
+EXPORT_SYMBOL(msnd_get_dev);
+
+EXPORT_SYMBOL(msnd_fifo_init);
+EXPORT_SYMBOL(msnd_fifo_free);
+EXPORT_SYMBOL(msnd_fifo_alloc);
+EXPORT_SYMBOL(msnd_fifo_make_empty);
+EXPORT_SYMBOL(msnd_fifo_write);
+EXPORT_SYMBOL(msnd_fifo_read);
+
+EXPORT_SYMBOL(msnd_wait_TXDE);
+EXPORT_SYMBOL(msnd_wait_HC0);
+EXPORT_SYMBOL(msnd_send_dsp_cmd);
+EXPORT_SYMBOL(msnd_send_word);
+EXPORT_SYMBOL(msnd_upload_host);
+
+EXPORT_SYMBOL(msnd_enable_irq);
+EXPORT_SYMBOL(msnd_disable_irq);
+
+#ifdef MODULE
+MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION ("Turtle Beach MultiSound Driver Base");
+
+int init_module(void)
+{
+ return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif
--- /dev/null
+/*********************************************************************
+ *
+ * msnd.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_H
+#define __MSND_H
+
+#define VERSION "0.6"
+
+#define DEFSAMPLERATE 44100
+#define DEFSAMPLESIZE 16
+#define DEFCHANNELS 2
+
+#define DEFFIFOSIZE 64
+
+#define SNDCARD_MSND 38
+
+#define SRAM_BANK_SIZE 0x8000
+#define SRAM_CNTL_START 0x7F00
+
+#define DSP_BASE_ADDR 0x4000
+#define DSP_BANK_BASE 0x4000
+
+#define HP_ICR 0x00
+#define HP_CVR 0x01
+#define HP_ISR 0x02
+#define HP_IVR 0x03
+#define HP_NU 0x04
+#define HP_INFO 0x04
+#define HP_TXH 0x05
+#define HP_RXH 0x05
+#define HP_TXM 0x06
+#define HP_RXM 0x06
+#define HP_TXL 0x07
+#define HP_RXL 0x07
+
+#define HP_ICR_DEF 0x00
+#define HP_CVR_DEF 0x12
+#define HP_ISR_DEF 0x06
+#define HP_IVR_DEF 0x0f
+#define HP_NU_DEF 0x00
+
+#define HP_IRQM 0x09
+
+#define HPR_BLRC 0x08
+#define HPR_SPR1 0x09
+#define HPR_SPR2 0x0A
+#define HPR_TCL0 0x0B
+#define HPR_TCL1 0x0C
+#define HPR_TCL2 0x0D
+#define HPR_TCL3 0x0E
+#define HPR_TCL4 0x0F
+
+#define HPICR_INIT 0x80
+#define HPICR_HM1 0x40
+#define HPICR_HM0 0x20
+#define HPICR_HF1 0x10
+#define HPICR_HF0 0x08
+#define HPICR_TREQ 0x02
+#define HPICR_RREQ 0x01
+
+#define HPCVR_HC 0x80
+
+#define HPISR_HREQ 0x80
+#define HPISR_DMA 0x40
+#define HPISR_HF3 0x10
+#define HPISR_HF2 0x08
+#define HPISR_TRDY 0x04
+#define HPISR_TXDE 0x02
+#define HPISR_RXDF 0x01
+
+#define HPIO_290 0
+#define HPIO_260 1
+#define HPIO_250 2
+#define HPIO_240 3
+#define HPIO_230 4
+#define HPIO_220 5
+#define HPIO_210 6
+#define HPIO_3E0 7
+
+#define HPMEM_NONE 0
+#define HPMEM_B000 1
+#define HPMEM_C800 2
+#define HPMEM_D000 3
+#define HPMEM_D400 4
+#define HPMEM_D800 5
+#define HPMEM_E000 6
+#define HPMEM_E800 7
+
+#define HPIRQ_NONE 0
+#define HPIRQ_5 1
+#define HPIRQ_7 2
+#define HPIRQ_9 3
+#define HPIRQ_10 4
+#define HPIRQ_11 5
+#define HPIRQ_12 6
+#define HPIRQ_15 7
+
+#define HIMT_PLAY_DONE 0x00
+#define HIMT_RECORD_DONE 0x01
+#define HIMT_MIDI_EOS 0x02
+#define HIMT_MIDI_OUT 0x03
+
+#define HIMT_MIDI_IN_UCHAR 0x0E
+#define HIMT_DSP 0x0F
+
+#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF ))
+#define LOWORD(l) ((WORD)(DWORD)(l))
+#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8 ) & 0xFF ))
+#define LOBYTE(w) ((BYTE)(w))
+#define MAKELONG(low,hi) ((long)(((WORD)(low))|(((DWORD)((WORD)(hi)))<<16)))
+#define MAKEWORD(low,hi) ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8)))
+
+#define PCTODSP_OFFSET(w) (USHORT)((w)/2)
+#define PCTODSP_BASED(w) (USHORT)(((w)/2) + DSP_BASE_ADDR)
+
+#ifdef SLOWIO
+# define outb outb_p
+# define inb inb_p
+#endif
+
+typedef unsigned char BYTE;
+typedef unsigned short USHORT;
+typedef unsigned short WORD;
+typedef unsigned int DWORD;
+typedef
+struct DAQueueDataStruct * LPDAQD;
+
+#define GCC_PACKED __attribute__ ((packed))
+
+struct JobQueueStruct {
+ WORD wStart;
+ WORD wSize;
+ WORD wHead;
+ WORD wTail;
+} GCC_PACKED;
+
+struct DAQueueDataStruct {
+ WORD wStart;
+ WORD wSize;
+ WORD wFormat;
+ WORD wSampleSize;
+ WORD wChannels;
+ WORD wSampleRate;
+ WORD wIntMsg;
+ WORD wFlags;
+} GCC_PACKED;
+
+typedef struct {
+ size_t n, len;
+ char *data;
+ int head, tail;
+} msnd_fifo;
+
+typedef struct multisound_dev {
+
+ char *name;
+ int dsp_minor, mixer_minor;
+
+ /* Hardware resources */
+ unsigned int io, numio;
+ int memid, irqid;
+ int irq, irq_ref;
+ unsigned char info;
+ char *base;
+ spinlock_t lock;
+
+ /* MultiSound DDK variables */
+ enum { msndClassic, msndPinnacle } type;
+ struct SMA0_CommonData *SMA; /* diff. structure for classic vs. pinnacle */
+ struct DAQueueDataStruct *CurDAQD;
+ struct DAQueueDataStruct *CurDARQD;
+ WORD *pwDSPQData , *pwMIDQData , *pwMODQData;
+ struct JobQueueStruct *DAPQ , *DARQ , *MODQ , *MIDQ , *DSPQ;
+
+ /* State variables */
+ mode_t mode;
+ unsigned long flags;
+#define F_BANKONE 0
+#define F_INTERRUPT 1
+#define F_WRITING 2
+#define F_WRITEBLOCK 3
+#define F_READING 4
+#define F_READBLOCK 5
+#define F_AUDIO_INUSE 6
+#define F_EXT_MIDI_INUSE 7
+#define F_INT_MIDI_INUSE 8
+ struct wait_queue *writeblock, *readblock;
+ unsigned long recsrc;
+ int left_levels[16];
+ int right_levels[16];
+ int calibrate_signal;
+ int sample_size;
+ int sample_rate;
+ int channels;
+ void (*inc_ref)(void);
+ void (*dec_ref)(void);
+
+ /* Digital audio FIFOs */
+ int fifosize;
+ msnd_fifo DAPF, DARF;
+ int lastbank;
+
+ /* MIDI in callback */
+ void (*midi_in_interrupt)(struct multisound_dev *);
+
+} multisound_dev_t;
+
+#ifndef mdelay
+# define mdelay(a) udelay((a) * 1000)
+#endif
+
+int msnd_register(multisound_dev_t *dev);
+void msnd_unregister(multisound_dev_t *dev);
+int msnd_get_num_devs(void);
+multisound_dev_t * msnd_get_dev(int i);
+
+void msnd_fifo_init(msnd_fifo *f);
+void msnd_fifo_free(msnd_fifo *f);
+int msnd_fifo_alloc(msnd_fifo *f, size_t n);
+void msnd_fifo_make_empty(msnd_fifo *f);
+int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user);
+int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user);
+
+int msnd_wait_TXDE(multisound_dev_t *dev);
+int msnd_wait_HC0(multisound_dev_t *dev);
+int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd);
+int msnd_send_word(multisound_dev_t *dev, unsigned char high,
+ unsigned char mid, unsigned char low);
+int msnd_upload_host(multisound_dev_t *dev, char *bin, int len);
+int msnd_enable_irq(multisound_dev_t *dev);
+int msnd_disable_irq(multisound_dev_t *dev);
+
+#endif /* __MSND_H */
--- /dev/null
+/*********************************************************************
+ *
+ * msnd_classic.c - Support for Turtle Beach Classic/Monterey/Tahiti
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd_classic.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include "sound_config.h"
+#include "sound_firmware.h"
+#define SLOWIO
+#include "msnd.h"
+#include "msnd_classic.h"
+
+#define LOGNAME "msnd_classic"
+#define DEVNAME dev.name
+#define MIXERMINOR dev.mixer_minor
+#define DSPMINOR dev.dsp_minor
+
+multisound_dev_t dev;
+
+#ifndef HAVE_DSPCODEH
+static char *dspini, *permini;
+static int sizeof_dspini, sizeof_permini;
+#endif
+
+static void reset_play_queue(void)
+{
+ int n;
+ LPDAQD lpDAQ;
+
+ msnd_fifo_make_empty(&dev.DAPF);
+ dev.DAPQ->wHead = 0;
+ dev.DAPQ->wTail = PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE);
+ dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF);
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+
+ for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+
+ writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+ writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+ writew(1, &lpDAQ->wFormat);
+ writew(dev.sample_size, &lpDAQ->wSampleSize);
+ writew(dev.channels, &lpDAQ->wChannels);
+ writew(dev.sample_rate, &lpDAQ->wSampleRate);
+ writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+ writew(n + 1, &lpDAQ->wFlags);
+
+ }
+
+ dev.lastbank = -1;
+}
+
+static void reset_record_queue(void)
+{
+ int n;
+ LPDAQD lpDAQ;
+
+ msnd_fifo_make_empty(&dev.DARF);
+ dev.DARQ->wHead = 0;
+ dev.DARQ->wTail = PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE);
+ dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF);
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+ writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+ writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+ writew(1, &lpDAQ->wFormat);
+ writew(dev.sample_size, &lpDAQ->wSampleSize);
+ writew(dev.channels, &lpDAQ->wChannels);
+ writew(dev.sample_rate, &lpDAQ->wSampleRate);
+ writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+ writew(n + 1, &lpDAQ->wFlags);
+
+ }
+}
+
+static void reset_queues(void)
+{
+ dev.DSPQ->wHead = dev.DSPQ->wTail = 0;
+ reset_play_queue();
+ reset_record_queue();
+}
+
+static int dsp_ioctl(unsigned int cmd, unsigned long arg)
+{
+ int val, i, data;
+ LPDAQD lpDAQ, lpDARQ;
+
+ lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+ lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+ switch (cmd) {
+ case SNDCTL_DSP_SUBDIVIDE:
+ case SNDCTL_DSP_SETFRAGMENT:
+ case SNDCTL_DSP_SETDUPLEX:
+ return 0;
+
+ case SNDCTL_DSP_GETIPTR:
+ case SNDCTL_DSP_GETOPTR:
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ return -EINVAL;
+
+ case SNDCTL_DSP_SYNC:
+ case SNDCTL_DSP_RESET:
+
+ reset_play_queue();
+ reset_record_queue();
+
+ return 0;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+
+ if (put_user(dev.fifosize / 4, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_NONBLOCK:
+
+ dev.mode |= O_NONBLOCK;
+
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+
+ val = DSP_CAP_DUPLEX | DSP_CAP_BATCH;
+ if (put_user(val, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_SAMPLESIZE:
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (val) {
+ case 16:
+ case 8:
+ data = val;
+ break;
+ default:
+ data = DEFSAMPLESIZE;
+ break;
+ }
+
+ for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+ lpDAQ->wSampleSize = data;
+ lpDARQ->wSampleSize = data;
+ }
+
+ dev.sample_size = data;
+
+ if (put_user(data, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_SPEED:
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ if (val < 8000)
+ val = 8000;
+
+ if (val > 48000)
+ val = 48000;
+
+ data = val;
+
+ for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+ lpDAQ->wSampleRate = data;
+ lpDARQ->wSampleRate = data;
+ }
+
+ dev.sample_rate = data;
+
+ if (put_user(data, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (val) {
+ case 1:
+ case 2:
+ data = val;
+ break;
+ default:
+ val = data = 2;
+ break;
+ }
+
+ for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+ lpDAQ->wChannels = data;
+ lpDARQ->wChannels = data;
+ }
+
+ dev.channels = data;
+
+ if (put_user(val, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_STEREO:
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (val) {
+ case 0:
+ data = 1;
+ break;
+ default:
+ val = 1;
+ case 1:
+ data = 2;
+ break;
+ }
+
+ for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+ lpDAQ->wChannels = data;
+ lpDARQ->wChannels = data;
+ }
+
+ dev.channels = data;
+
+ if (put_user(val, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int mixer_get(int d)
+{
+ if (d > 31)
+ return -EINVAL;
+
+ switch (d) {
+ case SOUND_MIXER_VOLUME:
+ case SOUND_MIXER_SYNTH:
+ case SOUND_MIXER_PCM:
+ case SOUND_MIXER_LINE:
+ case SOUND_MIXER_MIC:
+ case SOUND_MIXER_IMIX:
+ case SOUND_MIXER_LINE1:
+ return (dev.left_levels[d] >> 8) * 100 / 0xff |
+ (((dev.right_levels[d] >> 8) * 100 / 0xff) << 8);
+ default:
+ return 0;
+ }
+}
+
+#define update_vol(a,b,s) \
+ writew(dev.left_levels[a] * readw(&dev.SMA->wCurrMastVolLeft) / 0xffff / s, \
+ &dev.SMA->b##Left); \
+ writew(dev.right_levels[a] * readw(&dev.SMA->wCurrMastVolRight) / 0xffff / s, \
+ &dev.SMA->b##Right);
+
+static int mixer_set(int d, int value)
+{
+ int left = value & 0x000000ff;
+ int right = (value & 0x0000ff00) >> 8;
+ int bLeft, bRight;
+ int wLeft, wRight;
+
+ if (d > 31)
+ return -EINVAL;
+
+ bLeft = left * 0xff / 100;
+ wLeft = left * 0xffff / 100;
+
+ bRight = right * 0xff / 100;
+ wRight = right * 0xffff / 100;
+
+ dev.left_levels[d] = wLeft;
+ dev.right_levels[d] = wRight;
+
+ switch (d) {
+ case SOUND_MIXER_VOLUME: /* master volume */
+ writew(wLeft / 2, &dev.SMA->wCurrMastVolLeft);
+ writew(wRight / 2, &dev.SMA->wCurrMastVolRight);
+ break;
+
+ /* pot controls */
+ case SOUND_MIXER_LINE: /* aux pot control */
+ writeb(bLeft, &dev.SMA->bInPotPosLeft);
+ writeb(bRight, &dev.SMA->bInPotPosRight);
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ break;
+
+ case SOUND_MIXER_LINE1: /* line pot control */
+ writeb(bLeft, &dev.SMA->bAuxPotPosLeft);
+ writeb(bRight, &dev.SMA->bAuxPotPosRight);
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0)
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ break;
+
+ /* digital controls */
+ case SOUND_MIXER_SYNTH: /* synth vol (dsp mix) */
+ case SOUND_MIXER_PCM: /* pcm vol (dsp mix) */
+ case SOUND_MIXER_IMIX: /* input monitor (dsp mix) */
+ break;
+
+ default:
+ return 0;
+ }
+
+ /* update digital controls for master volume */
+ update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1);
+ update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1);
+
+ return mixer_get(d);
+}
+
+static unsigned long set_recsrc(unsigned long recsrc)
+{
+#ifdef HAVE_NORECSRC
+ if (recsrc == 0)
+ dev.recsrc = 0;
+ else
+#endif
+ dev.recsrc ^= recsrc;
+
+ return dev.recsrc;
+}
+
+static int mixer_ioctl(unsigned int cmd, unsigned long arg)
+{
+ int val = 0;
+
+ if (((cmd >> 8) & 0xff) == 'M') {
+
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ val = set_recsrc(val);
+ break;
+
+ default:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ val = mixer_set(cmd & 0xff, val);
+ break;
+ }
+
+ return put_user(val, (int *)arg);
+ }
+ else {
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ val = dev.recsrc;
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ case SOUND_MIXER_STEREODEVS:
+ val = SOUND_MASK_VOLUME |
+ SOUND_MASK_PCM |
+ SOUND_MASK_LINE |
+ SOUND_MASK_IMIX |
+ SOUND_MASK_LINE1;
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ val = 0;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ val = SOUND_CAP_EXCL_INPUT;
+ break;
+
+ default:
+ if ((val = mixer_get(cmd & 0xff)) < 0)
+ return -EINVAL;
+ break;
+ }
+ }
+
+ return put_user(val, (int *)arg);
+ }
+
+ return -EINVAL;
+}
+
+static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int minor = MINOR(inode->i_rdev);
+
+ if (minor == DSPMINOR)
+ return dsp_ioctl(cmd, arg);
+ else if (minor == MIXERMINOR)
+ return mixer_ioctl(cmd, arg);
+
+ return -EINVAL;
+}
+
+static void dsp_halt(void)
+{
+ mdelay(1);
+ if (test_and_clear_bit(F_READING, &dev.flags)) {
+
+ msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
+ msnd_disable_irq(&dev);
+
+ }
+ mdelay(1);
+ if (test_and_clear_bit(F_WRITING, &dev.flags)) {
+
+ msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+ msnd_disable_irq(&dev);
+
+ }
+ mdelay(1);
+ reset_queues();
+}
+
+static int dsp_open(struct file *file)
+{
+ dev.mode = file->f_mode;
+ set_bit(F_AUDIO_INUSE, &dev.flags);
+ reset_queues();
+ return 0;
+}
+
+static int dsp_close(void)
+{
+ dsp_halt();
+ clear_bit(F_AUDIO_INUSE, &dev.flags);
+ return 0;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ int err = 0;
+
+ if (minor == DSPMINOR) {
+
+ if (test_bit(F_AUDIO_INUSE, &dev.flags))
+ return -EBUSY;
+
+ err = dsp_open(file);
+ }
+ else if (minor == MIXERMINOR) {
+ /* nothing */
+ } else
+ err = -EINVAL;
+
+ if (err >= 0)
+ MOD_INC_USE_COUNT;
+
+ return err;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ int err = 0;
+
+ if (minor == DSPMINOR) {
+ err = dsp_close();
+ }
+ else if (minor == MIXERMINOR) {
+ /* nothing */
+ } else
+ err = -EINVAL;
+
+ if (err >= 0)
+ MOD_DEC_USE_COUNT;
+
+ return err;
+}
+
+static int DAPF_to_bank(int bank)
+{
+ return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0);
+}
+
+static int bank_to_DARF(int bank)
+{
+ return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0);
+}
+
+static int dsp_read(char *buf, size_t len)
+{
+ int err = 0;
+ int count = len;
+
+ while (count > 0) {
+
+ int n;
+
+ if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": FIFO read error\n");
+ return n;
+ }
+
+ buf += n;
+ count -= n;
+
+ if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
+
+ reset_record_queue();
+ msnd_enable_irq(&dev);
+ msnd_send_dsp_cmd(&dev, HDEX_RECORD_START);
+
+ }
+
+ if (dev.mode & O_NONBLOCK)
+ return count == len ? -EAGAIN : len - count;
+
+ if (count > 0) {
+
+ set_bit(F_READBLOCK, &dev.flags);
+ interruptible_sleep_on(&dev.readblock);
+ clear_bit(F_READBLOCK, &dev.flags);
+
+ if (signal_pending(current))
+ err = -EINTR;
+
+ }
+
+ if (err != 0)
+ return err;
+ }
+
+ return len - count;
+}
+
+static int dsp_write(const char *buf, size_t len)
+{
+ int err = 0;
+ int count = len;
+
+ while (count > 0) {
+
+ int n;
+
+ if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": FIFO write error\n");
+ return n;
+ }
+
+ buf += n;
+ count -= n;
+
+ if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
+
+ reset_play_queue();
+ msnd_enable_irq(&dev);
+ msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+ }
+
+ if (dev.mode & O_NONBLOCK)
+ return count == len ? -EAGAIN : len - count;
+
+ if (count > 0) {
+
+ set_bit(F_WRITEBLOCK, &dev.flags);
+ interruptible_sleep_on(&dev.writeblock);
+ clear_bit(F_WRITEBLOCK, &dev.flags);
+
+ if (signal_pending(current))
+ err = -EINTR;
+
+ }
+
+ if (err != 0)
+ return err;
+ }
+
+ return len - count;
+}
+
+static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off)
+{
+ int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ if (minor == DSPMINOR) {
+
+ return dsp_read(buf, count);
+
+ } else
+ return -EINVAL;
+}
+
+static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+ int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ if (minor == DSPMINOR) {
+
+ return dsp_write(buf, count);
+
+ } else
+ return -EINVAL;
+}
+
+static void eval_dsp_msg(WORD wMessage)
+{
+ switch (HIBYTE(wMessage)) {
+ case HIMT_PLAY_DONE:
+
+ if (dev.lastbank == LOBYTE(wMessage))
+ break;
+
+ dev.lastbank = LOBYTE(wMessage);
+
+ dev.CurDAQD->wSize = DAP_BUFF_SIZE;
+
+ if ((dev.DAPQ->wTail += PCTODSP_OFFSET(DAPQ_STRUCT_SIZE)) > dev.DAPQ->wSize)
+ dev.DAPQ->wTail = 0;
+
+ if (++dev.CurDAQD > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE))
+ dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+
+ if (dev.lastbank < 3) {
+
+ if (DAPF_to_bank(dev.lastbank) > 0) {
+
+ mdelay(1);
+ msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+ }
+ else if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
+
+ memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+ clear_bit(F_WRITING, &dev.flags);
+ msnd_disable_irq(&dev);
+
+ }
+ }
+
+ if (test_bit(F_WRITEBLOCK, &dev.flags))
+ wake_up_interruptible(&dev.writeblock);
+
+ break;
+
+ case HIMT_RECORD_DONE: {
+
+ WORD wTemp;
+
+ wTemp = dev.DARQ->wTail + (DARQ_STRUCT_SIZE / 2);
+
+ if (wTemp > dev.DARQ->wSize)
+ wTemp = 0;
+
+ while (wTemp == dev.DARQ->wHead);
+
+ dev.DARQ->wTail = wTemp;
+
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ if (bank_to_DARF(LOBYTE(wMessage)) == 0 &&
+ !test_bit(F_READBLOCK, &dev.flags)) {
+
+ memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+ clear_bit(F_READING, &dev.flags);
+ msnd_disable_irq(&dev);
+
+ }
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ if (test_bit(F_READBLOCK, &dev.flags))
+ wake_up_interruptible(&dev.readblock);
+
+ } break;
+
+ case HIMT_DSP:
+ switch (LOBYTE(wMessage)) {
+ case HIDSP_INT_PLAY_UNDER:
+ printk(KERN_INFO LOGNAME ": Write underflow\n");
+ reset_play_queue();
+ break;
+
+ case HIDSP_INT_RECORD_OVER:
+ printk(KERN_INFO LOGNAME ": Read overflow\n");
+ reset_record_queue();
+ break;
+
+ default:
+ printk(KERN_INFO LOGNAME ": DSP message %u\n", LOBYTE(wMessage));
+ break;
+ }
+ break;
+
+ case HIMT_MIDI_IN_UCHAR:
+ if (dev.midi_in_interrupt)
+ (*dev.midi_in_interrupt)(&dev);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (test_bit(F_INTERRUPT, &dev.flags) ||
+ ((multisound_dev_t *)dev_id != &dev))
+ return;
+
+ set_bit(F_INTERRUPT, &dev.flags);
+
+ if (test_bit(F_BANKONE, &dev.flags))
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ inb(dev.io + HP_RXL);
+
+ while (dev.DSPQ->wTail != dev.DSPQ->wHead) {
+
+ eval_dsp_msg(*(dev.pwDSPQData + dev.DSPQ->wHead));
+
+ if (++dev.DSPQ->wHead > dev.DSPQ->wSize)
+ dev.DSPQ->wHead = 0;
+ }
+
+ if (test_bit(F_BANKONE, &dev.flags))
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+
+ clear_bit(F_INTERRUPT, &dev.flags);
+}
+
+static struct file_operations dev_fileops = {
+ NULL,
+ dev_read,
+ dev_write,
+ NULL,
+ NULL,
+ dev_ioctl,
+ NULL,
+ dev_open,
+ dev_close,
+};
+
+__initfunc(static int reset_dsp(void))
+{
+ int timeout = 20000;
+
+ outb(HPDSPRESET_ON, dev.io + HP_DSPR);
+
+ mdelay(1);
+
+ dev.info = inb(dev.io + HP_INFO);
+
+ outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
+
+ mdelay(1);
+
+ while (timeout-- > 0) {
+
+ if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
+ return 0;
+
+ mdelay(1);
+ }
+
+ printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+ return -EIO;
+}
+
+__initfunc(static int probe_multisound(void))
+{
+ if (check_region(dev.io, dev.numio)) {
+
+ printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+ return -ENODEV;
+ }
+
+ request_region(dev.io, dev.numio, "probing");
+
+ if (reset_dsp() < 0) {
+
+ release_region(dev.io, dev.numio);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO LOGNAME ": DSP reset successful\n");
+
+ dev.name = "Classic/Tahiti/Monterey";
+
+ printk(KERN_INFO LOGNAME ": Turtle Beach %s, "
+ "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n",
+ dev.name,
+ dev.io, dev.io + dev.numio - 1,
+ dev.irq,
+ dev.base, dev.base + 0x7fff);
+
+ release_region(dev.io, dev.numio);
+
+ return 0;
+}
+
+__initfunc(static int init_sma(void))
+{
+ int n;
+ LPDAQD lpDAQ;
+
+ outb(dev.memid, dev.io + HP_MEMM);
+
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ memset_io(dev.base, 0, 0x8000);
+
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ memset_io(dev.base, 0, 0x8000);
+
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ dev.DAPQ = (struct JobQueueStruct *)(dev.base + DAPQ_OFFSET);
+ dev.DARQ = (struct JobQueueStruct *)(dev.base + DARQ_OFFSET);
+ dev.MODQ = (struct JobQueueStruct *)(dev.base + MODQ_OFFSET);
+ dev.MIDQ = (struct JobQueueStruct *)(dev.base + MIDQ_OFFSET);
+ dev.DSPQ = (struct JobQueueStruct *)(dev.base + DSPQ_OFFSET);
+
+ dev.SMA = (struct SMA0_CommonData *)(dev.base + SMA_STRUCT_START);
+
+ dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+ dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+ dev.sample_size = DEFSAMPLESIZE;
+ dev.sample_rate = DEFSAMPLERATE;
+ dev.channels = DEFCHANNELS;
+
+ for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+
+ writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+ writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+ writew(1, &lpDAQ->wFormat);
+ writew(dev.sample_size, &lpDAQ->wSampleSize);
+ writew(dev.channels, &lpDAQ->wChannels);
+ writew(dev.sample_rate, &lpDAQ->wSampleRate);
+ writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+ writew(n + 1, &lpDAQ->wFlags);
+ }
+
+ for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+ writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+ writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+ writew(1, &lpDAQ->wFormat);
+ writew(dev.sample_size, &lpDAQ->wSampleSize);
+ writew(dev.channels, &lpDAQ->wChannels);
+ writew(dev.sample_rate, &lpDAQ->wSampleRate);
+ writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+ writew(n + 1, &lpDAQ->wFlags);
+
+ }
+
+ dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF);
+ dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF);
+ dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF);
+
+ writew(PCTODSP_BASED(MIDQ_DATA_BUFF), &dev.MIDQ->wStart);
+ writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, &dev.MIDQ->wSize);
+ writew(0, &dev.MIDQ->wHead);
+ writew(0, &dev.MIDQ->wTail);
+
+ writew(PCTODSP_BASED(MODQ_DATA_BUFF), &dev.MODQ->wStart);
+ writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, &dev.MODQ->wSize);
+ writew(0, &dev.MODQ->wHead);
+ writew(0, &dev.MODQ->wTail);
+
+ writew(PCTODSP_BASED(DAPQ_DATA_BUFF), &dev.DAPQ->wStart);
+ writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, &dev.DAPQ->wSize);
+ writew(0, &dev.DAPQ->wHead);
+ writew(0, &dev.DAPQ->wTail);
+
+ writew(PCTODSP_BASED(DARQ_DATA_BUFF), &dev.DARQ->wStart);
+ writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, &dev.DARQ->wSize);
+ writew(0, &dev.DARQ->wHead);
+ writew(0, &dev.DARQ->wTail);
+
+ writew(PCTODSP_BASED(DSPQ_DATA_BUFF), &dev.DSPQ->wStart);
+ writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, &dev.DSPQ->wSize);
+ writew(0, &dev.DSPQ->wHead);
+ writew(0, &dev.DSPQ->wTail);
+
+ writew(0, &dev.SMA->wCurrPlayBytes);
+ writew(0, &dev.SMA->wCurrRecordBytes);
+
+ writew(0, &dev.SMA->wCurrPlayVolLeft);
+ writew(0, &dev.SMA->wCurrPlayVolRight);
+
+ writew(0, &dev.SMA->wCurrInVolLeft);
+ writew(0, &dev.SMA->wCurrInVolRight);
+
+ writew(0, &dev.SMA->wCurrMastVolLeft);
+ writew(0, &dev.SMA->wCurrMastVolRight);
+
+ writew(0x0000, &dev.SMA->wCurrDSPStatusFlags);
+ writew(0x0000, &dev.SMA->wCurrHostStatusFlags);
+
+ writew(0x303, &dev.SMA->wCurrInputTagBits);
+ writew(0, &dev.SMA->wCurrLeftPeak);
+ writew(0, &dev.SMA->wCurrRightPeak);
+
+ writeb(0, &dev.SMA->bInPotPosRight);
+ writeb(0, &dev.SMA->bInPotPosLeft);
+
+ writeb(0, &dev.SMA->bAuxPotPosRight);
+ writeb(0, &dev.SMA->bAuxPotPosLeft);
+
+ writew(dev.sample_rate, &dev.SMA->wCalFreqAtoD);
+
+ return 0;
+}
+
+__initfunc(static int calibrate_adc(WORD srate))
+{
+ if (!dev.calibrate_signal) {
+
+ printk(KERN_INFO LOGNAME ": ADC calibration to board ground ");
+ writew(readw(&dev.SMA->wCurrHostStatusFlags)
+ | 0x0001, &dev.SMA->wCurrHostStatusFlags);
+ }
+ else {
+
+ printk(KERN_INFO LOGNAME ": ADC calibration to signal ground ");
+ writew(readw(&dev.SMA->wCurrHostStatusFlags)
+ & ~0x0001, &dev.SMA->wCurrHostStatusFlags);
+ }
+
+ writew(srate, &dev.SMA->wCalFreqAtoD);
+
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
+
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ;
+ schedule();
+ current->timeout = 0;
+ printk("successful\n");
+ return 0;
+ }
+
+ printk("failed\n");
+
+ return -EIO;
+}
+
+__initfunc(static int upload_dsp_code(void))
+{
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+#ifdef HAVE_DSPCODEH
+ printk(KERN_INFO LOGNAME ": Using resident Turtle Beach DSP code\n");
+#else
+ printk(KERN_INFO LOGNAME ": Loading Turtle Beach DSP code\n");
+ INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE);
+ if (!INITCODE) {
+ printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+ return -EBUSY;
+ }
+
+ PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE);
+ if (!PERMCODE) {
+ printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+ vfree(INITCODE);
+ return -EBUSY;
+ }
+#endif
+ memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+
+ if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+ return -ENODEV;
+ }
+
+#ifndef HAVE_DSPCODEH
+ vfree(INITCODE);
+ vfree(PERMCODE);
+#endif
+
+ return 0;
+}
+
+__initfunc(static void reset_proteus(void))
+{
+ outb(HPPRORESET_ON, dev.io + HP_PROR);
+ mdelay(TIME_PRO_RESET);
+ outb(HPPRORESET_OFF, dev.io + HP_PROR);
+ mdelay(TIME_PRO_RESET_DONE);
+}
+
+__initfunc(static int initialize(void))
+{
+ int err, timeout;
+
+ outb(HPWAITSTATE_0, dev.io + HP_WAIT);
+ outb(HPBITMODE_16, dev.io + HP_BITM);
+
+ reset_proteus();
+
+ if ((err = init_sma()) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+ return err;
+ }
+
+ if ((err = reset_dsp()) < 0)
+ return err;
+
+ if ((err = upload_dsp_code()) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+ return err;
+
+ } else
+ printk(KERN_INFO LOGNAME ": DSP upload successful\n");
+
+ timeout = 2000;
+
+ while (readw(dev.base)) {
+
+ mdelay(1);
+ if (--timeout < 0)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+__initfunc(static int attach_multisound(void))
+{
+ int err;
+
+ printk(KERN_DEBUG LOGNAME ": Intializing DSP\n");
+
+ if ((err = request_irq(dev.irq, intr, SA_SHIRQ, DEVNAME, &dev)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
+ return err;
+
+ }
+
+ request_region(dev.io, dev.numio, DEVNAME);
+
+ if ((err = initialize()) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": Initialization failure\n");
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ return err;
+
+ }
+
+ if ((err = msnd_register(&dev)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n");
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ return err;
+ }
+
+ if ((DSPMINOR = register_sound_dsp(&dev_fileops)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n");
+ msnd_unregister(&dev);
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ return DSPMINOR;
+ }
+
+ if ((MIXERMINOR = register_sound_mixer(&dev_fileops)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n");
+ unregister_sound_mixer(MIXERMINOR);
+ msnd_unregister(&dev);
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ return MIXERMINOR;
+ }
+ printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", MIXERMINOR, DSPMINOR);
+
+ calibrate_adc(dev.sample_rate);
+ set_recsrc(0);
+
+ return 0;
+}
+
+static void unload_multisound(void)
+{
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ unregister_sound_mixer(MIXERMINOR);
+ unregister_sound_dsp(DSPMINOR);
+ msnd_unregister(&dev);
+}
+
+static void mod_inc_ref(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void mod_dec_ref(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION ("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_PARM (io, "i");
+MODULE_PARM (irq, "i");
+MODULE_PARM (mem, "i");
+MODULE_PARM (major, "i");
+MODULE_PARM (fifosize, "i");
+MODULE_PARM (calibrate_signal, "i");
+
+static int io __initdata = -1;
+static int irq __initdata = -1;
+static int mem __initdata = -1;
+static int fifosize __initdata = DEFFIFOSIZE;
+static int
+calibrate_signal __initdata = 0;
+
+int init_module(void)
+{
+ int err;
+
+ printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
+ VERSION ", Copyright (C) 1998 Andrew Veliath\n");
+
+ if (io == -1 || irq == -1 || mem == -1) {
+
+ printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+ }
+
+ if (io == -1 ||
+ !(io == 0x290 ||
+ io == 0x260 ||
+ io == 0x250 ||
+ io == 0x240 ||
+ io == 0x230 ||
+ io == 0x220 ||
+ io == 0x210 ||
+ io == 0x3e0)) {
+
+ printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set\n");
+ return -EINVAL;
+ }
+
+ if (irq == -1 ||
+ !(irq == 5 ||
+ irq == 7 ||
+ irq == 9 ||
+ irq == 10 ||
+ irq == 11 ||
+ irq == 12)) {
+
+ printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+ return -EINVAL;
+ }
+
+ if (mem == -1 ||
+ !(mem == 0xb0000 ||
+ mem == 0xc8000 ||
+ mem == 0xd0000 ||
+ mem == 0xd8000 ||
+ mem == 0xe0000 ||
+ mem == 0xe8000)) {
+
+ printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+ "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+ return -EINVAL;
+ }
+
+ switch (irq) {
+ case 5: dev.irqid = HPIRQ_5; break;
+ case 7: dev.irqid = HPIRQ_7; break;
+ case 9: dev.irqid = HPIRQ_9; break;
+ case 10: dev.irqid = HPIRQ_10; break;
+ case 11: dev.irqid = HPIRQ_11; break;
+ case 12: dev.irqid = HPIRQ_12; break;
+ }
+
+ switch (mem) {
+ case 0xb0000: dev.memid = HPMEM_B000; break;
+ case 0xc8000: dev.memid = HPMEM_C800; break;
+ case 0xd0000: dev.memid = HPMEM_D000; break;
+ case 0xd8000: dev.memid = HPMEM_D800; break;
+ case 0xe0000: dev.memid = HPMEM_E000; break;
+ case 0xe8000: dev.memid = HPMEM_E800; break;
+ }
+
+ if (fifosize < 16)
+ fifosize = 16;
+
+ if (fifosize > 768)
+ fifosize = 768;
+
+ dev.type = msndClassic;
+ dev.io = io;
+ dev.numio = DSP_NUMIO;
+ dev.irq = irq;
+ dev.base = phys_to_virt(mem);
+ dev.fifosize = fifosize * 1024;
+ dev.calibrate_signal = calibrate_signal ? 1 : 0;
+ dev.recsrc = 0;
+ dev.inc_ref = mod_inc_ref;
+ dev.dec_ref = mod_dec_ref;
+
+ init_waitqueue(&dev.writeblock);
+ init_waitqueue(&dev.readblock);
+ msnd_fifo_init(&dev.DAPF);
+ msnd_fifo_init(&dev.DARF);
+ spin_lock_init(&dev.lock);
+
+ printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize);
+
+ if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n");
+ return err;
+ }
+
+ if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n");
+ msnd_fifo_free(&dev.DAPF);
+ return err;
+ }
+
+ if ((err = probe_multisound()) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Probe failed\n");
+ msnd_fifo_free(&dev.DAPF);
+ msnd_fifo_free(&dev.DARF);
+ return err;
+
+ }
+
+ if ((err = attach_multisound()) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Attach failed\n");
+ msnd_fifo_free(&dev.DAPF);
+ msnd_fifo_free(&dev.DARF);
+ return err;
+
+ }
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ printk(KERN_INFO LOGNAME ": Unloading\n");
+
+ unload_multisound();
+
+ msnd_fifo_free(&dev.DAPF);
+ msnd_fifo_free(&dev.DARF);
+
+}
+#endif
--- /dev/null
+/*********************************************************************
+ *
+ * msnd_classic.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd_classic.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_CLASSIC_H
+#define __MSND_CLASSIC_H
+
+#define DSP_NUMIO 0x10
+
+#define HP_MEMM 0x08
+
+#define HP_BITM 0x0E
+#define HP_WAIT 0x0D
+#define HP_DSPR 0x0A
+#define HP_PROR 0x0B
+#define HP_BLKS 0x0C
+
+#define HPPRORESET_OFF 0
+#define HPPRORESET_ON 1
+
+#define HPDSPRESET_OFF 0
+#define HPDSPRESET_ON 1
+
+#define HPBLKSEL_0 0
+#define HPBLKSEL_1 1
+
+#define HPWAITSTATE_0 0
+#define HPWAITSTATE_1 1
+
+#define HPBITMODE_16 0
+#define HPBITMODE_8 1
+
+#define HIDSP_INT_PLAY_UNDER 0x00
+#define HIDSP_INT_RECORD_OVER 0x01
+#define HIDSP_INPUT_CLIPPING 0x02
+#define HIDSP_MIDI_IN_OVER 0x10
+#define HIDSP_MIDI_OVERRUN_ERR 0x13
+
+#define HDEX_BASE 0x92
+#define HDEX_PLAY_START (0 + HDEX_BASE)
+#define HDEX_PLAY_STOP (1 + HDEX_BASE)
+#define HDEX_PLAY_PAUSE (2 + HDEX_BASE)
+#define HDEX_PLAY_RESUME (3 + HDEX_BASE)
+#define HDEX_RECORD_START (4 + HDEX_BASE)
+#define HDEX_RECORD_STOP (5 + HDEX_BASE)
+#define HDEX_MIDI_IN_START (6 + HDEX_BASE)
+#define HDEX_MIDI_IN_STOP (7 + HDEX_BASE)
+#define HDEX_MIDI_OUT_START (8 + HDEX_BASE)
+#define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE)
+#define HDEX_AUX_REQ (10 + HDEX_BASE)
+
+#define HDEXAR_CLEAR_PEAKS 1
+#define HDEXAR_IN_SET_POTS 2
+#define HDEXAR_AUX_SET_POTS 3
+#define HDEXAR_CAL_A_TO_D 4
+#define HDEXAR_RD_EXT_DSP_BITS 5
+
+#define TIME_PRO_RESET_DONE 0x028A
+#define TIME_PRO_SYSEX 0x0040
+#define TIME_PRO_RESET 0x0032
+
+#define AGND 0x01
+#define SIGNAL 0x02
+
+#define EXT_DSP_BIT_DCAL 0x0001
+#define EXT_DSP_BIT_MIDI_CON 0x0002
+
+#define BUFFSIZE 0x8000
+#define HOSTQ_SIZE 0x40
+
+#define SRAM_CNTL_START 0x7F00
+#define SMA_STRUCT_START 0x7F40
+
+#define DAP_BUFF_SIZE 0x2400
+#define DAR_BUFF_SIZE 0x2000
+
+#define DAPQ_STRUCT_SIZE 0x10
+#define DARQ_STRUCT_SIZE 0x10
+#define DAPQ_BUFF_SIZE (3 * 0x10)
+#define DARQ_BUFF_SIZE (3 * 0x10)
+#define MODQ_BUFF_SIZE 0x400
+#define MIDQ_BUFF_SIZE 0x200
+#define DSPQ_BUFF_SIZE 0x40
+
+#define DAPQ_DATA_BUFF 0x6C00
+#define DARQ_DATA_BUFF 0x6C30
+#define MODQ_DATA_BUFF 0x6C60
+#define MIDQ_DATA_BUFF 0x7060
+#define DSPQ_DATA_BUFF 0x7260
+
+#define DAPQ_OFFSET SRAM_CNTL_START
+#define DARQ_OFFSET (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
+
+#define MOP_PROTEUS 0x10
+#define MOP_EXTOUT 0x32
+#define MOP_EXTTHRU 0x02
+#define MOP_OUTMASK 0x01
+
+#define MIP_EXTIN 0x01
+#define MIP_PROTEUS 0x00
+#define MIP_INMASK 0x32
+
+struct SMA0_CommonData {
+ WORD wCurrPlayBytes;
+ WORD wCurrRecordBytes;
+ WORD wCurrPlayVolLeft;
+ WORD wCurrPlayVolRight;
+ WORD wCurrInVolLeft;
+ WORD wCurrInVolRight;
+ WORD wUser_3;
+ WORD wUser_4;
+ DWORD dwUser_5;
+ DWORD dwUser_6;
+ WORD wUser_7;
+ WORD wReserved_A;
+ WORD wReserved_B;
+ WORD wReserved_C;
+ WORD wReserved_D;
+ WORD wReserved_E;
+ WORD wReserved_F;
+ WORD wReserved_G;
+ WORD wReserved_H;
+ WORD wCurrDSPStatusFlags;
+ WORD wCurrHostStatusFlags;
+ WORD wCurrInputTagBits;
+ WORD wCurrLeftPeak;
+ WORD wCurrRightPeak;
+ WORD wExtDSPbits;
+ BYTE bExtHostbits;
+ BYTE bBoardLevel;
+ BYTE bInPotPosRight;
+ BYTE bInPotPosLeft;
+ BYTE bAuxPotPosRight;
+ BYTE bAuxPotPosLeft;
+ WORD wCurrMastVolLeft;
+ WORD wCurrMastVolRight;
+ BYTE bUser_12;
+ BYTE bUser_13;
+ WORD wUser_14;
+ WORD wUser_15;
+ WORD wCalFreqAtoD;
+ WORD wUser_16;
+ WORD wUser_17;
+} GCC_PACKED;
+
+#ifdef HAVE_DSPCODEH
+# include "msndperm.c"
+# include "msndinit.c"
+# define PERMCODE msndperm
+# define INITCODE msndinit
+# define PERMCODESIZE sizeof(msndperm)
+# define INITCODESIZE sizeof(msndinit)
+#else
+# define PERMCODEFILE CONFIG_MSNDCLAS_PERM_FILE
+# define INITCODEFILE CONFIG_MSNDCLAS_INIT_FILE
+# define PERMCODE dspini
+# define INITCODE permini
+# define PERMCODESIZE sizeof_dspini
+# define INITCODESIZE sizeof_permini
+#endif
+#define LONGNAME "MultiSound (Classic/Monterey/Tahiti)"
+
+#endif /* __MSND_CLASSIC_H */
--- /dev/null
+/*********************************************************************
+ *
+ * msnd_pinnacle.c - Support for Turtle Beach Pinnacle and Fiji
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd_pinnacle.c,v 1.2 1998/06/09 20:37:39 andrewtv Exp $
+ *
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include "sound_config.h"
+#include "sound_firmware.h"
+#include "msnd.h"
+#include "msnd_pinnacle.h"
+
+#define LOGNAME "msnd_pinnacle"
+#define DEVNAME dev.name
+#define MIXERMINOR dev.mixer_minor
+#define DSPMINOR dev.dsp_minor
+
+multisound_dev_t dev;
+
+#ifndef HAVE_DSPCODEH
+static char *dspini, *permini;
+static int sizeof_dspini, sizeof_permini;
+#endif
+
+static void reset_play_queue(void)
+{
+ int n;
+ LPDAQD lpDAQ;
+
+ msnd_fifo_make_empty(&dev.DAPF);
+ dev.DAPQ->wHead = 0;
+ dev.DAPQ->wTail = PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE);
+ dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF);
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+
+ for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+
+ writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+ writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+ writew(1, &lpDAQ->wFormat);
+ writew(dev.sample_size, &lpDAQ->wSampleSize);
+ writew(dev.channels, &lpDAQ->wChannels);
+ writew(dev.sample_rate, &lpDAQ->wSampleRate);
+ writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+ writew(n + 1, &lpDAQ->wFlags);
+
+ }
+
+ dev.lastbank = -1;
+}
+
+static void reset_record_queue(void)
+{
+ int n;
+ LPDAQD lpDAQ;
+
+ msnd_fifo_make_empty(&dev.DARF);
+ dev.DARQ->wHead = 0;
+ dev.DARQ->wTail = PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE);
+ dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF);
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+ writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+ writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+ writew(1, &lpDAQ->wFormat);
+ writew(dev.sample_size, &lpDAQ->wSampleSize);
+ writew(dev.channels, &lpDAQ->wChannels);
+ writew(dev.sample_rate, &lpDAQ->wSampleRate);
+ writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+ writew(n + 1, &lpDAQ->wFlags);
+
+ }
+}
+
+static void reset_queues(void)
+{
+ dev.DSPQ->wHead = dev.DSPQ->wTail = 0;
+ reset_play_queue();
+ reset_record_queue();
+}
+
+static int dsp_ioctl(unsigned int cmd, unsigned long arg)
+{
+ int val, i, data;
+ LPDAQD lpDAQ, lpDARQ;
+
+ lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+ lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+ switch (cmd) {
+ case SNDCTL_DSP_SUBDIVIDE:
+ case SNDCTL_DSP_SETFRAGMENT:
+ case SNDCTL_DSP_SETDUPLEX:
+ return 0;
+
+ case SNDCTL_DSP_GETIPTR:
+ case SNDCTL_DSP_GETOPTR:
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ return -EINVAL;
+
+ case SNDCTL_DSP_SYNC:
+ case SNDCTL_DSP_RESET:
+
+ reset_play_queue();
+ reset_record_queue();
+
+ return 0;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+
+ if (put_user(dev.fifosize / 4, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_NONBLOCK:
+
+ dev.mode |= O_NONBLOCK;
+
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+
+ val = DSP_CAP_DUPLEX | DSP_CAP_BATCH;
+ if (put_user(val, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_SAMPLESIZE:
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (val) {
+ case 16:
+ case 8:
+ data = val;
+ break;
+ default:
+ data = DEFSAMPLESIZE;
+ break;
+ }
+
+ for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+ lpDAQ->wSampleSize = data;
+ lpDARQ->wSampleSize = data;
+ }
+
+ dev.sample_size = data;
+
+ if (put_user(data, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_SPEED:
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ if (val < 8000)
+ val = 8000;
+
+ if (val > 48000)
+ val = 48000;
+
+ data = val;
+
+ for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+ lpDAQ->wSampleRate = data;
+ lpDARQ->wSampleRate = data;
+ }
+
+ dev.sample_rate = data;
+
+ if (put_user(data, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (val) {
+ case 1:
+ case 2:
+ data = val;
+ break;
+ default:
+ val = data = 2;
+ break;
+ }
+
+ for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+ lpDAQ->wChannels = data;
+ lpDARQ->wChannels = data;
+ }
+
+ dev.channels = data;
+
+ if (put_user(val, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+
+ case SNDCTL_DSP_STEREO:
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (val) {
+ case 0:
+ data = 1;
+ break;
+ default:
+ val = 1;
+ case 1:
+ data = 2;
+ break;
+ }
+
+ for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) {
+
+ lpDAQ->wChannels = data;
+ lpDARQ->wChannels = data;
+ }
+
+ dev.channels = data;
+
+ if (put_user(val, (int *)arg))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int mixer_get(int d)
+{
+ if (d > 31)
+ return -EINVAL;
+
+ switch (d) {
+ case SOUND_MIXER_VOLUME:
+ case SOUND_MIXER_SYNTH:
+ case SOUND_MIXER_PCM:
+ case SOUND_MIXER_LINE:
+ case SOUND_MIXER_MIC:
+ case SOUND_MIXER_IMIX:
+ case SOUND_MIXER_LINE1:
+ return (dev.left_levels[d] >> 8) * 100 / 0xff |
+ (((dev.right_levels[d] >> 8) * 100 / 0xff) << 8);
+ default:
+ return 0;
+ }
+}
+
+#define update_vol(a,b,s) \
+ writew(dev.left_levels[a] * readw(&dev.SMA->wCurrMastVolLeft) / 0xffff / s, \
+ &dev.SMA->b##Left); \
+ writew(dev.right_levels[a] * readw(&dev.SMA->wCurrMastVolRight) / 0xffff / s, \
+ &dev.SMA->b##Right);
+
+static int mixer_set(int d, int value)
+{
+ int left = value & 0x000000ff;
+ int right = (value & 0x0000ff00) >> 8;
+ int bLeft, bRight;
+ int wLeft, wRight;
+
+ if (d > 31)
+ return -EINVAL;
+
+ bLeft = left * 0xff / 100;
+ wLeft = left * 0xffff / 100;
+
+ bRight = right * 0xff / 100;
+ wRight = right * 0xffff / 100;
+
+ dev.left_levels[d] = wLeft;
+ dev.right_levels[d] = wRight;
+
+ switch (d) {
+ case SOUND_MIXER_VOLUME: /* master volume */
+ writew(wLeft / 2, &dev.SMA->wCurrMastVolLeft);
+ writew(wRight / 2, &dev.SMA->wCurrMastVolRight);
+ break;
+
+ /* pot controls */
+ case SOUND_MIXER_LINE: /* aux pot control */
+ writeb(bLeft, &dev.SMA->bInPotPosLeft);
+ writeb(bRight, &dev.SMA->bInPotPosRight);
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ break;
+
+ case SOUND_MIXER_MIC: /* mic pot control */
+ writeb(bLeft, &dev.SMA->bMicPotPosLeft);
+ writeb(bRight, &dev.SMA->bMicPotPosRight);
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ break;
+
+ case SOUND_MIXER_LINE1: /* line pot control */
+ writeb(bLeft, &dev.SMA->bAuxPotPosLeft);
+ writeb(bRight, &dev.SMA->bAuxPotPosRight);
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0)
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+ break;
+
+ /* digital controls */
+ case SOUND_MIXER_SYNTH: /* synth vol (dsp mix) */
+ case SOUND_MIXER_PCM: /* pcm vol (dsp mix) */
+ case SOUND_MIXER_IMIX: /* input monitor (dsp mix) */
+ break;
+
+ default:
+ return 0;
+ }
+
+ /* update digital controls for master volume */
+ update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1);
+ update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1);
+ update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1);
+
+ return mixer_get(d);
+}
+
+static unsigned long set_recsrc(unsigned long recsrc)
+{
+#ifdef HAVE_NORECSRC
+ if (recsrc == 0)
+ dev.recsrc = 0;
+ else
+#endif
+ dev.recsrc ^= recsrc;
+
+ if (dev.recsrc & SOUND_MASK_LINE) {
+
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+
+ }
+ else if (dev.recsrc & SOUND_MASK_SYNTH) {
+
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0)
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+
+ }
+ else {
+#ifdef HAVE_NORECSRC
+ /* Select no input (?) */
+ dev.recsrc = 0;
+#else
+ dev.recsrc = SOUND_MASK_LINE;
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+#endif
+ }
+
+ return dev.recsrc;
+}
+
+static int mixer_ioctl(unsigned int cmd, unsigned long arg)
+{
+ int val = 0;
+
+ if (((cmd >> 8) & 0xff) == 'M') {
+
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ val = set_recsrc(val);
+ break;
+
+ default:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ val = mixer_set(cmd & 0xff, val);
+ break;
+ }
+
+ return put_user(val, (int *)arg);
+ }
+ else {
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ val = dev.recsrc;
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ case SOUND_MIXER_STEREODEVS:
+ val = SOUND_MASK_VOLUME |
+ SOUND_MASK_SYNTH |
+ SOUND_MASK_PCM |
+ SOUND_MASK_LINE |
+ SOUND_MASK_IMIX |
+ SOUND_MASK_MIC;
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ val = SOUND_MASK_LINE |
+ SOUND_MASK_SYNTH;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ val = SOUND_CAP_EXCL_INPUT;
+ break;
+
+ default:
+ if ((val = mixer_get(cmd & 0xff)) < 0)
+ return -EINVAL;
+ break;
+ }
+ }
+
+ return put_user(val, (int *)arg);
+ }
+
+ return -EINVAL;
+}
+
+static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int minor = MINOR(inode->i_rdev);
+
+ if (minor == DSPMINOR)
+ return dsp_ioctl(cmd, arg);
+ else if (minor == MIXERMINOR)
+ return mixer_ioctl(cmd, arg);
+
+ return -EINVAL;
+}
+
+static void dsp_halt(void)
+{
+ mdelay(1);
+ if (test_and_clear_bit(F_READING, &dev.flags)) {
+
+ msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
+ msnd_disable_irq(&dev);
+
+ }
+ mdelay(1);
+ if (test_and_clear_bit(F_WRITING, &dev.flags)) {
+
+ msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+ msnd_disable_irq(&dev);
+
+ }
+ mdelay(1);
+ reset_queues();
+}
+
+static int dsp_open(struct file *file)
+{
+ dev.mode = file->f_mode;
+ set_bit(F_AUDIO_INUSE, &dev.flags);
+ reset_queues();
+ return 0;
+}
+
+static int dsp_close(void)
+{
+ dsp_halt();
+ clear_bit(F_AUDIO_INUSE, &dev.flags);
+ return 0;
+}
+
+static int dev_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ int err = 0;
+
+ if (minor == DSPMINOR) {
+
+ if (test_bit(F_AUDIO_INUSE, &dev.flags))
+ return -EBUSY;
+
+ err = dsp_open(file);
+ }
+ else if (minor == MIXERMINOR) {
+ /* nothing */
+ } else
+ err = -EINVAL;
+
+ if (err >= 0)
+ MOD_INC_USE_COUNT;
+
+ return err;
+}
+
+static int dev_close(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ int err = 0;
+
+ if (minor == DSPMINOR) {
+ err = dsp_close();
+ }
+ else if (minor == MIXERMINOR) {
+ /* nothing */
+ } else
+ err = -EINVAL;
+
+ if (err >= 0)
+ MOD_DEC_USE_COUNT;
+
+ return err;
+}
+
+static int DAPF_to_bank(int bank)
+{
+ return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0);
+}
+
+static int bank_to_DARF(int bank)
+{
+ return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0);
+}
+
+static int dsp_read(char *buf, size_t len)
+{
+ int err = 0;
+ int count = len;
+
+ while (count > 0) {
+
+ int n;
+
+ if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": FIFO read error\n");
+ return n;
+ }
+
+ buf += n;
+ count -= n;
+
+ if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
+
+ reset_record_queue();
+ msnd_enable_irq(&dev);
+ msnd_send_dsp_cmd(&dev, HDEX_RECORD_START);
+
+ }
+
+ if (dev.mode & O_NONBLOCK)
+ return count == len ? -EAGAIN : len - count;
+
+ if (count > 0) {
+
+ set_bit(F_READBLOCK, &dev.flags);
+ interruptible_sleep_on(&dev.readblock);
+ clear_bit(F_READBLOCK, &dev.flags);
+
+ if (signal_pending(current))
+ err = -EINTR;
+
+ }
+
+ if (err != 0)
+ return err;
+ }
+
+ return len - count;
+}
+
+static int dsp_write(const char *buf, size_t len)
+{
+ int err = 0;
+ int count = len;
+
+ while (count > 0) {
+
+ int n;
+
+ if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": FIFO write error\n");
+ return n;
+ }
+
+ buf += n;
+ count -= n;
+
+ if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
+
+ reset_play_queue();
+ msnd_enable_irq(&dev);
+ msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+ }
+
+ if (dev.mode & O_NONBLOCK)
+ return count == len ? -EAGAIN : len - count;
+
+ if (count > 0) {
+
+ set_bit(F_WRITEBLOCK, &dev.flags);
+ interruptible_sleep_on(&dev.writeblock);
+ clear_bit(F_WRITEBLOCK, &dev.flags);
+
+ if (signal_pending(current))
+ err = -EINTR;
+
+ }
+
+ if (err != 0)
+ return err;
+ }
+
+ return len - count;
+}
+
+static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off)
+{
+ int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ if (minor == DSPMINOR) {
+
+ return dsp_read(buf, count);
+
+ } else
+ return -EINVAL;
+}
+
+static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+ int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ if (minor == DSPMINOR) {
+
+ return dsp_write(buf, count);
+
+ } else
+ return -EINVAL;
+}
+
+static void eval_dsp_msg(WORD wMessage)
+{
+ switch (HIBYTE(wMessage)) {
+ case HIMT_PLAY_DONE:
+
+ if (dev.lastbank == LOBYTE(wMessage))
+ break;
+
+ dev.lastbank = LOBYTE(wMessage);
+
+ dev.CurDAQD->wSize = DAP_BUFF_SIZE;
+
+ if ((dev.DAPQ->wTail += PCTODSP_OFFSET(DAPQ_STRUCT_SIZE)) > dev.DAPQ->wSize)
+ dev.DAPQ->wTail = 0;
+
+ if (++dev.CurDAQD > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE))
+ dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+
+ if (dev.lastbank < 3) {
+
+ if (DAPF_to_bank(dev.lastbank) > 0) {
+
+ mdelay(1);
+ msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+
+ }
+ else if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
+
+ memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+ clear_bit(F_WRITING, &dev.flags);
+ msnd_disable_irq(&dev);
+
+ }
+ }
+
+ if (test_bit(F_WRITEBLOCK, &dev.flags))
+ wake_up_interruptible(&dev.writeblock);
+
+ break;
+
+ case HIMT_RECORD_DONE: {
+
+ WORD wTemp;
+
+ wTemp = dev.DARQ->wTail + (DARQ_STRUCT_SIZE / 2);
+
+ if (wTemp > dev.DARQ->wSize)
+ wTemp = 0;
+
+ while (wTemp == dev.DARQ->wHead);
+
+ dev.DARQ->wTail = wTemp;
+
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ if (bank_to_DARF(LOBYTE(wMessage)) == 0 &&
+ !test_bit(F_READBLOCK, &dev.flags)) {
+
+ memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
+ clear_bit(F_READING, &dev.flags);
+ msnd_disable_irq(&dev);
+
+ }
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ if (test_bit(F_READBLOCK, &dev.flags))
+ wake_up_interruptible(&dev.readblock);
+
+ } break;
+
+ case HIMT_DSP:
+ switch (LOBYTE(wMessage)) {
+ case HIDSP_PLAY_UNDER:
+ case HIDSP_INT_PLAY_UNDER:
+ printk(KERN_INFO LOGNAME ": Write underflow\n");
+ reset_play_queue();
+ break;
+
+ case HIDSP_INT_RECORD_OVER:
+ printk(KERN_INFO LOGNAME ": Read overflow\n");
+ reset_record_queue();
+ break;
+
+ default:
+ printk(KERN_INFO LOGNAME ": DSP message %u\n", LOBYTE(wMessage));
+ break;
+ }
+ break;
+
+ case HIMT_MIDI_IN_UCHAR:
+ if (dev.midi_in_interrupt)
+ (*dev.midi_in_interrupt)(&dev);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (test_bit(F_INTERRUPT, &dev.flags) ||
+ ((multisound_dev_t *)dev_id != &dev))
+ return;
+
+ set_bit(F_INTERRUPT, &dev.flags);
+
+ if (test_bit(F_BANKONE, &dev.flags))
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ inb(dev.io + HP_RXL);
+
+ while (dev.DSPQ->wTail != dev.DSPQ->wHead) {
+
+ eval_dsp_msg(*(dev.pwDSPQData + dev.DSPQ->wHead));
+
+ if (++dev.DSPQ->wHead > dev.DSPQ->wSize)
+ dev.DSPQ->wHead = 0;
+ }
+
+ if (test_bit(F_BANKONE, &dev.flags))
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+
+ clear_bit(F_INTERRUPT, &dev.flags);
+}
+
+static struct file_operations dev_fileops = {
+ NULL,
+ dev_read,
+ dev_write,
+ NULL,
+ NULL,
+ dev_ioctl,
+ NULL,
+ dev_open,
+ dev_close,
+};
+
+__initfunc(static int reset_dsp(void))
+{
+ int timeout = 20000;
+
+ outb(HPDSPRESET_ON, dev.io + HP_DSPR);
+
+ mdelay(1);
+
+ dev.info = inb(dev.io + HP_INFO);
+
+ outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
+
+ mdelay(1);
+
+ while (timeout-- > 0) {
+
+ if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
+ return 0;
+
+ mdelay(1);
+ }
+
+ printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
+
+ return -EIO;
+}
+
+__initfunc(static int probe_multisound(void))
+{
+ char *xv, *rev = NULL;
+ char *pin = "Pinnacle", *fiji = "Fiji";
+ char *pinfiji = "Pinnacle/Fiji";
+
+ if (check_region(dev.io, dev.numio)) {
+
+ printk(KERN_ERR LOGNAME ": I/O port conflict\n");
+ return -ENODEV;
+ }
+
+ request_region(dev.io, dev.numio, "probing");
+
+ if (reset_dsp() < 0) {
+
+ release_region(dev.io, dev.numio);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO LOGNAME ": DSP reset successful\n");
+
+ switch (dev.info >> 4) {
+ case 0xf: xv = "<= 1.15"; break;
+ case 0x1: xv = "1.18/1.2"; break;
+ case 0x2: xv = "1.3"; break;
+ case 0x3: xv = "1.4"; break;
+ default: xv = "unknown"; break;
+ }
+
+ switch (dev.info & 0x7) {
+ case 0x0: rev = "I"; dev.name = pin; break;
+ case 0x1: rev = "F"; dev.name = pin; break;
+ case 0x2: rev = "G"; dev.name = pin; break;
+ case 0x3: rev = "H"; dev.name = pin; break;
+ case 0x4: rev = "E"; dev.name = fiji; break;
+ case 0x5: rev = "C"; dev.name = fiji; break;
+ case 0x6: rev = "D"; dev.name = fiji; break;
+ case 0x7:
+ rev = "A-B (Fiji) or A-E (Pinnacle)";
+ dev.name = pinfiji;
+ break;
+ }
+
+ printk(KERN_INFO LOGNAME ": Turtle Beach %s revision %s, Xilinx version %s, "
+ "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n",
+ dev.name,
+ rev, xv,
+ dev.io, dev.io + dev.numio - 1,
+ dev.irq,
+ dev.base, dev.base + 0x7fff);
+
+ release_region(dev.io, dev.numio);
+
+ return 0;
+}
+
+__initfunc(static int init_sma(void))
+{
+ int n;
+ LPDAQD lpDAQ;
+
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ memset_io(dev.base, 0, 0x8000);
+
+ outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ memset_io(dev.base, 0, 0x8000);
+
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+ dev.DAPQ = (struct JobQueueStruct *)(dev.base + DAPQ_OFFSET);
+ dev.DARQ = (struct JobQueueStruct *)(dev.base + DARQ_OFFSET);
+ dev.MODQ = (struct JobQueueStruct *)(dev.base + MODQ_OFFSET);
+ dev.MIDQ = (struct JobQueueStruct *)(dev.base + MIDQ_OFFSET);
+ dev.DSPQ = (struct JobQueueStruct *)(dev.base + DSPQ_OFFSET);
+
+ dev.SMA = (struct SMA0_CommonData *)(dev.base + SMA_STRUCT_START);
+
+ dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
+ dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+
+ dev.sample_size = DEFSAMPLESIZE;
+ dev.sample_rate = DEFSAMPLERATE;
+ dev.channels = DEFCHANNELS;
+
+ for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) {
+
+ writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart);
+ writew(DAP_BUFF_SIZE, &lpDAQ->wSize);
+ writew(1, &lpDAQ->wFormat);
+ writew(dev.sample_size, &lpDAQ->wSampleSize);
+ writew(dev.channels, &lpDAQ->wChannels);
+ writew(dev.sample_rate, &lpDAQ->wSampleRate);
+ writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+ writew(n + 1, &lpDAQ->wFlags);
+ }
+
+ for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) {
+
+ writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart);
+ writew(DAR_BUFF_SIZE, &lpDAQ->wSize);
+ writew(1, &lpDAQ->wFormat);
+ writew(dev.sample_size, &lpDAQ->wSampleSize);
+ writew(dev.channels, &lpDAQ->wChannels);
+ writew(dev.sample_rate, &lpDAQ->wSampleRate);
+ writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg);
+ writew(n + 1, &lpDAQ->wFlags);
+
+ }
+
+ dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF);
+ dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF);
+ dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF);
+
+ writew(PCTODSP_BASED(MIDQ_DATA_BUFF), &dev.MIDQ->wStart);
+ writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, &dev.MIDQ->wSize);
+ writew(0, &dev.MIDQ->wHead);
+ writew(0, &dev.MIDQ->wTail);
+
+ writew(PCTODSP_BASED(MODQ_DATA_BUFF), &dev.MODQ->wStart);
+ writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, &dev.MODQ->wSize);
+ writew(0, &dev.MODQ->wHead);
+ writew(0, &dev.MODQ->wTail);
+
+ writew(PCTODSP_BASED(DAPQ_DATA_BUFF), &dev.DAPQ->wStart);
+ writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, &dev.DAPQ->wSize);
+ writew(0, &dev.DAPQ->wHead);
+ writew(0, &dev.DAPQ->wTail);
+
+ writew(PCTODSP_BASED(DARQ_DATA_BUFF), &dev.DARQ->wStart);
+ writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, &dev.DARQ->wSize);
+ writew(0, &dev.DARQ->wHead);
+ writew(0, &dev.DARQ->wTail);
+
+ writew(PCTODSP_BASED(DSPQ_DATA_BUFF), &dev.DSPQ->wStart);
+ writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, &dev.DSPQ->wSize);
+ writew(0, &dev.DSPQ->wHead);
+ writew(0, &dev.DSPQ->wTail);
+
+ writew(0, &dev.SMA->wCurrPlayBytes);
+ writew(0, &dev.SMA->wCurrRecordBytes);
+
+ writew(0, &dev.SMA->wCurrPlayVolLeft);
+ writew(0, &dev.SMA->wCurrPlayVolRight);
+
+ writew(0, &dev.SMA->wCurrInVolLeft);
+ writew(0, &dev.SMA->wCurrInVolRight);
+
+ writew(0, &dev.SMA->wCurrMastVolLeft);
+ writew(0, &dev.SMA->wCurrMastVolRight);
+
+ writel(0x00010000, &dev.SMA->dwCurrPlayPitch);
+ writel(0x00000001, &dev.SMA->dwCurrPlayRate);
+
+ writew(0x0000, &dev.SMA->wCurrDSPStatusFlags);
+ writew(0x0000, &dev.SMA->wCurrHostStatusFlags);
+
+ writew(0x303, &dev.SMA->wCurrInputTagBits);
+ writew(0, &dev.SMA->wCurrLeftPeak);
+ writew(0, &dev.SMA->wCurrRightPeak);
+
+ writeb(0, &dev.SMA->bInPotPosRight);
+ writeb(0, &dev.SMA->bInPotPosLeft);
+
+ writeb(0, &dev.SMA->bAuxPotPosRight);
+ writeb(0, &dev.SMA->bAuxPotPosLeft);
+
+ writew(1, &dev.SMA->wCurrPlayFormat);
+ writew(dev.sample_size, &dev.SMA->wCurrPlaySampleSize);
+ writew(dev.channels, &dev.SMA->wCurrPlayChannels);
+ writew(dev.sample_rate, &dev.SMA->wCurrPlaySampleRate);
+ writew(dev.sample_rate, &dev.SMA->wCalFreqAtoD);
+
+ return 0;
+}
+
+__initfunc(static int calibrate_adc(WORD srate))
+{
+ if (!dev.calibrate_signal) {
+
+ printk(KERN_INFO LOGNAME ": ADC calibration to board ground ");
+ writew(readw(&dev.SMA->wCurrHostStatusFlags)
+ | 0x0001, &dev.SMA->wCurrHostStatusFlags);
+ }
+ else {
+
+ printk(KERN_INFO LOGNAME ": ADC calibration to signal ground ");
+ writew(readw(&dev.SMA->wCurrHostStatusFlags)
+ & ~0x0001, &dev.SMA->wCurrHostStatusFlags);
+ }
+
+ writew(srate, &dev.SMA->wCalFreqAtoD);
+
+ if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
+ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
+
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ;
+ schedule();
+ current->timeout = 0;
+ printk("successful\n");
+ return 0;
+ }
+
+ printk("failed\n");
+
+ return -EIO;
+}
+
+__initfunc(static int upload_dsp_code(void))
+{
+ outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+#ifdef HAVE_DSPCODEH
+ printk(KERN_INFO LOGNAME ": Using resident Turtle Beach DSP code\n");
+#else
+ printk(KERN_INFO LOGNAME ": Loading Turtle Beach DSP code\n");
+ INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE);
+ if (!INITCODE) {
+ printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
+ return -EBUSY;
+ }
+
+ PERMCODESIZE = mod_firmware_load(PERMCODEFILE, &PERMCODE);
+ if (!PERMCODE) {
+ printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
+ vfree(INITCODE);
+ return -EBUSY;
+ }
+#endif
+ memcpy_toio(dev.base, PERMCODE, PERMCODESIZE);
+
+ if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
+ return -ENODEV;
+ }
+
+#ifndef HAVE_DSPCODEH
+ vfree(INITCODE);
+ vfree(PERMCODE);
+#endif
+
+ return 0;
+}
+
+__initfunc(static int initialize(void))
+{
+ int err, timeout;
+
+ if ((err = init_sma()) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
+ return err;
+ }
+
+ if ((err = reset_dsp()) < 0)
+ return err;
+
+ if ((err = upload_dsp_code()) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
+ return err;
+
+ } else
+ printk(KERN_INFO LOGNAME ": DSP upload successful\n");
+
+ timeout = 2000;
+
+ while (readw(dev.base)) {
+
+ mdelay(1);
+ if (--timeout < 0)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+__initfunc(static int attach_multisound(void))
+{
+ int err;
+
+ printk(KERN_DEBUG LOGNAME ": Intializing DSP\n");
+
+ if ((err = request_irq(dev.irq, intr, SA_SHIRQ, DEVNAME, &dev)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
+ return err;
+
+ }
+
+ request_region(dev.io, dev.numio, DEVNAME);
+
+ if ((err = initialize()) < 0) {
+
+ printk(KERN_WARNING LOGNAME ": Initialization failure\n");
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ return err;
+
+ }
+
+ if ((err = msnd_register(&dev)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n");
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ return err;
+ }
+
+ if ((DSPMINOR = register_sound_dsp(&dev_fileops)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n");
+ msnd_unregister(&dev);
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ return DSPMINOR;
+ }
+
+ if ((MIXERMINOR = register_sound_mixer(&dev_fileops)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n");
+ unregister_sound_mixer(MIXERMINOR);
+ msnd_unregister(&dev);
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ return MIXERMINOR;
+ }
+ printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", MIXERMINOR, DSPMINOR);
+
+ calibrate_adc(dev.sample_rate);
+ set_recsrc(0);
+
+ return 0;
+}
+
+static void unload_multisound(void)
+{
+ release_region(dev.io, dev.numio);
+ free_irq(dev.irq, &dev);
+ unregister_sound_mixer(MIXERMINOR);
+ unregister_sound_dsp(DSPMINOR);
+ msnd_unregister(&dev);
+}
+
+static void mod_inc_ref(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void mod_dec_ref(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>");
+MODULE_DESCRIPTION ("Turtle Beach " LONGNAME " Linux Driver");
+MODULE_PARM (io, "i");
+MODULE_PARM (irq, "i");
+MODULE_PARM (mem, "i");
+MODULE_PARM (major, "i");
+MODULE_PARM (fifosize, "i");
+MODULE_PARM (calibrate_signal, "i");
+
+static int io __initdata = -1;
+static int irq __initdata = -1;
+static int mem __initdata = -1;
+static int fifosize __initdata = DEFFIFOSIZE;
+static int
+calibrate_signal __initdata = 0;
+
+int init_module(void)
+{
+ int err;
+
+ printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
+ VERSION ", Copyright (C) 1998 Andrew Veliath\n");
+
+ if (io == -1 || irq == -1 || mem == -1) {
+
+ printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
+ }
+
+ if (io == -1 ||
+ !(io == 0x290 ||
+ io == 0x260 ||
+ io == 0x250 ||
+ io == 0x240 ||
+ io == 0x230 ||
+ io == 0x220 ||
+ io == 0x210 ||
+ io == 0x3e0)) {
+
+ printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set\n");
+ return -EINVAL;
+ }
+
+ if (irq == -1 ||
+ !(irq == 5 ||
+ irq == 7 ||
+ irq == 9 ||
+ irq == 10 ||
+ irq == 11 ||
+ irq == 12)) {
+
+ printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
+ return -EINVAL;
+ }
+
+ if (mem == -1 ||
+ !(mem == 0xb0000 ||
+ mem == 0xc8000 ||
+ mem == 0xd0000 ||
+ mem == 0xd8000 ||
+ mem == 0xe0000 ||
+ mem == 0xe8000)) {
+
+ printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
+ "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+ return -EINVAL;
+ }
+
+ if (fifosize < 16)
+ fifosize = 16;
+
+ if (fifosize > 768)
+ fifosize = 768;
+
+ dev.type = msndPinnacle;
+ dev.io = io;
+ dev.numio = DSP_NUMIO;
+ dev.irq = irq;
+ dev.base = phys_to_virt(mem);
+ dev.fifosize = fifosize * 1024;
+ dev.calibrate_signal = calibrate_signal ? 1 : 0;
+ dev.recsrc = 0;
+ dev.inc_ref = mod_inc_ref;
+ dev.dec_ref = mod_dec_ref;
+
+ init_waitqueue(&dev.writeblock);
+ init_waitqueue(&dev.readblock);
+ msnd_fifo_init(&dev.DAPF);
+ msnd_fifo_init(&dev.DARF);
+ spin_lock_init(&dev.lock);
+
+ printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize);
+
+ if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n");
+ return err;
+ }
+
+ if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n");
+ msnd_fifo_free(&dev.DAPF);
+ return err;
+ }
+
+ if ((err = probe_multisound()) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Probe failed\n");
+ msnd_fifo_free(&dev.DAPF);
+ msnd_fifo_free(&dev.DARF);
+ return err;
+
+ }
+
+ if ((err = attach_multisound()) < 0) {
+
+ printk(KERN_ERR LOGNAME ": Attach failed\n");
+ msnd_fifo_free(&dev.DAPF);
+ msnd_fifo_free(&dev.DARF);
+ return err;
+
+ }
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ printk(KERN_INFO LOGNAME ": Unloading\n");
+
+ unload_multisound();
+
+ msnd_fifo_free(&dev.DAPF);
+ msnd_fifo_free(&dev.DARF);
+
+}
+#endif
--- /dev/null
+/*********************************************************************
+ *
+ * msnd_pinnacle.h
+ *
+ * Turtle Beach MultiSound Soundcard Driver for Linux
+ *
+ * Some parts of this header file were derived from the Turtle Beach
+ * MultiSound Driver Development Kit.
+ *
+ * Copyright (C) 1998 Andrew Veliath
+ * Copyright (C) 1993 Turtle Beach Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: msnd_pinnacle.h,v 1.3 1998/06/09 20:39:34 andrewtv Exp $
+ *
+ ********************************************************************/
+#ifndef __MSND_PINNACLE_H
+#define __MSND_PINNACLE_H
+
+#define DSP_NUMIO 0x08
+
+#define HP_DSPR 0x04
+#define HP_BLKS 0x04
+
+#define HPDSPRESET_OFF 2
+#define HPDSPRESET_ON 0
+
+#define HPBLKSEL_0 2
+#define HPBLKSEL_1 3
+
+#define HIMT_DAT_OFF 0x03
+
+#define HIDSP_PLAY_UNDER 0x00
+#define HIDSP_INT_PLAY_UNDER 0x01
+#define HIDSP_SSI_TX_UNDER 0x02
+#define HIDSP_RECQ_OVERFLOW 0x08
+#define HIDSP_INT_RECORD_OVER 0x09
+#define HIDSP_SSI_RX_OVERFLOW 0x0a
+
+#define HIDSP_MIDI_IN_OVER 0x10
+
+#define HIDSP_MIDI_FRAME_ERR 0x11
+#define HIDSP_MIDI_PARITY_ERR 0x12
+#define HIDSP_MIDI_OVERRUN_ERR 0x13
+
+#define HIDSP_INPUT_CLIPPING 0x20
+#define HIDSP_MIX_CLIPPING 0x30
+#define HIDSP_DAT_IN_OFF 0x21
+
+#define HDEX_BASE 0x92
+#define HDEX_PLAY_START (0 + HDEX_BASE)
+#define HDEX_PLAY_STOP (1 + HDEX_BASE)
+#define HDEX_PLAY_PAUSE (2 + HDEX_BASE)
+#define HDEX_PLAY_RESUME (3 + HDEX_BASE)
+#define HDEX_RECORD_START (4 + HDEX_BASE)
+#define HDEX_RECORD_STOP (5 + HDEX_BASE)
+#define HDEX_MIDI_IN_START (6 + HDEX_BASE)
+#define HDEX_MIDI_IN_STOP (7 + HDEX_BASE)
+#define HDEX_MIDI_OUT_START (8 + HDEX_BASE)
+#define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE)
+#define HDEX_AUX_REQ (10 + HDEX_BASE)
+
+#define HDEXAR_SET_ANA_IN 0
+#define HDEXAR_CLEAR_PEAKS 1
+#define HDEXAR_IN_SET_POTS 2
+#define HDEXAR_AUX_SET_POTS 3
+#define HDEXAR_CAL_A_TO_D 4
+#define HDEXAR_RD_EXT_DSP_BITS 5
+
+#define HDEXAR_SET_SYNTH_IN 4
+#define HDEXAR_READ_DAT_IN 5
+#define HDEXAR_MIC_SET_POTS 6
+#define HDEXAR_SET_DAT_IN 7
+
+#define HDEXAR_SET_SYNTH_48 8
+#define HDEXAR_SET_SYNTH_44 9
+
+#define TIME_PRO_RESET_DONE 0x028A
+#define TIME_PRO_SYSEX 0x001E
+#define TIME_PRO_RESET 0x0032
+
+#define AGND 0x01
+#define SIGNAL 0x02
+
+#define EXT_DSP_BIT_DCAL 0x0001
+#define EXT_DSP_BIT_MIDI_CON 0x0002
+
+#define BUFFSIZE 0x8000
+#define HOSTQ_SIZE 0x40
+
+#define SRAM_CNTL_START 0x7F00
+#define SMA_STRUCT_START 0x7F40
+
+#define DAP_BUFF_SIZE 0x2400
+#define DAR_BUFF_SIZE 0x2000
+
+#define DAPQ_STRUCT_SIZE 0x10
+#define DARQ_STRUCT_SIZE 0x10
+#define DAPQ_BUFF_SIZE (3 * 0x10)
+#define DARQ_BUFF_SIZE (3 * 0x10)
+#define MODQ_BUFF_SIZE 0x400
+#define MIDQ_BUFF_SIZE 0x800
+#define DSPQ_BUFF_SIZE 0x5A0
+
+#define DAPQ_DATA_BUFF 0x6C00
+#define DARQ_DATA_BUFF 0x6C30
+#define MODQ_DATA_BUFF 0x6C60
+#define MIDQ_DATA_BUFF 0x7060
+#define DSPQ_DATA_BUFF 0x7860
+
+#define DAPQ_OFFSET SRAM_CNTL_START
+#define DARQ_OFFSET (SRAM_CNTL_START + 0x08)
+#define MODQ_OFFSET (SRAM_CNTL_START + 0x10)
+#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
+#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
+
+#define WAVEHDR_MOP 0
+#define EXTOUT_MOP 1
+#define HWINIT_MOP 0xFE
+#define NO_MOP 0xFF
+
+#define MAX_MOP 1
+
+#define EXTIN_MIP 0
+#define WAVEHDR_MIP 1
+#define HWINIT_MIP 0xFE
+
+#define MAX_MIP 1
+
+struct SMA0_CommonData {
+ WORD wCurrPlayBytes;
+ WORD wCurrRecordBytes;
+ WORD wCurrPlayVolLeft;
+ WORD wCurrPlayVolRight;
+
+ WORD wCurrInVolLeft;
+ WORD wCurrInVolRight;
+ WORD wCurrMHdrVolLeft;
+ WORD wCurrMHdrVolRight;
+
+ DWORD dwCurrPlayPitch;
+ DWORD dwCurrPlayRate;
+
+ WORD wCurrMIDIIOPatch;
+
+ WORD wCurrPlayFormat;
+ WORD wCurrPlaySampleSize;
+ WORD wCurrPlayChannels;
+ WORD wCurrPlaySampleRate;
+
+ WORD wCurrRecordFormat;
+ WORD wCurrRecordSampleSize;
+ WORD wCurrRecordChannels;
+ WORD wCurrRecordSampleRate;
+
+ WORD wCurrDSPStatusFlags;
+ WORD wCurrHostStatusFlags;
+
+ WORD wCurrInputTagBits;
+ WORD wCurrLeftPeak;
+ WORD wCurrRightPeak;
+
+ BYTE bMicPotPosLeft;
+ BYTE bMicPotPosRight;
+
+ BYTE bMicPotMaxLeft;
+ BYTE bMicPotMaxRight;
+
+ BYTE bInPotPosLeft;
+ BYTE bInPotPosRight;
+
+ BYTE bAuxPotPosLeft;
+ BYTE bAuxPotPosRight;
+
+ BYTE bInPotMaxLeft;
+ BYTE bInPotMaxRight;
+ BYTE bAuxPotMaxLeft;
+ BYTE bAuxPotMaxRight;
+ BYTE bInPotMaxMethod;
+ BYTE bAuxPotMaxMethod;
+
+ WORD wCurrMastVolLeft;
+ WORD wCurrMastVolRight;
+
+ WORD wCalFreqAtoD;
+
+ WORD wCurrAuxVolLeft;
+ WORD wCurrAuxVolRight;
+
+ WORD wCurrPlay1VolLeft;
+ WORD wCurrPlay1VolRight;
+ WORD wCurrPlay2VolLeft;
+ WORD wCurrPlay2VolRight;
+ WORD wCurrPlay3VolLeft;
+ WORD wCurrPlay3VolRight;
+ WORD wCurrPlay4VolLeft;
+ WORD wCurrPlay4VolRight;
+ WORD wCurrPlay1PeakLeft;
+ WORD wCurrPlay1PeakRight;
+ WORD wCurrPlay2PeakLeft;
+ WORD wCurrPlay2PeakRight;
+ WORD wCurrPlay3PeakLeft;
+ WORD wCurrPlay3PeakRight;
+ WORD wCurrPlay4PeakLeft;
+ WORD wCurrPlay4PeakRight;
+ WORD wCurrPlayPeakLeft;
+ WORD wCurrPlayPeakRight;
+
+ WORD wCurrDATSR;
+ WORD wCurrDATRXCHNL;
+ WORD wCurrDATTXCHNL;
+ WORD wCurrDATRXRate;
+
+ DWORD dwDSPPlayCount;
+} GCC_PACKED;
+
+#ifdef HAVE_DSPCODEH
+# include "pndsperm.c"
+# include "pndspini.c"
+# define PERMCODE pndsperm
+# define INITCODE pndspini
+# define PERMCODESIZE sizeof(pndsperm)
+# define INITCODESIZE sizeof(pndspini)
+#else
+# define PERMCODEFILE CONFIG_MSNDPIN_PERM_FILE
+# define INITCODEFILE CONFIG_MSNDPIN_INIT_FILE
+# define PERMCODE dspini
+# define INITCODE permini
+# define PERMCODESIZE sizeof_dspini
+# define INITCODESIZE sizeof_permini
+#endif
+#define LONGNAME "MultiSound (Pinnacle/Fiji)"
+
+#endif /* __MSND_PINNACLE_H */
#else
#define MODULEPROCSTRING "Driver compiled into kernel"
#endif
-
+
+ down(&uts_sem);
+
len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"
"Load type: " MODULEPROCSTRING "\n"
"Kernel: %s %s %s %s %s\n"
"Config options: %x\n\nInstalled drivers: \n",
system_utsname.sysname, system_utsname.nodename, system_utsname.release,
system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);
+ up(&uts_sem);
for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) {
if (!sound_drivers[i].card_type)
#include <linux/config.h>
#include <linux/module.h>
-#ifdef CONFIG_VMIDI
-
#include "sound_config.h"
#include "soundmodule.h"
+
+#ifdef CONFIG_VMIDI
+
#include "v_midi.h"
static vmidi_devc *v_devc[2] = { NULL, NULL};
if (get_write_access(inode))
goto end_coredump;
if (init_private_file(&file, dentry, 3))
- goto end_coredump;
+ goto end_coredump_write;
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
close_coredump:
if (file.f_op->release)
file.f_op->release(inode,&file);
+end_coredump_write:
put_write_access(inode);
end_coredump:
set_fs(fs);
static struct super_block *mounts = NULL;
-static void devpts_put_inode(struct inode *inode)
-{
-}
-
-static void devpts_delete_inode(struct inode *inode)
-{
- inode->i_size = 0;
-}
-
static void devpts_put_super(struct super_block *sb)
{
struct devpts_sb_info *sbi = SBI(sb);
if ( inode->i_count != 1 )
printk("devpts_put_super: badness: entry %d count %d\n",
i, inode->i_count);
+ inode->i_nlink--;
iput(inode);
}
}
static struct super_operations devpts_sops = {
devpts_read_inode,
devpts_write_inode,
- devpts_put_inode,
- devpts_delete_inode,
+ NULL, /* put_inode */
+ NULL, /* delete_inode */
NULL, /* notify_change */
devpts_put_super,
NULL, /* write_super */
if ( ino >= NR_PTYS )
return; /* Bogus */
- inode->i_nlink = 1;
-
inode->i_mode = S_IFCHR;
inode->i_rdev = MKDEV(0,0); /* Gets filled in by devpts_pty_new() */
inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
inode->i_mode = sbi->mode | S_IFCHR;
inode->i_rdev = device;
+ inode->i_nlink++;
sbi->inodes[number] = inode;
}
}
if ( inode ) {
sbi->inodes[number] = NULL;
- inode->i_nlink = 0; /* Is this right? */
+ inode->i_nlink--;
iput(inode);
}
}
init_adfs_fs();
#endif
+#ifdef CONFIG_ADFS_FS
+ init_adfs_fs();
+#endif
+
#ifdef CONFIG_DEVPTS_FS
init_devpts_fs();
#endif
return i;
}
+/* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
+int get_acorn_filename(struct iso_directory_record * de,
+ char * retname, struct inode * inode)
+{
+ int std;
+ unsigned char * chr;
+ int retnamlen = isofs_name_translate(de->name,
+ de->name_len[0], retname);
+ if (retnamlen == 0) return 0;
+ std = sizeof(struct iso_directory_record) + de->name_len[0];
+ if (std & 1) std++;
+ if ((*((unsigned char *) de) - std) != 32) return retnamlen;
+ chr = ((unsigned char *) de) + std;
+ if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
+ if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
+ if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
+ && ((chr[12] & 0xf0) == 0xf0))
+ {
+ retname[retnamlen] = ',';
+ sprintf(retname+retnamlen+1, "%3.3x",
+ ((chr[12] & 0xf) << 8) | chr[11]);
+ retnamlen += 4;
+ }
+ return retnamlen;
+}
+
/*
* This should _really_ be cleaned up some day..
*/
p = tmpname;
} else
#endif
- {
- if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
- len = isofs_name_translate(de->name, de->name_len[0],
- tmpname);
- p = tmpname;
- } else {
- p = de->name;
- len = de->name_len[0];
- }
+ if (inode->i_sb->u.isofs_sb.s_mapping == 'a') {
+ len = get_acorn_filename(de, tmpname, inode);
+ p = tmpname;
+ } else
+ if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
+ len = isofs_name_translate(de->name,
+ de->name_len[0], tmpname);
+ p = tmpname;
+ } else {
+ p = de->name;
+ len = de->name_len[0];
}
}
if (len > 0) {
{
char *this_char,*value;
- popt->map = 'n';
+ popt->map = 'a';
popt->rock = 'y';
popt->joliet = 'y';
popt->cruft = 'n';
} else
#endif
if (!strcmp(this_char,"map") && value) {
- if (value[0] && !value[1] && strchr("on",*value))
+ if (value[0] && !value[1] && strchr("ano",*value))
popt->map = *value;
else if (!strcmp(value,"off")) popt->map = 'o';
else if (!strcmp(value,"normal")) popt->map = 'n';
+ else if (!strcmp(value,"acorn")) popt->map = 'a';
else return 0;
}
else if (!strcmp(this_char,"check") && value) {
dlen = get_joliet_filename(de, dir, page);
dpnt = page;
#endif
+ } else if (dir->i_sb->u.isofs_sb.s_mapping == 'a') {
+ dlen = get_acorn_filename(de, page, dir);
+ dpnt = page;
} else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
for (i = 0; i < dlen; i++) {
c = dpnt[i];
if (numblocks==0 || !(bh=map[numblocks-1]))
return(0);
- i = (numbits-(numblocks-1)*BLOCK_SIZE*8)/8;
+ i = ((numbits-(numblocks-1)*BLOCK_SIZE*8)/16)*2;
for (j=0; j<i; j++) {
sum += nibblemap[bh->b_data[j] & 0xf]
+ nibblemap[(bh->b_data[j]>>4) & 0xf];
}
- i = numbits%8;
+ i = numbits%16;
if (i!=0) {
- i = bh->b_data[j] | ~((1<<i) - 1);
+ i = *(__u16 *)(&bh->b_data[j]) | ~((1<<i) - 1);
sum += nibblemap[i & 0xf] + nibblemap[(i>>4) & 0xf];
+ sum += nibblemap[(i>>8) & 0xf] + nibblemap[(i>>12) & 0xf];
}
return(sum);
}
zone = block - sb->u.minix_sb.s_firstdatazone + 1;
bit = zone & 8191;
zone >>= 13;
- bh = sb->u.minix_sb.s_zmap[zone];
- if (!bh) {
+ if (zone >= sb->u.minix_sb.s_zmap_blocks) {
printk("minix_free_block: nonexistent bitmap buffer\n");
return;
}
+ bh = sb->u.minix_sb.s_zmap[zone];
if (!minix_clear_bit(bit,bh->b_data))
printk("free_block (%s:%d): bit already cleared\n",
kdevname(sb->s_dev), block);
}
repeat:
j = 8192;
- for (i=0 ; i<64 ; i++)
- if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL)
- if ((j=minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
- break;
- if (i>=64 || !bh || j>=8192)
+ bh = NULL;
+ for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) {
+ bh = sb->u.minix_sb.s_zmap[i];
+ if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
+ break;
+ }
+ if (!bh || j >= 8192)
return 0;
if (minix_set_bit(j,bh->b_data)) {
printk("new_block: bit already set");
int ino, block;
ino = inode->i_ino;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s: %d is out of range\n",
kdevname(inode->i_dev), ino);
return 0;
int ino, block;
ino = inode->i_ino;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s: %d is out of range\n",
kdevname(inode->i_dev), ino);
return 0;
printk("free_inode: inode on nonexistent device\n");
return;
}
- if (inode->i_ino < 1 || inode->i_ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
ino = inode->i_ino;
- if (!(bh=inode->i_sb->u.minix_sb.s_imap[ino >> 13])) {
+ if ((ino >> 13) >= inode->i_sb->u.minix_sb.s_imap_blocks) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
+ bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13];
minix_clear_inode(inode);
clear_inode(inode);
if (!minix_clear_bit(ino & 8191, bh->b_data))
inode->i_sb = sb;
inode->i_flags = inode->i_sb->s_flags;
j = 8192;
- for (i=0 ; i<8 ; i++)
- if ((bh = inode->i_sb->u.minix_sb.s_imap[i]) != NULL)
- if ((j=minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
- break;
+ bh = NULL;
+ for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++) {
+ bh = inode->i_sb->u.minix_sb.s_imap[i];
+ if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
+ break;
+ }
if (!bh || j >= 8192) {
iput(inode);
return NULL;
}
mark_buffer_dirty(bh, 1);
j += i*8192;
- if (!j || j >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!j || j > inode->i_sb->u.minix_sb.s_ninodes) {
iput(inode);
return NULL;
}
sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state;
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
}
- for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++)
+ for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++)
brelse(sb->u.minix_sb.s_imap[i]);
- for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
+ for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++)
brelse(sb->u.minix_sb.s_zmap[i]);
brelse (sb->u.minix_sb.s_sbh);
kfree(sb->u.minix_sb.s_imap);
const char * errmsg;
struct inode *root_inode;
- /* N.B. These should be compile-time tests */
+ /* N.B. These should be compile-time tests.
+ Unfortunately that is impossible. */
if (32 != sizeof (struct minix_inode))
panic("bad V1 i-node size");
if (64 != sizeof(struct minix2_inode))
s->u.minix_sb.s_version = MINIX_V1;
s->u.minix_sb.s_dirsize = 16;
s->u.minix_sb.s_namelen = 14;
+ s->u.minix_sb.s_link_max = MINIX_LINK_MAX;
} else if (s->s_magic == MINIX_SUPER_MAGIC2) {
s->u.minix_sb.s_version = MINIX_V1;
s->u.minix_sb.s_dirsize = 32;
s->u.minix_sb.s_namelen = 30;
+ s->u.minix_sb.s_link_max = MINIX_LINK_MAX;
} else if (s->s_magic == MINIX2_SUPER_MAGIC) {
s->u.minix_sb.s_version = MINIX_V2;
+ s->u.minix_sb.s_nzones = ms->s_zones;
s->u.minix_sb.s_dirsize = 16;
s->u.minix_sb.s_namelen = 14;
+ s->u.minix_sb.s_link_max = MINIX2_LINK_MAX;
} else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
s->u.minix_sb.s_version = MINIX_V2;
+ s->u.minix_sb.s_nzones = ms->s_zones;
s->u.minix_sb.s_dirsize = 32;
s->u.minix_sb.s_namelen = 30;
+ s->u.minix_sb.s_link_max = MINIX2_LINK_MAX;
} else
goto out_no_fs;
- if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS)
- goto out_too_big;
/*
* Allocate the buffer map to keep the superblock small.
*/
- i = (MINIX_I_MAP_SLOTS + MINIX_Z_MAP_SLOTS) * sizeof(bh);
+ i = (s->u.minix_sb.s_imap_blocks + s->u.minix_sb.s_zmap_blocks) * sizeof(bh);
map = kmalloc(i, GFP_KERNEL);
if (!map)
goto out_no_map;
memset(map, 0, i);
s->u.minix_sb.s_imap = &map[0];
- s->u.minix_sb.s_zmap = &map[MINIX_I_MAP_SLOTS];
+ s->u.minix_sb.s_zmap = &map[s->u.minix_sb.s_imap_blocks];
block=2;
for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) {
goto out_no_bitmap;
block++;
}
- if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks)
- goto out_no_bitmap;
minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data);
if (!s->s_root)
goto out_iput;
+ s->s_root->d_op = &minix_dentry_operations;
+
if (!(s->s_flags & MS_RDONLY)) {
ms->s_state &= ~MINIX_VALID_FS;
mark_buffer_dirty(bh, 1);
out_no_bitmap:
printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
out_freemap:
- for(i=0;i<MINIX_I_MAP_SLOTS;i++)
+ for (i = 0; i < s->u.minix_sb.s_imap_blocks; i++)
brelse(s->u.minix_sb.s_imap[i]);
- for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
+ for (i = 0; i < s->u.minix_sb.s_zmap_blocks; i++)
brelse(s->u.minix_sb.s_zmap[i]);
kfree(s->u.minix_sb.s_imap);
goto out_release;
printk ("MINIX-fs: can't allocate map\n");
goto out_release;
-out_too_big:
- if (!silent)
- printk ("MINIX-fs: filesystem too big\n");
- goto out_release;
-
out_no_fs:
if (!silent)
printk("VFS: Can't find a minix or minix V2 filesystem on dev "
ino = inode->i_ino;
inode->i_op = NULL;
inode->i_mode = 0;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
ino = inode->i_ino;
inode->i_op = NULL;
inode->i_mode = 0;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
int ino, block;
ino = inode->i_ino;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
int ino, block;
ino = inode->i_ino;
- if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
+ if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
static inline int namecompare(int len, int maxlen,
const char * name, const char * buffer)
{
- if (len > maxlen)
- return 0;
if (len < maxlen && buffer[len])
return 0;
return !memcmp(name, buffer, len);
}
-/*
- * ok, we cannot use strncmp, as the name is not in our data space.
- * Thus we'll have to use minix_match. No big problem. Match also makes
- * some sanity tests.
- *
- * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
- */
-static int minix_match(int len, const char * name,
- struct buffer_head * bh, unsigned long * offset,
- struct minix_sb_info * info)
-{
- struct minix_dir_entry * de;
-
- de = (struct minix_dir_entry *) (bh->b_data + *offset);
- *offset += info->s_dirsize;
- if (!de->inode || len > info->s_namelen)
- return 0;
- return namecompare(len,info->s_namelen,name,de->name);
-}
-
/*
* minix_find_entry()
*
unsigned long block, offset;
struct buffer_head * bh;
struct minix_sb_info * info;
+ struct minix_dir_entry *de;
*res_dir = NULL;
if (!dir || !dir->i_sb)
continue;
}
}
- *res_dir = (struct minix_dir_entry *) (bh->b_data + offset);
- if (minix_match(namelen,name,bh,&offset,info))
+ de = (struct minix_dir_entry *) (bh->b_data + offset);
+ offset += info->s_dirsize;
+ if (de->inode && namecompare(namelen,info->s_namelen,name,de->name)) {
+ *res_dir = de;
return bh;
+ }
if (offset < bh->b_size)
continue;
brelse(bh);
block++;
}
brelse(bh);
- *res_dir = NULL;
return NULL;
}
+#ifndef NO_TRUNCATE
+
+static int minix_hash(struct dentry *dentry, struct qstr *qstr)
+{
+ unsigned long hash;
+ int i;
+ const char *name;
+
+ i = dentry->d_inode->i_sb->u.minix_sb.s_namelen;
+ if (i >= qstr->len)
+ return 0;
+ /* Truncate the name in place, avoids having to define a compare
+ function. */
+ qstr->len = i;
+ name = qstr->name;
+ hash = init_name_hash();
+ while (i--)
+ hash = partial_name_hash(*name++, hash);
+ qstr->hash = end_name_hash(hash);
+ return 0;
+}
+
+#endif
+
+struct dentry_operations minix_dentry_operations = {
+ 0, /* revalidate */
+#ifndef NO_TRUNCATE
+ minix_hash,
+#else
+ 0,
+#endif
+ 0 /* compare */
+};
+
int minix_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode * inode = NULL;
struct minix_dir_entry * de;
struct buffer_head * bh;
+#ifndef NO_TRUNCATE
+ dentry->d_op = &minix_dentry_operations;
+#endif
bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
if (bh) {
int ino = de->inode;
brelse(bh);
return -EEXIST;
}
- if (dir->i_nlink >= MINIX_LINK_MAX)
+ if (dir->i_nlink >= info->s_link_max)
return -EMLINK;
inode = minix_new_inode(dir);
if (!inode)
retval = -ENOENT;
goto end_rmdir;
}
- if (inode->i_count > 1) {
+ if (dentry->d_count > 1) {
retval = -EBUSY;
goto end_rmdir;
}
if (S_ISDIR(inode->i_mode))
return -EPERM;
- if (inode->i_nlink >= MINIX_LINK_MAX)
+ if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
return -EMLINK;
bh = minix_find_entry(dir, dentry->d_name.name,
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
retval = -EMLINK;
- if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX)
+ if (!new_inode && new_dir->i_nlink >= info->s_link_max)
goto end_rename;
}
if (!new_bh) {
/*
* CREATE processing is complicated. The keyword here is `overloaded.'
- * There's a small race condition here between the check for existence
- * and the actual create() call, but one could even consider this a
- * feature because this only happens if someone else creates the file
- * at the same time.
+ * The parent directory is kept locked between the check for existence
+ * and the actual create() call in compliance with VFS protocols.
* N.B. After this call _both_ argp->fh and resp->fh need an fh_put
*/
static int
svc_fh *dirfhp = &argp->fh;
svc_fh *newfhp = &resp->fh;
struct iattr *attr = &argp->attrs;
- struct inode *inode = NULL;
- int nfserr, type, mode;
- int rdonly = 0, exists;
+ struct inode *inode;
+ int nfserr, type, mode, rdonly = 0;
dev_t rdev = NODEV;
dprintk("nfsd: CREATE %d/%ld %s\n",
SVCFH_DEV(dirfhp), SVCFH_INO(dirfhp), argp->name);
- /* Get the directory inode */
+ /* First verify the parent filehandle */
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
if (nfserr)
goto done; /* must fh_put dirfhp even on error */
} else if (nfserr)
goto done;
- /* First, check if the file already exists. */
- exists = !nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
-
- if (newfhp->fh_dverified)
- inode = newfhp->fh_dentry->d_inode;
+ /*
+ * Do a lookup to verify the new filehandle.
+ */
+ nfserr = nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
+ if (nfserr) {
+ if (nfserr != nfserr_noent)
+ goto done;
+ /*
+ * If the new filehandle wasn't verified, we can't tell
+ * whether the file exists or not. Time to bail ...
+ */
+ nfserr = nfserr_acces;
+ if (!newfhp->fh_dverified) {
+ printk(KERN_WARNING
+ "nfsd_proc_create: filehandle not verified\n");
+ goto done;
+ }
+ }
- /* Get rid of this soon... */
- if (exists && !inode) {
- printk("nfsd_proc_create: Wheee... exists but d_inode==NULL\n");
- nfserr = nfserr_rofs;
+ /*
+ * Lock the parent directory and check for existence.
+ */
+ nfserr = fh_lock_parent(dirfhp, newfhp->fh_dentry);
+ if (nfserr)
goto done;
- }
+ inode = newfhp->fh_dentry->d_inode;
/* Unfudge the mode bits */
if (attr->ia_valid & ATTR_MODE) {
mode = attr->ia_mode & ~S_IFMT;
if (!type) /* HP weirdness */
type = S_IFREG;
- } else if (exists) {
+ } else if (inode) {
type = inode->i_mode & S_IFMT;
mode = inode->i_mode & ~S_IFMT;
} else {
/* This is for "echo > /dev/null" a la SunOS. Argh. */
nfserr = nfserr_rofs;
- if (rdonly && (!exists || type == S_IFREG))
- goto done;
+ if (rdonly && (!inode || type == S_IFREG))
+ goto out_unlock;
attr->ia_valid |= ATTR_MODE;
attr->ia_mode = type | mode;
/* Special treatment for non-regular files according to the
* gospel of sun micro
*/
- nfserr = 0;
if (type != S_IFREG) {
int is_borc = 0;
u32 size = attr->ia_size;
} else if (size != rdev) {
/* dev got truncated because of 16bit Linux dev_t */
nfserr = nfserr_io; /* or nfserr_inval? */
- goto done;
+ goto out_unlock;
} else {
/* Okay, char or block special */
is_borc = 1;
}
/* Make sure the type and device matches */
- if (exists && (type != (inode->i_mode & S_IFMT)
- || (is_borc && inode->i_rdev != rdev))) {
- nfserr = nfserr_exist;
- goto done;
- }
+ nfserr = nfserr_exist;
+ if (inode && (type != (inode->i_mode & S_IFMT) ||
+ (is_borc && inode->i_rdev != rdev)))
+ goto out_unlock;
}
- if (!exists) {
+ nfserr = 0;
+ if (!inode) {
/* File doesn't exist. Create it and set attrs */
nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
attr, type, rdev, newfhp);
nfserr = nfsd_setattr(rqstp, newfhp, attr);
}
+out_unlock:
+ /* We don't really need to unlock, as fh_put does it. */
+ fh_unlock(dirfhp);
+
done:
fh_put(dirfhp);
RETURN(nfserr);
int nfserr;
dprintk("nfsd: SYMLINK %p %s -> %s\n",
- SVCFH_DENTRY(&argp->ffh),
- argp->fname, argp->tname);
+ SVCFH_DENTRY(&argp->ffh), argp->fname, argp->tname);
+ memset(&newfh, 0, sizeof(struct svc_fh));
/*
* Create the link, look up new file and set attrs.
*/
{
int nfserr;
- dprintk("nfsd: MKDIR %p %s\n",
- SVCFH_DENTRY(&argp->fh),
- argp->name);
+ dprintk("nfsd: MKDIR %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
+
+ if (resp->fh.fh_dverified) {
+ printk(KERN_WARNING
+ "nfsd_proc_mkdir: response already verified??\n");
+ }
- /* N.B. what about the dentry count?? */
- resp->fh.fh_dverified = 0; /* paranoia */
nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
fh_put(&argp->fh);
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/nfsfh.h>
#include <linux/quotaops.h>
#if LINUX_VERSION_CODE >= 0x020100
#include <asm/uaccess.h>
#endif
-extern void fh_update(struct svc_fh*);
-
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
/* Open mode for nfsd_open */
static struct raparms raparms[FILECACHE_MAX];
static struct raparms * raparm_cache = 0;
+/*
+ * Lock a parent directory following the VFS locking protocol.
+ */
+int
+fh_lock_parent(struct svc_fh *parent_fh, struct dentry *dchild)
+{
+ int nfserr = 0;
+
+ fh_lock(parent_fh);
+ /*
+ * Make sure the parent->child relationship still holds,
+ * and that the child is still hashed.
+ */
+ if (dchild->d_parent != parent_fh->fh_dentry)
+ goto out_not_parent;
+ if (list_empty(&dchild->d_hash))
+ goto out_not_hashed;
+out:
+ return nfserr;
+
+out_not_parent:
+ printk(KERN_WARNING
+ "fh_lock_parent: %s/%s parent changed\n",
+ dchild->d_parent->d_name.name, dchild->d_name.name);
+ goto out_unlock;
+out_not_hashed:
+ printk(KERN_WARNING
+ "fh_lock_parent: %s/%s unhashed\n",
+ dchild->d_parent->d_name.name, dchild->d_name.name);
+out_unlock:
+ nfserr = nfserr_noent;
+ fh_unlock(parent_fh);
+ goto out;
+}
+
/*
* Deny access to certain file systems
*/
}
/*
- * Create a file (regular, directory, device, fifo).
- * UNIX sockets not yet implemented.
+ * Create a file (regular, directory, device, fifo); UNIX sockets
+ * not yet implemented.
+ * If the response fh has been verified, the parent directory should
+ * already be locked. Note that the parent directory is left locked.
+ *
* N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
*/
int
{
struct dentry *dentry, *dchild;
struct inode *dirp;
+ nfsd_dirop_t opfunc = NULL;
int err;
err = nfserr_perm;
if (!flen)
goto out;
- if (!(iap->ia_valid & ATTR_MODE))
- iap->ia_mode = 0;
err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
if (err)
goto out;
dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
- /* Get all the sanity checks out of the way before we lock the parent. */
err = nfserr_notdir;
if(!dirp->i_op || !dirp->i_op->lookup)
goto out;
- err = nfserr_perm;
- if (type == S_IFREG) {
- if(!dirp->i_op->create)
- goto out;
- } else if(type == S_IFDIR) {
- if(!dirp->i_op->mkdir)
- goto out;
- } else if((type == S_IFCHR) || (type == S_IFBLK) || (type == S_IFIFO)) {
- if(!dirp->i_op->mknod)
- goto out;
- } else {
- goto out;
- }
-
/*
- * The response filehandle may have been setup already ...
+ * Check whether the response filehandle has been verified yet.
+ * If it has, the parent directory should already be locked.
*/
if (!resfhp->fh_dverified) {
dchild = lookup_dentry(fname, dget(dentry), 0);
err = PTR_ERR(dchild);
- if(IS_ERR(dchild))
+ if (IS_ERR(dchild))
goto out_nfserr;
fh_compose(resfhp, fhp->fh_export, dchild);
- } else
+ /* Lock the parent and check for errors ... */
+ err = fh_lock_parent(fhp, dchild);
+ if (err)
+ goto out;
+ } else {
dchild = resfhp->fh_dentry;
+ if (!fhp->fh_locked)
+ printk(KERN_ERR
+ "nfsd_create: parent %s/%s not locked!\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
+ }
/*
* Make sure the child dentry is still negative ...
*/
+ err = nfserr_exist;
if (dchild->d_inode) {
- printk("nfsd_create: dentry %s/%s not negative!\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+ printk(KERN_WARNING
+ "nfsd_create: dentry %s/%s not negative!\n",
+ dentry->d_name.name, dchild->d_name.name);
+ goto out;
}
- /* Looks good, lock the directory. */
- fh_lock(fhp);
- DQUOT_INIT(dirp);
+ /*
+ * Get the dir op function pointer.
+ */
+ err = nfserr_perm;
switch (type) {
case S_IFREG:
- err = dirp->i_op->create(dirp, dchild, iap->ia_mode);
+ opfunc = (nfsd_dirop_t) dirp->i_op->create;
break;
case S_IFDIR:
- err = dirp->i_op->mkdir(dirp, dchild, iap->ia_mode);
+ opfunc = (nfsd_dirop_t) dirp->i_op->mkdir;
break;
case S_IFCHR:
case S_IFBLK:
case S_IFIFO:
- err = dirp->i_op->mknod(dirp, dchild, iap->ia_mode, rdev);
+ opfunc = dirp->i_op->mknod;
break;
}
- DQUOT_DROP(dirp);
- fh_unlock(fhp);
+ if (!opfunc)
+ goto out;
+ if (!(iap->ia_valid & ATTR_MODE))
+ iap->ia_mode = 0;
+
+ /*
+ * Call the dir op function to create the object.
+ */
+ DQUOT_INIT(dirp);
+ err = opfunc(dirp, dchild, iap->ia_mode, rdev);
+ DQUOT_DROP(dirp);
if (err < 0)
goto out_nfserr;
+
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(dirp);
if (IS_ERR(dnew))
goto out_nfserr;
- err = -EEXIST;
+ /*
+ * Lock the parent before checking for existence
+ */
+ err = fh_lock_parent(fhp, dnew);
+ if (err)
+ goto out_compose;
+
+ err = nfserr_exist;
if (!dnew->d_inode) {
- fh_lock(fhp);
DQUOT_INIT(dirp);
err = dirp->i_op->symlink(dirp, dnew, path);
DQUOT_DROP(dirp);
- fh_unlock(fhp);
if (!err) {
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(dirp);
- }
+ } else
+ err = nfserrno(-err);
}
+ fh_unlock(fhp);
+
+ /* Compose the fh so the dentry will be freed ... */
+out_compose:
fh_compose(resfhp, fhp->fh_export, dnew);
- if (err)
- goto out_nfserr;
out:
return err;
if (err)
goto out;
+ err = nfserr_perm;
+ if (!len)
+ goto out;
+
ddir = ffhp->fh_dentry;
dirp = ddir->d_inode;
err = PTR_ERR(dnew);
if (IS_ERR(dnew))
goto out_nfserr;
+ /*
+ * Lock the parent before checking for existence
+ */
+ err = fh_lock_parent(ffhp, dnew);
+ if (err)
+ goto out_dput;
- err = -EEXIST;
+ err = nfserr_exist;
if (dnew->d_inode)
- goto dput_and_out;
-
- err = -EPERM;
- if (!len)
- goto dput_and_out;
+ goto out_unlock;
dold = tfhp->fh_dentry;
dest = dold->d_inode;
- err = -EACCES;
+ err = nfserr_acces;
if (nfsd_iscovered(ddir, ffhp->fh_export))
- goto dput_and_out;
+ goto out_unlock;
+ /* FIXME: nxdev for NFSv3 */
if (dirp->i_dev != dest->i_dev)
- goto dput_and_out; /* FIXME: nxdev for NFSv3 */
+ goto out_unlock;
- err = -EPERM;
+ err = nfserr_perm;
if (IS_IMMUTABLE(dest) /* || IS_APPEND(dest) */ )
- goto dput_and_out;
+ goto out_unlock;
if (!dirp->i_op || !dirp->i_op->link)
- goto dput_and_out;
+ goto out_unlock;
- fh_lock(ffhp);
DQUOT_INIT(dirp);
err = dirp->i_op->link(dold, dirp, dnew);
DQUOT_DROP(dirp);
- fh_unlock(ffhp);
+ if (!err) {
+ if (EX_ISSYNC(ffhp->fh_export)) {
+ write_inode_now(dirp);
+ write_inode_now(dest);
+ }
+ } else
+ err = nfserrno(-err);
- if (!err && EX_ISSYNC(ffhp->fh_export)) {
- write_inode_now(dirp);
- write_inode_now(dest);
- }
-dput_and_out:
+out_unlock:
+ fh_unlock(ffhp);
+out_dput:
dput(dnew);
- if (err)
- goto out_nfserr;
out:
return err;
if (IS_ERR(rdentry))
goto out_nfserr;
- fh_lock(fhp);
+ err = fh_lock_parent(fhp, rdentry);
+ if (err)
+ goto out;
+
DQUOT_INIT(dirp);
if (type == S_IFDIR) {
err = -ENOTDIR;
}
#elif defined(__powerpc__)
return (p->tss.wchan);
+#elif defined (CONFIG_ARM)
+ {
+ unsigned long fp, lr;
+ unsigned long stack_page;
+ int count = 0;
+
+ stack_page = 4096 + (unsigned long)p;
+ fp = get_css_fp (&p->tss);
+ do {
+ if (fp < stack_page || fp > 4092+stack_page)
+ return 0;
+ lr = pc_pointer (((unsigned long *)fp)[-1]);
+ if (lr < first_sched || lr > last_sched)
+ return lr;
+ fp = *(unsigned long *) (fp - 12);
+ } while (count ++ < 16);
+ }
#endif
return 0;
}
# define KSTK_EIP(tsk) \
(*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(CONFIG_ARM)
+# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
+# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
#elif defined(__mc68000__)
#define KSTK_EIP(tsk) \
({ \
return buffer;
}
-char * render_sigset_t(sigset_t *set, char *buffer)
-{
- int i = _NSIG, x;
- do {
- i -= 4, x = 0;
- if (sigismember(set, i+1)) x |= 1;
- if (sigismember(set, i+2)) x |= 2;
- if (sigismember(set, i+3)) x |= 4;
- if (sigismember(set, i+4)) x |= 8;
- *buffer++ = (x < 10 ? '0' : 'a' - 10) + x;
- } while (i >= 4);
- *buffer = 0;
- return buffer;
-}
-
static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
sigset_t *catch)
{
/* Not really failsafe, but we are read-only... */
for(;;) {
if (!offset || offset >= maxoff) {
- offset = 0xffffffff;
+ offset = maxoff;
filp->f_pos = offset;
return stored;
}
return qofs*8 + bofs;
}
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
/*
* Find next zero bit in a bitmap reasonably efficiently..
*/
#include <linux/config.h>
#include <asm/system.h>
+#include <asm/processor.h> /* For TASK_SIZE */
#include <asm/mmu_context.h>
/* Caches aren't brain-dead on the alpha. */
#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-3))
#define PTRS_PER_PMD (1UL << (PAGE_SHIFT-3))
#define PTRS_PER_PGD ((1UL << (PAGE_SHIFT-3))-1)
+#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
/* the no. of pointers that fit on a page: this will go away */
#define PTRS_PER_PAGE (1UL << (PAGE_SHIFT-3))
* used to allocate a kernel page table - this turns on ASN bits
* if any.
*/
-extern inline void pte_free_kernel(pte_t * pte)
+#ifndef __SMP__
+extern struct pgtable_cache_struct {
+ unsigned long *pgd_cache;
+ unsigned long *pte_cache;
+ unsigned long pgtable_cache_sz;
+} quicklists;
+#else
+#include <asm/smp.h>
+#define quicklists cpu_data[smp_processor_id()]
+#endif
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+
+extern __inline__ pgd_t *get_pgd_slow(void)
{
- free_page((unsigned long) pte);
+ pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
+
+ if (ret) {
+ init = pgd_offset(&init_mm, 0);
+ memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+ memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ }
+ return ret;
}
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+extern __inline__ pgd_t *get_pgd_fast(void)
{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (page) {
- pmd_set(pmd, page);
- return page + address;
- }
- pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
- return NULL;
- }
- free_page((unsigned long) page);
- }
- if (pmd_bad(*pmd)) {
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + address;
+ unsigned long *ret;
+
+ if((ret = pgd_quicklist) != NULL) {
+ pgd_quicklist = (unsigned long *)(*ret);
+ ret[0] = ret[1];
+ pgtable_cache_size--;
+ } else
+ ret = (unsigned long *)get_pgd_slow();
+ return (pgd_t *)ret;
}
-extern inline void pmd_free_kernel(pmd_t * pmd)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
{
- free_page((unsigned long) pmd);
+ *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+ pgd_quicklist = (unsigned long *) pgd;
+ pgtable_cache_size++;
}
-extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
{
- address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
- if (pgd_none(*pgd)) {
- pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
- if (pgd_none(*pgd)) {
- if (page) {
- pgd_set(pgd, page);
- return page + address;
- }
- pgd_set(pgd, BAD_PAGETABLE);
- return NULL;
- }
- free_page((unsigned long) page);
+ free_page((unsigned long)pgd);
+}
+
+extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
+
+extern __inline__ pmd_t *get_pmd_fast(void)
+{
+ unsigned long *ret;
+
+ if((ret = (unsigned long *)pte_quicklist) != NULL) {
+ pte_quicklist = (unsigned long *)(*ret);
+ ret[0] = ret[1];
+ pgtable_cache_size--;
}
- if (pgd_bad(*pgd)) {
- printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
- pgd_set(pgd, BAD_PAGETABLE);
- return NULL;
+ return (pmd_t *)ret;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+ *(unsigned long *)pmd = (unsigned long) pte_quicklist;
+ pte_quicklist = (unsigned long *) pmd;
+ pgtable_cache_size++;
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+ free_page((unsigned long)pmd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+ unsigned long *ret;
+
+ if((ret = (unsigned long *)pte_quicklist) != NULL) {
+ pte_quicklist = (unsigned long *)(*ret);
+ ret[0] = ret[1];
+ pgtable_cache_size--;
}
- return (pmd_t *) pgd_page(*pgd) + address;
+ return (pte_t *)ret;
}
-extern inline void pte_free(pte_t * pte)
+extern __inline__ void free_pte_fast(pte_t *pte)
{
- free_page((unsigned long) pte);
+ *(unsigned long *)pte = (unsigned long) pte_quicklist;
+ pte_quicklist = (unsigned long *) pte;
+ pgtable_cache_size++;
}
+extern __inline__ void free_pte_slow(pte_t *pte)
+{
+ free_page((unsigned long)pte);
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pmd(pgd_t *pgd);
+
+#define pte_free_kernel(pte) free_pte_fast(pte)
+#define pte_free(pte) free_pte_fast(pte)
+#define pmd_free_kernel(pmd) free_pmd_fast(pmd)
+#define pmd_free(pmd) free_pmd_fast(pmd)
+#define pgd_free(pgd) free_pgd_fast(pgd)
+#define pgd_alloc() get_pgd_fast()
+
extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
{
address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
if (pmd_none(*pmd)) {
- pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (page) {
- pmd_set(pmd, page);
- return page + address;
- }
- pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
- return NULL;
- }
- free_page((unsigned long) page);
+ pte_t *page = get_pte_fast();
+
+ if (!page)
+ return get_pte_slow(pmd, address);
+ pmd_set(pmd, page);
+ return page + address;
}
if (pmd_bad(*pmd)) {
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+ __bad_pte(pmd);
return NULL;
}
return (pte_t *) pmd_page(*pmd) + address;
}
-extern inline void pmd_free(pmd_t * pmd)
-{
- free_page((unsigned long) pmd);
-}
-
extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
{
address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
if (pgd_none(*pgd)) {
- pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
- if (pgd_none(*pgd)) {
- if (page) {
- pgd_set(pgd, page);
- return page + address;
- }
- pgd_set(pgd, BAD_PAGETABLE);
- return NULL;
- }
- free_page((unsigned long) page);
+ pmd_t *page = get_pmd_fast();
+
+ if (!page)
+ return get_pmd_slow(pgd, address);
+ pgd_set(pgd, page);
+ return page + address;
}
if (pgd_bad(*pgd)) {
- printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
- pgd_set(pgd, BAD_PAGETABLE);
+ __bad_pmd(pgd);
return NULL;
}
return (pmd_t *) pgd_page(*pgd) + address;
}
-extern inline void pgd_free(pgd_t * pgd)
-{
- free_page((unsigned long) pgd);
-}
+#define pte_alloc_kernel pte_alloc
+#define pmd_alloc_kernel pmd_alloc
-extern inline pgd_t * pgd_alloc(void)
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
{
- return (pgd_t *) get_free_page(GFP_KERNEL);
+ struct task_struct * p;
+ pgd_t *pgd;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (!p->mm)
+ continue;
+ *pgd_offset(p->mm,address) = entry;
+ }
+ read_unlock(&tasklist_lock);
+ for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+ pgd[(address >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1)] = entry;
}
extern pgd_t swapper_pg_dir[1024];
struct cpuinfo_alpha {
unsigned long loops_per_sec;
unsigned int next;
+ unsigned long *pgd_cache;
+ unsigned long *pte_cache;
+ unsigned long pgtable_cache_sz;
};
extern struct cpuinfo_alpha cpu_data[NR_CPUS];
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/a.out.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#ifdef __KERNEL__
-#define STACK_TOP (0x01a00000)
-#define LIBRARY_START_TEXT (0x00c00000)
-#endif
-
-#endif
-
+++ /dev/null
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#define MAX_DMA_ADDRESS 0x03000000
-
-#ifdef KERNEL_ARCH_DMA
-
-static inline void arch_disable_dma (int dmanr)
-{
- printk (dma_str, "arch_disable_dma", dmanr);
-}
-
-static inline void arch_enable_dma (int dmanr)
-{
- printk (dma_str, "arch_enable_dma", dmanr);
-}
-
-static inline void arch_set_dma_addr (int dmanr, unsigned int addr)
-{
- printk (dma_str, "arch_set_dma_addr", dmanr);
-}
-
-static inline void arch_set_dma_count (int dmanr, unsigned int count)
-{
- printk (dma_str, "arch_set_dma_count", dmanr);
-}
-
-static inline void arch_set_dma_mode (int dmanr, char mode)
-{
- printk (dma_str, "arch_set_dma_mode", dmanr);
-}
-
-static inline int arch_dma_count (int dmanr)
-{
- printk (dma_str, "arch_dma_count", dmanr);
- return 0;
-}
-
-#endif
-
-/* enable/disable a specific DMA channel */
-extern void enable_dma(unsigned int dmanr);
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
- switch(dmanr) {
- case 2: disable_irq(64); break;
- default: printk (dma_str, "disable_dma", dmanr); break;
- }
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while interrupts are disabled! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
- switch(dmanr) {
- case 2: break;
- default: printk (dma_str, "clear_dma_ff", dmanr); break;
- }
-}
-
-/* set mode (above) for a specific DMA channel */
-extern void set_dma_mode(unsigned int dmanr, char mode);
-
-/* Set only the page register bits of the transfer address.
- * This is used for successive transfers when we know the contents of
- * the lower 16 bits of the DMA current address register, but a 64k boundary
- * may have been crossed.
- */
-static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
-{
- printk (dma_str, "set_dma_page", dmanr);
-}
-
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-extern void set_dma_addr(unsigned int dmanr, unsigned int addr);
-
-/* Set transfer size for a specific DMA channel.
- */
-extern void set_dma_count(unsigned int dmanr, unsigned int count);
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-extern int get_dma_residue(unsigned int dmanr);
-
-#endif /* _ASM_ARCH_DMA_H */
-
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/hardware.h
- *
- * Copyright (C) 1996 Russell King.
- *
- * This file contains the hardware definitions of the A5000 series machines.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * What hardware must be present
- */
-#define HAS_IOC
-#define HAS_PCIO
-#define HAS_MEMC
-#define HAS_MEMC1A
-#define HAS_VIDC
-
-/*
- * Optional hardware
- */
-#define HAS_EXPMASK
-
-#ifndef __ASSEMBLER__
-
-/*
- * for use with inb/outb
- */
-#define VIDC_BASE 0x80100000
-#define IOCEC4IO_BASE 0x8009c000
-#define IOCECIO_BASE 0x80090000
-#define IOC_BASE 0x80080000
-#define MEMCECIO_BASE 0x80000000
-
-/*
- * IO definitions
- */
-#define EXPMASK_BASE ((volatile unsigned char *)0x03360000)
-#define IOEB_BASE ((volatile unsigned char *)0x03350050)
-#define PCIO_FLOPPYDMABASE ((volatile unsigned char *)0x0302a000)
-#define PCIO_BASE 0x03010000
-
-/*
- * Mapping areas
- */
-#define IO_END 0x03ffffff
-#define IO_BASE 0x03000000
-#define IO_SIZE (IO_END - IO_BASE)
-#define IO_START 0x03000000
-
-/*
- * Screen mapping information
- */
-#define SCREEN2_END 0x02078000
-#define SCREEN2_BASE 0x02000000
-#define SCREEN1_END SCREEN2_BASE
-#define SCREEN1_BASE 0x01f88000
-#define SCREEN_START 0x02000000
-
-/*
- * RAM definitions
- */
-#define MAPTOPHYS(a) (((unsigned long)a & 0x007fffff) + PAGE_OFFSET)
-#define KERNTOPHYS(a) ((((unsigned long)(&a)) & 0x007fffff) + PAGE_OFFSET)
-#define GET_MEMORY_END(p) (PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
-#define PARAMS_BASE (PAGE_OFFSET + 0x7c000)
-#define KERNEL_BASE (PAGE_OFFSET + 0x80000)
-
-#else
-
-#define IOEB_BASE 0x03350050
-#define IOC_BASE 0x03200000
-#define PCIO_FLOPPYDMABASE 0x0302a000
-#define PCIO_BASE 0x03010000
-#define IO_BASE 0x03000000
-
-#endif
-#endif
-
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/ide.h
- *
- * Copyright (c) 1997 Russell King
- */
-
-static __inline__ int
-ide_default_irq(ide_ioreg_t base)
-{
- if (base == 0x1f0)
- return 11;
- return 0;
-}
-
-static __inline__ ide_ioreg_t
-ide_default_io_base(int index)
-{
- if (index == 0)
- return 0x1f0;
- return 0;
-}
-
-static __inline__ int
-ide_default_stepping(int index)
-{
- return 0;
-}
-
-static __inline__ void
-ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int stepping, int *irq)
-{
- ide_ioreg_t port = base;
- ide_ioreg_t ctrl = base + 0x206;
- int i;
-
- i = 8;
- while (i--) {
- *p++ = port;
- port += 1 << stepping;
- }
- *p++ = ctrl;
- if (irq != NULL)
- irq = 0;
-}
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/io.h
- *
- * Copyright (C) 1997 Russell King
- *
- * Modifications:
- * 06-Dec-1997 RMK Created.
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- * address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- * to an address that the kernel can use.
- */
-#define virt_to_bus(x) ((unsigned long)(x))
-#define bus_to_virt(x) ((void *)(x))
-
-/*
- * This architecture does not require any delayed IO, and
- * has the constant-optimised IO
- */
-#undef ARCH_IO_DELAY
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses. PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1. ARM addresses are 0x80000000+
- * and are translated to the start of IO. Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x) (!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-extern __inline__ void __outb (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "strb %1, [%0, %2, lsl #2]"
- : "=&r" (temp)
- : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-extern __inline__ void __outw (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "str %1, [%0, %2, lsl #2]"
- : "=&r" (temp)
- : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-extern __inline__ void __outl (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "str %1, [%0, %2, lsl #2]"
- : "=&r" (temp)
- : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr) \
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port) \
-{ \
- unsigned long temp, value; \
- __asm__ __volatile__( \
- "tst %2, #0x80000000\n\t" \
- "mov %0, %4\n\t" \
- "addeq %0, %0, %3\n\t" \
- "ldr" ##instr## " %1, [%0, %2, lsl #2]" \
- : "=&r" (temp), "=r" (value) \
- : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \
- : "cc"); \
- return (unsigned sz)value; \
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port) \
-{ \
- if (__PORT_PCIO(port)) \
- return (unsigned int)(PCIO_BASE + (port << 2)); \
- else \
- return (unsigned int)(IO_BASE + (port << 2)); \
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr) \
- DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port) \
-({ \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "strb %0, [%1, %2]" \
- : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "strb %0, [%1, %2]" \
- : : "r" (value), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inbc(port) \
-({ \
- unsigned char result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldrb %0, [%1, %2]" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldrb %0, [%1, %2]" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result; \
-})
-
-#define __outwc(value,port) \
-({ \
- unsigned long v = value; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "str %0, [%1, %2]" \
- : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "str %0, [%1, %2]" \
- : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inwc(port) \
-({ \
- unsigned short result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2]" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2]" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result & 0xffff; \
-})
-
-#define __outlc(v,p) __outwc((v),(p))
-
-#define __inlc(port) \
-({ \
- unsigned long result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2]" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2]" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result; \
-})
-
-#define __ioaddrc(port) \
-({ \
- unsigned long addr; \
- if (__PORT_PCIO((port))) \
- addr = PCIO_BASE + ((port) << 2); \
- else \
- addr = IO_BASE + ((port) << 2); \
- addr; \
-})
-
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p) \
- (*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p) \
- (*(volatile unsigned char *)(p))
-
-#define outl_t(v,p) \
- (*(volatile unsigned long *)(p) = (v))
-
-#define inl_t(p) \
- (*(volatile unsigned long *)(p))
-
-#endif
+++ /dev/null
-/*
- * include/asm-arm/arch-a5k/irq.h
- *
- * Copyright (C) 1996 Russell King
- *
- * Changelog:
- * 24-09-1996 RMK Created
- * 10-10-1996 RMK Brought up to date with arch-sa110eval
- * 22-10-1996 RMK Changed interrupt numbers & uses new inb/outb macros
- * 11-01-1998 RMK Added mask_and_ack_irq
- */
-
-#define BUILD_IRQ(s,n,m) \
- void IRQ##n##_interrupt(void); \
- void fast_IRQ##n##_interrupt(void); \
- void bad_IRQ##n##_interrupt(void); \
- void probe_IRQ##n##_interrupt(void);
-
-/*
- * The timer is a special interrupt
- */
-#define IRQ5_interrupt timer_IRQ_interrupt
-
-#define IRQ_INTERRUPT(n) IRQ##n##_interrupt
-#define FAST_INTERRUPT(n) fast_IRQ##n##_interrupt
-#define BAD_INTERRUPT(n) bad_IRQ##n##_interrupt
-#define PROBE_INTERRUPT(n) probe_IRQ##n##_interrupt
-
-#define X(x) (x)|0x01, (x)|0x02, (x)|0x04, (x)|0x08, (x)|0x10, (x)|0x20, (x)|0x40, (x)|0x80
-#define Z(x) (x), (x), (x), (x), (x), (x), (x), (x)
-
-static __inline__ void mask_and_ack_irq(unsigned int irq)
-{
- static const int addrmasks[] = {
- X((IOC_IRQMASKA - IOC_BASE)<<18 | (1 << 15)),
- X((IOC_IRQMASKB - IOC_BASE)<<18),
- Z(0),
- Z(0),
- Z(0),
- Z(0),
- Z(0),
- Z(0),
- X((IOC_FIQMASK - IOC_BASE)<<18),
- Z(0),
- Z(0),
- Z(0),
- Z(0),
- Z(0),
- Z(0),
- Z(0)
- };
- unsigned int temp1, temp2;
-
- __asm__ __volatile__(
-" ldr %1, [%5, %3, lsl #2]\n"
-" teq %1, #0\n"
-" beq 2f\n"
-" ldrb %0, [%2, %1, lsr #16]\n"
-" bic %0, %0, %1\n"
-" strb %0, [%2, %1, lsr #16]\n"
-" tst %1, #0x8000\n" /* do we need an IRQ clear? */
-" strneb %1, [%2, %4]\n"
-"2:"
- : "=&r" (temp1), "=&r" (temp2)
- : "r" (ioaddr(IOC_BASE)), "r" (irq),
- "I" ((IOC_IRQCLRA - IOC_BASE) << 2), "r" (addrmasks));
-}
-
-#undef X
-#undef Z
-
-static __inline__ void mask_irq(unsigned int irq)
-{
- extern void ecard_disableirq (unsigned int);
- extern void ecard_disablefiq (unsigned int);
- unsigned char mask = 1 << (irq & 7);
-
- switch (irq >> 3) {
- case 0:
- outb(inb(IOC_IRQMASKA) & ~mask, IOC_IRQMASKA);
- break;
- case 1:
- outb(inb(IOC_IRQMASKB) & ~mask, IOC_IRQMASKB);
- break;
- case 4:
- ecard_disableirq (irq & 7);
- break;
- case 8:
- outb(inb(IOC_FIQMASK) & ~mask, IOC_FIQMASK);
- break;
- case 12:
- ecard_disablefiq (irq & 7);
- }
-}
-
-static __inline__ void unmask_irq(unsigned int irq)
-{
- extern void ecard_enableirq (unsigned int);
- extern void ecard_enablefiq (unsigned int);
- unsigned char mask = 1 << (irq & 7);
-
- switch (irq >> 3) {
- case 0:
- outb(inb(IOC_IRQMASKA) | mask, IOC_IRQMASKA);
- break;
- case 1:
- outb(inb(IOC_IRQMASKB) | mask, IOC_IRQMASKB);
- break;
- case 4:
- ecard_enableirq (irq & 7);
- break;
- case 8:
- outb(inb(IOC_FIQMASK) | mask, IOC_FIQMASK);
- break;
- case 12:
- ecard_enablefiq (irq & 7);
- }
-}
-
-static __inline__ unsigned long get_enabled_irqs(void)
-{
- return inb(IOC_IRQMASKA) | inb(IOC_IRQMASKB) << 8;
-}
-
-static __inline__ void irq_init_irq(void)
-{
- outb(0, IOC_IRQMASKA);
- outb(0, IOC_IRQMASKB);
- outb(0, IOC_FIQMASK);
-}
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/irqs.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define IRQ_PRINTER 0
-#define IRQ_BATLOW 1
-#define IRQ_FLOPPYINDEX 2
-#define IRQ_VSYNCPULSE 3
-#define IRQ_POWERON 4
-#define IRQ_TIMER0 5
-#define IRQ_TIMER1 6
-#define IRQ_IMMEDIATE 7
-#define IRQ_EXPCARDFIQ 8
-#define IRQ_SOUNDCHANGE 9
-#define IRQ_SERIALPORT 10
-#define IRQ_HARDDISK 11
-#define IRQ_FLOPPYDISK 12
-#define IRQ_EXPANSIONCARD 13
-#define IRQ_KEYBOARDTX 14
-#define IRQ_KEYBOARDRX 15
-
-#define FIQ_FLOPPYDATA 0
-#define FIQ_ECONET 2
-#define FIQ_SERIALPORT 4
-#define FIQ_EXPANSIONCARD 6
-#define FIQ_FORCE 7
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/mmu.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- * 22-11-1996 RMK Created
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys(vpage) vpage
-#define __phys_to_virt(ppage) ppage
-
-#endif
+++ /dev/null
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (a5k) machine"
-#endif
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/processor.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- * 10-09-1996 RMK Created
- */
-
-#ifndef __ASM_ARCH_PROCESSOR_H
-#define __ASM_ARCH_PROCESSOR_H
-
-/*
- * Bus types
- */
-#define EISA_bus 0
-#define EISA_bus__is_a_macro /* for versions in ksyms.c */
-#define MCA_bus 0
-#define MCA_bus__is_a_macro /* for versions in ksyms.c */
-
-/*
- * User space: 26MB
- */
-#define TASK_SIZE (0x01a00000UL)
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE(off) (TASK_SIZE / 3)
-#define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0x02000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-#endif
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/serial.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- * 15-10-1996 RMK Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
- /* UART CLK PORT IRQ FLAGS */
-#define RS_UARTS \
- { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS3 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS13 */
-
-#endif
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/system.h
- *
- * Copyright (c) 1996 Russell King
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-extern __inline__ void arch_hard_reset (void)
-{
- extern void ecard_reset (int card);
-
- /*
- * Reset all expansion cards.
- */
- ecard_reset (-1);
-
- /*
- * copy branch instruction to reset location and call it
- */
- *(unsigned long *)0 = *(unsigned long *)0x03800000;
- ((void(*)(void))0)();
-
- /*
- * If that didn't work, loop endlessly
- */
- while (1);
-}
-
-#endif
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/time.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- * 24-Sep-1996 RMK Created
- * 10-Oct-1996 RMK Brought up to date with arch-sa110eval
- * 04-Dec-1997 RMK Updated for new arch/arm/time.c
- */
-
-extern __inline__ unsigned long gettimeoffset (void)
-{
- unsigned int count1, count2, status1, status2;
- unsigned long offset = 0;
-
- status1 = IOC_IRQREQA;
- barrier ();
- outb (0, IOC_T0LATCH);
- barrier ();
- count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
- barrier ();
- status2 = inb(IOC_IRQREQA);
- barrier ();
- outb (0, IOC_T0LATCH);
- barrier ();
- count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8);
-
- if (count2 < count1) {
- /*
- * This means that we haven't just had an interrupt
- * while reading into status2.
- */
- if (status2 & (1 << 5))
- offset = tick;
- count1 = count2;
- } else if (count2 > count1) {
- /*
- * We have just had another interrupt while reading
- * status2.
- */
- offset += tick;
- count1 = count2;
- }
-
- count1 = LATCH - count1;
- /*
- * count1 = number of clock ticks since last interrupt
- */
- offset += count1 * tick / LATCH;
- return offset;
-}
-
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
-
-/*
- * Updating of the RTC. We don't currently write the time to the
- * CMOS clock.
- */
-#define update_rtc()
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-extern __inline__ unsigned long setup_timer (void)
-{
- extern int iic_control (unsigned char, int, char *, int);
- unsigned int year, mon, day, hour, min, sec;
- char buf[8];
-
- outb(LATCH & 255, IOC_T0LTCHL);
- outb(LATCH >> 8, IOC_T0LTCHH);
- outb(0, IOC_T0GO);
-
- iic_control (0xa0, 0xc0, buf, 1);
- year = buf[0];
- if ((year += 1900) < 1970)
- year += 100;
-
- iic_control (0xa0, 2, buf, 5);
- mon = buf[4] & 0x1f;
- day = buf[3] & 0x3f;
- hour = buf[2];
- min = buf[1];
- sec = buf[0];
- BCD_TO_BIN(mon);
- BCD_TO_BIN(day);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(min);
- BCD_TO_BIN(sec);
-
- return mktime(year, mon, day, hour, min, sec);
-}
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/timex.h
- *
- * A5000 architecture timex specifications
- *
- * Copyright (C) 1997, 1998 Russell King
- */
-
-/*
- * On the RiscPC, the clock ticks at 2MHz.
- */
-#define CLOCK_TICK_RATE 2000000
-
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-a5k/uncompress.h
- *
- * Copyright (C) 1996 Russell King
- */
-#define VIDMEM ((char *)0x02000000)
-
-#include "../arch/arm/drivers/char/font.h"
-
-int video_num_columns, video_num_lines, video_size_row;
-int white, bytes_per_char_h;
-extern unsigned long con_charconvtable[256];
-
-struct param_struct {
- unsigned long page_size;
- unsigned long nr_pages;
- unsigned long ramdisk_size;
- unsigned long mountrootrdonly;
- unsigned long rootdev;
- unsigned long video_num_cols;
- unsigned long video_num_rows;
- unsigned long video_x;
- unsigned long video_y;
- unsigned long memc_control_reg;
- unsigned char sounddefault;
- unsigned char adfsdrives;
- unsigned char bytes_per_char_h;
- unsigned char bytes_per_char_v;
- unsigned long unused[256/4-11];
-};
-
-static struct param_struct *params = (struct param_struct *)0x0207c000;
-
-/*
- * This does not append a newline
- */
-static void puts(const char *s)
-{
- extern void ll_write_char(char *, unsigned long);
- int x,y;
- unsigned char c;
- char *ptr;
-
- x = params->video_x;
- y = params->video_y;
-
- while ( ( c = *(unsigned char *)s++ ) != '\0' ) {
- if ( c == '\n' ) {
- x = 0;
- if ( ++y >= video_num_lines ) {
- y--;
- }
- } else {
- ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h);
- ll_write_char(ptr, c|(white<<8));
- if ( ++x >= video_num_columns ) {
- x = 0;
- if ( ++y >= video_num_lines ) {
- y--;
- }
- }
- }
- }
-
- params->video_x = x;
- params->video_y = y;
-}
-
-static void error(char *x);
-
-/*
- * Setup for decompression
- */
-static void arch_decomp_setup(void)
-{
- int i;
-
- video_num_lines = params->video_num_rows;
- video_num_columns = params->video_num_cols;
- bytes_per_char_h = params->bytes_per_char_h;
- video_size_row = video_num_columns * bytes_per_char_h;
- if (bytes_per_char_h == 4)
- for (i = 0; i < 256; i++)
- con_charconvtable[i] =
- (i & 128 ? 1 << 0 : 0) |
- (i & 64 ? 1 << 4 : 0) |
- (i & 32 ? 1 << 8 : 0) |
- (i & 16 ? 1 << 12 : 0) |
- (i & 8 ? 1 << 16 : 0) |
- (i & 4 ? 1 << 20 : 0) |
- (i & 2 ? 1 << 24 : 0) |
- (i & 1 ? 1 << 28 : 0);
- else
- for (i = 0; i < 16; i++)
- con_charconvtable[i] =
- (i & 8 ? 1 << 0 : 0) |
- (i & 4 ? 1 << 8 : 0) |
- (i & 2 ? 1 << 16 : 0) |
- (i & 1 ? 1 << 24 : 0);
-
- white = bytes_per_char_h == 8 ? 0xfc : 7;
-
- if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n");
-}
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR 0x40000000
#define inl_t(p) \
(*(volatile unsigned long *)(p))
+/*
+ * This is not sufficient... (and it's a hack anyway)
+ */
+static inline void writeb(unsigned char b, unsigned int addr)
+{
+ *(volatile unsigned char *)(0xe0000000 + (addr)) = b;
+}
+
+static inline unsigned char readb(unsigned int addr)
+{
+ return *(volatile unsigned char *)(0xe0000000 + (addr));
+}
+
+static inline void writew(unsigned short b, unsigned int addr)
+{
+ *(volatile unsigned short *)(0xe0000000 + (addr)) = b;
+}
+
+static inline unsigned short readw(unsigned int addr)
+{
+ return *(volatile unsigned short *)(0xe0000000 + (addr));
+}
#endif
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
+#if 0
#define TASK_UNMAPPED_BASE(off) (TASK_SIZE / 3)
+#else
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+#endif
#define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
#define INIT_MMAP \
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * Use SRAM for cache flushing
- */
-#define SAFE_ADDR 0x40000000
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-ebsa110/serial.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- * 15-10-1996 RMK Created
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
- /* UART CLK PORT IRQ FLAGS */
-#define RS_UARTS \
- { 0, BASE_BAUD, 0x3F8, 1, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 2, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS3 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS13 */
-
-#endif
-
+++ /dev/null
-/*
- * linux/include/asm-arm/arch-rpc/mmap.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#define HAVE_MAP_VID_MEM
-#define SAFE_ADDR 0x00000000 /* ROM */
-
-unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
-{
- static int updated = 0;
- unsigned long address;
- pgd_t *pgd;
-
- if (updated)
- return 0;
- updated = update;
-
- address = SCREEN_START | PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE;
- pgd = swapper_pg_dir + (SCREEN2_BASE >> PGDIR_SHIFT);
- pgd_val(pgd[0]) = address;
- pgd_val(pgd[1]) = address + (1 << PGDIR_SHIFT);
-
- if (update) {
- unsigned long pgtable = PAGE_ALIGN(kmem), *p;
- int i;
-
- memzero ((void *)pgtable, 4096);
-
- pgd_val(pgd[-2]) = virt_to_phys(pgtable) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
- pgd_val(pgd[-1]) = virt_to_phys(pgtable + PTRS_PER_PTE*4) | PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL);
- p = (unsigned long *)pgtable;
-
- i = PTRS_PER_PTE * 2 - ((SCREEN1_END - log_start) >> PAGE_SHIFT);
- address = SCREEN_START | PTE_TYPE_SMALL | PTE_AP_WRITE;
-
- while (i < PTRS_PER_PTE * 2) {
- p[i++] = address;
- address += PAGE_SIZE;
- }
-
- flush_page_to_ram(pgtable);
-
- kmem = pgtable + PAGE_SIZE;
- }
- return kmem;
-}
return k;
}
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
#ifdef __KERNEL__
#define ext2_set_bit test_and_set_bit
--- /dev/null
+/* Support for FIQ on ARM architectures.
+ * Written by Philip Blundell <philb@gnu.org>, 1998
+ */
+
+#ifndef __ASM_FIQ_H
+#define __ASM_FIQ_H
+
+struct fiq_handler {
+ const char *name;
+ int (*callback)(void);
+};
+
+extern int claim_fiq(struct fiq_handler *f);
+extern void release_fiq(struct fiq_handler *f);
+
+#endif
#include <asm/arch/floppy.h>
#endif
-#define fd_outb(val,port) outb((val),(port))
+#define fd_outb(val,port) \
+ do { \
+ if ((port) == FD_DOR) \
+ fd_setdor((val)); \
+ else \
+ outb((val),(port)); \
+ } while(0)
+
#define fd_inb(port) inb((port))
#define fd_request_irq() request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL)
#define fd_set_dma_count(len) set_dma_count(FLOPPY_DMA, (len))
#define fd_cacheflush(addr,sz)
+/* need to clean up dma.h */
+#define DMA_FLOPPYDISK DMA_FLOPPY
+
/* Floppy_selects is the list of DOR's to select drive fd
*
* On initialisation, the floppy list is scanned, and the drives allocated
{ 0x10, 0x21, 0x23, 0x33 }
};
-#define fd_setdor(dor) \
-do { \
- int new_dor = (dor); \
- if (new_dor & 0xf0) \
- fd_outb((new_dor & 0x0c) | floppy_selects[fdc][new_dor & 3], FD_DOR); \
- else \
- fd_outb((new_dor & 0x0c), FD_DOR); \
+#define fd_setdor(dor) \
+do { \
+ int new_dor = (dor); \
+ if (new_dor & 0xf0) \
+ new_dor = (new_dor & 0x0c) | floppy_selects[fdc][new_dor & 3]; \
+ else \
+ new_dor &= 0x0c; \
+ outb(new_dor, FD_DOR); \
} while (0)
/*
extern unsigned int local_irq_count[NR_CPUS];
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+
#ifndef __SMP__
#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
#undef ARCH_IO_DELAY
#undef ARCH_IO_CONSTANT
-/*
- * Leftovers...
- */
-#if 0
-#define __outwc(value,port) \
-({ \
- if (port < 256) \
- __asm__ __volatile__( \
- "strh %0, [%1, %2]" \
- : : "r" (value), "r" (PCIO_BASE), "J" (port << 2)); \
- else if (__PORT_PCIO(port)) \
- __asm__ __volatile__( \
- "strh %0, [%1, %2]" \
- : : "r" (value), "r" (PCIO_BASE), "r" (port << 2)); \
- else \
- __asm__ __volatile__( \
- "strh %0, [%1, %2]" \
- : : "r" (value), "r" (IO_BASE), "r" (port << 2)); \
-})
-
-#define __inwc(port) \
-({ \
- unsigned short result; \
- if (port < 256) \
- __asm__ __volatile__( \
- "ldrh %0, [%1, %2]" \
- : "=r" (result) : "r" (PCIO_BASE), "J" (port << 2)); \
- else \
- if (__PORT_PCIO(port)) \
- __asm__ __volatile__( \
- "ldrh %0, [%1, %2]" \
- : "=r" (result) : "r" (PCIO_BASE), "r" (port << 2)); \
- else \
- __asm__ __volatile__( \
- "ldrh %0, [%1, %2]" \
- : "=r" (result) : "r" (IO_BASE), "r" (port << 2)); \
- result; \
-})
-#endif
#endif
-/* $Id: ioctl.h,v 1.1 1998/01/28 09:56:22 ecd Exp $
- *
+/*
* linux/ioctl.h for Linux by H.H. Bergman.
*/
+++ /dev/null
-/*
- * linux/include/asm-arm/irq-no.h
- *
- * Machine independent interrupt numbers
- */
-
-#include <asm/arch/irqs.h>
-
-#ifndef NR_IRQS
-#define NR_IRQS 128
-#endif
-/* $Id: namei.h,v 1.1 1998/01/28 09:56:37 ecd Exp $
+/*
* linux/include/asm-i386/namei.h
*
* Included from linux/fs/namei.c
mask = 1 << (nr & 0x1f);
return ((mask & *addr) != 0);
}
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
#endif /* _ASM_GENERIC_BITOPS_H */
return word;
}
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int ffs(int x)
+{
+ int r;
+
+ __asm__("bsfl %1,%0\n\t"
+ "jnz 1f\n\t"
+ "movl $-1,%0\n"
+ "1:" : "=r" (r) : "g" (x));
+ return r+1;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
#ifdef __KERNEL__
#define ext2_set_bit test_and_set_bit
* This file contains the functions and defines necessary to modify and use
* the i386 page table tree.
*/
-
#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#include <linux/tasks.h>
+
/* Caches aren't brain-dead on the intel. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define __flush_tlb() \
do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0)
-#if defined(CONFIG_M386) || defined(CONFIG_AMD_K5_INVBUG)
+#ifdef CONFIG_M386
#define __flush_tlb_one(addr) flush_tlb()
#else
#define __flush_tlb_one(addr) \
#define PTRS_PER_PTE 1024
#define PTRS_PER_PMD 1
#define PTRS_PER_PGD 1024
+#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
/*
* pgd entries used up by user/kernel:
* used to allocate a kernel page table - this turns on ASN bits
* if any.
*/
-extern inline void pte_free_kernel(pte_t * pte)
+
+#define pgd_quicklist (current_cpu_data.pgd_quick)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (current_cpu_data.pte_quick)
+#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
+
+extern __inline__ pgd_t *get_pgd_slow(void)
{
- free_page((unsigned long) pte);
+ pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
+
+ if (ret) {
+ init = pgd_offset(&init_mm, 0);
+ memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+ memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ }
+ return ret;
}
-extern const char bad_pmd_string[];
+extern __inline__ pgd_t *get_pgd_fast(void)
+{
+ unsigned long *ret;
+
+ if((ret = pgd_quicklist) != NULL) {
+ pgd_quicklist = (unsigned long *)(*ret);
+ ret[0] = ret[1];
+ pgtable_cache_size--;
+ } else
+ ret = (unsigned long *)get_pgd_slow();
+ return (pgd_t *)ret;
+}
-extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (page) {
- pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
- return page + address;
- }
- pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
- return NULL;
- }
- free_page((unsigned long) page);
- }
- if (pmd_bad(*pmd)) {
- printk(bad_pmd_string, pmd_val(*pmd));
- pmd_val(*pmd) = _KERNPG_TABLE + __pa(BAD_PAGETABLE);
- return NULL;
+ *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+ pgd_quicklist = (unsigned long *) pgd;
+ pgtable_cache_size++;
+}
+
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
+{
+ free_page((unsigned long)pgd);
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
+extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+
+extern __inline__ pte_t *get_pte_fast(void)
+{
+ unsigned long *ret;
+
+ if((ret = (unsigned long *)pte_quicklist) != NULL) {
+ pte_quicklist = (unsigned long *)(*ret);
+ ret[0] = ret[1];
+ pgtable_cache_size--;
}
- return (pte_t *) pmd_page(*pmd) + address;
+ return (pte_t *)ret;
}
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern inline void pmd_free_kernel(pmd_t * pmd)
+extern __inline__ void free_pte_fast(pte_t *pte)
{
- pmd_val(*pmd) = 0;
+ *(unsigned long *)pte = (unsigned long) pte_quicklist;
+ pte_quicklist = (unsigned long *) pte;
+ pgtable_cache_size++;
}
-extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+extern __inline__ void free_pte_slow(pte_t *pte)
{
- return (pmd_t *) pgd;
+ free_page((unsigned long)pte);
}
-extern inline void pte_free(pte_t * pte)
+/* We don't use pmd cache, so these are dummy routines */
+extern __inline__ pmd_t *get_pmd_fast(void)
{
- free_page((unsigned long) pte);
+ return (pmd_t *)0;
+}
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
+{
+}
+
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
+{
+}
+
+extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pte_kernel(pmd_t *pmd);
+
+#define pte_free_kernel(pte) free_pte_fast(pte)
+#define pte_free(pte) free_pte_fast(pte)
+#define pgd_free(pgd) free_pgd_fast(pgd)
+#define pgd_alloc() get_pgd_fast()
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+ address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+ if (pmd_none(*pmd)) {
+ pte_t * page = (pte_t *) get_pte_fast();
+
+ if (!page)
+ return get_pte_kernel_slow(pmd, address);
+ pmd_val(*pmd) = _KERNPG_TABLE + __pa(page);
+ return page + address;
+ }
+ if (pmd_bad(*pmd)) {
+ __bad_pte_kernel(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + address;
}
extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
{
address = (address >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1);
-repeat:
if (pmd_none(*pmd))
goto getnew;
if (pmd_bad(*pmd))
goto fix;
return (pte_t *) (pmd_page(*pmd) + address);
-
getnew:
{
- unsigned long page = __get_free_page(GFP_KERNEL);
- if (!pmd_none(*pmd))
- goto freenew;
+ unsigned long page = (unsigned long) get_pte_fast();
+
if (!page)
- goto oom;
- memset((void *) page, 0, PAGE_SIZE);
+ return get_pte_slow(pmd, address);
pmd_val(*pmd) = _PAGE_TABLE + __pa(page);
return (pte_t *) (page + address);
-freenew:
- free_page(page);
- goto repeat;
}
-
fix:
- printk(bad_pmd_string, pmd_val(*pmd));
-oom:
- pmd_val(*pmd) = _PAGE_TABLE + __pa(BAD_PAGETABLE);
+ __bad_pte(pmd);
return NULL;
}
*/
extern inline void pmd_free(pmd_t * pmd)
{
- pmd_val(*pmd) = 0;
}
extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
return (pmd_t *) pgd;
}
-extern inline void pgd_free(pgd_t * pgd)
-{
- free_page((unsigned long) pgd);
-}
+#define pmd_free_kernel pmd_free
+#define pmd_alloc_kernel pmd_alloc
-extern inline pgd_t * pgd_alloc(void)
+extern inline void set_pgdir(unsigned long address, pgd_t entry)
{
- return (pgd_t *) get_free_page(GFP_KERNEL);
+ struct task_struct * p;
+ pgd_t *pgd;
+#ifdef __SMP__
+ int i;
+#endif
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (!p->mm)
+ continue;
+ *pgd_offset(p->mm,address) = entry;
+ }
+ read_unlock(&tasklist_lock);
+#ifndef __SMP__
+ for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+ pgd[address >> PGDIR_SHIFT] = entry;
+#else
+ /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
+ modify pgd caches of other CPUs as well. -jj */
+ for (i = 0; i < NR_CPUS; i++)
+ for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+ pgd[address >> PGDIR_SHIFT] = entry;
+#endif
}
extern pgd_t swapper_pg_dir[1024];
int fdiv_bug;
int f00f_bug;
unsigned long loops_per_sec;
+ unsigned long *pgd_quick;
+ unsigned long *pte_quick;
+ unsigned long pgtable_cache_sz;
};
#define X86_VENDOR_INTEL 0
#define TOD2000_HOUR1_PM (1<<2)
#define TOD_2000 ((struct tod2000 *)(zTwoBase+0xDC0000))
-#endif /* __ASMm68k_AMIGAHW_H */
+#endif /* _M68K_AMIGAHW_H */
* clock sources */
#define SCC_BAUD_BASE_MVME_PCLK 781250 /* 12.5 MHz */
-#define SCC_BAUD_BASE_BVM 460800 /* 7.3728 MHz */
#define SCC_BAUD_BASE_MVME 625000 /* 10.000 MHz */
+#define SCC_BAUD_BASE_BVME_PCLK 781250 /* 12.5 MHz */ /* XXX ??? */
+#define SCC_BAUD_BASE_BVME 460800 /* 7.3728 MHz */
/* The SCC configuration structure */
+++ /dev/null
-#ifndef _LINUX_ATARI_MOUSE_H
-#define _LINUX_ATARI_MOUSE_H
-
-/*
- * linux/include/linux/atari_mouse.h
- * header file for Atari Mouse driver
- * by Robert de Vries (robert@and.nl) on 19Jul93
- */
-
-struct mouse_status {
- char buttons;
- short dx;
- short dy;
- int ready;
- int active;
- struct wait_queue *wait;
- struct fasync_struct *fasyncptr;
-};
-
-#endif
return res ^ 31;
}
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
/* Bitmap functions for the minix filesystem */
extern __inline__ int
--- /dev/null
+/*
+** asm/blinken.h -- m68k blinkenlights support (currently hp300 only)
+**
+** (c) 1998 Phil Blundell <philb@gnu.org>
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License. See the file COPYING in the main directory of this archive
+** for more details.
+**
+*/
+
+#ifndef _M68K_BLINKEN_H
+#define _M68K_BLINKEN_H
+
+#include <asm/setup.h>
+
+#define HP300_LEDS 0xf001ffff
+
+static __inline__ void blinken_leds(int x)
+{
+ if (MACH_IS_HP300)
+ {
+ *((volatile unsigned char *)HP300_LEDS) = (x);
+ }
+}
+
+#endif
#define ATARI_MACH_AB40 3 /* Afterburner040 on Falcon */
/*
- * Macintosh-specific tags
+ * Macintosh-specific tags (all u_long)
*/
#define BI_MAC_MODEL 0x8000 /* Mac Gestalt ID (model type) */
#define BI_MAC_GMTBIAS 0x8008 /* Mac GMT timezone offset */
#define BI_MAC_MEMSIZE 0x8009 /* Mac RAM size (sanity check) */
#define BI_MAC_CPUID 0x800a /* Mac CPU type (sanity check) */
+#define BI_MAC_ROMBASE 0x800b /* Mac system ROM base address */
+
+ /*
+ * Macintosh hardware profile data - unused, see macintosh.h for
+ * resonable type values
+ */
+
+#define BI_MAC_VIA1BASE 0x8010 /* Mac VIA1 base address (always present) */
+#define BI_MAC_VIA2BASE 0x8011 /* Mac VIA2 base address (type varies) */
+#define BI_MAC_VIA2TYPE 0x8012 /* Mac VIA2 type (VIA, RBV, OSS) */
+#define BI_MAC_ADBTYPE 0x8013 /* Mac ADB interface type */
+#define BI_MAC_ASCBASE 0x8014 /* Mac Apple Sound Chip base address */
+#define BI_MAC_SCSI5380 0x8015 /* Mac NCR 5380 SCSI (base address, multi) */
+#define BI_MAC_SCSIDMA 0x8016 /* Mac SCSI DMA (base address) */
+#define BI_MAC_SCSI5396 0x8017 /* Mac NCR 53C96 SCSI (base address, multi) */
+#define BI_MAC_IDETYPE 0x8018 /* Mac IDE interface type */
+#define BI_MAC_IDEBASE 0x8019 /* Mac IDE interface base address */
+#define BI_MAC_NUBUS 0x801a /* Mac Nubus type (none, regular, pseudo) */
+#define BI_MAC_SLOTMASK 0x801b /* Mac Nubus slots present */
+#define BI_MAC_SCCTYPE 0x801c /* Mac SCC serial type (normal, IOP) */
+#define BI_MAC_ETHTYPE 0x801d /* Mac builtin ethernet type (Sonic, MACE */
+#define BI_MAC_ETHBASE 0x801e /* Mac builtin ethernet base address */
+#define BI_MAC_PMU 0x801f /* Mac power managment / poweroff hardware */
+#define BI_MAC_IOP_SWIM 0x8020 /* Mac SWIM floppy IOP */
+#define BI_MAC_IOP_ADB 0x8021 /* Mac ADB IOP */
/*
* Mac: compatibility with old booter data format (temporarily)
+ * Fields unused with the new bootinfo can be deleted now; instead of
+ * adding new fields the struct might be splitted into a hardware address
+ * part and a hardware type part
*/
#ifndef __ASSEMBLY__
#define ATARI_BOOTI_VERSION MK_BI_VERSION( 2, 1 )
#define MAC_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
#define MVME16x_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
+#define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
#ifdef BOOTINFO_COMPAT_1_0
--- /dev/null
+#ifndef _M68K_BVME6000HW_H_
+#define _M68K_BVME6000HW_H_
+
+#include <asm/irq.h>
+
+/*
+ * PIT structure
+ */
+
+#define BVME_PIT_BASE 0xffa00000
+
+typedef struct {
+ unsigned char
+ pad_a[3], pgcr,
+ pad_b[3], psrr,
+ pad_c[3], paddr,
+ pad_d[3], pbddr,
+ pad_e[3], pcddr,
+ pad_f[3], pivr,
+ pad_g[3], pacr,
+ pad_h[3], pbcr,
+ pad_i[3], padr,
+ pad_j[3], pbdr,
+ pad_k[3], paar,
+ pad_l[3], pbar,
+ pad_m[3], pcdr,
+ pad_n[3], psr,
+ pad_o[3], res1,
+ pad_p[3], res2,
+ pad_q[3], tcr,
+ pad_r[3], tivr,
+ pad_s[3], res3,
+ pad_t[3], cprh,
+ pad_u[3], cprm,
+ pad_v[3], cprl,
+ pad_w[3], res4,
+ pad_x[3], crh,
+ pad_y[3], crm,
+ pad_z[3], crl,
+ pad_A[3], tsr,
+ pad_B[3], res5;
+} PitRegs_t, *PitRegsPtr;
+
+#define bvmepit ((*(volatile PitRegsPtr)(BVME_PIT_BASE)))
+
+#define BVME_RTC_BASE 0xff900000
+
+typedef struct {
+ unsigned char
+ pad_a[3], msr,
+ pad_b[3], t0cr_rtmr,
+ pad_c[3], t1cr_omr,
+ pad_d[3], pfr_icr0,
+ pad_e[3], irr_icr1,
+ pad_f[3], bcd_tenms,
+ pad_g[3], bcd_sec,
+ pad_h[3], bcd_min,
+ pad_i[3], bcd_hr,
+ pad_j[3], bcd_dom,
+ pad_k[3], bcd_mth,
+ pad_l[3], bcd_year,
+ pad_m[3], bcd_ujcc,
+ pad_n[3], bcd_hjcc,
+ pad_o[3], bcd_dow,
+ pad_p[3], t0lsb,
+ pad_q[3], t0msb,
+ pad_r[3], t1lsb,
+ pad_s[3], t1msb,
+ pad_t[3], cmp_sec,
+ pad_u[3], cmp_min,
+ pad_v[3], cmp_hr,
+ pad_w[3], cmp_dom,
+ pad_x[3], cmp_mth,
+ pad_y[3], cmp_dow,
+ pad_z[3], sav_sec,
+ pad_A[3], sav_min,
+ pad_B[3], sav_hr,
+ pad_C[3], sav_dom,
+ pad_D[3], sav_mth,
+ pad_E[3], ram,
+ pad_F[3], test;
+} RtcRegs_t, *RtcPtr_t;
+
+
+#define BVME_I596_BASE 0xff100000
+
+#define BVME_ETHIRQ_REG 0xff20000b
+
+#define BVME_LOCAL_IRQ_STAT 0xff20000f
+
+#define BVME_ETHERR 0x02
+#define BVME_ABORT_STATUS 0x08
+
+#define BVME_NCR53C710_BASE 0xff000000
+
+#define BVME_SCC_A_ADDR 0xffb0000b
+#define BVME_SCC_B_ADDR 0xffb00003
+
+#define BVME_CONFIG_REG 0xff500003
+
+#define config_reg_ptr (unsigned char *)BVME_CONFIG_REG
+
+#define BVME_CONFIG_SW1 0x08
+#define BVME_CONFIG_SW2 0x04
+#define BVME_CONFIG_SW3 0x02
+#define BVME_CONFIG_SW4 0x01
+
+
+#define BVME_IRQ_TYPE_PRIO 0
+
+#define BVME_IRQ_PRN 0x54
+#define BVME_IRQ_I596 0x1a
+#define BVME_IRQ_SCSI 0x1b
+#define BVME_IRQ_TIMER 0x59
+#define BVME_IRQ_RTC 0x1e
+#define BVME_IRQ_ABORT 0x1f
+
+/* SCC interrupts */
+#define BVME_IRQ_SCC_BASE 0x40
+#define BVME_IRQ_SCCB_TX 0x40
+#define BVME_IRQ_SCCB_STAT 0x42
+#define BVME_IRQ_SCCB_RX 0x44
+#define BVME_IRQ_SCCB_SPCOND 0x46
+#define BVME_IRQ_SCCA_TX 0x48
+#define BVME_IRQ_SCCA_STAT 0x4a
+#define BVME_IRQ_SCCA_RX 0x4c
+#define BVME_IRQ_SCCA_SPCOND 0x4e
+
+#endif
csum_partial_copy_from_user ( const char *src, char *dst,
int len, int sum, int *csum_err);
+/* FIXME: this needs to be written to really do no check -- Cort */
+#define csum_partial_copy_nocheck(src, dst, len, sum) \
+ csum_partial_copy((src), (dst), (len), (sum))
+
/*
* This is a version of ip_compute_csum() optimized for IP headers,
* which always checksum on 4 octet boundaries.
LTSS_FPCTXT = 24
/* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(CONFIG_ATARI_ONLY) && !defined(CONFIG_HADES)
/* block out HSYNC on the atari */
#define ALLOWINT 0xfbff
#define MAX_NOINT_IPL 3
extern unsigned int local_irq_count[NR_CPUS];
+#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+
#define hardirq_trylock(cpu) (++local_irq_count[cpu], (cpu) == 0)
#define hardirq_endlock(cpu) (--local_irq_count[cpu])
--- /dev/null
+/* Routines to test for presence/absence of hardware registers:
+ * see arch/m68k/mm/hwtest.c.
+ * -- PMM <pmaydell@chiark.greenend.org.uk> 05/1998
+ *
+ * Removed initfunc from decls. We might want them in modules, and
+ * the code is tiny anyway. 16/5/98 pb
+ */
+
+#ifndef __ASM_HWTEST_H
+#define __ASM_HWTEST_H
+
+extern int hwreg_present(volatile void *regp);
+extern int hwreg_write(volatile void *regp, unsigned short val);
+
+#endif
#include <asm/atari_stdma.h>
#endif
+#ifdef CONFIG_MAC
+#include <asm/macints.h>
+#endif
+
typedef unsigned char * ide_ioreg_t;
#ifndef MAX_HWIFS
} b;
} select_t;
+#ifdef CONFIG_MAC /* MSch: Hack; wrapper for ide_intr */
+void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs);
+#endif
+
static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *device, void *dev_id)
{
if (MACH_IS_AMIGA)
return request_irq(irq, handler, 0, device, dev_id);
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_MAC
+ if (MACH_IS_MAC)
+#if 0 /* MSch Hack: maybe later we'll call ide_intr without a wrapper */
+ return nubus_request_irq(12, dev_id, handler);
+#else
+ return nubus_request_irq(12, dev_id, mac_ide_intr);
+#endif
+#endif /* CONFIG_MAC */
return 0;
}
if (MACH_IS_AMIGA)
free_irq(irq, dev_id);
#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_MAC
+ if (MACH_IS_MAC)
+ nubus_free_irq(12);
+#endif /* CONFIG_MAC */
}
/*
#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
-#define insw(port, buf, nr) \
- if ((nr) % 16) \
- __asm__ __volatile__ \
- ("movel %0,%/a0; \
- movel %1,%/a1; \
- movel %2,%/d6; \
- subql #1,%/d6; \
- 1:movew %/a0@,%/a1@+; \
- dbra %/d6,1b" : \
- : "g" (port), "g" (buf), "g" (nr) \
- : "a0", "a1", "d6"); \
- else \
- __asm__ __volatile__ \
- ("movel %0,%/a0; \
- movel %1,%/a1; \
- movel %2,%/d6; \
- lsrl #4,%/d6; \
- subql #1,%/d6; \
- 1:movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- movew %/a0@,%/a1@+; \
- dbra %/d6,1b" : \
- : "g" (port), "g" (buf), "g" (nr) \
- : "a0", "a1", "d6")
-
-#define outsw(port, buf, nr) \
- if ((nr) % 16) \
- __asm__ __volatile__ \
- ("movel %0,%/a0; \
- movel %1,%/a1; \
- movel %2,%/d6; \
- subql #1,%/d6; \
- 1:movew %/a1@+,%/a0@; \
- dbra %/d6,1b" : \
- : "g" (port), "g" (buf), "g" (nr) \
- : "a0", "a1", "d6"); \
- else \
- __asm__ __volatile__ \
- ("movel %0,%/a0; \
- movel %1,%/a1; \
- movel %2,%/d6; \
- lsrl #4,%/d6; \
- subql #1,%/d6; \
- 1:movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- movew %/a1@+,%/a0@; \
- dbra %/d6,1b" : \
- : "g" (port), "g" (buf), "g" (nr) \
- : "a0", "a1", "d6")
+#define insw(port, buf, nr) ({ \
+ unsigned char *_port = (unsigned char *)(port); \
+ unsigned char *_buf = (buf); \
+ int _nr = (nr); \
+ unsigned long _tmp; \
+ \
+ if (_nr & 15) { \
+ _tmp = (_nr & 15) - 1; \
+ asm volatile ( \
+ "1: movew %2@,%3@+; dbra %4,1b" \
+ : "=a" (_buf), "=d" (_tmp) \
+ : "a" (_port), "0" (_buf), \
+ "1" (_tmp)); \
+ } \
+ _tmp = (_nr >> 4) - 1; \
+ asm volatile ( \
+ "1: " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "movew %2@,%3@+; " \
+ "dbra %4,1b" \
+ : "=a" (_buf), "=d" (_tmp) \
+ : "a" (_port), "0" (_buf), \
+ "1" (_tmp)); \
+})
+
+#define outsw(port, buf, nr) ({ \
+ unsigned char *_port = (unsigned char *)(port); \
+ unsigned char *_buf = (buf); \
+ int _nr = (nr); \
+ unsigned long _tmp; \
+ \
+ if (_nr & 15) { \
+ _tmp = (_nr & 15) - 1; \
+ asm volatile ( \
+ "1: movew %3@,%2@+; dbra %4,1b" \
+ : "=a" (_buf), "=d" (_tmp) \
+ : "a" (_port), "0" (_buf), \
+ "1" (_tmp)); \
+ } \
+ _tmp = (_nr >> 4) - 1; \
+ asm volatile ( \
+ "1: " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "movew %3@+,%2@; " \
+ "dbra %4,1b" \
+ : "=a" (_buf), "=d" (_tmp) \
+ : "a" (_port), "0" (_buf), \
+ "1" (_tmp)); \
+})
#ifdef CONFIG_ATARI
#define insl_swapw(data_reg, buffer, wcount) \
#define D_INT(cnt) (T_INT | (cnt))
#define D_TEXT(cnt) (T_TEXT | (cnt))
-#ifdef CONFIG_AMIGA
+#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC)
static u_short driveid_types[] = {
D_SHORT(10), /* config - vendor2 */
D_TEXT(20), /* serial_no */
- D_SHORT(3), /* buf_type - ecc_bytes */
+ D_SHORT(3), /* buf_type, buf_size - ecc_bytes */
D_TEXT(48), /* fw_rev - model */
D_CHAR(2), /* max_multsect - vendor3 */
D_SHORT(1), /* dword_io */
static __inline__ void ide_fix_driveid(struct hd_driveid *id)
{
-#ifdef CONFIG_AMIGA
+#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC)
u_char *p = (u_char *)id;
int i, j, cnt;
u_char t;
- if (!MACH_IS_AMIGA)
+ if (!MACH_IS_AMIGA && !MACH_IS_MAC)
return;
for (i = 0; i < num_driveid_types; i++) {
cnt = driveid_types[i] & T_MASK_COUNT;
* an interrupt, and in that case it does nothing. Hope that is reasonable and
* works. (Roman)
*/
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA)
+#ifdef CONFIG_ATARI_ONLY
#define ide__sti() \
do { \
if (!in_interrupt()) __sti(); \
#define readl(addr) \
({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
# define via_1 ((*(volatile struct VIA *)VIA1_BAS))
# define via_2 ((*(volatile struct VIA *)VIA2_BAS))
# define via1_regp ((volatile unsigned char *)VIA1_BAS)
-
-# define via2_regp ((volatile unsigned char *)VIA2_BAS)
-# define via2_ci_regp ((volatile unsigned char *)VIA2_BAS_IIci)
-# define rbv_regp ((volatile unsigned char *)VIA2_BAS_IIci)
+/*
+ * OSS/RBV base address
+ */
+
+#define OSS_BAS 0x50f1a000
+#define PSC_BAS 0x50f31000
+
+/* move to oss.h?? */
+#define nIFR 0x203
+#define oIFR 0x202
+
#endif /* linux/machw.h */
#define MAC_SCC_II 1
#define MAC_SCC_QUADRA 2
#define MAC_SCC_QUADRA2 3
+#define MAC_SCC_IOP 4
#define MAC_ETHER_NONE 0
#define MAC_ETHER_SONIC 1
#define MAC_MODEL_IICI 11
#define MAC_MODEL_IIFX 13 /* And well numbered it is too */
#define MAC_MODEL_IISI 18
+#define MAC_MODEL_LC 19
#define MAC_MODEL_Q900 20
#define MAC_MODEL_PB170 21
#define MAC_MODEL_Q700 22
#define MAC_MODEL_PB190 85
#define MAC_MODEL_TV 88
#define MAC_MODEL_P475 89 /* aka: LC475, P476 */
+#define MAC_MODEL_P475F 90 /* aka: P475 w/ FPU (no LC040) */
#define MAC_MODEL_P575 92 /* aka: LC575/580, P577/578/508 */
#define MAC_MODEL_Q605 94
#define MAC_MODEL_Q630 98 /* aka: LC630, P630/631/636/640 */
+#define MAC_MODEL_P588 99 /* aka: ?? */
#define MAC_MODEL_PB280 102
#define MAC_MODEL_PB280C 103
#define MAC_MODEL_PB150 115
#define VIA1_SOURCE_BASE 8
#define VIA2_SOURCE_BASE 16
-#define RBF_SOURCE_BASE 24
+#define RBV_SOURCE_BASE 24
#define MAC_SCC_SOURCE_BASE 32
-#define NUBUS_SOURCE_BASE 40
+#define NUBUS_SOURCE_BASE 56
#define NUBUS_MAX_SOURCES 8
/* FIXME: sources not contigous ... */
*/
#define IRQ_IDX(irq) (irq)
-#if 0
-/* convert vector number to int source number */
-#define IRQ_VECTOR_TO_SOURCE(v) (v)
-
-/* convert irq_handler index to vector number */
-#define IRQ_SOURCE_TO_VECTOR(i) (i)
-#endif
-
/* interrupt service types */
#define IRQ_TYPE_SLOW 0
#define IRQ_TYPE_FAST 1
#define IRQ_VIA2_6 (22)
#define IRQ_VIA2_7 (23)
+#if 0
/* RBV interrupts */
#define IRQ_RBV_0 (24)
#define IRQ_RBV_1 (25)
#define IRQ_RBV_5 (29)
#define IRQ_RBV_6 (30)
#define IRQ_RBV_7 (31)
+#endif
+
+/* Level 3 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC3_0 (24)
+#define IRQ_MAC_MACE IRQ_PSC3_0
+#define IRQ_PSC3_1 (25)
+#define IRQ_PSC3_2 (26)
+#define IRQ_PSC3_3 (27)
+/* Level 4 (SCC) interrupts */
#define IRQ_SCC (32)
-#define IRQ_SCCB (32)
-#define IRQ_SCCA (33)
+#define IRQ_SCCB (33)
+#define IRQ_SCCA (34)
#if 0 /* FIXME: are there multiple interrupt conditions on the SCC ?? */
/* SCC interrupts */
#define IRQ_SCCB_TX (32)
#define IRQ_SCCA_SPCOND (39)
#endif
-#define IRQ_NUBUS_1 (40)
+/* Level 4 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC4_0 (32)
+#define IRQ_PSC4_1 (33)
+#define IRQ_PSC4_2 (34)
+#define IRQ_PSC4_3 (35)
+#define IRQ_MAC_MACE_DMA IRQ_PSC4_3
+
+/* Level 5 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC5_0 (40)
+#define IRQ_PSC5_1 (41)
+#define IRQ_PSC5_2 (42)
+#define IRQ_PSC5_3 (43)
+
+/* Level 6 (PSC, AV Macs only) interrupts */
+#define IRQ_PSC6_0 (48)
+#define IRQ_PSC6_1 (49)
+#define IRQ_PSC6_2 (50)
+#define IRQ_PSC6_3 (51)
+
+/* Nubus interrupts (cascaded to VIA2) */
+#define IRQ_NUBUS_1 (56)
#define INT_CLK 24576 /* CLK while int_clk =2.456MHz and divide = 100 */
#define INT_TICKS 246 /* to make sched_time = 99.902... HZ */
spare3,
spare4,
data;
-} lpr_ctrl;
+} MVMElp, *MVMElpPtr;
-#define LPR_REGS ((volatile lpr_ctrl *)0xfff42030)
+#define MVME_LPR_BASE 0xfff42030
-#define I596_BASE 0xfff46000
+#define mvmelp ((*(volatile MVMElpPtr)(MVME_LPR_BASE)))
-#define SCC_A_ADDR 0xfff45005
-#define SCC_B_ADDR 0xfff45001
-
-#define IRQ_MVME162_TYPE_PRIO 0
-
-#define IRQ_MVME167_PRN 0x54
-#define IRQ_MVME16x_I596 0x57
-#define IRQ_MVME16x_SCSI 0x55
-#define IRQ_MVME16x_FLY 0x7f
-#define IRQ_MVME167_SER_ERR 0x5c
-#define IRQ_MVME167_SER_MODEM 0x5d
-#define IRQ_MVME167_SER_TX 0x5e
-#define IRQ_MVME167_SER_RX 0x5f
-#define IRQ_MVME16x_TIMER 0x59
+typedef struct {
+ unsigned char
+ ctrl,
+ bcd_sec,
+ bcd_min,
+ bcd_hr,
+ bcd_dow,
+ bcd_dom,
+ bcd_mth,
+ bcd_year;
+} MK48T08_t, *MK48T08ptr_t;
+
+#define RTC_WRITE 0x80
+#define RTC_READ 0x40
+#define RTC_STOP 0x20
+
+#define MVME_RTC_BASE 0xfffc1ff8
+
+#define MVME_I596_BASE 0xfff46000
+
+#define MVME_SCC_A_ADDR 0xfff45005
+#define MVME_SCC_B_ADDR 0xfff45001
+
+#define MVME162_IRQ_TYPE_PRIO 0
+
+#define MVME167_IRQ_PRN 0x54
+#define MVME16x_IRQ_I596 0x57
+#define MVME16x_IRQ_SCSI 0x55
+#define MVME16x_IRQ_FLY 0x7f
+#define MVME167_IRQ_SER_ERR 0x5c
+#define MVME167_IRQ_SER_MODEM 0x5d
+#define MVME167_IRQ_SER_TX 0x5e
+#define MVME167_IRQ_SER_RX 0x5f
+#define MVME16x_IRQ_TIMER 0x59
+#define MVME167_IRQ_ABORT 0x6e
+#define MVME162_IRQ_ABORT 0x5e
/* SCC interrupts, for MVME162 */
-#define IRQ_MVME162_SCC_BASE 0x40
-#define IRQ_MVME162_SCCB_TX 0x40
-#define IRQ_MVME162_SCCB_STAT 0x42
-#define IRQ_MVME162_SCCB_RX 0x44
-#define IRQ_MVME162_SCCB_SPCOND 0x46
-#define IRQ_MVME162_SCCA_TX 0x48
-#define IRQ_MVME162_SCCA_STAT 0x4a
-#define IRQ_MVME162_SCCA_RX 0x4c
-#define IRQ_MVME162_SCCA_SPCOND 0x4e
+#define MVME162_IRQ_SCC_BASE 0x40
+#define MVME162_IRQ_SCCB_TX 0x40
+#define MVME162_IRQ_SCCB_STAT 0x42
+#define MVME162_IRQ_SCCB_RX 0x44
+#define MVME162_IRQ_SCCB_SPCOND 0x46
+#define MVME162_IRQ_SCCA_TX 0x48
+#define MVME162_IRQ_SCCA_STAT 0x4a
+#define MVME162_IRQ_SCCA_RX 0x4c
+#define MVME162_IRQ_SCCA_SPCOND 0x4e
/* MVME162 version register */
#define MVME16x_CONFIG_GOT_SCCA 0x0400
#define MVME16x_CONFIG_GOT_SCCB 0x0800
-/* Specials for the ethernet driver */
-
-#define CA() (((struct i596_reg *)dev->base_addr)->ca = 1)
-
-#define MPU_PORT(c,x) \
- ((struct i596_reg *)(dev->base_addr))->porthi = ((c) | (u32)(x)) & 0xffff; \
- ((struct i596_reg *)(dev->base_addr))->portlo = ((c) | (u32)(x)) >> 16
-
-#define SCP_SYSBUS 0x00000054
-
-#define WSWAPrfd(x) ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPrbd(x) ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPscb(x) ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPcmd(x) ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPtbd(x) ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPchar(x) ((char *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- */
-#define PORT_RESET 0x00 /* reset 82596 */
-#define PORT_SELFTEST 0x01 /* selftest */
-#define PORT_ALTSCP 0x02 /* alternate SCB address */
-#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
-
-#define ISCP_BUSY 0x00010000
-
-#endif /* _M68K_MVME16xHW_H_ */
+#endif
* and initialized in head.S */
extern int m68k_pgtable_cachemode;
+/* This is the cache mode for normal pages, for supervisor access on
+ * processors >= '040. It is used in pte_mkcache(), and the variable is
+ * defined and initialized in head.S */
+
+#if defined(CONFIG_060_WRITETHROUGH)
+extern int m68k_supervisor_cachemode;
+#else
+#define m68k_supervisor_cachemode _PAGE_CACHE040
+#endif
+
#if defined(CPU_M68040_OR_M68060_ONLY)
#define mm_cachebits _PAGE_CACHE040
#elif defined(CPU_M68020_OR_M68030_ONLY)
pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_pgtable_cachemode;
return pte;
}
-extern inline pte_t pte_mkcache(pte_t pte) { pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | _PAGE_CACHE040; return pte; }
+extern inline pte_t pte_mkcache(pte_t pte) { pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode; return pte; }
/* to set the page-dir */
extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE(off) 0xC0000000UL
+#define TASK_UNMAPPED_BASE 0xC0000000UL
#define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
/*
{
}
+#define copy_segments(nr, tsk, mm) do { } while (0)
+#define release_segments(mm) do { } while (0)
+
/*
* Free current thread data structures etc..
*/
*/
extern inline unsigned long thread_saved_pc(struct thread_struct *t)
{
- extern int sys_pause(void);
- extern void schedule(void);
+ extern void scheduling_functions_start_here(void);
+ extern void scheduling_functions_end_here(void);
struct switch_stack *sw = (struct switch_stack *)t->ksp;
/* Check whether the thread is blocked in resume() */
- if (sw->retpc >= (unsigned long)schedule &&
- sw->retpc < (unsigned long)sys_pause)
+ if (sw->retpc > (unsigned long)scheduling_functions_start_here &&
+ sw->retpc < (unsigned long)scheduling_functions_end_here)
return ((unsigned long *)sw->a6)[1];
else
return sw->retpc;
}
-#define copy_segments(nr, tsk, mm) do { } while (0)
-#define release_segments(mm) do { } while (0)
-
/* Allocation and freeing of basic task resources. */
#define alloc_task_struct() \
((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
#define SER_WHIPPET 108 /* Amiga Hisoft Whippet PCMCIA (16c550B) */
#define SER_SCC_MVME 109 /* MVME162/MVME172 ports */
#define SER_SCC_MAC 110 /* Macintosh SCC channel */
+#define SER_HPDCA 111 /* HP DCA serial */
+#define SER_SCC_BVME 112 /* BVME6000 ports */
struct serial_struct {
int type;
#define MACH_MVME147 6
#define MACH_MVME16x 7
#define MACH_BVME6000 8
+#define MACH_HP300 9
#ifdef __KERNEL__
#if !defined(CONFIG_AMIGA)
# define MACH_IS_AMIGA (0)
#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
- || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+ || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
# define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
#else
-# define MACH_AMIGA_ONLY
+# define CONFIG_AMIGA_ONLY
# define MACH_IS_AMIGA (1)
# define MACH_TYPE (MACH_AMIGA)
#endif
#if !defined(CONFIG_ATARI)
# define MACH_IS_ATARI (0)
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
- || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+ || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
# define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
#else
-# define MACH_ATARI_ONLY
+# define CONFIG_ATARI_ONLY
# define MACH_IS_ATARI (1)
# define MACH_TYPE (MACH_ATARI)
#endif
#if !defined(CONFIG_MAC)
# define MACH_IS_MAC (0)
-#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
+ || defined(CONFIG_HP300) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
# define MACH_IS_MAC (m68k_machtype == MACH_MAC)
#else
# define CONFIG_MAC_ONLY
#if !defined (CONFIG_APOLLO)
# define MACH_IS_APOLLO (0)
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
- || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+ || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
# define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
#else
# define CONFIG_APOLLO_ONLY
#if !defined (CONFIG_MVME16x)
# define MACH_IS_MVME16x (0)
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
- || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)
+ || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
# define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
#else
# define CONFIG_MVME16x_ONLY
#if !defined (CONFIG_BVME6000)
# define MACH_IS_BVME6000 (0)
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
- || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)
+ || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_HP300)
# define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
#else
# define CONFIG_BVME6000_ONLY
# define MACH_TYPE (MACH_BVME6000)
#endif
+#if !defined (CONFIG_HP300)
+# define MACH_IS_HP300 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+ || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+# define MAC_IS_HP300 (m68k_machtype == MACH_HP300)
+#else
+# define CONFIG_HP300_ONLY
+# define MACH_IS_HP300 (1)
+# define MACH_TYPE (MACH_HP300)
+#endif
#ifndef MACH_TYPE
# define MACH_TYPE (m68k_machtype)
/* Here we must cater to libcs that poke about in kernel headers. */
struct sigaction {
- __sighandler_t sa_handler;
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction)(int, struct siginfo *, void *);
+ } _u;
sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
#endif /* __KERNEL__ */
typedef struct sigaltstack {
unsigned long __unused5;
};
+#if 0
typedef struct {
unsigned int major;
unsigned int minor;
unsigned long st_blksize;
unsigned long __unused4;
};
+#endif
#define __XSTAT_VER_1 1
#define __XSTAT_VER_2 2
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((volatile struct __xchg_dummy *)(x))
-#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) && !defined(CONFIG_HADES)
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) && !defined(CONFIG_HADES) && !defined(CONFIG_VME) && !defined(CONFIG_APOLLO)
/* block out HSYNC on the atari */
#define __sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory")
#else /* portable version */
#define __NR_pread 180
#define __NR_pwrite 181
#define __NR_lchown 182
+#define __NR_getcwd 183
+#define __NR_capget 184
+#define __NR_capset 185
/* user-visible error numbers are in the range -1 - -122: see
<asm-m68k/errno.h> */
return __res;
}
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
#ifdef __MIPSEB__
/* For now I steal the Sparc C versions, no need for speed, just need to
* get it working.
return 31 - n;
}
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+#if 0
+/* untested, someone with PPC knowledge? */
+/* From Alexander Kjeldaas <astor@guardian.no> */
+extern __inline__ int ffs(int x)
+{
+ int result;
+ asm ("cntlzw %0,%1" : "=r" (result) : "r" (x));
+ return 32 - result; /* IBM backwards ordering of bits */
+}
+#endif
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
/*
* This implementation of find_{first,next}_zero_bit was stolen from
* Linus' asm-alpha/bitops.h.
return result;
}
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+
/* find_next_zero_bit() finds the first zero bit in a bit string of length
* 'size' bits, starting the search at bit 'offset'. This is largely based
* on Linus's ALPHA routines, which are pretty portable BTW.
return result;
}
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#ifdef ULTRA_HAS_POPULATION_COUNT
+
+extern __inline__ unsigned int hweight32(unsigned int w)
+{
+ unsigned int res;
+
+ __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
+ return res;
+}
+
+extern __inline__ unsigned int hweight16(unsigned int w)
+{
+ unsigned int res;
+
+ __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
+ return res;
+}
+
+extern __inline__ unsigned int hweight8(unsigned int w)
+{
+ unsigned int res;
+
+ __asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
+ return res;
+}
+
+#else
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#endif
+
/* find_next_zero_bit() finds the first zero bit in a bit string of length
* 'size' bits, starting the search at bit 'offset'. This is largely based
* on Linus's ALPHA routines, which are pretty portable BTW.
};
#ifdef __KERNEL__
-
-
/*
* Calculate the boot block checksum on an ADFS drive. Note that this will
* appear to be correct if the sector contains all zeros, so also check that
* the disk size is non-zero!!!
*/
-
extern inline int adfs_checkbblk(unsigned char *ptr)
{
- int i = 511;
-
- int result = 0;
+ unsigned int result = 0;
+ unsigned char *p = ptr + 511;
do {
- result = (result & 0xff) + (result >> 8);
- result = result + ptr[i];
- i--;
- }
- while (i != 0);
-
- result &= 0xff;
- return result != ptr[511];
- return 0;
+ result = (result & 0xff) + (result >> 8);
+ result = result + *--p;
+ } while (p != ptr);
+
+ return (result & 0xff) != ptr[511];
}
/* dir.c */
--- /dev/null
+#ifndef _LINUX_BITOPS_H
+#define _LINUX_BITOPS_H
+
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int generic_ffs(int x)
+{
+ int r = 1;
+
+ if (!x)
+ return 0;
+ if (!(x & 0xffff)) {
+ x >>= 16;
+ r += 16;
+ }
+ if (!(x & 0xff)) {
+ x >>= 8;
+ r += 8;
+ }
+ if (!(x & 0xf)) {
+ x >>= 4;
+ r += 4;
+ }
+ if (!(x & 3)) {
+ x >>= 2;
+ r += 2;
+ }
+ if (!(x & 1)) {
+ x >>= 1;
+ r += 1;
+ }
+ return r;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+extern __inline__ unsigned int generic_hweight32(unsigned int w)
+{
+ unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+ res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+ res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+ res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+ return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+extern __inline__ unsigned int generic_hweight16(unsigned int w)
+{
+ unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+ res = (res & 0x3333) + ((res >> 2) & 0x3333);
+ res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+ return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+
+extern __inline__ unsigned int generic_hweight8(unsigned int w)
+{
+ unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+ res = (res & 0x33) + ((res >> 2) & 0x33);
+ return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+
+#include <asm/bitops.h>
+
+
+#endif
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+#elif (MAJOR_NR == MFM_ACORN_MAJOR)
+
+#define DEVICE_NAME "mfm disk"
+#define DEVICE_INTR do_mfm
+#define DEVICE_REQUEST do_mfm_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
#elif (MAJOR_NR == NBD_MAJOR)
#define DEVICE_NAME "nbd"
--- /dev/null
+/* header file for DIO boards for the HP300 architecture.
+ * Maybe this should handle DIO-II later?
+ * The general structure of this is vaguely based on how
+ * the Amiga port handles Zorro boards.
+ * Copyright (C) Peter Maydell 05/1998 <pmaydell@chiark.greenend.org.uk>
+ *
+ * The board IDs are from the NetBSD kernel, which for once provided
+ * helpful comments...
+ *
+ * This goes with arch/m68k/hp300/dio.c
+ */
+
+#ifndef _LINUX_DIO_H
+#define _LINUX_DIO_H
+
+/* The DIO boards in a system are distinguished by 'select codes' which
+ * range from 0-63 (DIO) and 132-255 (DIO-II).
+ * The DIO board with select code sc is located at physical address
+ * 0x600000 + sc * 0x10000
+ * So DIO cards cover [0x600000-0x800000); the areas [0x200000-0x400000) and
+ * [0x800000-0x1000000) are for additional space required by things
+ * like framebuffers. [0x400000-0x600000) is for miscellaneous internal I/O.
+ * On Linux, this is currently all mapped into the virtual address space
+ * at 0xf0000000 on bootup.
+ * DIO-II boards are at 0x1000000 + (sc - 132) * 0x400000
+ * which is address range [0x1000000-0x20000000) -- too big to map completely,
+ * so currently we just don't handle DIO-II boards. It wouldn't be hard to
+ * do with ioremap() though.
+ */
+#ifdef __KERNEL__
+/* DIO/DIO-II boards all have the following 8bit registers.
+ * These are offsets from the base of the device.
+ */
+#define DIO_IDOFF 0x01 /* primary device ID */
+#define DIO_IPLOFF 0x03 /* interrupt priority level */
+#define DIO_SECIDOFF 0x15 /* secondary device ID */
+#define DIOII_SIZEOFF 0x101 /* device size, DIO-II only */
+
+/* The internal HPIB device is special; this is its physaddr; its select code is 7.
+ * The reason why we have to treat it specially is because apparently it's broken:
+ * the device ID isn't consistent/reliable. *sigh*
+ */
+#define DIO_IHPIBADDR 0x47800
+#define DIO_IHPIBSCODE 7
+
+/* If we don't have the internal HPIB defined, then treat select code 7 like
+ * any other. If we *do* have internal HPIB, then we just have to assume that
+ * select code 7 is the internal HPIB regardless of the ID register :-<
+ */
+#define CONFIG_IHPIB /* hack hack : not yet a proper config option */
+#ifdef CONFIG_IHPIB
+#define DIO_ISIHPIB(scode) ((scode) == DIO_IHPIBSCODE)
+#else
+#define DIO_ISIHPIB(scode) 0
+#endif
+
+#define DIO_VIRADDRBASE 0xf0000000 /* vir addr where IOspace is mapped */
+
+#define DIO_BASE 0x600000 /* start of DIO space */
+#define DIO_END 0x1000000 /* end of DIO space */
+#define DIO_DEVSIZE 0x10000 /* size of a DIO device */
+
+#define DIOII_BASE 0x01000000 /* start of DIO-II space */
+#define DIOII_END 0x20000000 /* end of DIO-II space */
+#define DIOII_DEVSIZE 0x00400000 /* size of a DIO-II device */
+
+/* Highest valid select code. If we add DIO-II support this should become
+ * 256 for everything except HP320, which only has DIO.
+ */
+#define DIO_SCMAX 32
+#define DIOII_SCBASE 132 /* lowest DIO-II select code */
+#define DIO_SCINHOLE(scode) (((scode) >= 32) && ((scode) < DIOII_SCBASE))
+
+/* macros to read device IDs, given base address */
+#define DIO_ID(baseaddr) readb((baseaddr) + DIO_IDOFF)
+#define DIO_SECID(baseaddr) readb((baseaddr) + DIO_SECIDOFF)
+
+/* extract the interrupt level */
+#define DIO_IPL(baseaddr) (((readb((baseaddr) + DIO_IPLOFF) >> 4) & 0x03) + 3)
+
+/* find the size of a DIO-II board's address space.
+ * DIO boards are all fixed length.
+ */
+#define DIOII_SIZE(baseaddr) ((readb((baseaddr) + DIOII_SIZEOFF) + 1) * 0x100000)
+
+/* general purpose macro for both DIO and DIO-II */
+#define DIO_SIZE(scode, base) (DIO_ISDIOII((scode)) ? DIOII_SIZE((base)) : DIO_DEVSIZE)
+
+/* The hardware has primary and secondary IDs; we encode these in a single
+ * int as PRIMARY ID & (SECONDARY ID << 8).
+ * In practice this is only important for framebuffers,
+ * and everybody else just sets ID fields equal to the DIO_ID_FOO value.
+ */
+#define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) & ((int)pr & 0xff))
+/* macro to determine whether a given primary ID requires a secondary ID byte */
+#define DIO_NEEDSSECID(id) ((id) == DIO_ID_FBUFFER)
+
+/* Now a whole slew of macros giving device IDs and descriptive strings: */
+#define DIO_ID_DCA0 0x02 /* 98644A serial */
+#define DIO_DESC_DCA0 "98644A DCA0 serial"
+#define DIO_ID_DCA0REM 0x82 /* 98644A serial */
+#define DIO_DESC_DCA0REM "98644A DCA0REM serial"
+#define DIO_ID_DCA1 0x42 /* 98644A serial */
+#define DIO_DESC_DCA1 "98644A DCA1 serial"
+#define DIO_ID_DCA1REM 0xc2 /* 98644A serial */
+#define DIO_DESC_DCA1REM "98644A DCA1REM serial"
+#define DIO_ID_DCM 0x05 /* 98642A serial MUX */
+#define DIO_DESC_DCM "98642A DCM serial MUX"
+#define DIO_ID_DCMREM 0x85 /* 98642A serial MUX */
+#define DIO_DESC_DCMREM "98642A DCMREM serial MUX"
+#define DIO_ID_LAN 0x15 /* 98643A LAN */
+#define DIO_DESC_LAN "98643A LAN"
+#define DIO_ID_FHPIB 0x08 /* 98625A/98625B fast HP-IB */
+#define DIO_DESC_FHPIB "98625A/98625B fast HPIB"
+#define DIO_ID_NHPIB 0x80 /* 98624A HP-IB (normal ie slow) */
+#define DIO_DESC_NHPIB "98624A HPIB"
+#define DIO_ID_IHPIB 0x00 /* internal HPIB (not its real ID, it hasn't got one! */
+#define DIO_DESC_IHPIB "internal HPIB"
+#define DIO_ID_SCSI0 0x07 /* 98625A SCSI */
+#define DIO_DESC_SCSI0 "98625A SCSI0"
+#define DIO_ID_SCSI1 0x27 /* ditto */
+#define DIO_DESC_SCSI1 "98625A SCSI1"
+#define DIO_ID_SCSI2 0x47 /* ditto */
+#define DIO_DESC_SCSI2 "98625A SCSI2"
+#define DIO_ID_SCSI3 0x67 /* ditto */
+#define DIO_DESC_SCSI3 "98625A SCSI3"
+#define DIO_ID_FBUFFER 0x39 /* framebuffer: flavour is distinguished by secondary ID */
+#define DIO_DESC_FBUFFER "bitmapped display"
+/* the NetBSD kernel source is a bit unsure as to what these next IDs actually do :-> */
+#define DIO_ID_MISC0 0x03 /* 98622A */
+#define DIO_DESC_MISC0 "98622A"
+#define DIO_ID_MISC1 0x04 /* 98623A */
+#define DIO_DESC_MISC1 "98623A"
+#define DIO_ID_PARALLEL 0x06 /* internal parallel */
+#define DIO_DESC_PARALLEL "internal parallel"
+#define DIO_ID_MISC2 0x09 /* 98287A keyboard */
+#define DIO_DESC_MISC2 "98287A keyboard"
+#define DIO_ID_MISC3 0x0a /* HP98635A FP accelerator */
+#define DIO_DESC_MISC3 "HP98635A FP accelerator"
+#define DIO_ID_MISC4 0x0b /* timer */
+#define DIO_DESC_MISC4 "timer"
+#define DIO_ID_MISC5 0x12 /* 98640A */
+#define DIO_DESC_MISC5 "98640A"
+#define DIO_ID_MISC6 0x16 /* 98659A */
+#define DIO_DESC_MISC6 "98659A"
+#define DIO_ID_MISC7 0x19 /* 237 display */
+#define DIO_DESC_MISC7 "237 display"
+#define DIO_ID_MISC8 0x1a /* quad-wide card */
+#define DIO_DESC_MISC8 "quad-wide card"
+#define DIO_ID_MISC9 0x1b /* 98253A */
+#define DIO_DESC_MISC9 "98253A"
+#define DIO_ID_MISC10 0x1c /* 98627A */
+#define DIO_DESC_MISC10 "98253A"
+#define DIO_ID_MISC11 0x1d /* 98633A */
+#define DIO_DESC_MISC11 "98633A"
+#define DIO_ID_MISC12 0x1e /* 98259A */
+#define DIO_DESC_MISC12 "98259A"
+#define DIO_ID_MISC13 0x1f /* 8741 */
+#define DIO_DESC_MISC13 "8741"
+#define DIO_ID_VME 0x31 /* 98577A VME adapter */
+#define DIO_DESC_VME "98577A VME adapter"
+#define DIO_ID_DCL 0x34 /* 98628A serial */
+#define DIO_DESC_DCL "98628A DCL serial"
+#define DIO_ID_DCLREM 0xb4 /* 98628A serial */
+#define DIO_DESC_DCLREM "98628A DCLREM serial"
+/* These are the secondary IDs for the framebuffers */
+#define DIO_ID2_GATORBOX 0x01 /* 98700/98710 "gatorbox" */
+#define DIO_DESC2_GATORBOX "98700/98710 \"gatorbox\" display"
+#define DIO_ID2_TOPCAT 0x02 /* 98544/98545/98547 "topcat" */
+#define DIO_DESC2_TOPCAT "98544/98545/98547 \"topcat\" display"
+#define DIO_ID2_RENAISSANCE 0x04 /* 98720/98721 "renaissance" */
+#define DIO_DESC2_RENAISSANCE "98720/98721 \"renaissance\" display"
+#define DIO_ID2_LRCATSEYE 0x05 /* lowres "catseye" */
+#define DIO_DESC2_LRCATSEYE "low-res catseye display"
+#define DIO_ID2_HRCCATSEYE 0x06 /* highres colour "catseye" */
+#define DIO_DESC2_HRCCATSEYE "high-res color catseye display"
+#define DIO_ID2_HRMCATSEYE 0x07 /* highres mono "catseye" */
+#define DIO_DESC2_HRMCATSEYE "high-res mono catseye display"
+#define DIO_ID2_DAVINCI 0x08 /* 98730/98731 "davinci" */
+#define DIO_DESC2_DAVINCI "98730/98731 \"davinci\" display"
+#define DIO_ID2_XXXCATSEYE 0x09 /* "catseye" */
+#define DIO_DESC2_XXXCATSEYE "catseye display"
+#define DIO_ID2_HYPERION 0x0e /* A1096A "hyperion" */
+#define DIO_DESC2_HYPERION "A1096A \"hyperion\" display"
+#define DIO_ID2_XGENESIS 0x0b /* "x-genesis"; no NetBSD support */
+#define DIO_DESC2_XGENESIS "\"x-genesis\" display"
+#define DIO_ID2_TIGER 0x0c /* "tiger"; no NetBSD support */
+#define DIO_DESC2_TIGER "\"tiger\" display"
+#define DIO_ID2_YGENESIS 0x0d /* "y-genesis"; no NetBSD support */
+#define DIO_DESC2_YGENESIS "\"y-genesis\" display"
+/* if you add new IDs then you should tell dio.c about them so it can
+ * identify them...
+ */
+
+extern void dio_init(void);
+extern int dio_find(int deviceid);
+extern void *dio_scodetoviraddr(int scode);
+extern int dio_scodetoipl(int scode);
+extern void dio_config_board(int scode);
+extern void dio_unconfig_board(int scode);
+
+
+#endif /* __KERNEL__ */
+#endif /* ndef _LINUX_DIO_H */
#define RTCF_MASQ 0x00400000
#define RTCF_SNAT 0x00800000
#define RTCF_DOREDIRECT 0x01000000
-#define RTCF_LOG 0x02000000
#define RTCF_DIRECTSRC 0x04000000
#define RTCF_DNAT 0x08000000
#define RTCF_BROADCAST 0x10000000
extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *);
+int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
/* The stuff that follows may be totally unneeded. I have not checked to see
which prototypes we are still using. */
#endif /* __KERNEL__ */
#endif
-
-
-
/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
#define MINIX_LINK_MAX 250
+#define MINIX2_LINK_MAX 65530
#define MINIX_I_MAP_SLOTS 8
#define MINIX_Z_MAP_SLOTS 64
extern struct inode_operations minix_file_inode_operations;
extern struct inode_operations minix_dir_inode_operations;
extern struct inode_operations minix_symlink_inode_operations;
+extern struct dentry_operations minix_dentry_operations;
#endif /* __KERNEL__ */
unsigned long s_firstdatazone;
unsigned long s_log_zone_size;
unsigned long s_max_size;
- unsigned long s_dirsize;
- unsigned long s_namelen;
+ int s_dirsize;
+ int s_namelen;
+ int s_link_max;
struct buffer_head ** s_imap;
struct buffer_head ** s_zmap;
struct buffer_head * s_sbh;
extern void vmtruncate(struct inode * inode, unsigned long offset);
extern void handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
+extern void check_pgt_cache(void);
extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
extern void mem_init(unsigned long start_mem, unsigned long end_mem);
void *atalk_ptr; /* Appletalk link */
void *ip_ptr; /* IPv4 specific data */
+ void *dn_ptr; /* DECnet specific data */
struct Qdisc *qdisc;
struct Qdisc *qdisc_sleeping;
};
typedef int (*encode_dent_fn)(struct readdir_cd *, const char *,
int, off_t, ino_t);
+typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
/*
* Procedure table for NFSv2
*/
int nfsd_svc(unsigned short port, int nrservs);
+/* nfsd/vfs.c */
+int fh_lock_parent(struct svc_fh *, struct dentry *);
void nfsd_racache_init(void);
int nfsd_lookup(struct svc_rqst *, struct svc_fh *,
const char *, int, struct svc_fh *);
void (*release_resources)(struct parport *);
int (*claim_resources)(struct parport *);
+ void (*epp_write_data)(struct parport *, unsigned char);
+ unsigned char (*epp_read_data)(struct parport *);
+ void (*epp_write_addr)(struct parport *, unsigned char);
+ unsigned char (*epp_read_addr)(struct parport *);
+ int (*epp_check_timeout)(struct parport *);
size_t (*epp_write_block)(struct parport *, void *, size_t);
size_t (*epp_read_block)(struct parport *, void *, size_t);
#define parport_change_mode(p,m) parport_pc_change_mode(p,m)
#define parport_release_resources(p) parport_pc_release_resources(p)
#define parport_claim_resources(p) parport_pc_claim_resources(p)
+#define parport_epp_write_data(p,x) parport_pc_write_epp(p,x)
+#define parport_epp_read_data(p) parport_pc_read_epp(p)
+#define parport_epp_write_addr(p,x) parport_pc_write_epp_addr(p,x)
+#define parport_epp_read_addr(p) parport_pc_read_epp_addr(p)
+#define parport_epp_check_timeout(p) parport_pc_check_epp_timeout(p)
#endif
#ifdef PARPORT_NEED_GENERIC_OPS
#define parport_change_mode(p,m) (p)->ops->change_mode(p,m)
#define parport_release_resources(p) (p)->ops->release_resources(p)
#define parport_claim_resources(p) (p)->ops->claim_resources(p)
+#define parport_epp_write_data(p,x) (p)->ops->epp_write_data(p,x)
+#define parport_epp_read_data(p) (p)->ops->epp_read_data(p)
+#define parport_epp_write_addr(p,x) (p)->ops->epp_write_addr(p,x)
+#define parport_epp_read_addr(p) (p)->ops->epp_read_addr(p)
+#define parport_epp_check_timeout(p) (p)->ops->epp_check_timeout(p)
#endif
#endif /* __KERNEL__ */
#define ECONTROL 0x402
#define CONFIGB 0x401
#define CONFIGA 0x400
-#define EPPREG 0x4
+#define EPPDATA 0x4
+#define EPPADDR 0x3
#define CONTROL 0x2
#define STATUS 0x1
#define DATA 0
+extern int parport_pc_epp_clear_timeout(struct parport *pb);
+
+
extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
{
- outb(d, p->base+EPPREG);
+ outb(d, p->base+EPPDATA);
}
extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
{
- return inb(p->base+EPPREG);
+ return inb(p->base+EPPDATA);
+}
+
+extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+{
+ outb(d, p->base+EPPADDR);
+}
+
+extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p)
+{
+ return inb(p->base+EPPADDR);
+}
+
+extern __inline__ int parport_pc_check_epp_timeout(struct parport *p)
+{
+ if (!(inb(p->base+STATUS) & 1))
+ return 0;
+ parport_pc_epp_clear_timeout(p);
+ return 1;
}
extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
--- /dev/null
+/* pg.h (c) 1998 Grant R. Guenther <grant@torque.net>
+ Under the terms of the GNU public license
+
+
+ pg.h defines the user interface to the generic ATAPI packet
+ command driver for parallel port ATAPI devices (pg). The
+ driver is loosely modelled after the generic SCSI driver, sg,
+ although the actual interface is different.
+
+ The pg driver provides a simple character device interface for
+ sending ATAPI commands to a device. With the exception of the
+ ATAPI reset operation, all operations are performed by a pair
+ of read and write operations to the appropriate /dev/pgN device.
+ A write operation delivers a command and any outbound data in
+ a single buffer. Normally, the write will succeed unless the
+ device is offline or malfunctioning, or there is already another
+ command pending. If the write succeeds, it should be followed
+ immediately by a read operation, to obtain any returned data and
+ status information. A read will fail if there is no operation
+ in progress.
+
+ As a special case, the device can be reset with a write operation,
+ and in this case, no following read is expected, or permitted.
+
+ There are no ioctl() operations. Any single operation
+ may transfer at most PG_MAX_DATA bytes. Note that the driver must
+ copy the data through an internal buffer. In keeping with all
+ current ATAPI devices, command packets are assumed to be exactly
+ 12 bytes in length.
+
+ To permit future changes to this interface, the headers in the
+ read and write buffers contain a single character "magic" flag.
+ Currently this flag must be the character "P".
+
+*/
+
+#define PG_MAGIC 'P'
+#define PG_RESET 'Z'
+#define PG_COMMAND 'C'
+
+#define PG_MAX_DATA 32768
+
+struct pg_write_hdr {
+
+ char magic; /* == PG_MAGIC */
+ char func; /* PG_RESET or PG_COMMAND */
+ int dlen; /* number of bytes expected to transfer */
+ int timeout; /* number of seconds before timeout */
+ char packet[12]; /* packet command */
+
+};
+
+struct pg_read_hdr {
+
+ char magic; /* == PG_MAGIC */
+ char scsi; /* "scsi" status == sense key */
+ int dlen; /* size of device transfer request */
+ int duration; /* time in seconds command took */
+ char pad[12]; /* not used */
+
+};
+
+/* end of pg.h */
if (ufdset) {
int error;
error = verify_area(VERIFY_WRITE, ufdset, nr);
- if (!error)
- error = __copy_from_user(fdset, ufdset, nr);
+ if (!error && __copy_from_user(fdset, ufdset, nr))
+ error = -EFAULT;
return error;
}
memset(fdset, 0, nr);
PROC_SLABINFO,
PROC_PARPORT,
PROC_PPC_HTAB,
+ PROC_STRAM,
PROC_SOUND,
PROC_MTRR, /* whether enabled or not */
PROC_FS
atomic_dec(&rtnl_rlockct);
if (atomic_read(&rtnl_rlockct) <= 1) {
wake_up(&rtnl_wait);
- if (rtnl->receive_queue.qlen)
+ if (rtnl && rtnl->receive_queue.qlen)
rtnl->data_ready(rtnl, 0);
}
}
atomic_dec(&rtnl_rlockct); \
if (atomic_read(&rtnl_rlockct) <= 1) { \
wake_up(&rtnl_wait); \
- if (rtnl->receive_queue.qlen) \
+ if (rtnl && rtnl->receive_queue.qlen) \
rtnl->data_ready(rtnl, 0); \
} \
})
}
}
+extern char * render_sigset_t(sigset_t *set, char *buffer);
+
/* Some extensions for manipulating the low 32 signals in particular. */
extern inline void sigaddsetmask(sigset_t *set, unsigned long mask)
void si_swapinfo(struct sysinfo *);
unsigned long get_swap_page(void);
extern void FASTCALL(swap_free(unsigned long));
+struct swap_list_t {
+ int head; /* head of priority-ordered swapfile list */
+ int next; /* swapfile to be used next */
+};
+extern struct swap_list_t swap_list;
/*
* vm_ops not present page codes for shared memory.
VM_OVERCOMMIT_MEMORY, /* Turn off the virtual memory safety limit */
VM_BUFFERMEM, /* struct: Set buffer memory thresholds */
VM_PAGECACHE, /* struct: Set cache memory thresholds */
- VM_PAGERDAEMON /* struct: Control kswapd behaviour */
+ VM_PAGERDAEMON, /* struct: Control kswapd behaviour */
+ VM_PGT_CACHE /* struct: Set page table cache parameters */
};
timer->prev = NULL;
}
+/*
+ * These inlines deal with timer wrapping correctly. You are
+ * strongly encouraged to use them
+ * 1. Because people otherwise forget
+ * 2. Because if the timer wrap changes in future you wont have to
+ * alter your driver code.
+ */
+
+extern inline int time_before(unsigned long a, unsigned long b)
+{
+ return((long)((a) - (b)) < 0L);
+}
+
+extern inline int time_after(unsigned long a, unsigned long b)
+{
+ return((long)((a) - (b)) > 0L);
+}
+
#endif
extern struct new_utsname system_utsname;
+extern struct semaphore uts_sem;
#endif
void vmfree_area_pages(unsigned long address, unsigned long size);
int vmalloc_area_pages(unsigned long address, unsigned long size);
-extern inline void set_pgdir(unsigned long address, pgd_t entry)
-{
-#if !defined(__mc68000__) && !defined(__sparc_v9__)
- struct task_struct * p;
-
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (!p->mm)
- continue;
- *pgd_offset(p->mm,address) = entry;
- }
- read_unlock(&tasklist_lock);
-#endif
-}
-
#endif
return mss_now;
}
-/* Compute the actual receive window we are currently advertising. */
+/* Compute the actual receive window we are currently advertising.
+ * Rcv_nxt can be after the window if our peer push more data
+ * than the offered window.
+ */
static __inline__ u32 tcp_receive_window(struct tcp_opt *tp)
{
- return tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
+ s32 win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt;
+
+ if (win < 0)
+ win = 0;
+ return (u32) win;
}
/* Choose a new window, without checks for shrinking, and without
* scaling applied to the result. The caller does these things
* if necessary. This is a "raw" window selection.
*/
-extern u32 __tcp_select_window(struct sock *sk);
+extern u32 __tcp_select_window(struct sock *sk, u32 cur_win);
/* Chose a new window to advertise, update state in tcp_opt for the
* socket, and return result with RFC1323 scaling applied. The return
extern __inline__ u16 tcp_select_window(struct sock *sk)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- u32 new_win = __tcp_select_window(sk);
u32 cur_win = tcp_receive_window(tp);
+ u32 new_win = __tcp_select_window(sk, cur_win);
/* Never shrink the offered window */
if(new_win < cur_win)
extern __inline__ int tcp_raise_window(struct sock *sk)
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- u32 new_win = __tcp_select_window(sk);
u32 cur_win = tcp_receive_window(tp);
+ u32 new_win = __tcp_select_window(sk, cur_win);
return (new_win && (new_win > (cur_win << 1)));
}
#include <linux/pci.h>
#endif
+#ifdef CONFIG_DIO
+#include <linux/dio.h>
+#endif
+
/*
* Versions of gcc older than that listed below may actually compile
* and link okay, but the end product can have subtle run time bugs.
extern void filescache_init(void);
extern void signals_init(void);
+#ifdef CONFIG_ARCH_ACORN
+extern void ecard_init(void);
+#endif
+
extern void smp_setup(char *str, int *ints);
#ifdef __i386__
extern void ioapic_pirq_setup(char *str, int *ints);
#ifdef CONFIG_PARIDE_PT
extern void pt_setup(char *str, int *ints);
#endif
+#ifdef CONFIG_PARIDE_PG
+extern void pg_setup(char *str, int *ints);
+#endif
#ifdef CONFIG_PARIDE_PCD
extern void pcd_setup(char *str, int *ints);
#endif
#endif
#ifdef CONFIG_PARIDE_PT
{ "pt.", pt_setup },
+#endif
+#ifdef CONFIG_PARIDE_PG
+ { "pg.", pg_setup },
#endif
{ 0, 0 }
};
#ifdef CONFIG_SYSCTL
sysctl_init();
#endif
+#ifdef CONFIG_DIO
+ dio_init();
+#endif
/*
* Ok, at this point all CPU's should be initialized, so
#ifdef CONFIG_MCA
mca_init();
#endif
+#ifdef CONFIG_ARCH_ACORN
+ ecard_init();
+#endif
/*
* We count on the initial thread going ok
int pid;
int waitpid_result;
- /* Don't allow request_mode() before the root fs is mounted! */
+ /* Don't allow request_module() before the root fs is mounted! */
if ( ! current->fs->root ) {
printk(KERN_ERR "request_module[%s]: Root fs not mounted\n",
module_name);
EXPORT_SYMBOL(vsprintf);
EXPORT_SYMBOL(kdevname);
EXPORT_SYMBOL(simple_strtoul);
-EXPORT_SYMBOL(system_utsname);
+EXPORT_SYMBOL(system_utsname); /* UTS data */
+EXPORT_SYMBOL(uts_sem); /* UTS semaphore */
EXPORT_SYMBOL(sys_call_table);
EXPORT_SYMBOL(machine_restart);
EXPORT_SYMBOL(machine_halt);
printk("\n");
{
- extern char * render_sigset_t(sigset_t *set, char *buffer);
struct signal_queue *q;
char s[sizeof(sigset_t)*2+1], b[sizeof(sigset_t)*2+1];
}
}
+char * render_sigset_t(sigset_t *set, char *buffer)
+{
+ int i = _NSIG, x;
+ do {
+ i -= 4, x = 0;
+ if (sigismember(set, i+1)) x |= 1;
+ if (sigismember(set, i+2)) x |= 2;
+ if (sigismember(set, i+3)) x |= 4;
+ if (sigismember(set, i+4)) x |= 8;
+ *buffer++ = (x < 10 ? '0' : 'a' - 10) + x;
+ } while (i >= 4);
+ *buffer = 0;
+ return buffer;
+}
+
void show_state(void)
{
struct task_struct *p;
extern unsigned long htab_reclaim_on, zero_paged_on;
#endif
+extern int pgt_cache_water[];
+
static int parse_table(int *, int, void *, size_t *, void *, size_t,
ctl_table *, void **);
+static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp);
static ctl_table root_table[];
static ctl_table kern_table[] = {
{KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
- 0444, NULL, &proc_dostring, &sysctl_string},
+ 0444, NULL, &proc_doutsstring, &sysctl_string},
{KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
- 0444, NULL, &proc_dostring, &sysctl_string},
+ 0444, NULL, &proc_doutsstring, &sysctl_string},
{KERN_VERSION, "version", system_utsname.version, 64,
- 0444, NULL, &proc_dostring, &sysctl_string},
+ 0444, NULL, &proc_doutsstring, &sysctl_string},
{KERN_NODENAME, "hostname", system_utsname.nodename, 64,
- 0644, NULL, &proc_dostring, &sysctl_string},
+ 0644, NULL, &proc_doutsstring, &sysctl_string},
{KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
- 0644, NULL, &proc_dostring, &sysctl_string},
+ 0644, NULL, &proc_doutsstring, &sysctl_string},
{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
0644, NULL, &proc_dointvec},
#ifdef CONFIG_BLK_DEV_INITRD
&page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
{VM_PAGERDAEMON, "kswapd",
&pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
+ {VM_PGT_CACHE, "pagetable_cache",
+ &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
{0}
};
return 0;
}
+/*
+ * Special case of dostring for the UTS structure. This has locks
+ * to observe. Should this be in kernel/sys.c ????
+ */
+
+static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ int r;
+ down(&uts_sem);
+ r=proc_dostring(table,write,filp,buffer,lenp);
+ up(&uts_sem);
+ return r;
+}
+
static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp, int conv)
{
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
copy_page(to, from);
}
-#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
-
mem_map_t * mem_map = NULL;
/*
int new_page_tables(struct task_struct * tsk)
{
- pgd_t * page_dir, * new_pg;
+ pgd_t * new_pg;
if (!(new_pg = pgd_alloc()))
return -ENOMEM;
- page_dir = pgd_offset(&init_mm, 0);
- memcpy(new_pg + USER_PTRS_PER_PGD, page_dir + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof (pgd_t));
SET_PAGE_DIR(tsk, new_pg);
tsk->mm->pgd = new_pg;
return 0;
no_memory:
oom(tsk);
}
+
+/* Low and high watermarks for page table cache.
+ The system should try to have pgt_water[0] <= cache elements <= pgt_water[1]
+ */
+int pgt_cache_water[2] = { 25, 50 };
+
+void check_pgt_cache(void)
+{
+ if(pgtable_cache_size > pgt_cache_water[0]) {
+ do {
+ if(pgd_quicklist)
+ free_pgd_slow(get_pgd_fast());
+ if(pmd_quicklist)
+ free_pmd_slow(get_pmd_fast());
+ if(pte_quicklist)
+ free_pte_slow(get_pte_fast());
+ } while(pgtable_cache_size > pgt_cache_water[1]);
+ }
+}
/* Check against rlimit and stack.. */
rlim = current->rlim[RLIMIT_DATA].rlim_cur;
- if (rlim >= RLIM_INFINITY)
- rlim = ~0;
- if (brk - mm->end_code > rlim)
+ if (rlim < RLIM_INFINITY && brk - mm->end_code > rlim)
goto out;
/* Check against existing mmap mappings. */
int do_munmap(unsigned long addr, size_t len)
{
struct mm_struct * mm;
- struct vm_area_struct *mpnt, *next, *free, *extra;
+ struct vm_area_struct *mpnt, *free, *extra;
int freed;
if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
if (!mpnt)
return 0;
+ /* If we'll make "hole", check the vm areas limit */
+ if ((mpnt->vm_start < addr && mpnt->vm_end > addr+len) &&
+ mm->map_count > MAX_MAP_COUNT)
+ return -ENOMEM;
+
/*
* We may need one additional vma to fix up the mappings ...
* and this is the last chance for an easy error exit.
if (!extra)
return -ENOMEM;
- next = mpnt->vm_next;
-
- /* we have mpnt->vm_next = next and addr < mpnt->vm_end */
+ /* we have addr < mpnt->vm_end */
free = NULL;
for ( ; mpnt && mpnt->vm_start < addr+len; ) {
struct vm_area_struct *next = mpnt->vm_next;
mpnt = next;
}
- if (free && (free->vm_start < addr) && (free->vm_end > addr+len)) {
- if (mm->map_count > MAX_MAP_COUNT) {
- kmem_cache_free(vm_area_cachep, extra);
- return -ENOMEM;
- }
- }
-
/* Ok - we have the memory areas we should free on the 'free' list,
* so release them, and unmap the page range..
* If the one of the segments is only being partially unmapped,
unsigned int nr_swapfiles = 0;
-static struct {
- int head; /* head of priority-ordered swapfile list */
- int next; /* swapfile to be used next */
-} swap_list = {-1, -1};
+struct swap_list_t swap_list = {-1, -1};
struct swap_info_struct swap_info[MAX_SWAPFILES];
p->flags = SWP_WRITEOK;
p->pages = j;
nr_swap_pages += j;
- printk("Adding Swap: %dk swap-space (priority %d)\n",
+ printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
j<<(PAGE_SHIFT-10), p->prio);
/* insert swap space into swap_list: */
dir = pgd_offset_k(address);
flush_cache_all();
while (address < end) {
- pmd_t *pmd = pmd_alloc_kernel(dir, address);
+ pmd_t *pmd;
+ pgd_t olddir = *dir;
+
+ pmd = pmd_alloc_kernel(dir, address);
if (!pmd)
return -ENOMEM;
if (alloc_area_pmd(pmd, address, end - address))
return -ENOMEM;
- set_pgdir(address, *dir);
+ if (pgd_val(olddir) != pgd_val(*dir))
+ set_pgdir(address, *dir);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
}
if (!area)
return NULL;
addr = (void *) VMALLOC_START;
- area->size = size + PAGE_SIZE;
- area->next = NULL;
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
if (size + (unsigned long) addr < (unsigned long) tmp->addr)
break;
addr = (void *) (tmp->size + (unsigned long) tmp->addr);
}
area->addr = addr;
+ area->size = size + PAGE_SIZE;
area->next = *p;
*p = area;
return area;
long vread(char *buf, char *addr, unsigned long count)
{
- struct vm_struct **p, *tmp;
+ struct vm_struct *tmp;
char *vaddr, *buf_start = buf;
- int n;
+ unsigned long n;
/* Don't allow overflow */
if ((unsigned long) addr + count < count)
count = -(unsigned long) addr;
- for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+ for (tmp = vmlist; tmp; tmp = tmp->next) {
vaddr = (char *) tmp->addr;
+ if (addr >= vaddr + tmp->size - PAGE_SIZE)
+ continue;
while (addr < vaddr) {
if (count == 0)
goto finished;
addr++;
count--;
}
- n = tmp->size - PAGE_SIZE;
- if (addr > vaddr)
- n -= addr - vaddr;
- while (--n >= 0) {
+ n = vaddr + tmp->size - PAGE_SIZE - addr;
+ do {
if (count == 0)
goto finished;
put_user(*addr, buf);
buf++;
addr++;
count--;
- }
+ } while (--n > 0);
}
finished:
return buf - buf_start;
}
/*
- * Register SNAP clients. We don't yet use this for IP or IPX.
+ * Register SNAP clients. We don't yet use this for IP.
*/
struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *))
int size;
if (stats)
- size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %8lu %4lu %4lu %4lu %5lu %4lu %4lu\n",
+ size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
dev->name,
stats->rx_bytes,
stats->rx_packets, stats->rx_errors,
dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_RUNNING|IFF_NOARP|
IFF_SLAVE|IFF_MASTER|
IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) |
- (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC));
+ (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI));
/*
* Load in the correct multicast list now the flags have changed.
if (ret == 0)
dev_mc_upload(dev);
- }
+ }
if (dev->flags&IFF_UP &&
- ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC|IFF_VOLATILE))) {
- printk(KERN_DEBUG "SIFFL %s(%s)\n", dev->name, current->comm);
+ ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC|IFF_ALLMULTI|IFF_VOLATILE)))
notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
- }
if ((flags^dev->gflags)&IFF_PROMISC) {
int inc = (flags&IFF_PROMISC) ? +1 : -1;
dev_set_promiscuity(dev, inc);
}
+ /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI
+ is important. Some (broken) drivers set IFF_PROMISC, when
+ IFF_ALLMULTI is requested not asking us and not reporting.
+ */
+ if ((flags^dev->gflags)&IFF_ALLMULTI) {
+ int inc = (flags&IFF_ALLMULTI) ? +1 : -1;
+ dev->gflags ^= IFF_ALLMULTI;
+ dev_set_allmulti(dev, inc);
+ }
+
return ret;
}
switch(cmd)
{
case SIOCGIFFLAGS: /* Get interface flags */
- ifr->ifr_flags = (dev->flags&~IFF_PROMISC)|(dev->gflags&IFF_PROMISC);
+ ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+ |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI));
return 0;
case SIOCSIFFLAGS: /* Set interface flags */
printk("Evaluating net profiler cost ...");
#if CPU == 586 || CPU == 686
if (!(boot_cpu_data.x86_capability & 16)) {
- printk(KERN_ERR "Sorry, you CPU does not support tsc. Net profiler is dying...\n");
+ printk(KERN_ERR "Sorry, your CPU does not support TSC. Net profiler disabled.\n");
return -1;
}
#endif
sk->broadcast=valbool;
break;
case SO_SNDBUF:
- /*
- * The spec isnt clear if ENOBUFS or EINVAL
- * is best
- */
-
- /* printk(KERN_DEBUG "setting SO_SNDBUF %d\n", val); */
+ /* Don't error on this BSD doesn't and if you think
+ about it this is right. Otherwise apps have to
+ play 'guess the biggest size' games. RCVBUF/SNDBUF
+ are treated in BSD as hints */
+
if (val > sysctl_wmem_max)
- return -EINVAL;
+ return 0;
- /* FIXME: the tcp code should be made to work even
- * with small sndbuf values.
- */
sk->sndbuf = max(val*2,2048);
/*
break;
case SO_RCVBUF:
- /* printk(KERN_DEBUG "setting SO_RCVBUF %d\n", val); */
-
+ /* Don't error on this BSD doesn't and if you think
+ about it this is right. Otherwise apps have to
+ play 'guess the biggest size' games. RCVBUF/SNDBUF
+ are treated in BSD as hints */
+
if (val > sysctl_rmem_max)
- return -EINVAL;
+ return 0;
/* FIXME: is this lower bound the right one? */
sk->rcvbuf = max(val*2,256);
{
struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
- if(sk && zero_it) {
- memset(sk, 0, sizeof(struct sock));
+ if(sk) {
+ if (zero_it) memset(sk, 0, sizeof(struct sock));
sk->family = family;
}
void *sock_kmalloc(struct sock *sk, int size, int priority)
{
- void *mem = NULL;
if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) {
+ void *mem;
/* First do the add, to avoid the race if kmalloc
* might sleep.
*/
atomic_add(size, &sk->omem_alloc);
mem = kmalloc(size, priority);
+ if (mem)
+ return mem;
+ atomic_sub(size, &sk->omem_alloc);
}
- return mem;
+ return NULL;
}
void sock_kfree_s(struct sock *sk, void *mem, int size)
unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt)
{
- return -EOPNOTSUPP;
+ return 0;
}
int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
*
* IPv4 Forwarding Information Base: FIB frontend.
*
- * Version: $Id: fib_frontend.c,v 1.10 1998/05/08 21:06:27 davem Exp $
+ * Version: $Id: fib_frontend.c,v 1.11 1998/06/11 03:15:40 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
if (tb)
err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
}
+ if (rta.rta_mx)
+ kfree(rta.rta_mx);
}
rtnl_unlock();
return err;
*
* IPv4 Forwarding Information Base: semantics.
*
- * Version: $Id: fib_semantics.c,v 1.8 1998/04/28 06:21:58 davem Exp $
+ * Version: $Id: fib_semantics.c,v 1.9 1998/06/11 03:15:41 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
*rta->rta_mtu = r->rt_mtu;
}
#else
- if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT))
- printk(KERN_DEBUG "SIOCRT*: mtu/window/irtt are not implemnted.\n");
+ if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {
+ struct rtattr *rec;
+ struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);
+ if (mx == NULL)
+ return -ENOMEM;
+ rta->rta_mx = mx;
+ mx->rta_type = RTA_METRICS;
+ mx->rta_len = RTA_LENGTH(0);
+ if (r->rt_flags&RTF_MTU) {
+ rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+ rec->rta_type = RTAX_MTU;
+ rec->rta_len = RTA_LENGTH(4);
+ mx->rta_len += RTA_LENGTH(4);
+ *(u32*)RTA_DATA(rec) = r->rt_mtu;
+ }
+ if (r->rt_flags&RTF_WINDOW) {
+ rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+ rec->rta_type = RTAX_WINDOW;
+ rec->rta_len = RTA_LENGTH(4);
+ mx->rta_len += RTA_LENGTH(4);
+ *(u32*)RTA_DATA(rec) = r->rt_window;
+ }
+ if (r->rt_flags&RTF_IRTT) {
+ rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+ rec->rta_type = RTAX_RTT;
+ rec->rta_len = RTA_LENGTH(4);
+ mx->rta_len += RTA_LENGTH(4);
+ *(u32*)RTA_DATA(rec) = r->rt_irtt;
+ }
+ }
#endif
return 0;
}
*
* Alan Cox, <alan@cymru.net>
*
- * Version: $Id: icmp.c,v 1.41 1998/04/29 22:12:10 alan Exp $
+ * Version: $Id: icmp.c,v 1.43 1998/06/11 03:15:43 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
*/
saddr = iph->daddr;
- if (!(rt->rt_flags&RTCF_LOCAL))
+ if (!(rt->rt_flags & RTCF_LOCAL))
saddr = 0;
tos = icmp_pointers[type].error ?
*
* The IP fragmentation functionality.
*
- * Version: $Id: ip_fragment.c,v 1.36 1998/04/18 02:13:07 davem Exp $
+ * Version: $Id: ip_fragment.c,v 1.37 1998/06/10 00:22:00 davem Exp $
*
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
* Andi Kleen : Add sysctls.
* xxxx : Overlapfrag bug.
* Ultima : ip_expire() kernel panic.
+ * Bill Hawes : Frag accounting and evictor fixes.
*/
#include <linux/types.h>
atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */
-char *in_ntoa(__u32 in);
-
/* Memory Tracking Functions. */
extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
{
extern __inline__ void frag_kfree_s(void *ptr, int len)
{
atomic_sub(len, &ip_frag_mem);
- kfree_s(ptr,len);
+ kfree(ptr);
}
extern __inline__ void *frag_kmalloc(int size, int pri)
{
- void *vp=kmalloc(size,pri);
+ void *vp = kmalloc(size, pri);
if(!vp)
return NULL;
struct ipfrag *fp;
fp = (struct ipfrag *) frag_kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
- if (fp == NULL) {
- NETDEBUG(printk(KERN_ERR "IP: frag_create: no memory left !\n"));
- return(NULL);
- }
+ if (fp == NULL)
+ goto out_nomem;
/* Fill in the structure. */
fp->offset = offset;
atomic_add(skb->truesize, &ip_frag_mem);
return(fp);
+
+out_nomem:
+ NETDEBUG(printk(KERN_ERR "IP: frag_create: no memory left !\n"));
+ return(NULL);
}
/* Find the correct entry in the "incomplete datagrams" queue for
unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
struct ipq *qp;
- start_bh_atomic();
+ /* Always, we are in a BH context, so no locking. -DaveM */
for(qp = ipq_hash[hash]; qp; qp = qp->next) {
if(qp->iph->id == id &&
qp->iph->saddr == saddr &&
break;
}
}
- end_bh_atomic();
return qp;
}
/* Remove an entry from the "incomplete datagrams" queue, either
* because we completed, reassembled and processed it, or because
* it timed out.
+ *
+ * This is called _only_ from BH contexts, on packet reception
+ * processing and from frag queue expiration timers. -DaveM
*/
static void ip_free(struct ipq *qp)
{
del_timer(&qp->timer);
/* Remove this entry from the "incomplete datagrams" queue. */
- start_bh_atomic();
if(qp->next)
qp->next->pprev = qp->pprev;
*qp->pprev = qp->next;
- end_bh_atomic();
/* Release all fragment data. */
fp = qp->fragments;
frag_kfree_s(qp, sizeof(struct ipq));
}
-/* Oops, a fragment queue timed out. Kill it and send an ICMP reply. */
+/*
+ * Oops, a fragment queue timed out. Kill it and send an ICMP reply.
+ */
static void ip_expire(unsigned long arg)
{
struct ipq *qp = (struct ipq *) arg;
#ifdef IP_EXPIRE_DEBUG
printk("warning: possible ip-expire attack\n");
#endif
- ip_free(qp);
- return;
+ goto out;
}
/* Send an ICMP "Fragment Reassembly Timeout" message. */
ip_statistics.IpReasmTimeout++;
ip_statistics.IpReasmFails++;
- icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+ icmp_send(qp->fragments->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+out:
/* Nuke the fragment queue. */
ip_free(qp);
}
*/
static void ip_evictor(void)
{
- while(atomic_read(&ip_frag_mem)>sysctl_ipfrag_low_thresh) {
- int i;
-
- /* FIXME: Make LRU queue of frag heads. -DaveM */
- for(i = 0; i < IPQ_HASHSZ; i++)
- if(ipq_hash[i])
- break;
- if(i >= IPQ_HASHSZ)
- panic("ip_evictor: memcount");
- ip_free(ipq_hash[i]);
+ int i, progress;
+
+restart:
+ progress = 0;
+ /* FIXME: Make LRU queue of frag heads. -DaveM */
+ for (i = 0; i < IPQ_HASHSZ; i++) {
+ struct ipq *qp;
+ if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh)
+ return;
+ /* We are in a BH context, so these queue
+ * accesses are safe. -DaveM
+ */
+ qp = ipq_hash[i];
+ if (qp) {
+ /* find the oldest queue for this hash bucket */
+ while (qp->next)
+ qp = qp->next;
+ ip_free(qp);
+ progress = 1;
+ }
}
+ if (progress)
+ goto restart;
+ panic("ip_evictor: memcount");
}
/* Add an entry to the 'ipq' queue for a newly received IP datagram.
int ihlen;
qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
- if (qp == NULL) {
- NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
- return(NULL);
- }
+ if (qp == NULL)
+ goto out_nomem;
/* Allocate memory for the IP header (plus 8 octets for ICMP). */
ihlen = iph->ihl * 4;
qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC);
- if (qp->iph == NULL) {
- NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
- frag_kfree_s(qp, sizeof(struct ipq));
- return NULL;
- }
+ if (qp->iph == NULL)
+ goto out_free;
memcpy(qp->iph, iph, ihlen + 8);
qp->len = 0;
qp->fragments = NULL;
qp->dev = skb->dev;
- /* Start a timer for this entry. */
+ /* Initialize a timer for this entry. */
init_timer(&qp->timer);
- qp->timer.expires = jiffies + sysctl_ipfrag_time; /* about 30 seconds */
- qp->timer.data = (unsigned long) qp; /* pointer to queue */
- qp->timer.function = ip_expire; /* expire function */
- add_timer(&qp->timer);
+ qp->timer.expires = 0; /* (to be set later) */
+ qp->timer.data = (unsigned long) qp; /* pointer to queue */
+ qp->timer.function = ip_expire; /* expire function */
/* Add this entry to the queue. */
hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
- start_bh_atomic();
+ /* We are in a BH context, no locking necessary. -DaveM */
if((qp->next = ipq_hash[hash]) != NULL)
qp->next->pprev = &qp->next;
ipq_hash[hash] = qp;
qp->pprev = &ipq_hash[hash];
- end_bh_atomic();
return qp;
+
+out_free:
+ frag_kfree_s(qp, sizeof(struct ipq));
+out_nomem:
+ NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
+ return(NULL);
}
/* See if a fragment queue is complete. */
/* Allocate a new buffer for the datagram. */
len = qp->ihlen + qp->len;
- if(len>65535) {
- if (net_ratelimit())
- printk(KERN_INFO "Oversized IP packet from %d.%d.%d.%d.\n", NIPQUAD(qp->iph->saddr));
- ip_statistics.IpReasmFails++;
- ip_free(qp);
- return NULL;
- }
+ if(len > 65535)
+ goto out_oversize;
- if ((skb = dev_alloc_skb(len)) == NULL) {
- ip_statistics.IpReasmFails++;
- NETDEBUG(printk(KERN_ERR "IP: queue_glue: no memory for gluing queue %p\n", qp));
- ip_free(qp);
- return NULL;
- }
+ skb = dev_alloc_skb(len);
+ if (!skb)
+ goto out_nomem;
/* Fill in the basic details. */
skb->mac.raw = ptr = skb->data;
- skb->nh.iph = iph = (struct iphdr*)skb_put(skb,len);
+ skb->nh.iph = iph = (struct iphdr *) skb_put(skb, len);
/* Copy the original IP headers into the new buffer. */
memcpy(ptr, qp->iph, qp->ihlen);
fp = qp->fragments;
count = qp->ihlen;
while(fp) {
- if (fp->len < 0 || count+fp->len > skb->len) {
- NETDEBUG(printk(KERN_ERR "Invalid fragment list: "
- "Fragment over size.\n"));
- ip_free(qp);
- kfree_skb(skb);
- ip_statistics.IpReasmFails++;
- return NULL;
- }
+ if ((fp->len < 0) || ((count + fp->len) > skb->len))
+ goto out_invalid;
memcpy((ptr + fp->offset), fp->ptr, fp->len);
if (count == qp->ihlen) {
skb->dst = dst_clone(fp->skb->dst);
skb->pkt_type = qp->fragments->skb->pkt_type;
skb->protocol = qp->fragments->skb->protocol;
- /* We glued together all fragments, so remove the queue entry. */
- ip_free(qp);
/* Done with all fragments. Fixup the new IP header. */
iph = skb->nh.iph;
iph->frag_off = 0;
iph->tot_len = htons(count);
-
ip_statistics.IpReasmOKs++;
return skb;
+
+out_invalid:
+ NETDEBUG(printk(KERN_ERR
+ "Invalid fragment list: Fragment over size.\n"));
+ kfree_skb(skb);
+ goto out_fail;
+out_nomem:
+ NETDEBUG(printk(KERN_ERR
+ "IP: queue_glue: no memory for gluing queue %p\n",
+ qp));
+ goto out_fail;
+out_oversize:
+ if (net_ratelimit())
+ printk(KERN_INFO
+ "Oversized IP packet from %d.%d.%d.%d.\n",
+ NIPQUAD(qp->iph->saddr));
+out_fail:
+ ip_statistics.IpReasmFails++;
+ return NULL;
}
/* Process an incoming IP datagram fragment. */
struct sk_buff *ip_defrag(struct sk_buff *skb)
{
struct iphdr *iph = skb->nh.iph;
- struct ipfrag *prev, *next, *tmp;
- struct ipfrag *tfp;
+ struct ipfrag *prev, *next, *tmp, *tfp;
struct ipq *qp;
- struct sk_buff *skb2;
unsigned char *ptr;
int flags, offset;
int i, ihl, end;
ip_statistics.IpReasmReqds++;
/* Start by cleaning up the memory. */
- if(atomic_read(&ip_frag_mem)>sysctl_ipfrag_high_thresh)
+ if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
ip_evictor();
- /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
+ /*
+ * Look for the entry for this IP datagram in the
+ * "incomplete datagrams" queue. If found, the
+ * timer is removed.
+ */
qp = ip_find(iph, skb->dst);
/* Is this a non-fragmented datagram? */
offset = ntohs(iph->frag_off);
flags = offset & ~IP_OFFSET;
offset &= IP_OFFSET;
- if (((flags & IP_MF) == 0) && (offset == 0)) {
- if (qp != NULL) {
- /* Fragmented frame replaced by full unfragmented copy. */
- ip_free(qp);
- }
- return skb;
- }
offset <<= 3; /* offset is in 8-byte chunks */
ihl = iph->ihl * 4;
- /* If the queue already existed, keep restarting its timer as long
- * as we still are receiving fragments. Otherwise, create a fresh
- * queue entry.
+ /*
+ * Check whether to create a fresh queue entry. If the
+ * queue already exists, its timer will be restarted as
+ * long as we continue to receive fragments.
*/
if (qp) {
/* ANK. If the first fragment is received,
* we should remember the correct IP header (with options)
*/
if (offset == 0) {
+ /* Fragmented frame replaced by unfragmented copy? */
+ if ((flags & IP_MF) == 0)
+ goto out_freequeue;
qp->ihlen = ihl;
- memcpy(qp->iph, iph, ihl+8);
+ memcpy(qp->iph, iph, (ihl + 8));
}
- /* about 30 seconds */
- mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time);
} else {
+ /* Fragmented frame replaced by unfragmented copy? */
+ if ((offset == 0) && ((flags & IP_MF) == 0))
+ goto out_skb;
+
/* If we failed to create it, then discard the frame. */
- if ((qp = ip_create(skb, iph)) == NULL) {
- kfree_skb(skb);
- ip_statistics.IpReasmFails++;
- return NULL;
- }
+ qp = ip_create(skb, iph);
+ if (!qp)
+ goto out_freeskb;
}
/* Attempt to construct an oversize packet. */
- if(ntohs(iph->tot_len)+(int)offset>65535) {
- if (net_ratelimit())
- printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n", NIPQUAD(iph->saddr));
- frag_kfree_skb(skb);
- ip_statistics.IpReasmFails++;
- return NULL;
- }
+ if((ntohs(iph->tot_len) + ((int) offset)) > 65535)
+ goto out_oversize;
/* Determine the position of this fragment. */
end = offset + ntohs(iph->tot_len) - ihl;
- /* Point into the IP datagram 'data' part. */
- ptr = skb->data + ihl;
-
/* Is this the final fragment? */
if ((flags & IP_MF) == 0)
qp->len = end;
prev = next;
}
+ /* Point into the IP datagram 'data' part. */
+ ptr = skb->data + ihl;
+
/* We found where to put this one. Check for overlap with
* preceding fragment, and, if needed, align things so that
* any overlaps are eliminated.
*/
- if (prev != NULL && offset < prev->end) {
+ if ((prev != NULL) && (offset < prev->end)) {
i = prev->end - offset;
offset += i; /* ptr into datagram */
ptr += i; /* ptr into fragment data */
/* Look for overlap with succeeding segments.
* If we can merge fragments, do it.
*/
- for(tmp=next; tmp != NULL; tmp = tfp) {
+ for (tmp = next; tmp != NULL; tmp = tfp) {
tfp = tmp->next;
if (tmp->offset >= end)
- break; /* no overlaps at all */
+ break; /* no overlaps at all */
- i = end - next->offset; /* overlap is 'i' bytes */
- tmp->len -= i; /* so reduce size of */
- tmp->offset += i; /* next fragment */
+ i = end - next->offset; /* overlap is 'i' bytes */
+ tmp->len -= i; /* so reduce size of */
+ tmp->offset += i; /* next fragment */
tmp->ptr += i;
/* If we get a frag size of <= 0, remove it and the packet
}
}
- /* Insert this fragment in the chain of fragments. */
- tfp = NULL;
+ /*
+ * Create a fragment to hold this skb.
+ * No memory to save the fragment? throw the lot ...
+ */
tfp = ip_frag_create(offset, end, skb, ptr);
+ if (!tfp)
+ goto out_freeskb;
- /* No memory to save the fragment - so throw the lot. */
- if (!tfp) {
- frag_kfree_skb(skb);
- return NULL;
- }
+ /* Insert this fragment in the chain of fragments. */
tfp->prev = prev;
tfp->next = next;
if (prev != NULL)
*/
if (ip_done(qp)) {
/* Glue together the fragments. */
- skb2 = ip_glue(qp);
- return(skb2);
+ skb = ip_glue(qp);
+ /* Free the queue entry. */
+out_freequeue:
+ ip_free(qp);
+out_skb:
+ return skb;
}
+
+ /*
+ * The queue is still active ... reset its timer.
+ */
+out_timer:
+ mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time); /* ~ 30 seconds */
+out:
return NULL;
+
+ /*
+ * Error exits ... we need to reset the timer if there's a queue.
+ */
+out_oversize:
+ if (net_ratelimit())
+ printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n",
+ NIPQUAD(iph->saddr));
+ /* the skb isn't in a fragment, so fall through to free it */
+out_freeskb:
+ kfree_skb(skb);
+ ip_statistics.IpReasmFails++;
+ if (qp)
+ goto out_timer;
+ goto out;
}
/*
- * This code is heavily based on the code in ip_fw.c; see that file for
- * copyrights and attributions. This code is basically GPL.
+ * This code is heavily based on the code on the old ip_fw.c code; see below for
+ * copyrights and attributions of the old code. This code is basically GPL.
*
* 15-Aug-1997: Major changes to allow graphs for firewall rules.
* Paul Russell <Paul.Russell@rustcorp.com.au> and
* Added packet and byte counters for policy matches.
* 26-Feb-1998: Fixed race conditions, added SMP support.
* 18-Mar-1998: Fix SMP, fix race condition fix.
- * 1-May-1998: Remove caching of device pointer, added caching
- * for proc output (no longer order n^2).
+ * 1-May-1998: Remove caching of device pointer.
+ * 12-May-1998: Allow tiny fragment case for TCP/UDP.
+ * 15-May-1998: Treat short packets as fragments, don't just block.
*/
+/*
+ *
+ * The origina Linux port was done Alan Cox, with changes/fixes from
+ * Pauline Middlelink, Jos Vos, Thomas Quinot, Wouter Gadeyne, Juan
+ * Jose Ciarlante, Bernd Eckenfels, Keith Owens and others.
+ *
+ * Copyright from the original FreeBSD version follows:
+ *
+ * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind. */
+
+
#include <linux/config.h>
#include <asm/uaccess.h>
*
* For SMP (kernel v2.1+), multiply this by # CPUs.
*
+ * [Note that this in not correct for 2.2 - because the socket code always
+ * uses lock_kernel() to serialize, and bottom halves (timers and net_bhs)
+ * only run on one CPU at a time. This will probably change for 2.3.
+ * It is still good to use spinlocks because that avoids the global cli()
+ * for updating the tables, which is rather costly in SMP kernels -AK]
+ *
* This means counters and backchains can get corrupted if no precautions
* are taken.
*
return FW_BLOCK;
}
- /* Check for too-small packets (not non-first fragments).
- * For each protocol, we assume that we can get the required
- * information, eg. port number or ICMP type. If this fails,
- * reject it.
- *
- * Sizes might as well be rounded up to 8 here, since either
- * there are more fragments to come (which must be on 8-byte
- * boundaries), or this is a bogus packet anyway.
+ /* If we can't investigate ports, treat as fragment. It's
+ * either a trucated whole packet, or a truncated first
+ * fragment, or a TCP first fragment of length 8-15, in which
+ * case the above rule stops reassembly.
*/
if (offset == 0) {
unsigned int size_req;
default:
size_req = 0;
}
- if (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req) {
- if (!testing && net_ratelimit()) {
- printk("Packet too short.\n");
- dump_packet(ip,rif,NULL,NULL,0,0);
- }
- return FW_BLOCK;
- }
+ offset = (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req);
}
src = ip->saddr;
/*
* If we got interface from which packet came
- * we can use the address directly. This is unlike
- * 4.4BSD derived systems that have an address chain
- * per device. We have a device per address with dummy
- * devices instead.
+ * we can use the address directly. Linux 2.1 now uses address
+ * chains per device too, but unlike BSD we first check if the
+ * incoming packet matches a device address and the routing
+ * table before calling the firewall.
*/
dprintf("Packet ");
return NULL;
}
-#if DEBUG_IP_FIREWALL_USER
+#ifdef DEBUG_IP_FIREWALL_USER
/* These are sanity checks that don't really matter.
* We can get rid of these once testing is complete.
*/
*
* The Internet Protocol (IP) module.
*
- * Version: $Id: ip_input.c,v 1.30 1998/05/08 01:54:54 davem Exp $
+ * Version: $Id: ip_input.c,v 1.31 1998/05/17 02:19:15 freitag Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox : Multicast routing hooks
* Jos Vos : Do accounting *before* call_in_firewall
* Willy Konynenberg : Transparent proxying support
- * Mike McLagan : Routing by source
*
*
*
/*
* See if the firewall wants to dispose of the packet.
+ *
+ * Note: the current standard firewall code expects that the
+ * destination address was already checked against the interface
+ * address lists.
+ *
+ * If this code is ever moved in front of ip_route_input() you need
+ * to fix the fw code [moving it might be a good idea anyways,
+ * so that we can firewall against potentially bugs in the options
+ * or routing code]
*/
#ifdef CONFIG_FIREWALL
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.57 1998/05/08 01:54:56 davem Exp $
+ * Version: $Id: ip_output.c,v 1.58 1998/05/15 15:21:36 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
{
struct rtable *rt = (struct rtable *)skb->dst;
struct iphdr *iph;
+ struct device *dev;
/* Build the IP header. */
if (opt)
ip_options_build(skb, opt, daddr, rt, 0);
}
+ dev = rt->u.dst.dev;
+
+ if (call_out_firewall(PF_INET, dev, iph, NULL, &skb) < FW_ACCEPT)
+ goto drop;
+
ip_send_check(iph);
/* Send it out. */
skb->dst->output(skb);
+ return;
+
+drop:
+ kfree_skb(skb);
}
int __ip_finish_output(struct sk_buff *skb)
/*
- * $Id: ipconfig.c,v 1.12 1998/05/03 14:30:53 alan Exp $
+ * $Id: ipconfig.c,v 1.13 1998/06/09 03:40:47 zaitcev Exp $
*
* Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
* information to configure own IP address and routes.
__initfunc(int ic_defaults(void))
{
+ /*
+ * At this point we have no userspace running so need not
+ * claim locks on system_utsname
+ */
+
if (!ic_host_name_set)
strcpy(system_utsname.nodename, in_ntoa(ic_myaddr));
}
/*
- * Decode any IP configuration options in the "ipconfig" kernel command
- * line parameter. It consists of option fields separated by colons in
+ * Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
+ * command line parameter. It consists of option fields separated by colons in
* the following order:
*
* <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<bootp|rarp>
*
* ROUTE - implementation of the IP router.
*
- * Version: $Id: route.c,v 1.50 1998/05/13 06:23:25 davem Exp $
+ * Version: $Id: route.c,v 1.52 1998/06/11 03:15:47 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
rth->u.dst.input= ip_local_deliver;
+ rth->rt_flags = flags|RTCF_LOCAL;
if (res.type == RTN_UNREACHABLE) {
rth->u.dst.input= ip_error;
- rth->u.dst.error= err;
+ rth->u.dst.error= -err;
+ rth->rt_flags &= ~RTCF_LOCAL;
}
- rth->rt_flags = flags|RTCF_LOCAL;
rth->rt_type = res.type;
skb->dst = (struct dst_entry*)rt_intern_hash(hash, rth);
return 0;
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * $Id: syncookies.c,v 1.5 1998/04/03 09:49:46 freitag Exp $
+ * $Id: syncookies.c,v 1.6 1998/06/10 07:29:22 davem Exp $
*
* Missing: IPv6 support.
*/
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.114 1998/04/26 01:11:33 davem Exp $
+ * Version: $Id: tcp.c,v 1.115 1998/05/13 13:44:13 alan Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
add_wait_queue(sk->sleep, &wait);
lock_sock(sk);
+
+ /*
+ * BUG BUG BUG
+ * This violates 1003.1g compliance. We must wait for
+ * data to exist even if we read none!
+ */
+
while (len > 0) {
struct sk_buff * skb;
u32 offset;
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.118 1998/05/06 04:53:48 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.119 1998/05/23 13:10:24 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
}
} else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) {
/* Bulk data transfer: receiver */
- if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf)
+ if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) {
+ /* We must send an ACK for zero window probes. */
+ if (!before(TCP_SKB_CB(skb)->seq,
+ tp->rcv_wup + tp->rcv_wnd))
+ tcp_send_ack(sk);
goto discard;
+ }
skb_pull(skb,th->doff*4);
}
if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
- if (!th->rst) {
- if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
- SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
- TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
- tp->rcv_wup, tp->rcv_wnd);
- }
- tcp_send_ack(sk);
+ /* RFC793, page 37: "In all states except SYN-SENT, all reset
+ * (RST) segments are validated by checking their SEQ-fields."
+ * And page 69: "If an incoming segment is not acceptable,
+ * an acknowledgment should be sent in reply (unless the RST bit
+ * is set, if so drop the segment and return)".
+ */
+ if (th->rst)
goto discard;
+ if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
+ SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
+ TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
+ tp->rcv_wup, tp->rcv_wnd);
}
+ tcp_send_ack(sk);
+ goto discard;
}
if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_output.c,v 1.90 1998/05/06 04:59:15 davem Exp $
+ * Version: $Id: tcp_output.c,v 1.91 1998/05/23 13:10:21 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* Note, we don't "adjust" for TIMESTAMP or SACK option bytes.
*/
-u32 __tcp_select_window(struct sock *sk)
+u32 __tcp_select_window(struct sock *sk, u32 cur_win)
{
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
unsigned int mss = sk->mss;
- unsigned int free_space;
- u32 window, cur_win;
+ int free_space;
+ u32 window;
+ /* Sometimes free_space can be < 0. */
free_space = (sk->rcvbuf - atomic_read(&sk->rmem_alloc)) / 2;
if (tp->window_clamp) {
- free_space = min(tp->window_clamp, free_space);
+ if (free_space > ((int) tp->window_clamp))
+ free_space = tp->window_clamp;
mss = min(tp->window_clamp, mss);
} else {
printk("tcp_select_window: tp->window_clamp == 0.\n");
printk("tcp_select_window: sk->mss fell to 0.\n");
}
- cur_win = tcp_receive_window(tp);
- if (free_space < sk->rcvbuf/4 && free_space < mss/2) {
+ if ((free_space < (sk->rcvbuf/4)) && (free_space < ((int) (mss/2)))) {
window = 0;
} else {
/* Get the largest window that is a nice multiple of mss.
* is too small.
*/
window = tp->rcv_wnd;
- if ((window <= (free_space - mss)) || (window > free_space))
- window = (free_space/mss)*mss;
+ if ((((int) window) <= (free_space - ((int) mss))) ||
+ (((int) window) > free_space))
+ window = (((unsigned int) free_space)/mss)*mss;
}
return window;
}
*
* The User Datagram Protocol (UDP).
*
- * Version: $Id: udp.c,v 1.56 1998/05/08 21:06:30 davem Exp $
+ * Version: $Id: udp.c,v 1.57 1998/05/14 06:32:44 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Andi Kleen : Some cleanups, cache destination entry
* for connect.
* Vitaly E. Lavrov : Transparent proxy revived after year coma.
+ * Melvin Smith : Check msg_name not msg_namelen in sendto(),
+ * return ENOTCONN for unconnected sockets (POSIX)
*
*
* This program is free software; you can redistribute it and/or
* Get and verify the address.
*/
- if (msg->msg_namelen) {
+ if (msg->msg_name) {
struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
if (msg->msg_namelen < sizeof(*usin))
return(-EINVAL);
*/
} else {
if (sk->state != TCP_ESTABLISHED)
- return -EINVAL;
+ return -ENOTCONN;
ufh.daddr = sk->daddr;
ufh.uh.dest = sk->dport;
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.33 1998/05/08 21:06:32 davem Exp $
+ * $Id: af_inet6.c,v 1.36 1998/06/10 07:29:25 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
}
#endif
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+extern void ipv6_sysctl_register(void);
+extern void ipv6_sysctl_unregister(void);
+#endif
+
#ifdef MODULE
int init_module(void)
#else
void cleanup_module(void)
{
/* First of all disallow new sockets creation. */
- sock_unregister(AF_INET6);
+ sock_unregister(PF_INET6);
#ifdef CONFIG_PROC_FS
proc_net_unregister(proc_net_raw6.low_ino);
proc_net_unregister(proc_net_tcp6.low_ino);
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.81 1998/05/03 14:31:10 alan Exp $
+ * $Id: tcp_ipv6.c,v 1.82 1998/06/11 03:15:52 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
{
int hashent = (lport ^ fport);
- hashent ^= (laddr->s6_addr32[0] ^ laddr->s6_addr32[1]);
- hashent ^= (faddr->s6_addr32[0] ^ faddr->s6_addr32[1]);
- hashent ^= (faddr->s6_addr32[2] ^ faddr->s6_addr32[3]);
+ hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
return (hashent & ((TCP_HTABLE_SIZE/2) - 1));
}
static void tcp_v6_hash(struct sock *sk)
{
+ /* Well, I know that it is ugly...
+ All this ->prot, ->af_specific etc. need LARGE cleanup --ANK
+ */
+ if (sk->tp_pinfo.af_tcp.af_specific == &ipv6_mapped) {
+ tcp_prot.hash(sk);
+ return;
+ }
if(sk->state != TCP_CLOSE) {
struct sock **skp;
if (err) {
sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
sk->backlog_rcv = tcp_v6_do_rcv;
+ } else {
+ /* Yuup... And it is not the only place... --ANK */
+ ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000FFFF),
+ sk->saddr);
+ ipv6_addr_set(&np->rcv_saddr, 0, 0, __constant_htonl(0x0000FFFF),
+ sk->rcv_saddr);
}
-
+
return err;
}
*
* Based on linux/ipv4/udp.c
*
- * $Id: udp.c,v 1.28 1998/05/03 14:31:12 alan Exp $
+ * $Id: udp.c,v 1.29 1998/05/15 15:21:39 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
}
} else {
if (sk->state != TCP_ESTABLISHED)
- return(-EINVAL);
+ return(-ENOTCONN);
udh.uh.dest = sk->dport;
daddr = &sk->net_pinfo.af_inet6.daddr;
break;
f->next = *fp;
*fp = f;
+ *arg = (unsigned long)f;
return 0;
}
}
if (cl->police) {
opt.police = cl->police;
- RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
+ RTA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt);
}
return skb->len;
return 0;
}
neigh_release(n);
- return (skb_res != NULL);
+ return (skb_res == NULL) ? -EAGAIN : 1;
}
static __inline__ int
restart:
nores = 0;
- busy = 1;
+ busy = 0;
if ((q = start) == NULL)
goto drop;
do {
struct device *slave = q->dev;
- if (!slave->tbusy && slave->qdisc_sleeping == q) {
- busy = 0;
-
- if (q->h.forw == NULL) {
- q->h.forw = qdisc_head.forw;
- qdisc_head.forw = &q->h;
- }
+ if (slave->qdisc_sleeping != q)
+ continue;
+ if (slave->tbusy) {
+ busy = 1;
+ continue;
+ }
- switch (teql_resolve(skb, skb_res, slave)) {
- case 0:
- if (slave->hard_start_xmit(skb, slave) == 0) {
- master->slaves = NEXT_SLAVE(q);
- dev->tbusy = 0;
- master->stats.tx_packets++;
- master->stats.tx_bytes += len;
- return 0;
- }
- break;
- case 1:
+ if (q->h.forw == NULL) {
+ q->h.forw = qdisc_head.forw;
+ qdisc_head.forw = &q->h;
+ }
+
+ switch (teql_resolve(skb, skb_res, slave)) {
+ case 0:
+ if (slave->hard_start_xmit(skb, slave) == 0) {
master->slaves = NEXT_SLAVE(q);
dev->tbusy = 0;
- return 0;
- default:
- nores = 1;
- break;
+ master->stats.tx_packets++;
+ master->stats.tx_bytes += len;
+ return 0;
}
- __skb_pull(skb, skb->nh.raw - skb->data);
+ if (dev->tbusy)
+ busy = 1;
+ break;
+ case 1:
+ master->slaves = NEXT_SLAVE(q);
+ dev->tbusy = 0;
+ return 0;
+ default:
+ nores = 1;
+ break;
}
+ __skb_pull(skb, skb->nh.raw - skb->data);
} while ((q = NEXT_SLAVE(q)) != start);
if (nores && skb_res == NULL) {
/*
* Clear the set of configuration strings.
*/
-void clear_config( )
+void clear_config(void)
{
len_config = 0;
define_config(0, "", 0);
* Thus, there is one memory access per sizeof(unsigned long) characters.
*/
-#if defined(__alpha__) || defined(__i386__)
+#if defined(__alpha__) || defined(__i386__) || defined(__arm__)
#define LE_MACHINE
#endif